Problem Accessing Some Memory For Manual Address Translation

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.

Your project is doomed. You have no way to coordinate the memory
manager with your driver so while your driver is walking things it is
easy enough for the memory manager to change things.

Your specific problem is that every process has its own address space
for memory and addresses in this space can map into different physical
addresses. This is your 2GB problem unless you are running in the
context of the desired process you have different addresses.

Whoever put the requirement you do this without standard calls is worse
than an idiot, assuming this is for a company the person should be fired
for cause immediately.

Don Burn (MVP, Windows DKD)
Windows Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr

xxxxx@yahoo.com” wrote in message
news:xxxxx@ntdev:

> 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.

Don Burn wrote:

Whoever put the requirement you do this without standard calls is worse
than an idiot, assuming this is for a company the person should be fired
for cause immediately.

He’s a student. This is a learning assignment.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

I guess that means he is learning the professor is an idiot.

Don Burn (MVP, Windows DKD)
Windows Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr

“Tim Roberts” wrote in message news:xxxxx@ntdev:

> Don Burn wrote:
> > Whoever put the requirement you do this without standard calls is worse
> > than an idiot, assuming this is for a company the person should be fired
> > for cause immediately.
>
> He’s a student. This is a learning assignment.
>
> –
> Tim Roberts, xxxxx@probo.com
> Providenza & Boekelheide, Inc.

xxxxx@yahoo.com wrote:

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.

How are you getting in to your driver to read this information?
Remember that the lower 2GB of the page tables is different for every
process. Here’s one possible explanation. Let’s say your driver is
reading this data in response to an ioctl. Let’s further say you wrote
this as a KMDF driver and turned on synchronization scope. In that
case, your callbacks are being called from a system process, not from
the original calling process. The page tables will not be what you expect.

Do you want to post some of your code? I can’t promise we will all be
kind to it.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

I commend you for not trying to hide that you are a student working on an
assignment. Not sure if the assignment can be done as you have stated it in
Windows, but you have gone a long way to doing what is possible. What you
might not understand is that *every* 32 bit usermode process on 32-bit
Windows has the same address space, from 0-2GB is the space for the UM code,
and 2-4GB is the shared system space. So while you are in kernel mode, all
the addresses in the system space work fine, and you will get inconsistent
results (at best, a crash or silently corrupted data at worst) in the UM
address space.

So how to resolve? You need to map the UM addresses into the System Space.
If you were using system calls to do it, MmMapLockedPagesSpecifyCache() and
friends would be the way to do so. If you aren’t able to do that, you’ll
probably have to reverse engineer them to understand how Windows does it.
Once you get that, you should be able to dump your process’s address space.
I wouldn?t recommend trying any other process’s address space right away.

Phil

Philip D. Barila??? (303) 776-1264

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@yahoo.com
Sent: Tuesday, March 22, 2011 11:46 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] Problem Accessing Some Memory For Manual Address
Translation

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.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Wow, thanks for some of the fast responses guys.

This is actually an assignment I was given as a exercise for an interview. The person who gave this assignment did mention that this assignment was to serve the purpose of getting our feet wet with writing a simple driver and getting it to compile, and I think the purpose was also to demonstrate our understanding of how paging works, and probably to get a feel for our coding style as well. I’m not sure if they are actually looking for 100 percent correct output, though I personally wanted to get it perfect. Here is some code I wrote (I have made some minor changes on my computer at home, but this should be reasonably close enough). This is the function I’m using for conversion (please excuse me if this is super amateurish):

unsigned long VirtualToPhysical(unsigned long VirtualAddress)

{

PHYSICAL_ADDRESS pa;

unsigned long *PageDirectory, *PageTable, *PageFrame;

unsigned long Directory, Table, Offset, P_Flag, PS_Flag, Entry, BasePhysicalAddress;

//Bit shifting to extract the page directory offset

Directory = VirtualAddress >> 22; //Get leading 10 bits

//Load up CR3, or the page directory physical address base

__asm mov eax, cr3

__asm mov pa.LowPart, eax

pa.HighPart = 0x0;

//4*1024 = 4KB directory size

if((PageDirectory = MmMapIoSpace(pa, 4*1000, FALSE)) == NULL)

return 0;

Entry = *(PageDirectory + Directory);

P_Flag = Entry & 0x1; //Get bit-0

PS_Flag = (Entry << 24) >> 31; //Get bit-7

//If page table doesn’t exist in physical memory

if(P_Flag == 0)

return 0;

//Case of 4KB pages

if(PS_Flag == 0)

{

//DbgPrint(“4Kb”);

Table = (VirtualAddress << 10) >> 22; //Get the “table” bits

Offset = (VirtualAddress << 20) >> 20; //Get the “offset” bits

pa.LowPart = (Entry >> 12) << 12; //Clear lower 12 bits

//Load in the page table into virtual memory for parsing

if((PageTable = MmMapIoSpace(pa, 4*1000, FALSE)) == NULL)

return 0;

//The entry is the contents of the page table + table offset

Entry = *(PageTable + Table);

//Entry = *(PageTable) | (Table << 2);

//DbgPrint(“PTE: %x”, *(PageTable+1));

P_Flag = Entry & 1; //Get the 0-bit

//If the page doesn’t exist in physical memory

if(P_Flag == 0)

return 0;

return ((Entry >> 12) << 12) | (Offset << 2);

}

//Case of 4MB pages

else

{

//DbgPrint(“4MB”);

Offset = (VirtualAddress << 10) >> 10; //Get the 22 offset bits

return ((Entry >> 22) << 22) | (Offset << 2);

}

}

xxxxx@yahoo.com wrote:

Wow, thanks for some of the fast responses guys.

This is actually an assignment I was given as a exercise for an interview. The person who gave this assignment did mention that this assignment was to serve the purpose of getting our feet wet with writing a simple driver and getting it to compile, and I think the purpose was also to demonstrate our understanding of how paging works, and probably to get a feel for our coding style as well. I’m not sure if they are actually looking for 100 percent correct output, though I personally wanted to get it perfect. Here is some code I wrote (I have made some minor changes on my computer at home, but this should be reasonably close enough). This is the function I’m using for conversion (please excuse me if this is super amateurish):

Well, it’s not the way I would have written it, and I’m going to have to
bite my tongue to resist the temptation to issue style observations, but
this doesn’t answer the question of “how did you get there”. The issue
of mapping user space requires that you know exactly what process
context you’re in.

I will say that ((x >> 12) << 12) seems like an odd way to write (x &
~0xfff), which more accurately expresses the intent. And (Entry << 24)

> 31 seems like an odd way to write ((Entry >> 7) & 1). I always worry
about sign-extending, even though you have used unsigned types.

Also, when you MmMapIoSpace, you are supposed to unmap it eventually.
And a page is 4096 bytes, not 4 * 1000.

//4*1024 = 4KB directory size
if((PageDirectory = MmMapIoSpace(pa, 4*1000, FALSE)) == NULL)


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

One way to handle the low order 2GB is to use KeStackAttachProcess to
set the process context to the one you want. Also, if your driver is
KMDF you can use an EvtIoInContext call to force your context to the be
the calling process.

As Tim noted in his last message there are cleaner ways to extract the
bits. Also, please remember that for any real product this has the
probability of crashing due to the lack of coordination with the memory
manager. This is why I called the individual who assigned it an idiot,
since way too many times in my career I have seen these simple
assignments carried forward into a product when the constraints placed
on the assignment mean the code is never going to be safe.

Don Burn (MVP, Windows DKD)
Windows Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr

xxxxx@yahoo.com” wrote in message
news:xxxxx@ntdev:

> Wow, thanks for some of the fast responses guys.
>
> This is actually an assignment I was given as a exercise for an interview. The person who gave this assignment did mention that this assignment was to serve the purpose of getting our feet wet with writing a simple driver and getting it to compile, and I think the purpose was also to demonstrate our understanding of how paging works, and probably to get a feel for our coding style as well. I’m not sure if they are actually looking for 100 percent correct output, though I personally wanted to get it perfect. Here is some code I wrote (I have made some minor changes on my computer at home, but this should be reasonably close enough). This is the function I’m using for conversion (please excuse me if this is super amateurish):
>
> unsigned long VirtualToPhysical(unsigned long VirtualAddress)
>
> {
>
> PHYSICAL_ADDRESS pa;
>
> unsigned long *PageDirectory, PageTable, PageFrame;
>
> unsigned long Directory, Table, Offset, P_Flag, PS_Flag, Entry, BasePhysicalAddress;
>
>
>
> //Bit shifting to extract the page directory offset
>
> Directory = VirtualAddress >> 22; //Get leading 10 bits
>
>
>
> //Load up CR3, or the page directory physical address base
>
> asm mov eax, cr3
>
>
asm mov pa.LowPart, eax
>
> pa.HighPart = 0x0;
>
>
>
> //4
1024 = 4KB directory size
>
> if((PageDirectory = MmMapIoSpace(pa, 4
1000, FALSE)) == NULL)
>
> return 0;
>
>
>
> Entry = (PageDirectory + Directory);
>
>
>
> P_Flag = Entry & 0x1; //Get bit-0
>
> PS_Flag = (Entry << 24) >> 31; //Get bit-7
>
>
>
> //If page table doesn’t exist in physical memory
>
> if(P_Flag == 0)
>
> return 0;
>
>
>
> //Case of 4KB pages
>
> if(PS_Flag == 0)
>
> {
>
> //DbgPrint(“4Kb”);
>
>
>
> Table = (VirtualAddress << 10) >> 22; //Get the “table” bits
>
> Offset = (VirtualAddress << 20) >> 20; //Get the “offset” bits
>
>
>
> pa.LowPart = (Entry >> 12) << 12; //Clear lower 12 bits
>
>
>
> //Load in the page table into virtual memory for parsing
>
> if((PageTable = MmMapIoSpace(pa, 4
1000, FALSE)) == NULL)
>
> return 0;
>
>
>
> //The entry is the contents of the page table + table offset
>
> Entry = *(PageTable + Table);
>
> //Entry = *(PageTable) | (Table << 2);
>
>
>
> //DbgPrint(“PTE: %x”, *(PageTable+1));
>
>
>
> P_Flag = Entry & 1; //Get the 0-bit
>
>
>
> //If the page doesn’t exist in physical memory
>
> if(P_Flag == 0)
>
> return 0;
>
>
>
>
>
> return ((Entry >> 12) << 12) | (Offset << 2);
>
>
>
>
>
> }
>
> //Case of 4MB pages
>
> else
>
> {
>
> //DbgPrint(“4MB”);
>
>
>
> Offset = (VirtualAddress << 10) >> 10; //Get the 22 offset bits
>
>
>
>
>
> return ((Entry >> 22) << 22) | (Offset << 2);
>
> }
>
>
>
> }

Ah yes, those are some of the changes that I made. I realised the excessive bit shifting was sloppy, and replaced it with masking.

While I appreciate your reservation in critiquing the code, I would actually really like criticism, as I am striving every day to become a better programmer. I am new to computer architecture, hardware, drivers, etc. A week ago I had no experience whatsoever, so if you could share how you would approach this problem (keeping in mind I am very new to this stuff) I would find that exceptionally helpful. I feel like I’m just fumbling through this without really much to go on besides the Intel manual’s description of address translations and scattered bits and pieces of information on drivers I find online . Also, it is clear that I don’t understand operating systems enough to really write any intelligible driver. Is there some sort of beginner guide or book you could please refer me to? Where did you start?

As to answer your question, “how did I get there”, I suppose I’m not fully understanding what you are looking for. Could you please elaborate on what information you need?

Again, thank you gentlemen for your time.

xxxxx@yahoo.com wrote:

As to answer your question, “how did I get there”, I suppose I’m not fully understanding what you are looking for. Could you please elaborate on what information you need?

From where is your conversion function being called? I assume that this
all started from a DeviceIoControl call in an application, which
eventually sends an IRP to your driver that you are responding to. Is
this a KMDF driver, so that you have an EvtIoDeviceControl handler? Or
is it a WDM driver, so that you have an IRP_MJ_DEVICE_CONTROL handler?


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Oh I see.

No, it is being called from DriverEntry. There is no I/O at all in this driver, I simply just hardcode some address I want translated, and pass it into the function. There were no specifications for I/O or anything. All this assignment literally does is pass in a hardcoded address, does the address translation, and prints the result to DbgPrint. It is literally just has DriverEntry, DriverUnload, and my function. It was never meant to be a formal driver. There is no application associated with it. It’s literally that simple.

I really believe the scope of this assignment is to show I can build/compile a “driver” that is able to be loaded and unloaded, and also to demonstrate I understand the basic concepts of paging.

Then you are going to have to use KeStackAttachProcess to access the
lower 2GB since the driver is running in the system process context that
does not have the lower 2GB mapped.

Don Burn (MVP, Windows DKD)
Windows Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr

xxxxx@yahoo.com” wrote in message
news:xxxxx@ntdev:

> Oh I see.
>
> No, it is being called from DriverEntry. There is no I/O at all in this driver, I simply just hardcode some address I want translated, and pass it into the function. There were no specifications for I/O or anything. All this assignment literally does is pass in a hardcoded address, does the address translation, and prints the result to DbgPrint. It is literally just has DriverEntry, DriverUnload, and my function. It was never meant to be a formal driver. There is no application associated with it. It’s literally that simple.
>
> I really believe the scope of this assignment is to show I can build/compile a “driver” that is able to be loaded and unloaded, and also to demonstrate I understand the basic concepts of paging.

Thank you for pointing me in the right direction, it is more clear. I will go ahead and learn about KeStackAttachProcess and contexts and how to integrate it into this assignment.

Again, thank you gentlemen for your time and patience. I appreciate your assistance.

Also, the last parameter to MmMapIoSpace is not a boolean. It’s a memory cache type, and you should pass MmCached here since page tables are cached.

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Tim Roberts
Sent: Tuesday, March 22, 2011 11:23 AM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] Problem Accessing Some Memory For Manual Address Translation

Also, when you MmMapIoSpace, you are supposed to unmap it eventually.
And a page is 4096 bytes, not 4 * 1000.

//4*1024 = 4KB directory size
if((PageDirectory = MmMapIoSpace(pa, 4*1000, FALSE)) == NULL)

The system process usually does have a few user space allocations in it, you can dump them using !vad in kd.

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Don Burn
Sent: Tuesday, March 22, 2011 12:07 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Problem Accessing Some Memory For Manual Address Translation

Then you are going to have to use KeStackAttachProcess to access the lower 2GB since the driver is running in the system process context that does not have the lower 2GB mapped.

xxxxx@yahoo.com” wrote in message
news:xxxxx@ntdev:

> Oh I see.
>
> No, it is being called from DriverEntry. There is no I/O at all in this driver, I simply just hardcode some address I want translated, and pass it into the function. There were no specifications for I/O or anything. All this assignment literally does is pass in a hardcoded address, does the address translation, and prints the result to DbgPrint. It is literally just has DriverEntry, DriverUnload, and my function. It was never meant to be a formal driver. There is no application associated with it. It’s literally that simple.
>
> I really believe the scope of this assignment is to show I can build/compile a “driver” that is able to be loaded and unloaded, and also to demonstrate I understand the basic concepts of paging.

A “levelonemage” huh … Is that defining one as most or least desirable. Note, all of those answering your questions are not using “twit” nicknames or gamer names.

Gary G. Little

----- Original Message -----
From: xxxxx@yahoo.com
To: “Windows System Software Devs Interest List”
Sent: Tuesday, March 22, 2011 1:40:50 PM
Subject: RE:[ntdev] Problem Accessing Some Memory For Manual Address Translation

Ah yes, those are some of the changes that I made. I realised the excessive bit shifting was sloppy, and replaced it with masking.

While I appreciate your reservation in critiquing the code, I would actually really like criticism, as I am striving every day to become a better programmer. I am new to computer architecture, hardware, drivers, etc. A week ago I had no experience whatsoever, so if you could share how you would approach this problem (keeping in mind I am very new to this stuff) I would find that exceptionally helpful. I feel like I’m just fumbling through this without really much to go on besides the Intel manual’s description of address translations and scattered bits and pieces of information on drivers I find online . Also, it is clear that I don’t understand operating systems enough to really write any intelligible driver. Is there some sort of beginner guide or book you could please refer me to? Where did you start?

As to answer your question, “how did I get there”, I suppose I’m not fully understanding what you are looking for. Could you please elaborate on what information you need?

Again, thank you gentlemen for your time.


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

I wonder how I was able to get by through 15 years of writing drivers without walking a page table even once.

Although I have written page table management code for my standalone memtest program.

> 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

For nonpaged kernel memory - yes. MmGetPhysicalAddress.

But note: Windows is designed in a way to hide the physical addresses from all code at all, the only valid need in a physical address is considered to be DMA, and, with DMA APIs, you can only see the bus-side addresses (above IOMMU or such) and not the actual physical addresses. There is a way to cheat the DMA APIs, I will describe it later.

Also note that Don is correct: the VA->PA mappings are too volatile, so, even if you will take the snapshot of the page tables, it will immediately become obsolete due to running OS’s activities.

If you really want to take some kind of snapshot of the process’s VA->PA mappings for a valid address range just for demo/educational/interview purposes - then use MmProbeAndLockPages in the correct process context for the correct VA range, then look at MDL tail - i.e. ((ULONG_PTR)( Mdl + 1 ))[i], or MmGetMdlPfnArray(Mdl)[i] - this will give you the PFN number. Multiply it by PAGE_SIZE using a shift - and you will have the PA, which will be valid till you will unlock the MDL.

This is the way of cheating the DMA APIs. More so, the DMA APIs implementation should surely do exactly this.

We have forgot one important thing - how to determine what VA ranges are valid in the process. To do this, I would suggest the undocumented call ZwQueryVirtualMemory.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

> No, it is being called from DriverEntry.

…which runs in System process context :slight_smile:

There is no I/O at all in this driver, I simply just hardcode some address I want translated

And in what process must the translation run?


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com