ARM64架构启动流程

ARM64 架构的启动流程是一个多阶段、分层次的过程,涉及硬件初始化、权限切换、代码加载和操作系统启动。以下是其核心流程的详细说明:


1. 硬件上电与 BootROM 执行

  • 复位向量(Reset Vector)
    CPU 上电后,从固定地址(通常为 0x00000000 或厂商定义的地址)开始执行 BootROM 代码。

    • BootROM 是芯片内部只读固件,负责最底层硬件初始化(如时钟、内存控制器、安全引擎)。
    • 验证下一阶段代码(如 Bootloader)的数字签名(Secure Boot)。
  • 异常级别(Exception Level, EL)
    ARM64 启动时运行在最高特权模式:

    • EL3(Secure Monitor):负责安全世界(Secure World)与非安全世界(Normal World)的切换。
    • EL2(Hypervisor):可选,支持虚拟化。
    • EL1(OS Kernel):操作系统内核运行级别。
    • EL0(User Space):用户应用程序。

2. 加载并执行 Bootloader

阶段 1:Primary Bootloader(如 ARM Trusted Firmware, ATF)
  • 任务

    1. 初始化关键外设(如 UART 调试串口、DRAM 控制器)。
    2. 设置异常向量表(Exception Vector Table)。
    3. 加载下一阶段 Bootloader(如 U-Boot)到内存。
    4. 切换异常级别(从 EL3 → EL2 或 EL1)。
  • 示例代码(ATF 跳转)

    bl31_main() {
        // 初始化平台硬件
        plat_initialize();
        // 跳转到非安全世界(EL2/EL1)
        enter_normal_world();
    }
    
阶段 2:Secondary Bootloader(如 U-Boot)
  • 任务

    1. 完整内存映射初始化(如 DDR 配置)。
    2. 加载设备树(Device Tree Blob, DTB)或 ACPI 表。
    3. 从存储介质(eMMC、NVMe、网络)加载操作系统内核(如 Linux)。
    4. 传递启动参数(内核地址、设备树地址、命令行参数)。
  • U-Boot 命令示例

    # 从 eMMC 加载内核和设备树到内存
    load mmc 0:1 ${kernel_addr_r} Image
    load mmc 0:1 ${fdt_addr_r} dtb.dtb
    # 启动内核
    booti ${kernel_addr_r} - ${fdt_addr_r}
    

3. 操作系统内核启动

内核解压与重定位(如 Linux)
  • 任务

    1. 自解压(如果内核为压缩格式,如 Image.gz)。
    2. 初始化页表、MMU 和缓存。
    3. 解析设备树或 ACPI,初始化硬件(如中断控制器、PCIe、USB)。
    4. 挂载根文件系统,启动用户空间初始化进程(如 systemdinit)。
  • 内核启动流程

    start_kernel() {
        setup_arch();          // 架构相关初始化(ARM64)
        init_irq();            // 中断控制器初始化(GIC)
        time_init();           // 时钟源初始化
        rest_init();           // 创建 init 进程
    }
    

4. 多核启动(SMP 初始化)

  • 主核(Primary Core):执行完整启动流程。

  • 从核(Secondary Cores)

    1. 上电后处于等待状态(通过 spin-table 或 PSCI 协议)。
    2. 主核通过发送中断(SGI)或设置唤醒地址唤醒从核。
    3. 从核跳转到内核指定的入口地址(如 secondary_startup)。
  • 示例(设备树配置 spin-table)

    cpu@1 {
        device_type = "cpu";
        reg = <0x0 0x1>;
        enable-method = "spin-table";
        cpu-release-addr = <0x0 0x8000fff8>;
    };
    

5. 安全启动与 TrustZone

  • TrustZone 划分

    • 安全世界(Secure World):运行安全监控程序(如 ATF BL31)和可信应用(TA)。
    • 非安全世界(Normal World):运行普通操作系统(如 Linux、Android)。
  • 启动流程中的安全切换

    1. BootROM 在 EL3 验证 Bootloader 签名。
    2. ATF(BL31)作为安全监控器,处理安全世界与非安全世界的切换。
    3. 内核运行在非安全世界的 EL1,无法直接访问安全资源。

6. 关键地址与数据传递

  • 内核加载地址

    • 由 Bootloader 指定(如 U-Boot 的 kernel_addr_r=0x80080000)。
    • 必须与内核链接地址一致(通过 CONFIG_PHYS_OFFSET 配置)。
  • 设备树/ACPI 地址

    • 设备树地址通过寄存器 x0 传递给内核。
    • ACPI 表由 UEFI 固件直接放置在内存中。

7. 调试与常见问题

  • 调试手段

    • 串口输出:通过 UART 打印 Bootloader 和内核日志。
    • JTAG 调试:追踪 CPU 执行流程,检查寄存器/内存状态。
  • 常见问题

    • 内存初始化失败:DRAM 参数配置错误(如时序、容量)。
    • 设备树错误:硬件描述不匹配导致内核崩溃。
    • 安全启动阻止:未签名或版本不符的固件被拒绝加载。

流程图示例

[ 硬件上电 ]  
    → BootROM(EL3)  
        → 加载并验证 ATF BL2  
            → ATF BL31(EL3)  
                → 切换至非安全世界,跳转至 U-Boot(EL2/EL1)  
                    → U-Boot 加载 Linux 内核和设备树  
                        → 内核启动(EL1)  
                            → 用户空间(EL0)

总结

ARM64 的启动流程是一个分层次、多阶段协作的过程,涉及从硬件初始化到操作系统加载的多个环节。理解其核心阶段(BootROM → Bootloader → Kernel)和权限切换(EL3 → EL1)是进行底层开发或系统移植的关键。实际应用中需结合具体芯片手册和调试工具,确保各阶段代码的地址、权限和安全策略正确配置。

你可能感兴趣的:(linux,c语言)