接前一篇文章:字节跳动社招面经 —— BSP驱动工程师(4)
本文内容参考:
ARM64架构启动流程_arm64 linux kernel 启动流程-CSDN博客
特此致谢!
上一回讲解了“嵌入式充电站”发的一篇文章字节跳动社招面经——BSP驱动工程师中的面试题一面的第2题,本回解析第3题。再次贴出面试题:
3. arm64启动流程
arm64架构的启动流程是一个多阶段、分层次的过程,涉及硬件初始化、权限切换、代码加载和操作系统启动。以下是其核心流程的详细说明:
(1)硬件上电与BootROM执行
1)复位向量(Reset Vector)
CPU上电后,从固定地址(通常为0x00000000
或厂商定义的地址)开始执行BootROM代码。
- BootROM是芯片内部只读固件,负责最底层硬件初始化(如时钟、内存控制器、安全引擎)。
- 验证下一阶段代码(如Bootloader)的数字签名(Secure Boot)。
2)异常级别(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)
- 任务
a. 初始化关键外设(如UART调试串口、DRAM控制器);
b. 设置异常向量表(Exception Vector Table);
c. 加载下一阶段Bootloader(如U-Boot)到内存;
d. 切换异常级别(从EL3 → EL2或EL1)。
- 示例代码(ATF跳转)
bl31_main() {// 初始化平台硬件plat_initialize();// 跳转到非安全世界(EL2/EL1)enter_normal_world();
}
2)阶段 2:Secondary Bootloader(如U-Boot)
- 任务
a. 完整内存映射初始化(如DDR配置);
b. 加载设备树(Device Tree Blob,DTB)或ACPI表;
c. 从存储介质(eMMC、NVMe、网络)加载操作系统内核(如Linux);
d. 传递启动参数(内核地址、设备树地址、命令行参数)。
-
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)操作系统内核启动
1)内核解压与重定位(如Linux)
- 任务
a. 自解压(如果内核为压缩格式,如Image.gz
);
b. 初始化页表、MMU和缓存;
c. 解析设备树或ACPI,初始化硬件(如中断控制器、PCIe、USB);
d. 挂载根文件系统,启动用户空间初始化进程(如systemd
或init
)。
- 内核启动流程
start_kernel() {setup_arch(); // 架构相关初始化(ARM64)init_irq(); // 中断控制器初始化(GIC)time_init(); // 时钟源初始化rest_init(); // 创建 init 进程
}
(4)多核启动(SMP初始化)
- 主核(Primary Core)
执行完整启动流程。
- 从核(Secondary Cores)
a. 上电后处于等待状态(通过spin-table
或PSCI协议);
b. 主核通过发送中断(SGI)或设置唤醒地址唤醒从核;
c. 从核跳转到内核指定的入口地址(如secondary_startup
)。
- 示例(设备树配置spin-table)
cpu@1 {device_type = "cpu";reg = <0x0 0x1>;enable-method = "spin-table";cpu-release-addr = <0x0 0x8000fff8>;
};
更多内容请看下回。