100 lines
3.3 KiB
C
100 lines
3.3 KiB
C
#include <stdint.h>
|
|
|
|
#include "gdt.h"
|
|
#include "kprintf.h"
|
|
|
|
extern void set_gdt(uint32_t gdt_ptr);
|
|
|
|
struct tss TSS;
|
|
uint8_t gdt_entries[GDT_SIZE * 8];
|
|
struct gdt_descriptor *gdtr = (struct gdt_descriptor *)GDT_ADDRESS;
|
|
|
|
static void set_gdt_entry_value(uint8_t *target, uint32_t base, uint32_t limit,
|
|
uint8_t access, uint8_t granularity)
|
|
{
|
|
if (limit > 0xFFFFF) {
|
|
kprintf(KERN_ERR
|
|
"GDT cannot encode limits larger than 0xFFFFF");
|
|
}
|
|
|
|
// Encode the limit
|
|
target[0] = limit & 0xFF;
|
|
target[1] = (limit >> 8) & 0xFF;
|
|
target[6] = (limit >> 16) & 0x0F;
|
|
|
|
// Encode the base
|
|
target[2] = base & 0xFF;
|
|
target[3] = (base >> 8) & 0xFF;
|
|
target[4] = (base >> 16) & 0xFF;
|
|
target[7] = (base >> 24) & 0xFF;
|
|
|
|
// Encode the access byte
|
|
target[5] = access;
|
|
|
|
// Encode the flags
|
|
target[6] |= (granularity << 4);
|
|
}
|
|
|
|
void init_gdt(void)
|
|
{
|
|
gdtr->size = 8 * GDT_SIZE - 1;
|
|
gdtr->base = (uint32_t)&gdt_entries[0];
|
|
|
|
set_gdt_entry_value(gdt_entries + 0x00, 0, 0, 0, 0); // Null segment
|
|
|
|
set_gdt_entry_value(
|
|
gdt_entries + GDT_OFFSET_KERNEL_CODE, 0, 0xFFFFF,
|
|
GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_KERNEL_MODE |
|
|
GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_EXECUTABLE |
|
|
GDT_ACCESS_DC_NOT_CONFORM |
|
|
GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA |
|
|
GDT_ACCESS_A_ACCESSED,
|
|
GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // Kernel code
|
|
set_gdt_entry_value(
|
|
gdt_entries + GDT_OFFSET_KERNEL_DATA, 0, 0xFFFFF,
|
|
GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_KERNEL_MODE |
|
|
GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_NOT_EXECUTABLE |
|
|
GDT_ACCESS_DC_NOT_CONFORM |
|
|
GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA |
|
|
GDT_ACCESS_A_ACCESSED,
|
|
GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // Kernel data
|
|
set_gdt_entry_value(
|
|
gdt_entries + GDT_OFFSET_KERNEL_STACK, 0, 0xFFFFF,
|
|
GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_KERNEL_MODE |
|
|
GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_NOT_EXECUTABLE |
|
|
GDT_ACCESS_DC_CONFORM |
|
|
GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA |
|
|
GDT_ACCESS_A_ACCESSED,
|
|
GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // Kernel stack
|
|
|
|
set_gdt_entry_value(
|
|
gdt_entries + GDT_OFFSET_USER_CODE, 0, 0xFFFFF,
|
|
GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_USER_MODE |
|
|
GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_EXECUTABLE |
|
|
GDT_ACCESS_DC_CONFORM |
|
|
GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA |
|
|
GDT_ACCESS_A_ACCESSED,
|
|
GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // User code
|
|
set_gdt_entry_value(
|
|
gdt_entries + GDT_OFFSET_USER_DATA, 0, 0xFFFFF,
|
|
GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_USER_MODE |
|
|
GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_NOT_EXECUTABLE |
|
|
GDT_ACCESS_DC_NOT_CONFORM |
|
|
GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA |
|
|
GDT_ACCESS_A_ACCESSED,
|
|
GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // User data
|
|
set_gdt_entry_value(
|
|
gdt_entries + GDT_OFFSET_USER_STACK, 0, 0xFFFFF,
|
|
GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_USER_MODE |
|
|
GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_NOT_EXECUTABLE |
|
|
GDT_ACCESS_DC_CONFORM |
|
|
GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA |
|
|
GDT_ACCESS_A_ACCESSED,
|
|
GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // User stack
|
|
// TSS
|
|
set_gdt_entry_value(gdt_entries + GDT_OFFSET_TSS, (uint32_t)&TSS,
|
|
sizeof(struct tss) - 1, 0x89, 0);
|
|
|
|
set_gdt(((uint32_t)gdtr));
|
|
}
|