diff options
| author | Ada Christine <adachristine18@gmail.com> | 2022-01-17 12:22:30 +0000 |
|---|---|---|
| committer | Ada Christine <adachristine18@gmail.com> | 2022-01-17 12:22:30 +0000 |
| commit | 2f2e5b43d2985abd504ecd5672ce783bef904f2f (patch) | |
| tree | 3c24efcea6b0ce6dda0ee720b3afe250247f2dfb | |
| parent | dc7152c1cc6412871e1120ed53fb94ed386613cc (diff) | |
preparing for multitasking
| -rw-r--r-- | kc/core/Makefile | 6 | ||||
| -rw-r--r-- | kc/core/cpu.h | 10 | ||||
| -rw-r--r-- | kc/core/cpu/cpu.c | 294 | ||||
| -rw-r--r-- | kc/core/cpu/msr.c | 29 | ||||
| -rw-r--r-- | kc/core/cpu/msr.h | 15 | ||||
| -rw-r--r-- | kc/core/exceptions.h | 3 | ||||
| -rw-r--r-- | kc/core/kc_main.c | 4 |
7 files changed, 353 insertions, 8 deletions
diff --git a/kc/core/Makefile b/kc/core/Makefile index 53f1cea..2b8ab8d 100644 --- a/kc/core/Makefile +++ b/kc/core/Makefile @@ -1,18 +1,18 @@ include ../../defaults.mk include ../defaults.mk -VPATH := ../../lib ../ +VPATH := ../../lib ../ cpu/ TARGET := kernel.os .DEFAULT: $(TARGET) -CPPFLAGS += -I../../api +CPPFLAGS += -I../../api -I. CFLAGS += -Wno-unused-const-variable -Wno-unused-function -fvisibility=hidden -g SOBJS := GOBJS := entry_x86_64.o reloc_x86_64.o kprint.o serial.o port.o \ kc_main.o main.o memory.o memset.o memcpy.o memmove.o memcmp.o cpu.o \ - vm_tree.o exceptions.o panic.o + vm_tree.o exceptions.o panic.o msr.o IOBJS := # __attribute__((interrupt)) requires -mgeneral-regs-only diff --git a/kc/core/cpu.h b/kc/core/cpu.h index 2d5e134..a8da9bf 100644 --- a/kc/core/cpu.h +++ b/kc/core/cpu.h @@ -1,15 +1,17 @@ #pragma once -#include <stdint.h> +#include "task.h" + +#include <stdnoreturn.h> void cpu_init(void); +noreturn void cpu_task_begin(void); +void cpu_task_set(struct kc_thread *task); + void isr_install(int vec, void (*isr)(void), int ist, int trap); void ist_install(int ist, void *stack); void int_enable(void); void int_disable(void); -uint64_t msr_read(uint32_t index); -void msr_write(uint32_t index, uint64_t value); - diff --git a/kc/core/cpu/cpu.c b/kc/core/cpu/cpu.c new file mode 100644 index 0000000..49a88be --- /dev/null +++ b/kc/core/cpu/cpu.c @@ -0,0 +1,294 @@ +#include "cpu.h" +#include "exceptions.h" +#include "kprint.h" +#include "panic.h" +#include "msr.h" +#include "task.h" +#include "memory.h" + +#include <stddef.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 EFER_SCE 1 + +#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; + +uint64_t *get_tss_rsp0(void) +{ + return &tss.rsp0; +} + +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 |= EFER_SCE; // enable syscall extensions + msr_write(MSR_EFER, efer_bits); +} + +void exceptions_init(void) +{ + isr_install(GENERAL_PROTECTION_VECTOR, &general_protection_isr, 0, 0); + 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"); +} + diff --git a/kc/core/cpu/msr.c b/kc/core/cpu/msr.c new file mode 100644 index 0000000..2efdd7d --- /dev/null +++ b/kc/core/cpu/msr.c @@ -0,0 +1,29 @@ +#include "msr.h" + +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) + ); +} + diff --git a/kc/core/cpu/msr.h b/kc/core/cpu/msr.h new file mode 100644 index 0000000..a5014da --- /dev/null +++ b/kc/core/cpu/msr.h @@ -0,0 +1,15 @@ +#pragma once + +#include <stdint.h> + +#define EFER_SCE 1 + +#define MSR_EFER 0xc0000080 +#define MSR_STAR 0xc0000081 +#define MSR_LSTAR 0xc0000082 +#define MSR_CSTAR 0xc0000083 +#define MSR_SFMASK 0xc0000084 + +uint64_t msr_read(uint32_t index); +void msr_write(uint32_t index, uint64_t value); + diff --git a/kc/core/exceptions.h b/kc/core/exceptions.h index 5d22284..11696d5 100644 --- a/kc/core/exceptions.h +++ b/kc/core/exceptions.h @@ -1,7 +1,10 @@ #pragma once extern void page_fault_isr(void); +extern void general_protection_isr(void); +#define GENERAL_PROTECTION_VECTOR 0xd #define PAGE_FAULT_VECTOR 0xe void exceptions_init(void); + diff --git a/kc/core/kc_main.c b/kc/core/kc_main.c index d8ccc11..1eb07da 100644 --- a/kc/core/kc_main.c +++ b/kc/core/kc_main.c @@ -10,9 +10,11 @@ #include <stddef.h> #include <stdint.h> +//TODO: initialize vm before cpu? +// alternatively, split memory and/or cpu initialization steps + unsigned long kc_main(struct kc_boot_data *data) { - (void)data; cpu_init(); serial_init(); kputs("<hacker voice> i'm in 3333\r\n"); |
