If I don't immediate enable paging, I can't even write a single character to the video memory. It works in Bochs, but somehow I manage to crash the VMWare Player and VirtualBox emulators. The latter gives VERR_EM_INTERNAL_DISAS_ERROR and VERR_REM_VIRTUAL_CPU_ERROR Guru Meditation errors in the log.
The relevant bits from my linker script:
Code: Select all
ENTRY(KernelEntry)
SECTIONS
{
. = 0x00100000;
.multiboot ALIGN(0x1000) :
{
*(.multiboot)
}
.setup :
{
*(.setup)
}
. += 0xC0000000;
.text ALIGN(0x1000) : AT(ADDR(.text) - 0xC0000000)
{
*(.text)
*(.gnu.linkonce.t*)
}
...
Code: Select all
[BITS 32]
section .setup
global Temporary_GDT
Temporary_GDT:
dw gdt_end - gdt - 1 ; The size of the GDT
dd gdt ; The linear address of the GDT
gdt:
dd 0, 0 ; NULL GDT
; Code selector 0x08: base 0x40000000, limit 0xFFFFFFFF, type 0x9A, granularity 0xCF
db 0xFF, 0xFF, 0, 0, 0, 10011010b, 11001111b, 0x40
; Data selector 0x10: base 0x40000000, limit 0xFFFFFFFF, type 0x92, granularity 0xCF
db 0xFF, 0xFF, 0, 0, 0, 10010010b, 11001111b, 0x40
gdt_end:
section .text
cli
lgdt [Temporary_GDT]
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08:HigherHalf
HigherHalf:
mov esp, KernelStack
call KernelMain
; ...
Code: Select all
extern "C" void KernelMain()
{
// Normal VideoRAM address minus 0x40000000, the fake GDT base; or: 0xC00B8000
uint16* videoRam = (uint16*)(0xB8000 - 0x40000000);
videoRam[0] = 0x0F00 + 'A';
while (true);
}
When I postpone writing anything to the screen until after I've enabled paging and the new GDT, then everything works just fine. I don't want to enable paging just yet. What am I doing wrong?