summaryrefslogtreecommitdiff
path: root/arch/i386/boot/gdt.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/boot/gdt.c')
-rw-r--r--arch/i386/boot/gdt.c141
1 files changed, 78 insertions, 63 deletions
diff --git a/arch/i386/boot/gdt.c b/arch/i386/boot/gdt.c
index 6552721..3972e53 100644
--- a/arch/i386/boot/gdt.c
+++ b/arch/i386/boot/gdt.c
@@ -1,80 +1,95 @@
+#include <kernel/string.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 gdt_entry {
+ uint16_t limit_low;
+ uint16_t base_low;
+ uint8_t base_middle;
+ uint8_t access;
+ uint8_t gran;
+ uint8_t base_high;
+} __attribute__((packed));
-struct gpt_ptr {
+struct gdt_ptr {
uint16_t limit;
uint32_t base;
-}__attribute__((packed));
+} __attribute__((packed));
-uint64_t gdt_desc[5];
-struct gpt_ptr gp;
+struct tss_entry {
+ uint32_t link;
+ uint32_t esp0;
+ uint32_t ss0;
+ uint32_t esp1;
+ uint32_t ss2;
+ uint32_t cr3;
+ uint32_t eip;
+ uint32_t eflags;
+ uint32_t eax;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t ebx;
+ uint32_t esp;
+ uint32_t ebp;
+ uint32_t esi;
+ uint32_t edi;
+ uint32_t es;
+ uint32_t cs;
+ uint32_t ss;
+ uint32_t ds;
+ uint32_t fs;
+ uint32_t gs;
+ uint32_t ldtr;
+ uint16_t trap;
+ uint16_t iomap_base;
+} __attribute__((packed));
-extern void flush_gdt(struct gpt_ptr *ptr);
+struct gdt_entry desc[6];
+struct gdt_ptr gp;
+struct tss_entry tss_entry;
-uint64_t create_gdt_entry(uint32_t base, uint32_t limit, uint16_t flag) {
- uint64_t ret;
+extern void flush_gdt(void);
+extern void flush_tss(void);
- ret = limit & 0x000F0000;
- ret |= (flag << 8) & 0x00F0FF00;
- ret |= (base >> 16) & 0x000000FF;
- ret |= base & 0xFF000000;
+void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) {
+ desc[num].base_low = (base & 0xFFFF);
+ desc[num].base_middle = (base >> 16) & 0xFF;
+ desc[num].base_high = (base >> 24) & 0xFF;
- ret <<= 32;
+ desc[num].limit_low = (limit & 0xFFFF);
+ desc[num].gran = (limit >> 16) & 0x0F;
+ desc[num].gran |= (gran & 0xF0);
+ desc[num].access = access;
+}
- ret |= base << 16;
- ret |= limit & 0x0000FFFF;
+void write_tss(int num, uint16_t ss0, uint16_t esp0) {
+ uint32_t base = (uint32_t)&tss_entry;
+ uint32_t limit = base + sizeof(tss_entry);
- return ret;
+ gdt_set_gate(num, base, limit, 0xE9, 0x00);
+ memset(&tss_entry, 0x0, sizeof(tss_entry));
+
+ tss_entry.ss0 = ss0;
+ tss_entry.esp0 = esp0;
+ tss_entry.cs = 0x0B;
+ tss_entry.ss = 0x13;
+ tss_entry.ds = 0x13;
+ tss_entry.es = 0x13;
+ tss_entry.fs = 0x13;
+ tss_entry.gs = 0x13;
+ tss_entry.iomap_base = sizeof(tss_entry);
}
void gdt_install(void) {
- gp.limit = 64 * 5 - 1;
- gp.base = (uint32_t)&gdt_desc;
+ gp.limit = (sizeof(struct gdt_entry) * 6) - 1;
+ gp.base = (uint32_t)&desc;
+
+ gdt_set_gate(0, 0, 0, 0, 0);
+ gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
+ gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
+ gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF);
+ gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF);
+ write_tss(5, 0x10, 0x0);
- gdt_desc[0] = create_gdt_entry(0, 0, 0);
- gdt_desc[1] = create_gdt_entry(0, 0x000FFFFF, GDT_CODE_PL0);
- gdt_desc[2] = create_gdt_entry(0, 0x000FFFFF, GDT_DATA_PL0);
- gdt_desc[3] = create_gdt_entry(0, 0x000FFFFF, GDT_DATA_PL3);
- gdt_desc[4] = create_gdt_entry(0, 0x000FFFFF, GDT_DATA_PL3);
- flush_gdt(&gp);
+ flush_gdt();
+ flush_tss();
}