下面分析下__create_pgd_mapping会逐级建立映射关系,同时会进行权限的控制。建立页表映射的过程,整体流程如下: 可以看到建立页表就是填充页表描述符, 本质是填充物理页帧号和权限控制位这两部分内容,最后是通过调用set_pte()填充到对应的页表中。 map_mem 是不是所有内核内存都会建立映射?该函数为所有memory type...
create_pte_mapping(load_sz_pte,PAGE_OFFSET, load_pa + (va - PAGE_OFFSET), PAGE_SIZE,PAGE_KERNEL_EXEC); } //===2-4M=== create_pgd_mapping(early_pg_dir,PAGE_OFFSET + PMD_SIZE, (uintptr_t)early_pmd,PGDIR_SIZE,PAGE_TABLE); create_pmd_mapping(early_pmd,PAGE_OFFSET, (uintptr_t...
[2]入参pgdp就是swap_pg_dir,即内核全局页表。有了虚拟地址、物理地址和页表,然后通过__create_pgd_mapping()为他们建立映射,这样内核就可以通过虚拟地址访问到对应的物理地址了。 这样kernel image中的各个symbol就建立了paddr = vaddr - kimage_voffset的映射关系,cpu就能够在欢快的通过虚拟地址访问到物理内存...
ret = efi_create_mapping(&efi_mm, md); if(ret) { 这里分配了pgd的内存。看看efi_create_mapping做了什么: 1 2 3 4 5 6 int__init efi_create_mapping(structmm_struct *mm, efi_memory_desc_t *md) { 。。。 create_pgd_mapping(mm, md->phys_addr, md->virt_addr, md->num_pages << ...
* 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));bm_pgdp=pgd_offset_pgd(pgdp,FIXADDR_...
create_mapping(&map,false); } } create_mapping函数的大致流程如下图所示,这里需要提一下,linux内核使用的是四级页表,即PGD、PUD、PMD、PTE;而ARM32使用的是二级页表,即PMD、PTE。同时由于内存管理是以页为单位进行的,如果按照ARM硬件MMU的分页机制,一个PMD对应的PTE并不能完全占用完整个页,为了避免内存浪费,...
create_mapping函数的开始是一系列的检查,有意义的代码是最后的这个循环: pgd = pgd_offset_k(addr);//一级数组中addr对应的段在init_mm->pgd的下标 end = addr + length;//计算结束地址 do { unsigned long next = pgd_addr_end(addr, end);//获得下一段开始地址 ...
staticvoid__init__create_mapping(structmm_struct*mm,structmap_desc*md, void*(*alloc)(unsignedlongsz), boolng) { unsignedlongaddr,length,end; phys_addr_tphys; conststructmem_type*type; pgd_t*pgd; type=&mem_types[md->type]; #ifndefCONFIG_ARM_LPAE---(1) /* *Catch36-bitaddresses */...
关键词:用户内核空间划分、Node/Zone/Page、memblock、PGD/PUD/PMD/PTE、lowmem/highmem、ZONE_DMA/ZONE_NORMAL/ZONE_HIGHMEM、Watermark、MIGRATE_TYPES。 物理内存初始化是随着Linux内核初始化进行的,同时内存管理也是其他很多其他功能的基础。和内核中各种模块耦合在一起。
create_mapping函数的开始是一系列的检查,有意义的代码是最后的这个循环: pgd = pgd_offset_k(addr);//一级数组中addr对应的段在init_mm->pgd的下标 end = addr + length;//计算结束地址 do { unsigned long next = pgd_addr_end(addr, end);//获得下一段开始地址 ...