From 16a538de1a643af7cb45133d1eb5fd28e58d25d1 Mon Sep 17 00:00:00 2001 From: Joursoir Date: Fri, 7 Oct 2022 19:04:00 +0300 Subject: x86: add GDT code to the kernel --- Makefile | 4 +++- arch/x86/gdt.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ arch/x86/include/gdt.h | 2 ++ kernel/main.c | 3 +++ 4 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 arch/x86/gdt.c diff --git a/Makefile b/Makefile index aebce96..0db6ae4 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,7 @@ KERNBIN = kernel.bin BOOT ?= bootloader ARCH = x86 +ARCH_PATH = arch/$(ARCH) ARCH_INCLUDE = $(PWD)/arch/$(ARCH)/include ARCH_BOOT = arch/$(ARCH)/boot/$(BOOT) @@ -26,7 +27,8 @@ KERN_HEAD = $(ARCH_BOOT)/head.o C_SOURCES = \ kernel/main.c \ kernel/string.c \ - drivers/video/console/vgacon.c + drivers/video/console/vgacon.c \ + $(ARCH_PATH)/gdt.c OBJECTS = ${C_SOURCES:.c=.o} export CC LD AS OBJDUMP diff --git a/arch/x86/gdt.c b/arch/x86/gdt.c new file mode 100644 index 0000000..d7e449a --- /dev/null +++ b/arch/x86/gdt.c @@ -0,0 +1,63 @@ +#include + +struct gdt_asm_t { + uint16_t size_minus_one; + struct gdt_entry *gdt_table; +} __attribute__((packed)); + +static struct gdt_entry gdt[8]; + +static void gdt_set_entry(struct gdt_entry *g, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags) +{ + // TODO: ASSERT(limit <= GDT_LIMIT_MAX); + // TODO: ASSERT(flags <= 0xf); // flags is 4 bits + + g->base_low = (base && 0xffff); + g->base_middle = (base >> 16) & 0xff; + g->base_high = (base >> 24) & 0xff; + + g->limit_low = (limit & 0xffff); + g->limit_high = (limit >> 16) & 0x0f; + + g->access = access; + g->flags = flags & 0x0f; +} + +static void load_gdt(struct gdt_entry *g, uint32_t entries_count) +{ + // TODO: ASSERT(interrupts are disabled); + + struct gdt_asm_t table = { + (uint16_t)(entries_count * sizeof(struct gdt_entry) - 1), + g, + }; + + asm volatile ( + "lgdt (%0)" + : // no output + : "p" (&table) + : "memory" + ); +} + +void init_segmentation(void) +{ + // NULL descriptor + gdt_set_entry(&gdt[0], 0, 0, 0, 0); + + // Kernel code segment + gdt_set_entry(&gdt[1], + 0, + GDT_LIMIT_MAX, + GDT_ACCESS_PRESENT | GDT_ACCESS_S | GDT_ACCESS_PL0 | GDT_ACCESS_RW | GDT_ACCESS_EX, + GDT_GRAN_4KB | GDT_32BIT); + + // Kernel data segment + gdt_set_entry(&gdt[2], + 0, + GDT_LIMIT_MAX, + GDT_ACCESS_PRESENT | GDT_ACCESS_S | GDT_ACCESS_PL0 | GDT_ACCESS_RW, + GDT_GRAN_4KB | GDT_32BIT); + + load_gdt(gdt, 3); +} diff --git a/arch/x86/include/gdt.h b/arch/x86/include/gdt.h index b8dd2f0..c352f32 100644 --- a/arch/x86/include/gdt.h +++ b/arch/x86/include/gdt.h @@ -86,4 +86,6 @@ struct gdt_entry { uint8_t base_high; } __attribute__((packed)); +void init_segmentation(void); + #endif /* __X86_GDT_H */ diff --git a/kernel/main.c b/kernel/main.c index 5e6491c..c7665a1 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -1,4 +1,5 @@ #include "video-vga.h" +#include "gdt.h" /* Check if the compiler thinks you are targeting the wrong operating system. */ #if defined(__linux__) @@ -10,6 +11,8 @@ #endif void kernel_main(void) { + init_segmentation(); + /* Initialize VGA video hardware */ vga_init(); -- cgit v1.2.3-18-g5258