You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

reserved-memory驱动开发:memremap()与virt_to_phys()地址偏移问题

问题:reserved-memory驱动中virt_to_phys返回地址与原物理地址偏移异常

我正在为reserved-memory区域实现自定义Linux驱动,遵循Xilinx官方文档开发。内存预留已正常工作,probe函数中代码如下:

paddr = r.start;
vaddr = memremap(paddr, 4096, MEMREMAP_WB);
printk("Allocated reserved memory, vaddr: 0x%0X, paddr: 0x%0X\n", (u32)vaddr, paddr);
printk("Allocated reserved memory, paddr (2): 0x%0x\n", virt_to_phys(vaddr));

实际输出:

[10370.743577] Allocated reserved memory, vaddr: 0xE0847000, paddr: 0x20000000
[10370.750564] Allocated reserved memory, paddr (2): 0x20847000

原物理地址为0x20000000,但virt_to_phys返回的地址偏移了0x847000,请问该偏移来源是什么?如何确保驱动访问正确的物理地址0x20000000?


偏移来源分析

  • 函数适用范围错误:virt_to_phys仅对内核线性直接映射区的虚拟地址有效,而memremap(MEMREMAP_WB)返回的是vmalloc动态映射区的虚拟地址。对vmalloc地址调用virt_to_phys,得到的是vmalloc页表对应的物理页地址,而非你预留的物理内存地址,0x847000是这个错误转换产生的无效偏移。
  • memremap映射逻辑:MEMREMAP_WB模式下,内核会将预留物理内存映射到vmalloc区域,而非直接线性映射,因此虚拟地址和物理地址不存在固定的线性偏移关系。

解决方法

方案一:直接保留原始物理地址

驱动中直接保存初始化时获取的paddr(即r.start),后续需要使用物理地址时直接调用该值即可,无需通过虚拟地址转换。这是最简单高效的方式。

方案二:使用正确的地址转换函数(仅特殊场景需要)

如果必须从memremap返回的虚拟地址反推物理地址,需使用适用于vmalloc地址的转换逻辑:

struct page *page = virt_to_page(vaddr);
phys_addr_t correct_paddr = page_to_phys(page) + (vaddr - (void *)page_address(page));

但此方法完全没必要,因为你已经持有原始的paddr。

关键注意事项

  • 直接使用memremap返回的vaddr进行内存读写即可,它已经正确映射到你预留的0x20000000物理地址,无需额外转换。
  • 区分内核虚拟地址区域:线性直接映射区(virt_to_phys可用)、vmalloc动态映射区(需用page相关函数转换)、ioremap映射区(virt_to_phys可用)。

内容的提问来源于stack exchange,提问作者moudi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 21:12:42