Hello!
I am brand new to these forums and also to device driver writing and the Windows kernel, so please excuse my “noobishness” as I’m sure this is probably a very simple question.
So I have a project that requires me to write simple device driver that will translate a virtual address to a physical address. I realise there are probably built-in functions for this, but I am required to go through the process of manually stepping through the paging process. PAE is to be disabled, I am running on a single core Windows XP box, and I have to account for 4KB and 4MB page sizes and tell whether the address is currently present in memory or not. Using the CR3 register as the base address, I map in the physical address content of the page directory (via MmMapIoSpace) into virtual memory so I can traverse it, then take the correct PDE to get the page table base, perform the same steps with the page table, and so on until I arrive at the physical address.
Very simple. My driver is able to correctly translate virtual addresses into physical addresses (verified using WinDbg’s !pte and !vtop functions). However, lower addresses, say, for example, 0x10fff, are not translating correctly. After hours of looking for the problem, I realise that my driver is not correctly addressing roughly the lower 2GB of virtual address space. After a few more hours of trying to figure out why, I learned that Windows allocates the lower 2GB for user addresses, and the higher 2GB for system addresses. Therefore, my driver is correctly translating system (kernel mode) addresses, but it seems to be failing at translating the user space addresses, or so I am guessing.
Using !pte I saw why the address translation was failing. Apparently my program does not have the same PDE as the debugger !pte output. Like before, it matches on higher addresses and is translating correctly, but there is a mismatch on the lower addresses. Unfortunately, I am at school currently and do not have access to my test platform to copy/paste results, but it was something like this:
PDE at 0xC0300000, contains 0xA12345
where as my program contains something like 0x57cd067 or something. Sometimes it will just contain 0x0. This clearly leads to incorrect output.
So I figured “well, there is a problem with mapping the physical addresses block to virtual addresses”. I went ahead and did some code like this to test:
unsigned long *ptr = 0xC0300000;
unsigned long pde = *ptr;
And low and behold, I still couldn’t retrieve the 0xA12345 entry that the debugger claimed to have said, I still got 0x57cd067! So I pointed to the EXACT same location that Windows is using for address translation (as opposed to my program), and still got incorrect results with relation to the debugger output.
After a few more hours of reading, I suspected it was because I was using data types that Windows didn’t like, thus tried using “driver” data types such as ULONG, PVOID, etc, and still couldn’t match the PDE.
I am thoroughly stumped. I have worked on an explanation for this with some of my peers and even with some of the professors at my university, and no one seems to be able to figure out why. My best guess is that there is some sort of permission denial or protection on those memory regions, but still…I’m running in kernel mode so shouldn’t I be able to access all user memory? I just don’t know. At this point I have absolutely no idea what I am doing wrong nor how to fix it so I can correctly translate all addresses.
Any explanation would be greatly appreciated in my quest to completing this project. Thank you.