diff --git a/src/kernel/archs/hal.h b/src/kernel/archs/hal.h index 879d8f0..af009cb 100644 --- a/src/kernel/archs/hal.h +++ b/src/kernel/archs/hal.h @@ -2,7 +2,7 @@ #include -void hal_setup(void); +Res hal_setup(void); /* --- Assembly function --------------------------------------------------- */ diff --git a/src/kernel/archs/x86_64/gdt.c b/src/kernel/archs/x86_64/gdt.c new file mode 100644 index 0000000..5dbeab0 --- /dev/null +++ b/src/kernel/archs/x86_64/gdt.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include + +#include "gdt.h" + +static Gdt gdt = {0}; + +static Spinlock lock = SPINLOCK_INIT; + +static GdtDescriptor gdt_desc = { + .size = sizeof(gdt) - 1, + .offset = (uintptr_t)&gdt, +}; + +static void gdt_lazy_init(GdtEntry self[static 1], uint8_t access, uint8_t flags) +{ + memset(self, 0, sizeof(GdtEntry)); + + if (access == 0 && flags == 0) + { + return; + } + + self->access = access | GDT_ACCESS_PRESENT | GDT_ACCESS_READ_WRITE | GDT_ACCESS_DESCRIPTOR; + self->flags = flags | GDT_FLAGS_GRANULARITY; + + self->base_high = 0; + self->base_middle = 0; + self->base_low = 0; + + self->limit_low = 0xffff; + self->limit_high = 0x0f; +} + +void gdt_load_tss(Tss *tss) +{ + uintptr_t tss_ptr = (uintptr_t)tss; + + spinlock_acquire(&lock); + + gdt.tss_entry = (TssEntry){ + .length = sizeof(TssEntry), + + .base_low = tss_ptr & 0xffff, + .base_mid = (tss_ptr >> 16) & 0xff, + .base_high = (tss_ptr >> 24) & 0xff, + .base_upper = tss_ptr >> 32, + + .flags1 = TSS_FLAGS_PRESENT | TSS_FLAGS_64BITS_AVAILABLE, + .flags2 = 0, + + .reserved = 0, + }; + + spinlock_release(&lock); +} + +uintptr_t gdt_descriptor(void) +{ + return (uintptr_t)&gdt_desc; +} + +void gdt_init(void) +{ + gdt_lazy_init(&gdt.entries[GDT_NULL_DESC], 0, 0); + + gdt_lazy_init(&gdt.entries[GDT_KERNEL_CODE], GDT_ACCESS_EXE, GDT_FLAGS_LONG_MODE); + gdt_lazy_init(&gdt.entries[GDT_KERNEL_DATA], 0, GDT_FLAGS_SIZE); + + gdt_lazy_init(&gdt.entries[GDT_USER_DATA], GDT_ACCESS_USER, GDT_FLAGS_SIZE); + gdt_lazy_init(&gdt.entries[GDT_USER_CODE], GDT_ACCESS_USER | GDT_ACCESS_EXE, GDT_FLAGS_LONG_MODE); + gdt_load_tss(NULL); + + gdt_flush(gdt_descriptor()); + log$("GDT loaded"); + + tss_flush(); + log$("TSS loaded"); +} \ No newline at end of file diff --git a/src/kernel/archs/x86_64/gdt.h b/src/kernel/archs/x86_64/gdt.h new file mode 100644 index 0000000..1c5a335 --- /dev/null +++ b/src/kernel/archs/x86_64/gdt.h @@ -0,0 +1,91 @@ +#pragma once + +#include +#include + +enum gdtaccess : uint8_t +{ + GDT_ACCESS_READ_WRITE = (1 << 1), + GDT_ACCESS_EXE = (1 << 3), + GDT_ACCESS_DESCRIPTOR = (1 << 4), + GDT_ACCESS_USER = (3 << 5), + GDT_ACCESS_PRESENT = (1 << 7), +}; + +enum gdtflags : uint8_t +{ + GDT_FLAGS_LONG_MODE = (1 << 1), + GDT_FLAGS_SIZE = (1 << 2), + GDT_FLAGS_GRANULARITY = (1 << 3), +}; + +enum tssflags : uint8_t +{ + TSS_FLAGS_PRESENT = (1 << 7), + TSS_FLAGS_64BITS_AVAILABLE = (0x9), +}; + +enum +{ + GDT_NULL_DESC, + GDT_KERNEL_CODE, + GDT_KERNEL_DATA, + GDT_USER_DATA, + GDT_USER_CODE, + + GDT_ENTRIES_LENGTH +}; + +typedef struct [[gnu::packed]] +{ + uint16_t limit_low; + uint16_t base_low; + uint8_t base_middle; + uint8_t access; + uint8_t limit_high : 4; + uint8_t flags : 4; + uint8_t base_high; +} GdtEntry; + +typedef struct [[gnu::packed]] +{ + uint16_t length; + uint16_t base_low; + uint8_t base_mid; + uint8_t flags1; + uint8_t flags2; + uint8_t base_high; + uint32_t base_upper; + uint32_t reserved; +} TssEntry; + +typedef struct [[gnu::packed]] +{ + uint32_t reserved; + uint64_t rsp[3]; + uint64_t reserved0; + uint64_t ist[7]; + uint32_t reserved1; + uint32_t reserved2; + uint16_t reserved3; + uint16_t iopb_offset; +} Tss; + +typedef struct [[gnu::packed]] +{ + uint16_t size; + uintptr_t offset; +} GdtDescriptor; + +typedef struct [[gnu::packed]] +{ + GdtEntry entries[GDT_ENTRIES_LENGTH]; + TssEntry tss_entry; +} Gdt; + +void gdt_init(void); +void gdt_load_tss(Tss *self); +uintptr_t gdt_descriptor(void); + +extern void gdt_flush(uintptr_t); +extern void tss_flush(void); \ No newline at end of file diff --git a/src/kernel/archs/x86_64/helper.s b/src/kernel/archs/x86_64/helper.s new file mode 100644 index 0000000..34f8df3 --- /dev/null +++ b/src/kernel/archs/x86_64/helper.s @@ -0,0 +1,22 @@ +.globl gdt_flush +.globl tss_flush + +gdt_flush: + lgdt (%rdi) + + mov $0x10, %ax + mov %ax, %ss + mov %ax, %ds + mov %ax, %es + pop %rdi + + mov $0x08, %rax + push %rax + push %rdi + lretq + + +tss_flush: + mov $0x28, %ax + ltr %ax + ret \ No newline at end of file diff --git a/src/kernel/archs/x86_64/mod.c b/src/kernel/archs/x86_64/mod.c index 9951b8f..01d21a3 100644 --- a/src/kernel/archs/x86_64/mod.c +++ b/src/kernel/archs/x86_64/mod.c @@ -1,6 +1,9 @@ +#include #include +#include #include "e9.h" +#include "gdt.h" Stream hal_dbg_stream(void) { @@ -9,6 +12,8 @@ Stream hal_dbg_stream(void) }; } -void hal_setup(void) +Res hal_setup(void) { + gdt_init(); + return ok$(); } \ No newline at end of file diff --git a/src/kernel/core/main.c b/src/kernel/core/main.c index 10f157b..eaea023 100644 --- a/src/kernel/core/main.c +++ b/src/kernel/core/main.c @@ -1,8 +1,10 @@ #include +#include _Noreturn int _start() { log$("Hello, world!"); + hal_setup(); for (;;) ; } \ No newline at end of file