在第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这个区域清了之前低端内存的映射关系,又重新作了二级映射。
Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。
它的内容包括:
- 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
- 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
- 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
- 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
- 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
- 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
- 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
- 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw
目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:
想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询
同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。