aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/gdt.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gdt.c')
-rw-r--r--kernel/gdt.c285
1 files changed, 285 insertions, 0 deletions
diff --git a/kernel/gdt.c b/kernel/gdt.c
new file mode 100644
index 0000000..b6d2c3a
--- /dev/null
+++ b/kernel/gdt.c
@@ -0,0 +1,285 @@
+
+#include "gdt.h"
+#include "kprintf.h"
+
+#include "asm_inline.h"
+#include "memops.h"
+
+#define NULL_DESCRIPTOR 0
+#define KERNEL_CODE 1
+#define KERNEL_DATA 2
+#define USER_CODE 3
+#define USER_DATA 4
+#define TASK_STATE_SEGMENT_LOW 5
+#define TASK_STATE_SEGMENT_HIGH 6
+
+__attribute__((aligned(0x08)))
+uint64_t gdt[7];
+
+gdt_load gdt_l;
+tss tss_g;
+
+// #define KDEBUG
+
+extern void asm_reload_segments();
+
+int init_gdt()
+{
+ /*
+ create_descriptor(NULL_DESCRIPTOR, 0, 0, 0, 0);
+ create_descriptor(KERNEL_CODE, 0, 0xFFFF, 0x9A, 0xA);
+ create_descriptor(KERNEL_DATA, 0, 0xFFFF, 0x92, 0xC);
+ create_descriptor(USER_CODE, 0, 0xFFFF, 0xFA, 0xA);
+ create_descriptor(USER_DATA, 0, 0xFFFF, 0xF2, 0xC);
+ */
+
+
+ gdt[NULL_DESCRIPTOR] = 0x0000000000000000;
+ /*
+ gdt[KERNEL_CODE] = 0x0020980000000000; // Code, DPL=0, R/X
+ gdt[KERNEL_DATA] = 0x0000920000000000; // Data, DPL=0, W
+ gdt[USER_CODE] = 0x0020F80000000000; // Code, DPL=3, R/X
+ gdt[USER_DATA] = 0x0000F20000000000; // Data, DPL=3, W
+ */
+
+ code_segment kernel_code = {
+ .limit = 0xFFFF,
+ .base_low = 0x0,
+ .base_mid = 0x0,
+ .A = 0x0,
+ .R = 0x1,
+ .C = 0x0, // conforming, used for privilege changes, leave it for now
+ .one0 = 0x1,
+ .one1 = 0x1,
+ .DPL = 0x0, // 0 -> kernel code
+ .P = 0x1,
+ .limit_high = 0xF,
+ .AVL = 0x0,
+ .L = 0x1,
+ .D = 0x0,
+ .G = 0x1,
+ .base_high = 0x0
+ };
+
+ data_segment kernel_data = {
+ .limit = 0xFFFF,
+ .base_low = 0x0,
+ .base_mid = 0x0,
+ .A = 0x0,
+ .W = 0x1,
+ .E = 0x0,
+ .zero = 0,
+ .one = 1,
+ .DPL = 0x0,
+ .P = 0x1,
+ .limit_high = 0xF,
+ .AVL = 0x0,
+ .L = 0x1,
+ .D = 0x0,
+ .G = 0x1,
+ .base_high = 0x0
+ };
+
+ code_segment user_code = {
+ .limit = 0xFFFF,
+ .base_low = 0x0,
+ .base_mid = 0x0,
+ .A = 0x0,
+ .R = 0x1, // ?
+ .C = 0x0, // conforming, used for privilege changes, leave it for now
+ .one0 = 0x1,
+ .one1 = 0x1,
+ .DPL = 0x3, // 0 -> user code
+ .P = 0x1,
+ .limit_high = 0xF,
+ .AVL = 0x0,
+ .L = 0x1,
+ .D = 0x0,
+ .G = 0x1,
+ .base_high = 0x0
+ };
+ data_segment user_data = {
+ .limit = 0xFFFF,
+ .base_low = 0x0,
+ .base_mid = 0x0,
+ .A = 0x0,
+ .W = 0x1,
+ .E = 0x0,
+ .zero = 0,
+ .one = 1,
+ .DPL = 0x3,
+ .P = 0x1,
+ .limit_high = 0xF,
+ .AVL = 0x0,
+ .L = 0x1,
+ .D = 0x0,
+ .G = 0x1,
+ .base_high = 0x0
+ };
+
+ //uint64_t addr = (uint64_t)tss_a;
+ //tss_a[16] = 0x00680000;
+
+ tss_g.rsv0 = 0x0;
+ tss_g.rsp0 = rrsp(); // <- change with ring 0 stack pointer(who knows which one is it, need to allocate or reserve?)
+ tss_g.rsp1 = 0x0;
+ tss_g.rsp2 = 0x0;
+ tss_g.rsv1 = 0x0;
+ tss_g.ist2 = 0x0;
+ tss_g.ist3 = 0x0;
+ tss_g.ist4 = 0x0;
+ tss_g.ist5 = 0x0;
+ tss_g.ist6 = 0x0;
+ tss_g.ist7 = 0x0;
+ tss_g.rsv2 = 0x0;
+ tss_g.rsv3 = 0x0;
+ tss_g.io_base = sizeof(tss);
+
+ uint64_t tss_m;
+ kmemcpy(&tss_g, &tss_m, sizeof(uint64_t));
+
+ tss_segment gdt_tss = {
+ .limit_low = 0xFFFF,
+ .base_low = tss_m & 0xFFFFFF,
+ .type = 0x9, // <- available tss ? (busy is 0xB)
+ .zero0 = 0x0,
+ .DPL = 0x0,
+ .P = 0x1,
+ .limit_high = 0xF,
+ .AVL = 0x0,
+ .zero1 = 0x0,
+ .zero2 = 0x0,
+ .G = 0x1, // <- maybe?
+ .base_high = (tss_m >> 24) & 0xFFFFFFFFFF,
+ .rsv1 = 0x0,
+ .zero3 = 0x0,
+ .rsv2 = 0x0,
+ };
+
+ /*
+ kmemcpy(&kernel_code, &gdt[KERNEL_CODE], sizeof(uint64_t));
+ kmemcpy(&kernel_data, &gdt[KERNEL_DATA], sizeof(uint64_t));
+ kmemcpy(&user_code, &gdt[USER_CODE], sizeof(uint64_t));
+ kmemcpy(&user_data, &gdt[USER_DATA], sizeof(uint64_t));
+ */
+ kmemcpy(&gdt_tss, &gdt[TASK_STATE_SEGMENT_LOW], 2*sizeof(uint64_t));
+
+ uint64_t kc = convert_code_segment(&kernel_code);
+ uint64_t kd = convert_data_segment(&kernel_data);
+ uint64_t uc = convert_code_segment(&user_code);
+ uint64_t ud = convert_data_segment(&user_data);
+
+ gdt[KERNEL_CODE] = kc;
+ // gdt[KERNEL_DATA] = kd;
+ gdt[KERNEL_DATA] = 0x0000920000000000; // maybe my code is wrong <- yes it is, no idea why, discovered, and can be safely hardcoded for 64bit
+ gdt[USER_CODE] = uc;
+ gdt[USER_DATA] = 0x0000920000000000;
+ // gdt[USER_DATA] = ud;
+
+ /*
+ gdt[TASK_STATE_SEGMENT_LOW] = (0x0067) | ((addr & 0xFFFFFF) << 16) |
+ (0x00E9LL << 40) | (((addr >> 24) & 0xFF) << 56);
+ gdt[TASK_STATE_SEGMENT_HIGH] = (addr >> 32);
+ */
+
+ #ifdef KDEBUG
+ kprintf("gdt pointer: %p\n", gdt);
+ kprintf("KERNEL CODE: %lX\n", gdt[KERNEL_CODE]);
+ kprintf("KERNEL DATA: %lX\n", gdt[KERNEL_DATA]);
+ kprintf("USER CODE: %lX\n", gdt[USER_CODE]);
+ kprintf("USER DATA: %lX\n", gdt[USER_DATA]);
+
+
+
+ kprintf("FUNCTION\n");
+
+ kprintf("KERNEL CODE: %lX\n", kc);
+ kprintf("KERNEL DATA: %lX\n", kd);
+ kprintf("USER CODE: %lX\n", uc);
+ kprintf("USER DATA: %lX\n", ud);
+ #endif
+
+ gdt_l.size = 7 * sizeof(uint64_t) - 1;
+ gdt_l.ptr = (uint64_t)(gdt);
+
+ lgdt(&gdt_l);
+ asm_reload_segments();
+
+ // ltr(TASK_STATE_SEGMENT_LOW << 3);
+
+ create_system_segment_descriptor();
+
+ return 1;
+}
+
+uint64_t create_descriptor(uint32_t base, uint32_t limit, uint8_t access_byte, uint16_t flag)
+{
+ // need to redo
+ 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;
+}
+
+void create_system_segment_descriptor()
+{
+
+}
+
+uint64_t convert_code_segment(code_segment* segment)
+{
+ uint64_t s = 0x0;
+
+ s = segment->limit & 0xFFFF;
+ s |= (uint64_t)(segment->base_low & 0xFFFF) << 16;
+ s |= (uint64_t)(segment->base_mid & 0xFF) << 32;
+ s |= (uint64_t)(segment->A & 0x1) << 40;
+ s |= (uint64_t)(segment->R & 0x1) << 41;
+ s |= (uint64_t)(segment->C & 0x1) << 42;
+ s |= (uint64_t)(segment->one0 & 0x1) << 43;
+ s |= (uint64_t)(segment->one1 & 0x1) << 44;
+ s |= (uint64_t)(segment->DPL & 0x3) << 45;
+ s |= (uint64_t)(segment->P & 0x1) << 47;
+ s |= (uint64_t)(segment->limit_high & 0xF) << 48;
+ s |= (uint64_t)(segment->AVL & 0x1) << 52;
+ s |= (uint64_t)(segment->L & 0x1) << 53;
+ s |= (uint64_t)(segment->D & 0x1) << 54;
+ s |= (uint64_t)(segment->G & 0x1) << 55;
+ s |= (uint64_t)(segment->base_high) << 56;
+
+ return s;
+}
+
+uint64_t convert_data_segment(data_segment* segment)
+{
+ uint64_t s = 0x0;
+ uint32_t* ss = (uint32_t*)&s;
+
+ s = segment->limit & 0xFFFF;
+ s |= (uint64_t)(segment->base_low & 0xFFFF) << 16;
+ s |= (uint64_t)(segment->base_mid & 0xFF) << 32;
+ s |= (uint64_t)(segment->A & 0x1) << 40;
+ s |= (uint64_t)(segment->W & 0x1) << 41;
+ s |= (uint64_t)(segment->E & 0x1) << 42;
+ s |= (uint64_t)(segment->one & 0x1) << 43;
+ s |= (uint64_t)(segment->zero & 0x1) << 44;
+ s |= (uint64_t)(segment->DPL & 0x3) << 45;
+ s |= (uint64_t)(segment->P & 0x1) << 47;
+ s |= (uint64_t)(segment->limit_high & 0xF) << 48;
+ s |= (uint64_t)(segment->AVL & 0x1) << 52;
+ s |= (uint64_t)(segment->L & 0x1) << 53;
+ s |= (uint64_t)(segment->D & 0x1) << 54;
+ s |= (uint64_t)(segment->G & 0x1) << 55;
+ s |= (uint64_t)(segment->base_high) << 56;
+
+ return s;
+}