paging_init 详解

paging_init主要完成初始化内核的分页机制,通过对boot阶段页表的覆盖,填充新的一级页表

 

建立二级页表项由 set_pte_ext 宏实现,实际上底层调用的是在内核启动之初获取的 list->processor->set_pte_ext,这是处理器相关的处理函数,对应的函数实现为 cpu_v7_set_pte_ext,在 arch/arm/mm/proc-v7-2level.S 中。

ENTRY(cpu_v7_set_pte_ext)
#ifdef CONFIG_MMU
    str    r1, [r0]            @ linux version  @直接把pte属性写入Linux版本页表
                                    
                                    
    bic    r3, r1, #0x000003f0            @r1值清除bit4~bit9存储到r3,r3作为临时变量存储硬件pte属性。
    bic    r3, r3, #PTE_TYPE_MASK        @清除r3 bit0、bit1,没有清除bit3、bit2是因为cache、buffer这两位,hw和linux保持一致。
    orr    r3, r3, r2                    @r3=r3|r2,r2是额外属性
    orr    r3, r3, #PTE_EXT_AP0 | 2    @设置hw bit4(AP0bit),设置hw bit1(根据上图,可以得知small page下bit1必须等于1)

    tst    r1, #1 << 4                 @判断r1传入的页表属性,是否设置了bit4(tex位)
    orrne    r3, r3, #PTE_EXT_TEX(1)    @如果linux属性设置了tex位,则硬件版本也要置位tex(hw bit6~8),两者bit偏移位置不一样。

    eor    r1, r1, #L_PTE_DIRTY                @翻转r1 DIRTY位(bit6)
    tst    r1, #L_PTE_RDONLY | L_PTE_DIRTY        @判断是否设置了只读。+
    orrne    r3, r3, #PTE_EXT_APX            @设置硬件版本hw bit9(APX值(置1只读))

    tst    r1, #L_PTE_USER                        @判断传入属性是否设置L_PTE_USR
    orrne    r3, r3, #PTE_EXT_AP1            @设置硬件版本hw bit5(AP1bit)

    tst    r1, #L_PTE_XN                        @判断传入属性是否设置XN(不可执行)
    orrne    r3, r3, #PTE_EXT_XN                @设置硬件版本hw bit0(不可执行位)

    tst    r1, #L_PTE_YOUNG
    tstne    r1, #L_PTE_VALID
    eorne    r1, r1, #L_PTE_NONE
    tstne    r1, #L_PTE_NONE
    moveq    r3, #0

 ARM(    str    r3, [r0, #2048]! )
 THUMB(    add    r0, r0, #2048 )
 THUMB(    str    r3, [r0] )
    ALT_SMP(W(nop))
    ALT_UP (mcr    p15, 0, r0, c7, c10, 1)        @ flush_pte
#endif
    bx    lr
ENDPROC(cpu_v7_set_pte_ext)

 

在 set_pte_ext 中,除了设置地址映射部分之外,还需要处理大量标志位的设置(比如 YOUNG、DIRTY bit),毕竟针对同一个页面,需要填充一个软件二级页表项和一个硬件二级页表项,硬件二级页表项给 MMU 使用,保存在 软件二级页表项 + 2048 地址处,在上面贴出的汇编代码中也有体现

 

posted @ 2023-07-01 18:52  流水灯  阅读(128)  评论(0编辑  收藏  举报