First off, I have two parts, a x64 uefi loader, and a x64 elf kernel. The loader essentially parses the kernel, sticks it in at 1MB and jumps to it.
The first problem is when I attempt to start the kernel in the loader. I disable interrupts, set up the gdt, and try to far jump to it, to segment 0x10 and the kernel start address. This causes VirtualBox to kill the VM, having an issue with the instruction jmp far %rcx. It does work fine when I jump to it normally, using the segment that uefi stuck me in by default (0x28).
This isn't a massive problem yet, since it works just jumping directly there.
The relevant code:
Code: Select all
UINT16 initialGdt[] =
{
/* gdt[0]: dummy */
0, 0, 0, 0,
/* gdt[1]: unused */
0, 0, 0, 0,
/* gdt[2]: code */
0xFFFF, /* 4Gb - (0x100000*0x1000 = 4Gb) */
0x0000, /* base address=0 */
0x9A00, /* code read/exec */
0x00CF, /* granularity=4096, 386 (+5th nibble of limit) */
/* gdt[3]: data */
0xFFFF, /* 4Gb - (0x100000*0x1000 = 4Gb) */
0x0000, /* base address=0 */
0x9200, /* data read/write */
0x00CF, /* granularity=4096, 386 (+5th nibble of limit) */
};
void StartKernel(void* address, KernelInfo* kinfo)
{
// Disable interrupts
__asm__ volatile("cli");
SetMem(gdtAddress.base, gdtAddress.limit, 0);
CopyMem(gdtAddress.base, initialGdt, sizeof(initialGdt));
__asm__ volatile("lidt %0" : : "m" (idtAddress));
__asm__ volatile("lgdt %0" : : "m" (gdtAddress));
__asm__ volatile("mov %0, %%rdi" : : "m" (kinfo));
__asm__ volatile("mov %0, %%rcx" : : "m" (address));
__asm__ volatile("jmp *%rcx");
}
interrupt.c
Code: Select all
static void SetIDT(u8 number, void* asmHandler, u16 selector, u8 flags, InterruptHandler handler)
{
idt[number].Offset1 = (u64)asmHandler & 0xFFFF;
idt[number].Offset2 = ((u64)asmHandler >> 16) & 0xFFFF;
idt[number].Offset3 = ((u64)asmHandler >> 32) & 0xFFFFFFFF;
idt[number].SegmentSelector = selector;
idt[number].Flags = flags;
isrHandlers[number] = handler;
}
void InitIDT()
{
SerialWriteText("Interrupts: Setting up interrupts\n");
SetIDT(0, &IDT0, 0x28, 0x8E, DefaultHandler);
...
SetIDT(31, &IDT31, 0x28, 0x8E, DefaultHandler);
SetIDT(238, &IDT238, 0x28, 0x8E, DefaultHandler);
DescriptorTableAddress idtAddress = { sizeof(IDTDescriptor) * 255, 0 };
memcpy(idtAddress.Base, &idt, idtAddress.Limit);
asm volatile("lidt %0" : : "m" (idtAddress));
asm volatile("sti");
SerialWriteText("Interrupts: Finished setting up interrupts\n");
}
Code: Select all
IDT0:
mov $0xDEADBABE, %rdx
hlt
iretq
The 0xDEADBABE isn't in the rdx register either, so I can assume that the interrupt handler isn't even called.
I'm unsure exactly what state UEFI leaves me in after I leave it. I'm fairly certain paging is disabled since cr3 doesn't have bit 31 enabled.