c++ 如何将虚拟内存地址翻译成物理地址?

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

在我的过程的上下文中,我可以获得该块的VIRTUAL内存地址,
 但是我需要找出它的PHYSICAL内存地址才能将其传递给一些外部设备。

1.在用户模式下,有没有办法将虚拟地址翻译成我的程序中的物理地址?
2.如果没有,我可以在KERNEL模式下找到这个虚拟到物理映射。我想这意味着我必须写一个司机去做…?你知道我可以使用的任何随时可用的驱动程序/ DLL / API,我的应用程序(程序)将与其进行翻译?
 如果我必须自己写驱动程序,我该怎么做这个翻译?我使用哪些功能?它是mmGetPhysicalAddress()吗?如何使用它?
另外,如果我理解正确,mmGetPhysicalAddress()返回虚拟基地址在调用进程上下文中的物理地址。但是,如果调用进程是驱动程序,并且我正在使用我的应用程序来调用该函数的驱动程序,我正在改变上下文,并且当mmGetPhysicalAddress例程被调用时,我已经不再在应用程序的上下文中…所以如何在应用程序(用户模式)内存空间中翻译虚拟地址,而不是驱动程序?

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

谢谢

最佳答案
在我的C程序(在Windows上),我正在分配一块内存,并且可以确保它在物理内存中保持锁定(未被忽略和连续)(即使用VirtualAllocEx(),MapUserPhysicalPages()等))。

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

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

1.在用户模式下,有没有办法将虚拟地址翻译成我的程序中的物理地址?

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

2.如果没有,我可以在KERNEL模式下找到这个虚拟到物理映射。我想这意味着我必须写一个司机去做…?

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

你知道我可以使用的任何随时可用的驱动程序/ DLL / API,我的应用程序(程序)将与其进行翻译?

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

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

如果我必须自己写驱动程序,我该怎么做这个翻译?我使用哪些功能?它是mmGetPhysicalAddress()吗?如何使用它?

写一个驱动程序还有更多的只是调用几个API。如果你要写一个驱动程序,我会推荐从MSDNOSR读取尽可能多的相关材料。另外,看看Windows Driver Kit中的例子。

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

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

转载注明原文:c++ 如何将虚拟内存地址翻译成物理地址? - 代码日志