diff options
| author | Jon Santmyer <jon@jonsantmyer.com> | 2026-09-04 11:31:40 -0400 |
|---|---|---|
| committer | Jon Santmyer <jon@jonsantmyer.com> | 2026-09-04 11:31:40 -0400 |
| commit | 8251da342161767fe203627223ccd4a7026701c6 (patch) | |
| tree | af2db0f11b0ea8ad35f88663a855bab39a80f679 /arch/x86_64/hal | |
| download | jove-kernel-8251da342161767fe203627223ccd4a7026701c6.tar.gz jove-kernel-8251da342161767fe203627223ccd4a7026701c6.tar.bz2 jove-kernel-8251da342161767fe203627223ccd4a7026701c6.zip | |
initial commit. working on tasking
Diffstat (limited to 'arch/x86_64/hal')
| -rw-r--r-- | arch/x86_64/hal/gdt.c | 81 | ||||
| -rw-r--r-- | arch/x86_64/hal/gdt.h | 48 | ||||
| -rw-r--r-- | arch/x86_64/hal/idt.c | 53 | ||||
| -rw-r--r-- | arch/x86_64/hal/idt.h | 66 | ||||
| -rw-r--r-- | arch/x86_64/hal/idt_entries.s | 127 | ||||
| -rw-r--r-- | arch/x86_64/hal/lxdt.s | 26 | ||||
| -rw-r--r-- | arch/x86_64/hal/msr.c | 52 | ||||
| -rw-r--r-- | arch/x86_64/hal/msr.h | 48 | ||||
| -rw-r--r-- | arch/x86_64/hal/obj.c | 87 | ||||
| -rw-r--r-- | arch/x86_64/hal/obj.h | 79 | ||||
| -rw-r--r-- | arch/x86_64/hal/paging.c | 174 | ||||
| -rw-r--r-- | arch/x86_64/hal/paging.h | 52 | ||||
| -rw-r--r-- | arch/x86_64/hal/port.h | 12 | ||||
| -rw-r--r-- | arch/x86_64/hal/process.c | 35 | ||||
| -rw-r--r-- | arch/x86_64/hal/process.h | 34 | ||||
| -rw-r--r-- | arch/x86_64/hal/serial_com.c | 92 | ||||
| -rw-r--r-- | arch/x86_64/hal/serial_com.h | 26 | ||||
| -rw-r--r-- | arch/x86_64/hal/smp.c | 65 | ||||
| -rw-r--r-- | arch/x86_64/hal/smp.h | 18 |
19 files changed, 1175 insertions, 0 deletions
diff --git a/arch/x86_64/hal/gdt.c b/arch/x86_64/hal/gdt.c new file mode 100644 index 0000000..a64bdc1 --- /dev/null +++ b/arch/x86_64/hal/gdt.c @@ -0,0 +1,81 @@ +#include "gdt.h" +#include "smp.h" +#include "lib/string.h" + +static struct gdt_entry _gdt[GDT_TSS_HI+1] = +{ + [GDT_KERNEL_NULL] = { 0 }, + [GDT_KERNEL_CODE] = (struct gdt_entry) { + .limit_0_15 = 0xFFFF, + .base_0_15 = 0x0, + .base_16_23 = 0x0, + .type_flg = 0b10011010, + .limit_flg = 0b10101111, + .base_24_31 = 0x0 + }, + [GDT_KERNEL_DATA] = (struct gdt_entry) { + .limit_0_15 = 0xFFFF, + .base_0_15 = 0x0, + .base_16_23 = 0x0, + .type_flg = 0b10010010, + .limit_flg = 0b10101111, + .base_24_31 = 0x0 + }, + [GDT_USER_NULL] = { 0 }, + [GDT_USER_DATA] = (struct gdt_entry) { + .limit_0_15 = 0xFFFF, + .base_0_15 = 0x0, + .base_16_23 = 0x0, + .type_flg = 0b11110010, + .limit_flg = 0b10101111, + .base_24_31 = 0x0 + }, + [GDT_USER_CODE] = (struct gdt_entry) { + .limit_0_15 = 0xFFFF, + .base_0_15 = 0x0, + .base_16_23 = 0x0, + .type_flg = 0b11111010, + .limit_flg = 0b10101111, + .base_24_31 = 0x0 + }, + [GDT_TSS_LO] = (struct gdt_entry) { + .limit_0_15 = 0x0, + .base_0_15 = 0x0, + .base_16_23 = 0x0, + .type_flg = 0x89, + .limit_flg = 0x0, + .base_24_31 = 0x0 + }, + [GDT_TSS_HI] = { 0 } +}; + +void +gdt_setup(processor_t *processor) +{ + memcpy(processor->gdt, _gdt, sizeof(struct gdt_entry) * (GDT_TSS_HI+1)); + + struct gdt_descriptor gdtr; + gdtr.base = (uintptr_t)&processor->gdt; + gdtr.limit = sizeof(struct gdt_entry) * (GDT_TSS_HI+1) - 1; + + extern void load_gdt(struct gdt_descriptor *gdtr); + load_gdt(&gdtr); + + uintptr_t tss_base = (uintptr_t)&processor->tss; + size_t tss_limit = sizeof(struct tss); + + struct gdt_entry *tss_lo = &processor->gdt[GDT_TSS_LO]; + struct gdt_entry *tss_hi = &processor->gdt[GDT_TSS_HI]; + + tss_lo->base_0_15 = (uint16_t)(tss_base & 0xFFFF); + tss_lo->base_16_23 = (uint8_t)((tss_base >> 16) & 0xFF); + tss_lo->base_24_31 = (uint8_t)((tss_base >> 24) & 0xFF); + tss_hi->limit_0_15 = (uint16_t)((tss_base >> 32) & 0xFFFF); + tss_hi->base_0_15 = (uint16_t)((tss_base >> 48) & 0xFFFF); + + tss_lo->limit_0_15 = (uint16_t)(tss_limit & 0xFFFF); + tss_lo->limit_flg |= (uint8_t)((tss_limit >> 16) & 0xF); + + extern void load_tss(void); + load_tss(); +} diff --git a/arch/x86_64/hal/gdt.h b/arch/x86_64/hal/gdt.h new file mode 100644 index 0000000..7fb7dfc --- /dev/null +++ b/arch/x86_64/hal/gdt.h @@ -0,0 +1,48 @@ +#ifndef _JOVE_x86_64_HAL_GDT_H +#define _JOVE_x86_64_HAL_GDT_H 1 + +#include <stddef.h> +#include <stdint.h> +#include "jove.h" + +enum { + GDT_KERNEL_NULL = 0, + GDT_KERNEL_CODE, + GDT_KERNEL_DATA, + GDT_USER_NULL, + GDT_USER_DATA, + GDT_USER_CODE, + GDT_TSS_LO, + GDT_TSS_HI +}; + +#define GDT_OFFSET(i) (i << 3) + +struct gdt_entry +{ + uint16_t limit_0_15; + uint16_t base_0_15; + uint8_t base_16_23; + uint8_t type_flg; + uint8_t limit_flg; + uint8_t base_24_31; +}; + +struct tss +{ + uint32_t rsv0; + uint64_t rsp[3]; + uint64_t rsv1; + uint64_t ist[7]; + uint64_t rsv2; + uint16_t rsv3; + uint16_t iopb; +} PACKED; + +struct gdt_descriptor +{ + uint16_t limit; + uint64_t base; +} PACKED; + +#endif diff --git a/arch/x86_64/hal/idt.c b/arch/x86_64/hal/idt.c new file mode 100644 index 0000000..b2251bd --- /dev/null +++ b/arch/x86_64/hal/idt.c @@ -0,0 +1,53 @@ +#include "idt.h" +#include "smp.h" +#include "gdt.h" +#include "jove.h" +#include "lib/printf.h" + +ALIGN(8) +static struct idt_entry s_idt[IDT_ENTRIES]; + +typedef void (*isr_t)(void); +extern isr_t __isrs[IDT_ENTRIES]; + +typedef struct int_stackframe *(*int_handler_t)(struct int_stackframe*); +int_handler_t __int_handles[IDT_ENTRIES]; + +static struct int_stackframe* +s_int_handle_stub(struct int_stackframe* frame) +{ + kprintf("Unhandled interrupt %i at %p\n", frame->int_num, frame->int_rip); + hcf(); +} + +void +idt_init(void) +{ + for(size_t i = 0; i < IDT_ENTRIES; i++) { + uintptr_t isr = (uintptr_t)(__isrs[i]); + + s_idt[i] = (struct idt_entry) { + .offset_0_15 = (uint16_t)(isr & 0xFFFF), + .segment_selector = GDT_KERNEL_CODE * 8, + .ist = 0, + .type = IDT_INTERRUPT_GATE, + .dpl = 0, + .p = 1, + .offset_16_31 = (uint16_t)((isr >> 16) & 0xFFFF), + .offset_32_63 = (uint32_t)(isr >> 32) + }; + + __int_handles[i] = s_int_handle_stub; + } +} + +void +idt_setup(processor_t *processor) +{ + struct idt_descriptor idtr = (struct idt_descriptor) { + .limit = sizeof(struct idt_entry) * IDT_ENTRIES - 1, + .base = (uint64_t)&s_idt + }; + + __asm__ volatile("lidt %0":: "m"(idtr)); +} diff --git a/arch/x86_64/hal/idt.h b/arch/x86_64/hal/idt.h new file mode 100644 index 0000000..961e720 --- /dev/null +++ b/arch/x86_64/hal/idt.h @@ -0,0 +1,66 @@ +#ifndef _JOVE_x86_64_HAL_IDT_H +#define _JOVE_x86_64_HAL_IDT_H 1 + +#include <stdint.h> +#include "jove.h" +#include "../x86_64.h" + +struct idt_entry +{ + uint16_t offset_0_15; + uint16_t segment_selector; + union { + struct { + uint8_t ist : 3; + uint8_t zero_1 : 5; + uint8_t type : 4; + uint8_t zero_2 : 1; + uint8_t dpl : 2; + uint8_t p : 1; + }; + uint16_t flags; + }; + uint16_t offset_16_31; + uint32_t offset_32_63; + uint32_t resv; +}; + +#define IDT_INTERRUPT_GATE 0xE + +struct idt_descriptor +{ + uint16_t limit; + uint64_t base; +} PACKED; + +struct int_stackframe +{ + struct cpu_state state; + uint64_t int_num, int_err; + uint64_t int_rip, int_cs, int_flags, int_rsp, int_rss; +}; + +#define IDT_ENTRIES 48 + +#define IDT_EXCEPT_DE 0 +#define IDT_EXCEPT_DB 1 +#define IDT_EXCEPT_NMI 2 +#define IDT_EXCEPT_BP 3 +#define IDT_EXCEPT_OF 4 +#define IDT_EXCEPT_BR 5 +#define IDT_EXCEPT_UD 6 +#define IDT_EXCEPT_NM 7 +#define IDT_EXCEPT_DF 8 +#define IDT_EXCEPT_TS 10 +#define IDT_EXCEPT_NP 11 +#define IDT_EXCEPT_SS 12 +#define IDT_EXCEPT_GP 13 +#define IDT_EXCEPT_PF 14 +#define IDT_EXCEPT_MF 16 +#define IDT_EXCEPT_AC 17 +#define IDT_EXCEPT_MC 18 +#define IDT_EXCEPT_XM 19 +#define IDT_EXCEPT_VE 20 +#define IDT_EXCEPT_CP 21 + +#endif diff --git a/arch/x86_64/hal/idt_entries.s b/arch/x86_64/hal/idt_entries.s new file mode 100644 index 0000000..204fa93 --- /dev/null +++ b/arch/x86_64/hal/idt_entries.s @@ -0,0 +1,127 @@ +.section .text +.macro push_state + 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 pop_state + 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 + +.macro swapgs_if_necessary + cmpq $0x08, 0x8(%rsp) + je 1f + swapgs +1: +.endm + +.extern __int_handles +.type __isr_header @function +__isr_header: + push_state + cld + + movq %rsp, %rdi + +isr_break: + movq 0x78(%rdi), %rax + movq __int_handles(,%rax,8), %rbx + call %rbx + + pop_state + addq $16, %rsp + swapgs_if_necessary + iretq +.size __isr_header, . - __isr_header + +.macro defn_isr_err num:req +.type __isr\num @function +__isr\num: + swapgs_if_necessary + pushq $\num + jmp __isr_header +.size __isr\num, . - __isr\num +.endm + +.macro defn_isr num:req +.type __isr\num @function +__isr\num: + swapgs_if_necessary + pushq $0 + pushq $\num + jmp __isr_header +.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 48-22 + defn_isr %i + .set i, i+1 +.endr + +.section .data + +.global __isrs +.type __isrs @object +__isrs: + .set i, 0 + .rept 48 + decl_isr %i + .set i, i+1 + .endr +.size __isrs, . - __isrs diff --git a/arch/x86_64/hal/lxdt.s b/arch/x86_64/hal/lxdt.s new file mode 100644 index 0000000..1591599 --- /dev/null +++ b/arch/x86_64/hal/lxdt.s @@ -0,0 +1,26 @@ +.global load_gdt +.type load_gdt @function +load_gdt: + lgdt (%rdi) +.reload_segments: + pushq $0x8 + leaq .reload_cs(%rip), %rax + pushq %rax + retfq +.reload_cs: + movw $0x10, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + retq +.size load_gdt, . - load_gdt + +.global load_tss +.type load_tss @function +load_tss: + movw $0x30, %ax + ltr %ax + retq +.size load_tss, . - load_tss diff --git a/arch/x86_64/hal/msr.c b/arch/x86_64/hal/msr.c new file mode 100644 index 0000000..f27e303 --- /dev/null +++ b/arch/x86_64/hal/msr.c @@ -0,0 +1,52 @@ +#include "msr.h" +#include "gdt.h" + +void +msr_read(uint32_t msr, uint32_t *lo, uint32_t *hi) +{ + __asm__ volatile("rdmsr": "=a"(*lo), "=d"(*hi): "c"(msr)); +} + +void +msr_write(uint32_t msr, uint32_t lo, uint32_t hi) +{ + __asm__ volatile("wrmsr":: "a"(lo), "c"(msr), "d"(hi)); +} + +void +msr_set_gs_base(uintptr_t gs) +{ + union msr_gs_base gs_base = { .gs = gs }; + msr_write(MSR_GS_BASE, gs_base.v[0], gs_base.v[1]); +} + +uintptr_t +msr_get_gs_base(void) +{ + union msr_gs_base gs_base; + msr_read(MSR_GS_BASE, &gs_base.v[0], &gs_base.v[1]); + return gs_base.gs; +} + +void +msr_enable_sce(void) +{ + uint32_t efer[2]; + msr_read(MSR_EFER, &efer[0], &efer[1]); + + efer[0] |= MSR_EFER_SCE; + msr_write(MSR_EFER, efer[0], efer[1]); + + union msr_star star; + star.kcs = GDT_OFFSET(GDT_KERNEL_CODE); + star.ucs = GDT_OFFSET(GDT_USER_CODE); + msr_write(MSR_STAR, star.v[0], star.v[1]); +} + +void +msr_set_lstar(void *lstar_value) +{ + union msr_lstar lstar; + lstar.rip = lstar_value; + msr_write(MSR_LSTAR, lstar.v[0], lstar.v[1]); +} diff --git a/arch/x86_64/hal/msr.h b/arch/x86_64/hal/msr.h new file mode 100644 index 0000000..69d96be --- /dev/null +++ b/arch/x86_64/hal/msr.h @@ -0,0 +1,48 @@ +#ifndef _JOVE_x86_64_HAL_MSR_H +#define _JOVE_x86_64_HAL_MSR_H 1 + +#include <stdint.h> + +#define MSR_FS_BASE 0xC0000100 +#define MSR_GS_BASE 0xC0000101 +#define MSR_KGS_BASE 0xC0000102 + +#define MSR_EFER 0xC0000080 +#define MSR_EFER_SCE 0b1 + +#define MSR_STAR 0xC0000081 +#define MSR_LSTAR 0xC0000082 +#define MSR_SFMASK 0xC0000084 + +union msr_gs_base +{ + uintptr_t gs; + uint32_t v[2]; +}; + +union msr_star +{ + struct { + uint32_t eip; + uint16_t kcs; + uint16_t ucs; + }; + uint16_t v[2]; +}; + +union msr_lstar +{ + void *rip; + uint32_t v[2]; +}; + +void msr_set_gs_base(uintptr_t gs_base); +uintptr_t msr_get_gs_base(void); + +void msr_enable_sce(void); +void msr_set_lstar(void *syscall_entry); + +void msr_read(uint32_t msr, uint32_t *lo, uint32_t *hi); +void msr_write(uint32_t msr, uint32_t lo, uint32_t hi); + +#endif diff --git a/arch/x86_64/hal/obj.c b/arch/x86_64/hal/obj.c new file mode 100644 index 0000000..783d2f4 --- /dev/null +++ b/arch/x86_64/hal/obj.c @@ -0,0 +1,87 @@ +#include "obj.h" +#include "arch/x86_64/lock.h" +#include "hal/obj.h" +#include "jove.h" + +jove_owned_obj_t* +obj_take(jove_obj_t *obj) +{ + take_mutex(&obj->lock); + return (jove_owned_obj_t*)obj; +} + +jove_obj_t* +obj_release(jove_owned_obj_t *obj) +{ + release_mutex((atomic_flag*)&obj->lock); + return (jove_obj_t*)obj; +} + +void* +obj_deref(jove_owned_obj_t *obj) +{ + return (void*)(((uintptr_t)obj_getvalue(obj)) | 0xFFFF800000000000ULL); +} + +uint8_t +obj_gettype(jove_owned_obj_t *obj) +{ + return obj->type; +} + +void +obj_settype(jove_owned_obj_t *obj, uint8_t type) +{ + obj->type = type; +} + +uintmax_t +obj_getvalue(jove_owned_obj_t *obj) +{ + return obj->value; +} + +void +obj_setvalue(jove_owned_obj_t *obj, uintmax_t value) +{ + obj->value = value & 0x00007FFFFFFFFFFFULL; +} + +jove_obj_t* +objdir_getlocal( + jove_owned_obj_t *objdir_obj, + uint16_t entry) +{ + if(objdir_obj->type != JOVE_OBJ_OBJDIR) { + reterr(EBADOBJ); + } + if(entry >= JOVE_OBJDIR_ENTRIES) { + reterr(EOOB); + } + + jove_objdir_t *objtab = obj_deref(objdir_obj); + return &objtab->entries[entry]; +} + +jove_owned_obj_t* +objdir_getobj( + jove_owned_obj_t *objdir_obj, + const uint16_t *path, + size_t path_len) +{ + if(path_len == 0) { + return objdir_obj; + } + { + jove_obj_t *child_locked_objdir = objdir_getlocal(objdir_obj, path[0]); + if(child_locked_objdir == NULL) { + return 0; + } + + jove_owned_obj_t *child_objdir = obj_take(child_locked_objdir); + jove_owned_obj_t *target_obj = objdir_getobj(child_objdir, path + 1, path_len - 1); + obj_release(child_objdir); + return target_obj; + } +} + diff --git a/arch/x86_64/hal/obj.h b/arch/x86_64/hal/obj.h new file mode 100644 index 0000000..645727d --- /dev/null +++ b/arch/x86_64/hal/obj.h @@ -0,0 +1,79 @@ +#ifndef _JOVE_ARCH_HAL_OBJ_H +#define _JOVE_ARCH_HAL_OBJ_H 1 + +#include <stdatomic.h> +#include <stdint.h> +#include <stddef.h> + +enum +{ + JOVE_OBJ_SERIAL_COM = 0x81, + JOVE_OBJ_PAGE_FRAME, + JOVE_OBJ_PAGE_MAPPING, +}; + +/*Represents a locked kernel object pointer inside of a object directory.*/ +typedef union jove_obj +{ + struct { + uint8_t type; + atomic_flag lock; + /*Raw value or pointer to a data-structure located in kernel memory.*/ + uint64_t value : 48; + }; + uintmax_t data; +} jove_obj_t; + +/*Represents an unlocked kernel object pointer. + *This object should only exist temporarily while accessing the underlying + *structure this object points to.*/ +typedef union jove_obj_locked +{ + struct { + uint8_t type; + uint8_t lock; + uint64_t value : 48; + }; + uintmax_t data; +} jove_owned_obj_t; + +/*Object directories are always 1 page wide. Since an object inside the directory + * is a pointer width, on x86_64 that is 512 entries per directory.*/ +#define JOVE_OBJDIR_SIZE 0x1000 +#define JOVE_OBJDIR_ENTRIES (JOVE_OBJDIR_SIZE / sizeof(jove_obj_t)) + +typedef struct jove_objdir +{ + jove_obj_t entries[JOVE_OBJDIR_ENTRIES]; +} jove_objdir_t; +/*Locks the mutex of the kernel object provided. Returns the locked version. */ +jove_owned_obj_t *obj_take(jove_obj_t *obj); +/*Unlocks the mutex of the kernel object provided. Returns the unlocked version. */ +jove_obj_t *obj_release(jove_owned_obj_t *obj); + +/*Converts the value pointer of the object into a pointer to kernel memory.*/ +void *obj_deref(jove_owned_obj_t *obj); + +/*Getters and setters for accessing the type field of the kernel object. */ +uint8_t obj_gettype(jove_owned_obj_t *obj); +void obj_settype(jove_owned_obj_t *obj, uint8_t type); + +/*Getters and setters for accessing the value field of the kernel object. */ +uintmax_t obj_getvalue(jove_owned_obj_t *obj); +void obj_setvalue(jove_owned_obj_t *obj, uintmax_t value); + +/*Returns the n'th entry of the object directory passed. + * If the passed object is not an objdir, returns NULL and sets errno to EBADOBJ. + * If the passed entry index is out of bounds, returns NULL and sets errno to EOOB.*/ +jove_obj_t *objdir_getlocal(jove_owned_obj_t *objdir_obj, uint16_t entry); + +/*Recursively seeks through an object directory for an object following the passed + * path variable. + * If the path length is zero, returns the passed object. + * If the passed object is not an objdir, returns NULL and sets errno to EBADOBJ. + * If any object excluding the object at the end of the path is not an objdir, + * returns NULL and sets errno to EBADOBJ. + * If any entry in the path is out of bounds, returns NULL and sets errno to EBADOBJ.*/ +jove_owned_obj_t *objdir_getobj(jove_owned_obj_t *objdir_obj, const uint16_t *path, size_t path_len); + +#endif diff --git a/arch/x86_64/hal/paging.c b/arch/x86_64/hal/paging.c new file mode 100644 index 0000000..c1a22a2 --- /dev/null +++ b/arch/x86_64/hal/paging.c @@ -0,0 +1,174 @@ +#include "paging.h" +#include "arch/x86_64/x86_64.h" +#include "jove.h" +#include "config.h" +#include "smp.h" +#include "lib/string.h" +#include "lib/printf.h" +#include "lib/panic.h" +#include "idt.h" + +PAGEALIGN page_t _kernel_pml4[512]; +PAGEALIGN page_t _kernel_pml3[512]; +PAGEALIGN page_t _kernel_pml2[512]; +PAGEALIGN page_t _kernel_pml1[512]; + +#define IDENT_HUGEPAGES ((PHYS_BIGPAGES_MAX + 511) / 512) +#define IDENT_GIANTPAGES ((IDENT_HUGEPAGES + 511) / 512) + +PAGEALIGN static page_t ident_pml3[IDENT_GIANTPAGES][512]; +PAGEALIGN static page_t ident_pml2[IDENT_HUGEPAGES][512]; + +void* +phys_tovirt(uintptr_t phys) +{ + return (void*)(phys | IDENT_VIRT_BASE); +} + +uintptr_t +paging_get_pml4(void) +{ + uintptr_t ret = 0; + __asm__ volatile("movq %%cr3, %0": "=r"(ret)); + return ret; +} + +void +paging_pml4_switch(uintptr_t pml4) +{ + __asm__ volatile("movq %0, %%cr3":: "r"(pml4)); +} + +static struct int_stackframe* +s_int_handle_pf_early(struct int_stackframe *frame) +{ + extern int _kernel_panic_unlock; + _kernel_panic_unlock = 1; + + union { + struct { + uint8_t p : 1; + uint8_t wr : 1; + uint8_t us : 1; + uint8_t rsvd : 1; + uint8_t id : 1; + uint8_t pk : 1; + }; + uint64_t value; + } pf_error = { .value = frame->int_err }; + + kprintf("Kernel has encountered a page fault exception early in initializaiton\n"); + kprintf("%s %s during %s\n", + pf_error.wr ? "Wrote to" : "Read from", + pf_error.p ? "Present" : "Non-present", + pf_error.id ? "Instruction fetch" : "Data access"); + uintptr_t cr2 = 0; + __asm__ volatile("movq %%cr2, %0": "=r"(cr2)); + kprintf("Faulting address: %p\n", cr2); + kprintf("RIP: %p | RSP: %p\n", frame->int_rip, frame->int_rsp); + print_state(&frame->state); + + hcf(); +} + +void +paging_pml4_init(void) +{ + //Setup kernel pages + memset(_kernel_pml4, 0, 0x1000); + memset(_kernel_pml3, 0, 0x1000); + memset(_kernel_pml2, 0, 0x1000); + memset(_kernel_pml1, 0, 0x1000); + + /*Paging entries depend on physical addresses to properly map. + * Since the virtual kernel address differs from the physical memory address, + * we need to convert the pointers using the physical memory pointer passed + * to us by the bootloader.*/ + uintptr_t kernel_pml4_pptr = KPTR_TOPHYS((uintptr_t)_kernel_pml4); + uintptr_t kernel_pml3_pptr = KPTR_TOPHYS((uintptr_t)_kernel_pml3); + uintptr_t kernel_pml2_pptr = KPTR_TOPHYS((uintptr_t)_kernel_pml2); + uintptr_t kernel_pml1_pptr = KPTR_TOPHYS((uintptr_t)_kernel_pml1); + + /*Maps pml4-2 as global writeable pages.*/ + _kernel_pml4[511].value = kernel_pml3_pptr | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_GLOBAL; + _kernel_pml3[510].value = kernel_pml2_pptr | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_GLOBAL; + _kernel_pml2[0].value = kernel_pml1_pptr | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_GLOBAL; + + /*text*/ + extern void *_kernel_text_start; + extern void *_kernel_text_end; + uintptr_t kernel_text_start_pptr = KPTR_TOPHYS((uintptr_t)&_kernel_text_start); + uintptr_t kernel_text_end_pptr = KPTR_TOPHYS((uintptr_t)&_kernel_text_end); + size_t kernel_text_pages = ((kernel_text_end_pptr - kernel_text_start_pptr) / 0x1000) + 1; + + uintptr_t kernel_text_off = (((uintptr_t)&_kernel_text_start) - KERNEL_VIRT_BASE) >> 12; + + for(size_t i = 0; i < kernel_text_pages; i++) { + size_t off = i + kernel_text_off; + uintptr_t page_off = kernel_text_start_pptr + (i << 12); + _kernel_pml1[off].value = page_off | PAGE_PRESENT | PAGE_GLOBAL; + } + + /*rodata*/ + extern void *_kernel_rodata_start; + extern void *_kernel_rodata_end; + uintptr_t kernel_rodata_start_pptr = KPTR_TOPHYS((uintptr_t)&_kernel_rodata_start); + uintptr_t kernel_rodata_end_pptr = KPTR_TOPHYS((uintptr_t)&_kernel_rodata_end); + size_t kernel_rodata_pages = ((kernel_rodata_end_pptr - kernel_rodata_start_pptr) / 0x1000) + 1; + + uintptr_t kernel_rodata_off = kernel_text_off + kernel_text_pages; + for(size_t i = 0; i < kernel_rodata_pages; i++) { + size_t off = i + kernel_rodata_off; + uintptr_t page_off = kernel_text_start_pptr + (off << 12); + _kernel_pml1[off].value = page_off | PAGE_PRESENT | PAGE_GLOBAL | PAGE_XD; + } + + /*data/bss*/ + extern void *_kernel_data_start; + extern void *_kernel_bss_end; + uintptr_t kernel_data_start_pptr = KPTR_TOPHYS((uintptr_t)&_kernel_data_start); + uintptr_t kernel_data_end_pptr = KPTR_TOPHYS((uintptr_t)&_kernel_bss_end); + size_t kernel_data_pages = ((kernel_data_end_pptr - kernel_data_start_pptr) / 0x1000) + 1; + + uintptr_t kernel_data_off = kernel_rodata_off + kernel_rodata_pages; + for(size_t i = 0; i < kernel_data_pages; i++) { + size_t off = i + kernel_data_off; + uintptr_t page_off = kernel_text_start_pptr + (off << 12); + _kernel_pml1[off].value = page_off | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_GLOBAL | PAGE_XD; + } + + /*Identity pages are mapped as huge pages starting at the 256'th PML3 entry. + *We want to support any range of physical memory up to several TiB, so + *the mapper has to consider multiple heirarchies of huge pages.*/ + for(size_t l3 = 0; l3 < IDENT_GIANTPAGES; l3++) { + memset(ident_pml3[l3], 0, 0x1000); + uintptr_t ident_pml3_pptr = KPTR_TOPHYS((uintptr_t)ident_pml3[l3]); + + _kernel_pml4[256 + l3].value = ident_pml3_pptr | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_GLOBAL; + } + + for(size_t l2 = 0; l2 < IDENT_HUGEPAGES; l2++) { + size_t l3 = l2 / 512; + size_t l2_mod = l2 % 512; + + memset(ident_pml2[l2], 0, 0x1000); + uintptr_t ident_pml2_pptr = KPTR_TOPHYS((uintptr_t)ident_pml2[l2]); + + ident_pml3[l3][l2_mod].value = ident_pml2_pptr | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_GLOBAL; + } + + for(size_t l1 = 0; l1 < PHYS_BIGPAGES_MAX; l1++) { + size_t l2 = l1 / 512; + size_t l1_mod = l1 % 512; + + ident_pml2[l2][l1_mod].value = (l1 << 21) | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_PS | PAGE_GLOBAL; + ident_pml2[l2][l1_mod].xd = 1; + } + + paging_pml4_switch(kernel_pml4_pptr); + + /*Before tasking, if the kernel has a bug and crashes we need some + * information about what happened.*/ + extern struct int_stackframe *(*__int_handles[])(struct int_stackframe*); + __int_handles[IDT_EXCEPT_PF] = s_int_handle_pf_early; +} diff --git a/arch/x86_64/hal/paging.h b/arch/x86_64/hal/paging.h new file mode 100644 index 0000000..54df1eb --- /dev/null +++ b/arch/x86_64/hal/paging.h @@ -0,0 +1,52 @@ +#ifndef _JOVE_x86_64_HAL_PAGING_H +#define _JOVE_x86_64_HAL_PAGING_H 1 + +#include "jove.h" +#include <stdint.h> + +typedef union page_table_entry +{ + struct { + uint8_t p : 1; + uint8_t rw : 1; + uint8_t u : 1; + uint8_t pwt : 1; + uint8_t pcd : 1; + uint8_t a : 1; + uint8_t d : 1; + uint8_t ps : 1; + uint8_t g : 1; + uint8_t ign_0 : 2; + uint8_t r : 1; + uint64_t paddr : 35; + uint8_t ign_1 : 4; + uint8_t pkey : 4; + uint8_t xd : 1; + }; + uint64_t value; +} PACKED page_t; + +#define PAGE_PRESENT 0b1 +#define PAGE_WRITEABLE 0b10 +#define PAGE_USER 0b100 +#define PAGE_WRITETHROUGH 0b1000 +#define PAGE_CACHEDISABLE 0b10000 +#define PAGE_ACCESSED 0b100000 +#define PAGE_DIRTY 0b1000000 +#define PAGE_PS 0b10000000 +#define PAGE_GLOBAL 0b100000000 +#define PAGE_XD (1ULL << 63) + +extern void *_kernel_physptr; + +#define PMLI_SHL(l) (12 + (l * 9)) +#define PMLI_MASK(l) (~0xFFFF << PMLI_SHL(l)) + +#define IDENT_VIRT_BASE 0xFFFF800000000000ULL +#define KERNEL_VIRT_BASE 0xFFFFFFFF80000000ULL +#define KPTR_TOPHYS(v) (v - KERNEL_VIRT_BASE + (uintptr_t)_kernel_physptr) + +uintptr_t paging_get_pml4(void); +void paging_pml4_init(void); + +#endif diff --git a/arch/x86_64/hal/port.h b/arch/x86_64/hal/port.h new file mode 100644 index 0000000..6dbc27c --- /dev/null +++ b/arch/x86_64/hal/port.h @@ -0,0 +1,12 @@ +#ifndef _JOVE_PORT_H +#define _JOVE_PORT_H 1 + +#include <stdint.h> + +static inline uint8_t inb(uint16_t port) +{ uint8_t r; __asm__ volatile("inb %w1, %b0": "=a"(r): "Nd"(port): "memory"); return r; } + +static inline void outb(uint16_t port, uint8_t v) +{ __asm__ volatile("outb %b0, %w1":: "a"(v), "Nd"(port): "memory"); } + +#endif diff --git a/arch/x86_64/hal/process.c b/arch/x86_64/hal/process.c new file mode 100644 index 0000000..dd49456 --- /dev/null +++ b/arch/x86_64/hal/process.c @@ -0,0 +1,35 @@ +#include "process.h" +#include "arch/x86_64/hal/obj.h" +#include "hal/obj.h" +#include "init.h" +#include "smp.h" +#include "paging.h" +#include "jove.h" + +PAGEALIGN char s_init_pcb_bytes[0x1000] = { 0 }; +static pcb_t *s_init_pcb = (pcb_t*)&s_init_pcb_bytes; + +void +processing_setup(void (*process_main)) +{ + uintptr_t ksp = (uintptr_t)&s_init_pcb_bytes + 8; + s_init_pcb->ksp = (void*)ksp; + s_init_pcb->pml4 = paging_get_pml4(); + + processor_t *proc = processor_current(); + proc->pcb = s_init_pcb; + proc->tss.rsp[0] = (uintptr_t)s_init_pcb->ksp; + + { + jove_owned_obj_t *process_obj = obj_take(objdir_getlocal(_rootdir_obj, ROOTDIR_PCB_I)); + obj_settype(process_obj, JOVE_OBJ_PROCESS); + obj_setvalue(process_obj, (uintptr_t)s_init_pcb); + obj_release(process_obj); + } + + __asm__ volatile("\ + movq %0, %%rsp; \ + movq $0, %%rbp; \ + jmpq %1":: + "r"(s_init_pcb->ksp), "r"(process_main)); +} diff --git a/arch/x86_64/hal/process.h b/arch/x86_64/hal/process.h new file mode 100644 index 0000000..0c0fb5b --- /dev/null +++ b/arch/x86_64/hal/process.h @@ -0,0 +1,34 @@ +#ifndef _JOVE_x86_64_HAL_PROCESS_H +#define _JOVE_x86_64_HAL_PROCESS_H 1 + +#include "hal/obj.h" +#include "arch/x86_64/x86_64.h" + +enum pcb_state +{ + PCB_DEAD, PCB_READY, PCB_RUNNING, PCB_BLOCKED +}; + +struct pcb_mailbox +{ + jove_obj_t *obj; + uintmax_t pcbid; +}; + +typedef struct process_control_block +{ + jove_obj_t *rootdir; + uintptr_t pml4; + + enum pcb_state state; + int killed; + struct pcb_mailbox send, recv; + + struct cpu_context context; + void *ksp; + char kstack[]; +} pcb_t; + +#define PCB_KSTACK_SIZE (0x1000 - sizeof(pcb_t)) + +#endif diff --git a/arch/x86_64/hal/serial_com.c b/arch/x86_64/hal/serial_com.c new file mode 100644 index 0000000..3967cd7 --- /dev/null +++ b/arch/x86_64/hal/serial_com.c @@ -0,0 +1,92 @@ +#include "serial_com.h" +#include "port.h" +#include "jove.h" +#include "hal/obj.h" +#include "init.h" +#include "lib/printf.h" + +static int +serial_com_recv(uint16_t port) +{ + return inb(SERIAL_COM_LSR(port)) & 1; +} + +static char +serial_com_getc(uint16_t port) +{ + while(serial_com_recv(port) == 0); + return inb(port); +} + +static int +serial_com_put_ready(uint16_t port) +{ + return inb(SERIAL_COM_LSR(port)) & 0x20; +} + +static void +serial_com_putc(uint16_t port, char c) +{ + while(serial_com_put_ready(port) == 0); + outb(port, c); +} + +int +serial_com_init_port( + uint16_t port, + uint16_t baud_divisor) +{ + uint8_t div_low = (uint8_t)baud_divisor; + uint8_t div_high = (uint8_t)(baud_divisor >> 8); + + outb(SERIAL_COM_IER(port), 0x00); // Disable all interrupts + outb(SERIAL_COM_LCR(port), 0x80); // Enable DLAB mode. + outb(SERIAL_COM_DLAB_BAUD_LO(port), div_low); + outb(SERIAL_COM_DLAB_BAUD_HI(port), div_high); + outb(SERIAL_COM_LCR(port), 0x03); // 8 bits, no parity, one stop bit. + outb(SERIAL_COM_FIFO(port), 0xC7); // Enable FIFO, clear them, 14 byte threshold. + outb(SERIAL_COM_MCR(port), 0x0B); // Enable IRQs, set RTS/DSR. + + //Test to check if the serial port actually works. + outb(SERIAL_COM_MCR(port), 0x1E); // Set loopback mode. + outb(port, 0xAE); // Send test byte. + if(inb(port) != 0xAE) { + return 1; + } + + //Set the port to normal operation mode. + //(no loopback, IRQs enabled, OUT#1 and OUT#2 enabled.) + outb(SERIAL_COM_MCR(port), 0x0F); + return 0; +} + +void +serial_com_init(void) +{ + if(serial_com_init_port(SERIAL_COM1, 3)) { + hcf(); + } + + { + jove_owned_obj_t *com_obj = obj_take(objdir_getlocal(_rootdir_obj, ROOTDIR_SERIAL_COM_I)); + obj_settype(com_obj, JOVE_OBJ_SERIAL_COM); + obj_setvalue(com_obj, SERIAL_COM1); + obj_release(com_obj); + } + + kprintf("Initialized COM1 on port %X for obj %X\n", SERIAL_COM1, ROOTDIR_SERIAL_COM_I); +} + +int +serial_com_write( + jove_owned_obj_t *obj, + const char *s, size_t len) +{ + if(obj->type != JOVE_OBJ_SERIAL_COM) { + reterr(EBADOBJ); + } + for(size_t i = 0; i < len; i++) { + serial_com_putc((uint16_t)obj->value, s[i]); + } + return len; +} diff --git a/arch/x86_64/hal/serial_com.h b/arch/x86_64/hal/serial_com.h new file mode 100644 index 0000000..2dbb0cd --- /dev/null +++ b/arch/x86_64/hal/serial_com.h @@ -0,0 +1,26 @@ +#ifndef _JOVE_SERIAL_COM_H +#define _JOVE_SERIAL_COM_H 1 + +#include <stdint.h> +#include "obj.h" + +#define SERIAL_COM1 0x3F8 + +#define SERIAL_COM_TR(com) (com) +#define SERIAL_COM_IER(com) (com + 1) +#define SERIAL_COM_II(com) (com + 2) +#define SERIAL_COM_FIFO(com) (com + 2) +#define SERIAL_COM_LCR(com) (com + 3) +#define SERIAL_COM_MCR(com) (com + 4) +#define SERIAL_COM_LSR(com) (com + 5) +#define SERIAL_COM_MSR(com) (com + 6) +#define SERIAL_COM_SR(com) (com + 7) + +#define SERIAL_COM_DLAB_BAUD_LO(com) (com) +#define SERIAL_COM_DLAB_BAUD_HI(com) (com + 1) + +void serial_com_init(void); + +int serial_com_write(jove_owned_obj_t *obj, const char *s, size_t len); + +#endif diff --git a/arch/x86_64/hal/smp.c b/arch/x86_64/hal/smp.c new file mode 100644 index 0000000..a28fdc1 --- /dev/null +++ b/arch/x86_64/hal/smp.c @@ -0,0 +1,65 @@ +#include "smp.h" +#include "init.h" +#include "hal/obj.h" +#include "config.h" +#include "jove.h" +#include "lib/printf.h" +#include "paging.h" +#include "msr.h" + +processor_t s_processors[SMP_PROCESSORS_MAX] = { 0 }; + +PAGEALIGN +jove_objdir_t s_processor_objdir = { 0 }; + +extern void +gdt_setup(processor_t *processor); + +extern void +idt_init(void); + +extern void +idt_setup(processor_t *processor); + +static void +init_processor(processor_t *processor, jove_owned_obj_t *obj) +{ + gdt_setup(processor); + idt_setup(processor); + + msr_set_gs_base((uintptr_t)processor); + + obj_settype(obj, JOVE_OBJ_PROCESSOR); + obj_setvalue(obj, (uintptr_t)processor); +} + +void +smp_init_bsp(void) +{ + idt_init(); + paging_pml4_init(); + + kprintf("%p\n", _rootdir_obj); + processor_t *bsp = &s_processors[0]; + { + jove_owned_obj_t *processor_objdir_obj = obj_take(objdir_getlocal(_rootdir_obj, ROOTDIR_PROCESSORS_I)); + obj_settype(processor_objdir_obj, JOVE_OBJ_OBJDIR); + obj_setvalue(processor_objdir_obj, (uintptr_t)&s_processor_objdir); + + jove_owned_obj_t *bsp_obj = obj_take(objdir_getlocal(processor_objdir_obj, 0)); + init_processor(bsp, bsp_obj); + + obj_release(bsp_obj); + obj_release(processor_objdir_obj); + } +} + +void *processor_current(void) +{ + return (processor_t*)msr_get_gs_base(); +} + +jove_obj_t *processor_objdir(void *processor) +{ + return ((processor_t*)processor)->pcb->rootdir; +} diff --git a/arch/x86_64/hal/smp.h b/arch/x86_64/hal/smp.h new file mode 100644 index 0000000..68e420f --- /dev/null +++ b/arch/x86_64/hal/smp.h @@ -0,0 +1,18 @@ +#ifndef _JOVE_x86_64_HAL_SMP_H +#define _JOVE_x86_64_HAL_SMP_H 1 + +#include "gdt.h" +#include "process.h" +#include "hal/smp.h" + +typedef struct processor +{ + struct gdt_entry gdt[GDT_TSS_HI+1]; + struct tss tss; + + pcb_t *pcb; +} processor_t; + +void smp_init_bsp(void); + +#endif |
