200 lines
6.9 KiB
C
200 lines
6.9 KiB
C
/*
|
|
Copyright 2025 Kamil Kowalczyk
|
|
|
|
Redistribution and use in source and binary forms, with or
|
|
without modification, are permitted provided that the following
|
|
conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
3. Neither the name of the copyright holder nor the names of its
|
|
contributors may be used to endorse or promote products derived from
|
|
this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
“AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <libk/types.h>
|
|
#include <libk/util.h>
|
|
#include <libk/string.h>
|
|
#include <libk/stdatomic.h>
|
|
#include <sys/cpu.h>
|
|
#include <sys/gdt_flush.h>
|
|
#include <sys/tss_flush.h>
|
|
#include <sys/idt_flush.h>
|
|
#include <sys/isr.h>
|
|
#include <sys/pic.h>
|
|
|
|
static volatile struct gdt_entry gdt[6];
|
|
static volatile struct gdt_ptr gdtptr;
|
|
static volatile struct tss tss;
|
|
static volatile struct idt_entry idt[0x100];
|
|
static volatile struct idt_ptr idtptr;
|
|
|
|
static struct { volatile uint32_t eflags; atomic_int nesting; } intr_state =
|
|
{ .eflags = 0, .nesting = 0 };
|
|
|
|
static void gdt_make_entry(int index, uint32_t base, uint32_t limit,
|
|
uint8_t access, uint8_t gran) {
|
|
gdt[index].base_low = (base & 0xFFFF);
|
|
gdt[index].base_mid = (base >> 16) & 0xFF;
|
|
gdt[index].base_up = (base >> 24) & 0xFF;
|
|
gdt[index].limit_low = (limit & 0xFFFF);
|
|
gdt[index].gran = ((limit >> 16) & 0x0F);
|
|
gdt[index].gran |= (gran & 0xF0);
|
|
gdt[index].access = access;
|
|
}
|
|
|
|
static void gdt_init(void) {
|
|
gdtptr.limit = ELEM_SIZE(gdt) * LEN(gdt) - 1;
|
|
gdtptr.base = (uint32_t)&gdt;
|
|
gdt_make_entry(0, 0, 0, 0, 0);
|
|
gdt_make_entry(1, 0, 0xFFFFF, 0x9A, 0xCF);
|
|
gdt_make_entry(2, 0, 0xFFFFF, 0x92, 0xCF);
|
|
gdt_make_entry(3, 0, 0xFFFFF, 0xFA, 0xCF);
|
|
gdt_make_entry(4, 0, 0xFFFFF, 0xF2, 0xCF);
|
|
|
|
gdt_flush((ptr_t)&gdtptr);
|
|
}
|
|
|
|
static void tss_init(void) {
|
|
uint32_t base = (uint32_t)&tss;
|
|
gdt_make_entry(5, base, base + sizeof(struct tss), 0xE9, 0);
|
|
|
|
memset((void *)&tss, 0, sizeof(tss));
|
|
|
|
uptr_t sp;
|
|
__asm__ volatile("mov %%esp, %0" : "=r"(sp));
|
|
|
|
tss.ss0 = 0x10;
|
|
tss.esp0 = (uint32_t)sp;
|
|
tss.cs = 0x08 | 0x3;
|
|
tss.ds = 0x10 | 0x3;
|
|
tss.es = 0x10 | 0x3;
|
|
tss.fs = 0x10 | 0x3;
|
|
tss.fs = 0x10 | 0x3;
|
|
tss.ss = 0x10 | 0x3;
|
|
tss.iomap = sizeof(tss);
|
|
|
|
tss_flush();
|
|
}
|
|
|
|
static void idt_make_entry(int index, uint32_t base, uint32_t sel, uint8_t flags) {
|
|
volatile struct idt_entry *ent = &idt[index];
|
|
ent->base_low = (base & 0xFFFF);
|
|
ent->base_up = ((base >> 16) & 0xFFFF);
|
|
ent->always0 = 0;
|
|
ent->sel = sel;
|
|
ent->flags = flags | 0x60;
|
|
}
|
|
|
|
void idt_init(void) {
|
|
memset((void *)idt, 0, sizeof(idt));
|
|
idtptr.base = (uint32_t)idt;
|
|
idtptr.limit = sizeof(idt) - 1;
|
|
|
|
idt_make_entry(0, (uint32_t)&except0, 0x08, 0x8E);
|
|
idt_make_entry(1, (uint32_t)&except1, 0x08, 0x8E);
|
|
idt_make_entry(2, (uint32_t)&except2, 0x08, 0x8E);
|
|
idt_make_entry(3, (uint32_t)&except3, 0x08, 0x8E);
|
|
idt_make_entry(4, (uint32_t)&except4, 0x08, 0x8E);
|
|
idt_make_entry(5, (uint32_t)&except5, 0x08, 0x8E);
|
|
idt_make_entry(6, (uint32_t)&except6, 0x08, 0x8E);
|
|
idt_make_entry(7, (uint32_t)&except7, 0x08, 0x8E);
|
|
idt_make_entry(8, (uint32_t)&except8, 0x08, 0x8E);
|
|
idt_make_entry(9, (uint32_t)&except9, 0x08, 0x8E);
|
|
idt_make_entry(10, (uint32_t)&except10, 0x08, 0x8E);
|
|
idt_make_entry(11, (uint32_t)&except11, 0x08, 0x8E);
|
|
idt_make_entry(12, (uint32_t)&except12, 0x08, 0x8E);
|
|
idt_make_entry(13, (uint32_t)&except13, 0x08, 0x8E);
|
|
idt_make_entry(14, (uint32_t)&except14, 0x08, 0x8E);
|
|
idt_make_entry(15, (uint32_t)&except15, 0x08, 0x8E);
|
|
idt_make_entry(16, (uint32_t)&except16, 0x08, 0x8E);
|
|
idt_make_entry(17, (uint32_t)&except17, 0x08, 0x8E);
|
|
idt_make_entry(18, (uint32_t)&except18, 0x08, 0x8E);
|
|
idt_make_entry(19, (uint32_t)&except19, 0x08, 0x8E);
|
|
idt_make_entry(20, (uint32_t)&except20, 0x08, 0x8E);
|
|
idt_make_entry(21, (uint32_t)&except21, 0x08, 0x8E);
|
|
idt_make_entry(22, (uint32_t)&except22, 0x08, 0x8E);
|
|
idt_make_entry(23, (uint32_t)&except23, 0x08, 0x8E);
|
|
idt_make_entry(24, (uint32_t)&except24, 0x08, 0x8E);
|
|
idt_make_entry(25, (uint32_t)&except25, 0x08, 0x8E);
|
|
idt_make_entry(26, (uint32_t)&except26, 0x08, 0x8E);
|
|
idt_make_entry(27, (uint32_t)&except27, 0x08, 0x8E);
|
|
idt_make_entry(28, (uint32_t)&except28, 0x08, 0x8E);
|
|
idt_make_entry(29, (uint32_t)&except29, 0x08, 0x8E);
|
|
idt_make_entry(30, (uint32_t)&except30, 0x08, 0x8E);
|
|
idt_make_entry(31, (uint32_t)&except31, 0x08, 0x8E);
|
|
idt_make_entry(32, (uint32_t)&irq0, 0x08, 0x8E);
|
|
idt_make_entry(33, (uint32_t)&irq1, 0x08, 0x8E);
|
|
idt_make_entry(34, (uint32_t)&irq2, 0x08, 0x8E);
|
|
idt_make_entry(35, (uint32_t)&irq3, 0x08, 0x8E);
|
|
idt_make_entry(36, (uint32_t)&irq4, 0x08, 0x8E);
|
|
idt_make_entry(37, (uint32_t)&irq5, 0x08, 0x8E);
|
|
idt_make_entry(38, (uint32_t)&irq6, 0x08, 0x8E);
|
|
idt_make_entry(39, (uint32_t)&irq7, 0x08, 0x8E);
|
|
idt_make_entry(40, (uint32_t)&irq8, 0x08, 0x8E);
|
|
idt_make_entry(41, (uint32_t)&irq9, 0x08, 0x8E);
|
|
idt_make_entry(42, (uint32_t)&irq10, 0x08, 0x8E);
|
|
idt_make_entry(43, (uint32_t)&irq11, 0x08, 0x8E);
|
|
idt_make_entry(44, (uint32_t)&irq12, 0x08, 0x8E);
|
|
idt_make_entry(45, (uint32_t)&irq13, 0x08, 0x8E);
|
|
idt_make_entry(46, (uint32_t)&irq14, 0x08, 0x8E);
|
|
idt_make_entry(47, (uint32_t)&irq15, 0x08, 0x8E);
|
|
idt_make_entry(128, (uint32_t)&except128, 0x08, 0xEE);
|
|
|
|
idt_flush((ptr_t)&idtptr);
|
|
}
|
|
|
|
void cpu_init(void) {
|
|
gdt_init();
|
|
tss_init();
|
|
pic_init();
|
|
idt_init();
|
|
}
|
|
|
|
static uint32_t intr_save1(void) {
|
|
uint32_t eflags;
|
|
__asm__ volatile ("pushfl; cli; popl %0;" : "=r"(eflags) :: "memory", "cc");
|
|
return eflags;
|
|
}
|
|
|
|
static void intr_restore1(uint32_t eflags) {
|
|
if (eflags & (1 << 9)) {
|
|
__asm__ volatile("sti" ::: "memory", "cc");
|
|
}
|
|
}
|
|
|
|
void intr_save(void) {
|
|
int prev = atomic_fetch_add_explicit(&intr_state.nesting, 1, memory_order_acq_rel);
|
|
if (prev == 0) {
|
|
intr_state.eflags = intr_save1();
|
|
}
|
|
}
|
|
|
|
void intr_restore(void) {
|
|
int prev = atomic_fetch_sub_explicit(&intr_state.nesting, 1, memory_order_acq_rel);
|
|
if (prev == 1) {
|
|
intr_restore1(intr_state.eflags);
|
|
}
|
|
}
|
|
|
|
void cpu_relax(void) {
|
|
__asm__ volatile("pause");
|
|
}
|