summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoursoir <chat@joursoir.net>2022-10-07 19:04:00 +0300
committerJoursoir <chat@joursoir.net>2022-10-13 18:58:06 +0300
commit16a538de1a643af7cb45133d1eb5fd28e58d25d1 (patch)
tree2d354ef4706528eb6e087fac5d659b7070740848
parentc4f8edeb0845e73a15baa513ade27df08db90248 (diff)
downloadmfsos-16a538de1a643af7cb45133d1eb5fd28e58d25d1.tar.gz
mfsos-16a538de1a643af7cb45133d1eb5fd28e58d25d1.tar.bz2
mfsos-16a538de1a643af7cb45133d1eb5fd28e58d25d1.zip
x86: add GDT code to the kernel
-rw-r--r--Makefile4
-rw-r--r--arch/x86/gdt.c63
-rw-r--r--arch/x86/include/gdt.h2
-rw-r--r--kernel/main.c3
4 files changed, 71 insertions, 1 deletions
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 <gdt.h>
+
+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();