diff options
Diffstat (limited to '')
| -rw-r--r-- | kernel/gdt.c | 285 |
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; +} |
