1*d78bcf64Slongjin.. SPDX-License-Identifier: GPL-2.0 2*d78bcf64Slongjin.. include:: ../../disclaimer-zh_CN.rst 3*d78bcf64Slongjin 4*d78bcf64Slongjin:Original: Documentation/arch/riscv/boot.rst 5*d78bcf64Slongjin 6*d78bcf64Slongjin:翻译: 7*d78bcf64Slongjin 8*d78bcf64Slongjin 龙进 Jin Long <longjin@dragonos.org> 9*d78bcf64Slongjin 10*d78bcf64Slongjin======================== 11*d78bcf64SlongjinRISC-V内核启动要求和限制 12*d78bcf64Slongjin======================== 13*d78bcf64Slongjin 14*d78bcf64Slongjin:Author: Alexandre Ghiti <alexghiti@rivosinc.com> 15*d78bcf64Slongjin:Date: 23 May 2023 16*d78bcf64Slongjin 17*d78bcf64Slongjin这份文档描述了RISC-V内核对引导加载程序和固件的期望,以及任何开发者在接触 18*d78bcf64Slongjin早期启动过程时必须牢记的约束。在这份文档中, ``早期启动过程`` 指的是在最 19*d78bcf64Slongjin终虚拟映射设置之前运行的任何代码。 20*d78bcf64Slongjin 21*d78bcf64Slongjin内核预加载的要求和限制 22*d78bcf64Slongjin====================== 23*d78bcf64Slongjin 24*d78bcf64SlongjinRISC-V内核对引导加载程序和平台固件有以下要求: 25*d78bcf64Slongjin 26*d78bcf64Slongjin寄存器状态 27*d78bcf64Slongjin---------- 28*d78bcf64Slongjin 29*d78bcf64SlongjinRISC-V内核期望: 30*d78bcf64Slongjin 31*d78bcf64Slongjin * ``$a0`` 应包含当前核心的hartid。 32*d78bcf64Slongjin * ``$a1`` 应包含内存中设备树的地址。 33*d78bcf64Slongjin 34*d78bcf64SlongjinCSR 寄存器状态 35*d78bcf64Slongjin-------------- 36*d78bcf64Slongjin 37*d78bcf64SlongjinRISC-V内核期望: 38*d78bcf64Slongjin 39*d78bcf64Slongjin * ``$satp = 0``: 如果存在MMU,必须将其禁用。 40*d78bcf64Slongjin 41*d78bcf64Slongjin为常驻固件保留的内存 42*d78bcf64Slongjin-------------------- 43*d78bcf64Slongjin 44*d78bcf64SlongjinRISC-V内核在直接映射中不能映射任何常驻内存或用PMPs保护的内存, 45*d78bcf64Slongjin因此固件必须根据设备树规范 和/或 UEFI规范正确标记这些区域。 46*d78bcf64Slongjin 47*d78bcf64Slongjin内核的位置 48*d78bcf64Slongjin---------- 49*d78bcf64Slongjin 50*d78bcf64SlongjinRISC-V内核期望被放置在PMD边界(对于rv64为2MB对齐,对于rv32为4MB对齐)。 51*d78bcf64Slongjin请注意,如果不是这样,EFI stub 将重定位内核。 52*d78bcf64Slongjin 53*d78bcf64Slongjin硬件描述 54*d78bcf64Slongjin-------- 55*d78bcf64Slongjin 56*d78bcf64Slongjin固件可以将设备树或ACPI表传递给RISC-V内核。 57*d78bcf64Slongjin 58*d78bcf64Slongjin设备树可以直接从前一阶段通过$a1寄存器传递给内核,或者在使用UEFI启动时, 59*d78bcf64Slongjin可以通过EFI配置表传递。 60*d78bcf64Slongjin 61*d78bcf64SlongjinACPI表通过EFI配置表传递给内核。在这种情况下,EFI stub 仍然会创建一个 62*d78bcf64Slongjin小的设备树。请参阅下面的"EFI stub 和设备树"部分,了解这个设备树的详细 63*d78bcf64Slongjin信息。 64*d78bcf64Slongjin 65*d78bcf64Slongjin内核入口 66*d78bcf64Slongjin-------- 67*d78bcf64Slongjin 68*d78bcf64Slongjin在SMP系统中,有两种方法可以进入内核: 69*d78bcf64Slongjin 70*d78bcf64Slongjin- ``RISCV_BOOT_SPINWAIT``:固件在内核中释放所有的hart,一个hart赢 71*d78bcf64Slongjin 得抽奖并执行早期启动代码,而其他的hart则停在那里等待初始化完成。这种 72*d78bcf64Slongjin 方法主要用于支持没有SBI HSM扩展和M模式RISC-V内核的旧固件。 73*d78bcf64Slongjin- ``有序启动``:固件只释放一个将执行初始化阶段的hart,然后使用SBI HSM 74*d78bcf64Slongjin 扩展启动所有其他的hart。有序启动方法是启动RISC-V内核的首选启动方法, 75*d78bcf64Slongjin 因为它可以支持CPU热插拔和kexec。 76*d78bcf64Slongjin 77*d78bcf64SlongjinUEFI 78*d78bcf64Slongjin---- 79*d78bcf64Slongjin 80*d78bcf64SlongjinUEFI 内存映射 81*d78bcf64Slongjin~~~~~~~~~~~~~ 82*d78bcf64Slongjin 83*d78bcf64Slongjin使用UEFI启动时,RISC-V内核将只使用EFI内存映射来填充系统内存。 84*d78bcf64Slongjin 85*d78bcf64SlongjinUEFI固件必须解析 ``/reserved-memory`` 设备树节点的子节点,并遵守设备 86*d78bcf64Slongjin树规范,将这些子节点的属性( ``no-map`` 和 ``reusable`` )转换为其正 87*d78bcf64Slongjin确的EFI等价物(参见设备树规范v0.4-rc1的"3.5.4/reserved-memory和 88*d78bcf64SlongjinUEFI"部分)。 89*d78bcf64Slongjin 90*d78bcf64SlongjinRISCV_EFI_BOOT_PROTOCOL 91*d78bcf64Slongjin~~~~~~~~~~~~~~~~~~~~~~~ 92*d78bcf64Slongjin 93*d78bcf64Slongjin使用UEFI启动时,EFI stub 需要引导hartid以便将其传递给 ``$a1`` 中的 94*d78bcf64SlongjinRISC-V内核。EFI stub使用以下方法之一获取引导hartid: 95*d78bcf64Slongjin 96*d78bcf64Slongjin- ``RISCV_EFI_BOOT_PROTOCOL`` (**首选**)。 97*d78bcf64Slongjin- ``boot-hartid`` 设备树子节点(**已弃用**)。 98*d78bcf64Slongjin 99*d78bcf64Slongjin任何新的固件都必须实现 ``RISCV_EFI_BOOT_PROTOCOL``,因为基于设备树 100*d78bcf64Slongjin的方法现已被弃用。 101*d78bcf64Slongjin 102*d78bcf64Slongjin早期启动的要求和约束 103*d78bcf64Slongjin==================== 104*d78bcf64Slongjin 105*d78bcf64SlongjinRISC-V内核的早期启动过程遵循以下约束: 106*d78bcf64Slongjin 107*d78bcf64SlongjinEFI stub 和设备树 108*d78bcf64Slongjin----------------- 109*d78bcf64Slongjin 110*d78bcf64Slongjin使用UEFI启动时,EFI stub 会用与arm64相同的参数补充(或创建)设备树, 111*d78bcf64Slongjin这些参数在Documentation/arch/arm/uefi.rst中的 112*d78bcf64Slongjin"UEFI kernel supporton ARM"段落中有描述。 113*d78bcf64Slongjin 114*d78bcf64Slongjin虚拟映射安装 115*d78bcf64Slongjin------------ 116*d78bcf64Slongjin 117*d78bcf64Slongjin在RISC-V内核中,虚拟映射的安装分为两步进行: 118*d78bcf64Slongjin 119*d78bcf64Slongjin1. ``setup_vm()`` 在 ``early_pg_dir`` 中安装一个临时的内核映射,这 120*d78bcf64Slongjin 允许发现系统内存。 此时只有内核文本/数据被映射。在建立这个映射时, 121*d78bcf64Slongjin 不能进行分配(因为系统内存还未知),所以``early_pg_dir``页表是静 122*d78bcf64Slongjin 态分配的(每个级别只使用一个表)。 123*d78bcf64Slongjin 124*d78bcf64Slongjin2. ``setup_vm_final()`` 在 ``swapper_pg_dir`` 中创建最终的内核映 125*d78bcf64Slongjin 射,并利用发现的系统内存 创建线性映射。在建立这个映射时,内核可以 126*d78bcf64Slongjin 分配内存,但不能直接访问它(因为直接映射还不存在),所以它使用fixmap 127*d78bcf64Slongjin 区域的临时映射来访问新分配的页表级别。 128*d78bcf64Slongjin 129*d78bcf64Slongjin为了让 ``virt_to_phys()`` 和 ``phys_to_virt()`` 能够正确地将直接 130*d78bcf64Slongjin映射地址转换为物理地址,它们需要知道DRAM的起始位置。这发生在步骤1之后, 131*d78bcf64Slongjin就在步骤2安装直接映射之前(参见arch/riscv/mm/init.c中的 132*d78bcf64Slongjin``setup_bootmem()`` 函数)。在安装最终虚拟映射之前使用这些宏时必须 133*d78bcf64Slongjin仔细检查。 134*d78bcf64Slongjin 135*d78bcf64Slongjin通过fixmap进行设备树映射 136*d78bcf64Slongjin------------------------ 137*d78bcf64Slongjin 138*d78bcf64Slongjin由于 ``reserved_mem`` 数组是用 ``setup_vm()`` 建立的虚拟地址初始化 139*d78bcf64Slongjin的,并且与``setup_vm_final()``建立的映射一起使用,RISC-V内核使用 140*d78bcf64Slongjinfixmap区域来映射设备树。这确保设备树可以通过两种虚拟映射访问。 141*d78bcf64Slongjin 142*d78bcf64SlongjinPre-MMU执行 143*d78bcf64Slongjin----------- 144*d78bcf64Slongjin 145*d78bcf64Slongjin在建立第一个虚拟映射之前,需要运行一些代码。这些包括第一个虚拟映射的安装本身, 146*d78bcf64Slongjin早期替代方案的修补,以及内核命令行的早期解析。这些代码必须非常小心地编译,因为: 147*d78bcf64Slongjin 148*d78bcf64Slongjin- ``-fno-pie``:这对于使用``-fPIE``的可重定位内核是必需的,否则,任何对 149*d78bcf64Slongjin 全局符号的访问都将通过 GOT进行,而GOT只是虚拟地重新定位。 150*d78bcf64Slongjin- ``-mcmodel=medany``:任何对全局符号的访问都必须是PC相对的,以避免在设 151*d78bcf64Slongjin 置MMU之前发生任何重定位。 152*d78bcf64Slongjin- *所有* 的仪表化功能也必须被禁用(包括KASAN,ftrace和其他)。 153*d78bcf64Slongjin 154*d78bcf64Slongjin由于使用来自不同编译单元的符号需要用这些标志编译该单元,我们建议尽可能不要使用 155*d78bcf64Slongjin外部符号。 156