如何将虚拟内存地址转换为物理地址?

时间:2008-12-14 14:46:42

标签: c++ windows memory virtual-address-space

在我的C ++程序中(在Windows上),我正在分配一块内存,并确保它在物理内存中保持锁定(未连接和连续)(即使用VirtualAllocEx(),MapUserPhysicalPages()等)。

在我的过程中,我可以获得该块的VIRTUAL内存地址, 但是我需要找出它的物理内存地址才能将它传递给某个外部设备。


1。在USER模式下,有什么方法可以将虚拟地址转换为程序中的物理地址吗?

2。如果没有,我只能在KERNEL模式下找到这个虚拟到物理的映射。我想这意味着我必须写一个驱动程序才能做到这一点......?你知道我可以使用的任何现成的驱动程序/ DLL / API,我的应用程序(程序)将与之交互以进行翻译吗?

3。如果我必须自己编写驱动程序,我该如何翻译?我使用哪些功能?是 mmGetPhysicalAddress()吗?我该如何使用它?

4。另外,如果我理解正确,mmGetPhysicalAddress()将返回调用进程上下文中的虚拟基地址的物理地址。但是如果调用进程是驱动程序,并且我正在使用我的应用程序来调用该函数的驱动程序,那么我正在改变上下文,当调用mmGetPhysicalAddress例程时,我不再处于应用程序的上下文中...所以如何翻译应用程序(用户模式)内存空间中的虚拟地址,而不是驱动程序?

任何答案,提示和代码摘录都将非常感谢!!

由于

6 个答案:

答案 0 :(得分:11)

在我的C ++程序中(在Windows上),我正在分配一块内存,并确保它在物理内存中保持锁定(未连接和连续)(即使用VirtualAllocEx(),MapUserPhysicalPages()等)

不,你无法确保它保持锁定状态。如果您的流程崩溃或提前退出怎么办?如果用户杀了它怎么办?该内存将被重用于其他内容,如果您的设备仍在执行DMA,最终将导致数据丢失/损坏或错误检查(BSOD)。

此外,MapUserPhysicalPages是Windows AWE(地址窗口扩展)的一部分,用于在32位版本的Windows Server上处理超过4 GB的RAM。我不认为它是用于破解用户模式DMA。

1。在USER模式下,有什么方法可以将虚拟地址转换为我的程序中的物理地址吗?

有些驱动程序允许您这样做,但您无法在Windows上从用户模式编程DMA,并且仍然拥有稳定安全的系统。让作为受限用户帐户运行的进程读/写物理内存允许该进程拥有系统。如果这是一次性系统或原型,这可能是可以接受的,但如果您希望其他人(特别是付费客户)使用您的软件和您的设备,您应该编写驱动程序。

2。如果没有,我只能在KERNEL模式下找到这个虚拟到物理的映射。我想这意味着我必须写一个驱动程序才能做到这一点......?

这是解决此问题的推荐方法。

您知道我可以使用的任何现成的驱动程序/ DLL / API,我的应用程序(程序)将与之交互以进行翻译吗?

您可以使用MDL (Memory Descriptor List)锁定任意内存,包括用户模式进程拥有的内存缓冲区,并将其虚拟地址转换为物理地址。您还可以让Windows使用METHOD_IN_DIRECTMETHOD_OUT_DIRECT为通过调用DeviceIoControl的缓冲区临时创建MDL。

请注意,虚拟地址空间中的连续页面在物理地址空间中几乎不会连续。希望您的设备能够处理它。

3。如果我必须自己编写驱动程序,我该如何进行此翻译?我使用哪些功能?是mmGetPhysicalAddress()吗?我该如何使用它?

编写驱动程序要比调用一些API要多得多。如果您要编写驱动程序,我建议您尽可能多地从MSDNOSR阅读相关材料。另外,请查看Windows Driver Kit

中的示例

4。此外,如果我理解正确,mmGetPhysicalAddress()将返回调用进程上下文中的虚拟基址的物理地址。但是如果调用进程是驱动程序,并且我正在使用我的应用程序来调用该函数的驱动程序,那么我正在改变上下文,当调用mmGetPhysicalAddress例程时,我不再处于应用程序的上下文中...所以如何翻译应用程序(用户模式)内存空间中的虚拟地址,而不是驱动程序?

驱动程序不是进程。驱动程序可以在任何进程的上下文中运行,也可以在各种提升的上下文(中断处理程序和DPC)中运行。

答案 1 :(得分:5)

您的应用程序中有一个虚拟的缓冲区。正如您所指出的那样,该范围的虚拟内存仅在您的应用程序的上下文中可用,并且其中一些可能随时被分页。因此,为了从设备访问内存(也就是说,执行DMA),您需要将其锁定并获取可以传递给设备的描述。

通过使用METHOD_IN_DIRECT或METHOD_OUT_DIRECT将IOCTL(通过DeviceControl功能)发送到驱动程序,可以获得称为MDL或内存描述符列表的缓冲区的描述。有关定义IOCTL的讨论,请参见以下页面。

http://msdn.microsoft.com/en-us/library/ms795909.aspx

现在您已在设备的驱动程序中描述了缓冲区,您可以将其锁定,以便缓冲区在设备可能对其执行的整个时间段内保留在内存中。在MSDN上查找MmProbeAndLockPages。

您的设备可能会也可能无法读取或写入缓冲区中的所有内存。该设备可能只支持32位DMA,机器可能有超过4GB的RAM。或者您可能正在处理具有IOMMU,GART或其他地址转换技术的计算机。为了适应这种情况,请使用各种DMA API来获取一组适合您的设备使用的逻辑地址。在许多情况下,这些逻辑地址将等同于您提出的问题的物理地址,但并非总是如此。

您使用哪种DMA API取决于您的设备是否可以处理分散/收集列表等。您的驱动程序在其设置代码中将调用IoGetDmaAdapter并使用它返回的一些函数。

通常,您会对GetScatterGatherList和PutScatterGatherList感兴趣。您提供了一个函数(ExecutionRoutine),它实际上对您的硬件进行编程以进行传输。

涉及很多细节。祝你好运。

答案 2 :(得分:5)

您无法从用户空间访问页表,它们将映射到内核中。

如果您在内核中,只需检查CR3的值以找到基页表地址,然后开始解析。

This blog series对如何执行此操作有一个很好的解释。您不需要任何OS工具/ API来解析虚拟< - >物理地址。

  

虚拟地址:f9a10054

1: kd> .formats 0xf9a10054
Binary:  11111001 10100001 00000000 01010100

Page Directory Pointer Index(PDPI)       11                        Index into
     

第1个表(页面目录指针   表)页面目录索引(PDI)
  111001 101指数排名第二   表(页面目录表)页面   表索引(PTI)
  00001 0000指数进入第3名   表(页表)字节索引
  0000 01010100 0x054,偏移量   进入物理内存页面

在他的例子中,他们使用windbg,!dq是物理内存读取。

enter image description here

答案 3 :(得分:5)

1)否

2)是的,你必须写一个驱动程序。 Best可以是虚拟驱动程序,也可以更改特殊外部设备的驱动程序。

3)这在这里变得非常混乱。 MmGetPhysicalAddress应该是您正在寻找的方法,但我真的不知道物理地址如何映射到bank / chip / etc.在物理记忆上。

4)你不能使用分页内存,因为它被重新定位。您可以在MDL上锁定带有MmProbeAndLockPages的分页内存,您可以在用户模式调用上下文传入的内存上构建。但最好分配非分页内存并将其交给用户模式应用程序。

PVOID p = ExAllocatePoolWithTag( NonPagedPool, POOL_TAG );
PHYSICAL_ADDRESS realAddr = MmGetPhysicalAddress( p );

// use realAddr

答案 4 :(得分:4)

真的不应该在usermode中做这样的事情;正如克里斯托弗所说的那样,你需要锁定页面,这样当设备使用它时mm不会决定翻出你的后备存储器,这最终会破坏随机存储页面。

  

但是如果调用进程是驱动程序,并且我正在使用我的应用程序来调用该函数的驱动程序,那么我正在更改上下文,并且当调用mmGetPhysicalAddress例程时,我不再处于应用程序的上下文中/ p>

驱动程序没有像用户模式应用程序那样的上下文;如果您通过IOCTL或其他东西调用驱动程序,通常(但不保证!)在调用用户线程的上下文中。但实际上,这对你所要求的并不重要,因为内核模式内存(任何高于0x80000000的内容)无论你身在何处都是相同的映射,你最终会在内核端分配内存。但同样,写一个合适的驱动程序。使用WDF(http://www.microsoft.com/whdc/driver/wdf/default.mspx),它将使编写正确的驱动程序更容易(虽然仍然相当棘手,Windows驱动程序编写并不容易)

编辑:我以为我会抛出一些书籍参考来帮助你,你绝对应该(即使你不追求编写驱动程序)阅读Russinovich和Solomon的Windows Internals(http://www.amazon.com/Microsoft-Windows-Internals-4th-Server/dp/0735619174/ref=pd_bbs_sr_2?ie=UTF8&s=books&qid=1229284688&sr=8-2) ;编写Microsoft Windows驱动程序模型也很好(http://www.amazon.com/Programming-Microsoft-Windows-Driver-Second/dp/0735618038/ref=sr_1_1?ie=UTF8&s=books&qid=1229284726&sr=1-1

答案 5 :(得分:-3)

等等,还有更多。为了获得在客户的Vista 64位上运行的特权,您可以花费更多的时间和金钱让您的内核模式驱动程序让我的微软辞职,