我想出了这个问题,因为我不明白在内核区域如何进行地址转换。
根据我的理解,要翻译0xC0000000
以上的任何地址,我们只需要用PAGE_OFFSET
减去此地址(除了内核初始化过程,我们需要一个8MB范围的页表)。但是,如果CPU执行需要地址的指令(例如0xF0000020
),而系统只有256MB RAM,则没有意义。
由于上述原因,我认为内核确实有一个页表,允许MMU将0xC0000000
以上的虚拟地址转换为物理地址。因此,在什么情况下我们可以直接减去PAGE_OFFSET
,在什么情况下我们需要内核页表?
我可能在开始时出错,所以请更正。
编辑
来自<<了解Linux虚拟内存管理器>>,它表示存在内核页表。现在,更加困惑......
3.6内核页表
系统首次启动时,未启用分页,因为页表不会 神奇地初始化自己。每个架构都以不同的方式实现 只讨论x86案例。页表初始化分为两个 阶段。引导阶段仅为8MiB设置页表,以便进行分页 单位可以启用。 第二阶段初始化其余页面表。我们 在以下部分中讨论这两个阶段。
3.6.1引导
...
3.6.2完成
负责完成页表的函数叫做paging_init()。该 x86上此函数的调用图如图3.4所示。
该函数首先调用pagetable_init()来初始化必要的页表 引用ZONE_DMA和ZONE_NORMAL中的所有物理内存。记住这一点 ZONE_HIGHMEM中的高内存不能直接引用和映射 暂时设置它。对于内核使用的每个pgd,引导内存 调用allocator(参见第5章)为PGD和PSE分配页面 如果可以使用4MiB TLB条目而不是4KiB,则将设置位。如果是PSE 不支持bit,将为每个pmd t分配PTE的页面。如果是CPU 支持PGE标志,它也将被设置为使页表条目是全局的 并且对所有流程都可见。
接下来,pagetable_init()调用fixrange_init()来设置固定地址 从FIXADDR_START开始的虚拟地址空间末尾的空间映射。 这些映射用于诸如本地高级可编程之类的目的 中断控制器(APIC)和FIX_KMAP_BEGIN之间的原子kmappings 和kmap_atomic()所需的FIX_KMAP_END。最后,函数调用 fixrang_init()初始化正常高内存所需的页表条目 使用kmap()进行映射。
在pagetable_init()返回后,内核空间的页表现已完全显示 初始化,所以静态PGD(swapper_pg_dir)被加载到CR3寄存器中 现在,寻呼单元正在使用静态表。
paging_init()的下一个任务是负责调用kmap_init() 使用PAGE_KERNEL保护标志初始化每个PTE。最后的任务是 调用zone_sizes_init(),初始化所有使用的区域结构。
答案 0 :(得分:0)
第一个900MB物理内存(如果存在)有一个线性映射,因此该内存的虚拟地址等于物理内存加PAGE_OFFSET
。当然,如果内核想要将该内存用于其他目的,这并不会阻止相同的物理内存映射到进程的地址空间的其他位置。
答案 1 :(得分:0)
尽管线性映射对于人类来说似乎很特殊,但它(通常)在MMU配置方面并不特殊。
正如您所说,要将虚拟地址从3G转换为3G + 900MB,我们可以使用PAGE_OFFSET直接减去这些地址。这是否意味着内核不需要任何页表?
仍需要这些表来解释到MMU的特定(线性)映射。虽然有一些特殊情况,如MIPS R3000。
但是,如果CPU执行需要地址的指令,例如0xF0000020
,这没有意义
我会问首先在该地址执行指令是否有意义。我的意思是,在具有256MB RAM的系统上,您不会仅仅遇到这样的请求(至少假设代码没有错误)。
让您感到困惑的一点是IMO:谁负责进行地址翻译?答案是(通常也是)MMU,用硬件实现。因此,页面表是MMU如何进行此类翻译的方式 - 这样做不是内核的责任。内核只需要配置MMU。
当CPU要求地址高于0xC0000000时,如何执行地址转换(virt-> phy)?
就像下面的地址一样。 This阅读可能会有所帮助。
答案 2 :(得分:0)
实际上,您的用户空间程序甚至内核都使用虚拟寻址。这意味着每个内存请求都通过MMU。如果它通过MMU,它使用页表(参见x86上的CR3寄存器)
virtual addr --> MMU --> physical addr
当你访问lowmem时,内核并没有使用一些神奇的优化。是的,lowmem是直接映射的,这就是为什么从人类的角度来看,你可以通过简单的减法将lowmem的虚拟地址转换为物理,但CPU通过内核页表进行翻译。