summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorDanny Holman <dholman@gymli.xyz>2021-07-24 02:27:40 -0500
committerDanny Holman <dholman@gymli.xyz>2021-07-24 02:27:40 -0500
commit7498b41d94b2f34468833b55ad0472d75b63064e (patch)
treea16b9c728edd4116b401f7fd337cb36b8d33fd78 /arch
parentd4003f1d6daf6883acb83a398e3fdba5336aefef (diff)
arch: i386: add GDT setup routines
Add a set of routines that setup the x86's global descriptor table. Signed-off-by: Danny Holman <dholman@gymli.xyz>
Diffstat (limited to 'arch')
-rw-r--r--arch/i386/boot/boot.s18
-rw-r--r--arch/i386/boot/gdt.c79
-rw-r--r--arch/i386/include/gdt.h69
-rw-r--r--arch/i386/make.config1
4 files changed, 98 insertions, 69 deletions
diff --git a/arch/i386/boot/boot.s b/arch/i386/boot/boot.s
index 792a790..842519f 100644
--- a/arch/i386/boot/boot.s
+++ b/arch/i386/boot/boot.s
@@ -68,8 +68,26 @@ _start:
movl $stack_top, %esp
+ call tty_init
+ call gdt_install
call kernel_main
cli
1: hlt
jmp 1b
+
+.global flush_gdt
+.type flush_gdt, @function
+
+flush_gdt:
+ cli
+ movl 4(%esp), %eax
+ lgdt (%eax)
+ movw $0x10, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+ movw %ax, %ss
+ jmp $0x08, $.flush
+.flush: ret
diff --git a/arch/i386/boot/gdt.c b/arch/i386/boot/gdt.c
new file mode 100644
index 0000000..d9bfc1e
--- /dev/null
+++ b/arch/i386/boot/gdt.c
@@ -0,0 +1,79 @@
+#include <kernel/io.h>
+#include <stdint.h>
+
+#define SEG_DESCTYPE(x) ((x) << 0x04) // Descriptor type (0 for system, 1 for code/data)
+#define SEG_PRES(x) ((x) << 0x07) // Present
+#define SEG_SAVL(x) ((x) << 0x0C) // Available for system use
+#define SEG_LONG(x) ((x) << 0x0D) // Long mode
+#define SEG_SIZE(x) ((x) << 0x0E) // Size (0 for 16-bit, 1 for 32)
+#define SEG_GRAN(x) ((x) << 0x0F) // Granularity (0 for 1B - 1MB, 1 for 4KB - 4GB)
+#define SEG_PRIV(x) (((x) & 0x03) << 0x05) // Set privilege level (0 - 3)
+
+#define SEG_DATA_RD 0x00 // Read-Only
+#define SEG_DATA_RDA 0x01 // Read-Only, accessed
+#define SEG_DATA_RDWR 0x02 // Read/Write
+#define SEG_DATA_RDWRA 0x03 // Read/Write, accessed
+#define SEG_DATA_RDEXPD 0x04 // Read-Only, expand-down
+#define SEG_DATA_RDEXPDA 0x05 // Read-Only, expand-down, accessed
+#define SEG_DATA_RDWREXPD 0x06 // Read/Write, expand-down
+#define SEG_DATA_RDWREXPDA 0x07 // Read/Write, expand-down, accessed
+#define SEG_CODE_EX 0x08 // Execute-Only
+#define SEG_CODE_EXA 0x09 // Execute-Only, accessed
+#define SEG_CODE_EXRD 0x0A // Execute/Read
+#define SEG_CODE_EXRDA 0x0B // Execute/Read, accessed
+#define SEG_CODE_EXC 0x0C // Execute-Only, conforming
+#define SEG_CODE_EXCA 0x0D // Execute-Only, conforming, accessed
+#define SEG_CODE_EXRDC 0x0E // Execute/Read, conforming
+#define SEG_CODE_EXRDCA 0x0F // Execute/Read, conforming, accessed
+
+#define GDT_CODE_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
+ SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
+ SEG_PRIV(0) | SEG_CODE_EXRD
+
+#define GDT_DATA_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
+ SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
+ SEG_PRIV(0) | SEG_DATA_RDWR
+
+#define GDT_CODE_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
+ SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
+ SEG_PRIV(3) | SEG_CODE_EXRD
+
+#define GDT_DATA_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
+ SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
+ SEG_PRIV(3) | SEG_DATA_RDWR
+
+struct gpt_ptr {
+ uint16_t limit;
+ uint32_t base;
+}__attribute__((packed));
+
+uint64_t desc[3];
+struct gpt_ptr gp;
+
+extern void flush_gdt(struct gpt_ptr *ptr);
+
+uint64_t create_gdt_entry(uint32_t base, uint32_t limit, uint16_t flag) {
+ uint64_t ret;
+
+ ret = limit & 0x000F0000;
+ ret |= (flag << 8) & 0x00F0FF00;
+ ret |= (base >> 16) & 0x000000FF;
+ ret |= base & 0xFF000000;
+
+ ret <<= 32;
+
+ ret |= base << 16;
+ ret |= limit & 0x0000FFFF;
+
+ return ret;
+}
+
+void gdt_install(void) {
+ gp.limit = 64 * 3 - 1;
+ gp.base = (uint32_t)&desc;
+
+ desc[0] = create_gdt_entry(0, 0, 0);
+ desc[1] = create_gdt_entry(0, 0x000FFFFF, (GDT_CODE_PL0));
+ desc[2] = create_gdt_entry(0, 0x000FFFFF, (GDT_DATA_PL0));
+ flush_gdt(&gp);
+}
diff --git a/arch/i386/include/gdt.h b/arch/i386/include/gdt.h
deleted file mode 100644
index 4ffa155..0000000
--- a/arch/i386/include/gdt.h
+++ /dev/null
@@ -1,69 +0,0 @@
-#ifndef GDT_H
-#define GDT_H
-
-#include <stdint.h>
-
-#define SEG_DESCTYPE(x) ((x) << 0x04)
-#define SEG_PRES(x) ((x) << 0x07)
-#define SEG_SAVL(x) ((x) << 0x0C)
-#define SEG_LONG(x) ((x) << 0x0D)
-#define SEG_SIZE(x) ((x) << 0x0E)
-#define SEG_GRAN(x) ((x) << 0x0F)
-#define SEG_PRIV(x) (((x) & 0x03) << 0x05)
-
-#define SEG_DATA_RD 0x00
-#define SEG_DATA_RDA 0x01
-#define SEG_DATA_RDWR 0x02
-#define SEG_DATA_RDWRA 0x03
-#define SEG_DATA_RDEXPD 0x04
-#define SEG_DATA_RDEXPDA 0x05
-#define SEG_DATA_RDWREXD 0x06
-#define SEG_DATA_RDWREXDA 0x07
-#define SEG_CODE_EX 0x08
-#define SEG_CODE_EXA 0x09
-#define SEG_CODE_EXRD 0x0A
-#define SEG_CODE_EXRDA 0x0B
-#define SEG_CODE_EXC 0x0C
-#define SEG_CODE_EXCA 0x0D
-#define SEG_CODE_EXRDC 0x0E
-#define SEG_CODE_EXRDCA 0x0F
-
-#define GDT_CODE_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
- SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
- SEG_PRIV(0) | SEG_CODE_EXRD
-
-#define GDT_DATA_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
- SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
- SEG_PRIV(0) | SEG_CODE_RDWR
-
-#define GDT_CODE_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
- SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
- SEG_PRIV(3) | SEG_DATA_EXRD
-
-#define GDT_DATA_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \
- SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \
- SEG_PRIV(3) | SEG_DATA_RDWR
-
-struct gdt {
- uint16_t size;
- uint32_t offset;
-} __attribute__((packed));
-
-void flush_gdt(void);
-
-uint64_t create_descriptor(uint32_t base, uint32_t limit, uint16_t flag) {
- uint64_t descriptor;
-
- descriptor = limit & 0x000F0000;
- descriptor |= (flag << 8) & 0x00F0FF00;
- descriptor |= (base >> 16) & 0x000000FF;
- descriptor |= base & 0xFF000000;
-
- descriptor <<= 32;
- descriptor |= base << 16;
- descriptor |= limit & 0x0000FFFF;
-
- return descriptor;
-}
-
-#endif
diff --git a/arch/i386/make.config b/arch/i386/make.config
index 1f09aea..6582794 100644
--- a/arch/i386/make.config
+++ b/arch/i386/make.config
@@ -5,4 +5,5 @@ KERNEL_ARCH_LIBS=
KERNEL_ARCH_OBJS=$(ARCHDIR)/boot/boot.o \
$(ARCHDIR)/boot/tty.o \
+ $(ARCHDIR)/boot/gdt.o \
$(ARCHDIR)/kernel/serial.o \