【问题标题】:How does ARM Linux emulate the dirty, accessed, and file bits of a PTE?ARM Linux 如何模拟 PTE 的脏位、访问位和文件位?
【发布时间】:2016-01-01 18:52:46
【问题描述】:

根据pgtable-2-level.h,ARM Linux 有两个版本的 PTE; Linux PTE 和硬件 PTE。 Linux PTE 存储在 1024 字节的偏移量以下。

handle_pte_fault 各种函数(如pte_filepte_mkdirtypte_mkyoung)中处理页面错误时,请使用 H/W PTE 版本调用。

但实际上 ARM H/W 并不支持其 PTE 中的脏、访问和文件位。

我的问题是它如何检查 H/W PTE 上页面的脏、已访问文件位?理想情况下,它应该检查 Linux PTE 上存储在 1024 字节偏移以下的那些位?

【问题讨论】:

    标签: linux-kernel arm mmu


    【解决方案1】:

    我的问题是它如何检查 H/W PTE 上页面的脏、已访问文件位?

    TL;DR - 通过在初始访问时出现页面错误来模拟它们。

    答案在pgtable-2-level.h

    “脏”位仅通过授予硬件写入权限来模拟 如果页面在 Linux PTE 中被标记为“可写”和“脏”。这 意味着对干净页面的写入将导致权限错误,并且 Linux MM 层将通过 handle_pte_fault() 将页面标记为脏。 为了让硬件注意到权限变化,TLB 条目必须 被刷新,而 ptep_set_access_flags() 会为我们做这件事。

    dirty 为例,页面的初始 MMU 映射被标记为只读。当一个进程写入它时,会产生一个页面错误。这是引用的handle_pte_fault,主要代码在fault.c as do_page_fault 中,并将调用最终以handle_pte_fault 结尾的通用handle_mm_fault。可以看代码,

    if (flags & FAULT_FLAG_WRITE) {
            if (!pte_write(entry))
                return do_wp_page(mm, vma, address,
                        pte, pmd, ptl, entry);
            entry = pte_mkdirty(entry);  /** Here is the dirty emulation. **/
    }
    

    所以Linux通用代码会检查页面的权限,认为它是可写的,并调用pte_mkdirty将页面标记为脏;整个过程通过故障处理程序启动或模拟。在 Linux PTE 中将页面标记为 dirty 后,ARM PTE 被标记为可写,因此后续写入不会导致错误。

    accessed 是相同的,只有读取和写入最初都会出错。 file 位也是完全未映射的,当发生故障时,会咨询 Linux PTE 以查看它是由文件支持还是完全未映射 页面错误。

    在用新的权限更新硬件表并记账后,用户态程序在故障指令处重新启动,除了处理故障的时间间隔外,它不会注意到差异。


    ARM Linux 使用 4k 页,ARM 2 级页表大小为 1k(256 个条目 * 4 字节)。从 pgtable-2-level.h cmets,

    因此,我们稍微调整了实现——我们告诉 Linux 我们在第一级有 2048 个条目,每个条目是 8 个字节(iow,两个指向第二级的硬件指针。)第二级包含两个硬件 PTE 表连续排列,前面是包含 Linux 所需状态信息的 Linux 版本。因此,我们最终在“PTE”级别中有 512 个条目。

    为了使用完整的 4K 页面,PTE 条目的结构类似于,

    1. Linux PTE [n]
    2. Linux PTE [n+1]
    3. ARM PTE [n]
    4. ARM PTE [n+1]

    一个完整的 4k 页面的四个 1k 项目。这些页面集合必须按进程进行管理,以便为每个进程提供唯一的内存视图,并且共享一些信息以节省实际 RAM。函数cpu_set_pte_ext 用于更改物理ARM 条目。由于每个 ARM CPU 版本使用稍微不同的表结构和功能,processor function table 中有一个条目指向一个汇编程序例程。例如,cpu_v7_set_pte_ext 是 ARMv7 或典型的原始 Cortex CPU 实现。该例程负责检查 Linux 标志并相应地更新硬件位。可以看出,r3 在该例程结束时被写入pte+2048(从 Linux PTE 到硬件 PTE 的偏移量)。 proc-marcos.S 中的汇编器宏 armv3_set_pte_ext 被许多较旧的 CPU 变体使用。

    见:Tim's notes on ARM MM
    Page table entry (PTE) descriptor in Linux kernel for ARM

    【讨论】:

    • 感谢您的宝贵回答,但我再次怀疑和困惑的是 pte_write() 如何为只读页面返回 true,pte_write 宏检查的 PTE 版本是 Linux PTE 还是 ARM PTE? ?以同样的方式 pte_mkdirty 修改了哪个条目 Linux PTE 或 ARM PTE ??因为 from handle_mm_fault 从 pte_offset_map 获取 pte ,它似乎返回 ARM PTE ,如果我错了,请纠正我。
    • 其实,这些似乎都是新问题。我已经更新了我的答案。您寻求的魔法是cpu_set_pte_ext,它类似于 C++ 虚函数,并且针对可变 ARM MMU 位布局(新的 CPU 类型具有扩展功能)以不同方式实现。但是,它们在写入 Linux PTE 和 ARM PTE (+2048) 时都很常见。
    • Linux 仅对 Linux PTE 值进行操作。只有当它们提交时,才会调用cpu_set_pte_ext 函数来检查Linux 版本并更新硬件版本​​。例如,set_pte_at 和其他一些初始化 PTE 的地方。
    猜你喜欢
    • 2011-10-20
    • 2021-07-02
    • 2013-01-03
    • 2022-01-19
    • 1970-01-01
    • 2013-03-24
    • 2013-03-19
    • 2020-05-28
    • 1970-01-01
    相关资源
    最近更新 更多