ARM64 AArch64 Linux启动

原创
2019/08/10 21:33
阅读数 491

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字节开始。

3.解压内核(可选)
AArch64内核当前不提供解压缩器,因此如果使用压缩的Image目标(例如Image.gz),
则需要由引导加载程序执行解压缩(gzip等)。 对于未实现此要求的引导加载程序,
可以使用未压缩的Image目标。

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)

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部