本文共 3035 字,大约阅读时间需要 10 分钟。
kernel 通过paging_init来映射物理内存void __init paging_init(void){ #为pgd申请内存并赋值,这时候还没有buddy system,因此在早期都是通过memblock来申请内存的 phys_addr_t pgd_phys = early_pgtable_alloc(); pgd_t *pgdp = pgd_set_fixmap(pgd_phys); #可以看到kernel本身占用的内存是单独映射的,这两个函数我们后面详细分析 map_kernel(pgdp); map_mem(pgdp); #在head.s中有申请一段memory来临时映射物理内存swapper_pg_dir,这里我们可以复用 #这段内存,这样我们就可以把通过memblock申请的pgd_phys 释放掉 cpu_replace_ttbr1(__va(pgd_phys)); memcpy(swapper_pg_dir, pgdp, PGD_SIZE); cpu_replace_ttbr1(lm_alias(swapper_pg_dir)); pgd_clear_fixmap(); #释放pgd_phys 占用的内存 memblock_free(pgd_phys, PAGE_SIZE); /* * We only reuse the PGD from the swapper_pg_dir, not the pud + pmd * allocated with it. */ #我们只是复用swapper_pg_dir 中pgd的memory,因此治理释放到pud和pmd 占用的内存 memblock_free(__pa_symbol(swapper_pg_dir) + PAGE_SIZE, __pa_symbol(swapper_pg_end) - __pa_symbol(swapper_pg_dir) - PAGE_SIZE);}首先看看map_kernelstatic void __init map_kernel(pgd_t *pgdp){ static struct vm_struct vmlinux_text, vmlinux_rodata, vmlinux_inittext, vmlinux_initdata, vmlinux_data; pgprot_t text_prot = rodata_enabled ? PAGE_KERNEL_ROX : PAGE_KERNEL_EXEC;#从下面这段可以看出kernel 本身占用的memory可以分为下面这5段 map_kernel_segment(pgdp, _text, _etext, text_prot, &vmlinux_text, 0, VM_NO_GUARD); map_kernel_segment(pgdp, __start_rodata, __inittext_begin, PAGE_KERNEL, &vmlinux_rodata, NO_CONT_MAPPINGS, VM_NO_GUARD); map_kernel_segment(pgdp, __inittext_begin, __inittext_end, text_prot, &vmlinux_inittext, 0, VM_NO_GUARD); map_kernel_segment(pgdp, __initdata_begin, __initdata_end, PAGE_KERNEL, &vmlinux_initdata, 0, VM_NO_GUARD); map_kernel_segment(pgdp, _data, _end, PAGE_KERNEL, &vmlinux_data, 0, 0);#最终map_kernel_segment->__create_pgd_mapping->pud->pmd->pte等来映射}memblock 中的memory映射如下:static void __init map_mem(pgd_t *pgdp){ phys_addr_t kernel_start = __pa_symbol(_text); phys_addr_t kernel_end = __pa_symbol(__init_begin); struct memblock_region *reg; int flags = 0; #是否开debug选项 if (debug_pagealloc_enabled()) flags = NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; /* * Take care not to create a writable alias for the * read-only text and rodata sections of the kernel image. * So temporarily mark them as NOMAP to skip mappings in * the following for-loop */ #由于kernel 占用的memory页包含在memblock中,且我们再前面已经映射kernel了,所以 #这里标记kernel占用的memory不用在重复映射了 memblock_mark_nomap(kernel_start, kernel_end - kernel_start);#ifdef CONFIG_KEXEC_CORE if (crashk_res.end) memblock_mark_nomap(crashk_res.start, resource_size(&crashk_res));#endif /* map all the memory banks */ #开始映射memblock中的memory for_each_memblock(memory, reg) { phys_addr_t start = reg->base; phys_addr_t end = start + reg->size; #起始地址大于结束地址的话,肯定更有问题,退出 if (start >= end) break; #如果memblock包含MEMBLOCK_NOMAP,则不用映射,例如前面提到的kernel的映射 if (memblock_is_nomap(reg)) continue; #开始映射memblock中的memory __map_memblock(pgdp, start, end, PAGE_KERNEL, flags); } __map_memblock(pgdp, kernel_start, kernel_end, PAGE_KERNEL, NO_CONT_MAPPINGS); #清除kernel memory段的MEMBLOCK_NOMAP memblock_clear_nomap(kernel_start, kernel_end - kernel_start);}
转载地址:http://knnmi.baihongyu.com/