I've been banging my head against a wall with this one. Hopefully someone will point out the obvious I'm missing.
Before entering long mode I identity map the first 4MB using 2x2MB pages. I also map the same PDPT high in the PML4 for higher half. This works.
Once my kernel is in C in the higher half, I parse GRUBs' memory map and attempt to map the rest of the RAM. At the same time removing the 4MB of identity mappings. This bit doesn't work. By doesn't work I mean I can't seem to get the TLB to flush. No, I'm not using global pages and I've even tried turning global pages off in CR4. Reloading CR3 or invlpg doesn't seem to shift the mappings!! WTH? I've only tested in BOCHS and QEmu.
Below is some code just to illustrate what I'm trying. Please, someone give me a "one liner" and point out how stupid I'm being. More code upon request.
Code: Select all
extern volatile uint64 *_boot_pml4;
extern volatile uint64 *_boot_pdpt;
extern volatile uint64 *_boot_pd0;
Code: Select all
address = 0;
//Map the first 1GB with 2MB pages
for(i = 0 ; i < 512 ; i++)
{
_boot_pd0[i] = address + 0x87;
address += (2*1024*1024);
}
/* Remove the identity mapping used when we first enabled long mode */
_boot_pdpt[0] = 0;
_boot_pml4[0] = 0;
/* reload CR3, flush TLB */
__asm__ volatile ("movq %0, %%cr3" :: "r" ((uint64)&_boot_pml4-KERNEL_VMA): "memory");
//amd64_invlpg(0x1ffff);
//amd64_invlpg(0x20000);
// __asm__ volatile("movq %cr3, %rax");
// __asm__ volatile("movq %rax, %cr3");
// __asm__("jmp 1f\n1:");
uint8 *p = (uint8*)0x1;
*p = 1; // I would expect this to fault