158 lines
3.6 KiB
C
158 lines
3.6 KiB
C
#include <kernel/tty.h>
|
|
#include <kernel/gdt.h>
|
|
#include <debugging.h>
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
|
|
#define NUM_ENTRIES 256
|
|
|
|
struct SegmentDescriptor {
|
|
uint32_t limit;
|
|
uint32_t base;
|
|
uint8_t access_byte;
|
|
uint8_t flags;
|
|
};
|
|
|
|
struct GDT {
|
|
uint16_t size;
|
|
uint64_t* base;
|
|
} __attribute__((packed));
|
|
|
|
struct tss_entry_struct tss;
|
|
|
|
static uint64_t entries[NUM_ENTRIES];
|
|
static size_t current_entry = 0;
|
|
struct GDT gdt;
|
|
|
|
static void encodeGdtEntry(uint8_t *target, struct SegmentDescriptor source)
|
|
{
|
|
// Check the limit to make sure that it can be encoded
|
|
if (source.limit > 0xFFFFF) {
|
|
terminal_writestring("WARNING: GDT entry has a limit (");
|
|
print_hex_bytes(&source.limit, 4);
|
|
terminal_writestring(") that is larger than accepted.");
|
|
return;
|
|
}
|
|
|
|
// Encode the limit
|
|
target[0] = source.limit & 0xFF;
|
|
target[1] = (source.limit >> 8) & 0xFF;
|
|
target[6] = (source.limit >> 16) & 0x0F;
|
|
|
|
// Encode the base
|
|
target[2] = source.base & 0xFF;
|
|
target[3] = (source.base >> 8) & 0xFF;
|
|
target[4] = (source.base >> 16) & 0xFF;
|
|
target[7] = (source.base >> 24) & 0xFF;
|
|
|
|
// Encode the access byte
|
|
target[5] = source.access_byte;
|
|
|
|
// Encode the flags
|
|
target[6] |= (source.flags << 4);
|
|
|
|
print_hex_bytes(target, 8);
|
|
}
|
|
|
|
static void add_entry(struct SegmentDescriptor entry)
|
|
{
|
|
if (current_entry == NUM_ENTRIES) {
|
|
terminal_writestring("WARNING: More GDT entries than NUM_ENTRIES.\n");
|
|
return;
|
|
}
|
|
|
|
uint64_t descriptor = 0;
|
|
encodeGdtEntry((uint8_t*) &descriptor, entry);
|
|
|
|
entries[current_entry] = descriptor;
|
|
|
|
current_entry++;
|
|
}
|
|
|
|
static void load_gdt()
|
|
{
|
|
gdt.size = NUM_ENTRIES * sizeof(struct SegmentDescriptor) - 1;
|
|
gdt.base = entries;
|
|
|
|
asm ( "lgdt %0" : : "m"(gdt) );
|
|
}
|
|
|
|
void gdt_init()
|
|
{
|
|
// https://wiki.osdev.org/Global_Descriptor_Table
|
|
|
|
terminal_initialize();
|
|
struct SegmentDescriptor null;
|
|
null.limit = 0;
|
|
null.base = 0;
|
|
null.access_byte = 0;
|
|
null.flags = 0;
|
|
|
|
terminal_writestring("Kernel Null: ");
|
|
|
|
add_entry(null);
|
|
|
|
terminal_putchar('\n');
|
|
|
|
struct SegmentDescriptor kernel_code;
|
|
kernel_code.limit = 0xFFFFF;
|
|
kernel_code.base = 0x00000000;
|
|
kernel_code.access_byte = 0b10011010;
|
|
kernel_code.flags = 0b1100;
|
|
|
|
terminal_writestring("Kernel Code: ");
|
|
|
|
add_entry(kernel_code);
|
|
terminal_putchar('\n');
|
|
|
|
struct SegmentDescriptor kernel_data;
|
|
kernel_data.limit = 0xFFFFF;
|
|
kernel_data.base = 0x00000000;
|
|
kernel_data.access_byte = 0b10010010;
|
|
kernel_data.flags = 0b1100;
|
|
|
|
terminal_writestring("Kernel Data: ");
|
|
add_entry(kernel_data);
|
|
terminal_putchar('\n');
|
|
|
|
struct SegmentDescriptor user_code;
|
|
user_code.limit = 0xFFFFF;
|
|
user_code.base = 0x00000000;
|
|
user_code.access_byte = 0b11111010;
|
|
user_code.flags = 0b1100;
|
|
|
|
terminal_writestring("User Code: ");
|
|
|
|
add_entry(user_code);
|
|
terminal_putchar('\n');
|
|
|
|
struct SegmentDescriptor user_data;
|
|
user_data.limit = 0xFFFFF;
|
|
user_data.base = 0x00000000;
|
|
user_data.access_byte = 0b11110010;
|
|
user_data.flags = 0b1100;
|
|
|
|
terminal_writestring("User Data: ");
|
|
|
|
add_entry(user_data);
|
|
terminal_putchar('\n');
|
|
|
|
struct SegmentDescriptor tss_segment;
|
|
tss_segment.limit = sizeof(tss_segment) - 1;
|
|
tss_segment.base = (uint32_t) &tss;
|
|
tss_segment.access_byte = 0x89;
|
|
tss_segment.flags = 0b0000;
|
|
|
|
terminal_writestring("TSS Segment: ");
|
|
|
|
add_entry(tss_segment);
|
|
terminal_putchar('\n');
|
|
|
|
load_gdt();
|
|
|
|
tss.ss0 = 0x10;
|
|
asm("mov %%esp, %0" : "=r" (tss.esp0));
|
|
|
|
asm ("ltr %%ax" : : "a"(0x28));
|
|
}
|