I'm working on a kernel for i386 and want to do the following:
- Write data to a virtual 4MB page in the current page directory ("current" as in it's loaded to
cr3
). - Make a separate page directory and set one of its entries to map to the physical address mapped to the 4MB page mentioned in step (1).
- Unmap the virtual page from step in the current page directory (that is, set that PD's entry to zero).
- Load the separate page directory from step 2 (via
cr3
) and read that data.
My intention with this is that I can write data to a page in one address space, then "transfer" that data to another address space by mapping to a page in that AS, then umapping the page in the current AS. However, this doesn't seem to work as intended. Once I load the second page directory, I'm noticing the data I wrote in step 1 isn't actually at the new virtual page I mapped to. I assume this has something to do with the TLB not properly being flushed, but I call invlpg
on the virtual addresses in steps 2 and 3.
I'm able to fix this by flushing the entire TLB by reloading cr3
. That is:
mov %cr3, %eax
mov %eax, %cr3
If I do this at the end of step 2 (after mapping the page in the separate page directory), then I can expect to see the data I wrote from step 1 in the new page dir after it's loaded.
Does this only work because invlpg
will only invalidate TLB entries for pages in the current page directory? I always thought the TLB operated completely separately from the page table. One thing I expected was also for the TLB to be flushed at the start of step 4 when I load the new page directory via cr3
, but I'm not seeing expected behavior.