Linux kernel 引导期间Linux内核空间中的页表

Linux kernel 引导期间Linux内核空间中的页表,linux-kernel,mmu,Linux Kernel,Mmu,我觉得Linux内核中的页表管理很混乱 在Linux内核空间中,在打开页表之前。内核将在具有1-1映射机制的虚拟内存中运行。打开页表后,内核将参考页表将虚拟地址转换为物理内存地址。 问题是: 此时,在打开页表之后,内核空间仍然是1GB(从0xC0000000到0xFFFFFF) 在内核进程的页表中,只映射0xC0000000-0xFFFFFFFF?范围内的页表条目(PTE)?。PTE超出此范围将不会被映射,因为内核代码永远不会跳转到那里 打开页表前后的映射地址相同? 例如,在打开页表之前,虚拟地

我觉得Linux内核中的页表管理很混乱

在Linux内核空间中,在打开页表之前。内核将在具有1-1映射机制的虚拟内存中运行。打开页表后,内核将参考页表将虚拟地址转换为物理内存地址。 问题是:

  • 此时,在打开页表之后,内核空间仍然是1GB(从0xC0000000到0xFFFFFF)

  • 在内核进程的页表中,只映射0xC0000000-0xFFFFFFFF?范围内的页表条目(PTE)?。PTE超出此范围将不会被映射,因为内核代码永远不会跳转到那里

  • 打开页表前后的映射地址相同?

    例如,在打开页表之前,虚拟地址0xC00000FF映射到物理地址0x000000FF,然后在打开页表之后,上述映射不会改变。虚拟地址0xC00000FF仍映射到物理地址0x000000FF。不同的是,在打开页表之后,CPU已经参考页表将虚拟地址转换为物理地址,而以前不需要这样做

  • 内核空间中的页表是全局的,将在系统中的所有进程(包括用户进程)中共享

  • x86 32位和ARM中的这种机制相同吗


  • 当Linux启用MMU时,只需要映射内核空间的虚拟地址。这种情况在引导的早期发生。此时,没有用户空间。MMU可以将多个虚拟地址映射到同一物理地址没有任何限制。因此,在启用MMU时,最简单的方法是为内核代码空间和映射
    link==phys
    0xC0000000进行
    virt==phys
    映射

  • 打开页表前后的映射地址是否相同
  • 如果物理代码地址为Oxff,最终链接地址为0xc00000FF,则在打开MMU时,我们有一个重复的映射。0xff0xc00000ff都映射到同一物理页面。简单的
    jmp
    (跳转)或
    b
    (分支)将从一个地址空间移动到另一个地址空间。此时,当我们在最终目标地址执行时,可以删除
    virt==phys
    映射

    我认为以上应该回答第1点到第3点。基本上,引导页面表不是最终页面表

    四,。内核空间中的页表是全局的,将在系统中的所有进程(包括用户进程)中共享

    是的,这是一个巨大的胜利,因为VIVT缓存和许多其他原因

    五,。x86 32位和ARM中的这种机制相同吗

    当然,基本的机制是不同的。即使对于这些系列中的不同处理器,它们也是不同的;486对P4对Amd-K6;ARM926与Cortex-A5与Cortex-A8等。但是,语义非常相似

    请参阅:-一篇关于早期Linux内存阶段的文章


    根据版本的不同,不同的内存池和页表映射在引导期间处于活动状态。在运行
    init
    之前,我们都熟悉的映射不需要就位。

    以下讨论基于32位ARM Linux,内核源代码版本为3.9
    如果您完成了设置初始页面表(稍后将由函数
    paging_init
    )和打开MMU的过程,您的所有问题都可以得到解决

    当引导加载程序首次启动内核时,汇编函数
    stext
    (在arch\arm\kernel\head.s中)是第一个运行的函数。请注意,MMU目前尚未打开

    除其他外,此函数
    stext
    完成的两个导入作业是:

    • 创建初始页面选项卡(稍后将由 函数
      分页\u init
    • 打开MMU
    • 跳转到内核初始化代码的C部分并进行
    在深入研究您的问题之前,最好了解:

    • 在打开MMU之前,CPU发出的每个地址都是物理地址 地址
    • 打开MMU后,CPU发出的每个地址都是虚拟地址
    • 在打开MMU之前,应该设置一个合适的页表,否则您的代码将“被吹走”
    • 按照惯例,Linux内核使用较高1GB部分的虚拟地址,而用户区使用较低的3GB部分
    现在是棘手的部分:
    第一个技巧:使用位置无关代码。 汇编函数stext链接到地址“
    PAGE\u OFFSET+TEXT\u OFFSET
    ”(0xCxxxxxxx),这是一个虚拟地址,但是,由于MMU尚未打开,汇编函数stext运行的实际地址是“
    PHYS\u OFFSET+TEXT\u OFFSET
    ”(实际值取决于实际硬件),这是一个物理地址

    所以,这里有一件事:函数
    stext
    的程序“认为”它运行在类似0xCxxxxxxx的地址中,但实际上它运行在地址(0x00000000+一些设置)中(假设您的硬件将0x00000000配置为RAM的起点)。因此,在启用MMU之前,需要非常仔细地编写汇编代码,以确保在执行过程中不会出错。实际上,使用了一种称为位置独立代码(PIC)的技术

    为了进一步解释上述内容,我提取了几个汇编代码片段:

    ldr r13, =__mmap_switched    @ address to jump to after MMU has been enabled
    
    b   __enable_mmu             @ jump to function "__enable_mmu" to turn on MMU
    
    请注意,上面的“ldr”指令是一条伪指令,表示“获取函数uu mmap_的(虚拟)地址并将其放入r13”

    和函数uu启用mmu依次调用函数u启用mmu: (请注意,我从函数\uu\t中删除了几个指令。)
    ENTRY(__turn_mmu_on)
        mcr p15, 0, r0, c1, c0, 0       @ write control reg to enable MMU====> This is where MMU is turned on, after this instruction, every address issued by CPU is "virtual address" which will be translated by MMU
        mov r3, r13   @ r13 stores the (virtual) address to jump to after MMU has been enabled, which is (0xC0000000 + some_offset)
        mov pc, r3    @ a long jump
    ENDPROC(__turn_mmu_on)