分配DMA缓冲区时LogicalAddress与PhysicalAddress的疑惑
DMA操作前需要分配物理地址连续的一个Buffer,AllocateCommonBuffer函数提供了这个功能,该函数原型如下:
PVOID AllocateCommonBuffer( _In_ PDMA_ADAPTER DmaAdapter, _In_ ULONG Length, _Out_ PPHYSICAL_ADDRESS LogicalAddress, _In_ BOOLEAN CacheEnabled );
第三个参数有点不是很能理解,PPHYSICAL_ADDRESS LogicalAddress, 至少从定义的变量名上看,微软似乎在暗示我:逻辑地址和物理地址是相同的 这样一个事实。
虚拟地址到物理地址的转化方法是与体系结构相关的。有分段、分页两种方式。x86 cpu下 分段分页都是支持的。MMU负责从虚拟地址到物理地址的转化。逻辑地址是段标识+段内偏移量的形式,MMU通过查询段表,可以把逻辑地址转化为线性地址。如果cpu没有开启分页功能,那么线性地址就是物理地址;如果cpu开启了分页功能,MMU还需要查询页表来将线性地址转化为物理地址,不同的逻辑地址可以映射到同一个线性地址上;不同的线性地址也可以映射到同一个物理地址上;所以是多对一的关系。另外,同一个线性地址,在发生换页以后,也可能被重新装载到另外一个物理地址上。所以这种多对一的映射关系也会随时间发生变化。
逻辑地址,线性地址,物理地址的关系总结如下:
逻辑地址(段机制转换)----> 线性地址(页机制转换)---->物理地址
从另一方面讲,在32位系统下使用32位的PCIe卡,即使逻辑地址和物理地址是相同的,但在64位的系统下,AllocateCommonBuffer返回的物理地址可能高于4GB,但逻辑地址肯定是低于4GB的,这种情况下逻辑地址和物理地址不可能相等。由此个人认为PPHYSICAL_ADDRESS LogicalAddress 这种定义只是微软命名习惯上的差异,这里的LogicalAddress就是物理地址而并非传统意义上的逻辑地址。