paging_init 用来建立页表,初始化zone的memory map
void *zero_page; sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL); build_mem_type_table(); sanity_check_meminfo(); prepare_page_table(); map_lowmem(); bootmem_init(); devicemaps_init(mdesc); kmap_init(); top_pmd = pmd_off_k(0xffff0000); /* * allocate the zero page. Note that this always succeeds and * returns a zeroed result. */ zero_page = alloc_bootmem_low_pages(PAGE_SIZE); empty_zero_page = virt_to_page(zero_page); __flush_dcache_page(NULL, empty_zero_page);
sanity_check_meminfo 检测判断是否需要创建highmem区,并且重建描述内存bank的数组
VMALLOC_MIN定义了vmalloc区的起始位置(通过VMALLOC_END和vmalloc_reserve计算得出),VMALLOC_END定义了vmalloc区的结束位置,vmalloc_reserve是系统预留给vmalloc区的大小。
prepare_page_table 这个函数会请空页目录,有两块地址空间区域是不需要清除的,一个是kernel image,另外一个是kernel线性地址映射区
map_lowmem 建立低端内存的所有页目录和页表:遍历memory bank,映射那些没有highmem标记的内存bank
bootmem_init :
1. 调用check_initrd获取initrd所在的memory bank对应的node
2. 对每一个节点:
3. 对每一个node 调用bootmem_free_node
4. high_memory 是一个很奇怪的变量,high_memory应该是物理内存的概念,但是high_memory变量保存的确实一个内核地址。
devicemaps_init 这个函数创建device的映射,
1. 把machine vectors映射到0xffff0000处
2. 调用平台特定的map_io,对于mx51,这个函数主要是映射mx51功能寄存器区, AIPS1 AIPS2 和SPBA0,这三个寄存器区大小为1MB,映射后的虚拟地址分别为0xF7E00000,0xF7D00000,0xFB100000
kmap_init 创建pkmap的pgd和pte。并且让pkmap_page_table指向这个PTE page的linux p/t。一般来说kmap都是使用一个page的pte来映射高端内存到内核地址空间,对于arm来说,每个page可以存放512个pte_t,所以pkmap的地址空间为2M。
empty zero page
按照源码注释,它是一个特定的初始化为0的页,用于COW
我的理解是,系统有时需要一个页面全零,这种情况下,并不需要分配一个全零的页面,而是让PTE指向empty_zero_page,当试图写这个page时,由于这个empty_zero_page是共享的,所以导致了COW。