← Documents Documentation/arch/riscv/boot.rst GitHub 원문 ↗

Linux 6.18.37 · Architecture

RISC-V Kernel Boot Requirements and Constraints

RISC-V kernel 진입 register, firmware memory, SMP·UEFI boot와 early mapping 제약입니다.

Source pathDocumentation/arch/riscv/boot.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약과 해설

boot.rst:1-169

Kernel entry 전 `$a0`, `$a1`, `$satp` 상태와 PMD alignment가 맞아야 합니다. Early boot는 `setup_vm()`의 static temporary mapping에서 memory를 발견한 뒤 `setup_vm_final()`의 final linear mapping으로 전환하며, 그 전 code는 PIE·code model·instrumentation 제약을 지켜야 합니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 ===============================================
4 RISC-V Kernel Boot Requirements and Constraints
5 ===============================================
6
7 :Author: Alexandre Ghiti <alexghiti@rivosinc.com>
8 :Date: 23 May 2023
9
10 This document describes what the RISC-V kernel expects from bootloaders and
11 firmware, and also the constraints that any developer must have in mind when
12 touching the early boot process. For the purposes of this document, the
13 ``early boot process`` refers to any code that runs before the final virtual
14 mapping is set up.
15
16 Pre-kernel Requirements and Constraints
17 =======================================
18
19 The RISC-V kernel expects the following of bootloaders and platform firmware:
20
21 Register state
22 --------------
23
24 The RISC-V kernel expects:
25
26 * ``$a0`` to contain the hartid of the current core.
27 * ``$a1`` to contain the address of the devicetree in memory.
28
29 CSR state
30 ---------
31
32 The RISC-V kernel expects:
33
34 * ``$satp = 0``: the MMU, if present, must be disabled.
35
36 Reserved memory for resident firmware
37 -------------------------------------
38
39 The RISC-V kernel must not map any resident memory, or memory protected with
40 PMPs, in the direct mapping, so the firmware must correctly mark those regions
41 as per the devicetree specification and/or the UEFI specification.
42
43 Kernel location
44 ---------------
45
46 The RISC-V kernel expects to be placed at a PMD boundary (2MB aligned for rv64
47 and 4MB aligned for rv32). Note that the EFI stub will physically relocate the
48 kernel if that's not the case.
49
50 Hardware description
51 --------------------
52
53 The firmware can pass either a devicetree or ACPI tables to the RISC-V kernel.
54
55 The devicetree is either passed directly to the kernel from the previous stage
56 using the ``$a1`` register, or when booting with UEFI, it can be passed using the
57 EFI configuration table.
58
59 The ACPI tables are passed to the kernel using the EFI configuration table. In
60 this case, a tiny devicetree is still created by the EFI stub. Please refer to
61 "EFI stub and devicetree" section below for details about this devicetree.
62
63 Kernel entry
64 ------------
65
66 On SMP systems, there are 2 methods to enter the kernel:
67
68 - ``RISCV_BOOT_SPINWAIT``: the firmware releases all harts in the kernel, one hart
69 wins a lottery and executes the early boot code while the other harts are
70 parked waiting for the initialization to finish. This method is mostly used to
71 support older firmwares without SBI HSM extension and M-mode RISC-V kernel.
72 - ``Ordered booting``: the firmware releases only one hart that will execute the
73 initialization phase and then will start all other harts using the SBI HSM
74 extension. The ordered booting method is the preferred booting method for
75 booting the RISC-V kernel because it can support CPU hotplug and kexec.
76
77 UEFI
78 ----
79
80 UEFI memory map
81 ~~~~~~~~~~~~~~~
82
83 When booting with UEFI, the RISC-V kernel will use only the EFI memory map to
84 populate the system memory.
85
86 The UEFI firmware must parse the subnodes of the ``/reserved-memory`` devicetree
87 node and abide by the devicetree specification to convert the attributes of
88 those subnodes (``no-map`` and ``reusable``) into their correct EFI equivalent
89 (refer to section "3.5.4 /reserved-memory and UEFI" of the devicetree
90 specification v0.4-rc1).
91
92 RISCV_EFI_BOOT_PROTOCOL
93 ~~~~~~~~~~~~~~~~~~~~~~~
94
95 When booting with UEFI, the EFI stub requires the boot hartid in order to pass
96 it to the RISC-V kernel in ``$a1``. The EFI stub retrieves the boot hartid using
97 one of the following methods:
98
99 - ``RISCV_EFI_BOOT_PROTOCOL`` (**preferred**).
100 - ``boot-hartid`` devicetree subnode (**deprecated**).
101
102 Any new firmware must implement ``RISCV_EFI_BOOT_PROTOCOL`` as the devicetree
103 based approach is deprecated now.
104
105 Early Boot Requirements and Constraints
106 =======================================
107
108 The RISC-V kernel's early boot process operates under the following constraints:
109
110 EFI stub and devicetree
111 -----------------------
112
113 When booting with UEFI, the devicetree is supplemented (or created) by the EFI
114 stub with the same parameters as arm64 which are described at the paragraph
115 "UEFI kernel support on ARM" in Documentation/arch/arm/uefi.rst.
116
117 Virtual mapping installation
118 ----------------------------
119
120 The installation of the virtual mapping is done in 2 steps in the RISC-V kernel:
121
122 1. ``setup_vm()`` installs a temporary kernel mapping in ``early_pg_dir`` which
123 allows discovery of the system memory. Only the kernel text/data are mapped
124 at this point. When establishing this mapping, no allocation can be done
125 (since the system memory is not known yet), so ``early_pg_dir`` page table is
126 statically allocated (using only one table for each level).
127
128 2. ``setup_vm_final()`` creates the final kernel mapping in ``swapper_pg_dir``
129 and takes advantage of the discovered system memory to create the linear
130 mapping. When establishing this mapping, the kernel can allocate memory but
131 cannot access it directly (since the direct mapping is not present yet), so
132 it uses temporary mappings in the fixmap region to be able to access the
133 newly allocated page table levels.
134
135 For ``virt_to_phys()`` and ``phys_to_virt()`` to be able to correctly convert
136 direct mapping addresses to physical addresses, they need to know the start of
137 the DRAM. This happens after step 1, right before step 2 installs the direct
138 mapping (see ``setup_bootmem()`` function in arch/riscv/mm/init.c). Any usage of
139 those macros before the final virtual mapping is installed must be carefully
140 examined.
141
142 Devicetree mapping via fixmap
143 -----------------------------
144
145 As the ``reserved_mem`` array is initialized with virtual addresses established
146 by ``setup_vm()``, and used with the mapping established by
147 ``setup_vm_final()``, the RISC-V kernel uses the fixmap region to map the
148 devicetree. This ensures that the devicetree remains accessible by both virtual
149 mappings.
150
151 Pre-MMU execution
152 -----------------
153
154 A few pieces of code need to run before even the first virtual mapping is
155 established. These are the installation of the first virtual mapping itself,
156 patching of early alternatives and the early parsing of the kernel command line.
157 That code must be very carefully compiled as:
158
159 - ``-fno-pie``: This is needed for relocatable kernels which use ``-fPIE``,
160 since otherwise, any access to a global symbol would go through the GOT which
161 is only relocated virtually.
162 - ``-mcmodel=medany``: Any access to a global symbol must be PC-relative to
163 avoid any relocations to happen before the MMU is setup.
164 - *all* instrumentation must also be disabled (that includes KASAN, ftrace and
165 others).
166
167 As using a symbol from a different compilation unit requires this unit to be
168 compiled with those flags, we advise, as much as possible, not to use external
169 symbols.
170

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

RISC-V kernel boot 요구사항

1-15

Alexandre Ghiti가 2023-05-23 작성한 이 문서는 RISC-V kernel이 bootloader와 firmware에 요구하는 상태, 그리고 final virtual mapping이 만들어지기 전 `early boot process`를 수정할 때 지켜야 할 제약을 설명합니다.

Pre-kernel register state

16-28

RISC-V kernel 진입 시 register는 다음 상태여야 합니다.

  • `$a0`: 현재 core의 hartid
  • `$a1`: memory에 있는 devicetree의 address

CSR와 resident firmware memory

29-41

`$satp = 0`이어야 하며 MMU가 존재한다면 disable된 상태여야 합니다.

Kernel은 resident firmware memory나 PMP로 보호된 memory를 direct mapping에 포함하면 안 됩니다. Firmware는 devicetree specification 또는 UEFI specification에 따라 해당 영역을 정확히 표시해야 합니다.

Kernel 위치와 hardware description

42-61

Kernel은 PMD boundary에 배치되어야 합니다. Alignment는 rv64에서 2MB, rv32에서 4MB이며, 맞지 않으면 EFI stub이 kernel을 물리적으로 relocate합니다.

Firmware는 devicetree 또는 ACPI table을 kernel에 전달할 수 있습니다. Devicetree는 이전 stage가 `$a1` register로 직접 넘기거나, UEFI boot에서는 EFI configuration table로 전달합니다.

ACPI table도 EFI configuration table로 전달됩니다. 이 경우에도 EFI stub이 작은 devicetree를 만들며 자세한 내용은 아래 EFI stub section에 있습니다.

RISC-V boot hardware description
Previous stage`$a1`DevicetreeKernel
UEFIEFI configuration tableDevicetree 또는 ACPIKernel

Boot 방식에 따라 hardware description이 kernel에 도달하는 경로입니다.

SMP kernel entry

62-75

SMP system에는 두 가지 kernel entry 방식이 있습니다.

  • `RISCV_BOOT_SPINWAIT`: firmware가 모든 hart를 kernel로 release하고 한 hart가 lottery에서 이겨 early boot code를 실행합니다. 나머지는 initialization이 끝날 때까지 parked 상태로 기다립니다. SBI HSM extension이 없는 이전 firmware와 M-mode kernel을 주로 지원합니다.
  • `Ordered booting`: firmware가 initialization을 수행할 hart 하나만 release하고, 그 hart가 SBI HSM extension으로 나머지를 시작합니다. CPU hotplug와 kexec를 지원하므로 권장 방식입니다.

UEFI memory map

76-90

UEFI로 boot할 때 RISC-V kernel은 EFI memory map만 사용해 system memory를 구성합니다.

UEFI firmware는 devicetree의 `/reserved-memory` subnode를 parsing하고 devicetree specification에 따라 `no-map`과 `reusable` attribute를 올바른 EFI equivalent로 변환해야 합니다. 기준은 devicetree specification v0.4-rc1의 `3.5.4 /reserved-memory and UEFI` section입니다.

RISCV_EFI_BOOT_PROTOCOL

91-103

UEFI boot에서 EFI stub은 boot hartid를 RISC-V kernel의 `$a1`에 전달하기 위해 이 값을 알아야 합니다. `RISCV_EFI_BOOT_PROTOCOL`을 사용하는 방법이 권장되며, devicetree의 `boot-hartid` subnode를 사용하는 방법은 deprecated입니다.

새 firmware는 deprecated된 devicetree 방식 대신 반드시 `RISCV_EFI_BOOT_PROTOCOL`을 구현해야 합니다.

Early boot와 EFI stub devicetree

104-116

RISC-V early boot는 final virtual mapping이 생기기 전의 제약 아래 동작합니다.

UEFI boot에서는 EFI stub이 devicetree를 보완하거나 새로 만듭니다. Parameter는 `Documentation/arch/arm/uefi.rst`의 `UEFI kernel support on ARM` 문단에 설명된 arm64와 같습니다.

두 단계 virtual mapping 설치

117-140

RISC-V kernel은 virtual mapping을 두 단계로 설치합니다.

  • `setup_vm()`은 `early_pg_dir`에 임시 kernel mapping을 만들고 system memory를 발견할 수 있게 합니다. 이때는 kernel text/data만 mapping합니다. Memory를 아직 알 수 없어 allocation할 수 없으므로 각 level에 table 하나만 쓰는 page table을 정적으로 할당합니다.
  • `setup_vm_final()`은 발견한 system memory를 이용해 `swapper_pg_dir`에 final kernel mapping과 linear mapping을 만듭니다. Memory allocation은 가능하지만 direct mapping이 아직 없어 직접 접근할 수 없으므로 fixmap의 임시 mapping으로 새 page-table level에 접근합니다.

`virt_to_phys()`와 `phys_to_virt()`가 direct-mapping address와 physical address를 정확히 변환하려면 DRAM 시작 주소가 필요합니다. 이는 1단계 뒤, `arch/riscv/mm/init.c`의 `setup_bootmem()`에서 2단계 direct mapping을 설치하기 직전에 알려집니다. Final mapping 전 macro 사용은 신중히 검토해야 합니다.

RISC-V virtual mapping 설치
`setup_vm()``early_pg_dir`Kernel text/data 임시 mappingSystem memory discovery
`setup_vm_final()`Fixmap으로 새 tables 접근`swapper_pg_dir`Final linear mapping

Memory discovery와 final direct mapping 사이의 두 단계를 나타냅니다.

Fixmap을 통한 devicetree mapping

141-149

`reserved_mem` array는 `setup_vm()` mapping에서 만든 virtual address로 초기화되고 `setup_vm_final()` mapping에서도 사용됩니다. 두 mapping 모두에서 devicetree에 접근할 수 있도록 kernel은 fixmap region에 devicetree를 mapping합니다.

Pre-MMU code 제약

150-169

첫 virtual mapping 설치, early alternative patching, kernel command-line early parsing은 첫 mapping보다 먼저 실행되어야 합니다.

  • `-fno-pie`: relocatable kernel이 `-fPIE`를 사용하더라도 global symbol access가 virtual relocation 전의 GOT를 통하지 않게 합니다.
  • `-mcmodel=medany`: MMU setup 전에 relocation이 필요하지 않도록 global symbol access를 PC-relative로 만듭니다.
  • KASAN, ftrace를 포함한 모든 instrumentation을 disable해야 합니다.

다른 compilation unit의 symbol을 사용하려면 그 unit도 같은 flag로 compile해야 하므로, 가능한 한 external symbol을 사용하지 않는 것이 권장됩니다.