pagingvirtual-memoryinterrupt-handlingosdevfault

Triple fault with higher-half kernel and interrupts


I am developing a tiny operating system for learning purposes (code here: https://github.com/davidedellagiustina/ScratchOS).

I have a higher half kernel running at 0xc0004000, mapped to physical 0x4000. The default page directory maps this area correctly and then has an entry for identity mapping the first 1MB of RAM (needed to jump to higher half). After entering the higher half, I delete the first entry of the page directory, invalidate the TLB and everything is fine (I get page faults if I try to access address 0x4000, so the page directory is updated successfully).

After that I set up an interrupt vector and interrupt handler functions for time and keyboard, and eventually I try to create a new and more complete page directory and replace the boot one, but I get a triple-fault when replacing the old one.

Currently the only way I can avoid the triple-fault is loading a new page directory that identity maps the first 1MB of RAM, and even trying to delete the first entry of the page directory after loading it (as I did during boot process) results in a triple-fault (so the identity mapping must stay there).

I was able to find out that disabling interrupts before switching page table (or even never re-enabling them after switching to protected mode, earlier on boot [comment instruction asm volatile("sti"); in function irq_init() at the bottom of file src/cpu/isr.c to test]) prevents the CPU from triple-faulting. So, I guess that I may have some problems with either my IDT (files src/cpu/idt.* and src/cpu/isr.*) or my GDT (loaded back in boot process when switching to protected mode, files src/boot/bootsect.asm and src/boot/gdt.asm). I aready double checked all the addresses loaded in these two structures. What am I missing? It looks like to me that it triple-faults because at some point, with no identity mapping of the first page, it cannot find the entire interrupt vector (which is loaded in virtual memory inside kernel, so mapped to physical first page), but the strange behaviour is that (see first paragraph) if the page directory which does not identity map the first 1MB is the boot one, it doesn't complain.

Can anybody help find out my mistake(s)?


Solution

  • The gdt and idt registers both take virtual addresses. When you disable the low mapping, that means that the next reference to the gdt or idt will cause a page fault. You need to reload both of these registers with their high-address equivalent before deleting the unity-page.