os/arch/i686/gdt.c

121 lines
2.7 KiB
C

#include <kernel/tty.h>
#include <debugging.h>
#include <stdint.h>
#include <stddef.h>
#define NUM_ENTRIES 3
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));
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 * 8 - 1;
gdt.base = entries;
for (int i = 0; i < NUM_ENTRIES; i++) {
print_hex_bytes(gdt.base + i, 8);
terminal_putchar('\n');
}
asm ( "lgdt %0" : : "m"(gdt) );
}
void gdt_init()
{
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 = 0x000003FF;
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_code.limit = 0x000003FF;
kernel_data.base = 0x00400000;
kernel_data.access_byte = 0b10010010;
kernel_data.flags = 0b1100;
terminal_writestring("Kernel Data: ");
add_entry(kernel_data);
terminal_putchar('\n');
load_gdt();
}