Categories
Uncategorized

[Original] (c) Linux paging_init resolve

background

    Read the fucking source code! –By Lu Xun

    A picture is worth a thousand words. –By Golgi

Description:

    Kernel Version: 4.14

    ARM64 processor, Contex-A53, binuclear

    Use tools: Source Insight 3.5, Visio

1 Introduction

From (b) Linux physical memory initialization, call paging_init seen before, stored Kernel Image and DTB of two physical memory area can be visited (the corresponding page table has been created). Although the physical memory memblock_add been added to the system, but this part of the physical memory to virtual memory mapping has not been established, it can memblock_alloc allocate some physical memory, but can not access, all need to wait for the implementation of paging_init. After the final page table is set up, you can go to access the final physical address of the virtual address.

按照惯例,先上图,来一张ARM64内核的内存布局图片吧,最终的布局如下所示:

Adventure open it!

2. paging_init

paging_init dapper source code directly Tieshanglai sub module to introduce it.

/*
 * paging_init() sets up the page tables, initialises the zone memory
 * maps and sets up the zero page.
 */
void __init paging_init(void)
{
    phys_addr_t pgd_phys = early_pgtable_alloc();   /********(mark 1)*******/
    pgd_t *pgd = pgd_set_fixmap(pgd_phys);

    map_kernel(pgd);                                        /********(mark 2)*******/
    map_mem(pgd);                                         /********(mark 3)*******/

    /*
     * 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));                 /********(mark 4)*******/
    memcpy(swapper_pg_dir, pgd, PGD_SIZE);
    cpu_replace_ttbr1(lm_alias(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_symbol(swapper_pg_dir) + PAGE_SIZE,
              SWAPPER_DIR_SIZE - PAGE_SIZE);
}

    mark 1: the size of physical memory allocated to store a PGD;

    mark 2: the respective core segments are mapped;

    mark 3: Add the physical memory subsystem memblock mapping;

    mark 4: switching the page table, the page table of contents and replace swappper_pg_dir newly created table of contents page;

代码看起来费劲?图来了:

It will be further analysis of each sub-module below.

3. early_pgtable_alloc

这个模块与FIX MAP映射区域相关,建议先阅读前文(二)Linux物理内存初始化
先上图:

FIX MAP area division may be seen from FIG.
    This function will be assigned physical memory, then before borrowing global page table bm_pte, to establish a physical address to map the virtual address, the role of this map is order to access physical memory, the memory is cleared, so it’s just a temporary operation, after the operation, calls pte_clear_fixmap () to clear the map.

After early_pgtable_alloc, we see paging_init call pgd_set_fixmap function, the function call after by memblock_alloc allocate physical memory, will eventually be used to store pgd table, the contents of this area will be copied to the last swapper_pg_dir go.

4. map_kernel

map_kernel的主要工作是完成内核中各个段的映射,此外还包括了FIXADDR_START虚拟地址的映射,如下图:

映射完成之后,可以看一下具体各个段的区域,以我自己使用的平台为例:

The address information can also be found from the System.map file.

aarch64-linux-gnu-objdump -x vmlinux can view more detailed address information.

5. map_mem

从函数名字中可以看出,map_mem主要完成的是物理内存的映射,这部分的物理内存是通过memblock_add添加到系统中的,当对应的memblock设置了MEMBLOCK_NOMAP的标志时,则不对其进行地址映射。
map_mem函数中,会遍历memblock中的各个块,然后调用__map_memblock来完成实际的映射操作。先来一张效果图:

map_mem are mapping a physical address to a linear region, we also found the Kernel Image in text, rodata segment mapped twice, because other subsystems, such as hibernate, mapped to the linear region, may require linear region the address referenced text kernel, rodata, the time limit will become read-only mapping / unenforceable, prevent accidental modification or execution.

map_kernelmap_mem函数中的页表映射,最终都是调用__create_pgd_mapping函数实现的:

Overall, it is progressively page table mapping relationship, while the middle will control privileges.
    Details will not be repeated, a code reading with pictures, the effect will be better Oh.

6. Replace the memory page table and release

This small part of the code, not on the map, look at the code it:

    /*
     * 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, PGD_SIZE);
    cpu_replace_ttbr1(lm_alias(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_symbol(swapper_pg_dir) + PAGE_SIZE,
              SWAPPER_DIR_SIZE - PAGE_SIZE);

In simple terms, the new-established pgd page table of contents, copied to swapper_pg_dir, that is before the overwrite temporary page tables. When the copy is complete, it is clear, we can paging_init the beginning of physical memory allocated to freed.
    In addition, in the previous article also analyzed over time swapper_pg_dir page table stored, is stored in a row pgd, pud, pmd, and now just need to reuse swapper_pg_dir, the rest of the course can be released.

Well, go beyond that, the road is long, from the Buddy System, Slab, Malloc and a variety of memory seems to show the operation is still a long way, he continued.

Leave a Reply