summaryrefslogtreecommitdiffstats
path: root/arch/x86_64/hal
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/hal')
-rw-r--r--arch/x86_64/hal/gdt.c81
-rw-r--r--arch/x86_64/hal/gdt.h48
-rw-r--r--arch/x86_64/hal/idt.c53
-rw-r--r--arch/x86_64/hal/idt.h66
-rw-r--r--arch/x86_64/hal/idt_entries.s127
-rw-r--r--arch/x86_64/hal/lxdt.s26
-rw-r--r--arch/x86_64/hal/msr.c52
-rw-r--r--arch/x86_64/hal/msr.h48
-rw-r--r--arch/x86_64/hal/obj.c87
-rw-r--r--arch/x86_64/hal/obj.h79
-rw-r--r--arch/x86_64/hal/paging.c174
-rw-r--r--arch/x86_64/hal/paging.h52
-rw-r--r--arch/x86_64/hal/port.h12
-rw-r--r--arch/x86_64/hal/process.c35
-rw-r--r--arch/x86_64/hal/process.h34
-rw-r--r--arch/x86_64/hal/serial_com.c92
-rw-r--r--arch/x86_64/hal/serial_com.h26
-rw-r--r--arch/x86_64/hal/smp.c65
-rw-r--r--arch/x86_64/hal/smp.h18
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