I'm trying to get my GDT setup following the tutorial on the Wiki. Unfortunately, as soon as I try to flush my GDT, the system (i.e. qemu) appears to jump to a random address, and if I continue execution under the debugger it will restart. I assume this means some exception is being thrown, but I don't know which one; since the GDT is a prerequisite for the IDT (as I understand it), I don't have the latter set up.
I'm using the following function to initialize the GDT. It's basically copy-pasted from the tutorial:
Code: Select all
global _set_gdt
_set_gdt:
mov eax, [esp + 4]
mov [gdtr + 2], eax
mov ax, [esp + 8]
mov [gdtr], ax
lgdt [gdtr]
reloadSegments:
; Reload CS register containing code selector:
jmp 0x08:reload_CS ; 0x08 points at the new code selector
reload_CS:
; Reload data segment registers:
mov ax, 0x10 ; 0x10 points at the new data selector
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
ret
Code: Select all
struct gdt_descriptor
{
uint32_t base;
uint32_t limit;
uint32_t type;
};
typedef struct gdt_descriptor gdt_descriptor_t;
static const uint32_t tss = 0xffffff97;
static const uint32_t tss_length = 0x68;
static const gdt_descriptor_t gdt_definitions[] =
{
{.base = 0, .limit = 0, .type = 0}, // Selector 0x0, null descriptor Cannot be used.
{.base = 0, .limit = 0xffffffff, .type = 0x9A}, // Selector 0x08, code
{.base = 0, .limit = 0xffffffff, .type = 0x10}, // Selector 0x10, data
{.base = tss, .limit = tss + tss_length, .type = 0x89} // Selector 0x18, TSS
};
static uint8_t gdt[GDT_ENTRY_SIZE * (sizeof(gdt_definitions) / sizeof(gdt_descriptor_t))];
Code: Select all
void gdt_initialize()
{
const size_t gdt_entry_count = sizeof(gdt_definitions) / sizeof(gdt_descriptor_t);
memset(gdt, 0, sizeof(gdt));
for(size_t i = 0; i < gdt_entry_count; ++i)
{
encode_gdt_entry(gdt + (i * GDT_ENTRY_SIZE), gdt_definitions[i]);
}
_set_gdt(gdt, sizeof(gdt));
}
Code: Select all
(gdb) x/32xb gdt
0x107020 <gdt>: 0x00 0x00 0x00 0x00 0x00 0x00 0x40 0x00
0x107028 <gdt+8>: 0xff 0xff 0x00 0x00 0x00 0x9a 0xcf 0x00
0x107030 <gdt+16>: 0xff 0xff 0x00 0x00 0x00 0x10 0xcf 0x00
0x107038 <gdt+24>: 0xff 0xff 0x97 0xff 0xff 0x89 0xcf 0xff
Stepping through in the debugger, everything looks correct up until the `mov ds, ax` instruction in `reload_CS`. Once that executes, the exception/crash occurs. One thing I'd like to do is check the value of the GDT register once I set it, but gdb can't do that and I don't know how to do it in qemu (if it's even possible). Any help is much appreciated!
PS: I noticed that the GDT tutorial uses Intel/NASM syntax whereas the getting started tutorials use AT&T/GAS. It would be nice to make these consistent.