요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
=====================
Booting AArch64 Linux
=====================
Author: Will Deacon <[email protected]>
Date : 07 September 2012
This document is based on the ARM booting document by Russell King and
is relevant to all public releases of the AArch64 Linux kernel.
The AArch64 exception model is made up of a number of exception levels
(EL0 - EL3), with EL0, EL1 and EL2 having a secure and a non-secure
counterpart. EL2 is the hypervisor level, EL3 is the highest priority
level and exists only in secure mode. Both are architecturally optional.
For the purposes of this document, we will use the term `boot loader`
simply to define all software that executes on the CPU(s) before control
is passed to the Linux kernel. This may include secure monitor and
hypervisor code, or it may just be a handful of instructions for
preparing a minimal boot environment.
Essentially, the boot loader should provide (as a minimum) the
following:
1. Setup and initialise the RAM
2. Setup the device tree
3. Decompress the kernel image
4. Call the kernel image
1. Setup and initialise RAM
---------------------------
Requirement: MANDATORY
The boot loader is expected to find and initialise all RAM that the
kernel will use for volatile data storage in the system. It performs
this in a machine dependent manner. (It may use internal algorithms
to automatically locate and size all RAM, or it may use knowledge of
the RAM in the machine, or any other method the boot loader designer
sees fit.)
For Arm Confidential Compute Realms this includes ensuring that all
protected RAM has a Realm IPA state (RIPAS) of "RAM".
2. Setup the device tree
-------------------------
Requirement: MANDATORY
The device tree blob (dtb) must be placed on an 8-byte boundary and must
not exceed 2 megabytes in size. Since the dtb will be mapped cacheable
using blocks of up to 2 megabytes in size, it must not be placed within
any 2M region which must be mapped with any specific attributes.
NOTE: versions prior to v4.2 also require that the DTB be placed within
the 512 MB region starting at text_offset bytes below the kernel Image.
3. Decompress the kernel image
------------------------------
Requirement: OPTIONAL
The AArch64 kernel does not currently provide a decompressor and
therefore requires decompression (gzip etc.) to be performed by the boot
loader if a compressed Image target (e.g. Image.gz) is used. For
bootloaders that do not implement this requirement, the uncompressed
Image target is available instead.
4. Call the kernel image
------------------------
Requirement: MANDATORY
The decompressed kernel image contains a 64-byte header as follows::
u32 code0; /* Executable code */
u32 code1; /* Executable code */
u64 text_offset; /* Image load offset, little endian */
u64 image_size; /* Effective Image size, little endian */
u64 flags; /* kernel flags, little endian */
u64 res2 = 0; /* reserved */
u64 res3 = 0; /* reserved */
u64 res4 = 0; /* reserved */
u32 magic = 0x644d5241; /* Magic number, little endian, "ARM\x64" */
u32 res5; /* reserved (used for PE COFF offset) */
Header notes:
- As of v3.17, all fields are little endian unless stated otherwise.
- code0/code1 are responsible for branching to stext.
- when booting through EFI, code0/code1 are initially skipped.
res5 is an offset to the PE header and the PE header has the EFI
entry point (efi_stub_entry). When the stub has done its work, it
jumps to code0 to resume the normal boot process.
- Prior to v3.17, the endianness of text_offset was not specified. In
these cases image_size is zero and text_offset is 0x80000 in the
endianness of the kernel. Where image_size is non-zero image_size is
little-endian and must be respected. Where image_size is zero,
text_offset can be assumed to be 0x80000.
- The flags field (introduced in v3.17) is a little-endian 64-bit field
composed as follows:
============= ===============================================================
Bit 0 Kernel endianness. 1 if BE, 0 if LE.
Bit 1-2 Kernel Page size.
* 0 - Unspecified.
* 1 - 4K
* 2 - 16K
* 3 - 64K
Bit 3 Kernel physical placement
0
2MB aligned base should be as close as possible
to the base of DRAM, since memory below it is not
accessible via the linear mapping
1
2MB aligned base such that all image_size bytes
counted from the start of the image are within
the 48-bit addressable range of physical memory
Bits 4-63 Reserved.
============= ===============================================================
- When image_size is zero, a bootloader should attempt to keep as much
memory as possible free for use by the kernel immediately after the
end of the kernel image. The amount of space required will vary
depending on selected features, and is effectively unbound.
The Image must be placed text_offset bytes from a 2MB aligned base
address anywhere in usable system RAM and called there. The region
between the 2 MB aligned base address and the start of the image has no
special significance to the kernel, and may be used for other purposes.
At least image_size bytes from the start of the image must be free for
use by the kernel.
NOTE: versions prior to v4.6 cannot make use of memory below the
physical offset of the Image so it is recommended that the Image be
placed as close as possible to the start of system RAM.
If an initrd/initramfs is passed to the kernel at boot, it must reside
entirely within a 1 GB aligned physical memory window of up to 32 GB in
size that fully covers the kernel Image as well.
Any memory described to the kernel (even that below the start of the
image) which is not marked as reserved from the kernel (e.g., with a
memreserve region in the device tree) will be considered as available to
the kernel.
Before jumping into the kernel, the following conditions must be met:
- Quiesce all DMA capable devices so that memory does not get
corrupted by bogus network packets or disk data. This will save
you many hours of debug.
- Primary CPU general-purpose register settings:
- x0 = physical address of device tree blob (dtb) in system RAM.
- x1 = 0 (reserved for future use)
- x2 = 0 (reserved for future use)
- x3 = 0 (reserved for future use)
- CPU mode
All forms of interrupts must be masked in PSTATE.DAIF (Debug, SError,
IRQ and FIQ).
The CPU must be in non-secure state, either in EL2 (RECOMMENDED in order
to have access to the virtualisation extensions), or in EL1.
- Caches, MMUs
The MMU must be off.
The instruction cache may be on or off, and must not hold any stale
entries corresponding to the loaded kernel image.
The address range corresponding to the loaded kernel image must be
cleaned to the PoC. In the presence of a system cache or other
coherent masters with caches enabled, this will typically require
cache maintenance by VA rather than set/way operations.
System caches which respect the architected cache maintenance by VA
operations must be configured and may be enabled.
System caches which do not respect architected cache maintenance by VA
operations (not recommended) must be configured and disabled.
- Architected timers
CNTFRQ must be programmed with the timer frequency and CNTVOFF must
be programmed with a consistent value on all CPUs. If entering the
kernel at EL1, CNTHCTL_EL2 must have EL1PCTEN (bit 0) set where
available.
- Coherency
All CPUs to be booted by the kernel must be part of the same coherency
domain on entry to the kernel. This may require IMPLEMENTATION DEFINED
initialisation to enable the receiving of maintenance operations on
each CPU.
- System registers
All writable architected system registers at or below the exception
level where the kernel image will be entered must be initialised by
software at a higher exception level to prevent execution in an UNKNOWN
state.
For all systems:
- If EL3 is present:
- SCR_EL3.FIQ must have the same value across all CPUs the kernel is
executing on.
- The value of SCR_EL3.FIQ must be the same as the one present at boot
time whenever the kernel is executing.
- If EL3 is present and the kernel is entered at EL2:
- SCR_EL3.HCE (bit 8) must be initialised to 0b1.
For systems with a GICv5 interrupt controller to be used in v5 mode:
- If the kernel is entered at EL1 and EL2 is present:
- ICH_HFGRTR_EL2.ICC_PPI_ACTIVERn_EL1 (bit 20) must be initialised to 0b1.
- ICH_HFGRTR_EL2.ICC_PPI_PRIORITYRn_EL1 (bit 19) must be initialised to 0b1.
- ICH_HFGRTR_EL2.ICC_PPI_PENDRn_EL1 (bit 18) must be initialised to 0b1.
- ICH_HFGRTR_EL2.ICC_PPI_ENABLERn_EL1 (bit 17) must be initialised to 0b1.
- ICH_HFGRTR_EL2.ICC_PPI_HMRn_EL1 (bit 16) must be initialised to 0b1.
- ICH_HFGRTR_EL2.ICC_IAFFIDR_EL1 (bit 7) must be initialised to 0b1.
- ICH_HFGRTR_EL2.ICC_ICSR_EL1 (bit 6) must be initialised to 0b1.
- ICH_HFGRTR_EL2.ICC_PCR_EL1 (bit 5) must be initialised to 0b1.
- ICH_HFGRTR_EL2.ICC_HPPIR_EL1 (bit 4) must be initialised to 0b1.
- ICH_HFGRTR_EL2.ICC_HAPR_EL1 (bit 3) must be initialised to 0b1.
- ICH_HFGRTR_EL2.ICC_CR0_EL1 (bit 2) must be initialised to 0b1.
- ICH_HFGRTR_EL2.ICC_IDRn_EL1 (bit 1) must be initialised to 0b1.
- ICH_HFGRTR_EL2.ICC_APR_EL1 (bit 0) must be initialised to 0b1.
- ICH_HFGWTR_EL2.ICC_PPI_ACTIVERn_EL1 (bit 20) must be initialised to 0b1.
- ICH_HFGWTR_EL2.ICC_PPI_PRIORITYRn_EL1 (bit 19) must be initialised to 0b1.
- ICH_HFGWTR_EL2.ICC_PPI_PENDRn_EL1 (bit 18) must be initialised to 0b1.
- ICH_HFGWTR_EL2.ICC_PPI_ENABLERn_EL1 (bit 17) must be initialised to 0b1.
- ICH_HFGWTR_EL2.ICC_ICSR_EL1 (bit 6) must be initialised to 0b1.
- ICH_HFGWTR_EL2.ICC_PCR_EL1 (bit 5) must be initialised to 0b1.
- ICH_HFGWTR_EL2.ICC_CR0_EL1 (bit 2) must be initialised to 0b1.
- ICH_HFGWTR_EL2.ICC_APR_EL1 (bit 0) must be initialised to 0b1.
- ICH_HFGITR_EL2.GICRCDNMIA (bit 10) must be initialised to 0b1.
- ICH_HFGITR_EL2.GICRCDIA (bit 9) must be initialised to 0b1.
- ICH_HFGITR_EL2.GICCDDI (bit 8) must be initialised to 0b1.
- ICH_HFGITR_EL2.GICCDEOI (bit 7) must be initialised to 0b1.
- ICH_HFGITR_EL2.GICCDHM (bit 6) must be initialised to 0b1.
- ICH_HFGITR_EL2.GICCDRCFG (bit 5) must be initialised to 0b1.
- ICH_HFGITR_EL2.GICCDPEND (bit 4) must be initialised to 0b1.
- ICH_HFGITR_EL2.GICCDAFF (bit 3) must be initialised to 0b1.
- ICH_HFGITR_EL2.GICCDPRI (bit 2) must be initialised to 0b1.
- ICH_HFGITR_EL2.GICCDDIS (bit 1) must be initialised to 0b1.
- ICH_HFGITR_EL2.GICCDEN (bit 0) must be initialised to 0b1.
- The DT or ACPI tables must describe a GICv5 interrupt controller.
For systems with a GICv3 interrupt controller to be used in v3 mode:
- If EL3 is present:
- ICC_SRE_EL3.Enable (bit 3) must be initialised to 0b1.
- ICC_SRE_EL3.SRE (bit 0) must be initialised to 0b1.
- ICC_CTLR_EL3.PMHE (bit 6) must be set to the same value across
all CPUs the kernel is executing on, and must stay constant
for the lifetime of the kernel.
- If the kernel is entered at EL1:
- ICC_SRE_EL2.Enable (bit 3) must be initialised to 0b1
- ICC_SRE_EL2.SRE (bit 0) must be initialised to 0b1.
- The DT or ACPI tables must describe a GICv3 interrupt controller.
For systems with a GICv3 interrupt controller to be used in
compatibility (v2) mode:
- If EL3 is present:
ICC_SRE_EL3.SRE (bit 0) must be initialised to 0b0.
- If the kernel is entered at EL1:
ICC_SRE_EL2.SRE (bit 0) must be initialised to 0b0.
- The DT or ACPI tables must describe a GICv2 interrupt controller.
For CPUs with pointer authentication functionality:
- If EL3 is present:
- SCR_EL3.APK (bit 16) must be initialised to 0b1
- SCR_EL3.API (bit 17) must be initialised to 0b1
- If the kernel is entered at EL1:
- HCR_EL2.APK (bit 40) must be initialised to 0b1
- HCR_EL2.API (bit 41) must be initialised to 0b1
For CPUs with Activity Monitors Unit v1 (AMUv1) extension present:
- If EL3 is present:
- CPTR_EL3.TAM (bit 30) must be initialised to 0b0
- CPTR_EL2.TAM (bit 30) must be initialised to 0b0
- AMCNTENSET0_EL0 must be initialised to 0b1111
- AMCNTENSET1_EL0 must be initialised to a platform specific value
having 0b1 set for the corresponding bit for each of the auxiliary
counters present.
- If the kernel is entered at EL1:
- AMCNTENSET0_EL0 must be initialised to 0b1111
- AMCNTENSET1_EL0 must be initialised to a platform specific value
having 0b1 set for the corresponding bit for each of the auxiliary
counters present.
For CPUs with the Fine Grained Traps (FEAT_FGT) extension present:
- If EL3 is present and the kernel is entered at EL2:
- SCR_EL3.FGTEn (bit 27) must be initialised to 0b1.
For CPUs with the Fine Grained Traps 2 (FEAT_FGT2) extension present:
- If EL3 is present and the kernel is entered at EL2:
- SCR_EL3.FGTEn2 (bit 59) must be initialised to 0b1.
For CPUs with support for HCRX_EL2 (FEAT_HCX) present:
- If EL3 is present and the kernel is entered at EL2:
- SCR_EL3.HXEn (bit 38) must be initialised to 0b1.
For CPUs with Advanced SIMD and floating point support:
- If EL3 is present:
- CPTR_EL3.TFP (bit 10) must be initialised to 0b0.
- If EL2 is present and the kernel is entered at EL1:
- CPTR_EL2.TFP (bit 10) must be initialised to 0b0.
For CPUs with the Scalable Vector Extension (FEAT_SVE) present:
- if EL3 is present:
- CPTR_EL3.EZ (bit 8) must be initialised to 0b1.
- ZCR_EL3.LEN must be initialised to the same value for all CPUs the
kernel is executed on.
- If the kernel is entered at EL1 and EL2 is present:
- CPTR_EL2.TZ (bit 8) must be initialised to 0b0.
- CPTR_EL2.ZEN (bits 17:16) must be initialised to 0b11.
- ZCR_EL2.LEN must be initialised to the same value for all CPUs the
kernel will execute on.
For CPUs with the Scalable Matrix Extension (FEAT_SME):
- If EL3 is present:
- CPTR_EL3.ESM (bit 12) must be initialised to 0b1.
- SCR_EL3.EnTP2 (bit 41) must be initialised to 0b1.
- SMCR_EL3.LEN must be initialised to the same value for all CPUs the
kernel will execute on.
- If the kernel is entered at EL1 and EL2 is present:
- CPTR_EL2.TSM (bit 12) must be initialised to 0b0.
- CPTR_EL2.SMEN (bits 25:24) must be initialised to 0b11.
- SCTLR_EL2.EnTP2 (bit 60) must be initialised to 0b1.
- SMCR_EL2.LEN must be initialised to the same value for all CPUs the
kernel will execute on.
- HWFGRTR_EL2.nTPIDR2_EL0 (bit 55) must be initialised to 0b01.
- HWFGWTR_EL2.nTPIDR2_EL0 (bit 55) must be initialised to 0b01.
- HWFGRTR_EL2.nSMPRI_EL1 (bit 54) must be initialised to 0b01.
- HWFGWTR_EL2.nSMPRI_EL1 (bit 54) must be initialised to 0b01.
For CPUs with the Scalable Matrix Extension FA64 feature (FEAT_SME_FA64):
- If EL3 is present:
- SMCR_EL3.FA64 (bit 31) must be initialised to 0b1.
- If the kernel is entered at EL1 and EL2 is present:
- SMCR_EL2.FA64 (bit 31) must be initialised to 0b1.
For CPUs with the Memory Tagging Extension feature (FEAT_MTE2):
- If EL3 is present:
- SCR_EL3.ATA (bit 26) must be initialised to 0b1.
- If the kernel is entered at EL1 and EL2 is present:
- HCR_EL2.ATA (bit 56) must be initialised to 0b1.
For CPUs with the Scalable Matrix Extension version 2 (FEAT_SME2):
- If EL3 is present:
- SMCR_EL3.EZT0 (bit 30) must be initialised to 0b1.
- If the kernel is entered at EL1 and EL2 is present:
- SMCR_EL2.EZT0 (bit 30) must be initialised to 0b1.
For CPUs with the Branch Record Buffer Extension (FEAT_BRBE):
- If EL3 is present:
- MDCR_EL3.SBRBE (bits 33:32) must be initialised to 0b01 or 0b11.
- If the kernel is entered at EL1 and EL2 is present:
- BRBCR_EL2.CC (bit 3) must be initialised to 0b1.
- BRBCR_EL2.MPRED (bit 4) must be initialised to 0b1.
- HDFGRTR_EL2.nBRBDATA (bit 61) must be initialised to 0b1.
- HDFGRTR_EL2.nBRBCTL (bit 60) must be initialised to 0b1.
- HDFGRTR_EL2.nBRBIDR (bit 59) must be initialised to 0b1.
- HDFGWTR_EL2.nBRBDATA (bit 61) must be initialised to 0b1.
- HDFGWTR_EL2.nBRBCTL (bit 60) must be initialised to 0b1.
- HFGITR_EL2.nBRBIALL (bit 56) must be initialised to 0b1.
- HFGITR_EL2.nBRBINJ (bit 55) must be initialised to 0b1.
For CPUs with the Performance Monitors Extension (FEAT_PMUv3p9):
- If EL3 is present:
- MDCR_EL3.EnPM2 (bit 7) must be initialised to 0b1.
- If the kernel is entered at EL1 and EL2 is present:
- HDFGRTR2_EL2.nPMICNTR_EL0 (bit 2) must be initialised to 0b1.
- HDFGRTR2_EL2.nPMICFILTR_EL0 (bit 3) must be initialised to 0b1.
- HDFGRTR2_EL2.nPMUACR_EL1 (bit 4) must be initialised to 0b1.
- HDFGWTR2_EL2.nPMICNTR_EL0 (bit 2) must be initialised to 0b1.
- HDFGWTR2_EL2.nPMICFILTR_EL0 (bit 3) must be initialised to 0b1.
- HDFGWTR2_EL2.nPMUACR_EL1 (bit 4) must be initialised to 0b1.
For CPUs with SPE data source filtering (FEAT_SPE_FDS):
- If EL3 is present:
- MDCR_EL3.EnPMS3 (bit 42) must be initialised to 0b1.
- If the kernel is entered at EL1 and EL2 is present:
- HDFGRTR2_EL2.nPMSDSFR_EL1 (bit 19) must be initialised to 0b1.
- HDFGWTR2_EL2.nPMSDSFR_EL1 (bit 19) must be initialised to 0b1.
For CPUs with Memory Copy and Memory Set instructions (FEAT_MOPS):
- If the kernel is entered at EL1 and EL2 is present:
- HCRX_EL2.MSCEn (bit 11) must be initialised to 0b1.
- HCRX_EL2.MCE2 (bit 10) must be initialised to 0b1 and the hypervisor
must handle MOPS exceptions as described in :ref:`arm64_mops_hyp`.
For CPUs with the Extended Translation Control Register feature (FEAT_TCR2):
- If EL3 is present:
- SCR_EL3.TCR2En (bit 43) must be initialised to 0b1.
- If the kernel is entered at EL1 and EL2 is present:
- HCRX_EL2.TCR2En (bit 14) must be initialised to 0b1.
For CPUs with the Stage 1 Permission Indirection Extension feature (FEAT_S1PIE):
- If EL3 is present:
- SCR_EL3.PIEn (bit 45) must be initialised to 0b1.
- If the kernel is entered at EL1 and EL2 is present:
- HFGRTR_EL2.nPIR_EL1 (bit 58) must be initialised to 0b1.
- HFGWTR_EL2.nPIR_EL1 (bit 58) must be initialised to 0b1.
- HFGRTR_EL2.nPIRE0_EL1 (bit 57) must be initialised to 0b1.
- HFGRWR_EL2.nPIRE0_EL1 (bit 57) must be initialised to 0b1.
- For CPUs with Guarded Control Stacks (FEAT_GCS):
- GCSCR_EL1 must be initialised to 0.
- GCSCRE0_EL1 must be initialised to 0.
- If EL3 is present:
- SCR_EL3.GCSEn (bit 39) must be initialised to 0b1.
- If EL2 is present:
- GCSCR_EL2 must be initialised to 0.
- If the kernel is entered at EL1 and EL2 is present:
- HCRX_EL2.GCSEn must be initialised to 0b1.
- HFGITR_EL2.nGCSEPP (bit 59) must be initialised to 0b1.
- HFGITR_EL2.nGCSSTR_EL1 (bit 58) must be initialised to 0b1.
- HFGITR_EL2.nGCSPUSHM_EL1 (bit 57) must be initialised to 0b1.
- HFGRTR_EL2.nGCS_EL1 (bit 53) must be initialised to 0b1.
- HFGRTR_EL2.nGCS_EL0 (bit 52) must be initialised to 0b1.
- HFGWTR_EL2.nGCS_EL1 (bit 53) must be initialised to 0b1.
- HFGWTR_EL2.nGCS_EL0 (bit 52) must be initialised to 0b1.
- For CPUs with debug architecture i.e FEAT_Debugv8pN (all versions):
- If EL3 is present:
- MDCR_EL3.TDA (bit 9) must be initialized to 0b0
- For CPUs with FEAT_PMUv3:
- If EL3 is present:
- MDCR_EL3.TPM (bit 6) must be initialized to 0b0
The requirements described above for CPU mode, caches, MMUs, architected
timers, coherency and system registers apply to all CPUs. All CPUs must
enter the kernel in the same exception level. Where the values documented
disable traps it is permissible for these traps to be enabled so long as
those traps are handled transparently by higher exception levels as though
the values documented were set.
The boot loader is expected to enter the kernel on each CPU in the
following manner:
- The primary CPU must jump directly to the first instruction of the
kernel image. The device tree blob passed by this CPU must contain
an 'enable-method' property for each cpu node. The supported
enable-methods are described below.
It is expected that the bootloader will generate these device tree
properties and insert them into the blob prior to kernel entry.
- CPUs with a "spin-table" enable-method must have a 'cpu-release-addr'
property in their cpu node. This property identifies a
naturally-aligned 64-bit zero-initalised memory location.
These CPUs should spin outside of the kernel in a reserved area of
memory (communicated to the kernel by a /memreserve/ region in the
device tree) polling their cpu-release-addr location, which must be
contained in the reserved region. A wfe instruction may be inserted
to reduce the overhead of the busy-loop and a sev will be issued by
the primary CPU. When a read of the location pointed to by the
cpu-release-addr returns a non-zero value, the CPU must jump to this
value. The value will be written as a single 64-bit little-endian
value, so CPUs must convert the read value to their native endianness
before jumping to it.
- CPUs with a "psci" enable method should remain outside of
the kernel (i.e. outside of the regions of memory described to the
kernel in the memory node, or in a reserved area of memory described
to the kernel by a /memreserve/ region in the device tree). The
kernel will issue CPU_ON calls as described in ARM document number ARM
DEN 0022A ("Power State Coordination Interface System Software on ARM
processors") to bring CPUs into the kernel.
The device tree should contain a 'psci' node, as described in
Documentation/devicetree/bindings/arm/psci.yaml.
- Secondary CPU general-purpose register settings
- x0 = 0 (reserved for future use)
- x1 = 0 (reserved for future use)
- x2 = 0 (reserved for future use)
- x3 = 0 (reserved for future use)
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
AArch64 boot loader의 최소 책임
1-31문서 제목은 `Booting AArch64 Linux`, 작성자는 Will Deacon `<[email protected]>`, 날짜는 `07 September 2012`입니다. Russell King의 ARM booting 문서를 바탕으로 하며 AArch64 Linux kernel의 모든 공개 release에 적용됩니다.
AArch64 exception model은 EL0부터 EL3까지의 exception level로 이루어집니다. EL0, EL1, EL2에는 secure와 non-secure counterpart가 있습니다. EL2는 hypervisor level이고 EL3은 secure mode에만 존재하는 최고 priority level이며, 둘 다 architecture상 선택 사항입니다.
이 문서에서 boot loader는 Linux kernel에 제어권을 넘기기 전에 CPU에서 실행되는 모든 software를 뜻합니다. Secure monitor와 hypervisor code를 포함할 수도 있고 최소 boot 환경을 준비하는 몇 instruction뿐일 수도 있습니다.
Boot loader가 최소한 제공해야 할 작업은 다음 네 가지입니다.
- 1. RAM 설정과 초기화
- 2. Device tree 설정
- 3. Kernel image 압축 해제
- 4. Kernel image 호출
1. RAM 설정과 초기화
32-47요구 수준: MANDATORY
Boot loader는 kernel이 volatile data storage로 사용할 system RAM을 모두 찾아 초기화해야 합니다. RAM을 자동으로 찾고 크기를 재는 내부 algorithm, machine의 RAM 정보 또는 boot loader 설계자가 적절하다고 판단한 다른 machine-dependent 방법을 사용할 수 있습니다.
Arm Confidential Compute Realm에서는 모든 protected RAM의 Realm IPA state(RIPAS)가 `RAM`인지 보장하는 작업도 포함됩니다.
2. Device tree 설정
48-60요구 수준: MANDATORY
Device tree blob(dtb)은 8-byte boundary에 배치하고 크기는 2MB를 넘지 않아야 합니다. Dtb는 최대 2MB block으로 cacheable mapping되므로 특정 attribute로 map해야 하는 2M 영역 안에 배치해서는 안 됩니다.
v4.2 이전 version은 DTB가 kernel Image보다 `text_offset` byte 아래에서 시작하는 512MB 영역 안에 있어야 한다는 요구도 있습니다.
3. Kernel image 압축 해제
61-72요구 수준: OPTIONAL
AArch64 kernel은 현재 decompressor를 제공하지 않습니다. 따라서 `Image.gz` 같은 compressed Image target을 사용하면 boot loader가 gzip 등의 압축을 풀어야 합니다. 이 요구를 구현하지 않은 boot loader는 uncompressed `Image` target을 사용할 수 있습니다.
4. Kernel image header와 메모리 배치
73-156요구 수준: MANDATORY
압축을 푼 kernel image는 다음 64-byte header를 포함합니다.
u32 code0; /* Executable code */
u32 code1; /* Executable code */
u64 text_offset; /* Image load offset, little endian */
u64 image_size; /* Effective Image size, little endian */
u64 flags; /* kernel flags, little endian */
u64 res2 = 0; /* reserved */
u64 res3 = 0; /* reserved */
u64 res4 = 0; /* reserved */
u32 magic = 0x644d5241; /* Magic number, little endian, "ARM\x64" */
u32 res5; /* reserved (used for PE COFF offset) */
Header field의 해석 규칙은 다음과 같습니다.
- v3.17부터 별도 설명이 없는 모든 field는 little endian입니다.
- `code0`과 `code1`은 `stext`로 branch합니다.
- EFI로 boot하면 처음에 `code0`/`code1`을 건너뜁니다. `res5`는 PE header offset이고 PE header에는 EFI entry point인 `efi_stub_entry`가 있습니다. Stub이 작업을 마치면 `code0`로 jump해 정상 boot를 계속합니다.
- v3.17 이전에는 `text_offset` endianness가 정해져 있지 않습니다. 이 경우 `image_size`는 0이고 `text_offset`은 kernel endianness의 `0x80000`입니다. `image_size`가 0이 아니면 little endian 값을 반드시 따르고, 0이면 `text_offset`을 `0x80000`으로 가정할 수 있습니다.
v3.17에서 도입한 `flags`는 다음 bit layout을 가진 little-endian 64-bit field입니다.
| Bit | 의미 | 값 |
|---|---|---|
| 0 | Kernel endianness | `1`: BE, `0`: LE |
| 1-2 | Kernel page size | `0`: unspecified, `1`: 4K, `2`: 16K, `3`: 64K |
| 3 | Kernel physical placement | `0`: memory below base는 linear mapping으로 접근할 수 없으므로 2MB aligned base를 DRAM base에 최대한 가깝게 둡니다. `1`: image start에서 센 `image_size` byte 전체가 48-bit physical address range 안에 들도록 2MB aligned base를 선택합니다. |
| 4-63 | Reserved | 예약됨 |
`image_size`가 0이면 boot loader는 kernel image 끝 직후의 memory를 kernel이 쓸 수 있도록 가능한 한 많이 비워 두어야 합니다. 필요한 공간은 선택한 기능에 따라 달라지며 사실상 상한이 없습니다.
Image는 usable system RAM 안의 임의 2MB-aligned base에서 `text_offset` byte 떨어진 위치에 놓고 그 위치에서 호출해야 합니다. Aligned base와 image start 사이 영역은 kernel에 특별한 의미가 없어 다른 용도로 사용할 수 있습니다. Image start부터 최소 `image_size` byte는 kernel이 사용하도록 비워야 합니다.
v4.6 이전 version은 Image physical offset 아래의 memory를 사용할 수 없으므로 Image를 system RAM 시작점에 최대한 가깝게 두기를 권장합니다.
Boot 시 initrd/initramfs를 전달하면 kernel Image 전체도 함께 포함하는, 1GB-aligned이고 최대 32GB 크기인 physical memory window 안에 initrd/initramfs 전체가 들어가야 합니다.
Kernel에 설명된 memory는 image start 아래쪽이라도 DT `memreserve` 영역 등으로 reserved 표시하지 않으면 kernel이 사용 가능한 것으로 간주합니다.
Kernel 진입 전 공통 상태
157-213Kernel로 jump하기 전에 모든 DMA-capable device를 quiesce해 잘못된 network packet이나 disk data가 memory를 손상하지 않게 해야 합니다. 이 조치가 많은 debugging 시간을 줄여 줍니다.
| 항목 | 진입 조건 |
|---|---|
| Primary CPU general-purpose register | `x0` = system RAM에 있는 dtb의 physical address, `x1` = `0`, `x2` = `0`, `x3` = `0` |
| CPU mode | PSTATE.DAIF의 Debug, SError, IRQ, FIQ를 모두 mask합니다. CPU는 non-secure EL2, virtualisation extension 접근을 위해 권장되는 상태, 또는 EL1에 있어야 합니다. |
| MMU와 instruction cache | MMU는 꺼야 합니다. I-cache는 켜거나 꺼도 되지만 load한 kernel image에 대응하는 stale entry가 없어야 합니다. |
| Data/cache clean | Load한 kernel image address range를 PoC까지 clean합니다. System cache나 cache를 켠 coherent master가 있으면 보통 set/way가 아니라 VA 기반 maintenance가 필요합니다. |
| System cache | Architected cache maintenance by VA를 따르는 cache는 구성 후 켤 수 있습니다. 이를 따르지 않는 비권장 cache는 구성 후 꺼야 합니다. |
| Architected timer | `CNTFRQ`에 timer frequency를 설정하고 모든 CPU의 `CNTVOFF`를 일관된 값으로 설정합니다. EL1 진입이면 사용할 수 있는 `CNTHCTL_EL2.EL1PCTEN` bit 0을 설정합니다. |
| Coherency | Kernel이 boot할 모든 CPU는 진입 시 같은 coherency domain에 속해야 합니다. 각 CPU가 maintenance operation을 받게 하려면 IMPLEMENTATION DEFINED 초기화가 필요할 수 있습니다. |
| System register | Kernel 진입 exception level 이하의 writable architected system register는 상위 exception level software가 초기화해 UNKNOWN state 실행을 막아야 합니다. |
공통 EL3 조건과 GICv5
214-266EL3이 있으면 kernel이 실행되는 모든 CPU에서 `SCR_EL3.FIQ` 값이 같아야 하며 kernel 실행 중에는 boot 시 값과 같아야 합니다. EL3이 있고 kernel을 EL2로 진입시키면 `SCR_EL3.HCE` bit 8을 `0b1`로 초기화합니다.
GICv5 interrupt controller를 v5 mode로 사용하면서 kernel을 EL1에 진입시키고 EL2가 있으면 다음 field를 모두 `0b1`로 초기화합니다.
| 기능·조건 | Register field | Bit | 초기값·제약 |
|---|---|---|---|
| GICv5 EL1 read trap | `ICH_HFGRTR_EL2.ICC_PPI_ACTIVERn_EL1` | 20 | `0b1` |
| GICv5 EL1 read trap | `ICH_HFGRTR_EL2.ICC_PPI_PRIORITYRn_EL1` | 19 | `0b1` |
| GICv5 EL1 read trap | `ICH_HFGRTR_EL2.ICC_PPI_PENDRn_EL1` | 18 | `0b1` |
| GICv5 EL1 read trap | `ICH_HFGRTR_EL2.ICC_PPI_ENABLERn_EL1` | 17 | `0b1` |
| GICv5 EL1 read trap | `ICH_HFGRTR_EL2.ICC_PPI_HMRn_EL1` | 16 | `0b1` |
| GICv5 EL1 read trap | `ICH_HFGRTR_EL2.ICC_IAFFIDR_EL1` | 7 | `0b1` |
| GICv5 EL1 read trap | `ICH_HFGRTR_EL2.ICC_ICSR_EL1` | 6 | `0b1` |
| GICv5 EL1 read trap | `ICH_HFGRTR_EL2.ICC_PCR_EL1` | 5 | `0b1` |
| GICv5 EL1 read trap | `ICH_HFGRTR_EL2.ICC_HPPIR_EL1` | 4 | `0b1` |
| GICv5 EL1 read trap | `ICH_HFGRTR_EL2.ICC_HAPR_EL1` | 3 | `0b1` |
| GICv5 EL1 read trap | `ICH_HFGRTR_EL2.ICC_CR0_EL1` | 2 | `0b1` |
| GICv5 EL1 read trap | `ICH_HFGRTR_EL2.ICC_IDRn_EL1` | 1 | `0b1` |
| GICv5 EL1 read trap | `ICH_HFGRTR_EL2.ICC_APR_EL1` | 0 | `0b1` |
| GICv5 EL1 write trap | `ICH_HFGWTR_EL2.ICC_PPI_ACTIVERn_EL1` | 20 | `0b1` |
| GICv5 EL1 write trap | `ICH_HFGWTR_EL2.ICC_PPI_PRIORITYRn_EL1` | 19 | `0b1` |
| GICv5 EL1 write trap | `ICH_HFGWTR_EL2.ICC_PPI_PENDRn_EL1` | 18 | `0b1` |
| GICv5 EL1 write trap | `ICH_HFGWTR_EL2.ICC_PPI_ENABLERn_EL1` | 17 | `0b1` |
| GICv5 EL1 write trap | `ICH_HFGWTR_EL2.ICC_ICSR_EL1` | 6 | `0b1` |
| GICv5 EL1 write trap | `ICH_HFGWTR_EL2.ICC_PCR_EL1` | 5 | `0b1` |
| GICv5 EL1 write trap | `ICH_HFGWTR_EL2.ICC_CR0_EL1` | 2 | `0b1` |
| GICv5 EL1 write trap | `ICH_HFGWTR_EL2.ICC_APR_EL1` | 0 | `0b1` |
| GICv5 instruction trap | `ICH_HFGITR_EL2.GICRCDNMIA` | 10 | `0b1` |
| GICv5 instruction trap | `ICH_HFGITR_EL2.GICRCDIA` | 9 | `0b1` |
| GICv5 instruction trap | `ICH_HFGITR_EL2.GICCDDI` | 8 | `0b1` |
| GICv5 instruction trap | `ICH_HFGITR_EL2.GICCDEOI` | 7 | `0b1` |
| GICv5 instruction trap | `ICH_HFGITR_EL2.GICCDHM` | 6 | `0b1` |
| GICv5 instruction trap | `ICH_HFGITR_EL2.GICCDRCFG` | 5 | `0b1` |
| GICv5 instruction trap | `ICH_HFGITR_EL2.GICCDPEND` | 4 | `0b1` |
| GICv5 instruction trap | `ICH_HFGITR_EL2.GICCDAFF` | 3 | `0b1` |
| GICv5 instruction trap | `ICH_HFGITR_EL2.GICCDPRI` | 2 | `0b1` |
| GICv5 instruction trap | `ICH_HFGITR_EL2.GICCDDIS` | 1 | `0b1` |
| GICv5 instruction trap | `ICH_HFGITR_EL2.GICCDEN` | 0 | `0b1` |
DT 또는 ACPI 테이블은 GICv5 interrupt controller를 설명해야 합니다.
GICv3·GICv2 compatibility와 pointer authentication
267-307| 기능·조건 | Register field | Bit | 초기값·제약 |
|---|---|---|---|
| GICv3, EL3 존재 | `ICC_SRE_EL3.Enable` | 3 | `0b1` |
| GICv3, EL3 존재 | `ICC_SRE_EL3.SRE` | 0 | `0b1` |
| GICv3, EL3 존재 | `ICC_CTLR_EL3.PMHE` | 6 | 모든 실행 CPU에서 같은 값이며 kernel lifetime 동안 고정 |
| GICv3, kernel EL1 진입 | `ICC_SRE_EL2.Enable` | 3 | `0b1` |
| GICv3, kernel EL1 진입 | `ICC_SRE_EL2.SRE` | 0 | `0b1` |
| GICv3 compatibility(v2), EL3 존재 | `ICC_SRE_EL3.SRE` | 0 | `0b0` |
| GICv3 compatibility(v2), kernel EL1 진입 | `ICC_SRE_EL2.SRE` | 0 | `0b0` |
| Pointer authentication, EL3 존재 | `SCR_EL3.APK` | 16 | `0b1` |
| Pointer authentication, EL3 존재 | `SCR_EL3.API` | 17 | `0b1` |
| Pointer authentication, kernel EL1 진입 | `HCR_EL2.APK` | 40 | `0b1` |
| Pointer authentication, kernel EL1 진입 | `HCR_EL2.API` | 41 | `0b1` |
GICv3를 v3 mode로 쓰면 DT 또는 ACPI가 GICv3 controller를 설명해야 합니다. GICv3를 compatibility(v2) mode로 쓰면 GICv2 controller로 설명해야 합니다.
AMUv1·FGT·FGT2·HCX
308-343| 기능·조건 | Register field | Bit | 초기값·제약 |
|---|---|---|---|
| AMUv1, EL3 존재 | `CPTR_EL3.TAM` | 30 | `0b0` |
| AMUv1, EL3 존재 | `CPTR_EL2.TAM` | 30 | `0b0` |
| AMUv1, EL3 존재 | `AMCNTENSET0_EL0` | - | `0b1111` |
| AMUv1, EL3 존재 | `AMCNTENSET1_EL0` | - | 존재하는 각 auxiliary counter bit를 `0b1`로 둔 platform-specific 값 |
| AMUv1, kernel EL1 진입 | `AMCNTENSET0_EL0` | - | `0b1111` |
| AMUv1, kernel EL1 진입 | `AMCNTENSET1_EL0` | - | 존재하는 각 auxiliary counter bit를 `0b1`로 둔 platform-specific 값 |
| FEAT_FGT, EL3 존재·kernel EL2 진입 | `SCR_EL3.FGTEn` | 27 | `0b1` |
| FEAT_FGT2, EL3 존재·kernel EL2 진입 | `SCR_EL3.FGTEn2` | 59 | `0b1` |
| FEAT_HCX, EL3 존재·kernel EL2 진입 | `SCR_EL3.HXEn` | 38 | `0b1` |
Advanced SIMD·SVE·SME
344-411| 기능·조건 | Register field | Bit | 초기값·제약 |
|---|---|---|---|
| Advanced SIMD/FP, EL3 존재 | `CPTR_EL3.TFP` | 10 | `0b0` |
| Advanced SIMD/FP, EL2 존재·kernel EL1 진입 | `CPTR_EL2.TFP` | 10 | `0b0` |
| FEAT_SVE, EL3 존재 | `CPTR_EL3.EZ` | 8 | `0b1` |
| FEAT_SVE, EL3 존재 | `ZCR_EL3.LEN` | - | Kernel이 실행될 모든 CPU에서 같은 값 |
| FEAT_SVE, EL2 존재·kernel EL1 진입 | `CPTR_EL2.TZ` | 8 | `0b0` |
| FEAT_SVE, EL2 존재·kernel EL1 진입 | `CPTR_EL2.ZEN` | 17:16 | `0b11` |
| FEAT_SVE, EL2 존재·kernel EL1 진입 | `ZCR_EL2.LEN` | - | Kernel이 실행될 모든 CPU에서 같은 값 |
| FEAT_SME, EL3 존재 | `CPTR_EL3.ESM` | 12 | `0b1` |
| FEAT_SME, EL3 존재 | `SCR_EL3.EnTP2` | 41 | `0b1` |
| FEAT_SME, EL3 존재 | `SMCR_EL3.LEN` | - | Kernel이 실행될 모든 CPU에서 같은 값 |
| FEAT_SME, EL2 존재·kernel EL1 진입 | `CPTR_EL2.TSM` | 12 | `0b0` |
| FEAT_SME, EL2 존재·kernel EL1 진입 | `CPTR_EL2.SMEN` | 25:24 | `0b11` |
| FEAT_SME, EL2 존재·kernel EL1 진입 | `SCTLR_EL2.EnTP2` | 60 | `0b1` |
| FEAT_SME, EL2 존재·kernel EL1 진입 | `SMCR_EL2.LEN` | - | Kernel이 실행될 모든 CPU에서 같은 값 |
| FEAT_SME, EL2 존재·kernel EL1 진입 | `HWFGRTR_EL2.nTPIDR2_EL0` | 55 | `0b01` |
| FEAT_SME, EL2 존재·kernel EL1 진입 | `HWFGWTR_EL2.nTPIDR2_EL0` | 55 | `0b01` |
| FEAT_SME, EL2 존재·kernel EL1 진입 | `HWFGRTR_EL2.nSMPRI_EL1` | 54 | `0b01` |
| FEAT_SME, EL2 존재·kernel EL1 진입 | `HWFGWTR_EL2.nSMPRI_EL1` | 54 | `0b01` |
| FEAT_SME_FA64, EL3 존재 | `SMCR_EL3.FA64` | 31 | `0b1` |
| FEAT_SME_FA64, EL2 존재·kernel EL1 진입 | `SMCR_EL2.FA64` | 31 | `0b1` |
MTE2·SME2·BRBE·PMUv3p9·SPE
412-478| 기능·조건 | Register field | Bit | 초기값·제약 |
|---|---|---|---|
| FEAT_MTE2, EL3 존재 | `SCR_EL3.ATA` | 26 | `0b1` |
| FEAT_MTE2, EL2 존재·kernel EL1 진입 | `HCR_EL2.ATA` | 56 | `0b1` |
| FEAT_SME2, EL3 존재 | `SMCR_EL3.EZT0` | 30 | `0b1` |
| FEAT_SME2, EL2 존재·kernel EL1 진입 | `SMCR_EL2.EZT0` | 30 | `0b1` |
| FEAT_BRBE, EL3 존재 | `MDCR_EL3.SBRBE` | 33:32 | `0b01` 또는 `0b11` |
| FEAT_BRBE, EL2 존재·kernel EL1 진입 | `BRBCR_EL2.CC` | 3 | `0b1` |
| FEAT_BRBE, EL2 존재·kernel EL1 진입 | `BRBCR_EL2.MPRED` | 4 | `0b1` |
| FEAT_BRBE, EL2 존재·kernel EL1 진입 | `HDFGRTR_EL2.nBRBDATA` | 61 | `0b1` |
| FEAT_BRBE, EL2 존재·kernel EL1 진입 | `HDFGRTR_EL2.nBRBCTL` | 60 | `0b1` |
| FEAT_BRBE, EL2 존재·kernel EL1 진입 | `HDFGRTR_EL2.nBRBIDR` | 59 | `0b1` |
| FEAT_BRBE, EL2 존재·kernel EL1 진입 | `HDFGWTR_EL2.nBRBDATA` | 61 | `0b1` |
| FEAT_BRBE, EL2 존재·kernel EL1 진입 | `HDFGWTR_EL2.nBRBCTL` | 60 | `0b1` |
| FEAT_BRBE, EL2 존재·kernel EL1 진입 | `HFGITR_EL2.nBRBIALL` | 56 | `0b1` |
| FEAT_BRBE, EL2 존재·kernel EL1 진입 | `HFGITR_EL2.nBRBINJ` | 55 | `0b1` |
| FEAT_PMUv3p9, EL3 존재 | `MDCR_EL3.EnPM2` | 7 | `0b1` |
| FEAT_PMUv3p9, EL2 존재·kernel EL1 진입 | `HDFGRTR2_EL2.nPMICNTR_EL0` | 2 | `0b1` |
| FEAT_PMUv3p9, EL2 존재·kernel EL1 진입 | `HDFGRTR2_EL2.nPMICFILTR_EL0` | 3 | `0b1` |
| FEAT_PMUv3p9, EL2 존재·kernel EL1 진입 | `HDFGRTR2_EL2.nPMUACR_EL1` | 4 | `0b1` |
| FEAT_PMUv3p9, EL2 존재·kernel EL1 진입 | `HDFGWTR2_EL2.nPMICNTR_EL0` | 2 | `0b1` |
| FEAT_PMUv3p9, EL2 존재·kernel EL1 진입 | `HDFGWTR2_EL2.nPMICFILTR_EL0` | 3 | `0b1` |
| FEAT_PMUv3p9, EL2 존재·kernel EL1 진입 | `HDFGWTR2_EL2.nPMUACR_EL1` | 4 | `0b1` |
| FEAT_SPE_FDS, EL3 존재 | `MDCR_EL3.EnPMS3` | 42 | `0b1` |
| FEAT_SPE_FDS, EL2 존재·kernel EL1 진입 | `HDFGRTR2_EL2.nPMSDSFR_EL1` | 19 | `0b1` |
| FEAT_SPE_FDS, EL2 존재·kernel EL1 진입 | `HDFGWTR2_EL2.nPMSDSFR_EL1` | 19 | `0b1` |
MOPS·TCR2·S1PIE·GCS·debug·PMU
479-558| 기능·조건 | Register field | Bit | 초기값·제약 |
|---|---|---|---|
| FEAT_MOPS, EL2 존재·kernel EL1 진입 | `HCRX_EL2.MSCEn` | 11 | `0b1` |
| FEAT_MOPS, EL2 존재·kernel EL1 진입 | `HCRX_EL2.MCE2` | 10 | `0b1`; hypervisor는 `arm64_mops_hyp`에 설명된 MOPS exception을 처리 |
| FEAT_TCR2, EL3 존재 | `SCR_EL3.TCR2En` | 43 | `0b1` |
| FEAT_TCR2, EL2 존재·kernel EL1 진입 | `HCRX_EL2.TCR2En` | 14 | `0b1` |
| FEAT_S1PIE, EL3 존재 | `SCR_EL3.PIEn` | 45 | `0b1` |
| FEAT_S1PIE, EL2 존재·kernel EL1 진입 | `HFGRTR_EL2.nPIR_EL1` | 58 | `0b1` |
| FEAT_S1PIE, EL2 존재·kernel EL1 진입 | `HFGWTR_EL2.nPIR_EL1` | 58 | `0b1` |
| FEAT_S1PIE, EL2 존재·kernel EL1 진입 | `HFGRTR_EL2.nPIRE0_EL1` | 57 | `0b1` |
| FEAT_S1PIE, EL2 존재·kernel EL1 진입 | `HFGRWR_EL2.nPIRE0_EL1` | 57 | `0b1` |
| FEAT_GCS, 모든 CPU | `GCSCR_EL1` | - | `0` |
| FEAT_GCS, 모든 CPU | `GCSCRE0_EL1` | - | `0` |
| FEAT_GCS, EL3 존재 | `SCR_EL3.GCSEn` | 39 | `0b1` |
| FEAT_GCS, EL2 존재 | `GCSCR_EL2` | - | `0` |
| FEAT_GCS, EL2 존재·kernel EL1 진입 | `HCRX_EL2.GCSEn` | - | `0b1` |
| FEAT_GCS, EL2 존재·kernel EL1 진입 | `HFGITR_EL2.nGCSEPP` | 59 | `0b1` |
| FEAT_GCS, EL2 존재·kernel EL1 진입 | `HFGITR_EL2.nGCSSTR_EL1` | 58 | `0b1` |
| FEAT_GCS, EL2 존재·kernel EL1 진입 | `HFGITR_EL2.nGCSPUSHM_EL1` | 57 | `0b1` |
| FEAT_GCS, EL2 존재·kernel EL1 진입 | `HFGRTR_EL2.nGCS_EL1` | 53 | `0b1` |
| FEAT_GCS, EL2 존재·kernel EL1 진입 | `HFGRTR_EL2.nGCS_EL0` | 52 | `0b1` |
| FEAT_GCS, EL2 존재·kernel EL1 진입 | `HFGWTR_EL2.nGCS_EL1` | 53 | `0b1` |
| FEAT_GCS, EL2 존재·kernel EL1 진입 | `HFGWTR_EL2.nGCS_EL0` | 52 | `0b1` |
| FEAT_Debugv8pN 전체 version, EL3 존재 | `MDCR_EL3.TDA` | 9 | `0b0` |
| FEAT_PMUv3, EL3 존재 | `MDCR_EL3.TPM` | 6 | `0b0` |
모든 CPU의 진입 level과 secondary CPU 시작
559-608앞에서 설명한 CPU mode, cache, MMU, architected timer, coherency, system register 요구사항은 모든 CPU에 적용됩니다. 모든 CPU는 같은 exception level로 kernel에 진입해야 합니다. 문서 값이 trap을 disable하도록 요구하더라도 상위 exception level이 해당 값을 설정한 것처럼 trap을 투명하게 처리한다면 trap을 enable해도 됩니다.
Primary CPU는 kernel image의 첫 instruction으로 직접 jump해야 합니다. 이 CPU가 전달하는 dtb에는 각 CPU node의 `enable-method` property가 있어야 합니다. Boot loader는 kernel 진입 전에 이 property를 만들고 blob에 삽입해야 합니다.
`spin-table` enable-method를 쓰는 CPU node에는 naturally aligned되고 0으로 초기화된 64-bit memory location을 가리키는 `cpu-release-addr` property가 있어야 합니다.
이 CPU들은 DT의 `/memreserve/` 영역으로 kernel에 알린 reserved memory 안에서 kernel 밖에 머물며, 같은 reserved 영역에 든 `cpu-release-addr` location을 polling해야 합니다. Busy loop overhead를 줄이기 위해 `wfe`를 넣을 수 있고 primary CPU가 `sev`를 실행합니다. Location read가 0이 아닌 값을 반환하면 그 address로 jump합니다. 값은 하나의 64-bit little-endian 값으로 쓰이므로 CPU는 jump 전에 native endianness로 변환해야 합니다.
`psci` enable-method를 쓰는 CPU는 kernel에 설명된 memory node 밖이나 DT `/memreserve/`가 설명하는 reserved memory 안에서 kernel 밖에 머물러야 합니다. Kernel은 Arm 문서 `ARM DEN 0022A`, `Power State Coordination Interface System Software on ARM processors`가 설명한 `CPU_ON` call로 CPU를 kernel에 진입시킵니다.
Device tree에는 `Documentation/devicetree/bindings/arm/psci.yaml`이 설명하는 `psci` node가 있어야 합니다.
Secondary CPU의 general-purpose register는 `x0 = 0`, `x1 = 0`, `x2 = 0`, `x3 = 0`으로 모두 future use를 위해 예약됩니다.
요약과 해설
booting.rst:1-608AArch64 boot protocol은 단순히 Image address로 jump하는 규약이 아닙니다. Boot loader는 RAM과 DTB를 준비하고 Image header의 placement 계약을 지키며 모든 CPU의 exception level·cache·timer·coherency·feature trap register를 일관된 상태로 만들어야 합니다.
각 단계의 출력이 다음 단계와 kernel entry contract의 입력이 됩니다.
Primary CPU와 secondary CPU가 공유하는 조건과 서로 다른 register 인자를 요약합니다.