From ac6b5d8a816db2f3cd9796e73d4aacdc3f8ef295 Mon Sep 17 00:00:00 2001 From: Song Shuai Date: Fri, 16 Jun 2023 18:26:09 +0800 Subject: [PATCH 1/2] add 20230615-hugepaged-linear-mapping.md Signed-off-by: Song Shuai --- articles/20230615-hugepaged-linear-mapping.md | 528 ++++++++++++++++++ 1 file changed, 528 insertions(+) create mode 100644 articles/20230615-hugepaged-linear-mapping.md diff --git a/articles/20230615-hugepaged-linear-mapping.md b/articles/20230615-hugepaged-linear-mapping.md new file mode 100644 index 0000000..ad95c84 --- /dev/null +++ b/articles/20230615-hugepaged-linear-mapping.md @@ -0,0 +1,528 @@ +> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.1 - [pangu epw]
+> Author: sugarfillet
+> Date: 2023/06/15
+> Revisor: Falcon falcon@tinylab.org
+> Project: [RISC-V Linux 内核剖析](https://gitee.com/tinylab/riscv-linux)
+> Proposal: [RISC-V Linux SMP 技术调研与分析](https://gitee.com/tinylab/riscv-linux/issues/I5MU96)
+> Sponsor: PLCT Lab, ISCAS + +# RISC-V Linux 线性地址大页支持补丁解读 + +## 前言 + +Linux-v6.4-rc1 发布后带来了几个比较重要的变更,其中 commit (3335068f8721 "riscv: Use PUD/P4D/PGD pages for the linear mapping") 用来为内核线性地址空间提供的大页映射的支持,以获取更好的性能并回收了一些浪费的内存。然而,此补丁却带来不少的问题,比如:休眠场景下的 panic 以及 UEFI 启动过程中的 panic。 + +本文对该 commit 及其背景知识进行介绍,并对其引发的两个问题进行分析。 + +**说明**: + +- 本文的 Linux 版本采用 `Linux v6.4-rc1` + +## RISC-V 地址翻译 + +如 "RISC-V-Reader-Chinese-v2p1.pdf" 文档所述: + +> RISC-V S 模式提供了一种传统的虚拟内存系统,它将内存划分为固定大小的页来进行地址转换和对内存内容的保护。启用分页的时候,大多数地址(包括 load 和 store 的有效地址和 +PC 中的地址)都是虚拟地址。要访问物理内存,它们必须被转换为真正的物理地址,这通过遍历一种称为页表的高基数树实现。页表中的叶节点指示虚地址是否已经被映射到了真正的物理页面,如果是,则指示了哪些权限模式和通过哪种类型的访问可以操作这个页。访问未被映射的页或访问权限不足会导致页错误例外(page fault exception)。 + +RISC-V MMU 可以将取指/load/store 等操作的的虚拟地址转化为物理地址,整个转换过程通过页表结构来实现。RISC-V 在 satp 寄存器的 Mode 字段定义所支持的分页方案,每种方案的区别主要体现在通过几个层级来映射不同长度的 VA 到不同长度的 PA,比如:Sv57 分页方案采用 5 级页表将 57 位的虚拟地址翻译为 56(44+12)位的物理地址: + +| stap.mode | SXLEN(pte_len) | VPNs | PPNs | page level | +|-----------|----------------|-------------------|------------------|------------| +| Sv32 | 32 | 32 (10+10+12) | 22 (12+10) | 2 | +| Sv39 | 64 | 39 (9+9+9+12) | 44 (26+9+9) | 3 | +| Sv48 | 64 | 48 (9+9+9+9+12) | 44 (17+9+9+9) | 4 | +| Sv57 | 64 | 57 (9+9+9+9+9+12) | 44 (8+9+9+9+9+9) | 5 | + +### MMU 地址翻译过程 + +在 RISC-V 特权手册 "Virtual Address Translation Process" 一节中详细地描述了 Sv32 分页方案的地址翻译过程。这里在 Qemu 环境默认的 Sv57 的分页方案下,以内核的加载地址为例,结合 Linux 早期虚拟地址映射保留的每级页目录地址(early_p4d/early_pud/early_pmd),观察 MMU 如何将虚拟地址 -- `0xffffffff80000000` 翻译为其对应的物理地址: + +首先将虚拟地址按照 Sv57 虚拟地址布局划分: + +``` +va=0xffffffff80000000 + +0x[f] 111| 1[ff] | [ff] 1|111 [f] 10| 00 [0] 000|0 [00] |[000] // [] 内的为 16 进制表示,[]之外的为按照 bit 表示,下文亦是如此 +> vpn4 vpn3 vpn2 vpn1 vpn0 offset +``` + +通过 satp.PPN 获取根页表:`early_pg_dir = satp.PPN << 12`,按照如下步骤依次获取每级目录的页表项: + +1. offset = va.vpn4 (511); pte = early_pg_dir[offset] (0x0000000020380c01) // `01` is not leaf so pte.ppn <<12 => early_p4d +2. offset = va.vpn3(511); pte = early_p4d[offset] (0x0000000020380801) // pte.ppn <<12 => early_pud +3. offset = va.vpn2 (510); pte = early_pud[offset] (0x0000000020381001) // pte.ppn <<12 => early_pmd +4. offset = va.vpn1 (0); pte = early_pmd[offset] (0x00000000200800ef) // `ef` is leaf so + +在步骤 4 可以看到当前 VA 对应 earyly_pmd 中偏移为 0 的 PTE,此表项为叶子表项。对此 PTE 按照 PTE 格式划分如下,其中 ppn[4:0] 则为 44 位的物理地址表示,右移 10 位得到其对应的页帧号,再左移 12 位,填充 va.offset 则得到该地址对应的 56 位长度的物理地址。而这个物理地址 `0x00000080200000` 恰恰就是内核加载的物理地址,且映射存放在 PMD 上。 + +``` +pte=0x00000000200800ef + +N PBMT |Reserved PPN | RSW D A G U X W R V + +0x[00]0 | 000[0000020080] 00 | 00[ef] // pte +> ppn[4:0] page bits + +pte.ppn[4:0] = (0x00000000200800ef >>10) = 0x [000]00080200 (len is 44) + +pa = 0x00000080200[000] (ppt.ppn[4:0] <<12 | va.off) + +``` + +```c +(gdb) p/z early_pg_dir +$31 = {{pgd = 0x0000000000000000} , {pgd = 0x00000000205c1401}, { + pgd = 0x0000000000000000} , {pgd = 0x0000000020380c01}} // 511 +(gdb) p/z early_p4d +$35 = {{p4d = 0x0000000000000000} , {p4d = 0x0000000020380801}} // 511 +(gdb) p/z early_pud +$36 = {{pud = 0x0000000000000000} , {pud = 0x0000000020381001}, {pud = 0x0000000000000000}} //510 +(gdb) p/z early_pmd +$37 = {{pmd = 0x00000000200800ef}, {pmd = 0x00000000201000ef}, {pmd = 0x00000000201800ef}, {pmd = 0x00000000202000ef}, {pmd = 0x00000000202800ef}, {pmd = 0x00000000203000ef}, {pmd = 0x00000000203800ef}, { + pmd = 0x00000000204000ef}, {pmd = 0x00000000204800ef}, {pmd = 0x00000000205000ef}, {pmd = 0x00000000205800ef}, {pmd = 0x0000000000000000} } // 0 +``` + +基于以上过程,S-mode 软件如果要开启虚拟内存,则需要建立页表并将根页表的 PFN 写入到 satp 寄存器中,同时需要执行 `sfence.vma` 指令用以同步当前所有的内存读写操作。 + +### Linux 设置页表 + +RISC-V Linux 中使用 `create_pgd_mapping()` 函数用于创建(根)页表,此函数的使用场景有: + +1. 初期的内存映射 `setup_vm()` 为 fix-mapping、内核镜像创建早期的临时页表 -- `early_pg_dir` +2. 系统内存发现后的后期内存映射 `setup_vm_final()` 为内核镜像以及线性地址空间创建页表 -- `swapper_pg_dir` +3. efi 为 runtime 内存创建 runtime 页表 -- `efi_mm` +4. 在休眠唤醒过程中,需要对切换到休眠镜像中保存的页表,调用 `temp_pgtable_mapping()` 函数创建临时页表 + +这里以内核线性地址的页表创建过程来做说明:在 `setup_vm_final()` 阶段,系统内存通过 dtb 或者 UEFI 内存映射表已添加到 `memblok.memory` 或者保留在 `memblock.reserved` 中,调用 `create_linear_mapping_page_table()` 将 `memblock.memory` 中的可用物理内存映射到 `PAGE_OFFSET` 开始的线性虚拟内存区域,调用 `create_pgd_mapping()` 创建页表,最终写入 `satp` 寄存器。调用 `create_pgd_mapping()` 传递的参数有: + +1. `swapper_pg_dir`: 根页表,后续以此变量写入 satp +2. `va`: 要映射的虚拟地址 +3. `pa`: 要映射的物理地址 +4. `map_size`: 要映射的内存大小,在 `best_map_size()` 函数中通过物理地址是否对齐 PGDIR_SIZE/../PMD_SIZE 来决定映射大小(下文的 UEFI 启动 panic 就与此有关) + + 比如:物理地址 `0x00000080200000` 对齐 `PMD_SIZE`,则返回 `PMD_SIZE`,物理地址 `0x00000080210000` 则返回 `PAGE_SIZE` + +5. `prot`: 定义当前映射 PTE 的保护位 + + 比如:内核代码段则为 `PAGE_KERNEL_READ_EXEC` + +```c +// arch/riscv/mm/init.c : 1248 + +static void __init setup_vm_final(void) + create_linear_mapping_page_table(); + /* Map all memory banks in the linear mapping */ + for_each_mem_range(i, &start, &end) { + if (start >= end) + break; + if (start <= __pa(PAGE_OFFSET) && + __pa(PAGE_OFFSET) < end) + start = __pa(PAGE_OFFSET); + if (end >= __pa(PAGE_OFFSET) + memory_limit) + end = __pa(PAGE_OFFSET) + memory_limit; + + create_linear_mapping_range(start, end); + } + + csr_write(CSR_SATP, PFN_DOWN(__pa_symbol(swapper_pg_dir)) | satp_mode); // 写入根页表 PFN 到 satp + local_flush_tlb_all(); + +static void __init create_linear_mapping_range(phys_addr_t start, + phys_addr_t end) +{ + phys_addr_t pa; + uintptr_t va, map_size; + + for (pa = start; pa < end; pa += map_size) { + va = (uintptr_t)__va(pa); + map_size = best_map_size(pa, end - pa); + + create_pgd_mapping(swapper_pg_dir, va, pa, map_size, + pgprot_from_va(va)); + } +} +``` + +`create_pgd_mapping()` 函数用于在页表树中迭代建立内存映射,大致的过程如下: + +1. `pgd_index(va)` 获取 VA 在 PGD 中的偏移(PGD 目录中的 PTE 数目为 `PTRS_PER_PGD -1`) +2. 如果 `map_size` 为 `PGDIR_SIZE`,则表示此映射存放在 PGD 目录中对应索引的叶子 PTE,否则存放到下一级页目录 +3. 存放到下一级页目录 + - 如果此 PTE 为空,则调用 `pt_ops` 结构中分配下一级页目录的函数,并保存在当前 PTE 中。`opt_ops` 在不同启动阶段采用的分配后端不同,可参考 (`pt_ops_set_{early,fixmap,late}`) + - 获取下一级页目录的(虚拟)地址,并调用下一级页目录的创建函数 `create_pgd_next_mapping()`,不同的分页方案调用不同的函数,比如:Sv32 为 `create_pmd_mapping()` + - 如果指定的是最小的 `map_size` -- `PAGE_SIZE`,则最终调用 `create_pte_mapping()` 在 PTE 中存储该页物理地址的 PFN + +```c +// arch/riscv/mm/init.c : 635 + +void __init create_pgd_mapping(pgd_t *pgdp, + uintptr_t va, phys_addr_t pa, + phys_addr_t sz, pgprot_t prot) +{ + pgd_next_t *nextp; + phys_addr_t next_phys; + // 该虚拟地址在其对应的页目录中的索引 + uintptr_t pgd_idx = pgd_index(va); /// (((a) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) + + if (sz == PGDIR_SIZE) { // 存放在 PGD 中 + if (pgd_val(pgdp[pgd_idx]) == 0) + pgdp[pgd_idx] = pfn_pgd(PFN_DOWN(pa), prot); + return; + } + + if (pgd_val(pgdp[pgd_idx]) == 0) { // 创建下一级页目录,并将其物理地址保存到此表项中 + next_phys = alloc_pgd_next(va); + pt_ops.alloc_pmd(__va) + + pgdp[pgd_idx] = pfn_pgd(PFN_DOWN(next_phys), PAGE_TABLE); + + nextp = get_pgd_next_virt(next_phys); // 获取虚拟地址 + pt_ops.get_pmd_virt + + memset(nextp, 0, PAGE_SIZE); + } else { + next_phys = PFN_PHYS(_pgd_pfn(pgdp[pgd_idx])); // 如果表项不为空,取出物理地址 + nextp = get_pgd_next_virt(next_phys); + } + + create_pgd_next_mapping(nextp, va, pa, sz, prot); // 在下一级目录项中对此地址进行映射 + create_pmd_mapping((pmd_t *)__nextp, __va, __pa, __sz, __prot))) + create_pte_mapping(ptep, va, pa, sz, prot) + ptep[pte_idx] = pfn_pte(PFN_DOWN(pa), prot); +} +``` + +通过本节的介绍,相信大家对 MMU 的地址翻译,以及 Linux 如何创建页表有了一定的了解。这两个知识是理解本文要讨论的这个 commit 的背景知识,我们继续。 + +## riscv: Use PUD/P4D/PGD pages for the linear mapping + +> 补丁原文就不贴了,可以结合具体的 commit id(3335068f8721)或者[邮件][1]来看 + +这个补丁在 Linux v6.4-rc1 版本引入,主要带来两个变更: + +- kernel_map.va_pa_offset 从之前的 `PAGE_OFFSET - kernel_map.phys_addr` 变更到 `PAGE_OFFSET - phys_ram_base`。 + + va_pa_offset 用于 `__va()/__pa()` 的计算,比如:对于线性地址的 `__pa()` 等价于:`#define linear_mapping_va_to_pa(x) ((unsigned long)(x) - kernel_map.va_pa_offset)`。此变更就导致:线性地址空间的物理地址可以不从 `kernel_map.phys_addr` -- `0x00000080200000` 开始(这个地址根据前文所述,`map_size` 为 `PMD_SIZE` 即只能进行 2M 的 PMD 的映射),从而可以采用更大的页进行映射,比如:`0x00000000c0000000` 地址可映射到 1G 的页目录上。这样能带来可能的更好的 TLB 性能。 + +- `MIN_MEMBLOCK_ADDR` 从 `__pa(PAGE_OFFSET)` 变更到 `0` + + 此变量用于在早期的内存发现过程中,定义 DRAM 内存发现的下限。此变更导致:可以利用 `0x00000080200000` 地址之前的物理地址,避免的一定的内存浪费。 + +> 注意:此修改使得 `setup_vm_setup()` 之前的 __va/__pa 操作都是无意义,如果你的代码执行了该操作,可能会报错 +> +> 为描述方面,后文统一以“大页补丁”来称呼此补丁。 + +## 休眠 panic + +此问题是我在对 Linux v6.4-rc1 的休眠特性进行分析(可参考社区对休眠的[三篇分析文章][2])的过程中发现的,在做了一些前期定位后,向社区发送了 [Bug Report][3] 邮件。此邮件中经历 50+ 个回复、多种方案的讨论后,最终以临时设置休眠选项为 `NONPORTABLE` 的方案来临时规避此问题。本节结合邮件列表对此问题做个系统的梳理: + +> 你可以在邮件中找到问题的复现方法和系统日志 + +在 `/sys/power/state` 中输入 `disk`,触发休眠过程中,出现 panic,关键日志如下: + +```sh +[root@stage4 ~]# echo disk > /sys/power/state +[ 448.600860] PM: hibernation: hibernation entry +[ 448.633200] Filesystems sync: 0.023 seconds +[ 448.637578] Freezing user space processes +[ 448.642714] Freezing user space processes completed (elapsed 0.004 seconds) +[ 448.643801] OOM killer disabled. +[ 448.646150] PM: hibernation: Preallocating image memory +[ 450.448810] PM: hibernation: Allocated 57556 pages for snapshot +[ 450.449347] PM: hibernation: Allocated 230224 kbytes in 1.80 seconds (127.90 MB/s) +[ 450.449950] Freezing remaining freezable tasks +[ 450.453384] Freezing remaining freezable tasks completed (elapsed 0.003 seconds) +[ 450.498622] Disabling non-boot CPUs ... +[ 450.501293] CPU0 attaching NULL sched-domain. +[ 450.501879] CPU1 attaching NULL sched-domain. +[ 450.503247] CPU0 attaching NULL sched-domain. +[ 450.503624] root domain span: 0 (max cpu_capacity = 1024) +[ 450.514289] CPU1: off +[ 450.525152] PM: hibernation: Creating image: +[ 450.525152] PM: hibernation: Need to copy 56199 pages + +[ 450.525152] Oops - load access fault [#1] +[ 450.525152] Modules linked in: +[ 450.525152] CPU: 0 PID: 210 Comm: bash Not tainted 6.4.0-rc1-00004-gcce672326817 #18 +[ 450.525152] Hardware name: riscv-virtio,qemu (DT) +[ 450.525152] epc : swsusp_save+0x2ee/0x45a +[ 450.525152] ra : swsusp_save+0x2b2/0x45a +[ 450.525152] epc : ffffffff809ac404 ra : ffffffff809ac3c8 sp : ff200000007dbc20 +[ 450.525152] gp : ffffffff815dc700 tp : ff6000000346b000 t0 : 65626968203a4d50 +[ 450.525152] t1 : 0000000000080000 t2 : 7265626968203a4d s0 : ff200000007dbc90 +[ 450.525152] s1 : 0000000000000001 a0 : 0000000000000001 a1 : ff5fffff80000000 +[ 450.525152] a2 : ff60000000000000 a3 : 0000000000001000 a4 : 0000000000000000 +[ 450.525152] a5 : ff60000000000000 a6 : ffffffff815eb000 a7 : ffffffffffff8000 +[ 450.525152] s2 : ff6000000ac22000 s3 : ffffffff815dbf45 s4 : 000000000000db87 +[ 450.525152] s5 : 0000000100000000 s6 : 0004000000000000 s7 : 0040000000000000 +[ 450.525152] s8 : ffffffff815dbf44 s9 : ff1c000002000000 s10: 0000000000080000 +[ 450.525152] s11: ffffffff81082060 t3 : 0000000000078000 t4 : ffffffff815f20c7 +[ 450.525152] t5 : ffffffff815f20c8 t6 : ff200000007dba28 +[ 450.525152] status: 0000000200000100 badaddr: ff60000000000000 cause: 0000000000000005 +[ 450.525152] [] swsusp_save+0x2ee/0x45a +[ 450.525152] [] swsusp_arch_suspend+0x4a/0x98 +[ 450.525152] [] hibernation_snapshot+0x1cc/0x3e2 +[ 450.525152] [] hibernate+0x14e/0x236 +[ 450.525152] [] state_store+0x6a/0x72 +[ 450.525152] [] kobj_attr_store+0xe/0x1a +[ 450.525152] [] sysfs_kf_write+0x32/0x3c +[ 450.525152] [] kernfs_fop_write_iter+0xfa/0x164 +[ 450.525152] [] vfs_write+0x27c/0x31e +[ 450.525152] [] ksys_write+0x68/0xda +[ 450.525152] [] sys_write+0x1a/0x22 +[ 450.525152] [] do_trap_ecall_u+0xc2/0xd6 +[ 450.525152] [] do_trap_ecall_u+0xc2/0xd6 +[ 450.525152] [] ret_from_exception+0x0/0x64 +[ 450.525152] Code: 8f91 8f95 87b3 40fc 8799 07b2 97ae 6685 8633 00e7 (620c) 0633 +[ 450.525152] ---[ end trace 0000000000000000 ]--- +``` + +从日志中可以看到,错误指令为 `epc: swsusp_save+0x2ee/0x45a`,对其执行反汇编后发现:在 `do_copy_page` 函数中,对寄存器 a2 中的地址执行 load 操作触发了 load access fault(此错误同时体现在 "Oops" 提示和 scause 寄存器的值中),可以判断这可能是一个访问 PMP 保护内存触发的异常。而发生错误的虚拟地址为 `0xff60000000000000`,正好的是内核线性地址的起始地址 -- `PAGE_OFFSET`,需要进一步确认该地址的映射的物理内存地址。 + +```c + +1381 *dst++ = *src++; + 0xffffffff809ac400 <+738>: add a2,a5,a4 + 0xffffffff809ac404 <+742>: ld a1,0(a2) // 0xff60000000000000 + 0xffffffff809ac406 <+744>: add a2,s2,a4 + 0xffffffff809ac40a <+748>: addi a4,a4,8 + 0xffffffff809ac40c <+750>: sd a1,0(a2) +``` + +> 结合当前环境,介绍 Linux 内存发现过程(如何将 dtb 中描述的内存信息添加到 memblock) + +Linux 初期的内存发现过程中,以 `parse_dtb() => early_init_dt_scan_memory()` 调用 `memblock_add()`,保存完整的系统内存在 `memblock.memory`,(范围由 `MIN_MEMBLOCK_ADDR` = 0 控制)。在正式页表 `swapper_pg_dir` 建立之前,调用 `early_init_fdt_scan_reserved_mem()` 初始化保留内存,如果对应的 "reserved-memory" 节点中没有 "no-map" 属性,则直接调用 `memblock_reserve()`,而不调用 `memblock_mark_nomap()`。可以在如下日志中看到初始化保留内存的信息: + +```c +[ 0.000000] OF: fdt: Looking for usable-memory-range property... +[ 0.000000] OF: fdt: Reserved memory: reserved region for node 'mmode_resv0@80000000': base 0x0000000080000000, size 0 MiB +[ 0.000000] OF: reserved mem: 0x0000000080000000..0x000000008003ffff (256 KiB) map non-reusable mmode_resv0@80000000 +``` + +此内存区域 `0x0000000080000000..0x000000008003ffff` 正是 OpenSBI 的固件内存(mmode_resv0@80000000),被识别为 "map"、"non-reusable",则该区域同时存在于 `memblock.memory` 和 `memblock.reserved` 中,且无 `MEMBLOCK_NOMAP` 标志。在后续的线性映射过程 `create_linear_mapping_page_table()` 中,`for_each_mem_range` 会对该内存区域进行映射,从 `ptdump` 中可以看到,内核线性地址正好映射到 OpenSBI 的固件内存物理地址: + +```c +---[ Linear mapping ]--- +0xff60000000000000-0xff60000000200000 0x0000000080000000 2M PMD D A G . . W R V // 固件内存 +0xff60000000200000-0xff60000000c00000 0x0000000080200000 10M PMD D A G . . . R V +0xff60000000c00000-0xff60000001000000 0x0000000080c00000 4M PMD D A G . . W R V +0xff60000001000000-0xff60000001600000 0x0000000081000000 6M PMD D A G . . . R V +0xff60000001600000-0xff60000040000000 0x0000000081600000 1002M PMD D A G . . W R V +0xff60000040000000-0xff60000100000000 0x00000000c0000000 3G PUD D A G . . W R V +---[ Modules/BPF mapping ]--- +---[ Kernel mapping ]--- +0xffffffff80000000-0xffffffff80a00000 0x0000000080200000 10M PMD D A G . X . R V +0xffffffff80a00000-0xffffffff80c00000 0x0000000080c00000 2M PMD D A G . . . R V +0xffffffff80c00000-0xffffffff80e00000 0x0000000080e00000 2M PMD D A G . . W R V +0xffffffff80e00000-0xffffffff81400000 0x0000000081000000 6M PMD D A G . . . R V +0xffffffff81400000-0xffffffff81800000 0x0000000081600000 4M PMD +``` + +> 为何 OpenSBI 不在 dtb 中对此固件内存设置 "no-map" 属性呢? + +在 OpenSBI 的 v0.8 中引入 commit 6966ad0abe70 ("platform/lib: Allow the OS to map the regions that are protected by PMP"),此提交对 PMP 保护的内存(比如:固件内存)默认不再设置 "no-map" 属性,并允许操作系统对其进行映射,同时提供 platform_override 使得某个平台(比如:sifive,fu540)可手动设置 "no-map" 属性。而此补丁的出发点,与上节描述的大页补丁是一致的,都是为了更好的 TLB 性能。 + +这样的话,panic 的原因就比较清晰了: + +1. OpenSBI 在 v0.8 之后对于固件内存默认不设置 "no-map" 属性 +2. 上节的大页补丁导致 OpenSBI 的固件内存被映射到线性地址空间 +3. 休眠过程中调用 `swsusp_save()` 拷贝当前系统内存页到休眠镜像,当对固件内存进行拷贝时,触发了 PMP 保护,进而 hart 发生 access fault 异常 + +那针对以上三个原因可以有如下解决方案: + +1. OpenSBI 恢复设置 "no-map" 属性 + + 牺牲 TLB 性能,还要考虑向后的兼容性 + +2. Linux 回退大页补丁 + + 回退会牺牲 TLB 性能(尽管此补丁的作者表示:对线性地址进行大页映射并不会带来更好的性能) + +3. 在休眠过程中跳过固件内存 + + 在启动早期对 "mmode_resv" 节点进行解析,并调用休眠的 `register_nosave_regions()` 接口保证此内存区域不会被休眠过程保存,实现可参考邮件中的[实验性补丁][4]。但此补丁不具有通用性,没办法处理非 "mmode_resv" 节点。 + +4. 设置休眠选项 -- `ARCH_HIBERNATION_POSSIBLE` 为 `NONPORTABLE` + + 休眠功能只能在 OpenSBI v8.0 之前(那些禁止 OS 映射固件内存的 SBI 实现)的系统中开启。而将休眠选项设置为 `NONPORTABLE`,用户可根据自己的系统配置,设置 `NONPORTABLE` 来开启或者关闭休眠功能。此方案在 commit (ed309ce52218 "RISC-V: mark hibernation as nonportable") 中实现。 + +个人比较赞成方案 1,但是推动起来应该比较困难,简单谈谈我对这个几个方案的看法: + +1. 方案 1:固件内存应该没有让内核对其映射的强烈需求,那么 OpenSBI 就应该将该区域设置为 "no-map",至于向后的兼容性,可通过文档的形式来描述 +2. 方案 2:如果对线性地址进行大页映射并不会带来更好的性能,可以回退此补丁 +3. 方案 3:其实此问题并非休眠的单点问题,邮件列表中对此方案的讨论从最初就点偏差 + 比如:通过内核模块直接访问 `PAGE_OFFSET` 也会崩溃(虽然此访问没有经过内存分配器进行,但不代表某些组件(比如:[memory debugging stuff][5])不会这么做) +4. 方案 4: 为了 v6.4 版本稳定的规避方案,需要用户自己判断固件环境来选择开启或者关闭休眠功能 + +最后,我会持续跟踪与此问题相关的一些内核/OpenSBI 的变更,让子弹再飞一会儿。 + +## UEFI 启动 panic + +此问题是我在对 Linux UEFI 启动过程的分析(参考社区对 Linux UEFI [相关文章][6])中发现的,在做了一些前期定位后,向社区发送了 [Bug Report][7] 邮件,本节结合邮件列表对此问题做个系统的梳理: + +> 你可以在邮件中找到问题的复现方法和系统日志 + +启动过程中内核 panic,关键日志如下: + +```sh +[ 0.000000] Unable to handle kernel paging request at virtual address ff6000007fdb1000 +[ 0.000000] Oops [#1] +[ 0.000000] Modules linked in: +[ 0.000000] CPU: 0 PID: 0 Comm: swapper Not tainted 6.4.0-rc1-00007-g6966d7988c4f #65 +[ 0.000000] Hardware name: riscv-virtio,qemu (DT) +[ 0.000000] epc : __memset+0x60/0xfc +[ 0.000000] ra : memblock_alloc_try_nid+0x72/0x82 +[ 0.000000] epc : ffffffff8081d48c ra : ffffffff80a126e4 sp : ffffffff81403e80 +[ 0.000000] gp : ffffffff814fbb38 tp : ffffffff8140dac0 t0 : ff6000007fdb1000 +[ 0.000000] t1 : 0000000000000000 t2 : 5f6b636f6c626d65 s0 : ffffffff81403ec0 +[ 0.000000] s1 : 0000000000026000 a0 : ff6000007fdb1000 a1 : 0000000000000000 +[ 0.000000] a2 : 0000000000026000 a3 : ff6000007fdd7000 a4 : 0000000000000000 +[ 0.000000] a5 : ff5fffff7ffc0000 a6 : 0000000000000018 a7 : 0000000000000080 +[ 0.000000] s2 : ff6000007fdb1000 s3 : ffffffffffffffff s4 : 0000000000009e38 +[ 0.000000] s5 : ffffffffffffffff s6 : ff6000007fdd8000 s7 : 0000000000002000 +[ 0.000000] s8 : 00000000000071c8 s9 : 0000000000000000 s10: 0000000000000000 +[ 0.000000] s11: 0000000000000000 t3 : ffffffff80c0be40 t4 : ffffffff80c0be40 +[ 0.000000] t5 : ffffffff80c0bdb0 t6 : ffffffff80c0be40 +[ 0.000000] status: 0000000200000100 badaddr: ff6000007fdb1000 cause: 000000000000000f // Store/AMO page fault +[ 0.000000] [] __memset+0x60/0xfc +[ 0.000000] [] pcpu_embed_first_chunk+0x568/0x738 +[ 0.000000] [] setup_per_cpu_areas+0x22/0xb6 +[ 0.000000] [] start_kernel+0x1ce/0x57e +[ 0.000000] Code: 1007 82b3 40e2 0797 0000 8793 00e7 8305 97ba 8782 (b023) 00b2 +[ 0.000000] ---[ end trace 0000000000000000 ]--- +[ 0.000000] Kernel panic - not syncing: Attempted to kill the idle task! +[ 0.000000] ---[ end Kernel panic - not syncing: Attempted to kill the idle task! ]--- +``` + +此问题与休眠问题,有如下不同: + +1. 异常类型不同 + + 此问题为 page fault 是系统开启分页后 MMU 相关的异常,而休眠问题是 access-fault,是有 PMAs 或者 PMP 引发的异常 + +2. 休眠问题中固件内存映射到线性地址的情况,在 UEFI 环境中不存在 + + 对于 `reserved-memory` 节点中没有设置 "no-map" 且保留的固件内存,EDK2 (RiscVVirt) 将其保存在 `EfiReservedMemoryType`(下文会详细介绍)。而 Linux UEFI 初始化过程 `efi_init() => reserve_regions()` 会以 EFI memory mapping 重新构建 memblock,对于 `EfiReservedMemoryType` 内存,不会将其添加到 `memblock.memory` 中,而是在之后的 `early_init_fdt_scan_reserved_mem()` 函数中保存在 `memblock.reserved`,故而不会映射到线性地址。 + +而发生 page fault 的错误地址 `0xff6000007fdb1000` 属于线性地址空间,调试一下线性地址空间的映射过程,看到如下日志: + +``` +song # lowmem region: [0x0000000081800000 -- 0x00000000ffe3d000], va: 0xff6000007fbc0000, pa: 0x00000000ffc00000, map_size: 200000 ,pg: e7 +song # lowmem region: [0x0000000081800000 -- 0x00000000ffe3d000], va: 0xff6000007fdc0000, pa: 0x00000000ffe00000, map_size: 1000 ,pg: e7 +``` + +错误地址存在于 "va: 0xff6000007fbc0000"、"pa: 0x00000000ffc00000" 的 2M PMD 映射中,尝试对该映射做个手动分析: + +1. map_size = best_map_size(pa, end - pa) + + 映射大小通过物理地址及其与 DRAM 最大内存地址进行计算,由于 "0x00000000ffc00000" 对齐 `PMD_SIZE` 则设置映射大小为 `PMD_SIZE` + +2. create_pgd_mapping(swapper_pg_dir, va, pa, map_size, pgprot_from_va(va)); + + 此函数在 "Linux 设置页表" 一节有详细介绍,迭代调用到 `create_pmd_mapping()` 并以 `pmd_index(va)` 为索引,设置当前物理地址的 PFN 到 PMD 表项中。而 "va: 0xff6000007fbc0000"(注意:此地址不是 2M 对齐的)在经过 `pmd_index(va)` 后,在最终的页表中实际映射到了 "va: 0xff6000007fa00000",参考下面代码块中的地址展开: + + ``` + va = 0xff6000007fbc0000 + + [ff6000007f]101|1[c0]|000 + vpn0 + + // the va after pmd_index(va) + + [ff6000007f]101|0[00]|000 + + real va : 0xff6000007fa00000 + + ``` + +整个 2M PMD 的真实映射表示为:"va: [0xff6000007fa00000,0xff6000007fc00000)" => "pa: [0x00000000ffc00000,0x00000000ffe00000)",而在此虚拟地址范围之后且在下一个 4K PTE 映射的起始虚拟地址之间 -- `[0xff6000007fc00000,0xff6000007fdc0000` 存在一个虚拟地址空洞,如果对其进行访问,都会导致 page fault,而此问题的错误地址 `0xff6000007fdb1000` 正好就在这个区间。 + +为了解决此虚拟地址空洞,应该在映射大小计算中考虑虚拟地址的与某个映射大小对齐,可参考如下代码,那么在此问题中,由于 va 不能对齐 `PMD_SIZE`,则此映射会以 `PAGE_SIZE` 进行。此修改在 riscv/fixes commit (49a0a3731596 "riscv: Check the virtual alignment before choosing a map size") 中实现。 + +```c +static uintptr_t __init best_map_size(phys_addr_t pa, uintptr_t va, + phys_addr_t size) +{ + if (!(pa & (PGDIR_SIZE - 1)) && !(va & (PGDIR_SIZE - 1)) && size >= PGDIR_SIZE) + return PGDIR_SIZE; + + if (!(pa & (P4D_SIZE - 1)) && !(va & (P4D_SIZE - 1)) && size >= P4D_SIZE) + return P4D_SIZE; + + if (!(pa & (PUD_SIZE - 1)) && !(va & (PUD_SIZE - 1)) && size >= PUD_SIZE) + return PUD_SIZE; + + if (!(pa & (PMD_SIZE - 1)) && !(va & (PMD_SIZE - 1)) && size >= PMD_SIZE) + return PMD_SIZE; + + return PAGE_SIZE; +} + +``` + +从这个问题,我们了解到:在调用 `create_pxd_mapping()` 接口设置页表时,需要保证虚拟地址 va 和物理地址 pa 在映射大小 map_size 上对齐。 + +此邮件意外的展开了关于 `reserved-memory` 节点中设置 "no-map" 属性的内存区域应该如何在 UEFI 中保存的讨论: + +根据 DT 规范(devicetree-specification v0.4-rc1 3.5.4 "/reserved-memory and UEFI"),设置 "no-map" 的保留内存存放在 EfiReservedMemoryType,其他类型的保留内存存放在 BootServiceData(会被 OS 在 ExitBootServices 之后回收)。而在 EDK2 (RiscVVirt) 中对于固件内存(mmode_resv0)无视其 "no-map" 属性直接保存到 EfiReservedMemoryType,避免 OS 访问。相关代码及日志体现在: + +```c +// edk2: OvmfPkg/RiscVVirt/Sec/Memory.c :200 + +MemoryPeimInitialization() + Node = fdt_path_offset (FdtPointer, "/reserved-memory/mmode_resv0"); + MmodeResvBase = fdt64_to_cpu (ReadUnaligned64 (RegProp)); + MmodeResvSize = fdt64_to_cpu (ReadUnaligned64 (RegProp + 1)); + InitializeRamRegions ( CurBase, CurSize, MmodeResvBase, MmodeResvSize); + AddReservedMemoryBaseSizeHob (MmodeResvBase, MmodeResvSize); + +// Linux 日志 +[ 0.000000] efi: 0x000080000000-0x00008003ffff [Reserved | | | | | | | | | | | | | |UC] // EfiReservedMemoryType +[ 0.000000] memblock_reserve: [0x00000000f8fd1000-0x00000000f8fd1fff] efi_init+0x150/0x26c +[ 0.000000] memblock_reserve: [0x0000000080200000-0x00000000817fffff] paging_init+0xee/0x5ae +[ 0.000000] memblock_reserve: [0x00000000f2b61000-0x00000000f6760fff] reserve_initrd_mem+0x9a/0xfc +[ 0.000000] memblock_reserve: [0x0000000080000000-0x000000008003ffff] early_init_fdt_scan_reserved_mem+0x242/0x2c6 +[ 0.000000] OF: reserved mem: 0x0000000080000000..0x000000008003ffff (256 KiB) map non-reusable mmode_resv0@80000000 +``` + +但是在那些遵守 DT 标准的 UEFI 固件(比如 U-Boot)中,对于没有设置 "no-map" 属性的固件内存,则保留在 BootServiceData 区域,会被 OS 回收并映射,这样就会导致与休眠 panic 类似的问题。那么只能在 OpenSBI 中将固件内存设置为 "no-map",正如 Atish Patra 所述: + +``` +Let's have a no-map set for the reserved memory set for the firmware. +The fallout would be anybody with kernel > 6.4 has to upgrade the firmware version that sets the no-map correctly +if they care about hibernation or EFI booting. + +OpenSBI v1.3 is planned this month anyway. +We can communicate the same to the rust-sbi project as well. +``` + +在我写这篇文章的时候,这个补丁已经提交了,参考 [platform/lib: Set no-map attribute on all PMP regions][8]。 + +## 小结 + +本文首先介绍了 RISC-V MMU 的地址翻译过程,并分析了 `create_pgd_mapping()` 接口是如何创建页表,之后介绍了 RISC-V Linux v6.4-rc1 大页补丁的实现,并对该补丁引发的两个 panic 进行分析,这里做个总结。 + +在 OpenSBI v8.0 之后的固件为提升 TLB 性能默认不为固件内存设置 "no-map"属性,使得 OS 可以映射固件内存,Linux 大页补丁调整了物理内存发现的下限,使得固件内存映射到了线性地址空间,而休眠过程对其进行拷贝时发生 access-fault。内核目前在 commit (ed309ce52218 "RISC-V: mark hibernation as nonportable") 中以 `NONPORTABLE` 选项在没有为固件内存设置 "no-map" 属性的 OpenSBI 中临时关闭休眠功能。 + +Linux 大页补丁在调用 `create_pgd_mapping()` 接口设置页表时,计算映射大小没有考虑虚拟地址对齐,进而产生了虚拟地址空洞,使得对空洞的访问触发 page fault,从而导致 UEFI 启动失败。此问题在 riscv/fixes commit (49a0a3731596 "riscv: Check the virtual alignment before choosing a map size") 中解决。 + +第二个问题,同时引发了另外一个潜在问题:在没有为固件内存设置 "no-map"属性的 OpenSBI 并且遵守 DT 规范(/reserved-memory and UEFI)的固件环境中,OS 会映射固件内存,从而导致与休眠 panic 相似的问题。此问题最终推动 OpenSBI 恢复对固件内存设置 "no-map" 属性,预计在 OpenSBI v1.3 可以看到。 + +如果你使用 RISC-V Linux v6.4-rc1 及其之后的内核版本,并遇到与上述两个问题,可降级到 OpenSBI 到 v0.8 之前的版本或者采用这个[补丁][8]对你的 OpenSBI 进行升级。 + +## 参考资料 + +- [RISC-V 休眠实现分析][2] +- [RISC-V Linux 内核 UEFI 启动过程分析][6] +- [Bug report: kernel paniced when system hibernates][3] +- [Bug report: kernel paniced while booting with UEFI][7] + +[1]: https://lore.kernel.org/r/20230324155421.271544-4-alexghiti@rivosinc.com +[2]: https://gitee.com/tinylab/riscv-linux/pulls/694 +[3]: https://lore.kernel.org/linux-riscv/CAAYs2=gQvkhTeioMmqRDVGjdtNF_vhB+vm_1dHJxPNi75YDQ_Q@mail.gmail.com/ +[4]: https://lore.kernel.org/linux-riscv/CAAYs2=jEPQLwe83UDVFStLuei4C+8ZuHJ98_J13RhobpjkGBVw@mail.gmail.com/ +[5]: https://lore.kernel.org/linux-kernel/20230530080425.18612-1-alexghiti@rivosinc.com/ +[6]: https://gitee.com/tinylab/riscv-linux/pulls/660 +[7]: https://lore.kernel.org/linux-riscv/tencent_7C3B580B47C1B17C16488EC1@qq.com/ +[8]: https://github.com/riscv-software-src/opensbi/commit/8153b2622b08802cc542f30a1fcba407a5667ab9 -- Gitee From b788974876c340c4170efeed56e36dfdf6d2698b Mon Sep 17 00:00:00 2001 From: Song Shuai Date: Fri, 30 Jun 2023 18:54:08 +0800 Subject: [PATCH 2/2] 20230615-hugepaged-linear-mapping.md: take the advices from falcon --- articles/20230615-hugepaged-linear-mapping.md | 73 ++++++++++++++---- .../sv57_address_trans.png | Bin 0 -> 75952 bytes 2 files changed, 56 insertions(+), 17 deletions(-) create mode 100644 articles/images/riscv-linear-mapping/sv57_address_trans.png diff --git a/articles/20230615-hugepaged-linear-mapping.md b/articles/20230615-hugepaged-linear-mapping.md index ad95c84..7d7a04c 100644 --- a/articles/20230615-hugepaged-linear-mapping.md +++ b/articles/20230615-hugepaged-linear-mapping.md @@ -1,4 +1,4 @@ -> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.1 - [pangu epw]
+> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.1 - [tables]
> Author: sugarfillet
> Date: 2023/06/15
> Revisor: Falcon falcon@tinylab.org
@@ -17,6 +17,17 @@ Linux-v6.4-rc1 发布后带来了几个比较重要的变更,其中 commit (33 **说明**: - 本文的 Linux 版本采用 `Linux v6.4-rc1` +- 本文采用的一些缩略词解释如下 + +| 缩略词 | 全称 | 说明 | +|-------------|---------------------------------|------------------------------------------------------------------| +| PA | Physical Address | 物理地址 | +| VA | Virtual Address | 虚拟地址 | +| PPN | Physical Page Number | 物理页帧号,与页内偏移 page offset 构成物理地址 | +| VPN | Virtual Page Number | 虚拟页帧号,与页内偏移 page offset 构成虚拟地址 | +| PTE | Page Table Entry | 页表项,存放叶子页表或者页目录的 PPN,还有一层含义代表最后一级的页表 | +| PGD | Page Global Directory | 根(页)目录 | +| P4D/PUD/PMD | Page 4th/Upper/Middle Directory | 不同级别的页目录项,不同分页方案有不同页目录项,详见下文 | ## RISC-V 地址翻译 @@ -27,17 +38,21 @@ PC 中的地址)都是虚拟地址。要访问物理内存,它们必须被 RISC-V MMU 可以将取指/load/store 等操作的的虚拟地址转化为物理地址,整个转换过程通过页表结构来实现。RISC-V 在 satp 寄存器的 Mode 字段定义所支持的分页方案,每种方案的区别主要体现在通过几个层级来映射不同长度的 VA 到不同长度的 PA,比如:Sv57 分页方案采用 5 级页表将 57 位的虚拟地址翻译为 56(44+12)位的物理地址: -| stap.mode | SXLEN(pte_len) | VPNs | PPNs | page level | -|-----------|----------------|-------------------|------------------|------------| -| Sv32 | 32 | 32 (10+10+12) | 22 (12+10) | 2 | -| Sv39 | 64 | 39 (9+9+9+12) | 44 (26+9+9) | 3 | -| Sv48 | 64 | 48 (9+9+9+9+12) | 44 (17+9+9+9) | 4 | -| Sv57 | 64 | 57 (9+9+9+9+9+12) | 44 (8+9+9+9+9+9) | 5 | +| stap.mode | SXLEN(pte_len) | VPNs | PPNs | page level | page tables | +|-----------|----------------|-------------------|------------------|------------|---------------------| +| Sv32 | 32 | 32 (10+10+12) | 22 (12+10) | 2 | PGD PTE | +| Sv39 | 64 | 39 (9+9+9+12) | 44 (26+9+9) | 3 | PGD PMD PTE | +| Sv48 | 64 | 48 (9+9+9+9+12) | 44 (17+9+9+9) | 4 | PGD PUD PMD PTE | +| Sv57 | 64 | 57 (9+9+9+9+9+12) | 44 (8+9+9+9+9+9) | 5 | PGD P4D PUD PMD PTE | ### MMU 地址翻译过程 在 RISC-V 特权手册 "Virtual Address Translation Process" 一节中详细地描述了 Sv32 分页方案的地址翻译过程。这里在 Qemu 环境默认的 Sv57 的分页方案下,以内核的加载地址为例,结合 Linux 早期虚拟地址映射保留的每级页目录地址(early_p4d/early_pud/early_pmd),观察 MMU 如何将虚拟地址 -- `0xffffffff80000000` 翻译为其对应的物理地址: +可参考此图阅读下文: + +![sv57_address_trans.png](images/riscv-linear-mapping/sv57_address_trans.png) + 首先将虚拟地址按照 Sv57 虚拟地址布局划分: ``` @@ -50,7 +65,7 @@ va=0xffffffff80000000 通过 satp.PPN 获取根页表:`early_pg_dir = satp.PPN << 12`,按照如下步骤依次获取每级目录的页表项: 1. offset = va.vpn4 (511); pte = early_pg_dir[offset] (0x0000000020380c01) // `01` is not leaf so pte.ppn <<12 => early_p4d -2. offset = va.vpn3(511); pte = early_p4d[offset] (0x0000000020380801) // pte.ppn <<12 => early_pud +2. offset = va.vpn3 (511); pte = early_p4d[offset] (0x0000000020380801) // pte.ppn <<12 => early_pud 3. offset = va.vpn2 (510); pte = early_pud[offset] (0x0000000020381001) // pte.ppn <<12 => early_pmd 4. offset = va.vpn1 (0); pte = early_pmd[offset] (0x00000000200800ef) // `ef` is leaf so @@ -150,7 +165,7 @@ static void __init create_linear_mapping_range(phys_addr_t start, 2. 如果 `map_size` 为 `PGDIR_SIZE`,则表示此映射存放在 PGD 目录中对应索引的叶子 PTE,否则存放到下一级页目录 3. 存放到下一级页目录 - 如果此 PTE 为空,则调用 `pt_ops` 结构中分配下一级页目录的函数,并保存在当前 PTE 中。`opt_ops` 在不同启动阶段采用的分配后端不同,可参考 (`pt_ops_set_{early,fixmap,late}`) - - 获取下一级页目录的(虚拟)地址,并调用下一级页目录的创建函数 `create_pgd_next_mapping()`,不同的分页方案调用不同的函数,比如:Sv32 为 `create_pmd_mapping()` + - 获取下一级页目录的(虚拟)地址,并调用下一级页目录的创建函数 `create_pgd_next_mapping()`,不同的分页方案调用不同的函数 - 如果指定的是最小的 `map_size` -- `PAGE_SIZE`,则最终调用 `create_pte_mapping()` 在 PTE 中存储该页物理地址的 PFN ```c @@ -193,6 +208,28 @@ void __init create_pgd_mapping(pgd_t *pgdp, } ``` +如果系统支持五级页表方案 (Sv57),则在 `map_size` 为 `PAGE_SIZE` 的情况下,依次调用 `create_p4d_mapping() => create_pud_mapping() => create_pmd_mapping() => create_pte_mapping()`;如果系统支持四级页表方案 (Sv48),则在 `map_size` 为 `PAGE_SIZE` 的情况下,依次调用 `create_pud_mapping() => create_pmd_mapping() => create_pte_mapping()`;如果系统支持三级页表方案(Sv39),则在 `map_size` 为 `PAGE_SIZE` 的情况下,依次调用 `create_pmd_mapping() => create_pte_mapping()`;如果是 32 位的二级页表方案(Sv32),则直接调用 `create_pte_mapping()`。 + +```c +// arch/riscv/mm/init.c : 611 + +#define create_pgd_next_mapping(__nextp, __va, __pa, __sz, __prot) \ + (pgtable_l5_enabled ? \ + create_p4d_mapping(__nextp, __va, __pa, __sz, __prot) : \ + (pgtable_l4_enabled ? \ + create_pud_mapping((pud_t *)__nextp, __va, __pa, __sz, __prot) : \ + create_pmd_mapping((pmd_t *)__nextp, __va, __pa, __sz, __prot))) + +create_pmd_mapping(pmd_t *pmdp, uintptr_t va, phys_addr_t pa, phys_addr_t sz, pgprot_t prot) + if (sz == PMD_SIZE) + pmdp[pmd_idx] = pfn_pmd(PFN_DOWN(pa), prot); + pte_phys = PFN_PHYS(_pmd_pfn(pmdp[pmd_idx])); + ptep = pt_ops.get_pte_virt(pte_phys); + create_pte_mapping(ptep, va, pa, sz, prot); + ptep[pte_idx] = pfn_pte(PFN_DOWN(pa), prot); + +``` + 通过本节的介绍,相信大家对 MMU 的地址翻译,以及 Linux 如何创建页表有了一定的了解。这两个知识是理解本文要讨论的这个 commit 的背景知识,我们继续。 ## riscv: Use PUD/P4D/PGD pages for the linear mapping @@ -215,7 +252,7 @@ void __init create_pgd_mapping(pgd_t *pgdp, ## 休眠 panic -此问题是我在对 Linux v6.4-rc1 的休眠特性进行分析(可参考社区对休眠的[三篇分析文章][2])的过程中发现的,在做了一些前期定位后,向社区发送了 [Bug Report][3] 邮件。此邮件中经历 50+ 个回复、多种方案的讨论后,最终以临时设置休眠选项为 `NONPORTABLE` 的方案来临时规避此问题。本节结合邮件列表对此问题做个系统的梳理: +此问题是我在对 Linux v6.4-rc1 的休眠特性进行分析(可参考社区对休眠的[三篇分析文章][2])的过程中发现的,在做了一些前期定位后,向社区发送了 [Bug Report][3] 邮件。本节结合邮件列表对此问题做个系统的梳理: > 你可以在邮件中找到问题的复现方法和系统日志 @@ -300,9 +337,11 @@ Linux 初期的内存发现过程中,以 `parse_dtb() => early_init_dt_scan_me [ 0.000000] OF: reserved mem: 0x0000000080000000..0x000000008003ffff (256 KiB) map non-reusable mmode_resv0@80000000 ``` -此内存区域 `0x0000000080000000..0x000000008003ffff` 正是 OpenSBI 的固件内存(mmode_resv0@80000000),被识别为 "map"、"non-reusable",则该区域同时存在于 `memblock.memory` 和 `memblock.reserved` 中,且无 `MEMBLOCK_NOMAP` 标志。在后续的线性映射过程 `create_linear_mapping_page_table()` 中,`for_each_mem_range` 会对该内存区域进行映射,从 `ptdump` 中可以看到,内核线性地址正好映射到 OpenSBI 的固件内存物理地址: +此内存区域 `0x0000000080000000..0x000000008003ffff` 正是 OpenSBI 的固件内存(mmode_resv0@80000000),被识别为 "map"、"non-reusable",则该区域同时存在于 `memblock.memory` 和 `memblock.reserved` 中,且无 `MEMBLOCK_NOMAP` 标志。在后续的线性映射过程 `create_linear_mapping_page_table()` 中,`for_each_mem_range` 会对该内存区域进行映射,从内核页表查询工具 -- `ptdump` 中可以看到,内核线性地址正好映射到 OpenSBI 的固件内存物理地址: -```c +```sh +# cat /sys/kernel/debug/kernel_page_tables +... ---[ Linear mapping ]--- 0xff60000000000000-0xff60000000200000 0x0000000080000000 2M PMD D A G . . W R V // 固件内存 0xff60000000200000-0xff60000000c00000 0x0000000080200000 10M PMD D A G . . . R V @@ -349,11 +388,11 @@ Linux 初期的内存发现过程中,以 `parse_dtb() => early_init_dt_scan_me 个人比较赞成方案 1,但是推动起来应该比较困难,简单谈谈我对这个几个方案的看法: -1. 方案 1:固件内存应该没有让内核对其映射的强烈需求,那么 OpenSBI 就应该将该区域设置为 "no-map",至于向后的兼容性,可通过文档的形式来描述 -2. 方案 2:如果对线性地址进行大页映射并不会带来更好的性能,可以回退此补丁 -3. 方案 3:其实此问题并非休眠的单点问题,邮件列表中对此方案的讨论从最初就点偏差 - 比如:通过内核模块直接访问 `PAGE_OFFSET` 也会崩溃(虽然此访问没有经过内存分配器进行,但不代表某些组件(比如:[memory debugging stuff][5])不会这么做) -4. 方案 4: 为了 v6.4 版本稳定的规避方案,需要用户自己判断固件环境来选择开启或者关闭休眠功能 +- 方案 1:固件内存应该没有让内核对其映射的强烈需求,那么 OpenSBI 就应该将该区域设置为 "no-map",至于向后的兼容性,可通过文档的形式来描述 +- 方案 2:如果对线性地址进行大页映射并不会带来更好的性能,可以回退此补丁 +- 方案 3:其实此问题并非休眠的单点问题,邮件列表中对此方案的讨论从最初就有点偏差 + - 比如:通过内核模块直接访问 `PAGE_OFFSET` 也会崩溃(虽然此访问没有经过内存分配器进行,但不代表某些组件(比如:[memory debugging stuff][5])不会这么做) +- 方案 4: 为了 v6.4 版本稳定的规避方案,需要用户自己判断固件环境来选择开启或者关闭休眠功能 最后,我会持续跟踪与此问题相关的一些内核/OpenSBI 的变更,让子弹再飞一会儿。 diff --git a/articles/images/riscv-linear-mapping/sv57_address_trans.png b/articles/images/riscv-linear-mapping/sv57_address_trans.png new file mode 100644 index 0000000000000000000000000000000000000000..1dbc0bcf63f89af983a10658ecb0755f07b96377 GIT binary patch literal 75952 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≷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 oI!fS_!p{bT>;Kg+w>BXxU8((LZAn22gFq^