summaryrefslogtreecommitdiff
path: root/src/arch/i386
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/i386')
-rw-r--r--src/arch/i386/gdt/gdt.c98
1 files changed, 53 insertions, 45 deletions
diff --git a/src/arch/i386/gdt/gdt.c b/src/arch/i386/gdt/gdt.c
index 3e0647b..c61002b 100644
--- a/src/arch/i386/gdt/gdt.c
+++ b/src/arch/i386/gdt/gdt.c
@@ -1,6 +1,7 @@
#include <arch/generic.h>
#include <arch/i386/gdt.h>
#include <kernel/util.h>
+#include <stdbool.h>
#include <stdint.h>
@@ -25,11 +26,10 @@ struct gdt_entry {
} __attribute__((packed));
struct tss_entry {
- uint32_t prev_tss; // unused
+ uint32_t _unused0;
uint32_t esp0; // kernel mode stack pointer
uint32_t ss0; // kernel mode stack segment
- // total size = 0x68 (?) - 3 * sizeof(uint32_t) = 5c
- uint8_t _unused[0x5c];
+ uint8_t _unused1[0x5c];
} __attribute__((packed));
struct lgdt_arg {
@@ -41,65 +41,73 @@ static struct gdt_entry GDT[SEG_end];
static struct tss_entry TSS;
static struct lgdt_arg lgdt_arg; // probably doesn't need to be global
+static void gdt_fillout(struct gdt_entry* entry, uint8_t ring, bool code);
static void gdt_prepare();
static void gdt_load();
+static void gdt_fillout(struct gdt_entry* entry, uint8_t ring, bool code) {
+ *entry = (struct gdt_entry) {
+ // set up the identity mapping
+ .limit_low = 0xFFFF,
+ .limit_high = 0xF,
+ .gran = 1, // 4KB * 0xFFFFF = (almost) 4GB
+ .base_low = 0,
+ .base_high = 0,
+
+ .ring = ring,
+ .code = code,
+
+ .accessed = 0,
+ .rw = 1,
+ .conforming = 0,
+ .codeordata = 1,
+ .present = 1,
+ .long_mode = 0, // ???
+ .available = 1, // ???
+ .x32 = 1,
+ };
+}
+
static void gdt_prepare() {
GDT[SEG_null].present = 0;
- GDT[SEG_r0data].limit_low = 0xFFFF;
- GDT[SEG_r0data].limit_high = 0xF;
- GDT[SEG_r0data].gran = 1; // 4KB * 0xFFFFF = (almost) 4GB
- GDT[SEG_r0data].base_low = 0;
- GDT[SEG_r0data].base_high = 0;
- GDT[SEG_r0data].accessed = 0;
- GDT[SEG_r0data].rw = 1;
- GDT[SEG_r0data].conforming = 0;
- GDT[SEG_r0data].code = 0;
- GDT[SEG_r0data].codeordata = 1;
- GDT[SEG_r0data].ring = 0;
- GDT[SEG_r0data].present = 1;
- GDT[SEG_r0data].long_mode = 0; // ???
- GDT[SEG_r0data].available = 1; // ???
- GDT[SEG_r0data].x32 = 1;
-
- // copy to r0 code
- GDT[SEG_r0code] = GDT[SEG_r0data];
- GDT[SEG_r0code].code = 1;
-
- GDT[SEG_r3data] = GDT[SEG_r0data];
- GDT[SEG_r3data].ring = 3;
- GDT[SEG_r3code] = GDT[SEG_r0code];
- GDT[SEG_r3code].ring = 3;
+ gdt_fillout(&GDT[SEG_r0code], 0, true);
+ gdt_fillout(&GDT[SEG_r0data], 0, false);
+ gdt_fillout(&GDT[SEG_r3code], 3, true);
+ gdt_fillout(&GDT[SEG_r3data], 3, false);
// tss
memset(&TSS, 0, sizeof(TSS));
TSS.ss0 = SEG_r0data << 3; // kernel data segment
- TSS.esp0 = (uint32_t) &stack_top;
-
- GDT[SEG_TSS].limit_low = sizeof(TSS);
- GDT[SEG_TSS].base_low = (uint32_t) &TSS;
- GDT[SEG_TSS].accessed = 1; // 1 for TSS
- GDT[SEG_TSS].rw = 0; // 1 busy / 0 not busy
- GDT[SEG_TSS].conforming = 0; // 0 for TSS
- GDT[SEG_TSS].code = 1; // 32bit
- GDT[SEG_TSS].codeordata = 0; // is a system entry
- GDT[SEG_TSS].ring = 3;
- GDT[SEG_TSS].present = 1;
- GDT[SEG_TSS].limit_high = (sizeof(TSS) >> 16) & 0xf;
- GDT[SEG_TSS].available = 0; // 0 for TSS
- GDT[SEG_TSS].long_mode = 0;
- GDT[SEG_TSS].x32 = 0; // idk
- GDT[SEG_TSS].gran = 0;
- GDT[SEG_TSS].base_high = (((uint32_t) &TSS) >> 24) & 0xff;
+ TSS.esp0 = (uintptr_t) &stack_top;
+
+ GDT[SEG_TSS] = (struct gdt_entry) {
+ .limit_low = sizeof(TSS),
+ .limit_high = sizeof(TSS) >> 16,
+ .gran = 0,
+ .base_low = (uintptr_t) &TSS,
+ .base_high = ((uintptr_t) &TSS) >> 24,
+
+ .accessed = 1, // 1 for TSS
+ .rw = 0, // 1 busy / 0 not busy
+ .conforming = 0, // 0 for TSS
+ .code = 1, // 32bit
+ .codeordata = 0, // is a system entry
+ .ring = 3,
+ .present = 1,
+ .available = 0, // 0 for TSS
+ .long_mode = 0,
+ .x32 = 0, // idk
+ };
}
static void gdt_load() {
lgdt_arg.limit = sizeof(GDT) - 1;
- lgdt_arg.base = (uint32_t) &GDT;
+ lgdt_arg.base = (uintptr_t) &GDT;
asm("lgdt (%0)"
: : "r" (&lgdt_arg) : "memory");
+
asm("ltr %%ax"
: : "a" (SEG_TSS << 3 | 3) : "memory");