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

在我的C ++程序(在Windows上),我分配了一块内存,可以确保它在物理内存中保持locking(未打开和连续)(即使用VirtualAllocEx(),MapUserPhysicalPages()等)。

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

1.有什么办法可以在用户模式下将虚拟地址转换成我的程序中的物理地址?

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

3.如果我自己写驱动程序,我该怎么做这个翻译? 我使用哪些函数? 它是mmGetPhysicalAddress() ? 我如何使用它?

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

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

谢谢

Solutions Collecting From Web of "如何将虚拟内存地址转换为物理地址?"

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

不,你不能确保它保持锁定。 如果你的程序崩溃,或者提前退出? 如果用户杀了它呢? 该内存将被重用于其他事情,如果您的设备仍然在做DMA,那最终将导致数据丢失/损坏或错误检查(BSOD)。

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

1.有什么办法可以在用户模式下将虚拟地址转换成我的程序中的物理地址?

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

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

这是解决这个问题的建议方法。

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

您可以使用MDL(内存描述符列表)来锁定任意内存(包括用户模式进程拥有的内存缓冲区),并将其虚拟地址转换为物理地址。 您也可以使用METHOD_IN_DIRECTMETHOD_OUT_DIRECT使Windows临时创建一个MDL,以传递给DeviceIoControl的调用。

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

3.如果我自己写驱动程序,我该怎么做这个翻译? 我使用哪些函数? 它是mmGetPhysicalAddress()? 我如何使用它?

编写驱动程序比调用一些API还要多。 如果你要写一个驱动程序,我建议阅读尽可能多的相关材料,你可以从MSDN和OSR 。 另外,请查看Windows驱动程序工具包中的示例。

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

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

1)没有

2)是的,你必须写一个司机。 最好是虚拟驱动程序,或更改特殊外部设备的驱动程序。

3)这在这里变得非常混乱。 MmGetPhysicalAddress应该是你锁定的方法,但我真的不知道如何物理地址映射到银行/芯片等。 在物理内存上。

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

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

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

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

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

编辑:只是以为我会抛出一些书引用来帮助你,你应该肯定(即使你不追求写驱动程序)阅读由Russinovich和所罗门Windows内部( 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

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

您可以通过使用METHOD_IN_DIRECT或METHOD_OUT_DIRECT向驱动程序发送一个IOCTL(通过DeviceControl函数)来获得名为MDL或Memory Descriptor List的缓冲区的描述。 有关定义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),它实际上编程您的硬件进行传输。

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

你不能从用户空间访问页表,它们被映射到内核中。

如果你在内核中,你可以简单地检查CR3的值来定位基本页表的地址,然后开始你的解析。

这个博客系列有一个很好的解释如何做到这一点。 您不需要任何操作系统设施/ API来解析虚拟< – >物理地址。

虚拟地址:f9a10054

 1: kd> .formats 0xf9a10054 Binary: 11111001 10100001 00000000 01010100 Page Directory Pointer Index(PDPI) 11 Index into 

第一个表(页目录指针表)页目录索引(PDI)
111001 101索引到第二个表(页目录表)页表索引(PTI)
00001 0000索引到第三个表(页表)字节索引
0000 01010100 0x054,物理内存页面的偏移量

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

在这里输入图像说明

等等,还有更多。 对于客户的Vista 64位版本的特权,您会花费更多的时间和金钱来让您的内核模式驱动程序辞职我的微软,