AArch64 Linux启动算法
AArch64异常模型由许多异常级别(EL0-EL3)组成,EL0和EL1具备安全和非安全两种模式对应。
EL2是hypervisor,仅存在于非安全模式。 EL3是最高优先级,仅在安全模式下存在。编程
出于本文档的目的,咱们将使用术语“引导加载程序”来简单地定义在控制传递到Linux内核以前
在CPU上执行的全部软件。 这可能包括安全监视器和管理程序代码,或者它可能只是一些准备
最小引导环境的指令。缓存
本质上,引导加载程序应该提供(至少)如下功能:
1.设置并初始化RAM
2.设置设备树
3.解压缩内核映像
4.调用内核映像安全
1.设置和初始化内存(必须)
引导加载程序将查找并初始化内核静态数据所要用到的全部RAM。
它将全部数据以机器执行顺序放到内存里。(它可使用内部算法自动定位和调整全部RAM,
或者它可使用机器中RAM的知识,或者引导加载程序设计者认为合适的任何其余方法。)网络
2.设置设备树(必须)
设备树blob(dtb)必须放在8字节对齐地址上,且大小不得超过2MB。
因为dtb将使用最大2MB的块进行可缓存映射,所以不得将其放置在必须与
任何特定属性映射的任何2M区域内。架构
注意:v4.2以前的版本还要求将DTB放在512 MB区域内,从内核Image下面的text_offset字节开始。app
3.解压内核(可选)
AArch64内核当前不提供解压缩器,所以若是使用压缩的Image目标(例如Image.gz),
则须要由引导加载程序执行解压缩(gzip等)。 对于未实现此要求的引导加载程序,
可使用未压缩的Image目标。es5
4.引导内核(必须)
一个压缩的内核镜像包含了一个64字节的头部信息:
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) */
说明:
- 在V3.17版本以后,除非另有说明,不然都是小端模式设计
- code0和code1是负责分支到文本????调试
- 在经过EFI启动时,最初会跳过code0 / code1。res5是PE头的偏移量,
PE头具备EFI入口点(efi_stub_entry)。当stub完成其工做时,它会跳转到code0以恢复正常启动过程。
- 在v3.17以前,未指定text_offset的字节顺序。 在这些状况下,image_size为零,
而且text_offset在内核的字节顺序中为0x80000。 在image_size为非零的状况下,
image_size是little-endian,必须遵照。 在image_size为零的状况下,
能够假设text_offset为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 may be anywhere in physical
memory
Bits 4-63: Reserved.
- 当image_size为零时,引导加载程序应该在内核映像结束后当即尝试保留尽量多的
内存供内核使用。 所需的空间量将根据所选功能而有所不一样,而且其实是未绑定的。
镜像必须放在 2MB对齐的基地址偏移 text_offset地址中,并会在那里调用执行。
2 MB对齐的基址和镜像的开头之间的区域对内核没有特殊意义,能够用于其余目的。
至少从映像开头的image_size字节必须是空闲的,以供内核使用。
注意:v4.6以前的版本没法使用低于Image物理偏移量的内存,所以建议将Image放置在
尽量靠近系统RAM启动位置的位置。
若是initrd / initramfs在引导时传递给内核,它必须彻底驻留在最大32GB的1GB对齐
物理内存窗口中,彻底覆盖内核Image。
向内核描述的任何内存(即便是在image开头之下)也没有被标记为从内核保留
(例如,在设备树中具备memreserve区域)将被认为是内核可用的。
在跳转到内核执行以前,必须知足如下条件:
1.关掉全部支持DMA的设备,以便内存不会被网络数据包或磁盘数据破坏。
这将为您节省大量的调试时间。
2.主CPU的通用寄存器设置为:
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)
3. CPU模式
在PSTATE.DAIF中屏蔽全部中断(Debug, SError, IRQ and FIQ).
CPU必须位于EL2(推荐以便访问虚拟化扩展)或非安全EL1。
4. cache、mmu
mmu必须关闭
icache必须关闭
必须将与加载的内核映像相对应的地址范围清除到PoC。
在存在启用高速缓存的系统高速缓存或其余连贯主控器的状况下,
这一般须要经过VA而不是set/way操做来维护高速缓存。
必须配置而且能够启用经过VA操做遵循架构缓存维护的系统缓存。
必须配置和禁用不遵循VA操做(不推荐)的架构缓存维护的系统缓存。
5.系统定时器
必须设置CNTFRQ定时器频率,而且CNTVOFF必须在全部CPU上编程为一致的值。
若是在EL1进入内核,CNTHCTL_EL2必须设置为有效,EL1PCTEN(位0)。
6.Coherency
在进入内核时,内核引导的全部CPU必须是同一个一致性域的一部分。
这可能须要IMPLEMENTATION DEFINED初始化,以便可以在每一个CPU上接收维护操做。
7.系统寄存器
在进入内核映像的异常级别的全部可写架构系统寄存器必须由更高异常级别的软件初始化,
以防止在UNKNOWN状态下执行。
对于在v3模式下使用GICv3中断控制器的系统:
- 若是存在EL3:
ICC_SRE_EL3.Enable(第3位)必须初始化为0b1。
必须将ICC_SRE_EL3.SRE(位0)初始化为0b1。
- 若是在EL1进入内核:
必须将ICC.SRE_EL2.Enable(第3位)初始化为0b1
必须将ICC_SRE_EL2.SRE(位0)初始化为0b1。
- DT或ACPI表必须描述GICv3中断控制器。
对于在兼容性(v2)模式下使用GICv3中断控制器的系统:
- 若是存在EL3:
必须将ICC_SRE_EL3.SRE(位0)初始化为0b0。
- 若是在EL1输入内核:
必须将ICC_SRE_EL2.SRE(位0)初始化为0b0。
- DT或ACPI表必须描述GICv2中断控制器。
上述CPU模式,高速缓存,MMU,架构定时器,一致性和系统寄存器的要求适用于全部CPU。
全部CPU必须在相同的异常级别中进入内核。
指望引导加载程序如下列方式进入每一个CPU的内核:
- 主CPU必须直接跳转到内核映像的第一条指令。此CPU传递的设备树blob必须包含每一个cpu节点
的“enable-method”属性。支持的启用方法以下所述。
预计引导加载程序将生成这些设备树属性,并在内核进入以前将它们插入到blob中。
- 具备“spin-table”enable-method的CPU必须在其cpu节点中具备“cpu-release addr”属性。
此属性标识天然对齐的64位零初始化内存位置。
这些CPU应该在内核的保留区域内自旋(经过设备树中的/ memreserve / region与内核通讯)
轮询它们的cpu-release-addr位置,该位置必须包含在保留区域中。能够插入wfe指令以减小
繁忙循环的开销,而且将由主CPU发出sev。当读取cpu-release-addr指向的位置返回非零值时,
CPU必须跳转到该值。该值将写为单个64位little-endian值,所以CPU必须在读取以前将读取值
转换为其本机字节序。
- 具备“psci”启用方法的CPU应该保留在内核以外(即,在内存节点中向内核描述的内存区域以外, 或者在内存中由/ memreserve / region描述的内存的保留区域以外)设备树)。内核将按照ARM文档 编号ARM DEN 0022A(“ARM处理器上的电源状态协调接口系统软件”)中的描述发出CPU_ON调用, 以将CPU带入内核。 设备树须要包含psci节点,具体描述见Documentation/devicetree/bindings/arm/psci.txt. -辅助寄存器设置: x0 = 0 (reserved for future use) x1 = 0 (reserved for future use) x2 = 0 (reserved for future use) x3 = 0 (reserved for future use)