Seemingly random behaviour after implementing GDT
Posted: Mon Feb 21, 2022 6:24 am
Hi, I'm trying to make my own kernel. I'm following tutorials from this site's wiki, "The little book about OS development", and some example OS I found on Github.
After implementing loading GDT, errors happens randomly on random points when executing GDT related codes. Sometimes everything works fine, serial console prints messages that executes after the GDT loading is finished. But sometimes the serial console shows everything works, but the video memory isn't updated anymore. Sometimes everything just doesn't work at all. I have very little knowledge in this area and couldn't figure out what might be the cause.
After implementing loading GDT, errors happens randomly on random points when executing GDT related codes. Sometimes everything works fine, serial console prints messages that executes after the GDT loading is finished. But sometimes the serial console shows everything works, but the video memory isn't updated anymore. Sometimes everything just doesn't work at all. I have very little knowledge in this area and couldn't figure out what might be the cause.
Code: Select all
gdt_object gdt_objects[5];
gdt_table table;
void gdt_entries_init() {
serial_print(SERIAL_COM1_BASE, "GDT setup start.\n");
table.size = (sizeof(gdt_object)*5)-1;
table.base = (unsigned int)&gdt_objects;
// NULL descriptor (Required)
gdt_encode(&gdt_objects[0], 0, 0, 0, 0);
gdt_encode(&gdt_objects[1], 0, 0xfffff, 0x9a, 0xcf);
gdt_encode(&gdt_objects[2], 0, 0xfffff, 0x92, 0xcf);
gdt_encode(&gdt_objects[3], 0, 0xfffff, 0xfa, 0xcf);
serial_print(SERIAL_COM1_BASE, "Flag.\n");
gdt_encode(&gdt_objects[4], 0, 0xfffff, 0xf2, 0xcf);
gdt_flush((unsigned int)&table);
serial_printf(SERIAL_COM1_BASE, "GDT flushed\n");
}
void gdt_encode(gdt_object *target, unsigned int base, unsigned int limit, unsigned char access, unsigned char flags) {
cpu_cli();
if (limit > 0xFFFFF) {
serial_printf(SERIAL_COM1_BASE, "GDT source limit error.\nlimit: %X\nbase: %X\n", limit, base);
return;
}
target->base_low = base & 0xFFFF; // Lower word of the base address.
target->base_mid = (base >> 16) & 0xFF; // Middle byte of the base address.
target->base_high = (base >> 24) & 0xFF; // Higher byte of the base address.
target->limit_low = limit & 0xFFFF; // Lower word of the limit.
target->flags_limit = (limit >> 16) & 0x0F; // Higher byte of the limit.
target->access = access;
target->flags_limit |= (flags) & 0xF0;
// serial_printf(
// SERIAL_COM1_BASE,
// "limit_low: %x\nbase_low: %x\nbase_mid: %x\naccess_byte: %x\nflags_limit: %x\nbase_high: %x\n\n",
// target->limit_low,
// target->base_low,
// target->base_mid,
// target->access,
// target->flags_limit,
// target->base_high
// );
cpu_sti();
}
Code: Select all
global cpu_sti
cpu_sti:
sti
ret
gdtr dw 0
dd 0
global gdt_flush:
gdt_flush:
mov eax, [esp + 4]
lgdt [eax]
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08:.flush
.flush:
ret