内存管理之remap_pfn_range

定义在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);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山羊哥-老宋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值