定义在v4.19.133 /mm/memory.c
int remap_pfn_range(struct vm_area_struct *, unsigned long addr,
unsigned long pfn, unsigned long size, pgprot_t);
/**
* remap_pfn_range - 映射内核内存到用户空间
* @vma: user vma to map to
* @addr: 目标用户地址开始于
* @pfn: 内核内存的物理地址
* @size: 映射区域的大小
* @prot: 此映射的页面保护标志
*
* 注意:只有在调用时保持mm信号量,这才是安全的.
*/
int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn, unsigned long size, pgprot_t prot)
{
pgd_t *pgd;
unsigned long next;
unsigned long end = addr + PAGE_ALIGN(size);
struct mm_struct *mm = vma->vm_mm;
unsigned long remap_pfn = pfn;
int err;
/*
* 物理重新映射的页面很特殊。 告诉世界其他地方:
* VM_IO告诉人们不要看这些页面(访问可能会有副作用)。
* VM_PFNMAP告诉核心MM基本页面只是原始PFN映射,并且没有与之关联的“结构页面”。
* VM_DONTEXPAND 使用mremap()禁用vma合并和扩展。
* VM_DONTDUMP 即使关闭了VM_IO,也要从核心转储中忽略vma。
*
* 有一种可怕的特殊情况来处理某些程序依赖的写时复制行为。
* 我们通过将“原始”未COW的页面与“ vma-> vm_pgoff”匹配来标记它们。
* 有关详细信息,请参见vm_normal_page()。
*/
if (is_cow_mapping(vma->vm_flags)) {
if (addr != vma->vm_start || end != vma->vm_end)
return -EINVAL;
vma->vm_pgoff = pfn;
}
err = track_pfn_remap(vma, &prot, remap_pfn, addr, PAGE_ALIGN(size));
if (err)
return -EINVAL;
vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
BUG_ON(addr >= end);
pfn -= addr >> PAGE_SHIFT;
pgd = pgd_offset(mm, addr);
flush_cache_range(vma, addr, end);
do {
next = pgd_addr_end(addr, end);
err = remap_p4d_range(mm, pgd, addr, next,
pfn + (addr >> PAGE_SHIFT), prot);
if (err)
break;
} while (pgd++, addr = next, addr != end);
if (err)
untrack_pfn(vma, remap_pfn, PAGE_ALIGN(size));
return err;
}
EXPORT_SYMBOL(remap_pfn_range);