diff options
Diffstat (limited to 'kc/core/cpu.c')
| -rw-r--r-- | kc/core/cpu.c | 310 |
1 files changed, 0 insertions, 310 deletions
diff --git a/kc/core/cpu.c b/kc/core/cpu.c deleted file mode 100644 index 7b3b95b..0000000 --- a/kc/core/cpu.c +++ /dev/null @@ -1,310 +0,0 @@ -#include "cpu.h" -#include "exceptions.h" -#include "kprint.h" -#include "panic.h" - -#include <stdint.h> - -#define GDT_ENTRIES 16 -#define IDT_ENTRIES 256 - -#define CODE_SUPER_SEG_INDEX 1 -#define CODE_USER_SEG_INDEX 2 -#define DATA_SEG_INDEX 3 -#define TASK_SEG_INDEX 4 - -#define MSR_EFER 0xc0000080 -#define MSR_STAR 0xc0000081 -#define MSR_LSTAR 0xc0000082 -#define MSR_CSTAR 0xc0000083 -#define MSR_SFMASK 0xc0000084 - - -struct dtr64 -{ - uint16_t limit; - uint64_t base; -} __attribute__((packed)); - -struct segment_descriptor -{ - uint16_t limit0; - uint16_t base0; - uint8_t base16; - uint8_t access; - uint8_t flags_limit16; - uint8_t base24; -} __attribute__((packed)); - -enum segment_descriptor_type -{ - CODE64_SUPER_SEG, - CODE64_USER_SEG, - DATA_SEG, - TASK64_SEG, -}; - -struct gate_descriptor -{ - uint16_t offset0; - uint16_t selector; - uint8_t ist; - uint8_t access; - uint16_t offset16; - uint64_t offset32; -} __attribute__((packed)); - -enum gate_descriptor_type -{ - INT64_GATE, - TRAP64_GATE, -}; - -struct task64_segment -{ - uint32_t reserved0; - uint64_t rsp0; - uint64_t rsp1; - uint64_t rsp2; - uint64_t reserved1; - uint64_t ist[7]; - uint16_t reserved2; - uint16_t iomap_base; -}; - -static struct segment_descriptor gdt[GDT_ENTRIES]; -static struct gate_descriptor idt[IDT_ENTRIES]; -static struct task64_segment tss; - -static void syscall_entry(void) -{ - kputs("system call\n"); - halt(); -} - -static void set_gdt(int index, - uint64_t base, - uint64_t limit, - enum segment_descriptor_type type) -{ - gdt[index].limit0 = limit & 0xffff; - gdt[index].base0 = base & 0xffff; - gdt[index].base16 = (base >> 16) & 0xff; - gdt[index].flags_limit16 = (limit >> 16) & 0xf; - gdt[index].base24 = (base >> 24) & 0xff; - - switch (type) - { - case CODE64_SUPER_SEG: - gdt[index].access = 0x9a; - gdt[index].flags_limit16 |= 0xa0; - break; - case CODE64_USER_SEG: - gdt[index].access = 0xfa; - gdt[index].flags_limit16 |= 0xa0; - break; - case DATA_SEG: - gdt[index].access = 0x92; - gdt[index].flags_limit16 |= 0xc0; - break; - case TASK64_SEG: - gdt[index].access = 0x89; - //TODO: make this cleaner i don't like it - gdt[index+1].limit0 = (base >> 32) & 0xffff; - gdt[index+1].base0 = (base >> 48) & 0xffff; - break; - }; -} - -static void set_idt(int vec, - uint16_t selector, - uint64_t offset, - enum gate_descriptor_type type) -{ - idt[vec].offset0 = offset & 0xffff; - idt[vec].selector = selector; - idt[vec].offset16 = (offset >> 16) & 0xffff; - idt[vec].offset32 = (offset >> 32) & 0xffffffff; - - switch (type) - { - case INT64_GATE: - idt[vec].access = 0x8e; - break; - case TRAP64_GATE: - idt[vec].access = 0x8f; - break; - } -} - -void set_ist(int vec, int ist_index) -{ - // non-destructively set the ist index. - idt[vec].access |= ist_index & 0x7; -} - -static void gdt_init(void) -{ - set_gdt(CODE_SUPER_SEG_INDEX, 0, (uint64_t)-1, CODE64_SUPER_SEG); - set_gdt(CODE_USER_SEG_INDEX, 0, (uint64_t)-1, CODE64_USER_SEG); - set_gdt(DATA_SEG_INDEX, 0, (uint64_t)-1, DATA_SEG); - set_gdt(TASK_SEG_INDEX, (uint64_t)&tss, sizeof(tss) - 1, TASK64_SEG); - - struct dtr64 gdtr = {sizeof(gdt) - 1, (uint64_t)&gdt}; - - __asm__ volatile - ( - // can't have interrupts during GDT reload - // but don't re-enable interrupts if they were already disabled - "pushf\n" - "cli\n" - "lgdt %0\n" - "mov %w2, %%ds\n" - "mov %w2, %%es\n" - "mov %w2, %%fs\n" - "mov %w2, %%gs\n" - "mov %w2, %%ss\n" - // make a far return frame on the stack - // [ss] @rsp+8 - // [rip] @rsp - "pushq %1\n" - "lea .Lflush(%%rip), %%rax\n" - "push %%rax\n" - // far return, now we're in the code segment - // defined here. - "lretq\n" - ".Lflush:\n" - "ltr %w3\n" - "popf\n" - // dependency on pre-boot GDT is now gone - : - : "m"(gdtr), - "i"(CODE_SUPER_SEG_INDEX << 3), - "r"(DATA_SEG_INDEX << 3), - "r"(TASK_SEG_INDEX << 3) - ); -} - -static void idt_init(void) -{ - struct dtr64 idtr = {sizeof(idt) - 1, (uint64_t)&idt}; - - __asm__ volatile - ( - // can't have interrupts enabled during IDT reload--obviously. - // as with GDT don't re-enable interrupts if they were already - // disabled. - "pushf\n" - "cli\n" - "lidt %0\n" - "popf\n" - // much more straightforward than the gdt code. - :: "m"(idtr) - ); -} - -void cpu_init(void) -{ - gdt_init(); - idt_init(); - exceptions_init(); - - //TODO: fix rudimentary syscall stuff. - - uint64_t lstar_bits = (uintptr_t)syscall_entry; - msr_write(MSR_LSTAR, lstar_bits); - - union - { - struct - { - uint32_t eip32; - uint8_t syscall_ss; - uint8_t syscall_cs; - uint8_t sysret_ss; - uint8_t sysret_cs; - } - fields; - uint64_t raw; - } - star_bits = - { - { - 0, - DATA_SEG_INDEX, - CODE_SUPER_SEG_INDEX, - DATA_SEG_INDEX, - CODE_USER_SEG_INDEX - } - }; - - msr_write(MSR_STAR, star_bits.raw); - - uint64_t efer_bits = msr_read(MSR_EFER); - efer_bits |= 1; // enable syscall extensions - msr_write(MSR_EFER, efer_bits); -} - -void exceptions_init(void) -{ - isr_install(PAGE_FAULT_VECTOR, &page_fault_isr, 0, 0); -} - -void isr_install(int vec, void (*isr)(void), int trap, int ist) -{ - enum gate_descriptor_type type = INT64_GATE; - - if (trap) - { - type = TRAP64_GATE; - } - - set_idt(vec, CODE_SUPER_SEG_INDEX << 3, (uint64_t)isr, type); - if (ist) - { - set_ist(vec, ist); - } -} - -void ist_install(int ist, void *stack) -{ - tss.ist[ist] = (uint64_t)stack; -} - -void int_enable(void) -{ - __asm__ ("sti"); -} - -void int_disable(void) -{ - __asm__ ("cli"); -} - -uint64_t msr_read(uint32_t index) -{ - uint32_t low; - uint32_t high; - - __asm__ volatile - ( - "rdmsr\n\t" - : "=a"(low), "=d"(high) - : "c"(index) - ); - - return ((uint64_t)high << 32)|low; -} - -void msr_write(uint32_t index, uint64_t value) -{ - uint32_t low = value & 0xffffffff; - uint32_t high = value >> 32; - - __asm__ volatile - ( - "wrmsr\n\t" - :: "a"(low), "d"(high), "c"(index) - ); -} - |
