ARM linux 建立页表过程

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);

build_mem_type_table 这个函数根据CPU类型,设置mem_types全局数组,mem_types数组保存了页目录和页表的属性,将来创建页目录和页表时,会用到mem_types。


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. 对每一个节点:

  • 获取该node的 min(最小pfn), node_low(最大low memory pfn), node_hight(最大high memory pfn)
  • 调用bootmem_init_node初始化node,bootmem_init_node会初始化bootmem bitmap
  • 如果是node 0,那么调用reserve_node_zero为node 0 reserve的内存:内核text和data区,初始化页表区(16KB),以及swapper_pg_dir之前的一块内存(在我的机器上是4个page)
  • 如果initrd存放在当前的node上,那么调用bootmem_reserve_initrd保留initrd占用的内存。initrd_start是initrd在起始虚拟内存地址,initrd_end是initrd结束的虚拟内存地址。

3. 对每一个node 调用bootmem_free_node

  • 设置这个node内各个zone的大小
  • 调用free_area_init_node:计算node的总pages数目,为这个node分配mem map,注意node内所有zone的memmap都分配在一起
  • 调用free_area_init_core:对于node内的每一个zone,进行初始化。注意这个函数present_pages是total size减去了该分区对应的memmap占用的pages,但是实际上memmap是放在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。

你可能感兴趣的:(ARM linux 建立页表过程)