uwe kirst wrote:
>
I think it’s a little bit more complicated.
No, it’s not! Really!
I’m assuming my user mode app is 32bit right now. But how do I assure
that the Virtual address is below 2GB?
Well, let’s back up a couple of steps. You’re dealing with three
addresses for this block of memory:
a) A physical address – This physical address can be anywhere in the
system’s memory space, regardless of address size. So, for the purposes
of our discussion, we don’t care about the physical address, right?
b) A kernel virtual address – This is the address your driver will use
to access the block of (physical) memory, with a mapping set up through
the kernel mode memory management hardware (PDEs and PTEs). This
address will be 32-bits on Windows 32 and 64-bits on Windows 64, because
drivers on Windows 64 systems must be 64-bit capable. This address is
nothing more than the pointer returned form ExAllocatePool(…).
c) A USER virtual address – This is the address into which you’re going
to map the block of (physical) memory that you allocate from pool,
that’s within the user application’s address space. You create this
address when running in the context of the requesting processing, by calling
ULONG_PTR ptr;
ptr = MmMapLockedPages(mdl, UserMode);
As described in your original posting (well, I added the ULONG_PTR data
type, which will be 32-bits on x86 and 64-bits on x64).
Your driver may not know if the caller is 32-bit or 64-bit (it could
find out, if it wanted to, by calling IoIs32BitProcess)… But the
MEMORY MANAGER certainly knows! So, when you call the function
MmMapLockedPages, and tell the Memory Manager to map the buffer
described by the MDL into the user mode address space of the current
process, the Memory Manager knows if the current process is 32-bit or
64-bit and maps the buffer into its address space, automatically
observing all the appropriate restrictions.
It really IS that simple.
deviceExtension->VirtualAddress = ExAllocatePool(PagedPool, NumberOfBytes);
if (deviceExtension->VirtualAddress) {
deviceExtension->Mdl = IoAllocateMdl(deviceExtension->VirtualAddress,
NumberOfBytes, FALSE, FALSE, NULL);
MmProbeAndLockPages(deviceExtension->Mdl, KernelMode,
IoModifyAccess); …
Given your code above, I have a few notes for you:
a) You really might want to re-think the whole idea of mapping POOL into
an application’s address space. This approach can open a complex
security loophole that can endager the system. I’d recommend allocating
memory in a section, and using that. This isn’t entirely free of
potential problems, but it’s better.
b) I personally dislike the idea of allocating paged pool and then
pinning it. Unless the pages are locked into memory for a short period
of time, why not allocate the pages from NON-paged pool in the first
place? In that case you’d call MmBuildMdlForNonPagedPool.
c) You should ALWAYS use ExAllocatePoolWithTag, instead of ExAllocatePool.
d) MmMapLockedPages is an obsolete function – You should certainly be
calling MmMapLockedPagesSpecifyCache.
e) Just to re-emphasize (even if just for the archive): Your approach
working, at least from the code segments you’ve provided thus far, is
entirely dependent on your driver running in the context of the process
into which you wish to map the memory segment, right?? And, for a
random driver in a random stack in the system (such as the storage
stack, just to choose an example) there’s no reason to believe that your
driver will be running in any specific thread/process context. Now, in
your specific driver, it is entirely possible that you KNOW for sure
that your driver runs in a specific thread/process context, and if so,
this is OK. I just wanted to be sure we had this point covered.
HTH,
Peter
OSR