diff options
Diffstat (limited to 'arch/x86_64')
-rw-r--r-- | arch/x86_64/gdt.c | 111 | ||||
-rw-r--r-- | arch/x86_64/idt.c | 46 | ||||
-rw-r--r-- | arch/x86_64/ivt.s | 91 | ||||
-rw-r--r-- | arch/x86_64/lgdt.s | 26 | ||||
-rw-r--r-- | arch/x86_64/page_directory.c | 114 | ||||
-rw-r--r-- | arch/x86_64/panic.c | 36 | ||||
-rw-r--r-- | arch/x86_64/processor.c | 126 | ||||
-rw-r--r-- | arch/x86_64/savestate.s | 35 | ||||
-rw-r--r-- | arch/x86_64/syscall.c | 25 | ||||
-rw-r--r-- | arch/x86_64/untyped_memory.c | 54 | ||||
-rw-r--r-- | arch/x86_64/untyped_retype_page.c | 51 | ||||
-rw-r--r-- | arch/x86_64/usermode.c | 184 |
12 files changed, 899 insertions, 0 deletions
diff --git a/arch/x86_64/gdt.c b/arch/x86_64/gdt.c new file mode 100644 index 0000000..e8ca912 --- /dev/null +++ b/arch/x86_64/gdt.c @@ -0,0 +1,111 @@ +#include "arch/x86_64/tables.h" +#include "arch/x86_64/processor.h" +#include "string.h" + +static segment_descriptor_t s_gdt[] = { + { 0 }, //Kernel NULL + { //Kernel Code + .limit_0_15 = 0xFFFF, + .base_0_15 = 0x0, + .type = CD_SEGMENT_TYPE_CODE | CD_SEGMENT_TYPE_WRITEABLE, + .s = 1, + .dpl = 0, + .p = 1, + .limit_16_19 = 0xF, + .avl = 0, + .l = 1, + .d_b = 0, + .g = 1, + .base_24_31 = 0x0 + }, + { //Kernel Data + .limit_0_15 = 0xFFFF, + .base_0_15 = 0x0, + .type = CD_SEGMENT_TYPE_WRITEABLE, + .s = 1, + .dpl = 0, + .p = 1, + .limit_16_19 = 0xF, + .avl = 0, + .l = 0, + .d_b = 1, + .g = 1, + .base_24_31 = 0x0 + }, + { 0 }, //User NULL + { //User Data + .limit_0_15 = 0xFFFF, + .base_0_15 = 0x0, + .type = CD_SEGMENT_TYPE_WRITEABLE, + .s = 1, + .dpl = 3, + .p = 1, + .limit_16_19 = 0xF, + .avl = 0, + .l = 0, + .d_b = 1, + .g = 1, + .base_24_31 = 0x0 + }, + { //User Code + .limit_0_15 = 0xFFFF, + .base_0_15 = 0x0, + .type = CD_SEGMENT_TYPE_CODE | CD_SEGMENT_TYPE_WRITEABLE, + .s = 1, + .dpl = 3, + .p = 1, + .limit_16_19 = 0xF, + .avl = 0, + .l = 1, + .d_b = 0, + .g = 1, + .base_24_31 = 0x0 + }, + { //TSS Low + .limit_0_15 = 0, + .base_0_15 = 0, + .base_16_23 = 0, + .type = S_SEGMENT_TYPE_TSS_AVAIL, + .avl = 0, + .s = 0, + .dpl = 0, + .p = 1, + .limit_16_19 = 0, + .l = 0, + .d_b = 0, + .g = 0, + .base_24_31 = 0 + }, + { 0 } //TSS High +}; + +void +gdt_setup(processor_t *processor) +{ + memcpy(processor->gdt, s_gdt, sizeof(s_gdt)); + + processor->gdtr.base = (uintptr_t)&s_gdt; + processor->gdtr.length = sizeof(s_gdt) - 1; + + segment_descriptor_t *tss_lo = &processor->gdt[GDT_ENTRY_TSS_LOW]; + segment_descriptor_t *tss_hi = &processor->gdt[GDT_ENTRY_TSS_HIGH]; + + uintptr_t tssb = (uintptr_t)&processor->tss; + tss_lo->base_0_15 = tssb & 0xFFFF; + tss_lo->base_16_23 = (tssb >> 16) & 0xFF; + tss_lo->base_24_31 = (tssb >> 24) & 0xFF; + tss_hi->limit_0_15 = (tssb >> 32) & 0xFFFF; + tss_hi->base_0_15 = (tssb >> 48) & 0xFFFF; + + size_t tssl = sizeof(tss_t); + tss_lo->limit_0_15 = tssl & 0xFFFF; + tss_lo->limit_16_19 = (tssl >> 16) & 0xF; + + processor->tss.iopb = tssl; + + extern void gdt_load(void*); + gdt_load(&processor->gdtr); + + extern void tss_flush(uint16_t); + tss_flush(GDT_ENTRY_TSS_LOW * sizeof(segment_descriptor_t)); +} diff --git a/arch/x86_64/idt.c b/arch/x86_64/idt.c new file mode 100644 index 0000000..99e1da1 --- /dev/null +++ b/arch/x86_64/idt.c @@ -0,0 +1,46 @@ +#include "arch/x86_64/tables.h" +#include "arch/x86_64/idt.h" + +__attribute__((aligned(4096))) +interrupt_gate_t s_idtd[256]; + +int64_t __isr_err; +int64_t __isr_num; + +void +isr_handle(ivt_state_t* state) +{ + kpanic_state(state, "Unhandled interrupt %i", __isr_num); +} + +void +ivt_setup(void) +{ + extern uintptr_t __ivt[256]; + for(int i = 0; i < 256; i++) { + uintptr_t base = __ivt[i]; + s_idtd[i] = (interrupt_gate_t) { + .base_0_15 = (base & 0xFFFF), + .segment_selector = 0x8, + .ist = 0, + .zero_0 = 0, + .type = 0xE, + .zero_1 = 0, + .dpl = 0, + .p = 1, + .base_16_31 = (base >> 16) & 0xFFFF, + .base_32_63 = (base >> 32) & 0xFFFFFFFF, + .resv = 0 + }; + } +} + +void +idt_setup(processor_t *processor) +{ + processor->idtr.base = (uintptr_t)&s_idtd; + processor->idtr.length = sizeof(s_idtd) - 1; + + extern void idt_load(void* idtr); + idt_load(&processor->idtr); +} diff --git a/arch/x86_64/ivt.s b/arch/x86_64/ivt.s new file mode 100644 index 0000000..d2d504b --- /dev/null +++ b/arch/x86_64/ivt.s @@ -0,0 +1,91 @@ +.section .text +.global idt_load +.type idt_load @function +idt_load: + lidt (%rdi) + sti + retq +.size idt_load, . - idt_load + +.include "arch/x86_64/savestate.s" + +.extern isr_handle +.type __isr_head @function +__isr_head: + pushall + movq %rsp, %rdi + cld + + call isr_handle + popall + iretq + +.extern __isr_err +.extern __isr_num + +.macro defn_isr_err num:req +.type __isr\num @function +__isr\num: + pushq %rbx + movq 8(%rsp), %rbx + movq %rbx, __isr_err + popq %rbx + addq $8, %rsp + movq $\num, __isr_num + jmp __isr_head +.size __isr\num, . - __isr\num +.endm + +.macro defn_isr num:req +.type __isr\num @function +__isr\num: + movq $\num, __isr_num + jmp __isr_head +.size __isr\num, . - __isr\num +.endm + +.macro decl_isr num:req +.quad __isr\num +.endm + +defn_isr 0 +defn_isr 1 +defn_isr 2 +defn_isr 3 +defn_isr 4 +defn_isr 5 +defn_isr 6 +defn_isr 7 +defn_isr_err 8 +defn_isr 9 +defn_isr_err 10 +defn_isr_err 11 +defn_isr_err 12 +defn_isr_err 13 +defn_isr_err 14 +defn_isr 15 +defn_isr 16 +defn_isr_err 17 +defn_isr 18 +defn_isr 19 +defn_isr 20 +defn_isr_err 21 + +.altmacro +.set i, 22 +.rept 256-22 + defn_isr %i + .set i, i+1 +.endr + +.section .data + +.global __ivt +.type __ivt @object +__ivt: + .set i, 0 + .rept 256 + decl_isr %i + .set i, i+1 + .endr +.size __ivt, . - __ivt diff --git a/arch/x86_64/lgdt.s b/arch/x86_64/lgdt.s new file mode 100644 index 0000000..7122ef9 --- /dev/null +++ b/arch/x86_64/lgdt.s @@ -0,0 +1,26 @@ +.global gdt_load +.type gdt_load @function +gdt_load: + lgdt (%rdi) +.reload_segments: + pushq $0x8 + leaq .reload_cs, %rax + pushq %rax + lretq +.reload_cs: + movw $0x10, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + retq +.size gdt_load, . - gdt_load + +.global tss_flush +.type tss_flush @function +tss_flush: + movw %di, %ax + ltr %ax + retq +.size tss_flush, . - tss_flush diff --git a/arch/x86_64/page_directory.c b/arch/x86_64/page_directory.c new file mode 100644 index 0000000..0506703 --- /dev/null +++ b/arch/x86_64/page_directory.c @@ -0,0 +1,114 @@ +#include "arch/x86_64/page.h" +#include "arch/x86_64/object.h" +#include "device/processor.h" +#include "print.h" +#include "memory.h" +#include "object.h" +#include "string.h" +#include "jove.h" + +physptr_t s_kpbase(void); + +#if defined(__limine__) + +#include "boot/limine/limine.h" +static struct limine_kernel_address_request s_kaddr_req = { + .id = LIMINE_KERNEL_ADDRESS_REQUEST +}; + +physptr_t s_kpbase(void) { return s_kaddr_req.response->physical_base; } + +#endif + +physptr_t +vmem_tophys_koff(virtptr_t v) +{ + return v - (physptr_t)&_kernel_start + s_kpbase(); +} + +#define IDENTITY_BASE 0xFFFF800000000000 +void* +vmem_phys_tovirt(physptr_t p) +{ + return (void*)(p + IDENTITY_BASE); +} + +uintptr_t vmem_ident_tophys(void *vptr) +{ + return ((uintptr_t)vptr) - IDENTITY_BASE; +} + +void* +pmle_get_page(pmle_t entry) +{ + uintptr_t pptr = entry.paddr << 12; + return vmem_phys_tovirt(pptr); +} + +__attribute__((aligned(0x1000))) pmle_t s_kernel_pml4[512]; // Page L4 +__attribute__((aligned(0x1000))) pmle_t s_kernel_pml3[512]; // Page L3 +__attribute__((aligned(0x1000))) pmle_t s_kernel_pml2[512]; // Page directory +__attribute__((aligned(0x1000))) pmle_t s_kernel_pml1[512]; // Page table + +__attribute__((aligned(0x1000))) pmle_t s_idmap_pml3[512]; +__attribute__((aligned(0x1000))) pmle_t s_idmap_pml2[512]; + +void +vmem_setup(void) +{ + memset(s_kernel_pml4, 0, 0x1000); + memset(s_kernel_pml3, 0, 0x1000); + memset(s_kernel_pml2, 0, 0x1000); + memset(s_kernel_pml1, 0, 0x1000); + + memset(s_idmap_pml3, 0, 0x1000); + memset(s_idmap_pml2, 0, 0x1000); + + virtptr_t kernel_start = (virtptr_t)&_kernel_start; + virtptr_t kernel_end = (virtptr_t)&_kernel_end; + + size_t kernel_size = kernel_end - kernel_start; + size_t kernel_size_pages = (kernel_size / 0x1000) + 1; + + physptr_t kernel_pml4_base = vmem_tophys_koff((virtptr_t)&s_kernel_pml4); + physptr_t kernel_pml3_base = vmem_tophys_koff((virtptr_t)&s_kernel_pml3); + physptr_t kernel_pml2_base = vmem_tophys_koff((virtptr_t)&s_kernel_pml2); + physptr_t kernel_pml1_base = vmem_tophys_koff((virtptr_t)&s_kernel_pml1); + + physptr_t idmap_pml3_base = vmem_tophys_koff((virtptr_t)&s_idmap_pml3); + physptr_t idmap_pml2_base = vmem_tophys_koff((virtptr_t)&s_idmap_pml2); + + processor_t *processor = processor_current(); + processor->pdir = kernel_pml4_base; + + //Map memory identity pages. + s_kernel_pml4[256].value = idmap_pml3_base | 2 | 1; + s_idmap_pml3[0].value = idmap_pml2_base | 2 | 1; + for(int i = 0; i < 512; i++) { + s_idmap_pml2[i].value = (i * 0x1000 * 512) | 0x80 | 2 | 1; + } + + //Map the kernel to himem. + + pmli_t kernel_pml3_i = PML_I_FOR_LAYER(kernel_start, 3); + pmli_t kernel_pml2_i = PML_I_FOR_LAYER(kernel_start, 2); + pmli_t kernel_pml1_ib = PML_I_FOR_LAYER(kernel_start, 1); + pmli_t kernel_pml1_ie = PML_I_FOR_LAYER(kernel_end, 1) + 1; + + s_kernel_pml4[511].value = kernel_pml3_base | 2 | 1; + s_kernel_pml3[kernel_pml3_i].value = kernel_pml2_base | 2 | 1; + s_kernel_pml2[kernel_pml2_i].value = kernel_pml1_base | 2 | 1; + for(pmli_t i = kernel_pml1_ib; i < kernel_pml1_ie; i++) { + s_kernel_pml1[i].value = ((i * 0x1000) + s_kpbase()) | 3; + } + + __asm__ volatile("mov %0, %%cr3":: "r"(kernel_pml4_base)); + + //Add page mapping object to init directory. + uint8_t pm_i = _initDirectory.self.data++; + _initDirectory.entries[pm_i] = (objdir_entry_t) { + .type = KO_MEMORY_MAPPING_PAGE, + .data = kernel_pml4_base + }; + _initData.pm_object = pm_i; +} diff --git a/arch/x86_64/panic.c b/arch/x86_64/panic.c new file mode 100644 index 0000000..2e34500 --- /dev/null +++ b/arch/x86_64/panic.c @@ -0,0 +1,36 @@ +#include "jove.h" +#include "arch/x86_64/idt.h" +#include "print.h" + +#include <stddef.h> + +struct stackFrame { + struct stackFrame *ebp; + uintptr_t eip; +}; + +void +kpanic_state(ivt_state_t *state, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + kprintf("Kernel Panic!\n"); + + kvprintf(fmt, ap); + kprintf("\n\nCore dump:\n"); + + kprintf("RAX %p | RBX %p | RCX %p | RDX %p\n", state->rax, state->rbx, state->rcx, state->rdx); + kprintf("RSI %p | RDI %p | RSP %p | RBP %p\n", state->rsi, state->rdi, state->rsp, state->rbp); + kprintf("R8 %p | R9 %p | R10 %p | R11 %p\n", state->r8, state->r9, state->r10, state->r11); + kprintf("R12 %p | R13 %p | R14 %p | R15 %p\n", state->r12, state->r13, state->r14, state->r15); + kprintf("RIP %p\n", state->rip); + + kprintf("\nStack trace:\n"); + struct stackFrame *frame = (struct stackFrame*)state->rbp; + for(size_t framei = 0; frame && framei < 64; ++framei) { + kprintf("%i %p : %p\n", framei, frame, frame->eip); + frame = frame->ebp; + } + + hcf(); +} diff --git a/arch/x86_64/processor.c b/arch/x86_64/processor.c new file mode 100644 index 0000000..b39ba63 --- /dev/null +++ b/arch/x86_64/processor.c @@ -0,0 +1,126 @@ +#include "device/processor.h" +#include "arch/x86_64/tables.h" +#include "include/arch/x86_64/idt.h" +#include "include/arch/x86_64/object.h" +#include "jove.h" + +processor_t s_bsp = { + .odir = &_initDirectory +}; + +struct jove_ObjectDirectory s_processor_dir = { + .entries = { + [0] = { + .type = KO_OBJECT_DIRECTORY, + .data = 2 + }, + [1] = { + .type = KO_DEV_PROCESSOR, + .data = (uintptr_t)&s_bsp + } + } +}; + +char s_initial_response_buffer[256] = { 0 }; + +typedef union msr_efer +{ + struct { + uint8_t sce : 1; + uint8_t resv : 7; + uint8_t lme : 1; + uint8_t unk0 : 1; + uint8_t lma : 1; + uint8_t nxe : 1; + uint8_t svme : 1; + uint8_t lmsle : 1; + uint8_t ffxsr : 1; + uint8_t tce : 1; + }; + uint32_t v[2]; +} msr_efer_t; + +typedef union msr_star +{ + struct { + uint32_t eip; + uint16_t kcs; + uint16_t ucs; + }; + uint32_t v[2]; +} msr_star_t; + +typedef union msr_lstar +{ + uint32_t v[2]; + uintptr_t ip; +} msr_lstar_t; + +static void +s_enable_sce(void) +{ + msr_efer_t feat; + rdmsr(MSR_EFER, &feat.v[0], &feat.v[1]); + + feat.sce = 1; + wrmsr(MSR_EFER, feat.v[0], feat.v[1]); + + msr_star_t star; + star.kcs = GDT_ENTRY_KERNEL_CODE * sizeof(segment_descriptor_t); + star.ucs = GDT_ENTRY_USER_CODE * sizeof(segment_descriptor_t); + wrmsr(MSR_STAR, star.v[0], star.v[1]); + + extern void _syscall_entry(void); + msr_lstar_t lstar; + lstar.ip = (uintptr_t)_syscall_entry; + wrmsr(MSR_LSTAR, lstar.v[0], lstar.v[1]); +} + +void +processor_setup(void *_processor) +{ + processor_t *processor = (processor_t*)_processor; + gdt_setup(processor); + idt_setup(processor); + + wrmsr(MSR_GS_BASE, + (uint32_t)((uintptr_t)_processor & 0xFFFFFFFF), + (uint32_t)((uintptr_t)_processor >> 32)); +} + +void +bsp_setup(void) +{ + uint64_t pd_i = _initDirectory.self.data++; + + _initDirectory.entries[pd_i] = (objdir_entry_t) { + .type = KO_OBJECT_DIRECTORY, + .data = (uintptr_t)(&s_processor_dir) + }; + _initData.processor_dir = pd_i; + + ivt_setup(); + s_enable_sce(); + + processor_setup(&s_bsp); +} + +void +rdmsr(uint32_t msr, uint32_t *lo, uint32_t *hi) +{ + __asm__ volatile("rdmsr": "=a"(*lo), "=d"(*hi): "c"(msr)); +} + +void +wrmsr(uint32_t msr, uint32_t lo, uint32_t hi) +{ + __asm__ volatile("wrmsr":: "a"(lo), "d"(hi), "c"(msr)); +} + +void* +processor_current(void) +{ + uint64_t r = 0; + rdmsr(MSR_GS_BASE, (uint32_t*)&r, ((uint32_t*)&r) + 1); + return (void*)r; +} diff --git a/arch/x86_64/savestate.s b/arch/x86_64/savestate.s new file mode 100644 index 0000000..f48b62c --- /dev/null +++ b/arch/x86_64/savestate.s @@ -0,0 +1,35 @@ +.macro pushall + pushq %rax + pushq %rbx + pushq %rcx + pushq %rdx + pushq %rsi + pushq %rdi + pushq %rbp + pushq %r8 + pushq %r9 + pushq %r10 + pushq %r11 + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 +.endm + +.macro popall + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %r11 + popq %r10 + popq %r9 + popq %r8 + popq %rbp + popq %rdi + popq %rsi + popq %rdx + popq %rcx + popq %rbx + popq %rax +.endm diff --git a/arch/x86_64/syscall.c b/arch/x86_64/syscall.c new file mode 100644 index 0000000..a563525 --- /dev/null +++ b/arch/x86_64/syscall.c @@ -0,0 +1,25 @@ +#include "arch/x86_64/processor.h" +#include <stddef.h> + +__attribute__((naked)) +void _syscall_entry(void) +{ + __asm__ volatile(" \ + pushq %%r11; \ + pushq %%rcx; \ + swapgs; \ + movq %%gs:%c[tcb], %%rax; \ + movq %%rsp, %c[sp](%%rax); \ + movq %c[ksp](%%rax), %%rsp; \ + pushq %c[sp](%%rax); \ + callq _syscall_handler; \ + swapgs; \ + popq %%rsp; \ + popq %%rcx; \ + popq %%r11; \ + sysretq;" + :: + [tcb] "i"(offsetof(processor_t, tcb)), + [sp] "i"(offsetof(tcb_t, sp)), + [ksp] "i"(offsetof(tcb_t, ksp))); +} diff --git a/arch/x86_64/untyped_memory.c b/arch/x86_64/untyped_memory.c new file mode 100644 index 0000000..699cdbf --- /dev/null +++ b/arch/x86_64/untyped_memory.c @@ -0,0 +1,54 @@ +#include "memory.h" +#include "jove.h" +#include "print.h" +#include "arch/x86_64/object.h" +#include "arch/x86_64/page.h" +#include <stddef.h> + +static struct jove_ObjectDirectory s_untyped_dir = { + .self = { .type = KO_OBJECT_DIRECTORY, .data = 1 }, +}; + +static void s_populate_tables(); + +#if defined(__limine__) + +#include "boot/limine/limine.h" +static volatile struct limine_memmap_request s_memmap_req = { + .id = LIMINE_MEMMAP_REQUEST, + .response = NULL +}; + +void +pmem_setup(void) +{ + size_t diri = _initDirectory.self.data++; + _initDirectory.entries[diri] = (objdir_entry_t) { + .type = KO_OBJECT_DIRECTORY, + .data = (uintptr_t)&s_untyped_dir + }; + _initData.untyped_data_dir = diri; + + if(s_memmap_req.response == NULL) { + klogf("Failed to load physical memory map"); + hcf(); + } + struct limine_memmap_response *response = s_memmap_req.response; + for(size_t i = 0; i < response->entry_count; i++) { + struct limine_memmap_entry *entry = response->entries[i]; + if(entry->type != LIMINE_MEMMAP_USABLE) continue; + + size_t table_index = s_untyped_dir.self.data++; + uintmax_t *untyped_data = vmem_phys_tovirt(entry->base); + objdir_entry_t *table_entry = &s_untyped_dir.entries[table_index]; + + table_entry->type = KO_MEMORY_UNTYPED; + table_entry->data = (uintptr_t)entry->base; + *untyped_data = entry->length; + + klogf("New untyped block %i at %p:%p\n", + table_index, entry->base, entry->length); + } +} + +#endif diff --git a/arch/x86_64/untyped_retype_page.c b/arch/x86_64/untyped_retype_page.c new file mode 100644 index 0000000..216d88d --- /dev/null +++ b/arch/x86_64/untyped_retype_page.c @@ -0,0 +1,51 @@ +#include "memory.h" +#include "arch/x86_64/page.h" +#include "print.h" +#include <stddef.h> + +static int +s_untyped_retype( + objdir_entry_t *untyped_entry, + size_t size, + size_t align, + void **dest) +{ + if(untyped_entry->type != KO_MEMORY_UNTYPED) return -1; + if((untyped_entry->data & (align - 1)) != 0) return -2; //EALIGN + + uintptr_t *untyped_data = vmem_phys_tovirt(untyped_entry->data); + uintmax_t untyped_size = *untyped_data; + + if(untyped_size <= size) { + return -3; + } + + *untyped_data -= size; + *dest = (void*)(untyped_entry->data + untyped_size - size); + + return 0; +} + +int untyped_retype_page(objdir_entry_t *untyped_entry, void **dest) +{ + int r = s_untyped_retype(untyped_entry, 0x1000, 0x1000, dest); + if(r != 0) return r; + + #ifdef DBG_MEM + klogf("Untyped block %p retyped to page at %p\n", untyped_entry->data, *dest); + #endif + return r; +} + +int +untyped_retype_kernel_stack(objdir_entry_t *untyped_entry, objdir_entry_t *dest_entry) +{ + int r = s_untyped_retype(untyped_entry, KERNEL_STACK_SIZE, 1, (void**)(&dest_entry->data)); + if(r != 0) return r; + + dest_entry->type = KO_KERNEL_STACK; + #ifdef DBG_MEM + klogf("Untyped block %p retyped to kernel stack at %p\n", untyped_entry->data, dest_entry->data); + #endif + return r; +} diff --git a/arch/x86_64/usermode.c b/arch/x86_64/usermode.c new file mode 100644 index 0000000..9ce5ed3 --- /dev/null +++ b/arch/x86_64/usermode.c @@ -0,0 +1,184 @@ +#include "arch/x86_64/object.h" +#include "object.h" +#include "memory.h" +#include "bootargs.h" +#include "device/initrd.h" +#include "object.h" +#include "panic.h" +#include "string.h" +#include "print.h" +#include "device/processor.h" +#include "arch/x86_64/page.h" + +static tcb_t s_init_tcb; + +//Dynamic allocation hell!!! +static uintptr_t +s_new_mapping(objdir_t *untyped_dir) +{ + objdir_entry_t *untyped_entry = NULL; + for(int i = 1; i < OBJECT_DIRECTORY_MAX_ENTRIES; i++) { + untyped_entry = &untyped_dir->entries[i]; + if(untyped_entry->type != KO_MEMORY_UNTYPED) continue; + uintptr_t mapping = 0; + int err = untyped_retype_page(untyped_entry, (void**)&mapping); + if(err != 0) continue; + return mapping; + } + return 0; +} + +static uintptr_t +s_new_kstack(objdir_t *untyped_dir, objdir_entry_t *dest_entry) +{ + objdir_entry_t *untyped_entry = NULL; + for(int i = 1; i < OBJECT_DIRECTORY_MAX_ENTRIES; i++) { + untyped_entry = &untyped_dir->entries[i]; + if(untyped_entry->type != KO_MEMORY_UNTYPED) continue; + + int err = untyped_retype_kernel_stack(untyped_entry, dest_entry); + if(err != 0) continue; + + uintptr_t ptr = dest_entry->data; + return (uintptr_t)vmem_phys_tovirt(ptr); + } + return 0; +} + +static pmle_t* +s_ensure_mapping_layer(pmle_t *pml, objdir_t *untyped_dir, uintptr_t addr, uint8_t layer) +{ + pmli_t pmli = PML_I_FOR_LAYER(addr, layer); + if(pml[pmli].p) + return pmle_get_page(pml[pmli]); + + uintptr_t table_phys = s_new_mapping(untyped_dir); + pmle_t *table = vmem_phys_tovirt(table_phys); + memset(table, 0, 0x1000); + + pml[pmli] = (pmle_t) { + .p = 1, + .rw = 1, + .us = 1, + .paddr = table_phys >> 12 + }; + __asm__ volatile("invlpg (%0)":: "r"(table_phys)); + return vmem_phys_tovirt(table_phys); +} + +static void +s_map_page(pmle_t *pml4, objdir_t *untyped_dir, uintptr_t addr) +{ + pmle_t *pml3 = s_ensure_mapping_layer(pml4, untyped_dir, addr, 4); + pmle_t *pml2 = s_ensure_mapping_layer(pml3, untyped_dir, addr, 3); + pmle_t *pml1 = s_ensure_mapping_layer(pml2, untyped_dir, addr, 2); + + pmli_t pml1i = PML_I_FOR_LAYER(addr, 1); + pmle_t *pmle = &pml1[pml1i]; + + uintptr_t pptr = s_new_mapping(untyped_dir); + + *pmle = (pmle_t) { + .p = 1, + .rw = 1, + .us = 1, + .paddr = pptr >> 12 + }; + __asm__ volatile("invlpg (%0)":: "r"(addr)); +} + +__attribute__((noreturn)) +static void +s_enter_usermode(void *ip, void *sp) +{ + __asm__ volatile("mov %0, %%rsp; \ + movq %1, %%rcx; \ + movq $0x202, %%r11; \ + cli; \ + swapgs; \ + sysretq":: + "r"(sp), "r"(ip): "memory"); + for(;;); +} + +void +init_load(void) +{ + const char *init_filename = bootargs_getarg("init"); + if(init_filename == NULL) { + kpanic("Missing boot argument \"init\""); + } + tar_header_t *init_header = initrd_find_file(init_filename); + if(init_header == NULL) { + kpanic("Init file not found in initrd. (expected \"%s\")", init_filename); + } + + size_t tcb_diri = _initDirectory.self.data++; + size_t kstack_diri = _initDirectory.self.data++; + size_t message_diri = _initDirectory.self.data++; + + _initData.tcb_object = tcb_diri; + _initData.kernel_stack_object = kstack_diri; + _initData.message_object = message_diri; + + _initDirectory.entries[tcb_diri] = (objdir_entry_t) { + .type = KO_TCB, + .data = (uintptr_t)&s_init_tcb + }; + + size_t untyped_diri = _initData.untyped_data_dir; + objdir_t *untyped_dir = (objdir_t*)_initDirectory.entries[untyped_diri].data; + + size_t pml4_diri = _initData.pm_object; + pmle_t *pml4 = vmem_phys_tovirt(_initDirectory.entries[pml4_diri].data); + + //Reserve and map pages for init binary + size_t init_size = initrd_file_size(init_header); + + size_t init_pages = (init_size >> 12); + uintptr_t init_base = 0x1000; + + for(size_t i = 0; i < init_pages + 1; i++) { + s_map_page(pml4, untyped_dir, init_base + (i * 0x1000)); + } + //Copy over init data + memcpy((void*)init_base, (&((tar_block_t*)init_header)[1])->data, init_size); + + //Create a user stack + uintptr_t stack_base = 0x00007FFFFFFFF000; + s_map_page(pml4, untyped_dir, stack_base); + uintptr_t sp = stack_base + 0xFF0; + + //Create a kernel stack for the init TCB + uintptr_t ksp_base = (uintptr_t)s_new_kstack(untyped_dir, &_initDirectory.entries[kstack_diri]); + _initDirectory.entries[kstack_diri] = (objdir_entry_t) { + .type = KO_KERNEL_STACK, + .data = ksp_base + }; + s_init_tcb.ksp = ksp_base + 0xFF0; + + processor_t *proc = (processor_t*)processor_current(); + proc->tss.rsp[0] = ksp_base; + + //Create a message object for init + uintptr_t message_base = init_base + (init_pages << 12); + message_base += ((~(message_base & 0xFFF)) & 0xFFF) + 1; + + s_map_page(pml4, untyped_dir, message_base); + _initDirectory.entries[message_diri] = (objdir_entry_t) { + .type = KO_MESSAGE, + .data = message_base + }; + _initData.message_object_address = message_base; + + //Write init data to user stack. + sp -= sizeof(init_data_t); + memcpy((void*)sp, &_initData, sizeof(init_data_t)); + sp -= sizeof(uintptr_t); + *((uintptr_t*)sp) = sp + sizeof(uintptr_t); + + //Setup usermode and jump + proc->tcb = &s_init_tcb; + proc->tss.rsp[0] = s_init_tcb.ksp; + s_enter_usermode((void*)init_base, (void*)sp); +} |