linux内存管理笔记(十四)----dma_contiguous_remap

在第linux内存管理笔记(十一)—CMA中,我们学习了操作系统预留的大量的连续内存,我们对其引入的原因和使用方法进行了分析,其主要是用于内核中分配连续的大块内存。

  • 当设备驱动不适用时,内存管理系统将该区域用于分配和管理可移动类型页面
  • 当驱动程序使用时,用于连续内存分配,此时已经分配的页面进行迁移

这样既可以在内核中分配连续的大内存,同时又不浪费内存空间,因为当内存不足的时候,可以通过内存迁移实现内存重新分配的方式。通过之前的分析,当启动的时候通过arm_memblock_init->dma_contiguous_reserve->dma_contiguous_reserve_area->dma_contiguous_early_fixup,将CMA的起始地址和空间长度存储在dma_mmu_remap

void __init dma_contiguous_early_fixup(phys_addr_t base, unsigned long size)
{
	dma_mmu_remap[dma_mmu_remap_num].base = base;
	dma_mmu_remap[dma_mmu_remap_num].size = size;
	dma_mmu_remap_num++;
}

在paging_init做完低端内存映射后,就调用到dma_contiguous_remap进行相关设置,看看这个函数做了些什么呢?

void __init dma_contiguous_remap(void)
{
	int i;
	for (i = 0; i < dma_mmu_remap_num; i++) {
		phys_addr_t start = dma_mmu_remap[i].base;                                   -------------(1)
		phys_addr_t end = start + dma_mmu_remap[i].size;
		struct map_desc map;
		unsigned long addr;
        
		if (end > arm_lowmem_limit)
			end = arm_lowmem_limit;
		if (start >= end)
			continue;

		map.pfn = __phys_to_pfn(start);                                             -------------(2)
		map.virtual = __phys_to_virt(start);
		map.length = end - start;
		map.type = MT_MEMORY_DMA_READY;

		for (addr = __phys_to_virt(start); addr < __phys_to_virt(end);              -------------(3)
		     addr += PMD_SIZE)
			pmd_clear(pmd_off_k(addr));

		flush_tlb_kernel_range(__phys_to_virt(start),                               -------------(4)
				       __phys_to_virt(end));

		iotable_init(&map, 1);                                                      -------------(5)
	}
}
  • 1.这个区域是之前通过dma_contiguous_reserve来设置的保留区域,其start = 0x8c00 0000,length = 0x1400 0000,这个空间大小与dts中配置的"shared-dma-pool"大小一致。
  • 2.配置该区间的Map_desc,为后边的映射create_mapping做准备
  • 3.清0x8c00 0000 - 0xA000 0000空间的pmd表
  • 4.刷新该的区域对应的tlb
  • 5.iotable_init函数来建立页映射关系,主要是CAM的映射

iotable_init函数就是最终实现建立虚拟地址映射的函数,其处理流程如下

void __init iotable_init(struct map_desc *io_desc, int nr)
{
	struct map_desc *md;
	struct vm_struct *vm;
	struct static_vm *svm;

	if (!nr)
		return;

	svm = early_alloc_aligned(sizeof(*svm) * nr, __alignof__(*svm));

	for (md = io_desc; nr; md++, nr--) {
		create_mapping(md);

		vm = &svm->vm;
		vm->addr = (void *)(md->virtual & PAGE_MASK);
		vm->size = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
		vm->phys_addr = __pfn_to_phys(md->pfn);
		vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
		vm->flags |= VM_ARM_MTYPE(md->type);
		vm->caller = iotable_init;
		add_static_vm_early(svm++);
	}
}

也是调用create_mapping依次对传入的io端口地址进行映射,而且利用add_static_vm_early函数添加到了vmlist和static_vmlist链表,这两个全局链表应该是用来管理虚拟内存的,标记io映射使用的虚拟内存。具体的后面再分析CMA与伙伴系统的关系的时候,再深入分析之间的联系。
总结下,我们主要是分析了dma_contiguous_remap的作用,主要是针对CMA的区域进行了重新的映射,主要是0x8c00 000 ~ 0xe000 0000这个区域清了之前低端内存的映射关系,又重新作了二级映射。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值