21

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

在我的进程上下文中,我可以获得该块的虚拟内存地址, 但我需要找出它的物理内存地址才能将其传递给某个外部设备。


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

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

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

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

任何答案、提示和代码摘录将不胜感激!!

谢谢

4

6 回答 6

12

在我的 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。如果您要编写驱动程序,我建议您从MSDNOSR阅读尽可能多的相关材料。另外,请查看Windows Driver Kit中的示例。

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

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

于 2008-12-14T19:11:08.913 回答
5

您不能从用户空间访问页表,它们是在内核中映射的。

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

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

虚拟地址:f9a10054

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

Page Directory Pointer Index(PDPI)       11                        Index into

1st table(Page Directory Pointer Table) Page Directory Index(PDI)
111001 101 Index into 2nd table(Page Directory Table) Page Table Index(PTI)
00001 0000 Index into 3rd table(Page Table) Byte Index
0000 01010100 0x054, 偏移量物理内存页

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

在此处输入图像描述

于 2011-03-18T22:32:21.133 回答
5

1) 没有

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

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

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

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

// use realAddr
于 2008-12-14T16:56:06.033 回答
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),它实际上对您的硬件进行编程以进行传输。

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

于 2009-06-11T00:09:59.333 回答
4

真的不应该在用户模式下做这样的事情;正如克里斯托弗所说,您需要锁定页面,以便 mm 在设备使用它时不会决定调出您的后备内存,这最终会破坏随机内存页面。

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

驱动程序没有用户模式应用程序那样的上下文;如果您通过 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

于 2008-12-14T19:28:18.410 回答
-4

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

于 2008-12-14T20:28:38.383 回答