关于remap_page_range第二个参数与vm_pgoff物理地址关联的疑问
核心结论
首先纠正一个常见误解:vma->vm_pgoff 不是用户空间虚拟地址的偏移,它的本质是 当前VMA关联的文件的页量级偏移,单位是页。它和物理地址的对应关系由实现mmap的驱动自己约定,没有统一的强制规则。
示例代码中offset和物理地址的关联逻辑
你贴的是典型的字符设备直接映射物理地址的mmap实现,这类驱动会和用户空间做约定:用户调用mmap()时传入的offset参数,就直接对应要映射的物理地址的字节偏移。
内核在为mmap调用构造vm_area_struct结构时,会把用户传入的offset按页对齐后右移PAGE_SHIFT(也就是除以页大小),存入vma->vm_pgoff字段。
所以代码里unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; 算出来的就是用户指定要映射的物理地址起始值,刚好符合老接口remap_page_range()第二个参数要求传入物理地址的规则。
你注意代码里的判断条件if (offset >= __pa(high_memory) || ...) ,这里直接把offset拿来和高端内存的起始物理地址做比较,也能直接证明这里的offset就是物理地址。
新接口remap_pfn_range仍使用vm_pgoff的原因
新接口remap_pfn_range要求传入的第三个参数是物理页帧号(PFN),也就是物理地址右移PAGE_SHIFT后的值。
刚好对于上述约定“mmap的offset对应物理地址偏移”的驱动来说,vma->vm_pgoff本身就是物理地址除以页大小的结果,也就是直接可以当PFN用,所以这类驱动代码直接把vm_pgoff传给remap_pfn_range是完全合理的。
补充说明
vm_pgoff没有强制对应物理地址:
- 如果是普通文件的mmap,
vm_pgoff是文件内的页偏移,驱动需要先根据这个偏移找到对应的页缓存页,再拿页的PFN来做映射 - 只有约定了“mmap偏移直接对应物理地址”的驱动场景下,
vm_pgoff才会和物理地址直接挂钩
内容的提问来源于stack exchange,提问作者Milan

