在我的 C++ 程序(在 Windows 上)中,我分配了一块内存,并且可以确保它在物理内存中保持锁定(未交换且连续)(即使用 VirtualAllocEx()、MapUserPhysicalPages() 等)。
不,您不能真正确保它保持锁定状态。如果您的进程崩溃或提前退出怎么办?如果用户杀死它怎么办?该内存将用于其他用途,如果您的设备仍在执行 DMA,最终将导致数据丢失/损坏或错误检查 (BSOD)。
此外,MapUserPhysicalPages
它是 Windows AWE(地址窗口扩展)的一部分,用于在 32 位版本的 Windows Server 上处理超过 4 GB 的 RAM。我不认为它是用来破解用户模式 DMA 的。
1.有什么方法可以在我的程序中以用户模式将虚拟地址转换为物理地址?
有一些驱动程序可以让您执行此操作,但您无法在 Windows 上从用户模式对 DMA 进行编程,并且仍然拥有稳定且安全的系统。让作为受限用户帐户运行的进程读/写物理内存允许该进程拥有系统。如果这是一次性系统或原型,这可能是可以接受的,但如果您希望其他人(尤其是付费客户)使用您的软件和设备,您应该编写一个驱动程序。
2. 如果没有,我只能在 KERNEL 模式下找到这个虚拟到物理的映射。我想这意味着我必须编写一个驱动程序来做到这一点......?
这是解决此问题的推荐方法。
您是否知道我可以使用的任何现成的驱动程序/DLL/API,我的应用程序(程序)将与之交互以进行翻译?
您可以使用MDL(内存描述符列表)锁定任意内存,包括用户模式进程拥有的内存缓冲区,并将其虚拟地址转换为物理地址。DeviceIoControl
您还可以让 Windows 为使用METHOD_IN_DIRECT
或传递给调用的缓冲区临时创建一个 MDL METHOD_OUT_DIRECT
。
请注意,虚拟地址空间中的连续页面在物理地址空间中几乎从不连续。希望您的设备能够处理这个问题。
3. 如果我必须自己编写驱动程序,我该如何翻译?我使用哪些功能?是 mmGetPhysicalAddress() 吗?我该如何使用它?
编写驱动程序不仅仅是调用一些 API。如果您要编写驱动程序,我建议您从MSDN和OSR阅读尽可能多的相关材料。另外,请查看Windows Driver Kit中的示例。
4. 另外,如果我理解正确,mmGetPhysicalAddress() 返回调用进程上下文中的虚拟基地址的物理地址。但是,如果调用进程是驱动程序,并且我正在使用我的应用程序来调用该函数的驱动程序,那么我正在更改上下文并且在调用 mmGetPhysicalAddress 例程时我不再处于应用程序的上下文中......所以如何转换应用程序(用户模式)内存空间中的虚拟地址,而不是驱动程序?
驱动程序不是进程。驱动程序可以在任何进程的上下文以及各种提升的上下文(中断处理程序和 DPC)中运行。