I am currently developing a x86-64 kernel from scratch for research purposes. The goal is to virtualize my own OS using Intels virtualization technology (VT-x). However I stumbled upon a xtremely strange problem which prevents me from continuing my project:
As soon after I enter the guest OS, the 32-bit entry point of my kernel needs to fetch the address of the 64-bit entry point for the kernel to jump to. This is done by retrieving the values of the kernel ELF header located in guest physical memory. However, at this point where the kernel ELF header is being retrieved, my OS throws an error saying that at the specified address there's no header:
To explain the image: the bottom half of the screen is the output of the host while the top half is the output of the guest.
Now I wondered why there is nothing even though I was pretty sure I placed the kernel ELF header at the specific address in guest physical memory (0x0019A000). Now a very important information to keep in mind: At this point where the error message comes up, paging has not been enabled yet. That means, just as described in the Intel documentation:
If CR0.PG = 0, each linear address is treated as a guest-physical address.
At this point paging is definitely not enabled since CR0 does not have bit 31 set. (Value of CR0: 0x60000011)
So I inspected the physical memory dump via Bochs:
Seems to be there, but the execution happens in the linear address space, to the instruction pointer is reading the instructions from the linear address space, and then there's the issue:
So my question is: What reasons do exist for the physical and the linear address space to differ from each other at just this one memory region while paging is disabled?
I checked:
- The GDT (CS and DS setup for 32-bit, base = 0x0, limit = 0xfffff)
- The selectors for the segments are set accordingly
- The EPT used to map guest-physical addresses (GPA) to host-physical addresses (HPA): The address is definitely mapped, and even dumping the memory in the host-physical address space shows me that the kernel ELF header is there just as it should be
- Paging is definitely not enabled, so the memdump should show the same content in memory at the same address