2

我正在从事一个研究项目,该项目需要我从自定义硬件执行内存捕获。我正在使用 Zedboard SoC(带有 FPGA 结构的双核 ARM Cortex-A9)。我设计了一个设备驱动程序,允许我执行虚拟内存捕获和物理内存捕获(使用控制Xilinx AXI DMA IP的 AXI4-Lite 外设)。

我的目标是捕获所有映射的页面,所以我检查 /proc/pid/maps 的映射区域,然后从 /proc/pid/pagemaps 获取 PFN,将物理地址传递给我的设备驱动程序,然后将它们传递给我的自定义硬件(它调用 Xilinx AXI DMA 从物理内存中获取内容)。

注意:我使用的是 Xilinx 的 PetaLinux 发行版,它基于 Linux 4.14 版构建。

我的设备驱动程序通过一系列 IOCTL 调用实现以下过程:

  1. 停止目标进程。
  2. 执行虚拟内存捕获(使用access_process_vm()函数)。
  3. 刷新缓存(使用flush_user_range()函数)。
  4. 执行物理内存捕获。
  5. 恢复目标进程。

然而,我注意到的是虚拟内存捕获和物理内存捕获在 [heap] 部分(这是延伸超过一页的第一部分)中不同。第一页匹配,但其他页面都没有接近。[stack] 部分根本不匹配。我应该注意,对于前两个内存部分,.text 和 .rodata,捕获完全匹配。现在的结论是,在运行时更改的数据在虚拟和物理捕获之间匹配,而在运行时更改的数据匹配。

所以这让我想知道:我是否使用正确的函数来确保缓存和 RAM 之间的一致性?如果不是,用于强制将缓存刷新到 RAM 的正确功能是什么?RAM 中的数据必须在目标进程停止时是最新的,因为我无法从自定义硬件访问缓存。

编辑1:关于这个问题被标记为这个问题的可能重复我正在使用接受的答案中的一个函数来启动缓存刷新。但是,从我的角度来看,它似乎无法正常工作,因为如果发生缓存刷新,物理内存与虚拟内存不匹配。

4

1 回答 1

2

对于以后遇到这个问题的人来说,问题不是我想的那样。我提到的 flush_user_range() 函数是用于将页面从缓存推回主内存的正确函数。

但是,我当时没有想到的是,实际上连续的页面不一定(而且通常不是)物理上连续的。在我的内核代码中,我将映射区域的长度传递给我的硬件,它从 AXI DMA 请求该长度的数据。我应该做的是虚拟到物理的转换,以获取每个区域中每个页面的物理地址,然后从主存储器请求一个页面长度的数据,对每个映射区域中的每个页面重复该过程。

我意识到这是一个非常具体的问题,可能不会帮助其他任何人做我正在做的事情,但希望学到的教训可以帮助将来的人:Linux 在物理内存中分配页面(通常大小为 4kB,尽管您不应该假设是这种情况),并且物理页面的集合包含在一个映射区域中。如果您正在处理需要检查物理内存的任何代码,请务必注意数据可能跨越物理页面边界的位置并采取相应措施。

于 2020-03-06T23:23:51.507 回答