#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; }