diff options
Diffstat (limited to 'kc')
| -rw-r--r-- | kc/core/cpu/cpu.c | 107 | ||||
| -rw-r--r-- | kc/core/cpu/descriptor.h | 4 | ||||
| -rw-r--r-- | kc/core/memory.h | 12 | ||||
| -rw-r--r-- | kc/core/memory/memory.c | 44 |
4 files changed, 106 insertions, 61 deletions
diff --git a/kc/core/cpu/cpu.c b/kc/core/cpu/cpu.c index a3205f7..f61ed00 100644 --- a/kc/core/cpu/cpu.c +++ b/kc/core/cpu/cpu.c @@ -15,10 +15,17 @@ #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 +enum kernel_segment_indices +{ + NULL_SEG, + CODE64_SUPER_SEG_INDEX, + DATA_SUPER_SEG_INDEX, + CODE32_USER_SEG_INDEX, + DATA32_USER_SEG_INDEX, + CODE64_USER_SEG_INDEX, + DATA64_USER_SEG_INDEX, + TASK64_SEG_INDEX +}; #define EFER_SCE 1 @@ -28,6 +35,13 @@ #define MSR_CSTAR 0xc0000083 #define MSR_SFMASK 0xc0000084 +struct cpu_state +{ + struct segment_descriptor gdt[GDT_ENTRIES]; + struct gate_descriptor idt[IDT_ENTRIES]; + struct task64_segment tss; +}; + static struct segment_descriptor gdt[GDT_ENTRIES]; static struct gate_descriptor idt[IDT_ENTRIES]; static struct task64_segment tss; @@ -64,10 +78,16 @@ static void set_gdt(int index, gdt[index].access = 0xfa; gdt[index].flags_limit16 |= 0xa0; break; - case DATA_SEG: + case CODE32_USER_SEG: + gdt[index].access = 0xfa; + gdt[index].flags_limit16 |= 0xc0; + case DATA_SUPER_SEG: gdt[index].access = 0x92; gdt[index].flags_limit16 |= 0xc0; break; + case DATA_USER_SEG: + gdt[index].access = 0xf2; + gdt[index].flags_limit16 |= 0xc0; case TASK64_SEG: gdt[index].access = 0x89; //TODO: make this cleaner i don't like it @@ -130,8 +150,7 @@ static void gdt_flush(uint16_t code_seg, uint16_t data_seg) "push %q0\n" "lea .Lflush(%%rip), %%rax\n" "push %%rax\n" - // far return, now we're in the code segment - // defined here. + // far return, now we're in the provided code segment "lretq\n" ".Lflush:\n" : @@ -162,41 +181,46 @@ static void gdt_load(struct dtr64 gdtr) ( "lgdt %0\n" : - : "m"(gdtr) + : + "m"(gdtr) ); irq_unlock(rflags); } -static void gdt_init(void) +static struct dtr64 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); + set_gdt(CODE64_SUPER_SEG_INDEX, 0, (uint64_t)-1, CODE64_SUPER_SEG); + set_gdt(DATA_SUPER_SEG_INDEX, 0, (uint64_t)-1, DATA_SUPER_SEG); + set_gdt(CODE32_USER_SEG_INDEX, 0, (uint64_t)-1, CODE32_USER_SEG); + set_gdt(DATA32_USER_SEG_INDEX, 0, (uint64_t)-1, DATA_USER_SEG); + set_gdt(CODE64_USER_SEG_INDEX, 0, (uint64_t)-1, CODE64_USER_SEG); + set_gdt(DATA64_USER_SEG_INDEX, 0, (uint64_t)-1, DATA_USER_SEG); + set_gdt(TASK64_SEG_INDEX, (uint64_t)&tss, sizeof(tss) - 1, TASK64_SEG); struct dtr64 gdtr = {sizeof(gdt) - 1, (uint64_t)&gdt}; + gdt_load(gdtr); - gdt_flush(CODE_SUPER_SEG_INDEX, DATA_SEG_INDEX); - gdt_load_task(TASK_SEG_INDEX); -} + gdt_flush(CODE64_SUPER_SEG_INDEX, DATA_SUPER_SEG_INDEX); + gdt_load_task(TASK64_SEG_INDEX); + return gdtr; +} -static void idt_init(void) +static struct dtr64 idt_init(void) { struct dtr64 idtr = {sizeof(idt) - 1, (uint64_t)&idt}; + uint64_t rflags = irq_lock(); __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) + : + : + "m"(idtr) ); + irq_unlock(rflags); + + return idtr; } void cpu_init(void) @@ -207,7 +231,7 @@ void cpu_init(void) //TODO: fix rudimentary syscall stuff. - uint64_t lstar_bits = (uintptr_t)syscall_entry; + uintptr_t lstar_bits = (uintptr_t)syscall_entry; msr_write(MSR_LSTAR, lstar_bits); union @@ -215,10 +239,8 @@ void cpu_init(void) struct { uint32_t eip32; - uint8_t syscall_ss; - uint8_t syscall_cs; - uint8_t sysret_ss; - uint8_t sysret_cs; + uint16_t syscall_cs; + uint16_t sysret_cs; } fields; uint64_t raw; @@ -227,10 +249,8 @@ void cpu_init(void) { { 0, - DATA_SEG_INDEX, - CODE_SUPER_SEG_INDEX, - DATA_SEG_INDEX, - CODE_USER_SEG_INDEX + CODE64_SUPER_SEG_INDEX << 3, + CODE32_USER_SEG_INDEX << 3 | 3 } }; @@ -253,15 +273,10 @@ void exceptions_init(void) void isr_install(int vec, void (*isr)(void), int trap, unsigned ist) { - enum gate_descriptor_type type = INT64_GATE; + enum gate_descriptor_type type = trap ? TRAP64_GATE : INT64_GATE; - if (trap) - { - type = TRAP64_GATE; - } + set_idt(vec, CODE64_SUPER_SEG_INDEX << 3, (uintptr_t)isr, type); - set_idt(vec, CODE_SUPER_SEG_INDEX << 3, (uintptr_t)isr, type); - // an IST greater than 7 is invalid if (ist && ist <= 7) { set_ist(vec, ist); @@ -277,13 +292,3 @@ void ist_install(int ist, void *stack) tss.ist[ist] = (uintptr_t)stack; } -void int_enable(void) -{ - __asm__ ("sti"); -} - -void int_disable(void) -{ - __asm__ ("cli"); -} - diff --git a/kc/core/cpu/descriptor.h b/kc/core/cpu/descriptor.h index 802c09c..c2a95ac 100644 --- a/kc/core/cpu/descriptor.h +++ b/kc/core/cpu/descriptor.h @@ -20,8 +20,10 @@ enum segment_descriptor_type { CODE64_SUPER_SEG, CODE64_USER_SEG, - DATA_SEG, + DATA_SUPER_SEG, TASK64_SEG, + CODE32_USER_SEG, + DATA_USER_SEG }; struct gate_descriptor diff --git a/kc/core/memory.h b/kc/core/memory.h index 1303a99..6f70e57 100644 --- a/kc/core/memory.h +++ b/kc/core/memory.h @@ -19,10 +19,13 @@ enum page_map_flags CONTENT_RWDATA = 0x3, CONTENT_MASK = 0x3, - SIZE_4K = 0x4, - SIZE_2M = 0x8, - SIZE_1G = 0xc, - SIZE_MASK = 0xc, + PRIV_USER = 0x4, + PRIV_MASK = 0x4, + + SIZE_4K = 0x8, + SIZE_2M = 0x10, + SIZE_1G = 0x18, + SIZE_MASK = 0x18, }; enum page_alloc_flags @@ -60,6 +63,7 @@ int page_inc_ref(kc_phys_addr page); int page_dec_ref(kc_phys_addr page); void *page_map(phys_addr_t paddr, enum page_map_flags flags); +void *page_set_flags(void *vaddr, enum page_map_flags flags); void page_unmap(void *vaddr); phys_addr_t page_alloc(enum page_alloc_flags flags); diff --git a/kc/core/memory/memory.c b/kc/core/memory/memory.c index 06c2942..f50752f 100644 --- a/kc/core/memory/memory.c +++ b/kc/core/memory/memory.c @@ -136,7 +136,9 @@ void page_free(kc_phys_addr page) page_stack_free(page); } -static void *map_tableset(void *vaddr, uint64_t *tables[4]) +#define TABLESET_COUNT 3 + +static void *map_tableset(void *vaddr, uint64_t *tables[TABLESET_COUNT]) { uint64_t current_phys; uint64_t *current_pte; @@ -144,8 +146,8 @@ static void *map_tableset(void *vaddr, uint64_t *tables[4]) // current_phys = page_address(mmu_get_map(), 1); - tables[3] = temp_page_map(current_phys, CONTENT_RWDATA); - int n = 3; + tables[TABLESET_COUNT] = temp_page_map(current_phys, CONTENT_RWDATA); + int n = TABLESET_COUNT; while (n) { @@ -185,6 +187,32 @@ static void *map_tableset(void *vaddr, uint64_t *tables[4]) return vaddr; } +void *page_set_flags(void *vaddr, enum page_map_flags flags) +{ + uint64_t *mapset[PAGE_MAP_LEVELS] = {NULL}; + + if (vaddr != map_tableset(vaddr, mapset)) + { + PANIC(GENERAL_PANIC); + } + + if (flags & PRIV_MASK) + { + mapset[3][pte_index(vaddr, 4)] |= PAGE_US; + mapset[2][pte_index(vaddr, 3)] |= PAGE_US; + mapset[1][pte_index(vaddr, 2)] |= PAGE_US; + mapset[0][pte_index(vaddr, 1)] |= PAGE_US; + } + + for(int i = 0; i < PAGE_MAP_LEVELS; i++) + { + if (mapset[i]) + temp_page_unmap(mapset[i]); + } + + return vaddr; +} + static void *page_map_at( void *vaddr, phys_addr_t paddr, @@ -192,7 +220,7 @@ static void *page_map_at( { // TODO: add checks to prevent attempts to map reserved addreses // - uint64_t *mapset[4] = {NULL}; + uint64_t *mapset[PAGE_MAP_LEVELS] = {NULL}; if (vaddr != map_tableset(vaddr, mapset)) { @@ -230,12 +258,18 @@ static void *page_map_at( default: vaddr = NULL; } + + if (flags & PRIV_MASK) + { + entry |= PAGE_US; + } + if (vaddr) { mapset[0][pte_index(vaddr, 1)] = page_address(paddr, 1) | entry; } - for (int i = 0; i < 4; i++) + for (int i = 0; i < PAGE_MAP_LEVELS; i++) { if (mapset[i]) { |
