os/arch/i686/gdt.c
2024-08-13 15:25:39 +02:00

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