前面我们讨论了页描述符对象分配,以及初始化。接下来我们再来了解内核页表建立初始化处理。针对ARM64进行。
start_kernel --> setup_arch --> paging_init()
void __init paging_init(void) { phys_addr_t pgd_phys = early_pgtable_alloc(); 分配页全局目录表地址
pgd_t *pgd = pgd_set_fixmap(pgd_phys);
map_kernel(pgd); 创建内核空间映射
map_mem(pgd); 对其他的一些bank块进行映射。
下面就是一些针对pgd进行设置。
/* * We want to reuse the original swapper_pg_dir so we don't have to * communicate the new address to non-coherent secondaries in * secondary_entry, and so cpu_switch_mm can generate the address with * adrp+add rather than a load from some global variable. * * To do this we need to go via a temporary pgd. */ cpu_replace_ttbr1(__va(pgd_phys)); memcpy(swapper_pg_dir, pgd, PAGE_SIZE); cpu_replace_ttbr1(swapper_pg_dir);
pgd_clear_fixmap(); memblock_free(pgd_phys, PAGE_SIZE);
/* * We only reuse the PGD from the swapper_pg_dir, not the pud + pmd * allocated with it. */ memblock_free(__pa(swapper_pg_dir) + PAGE_SIZE, SWAPPER_DIR_SIZE - PAGE_SIZE); }
static void __init map_kernel(pgd_t *pgd) { static struct vm_struct vmlinux_text, vmlinux_rodata, vmlinux_init, vmlinux_data;
map_kernel_segment(pgd, _text, _etext, PAGE_KERNEL_EXEC, &vmlinux_text); map_kernel_segment(pgd, __start_rodata, __init_begin, PAGE_KERNEL, &vmlinux_rodata); map_kernel_segment(pgd, __init_begin, __init_end, PAGE_KERNEL_EXEC, &vmlinux_init); map_kernel_segment(pgd, _data, _end, PAGE_KERNEL, &vmlinux_data);
if (!pgd_val(*pgd_offset_raw(pgd, FIXADDR_START))) { /* * The fixmap falls in a separate pgd to the kernel, and doesn't * live in the carveout for the swapper_pg_dir. We can simply * re-use the existing dir for the fixmap. */ set_pgd(pgd_offset_raw(pgd, FIXADDR_START), *pgd_offset_k(FIXADDR_START)); } else if (CONFIG_PGTABLE_LEVELS > 3) { /* * The fixmap shares its top level pgd entry with the kernel * mapping. This can really only occur when we are running * with 16k/4 levels, so we can simply reuse the pud level * entry instead. */ BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES)); set_pud(pud_set_fixmap_offset(pgd, FIXADDR_START), __pud(__pa(bm_pmd) | PUD_TYPE_TABLE)); pud_clear_fixmap(); } else { BUG(); }
kasan_copy_shadow(pgd); }
static void __init map_mem(pgd_t *pgd) { struct memblock_region *reg;
/* map all the memory banks */ for_each_memblock(memory, reg) { phys_addr_t start = reg->base; phys_addr_t end = start + reg->size;
if (start >= end) break; if (memblock_is_nomap(reg)) continue;
__map_memblock(pgd, start, end); } }