122 lines
3.6 KiB
C
122 lines
3.6 KiB
C
#pragma once
|
|
|
|
#include "../../kernel/memory.c"
|
|
#include <stdint.h>
|
|
|
|
struct gdt_row_t {
|
|
uint16_t limit_low;
|
|
uint16_t base_low;
|
|
uint8_t base_middle;
|
|
uint8_t access;
|
|
uint8_t granularity_limit_high;
|
|
uint8_t base_high;
|
|
} __attribute__((packed));
|
|
|
|
struct gdt_ptr_t {
|
|
uint16_t size;
|
|
uint32_t address;
|
|
} __attribute__((packed));
|
|
|
|
struct tss_row_t {
|
|
uint32_t prev_tss;
|
|
uint32_t esp_ring0;
|
|
uint32_t ss_ring0;
|
|
uint32_t padding[23]; // Extra options RAZZLE doesn't use
|
|
} __attribute__((packed));
|
|
|
|
enum gdt_access_t {
|
|
GDT_ACCESS_PRESENT = 0b10000000,
|
|
GDT_ACCESS_DPL_KERNEL = 0b00000000,
|
|
GDT_ACCESS_DPL_USER = 0b01100000,
|
|
GDT_ACCESS_CODEDATA = 0b00010000,
|
|
GDT_ACCESS_EXECUTABLE = 0b00001000,
|
|
GDT_ACCESS_GROW_DOWN = 0b00000100,
|
|
GDT_ACCESS_RW = 0b00000010,
|
|
GDT_ACCESS_ACCESSED = 0b00000001,
|
|
};
|
|
|
|
enum gdt_granularity_t {
|
|
GDT_GRANULARITY_4K = 0b10001111,
|
|
GDT_GRANULARITY_MODE_32BIT = 0b01001111,
|
|
};
|
|
|
|
struct tss_row_t tss_entry;
|
|
|
|
#define GDT_SIZE (6)
|
|
struct gdt_row_t gdt[GDT_SIZE];
|
|
|
|
void load_gdt(struct gdt_ptr_t *gp) {
|
|
asm volatile("lgdt (%0)\n\t"
|
|
"mov $0x10, %%ax\n\t"
|
|
"mov %%ax, %%ds\n\t"
|
|
"mov %%ax, %%es\n\t"
|
|
"mov %%ax, %%fs\n\t"
|
|
"mov %%ax, %%gs\n\t"
|
|
"mov %%ax, %%ss\n\t"
|
|
:
|
|
: "r"(gp)
|
|
: "%ax");
|
|
}
|
|
|
|
void set_gdt_row(uint32_t num, uint32_t base, uint32_t limit, uint8_t access,
|
|
uint8_t granularity) {
|
|
gdt[num].base_low = base & 0xFFFF;
|
|
gdt[num].base_middle = (base >> 16) & 0xFF;
|
|
gdt[num].base_high = (base >> 24) & 0xFF;
|
|
gdt[num].limit_low = limit & 0xFFFF;
|
|
gdt[num].granularity_limit_high = (limit >> 16) & 0x0F;
|
|
gdt[num].granularity_limit_high |= granularity & 0xF0;
|
|
gdt[num].access = access;
|
|
}
|
|
|
|
void load_tss(uint16_t gdt_row_num) {
|
|
gdt_row_num *= 8;
|
|
__asm__ volatile("mov %0, %%ax; ltr %%ax" : : "r"(gdt_row_num) : "ax");
|
|
}
|
|
|
|
#define KERNEL_CODE_SEL (0x08)
|
|
#define KERNEL_DATA_SEL (0x10)
|
|
|
|
void init_gdt() {
|
|
struct gdt_ptr_t gp;
|
|
gp.size = (sizeof(struct gdt_row_t) * GDT_SIZE) - 1;
|
|
gp.address = (uint32_t)&gdt;
|
|
|
|
set_gdt_row(0, 0, 0, 0, 0);
|
|
|
|
// Kernelmode code/data degments
|
|
set_gdt_row(1, 0, 0xFFFFFFFF,
|
|
GDT_ACCESS_PRESENT | GDT_ACCESS_DPL_KERNEL | GDT_ACCESS_CODEDATA |
|
|
GDT_ACCESS_EXECUTABLE | GDT_ACCESS_RW | GDT_ACCESS_ACCESSED,
|
|
GDT_GRANULARITY_4K | GDT_GRANULARITY_MODE_32BIT);
|
|
set_gdt_row(2, 0, 0xFFFFFFFF,
|
|
GDT_ACCESS_PRESENT | GDT_ACCESS_DPL_KERNEL | GDT_ACCESS_CODEDATA |
|
|
GDT_ACCESS_RW | GDT_ACCESS_ACCESSED,
|
|
GDT_GRANULARITY_4K | GDT_GRANULARITY_MODE_32BIT);
|
|
|
|
// Usermode code/data segments
|
|
set_gdt_row(3, 0x0000000, 0xFFFFFFFF,
|
|
GDT_ACCESS_PRESENT | GDT_ACCESS_DPL_USER | GDT_ACCESS_CODEDATA |
|
|
GDT_ACCESS_EXECUTABLE | GDT_ACCESS_RW | GDT_ACCESS_ACCESSED,
|
|
GDT_GRANULARITY_4K | GDT_GRANULARITY_MODE_32BIT);
|
|
set_gdt_row(4, 0x0000000, 0xFFFFFFFF,
|
|
GDT_ACCESS_PRESENT | GDT_ACCESS_DPL_USER | GDT_ACCESS_CODEDATA |
|
|
GDT_ACCESS_RW | GDT_ACCESS_ACCESSED,
|
|
GDT_GRANULARITY_4K | GDT_GRANULARITY_MODE_32BIT);
|
|
|
|
// TSS row
|
|
set_gdt_row(5, (uint32_t)&tss_entry, sizeof(tss_entry),
|
|
GDT_ACCESS_PRESENT | GDT_ACCESS_EXECUTABLE | GDT_ACCESS_ACCESSED,
|
|
GDT_GRANULARITY_4K | GDT_GRANULARITY_MODE_32BIT);
|
|
|
|
// Setup TSS
|
|
int kstack = 0;
|
|
memset((char *)&tss_entry, 0, sizeof(tss_entry));
|
|
tss_entry.ss_ring0 = 0x10;
|
|
tss_entry.esp_ring0 = (uint32_t)&kstack;
|
|
|
|
// Load GDT and TSS
|
|
load_gdt(&gp);
|
|
load_tss(5);
|
|
}
|