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