diff --git a/articles/20220319-riscv-uefi.md b/articles/20220319-riscv-uefi.md index 24064edfc137cda5402be60d161965f0b0fb2b50..2bfa727cdec3a4261633412d9d72313beba0a718 100644 --- a/articles/20220319-riscv-uefi.md +++ b/articles/20220319-riscv-uefi.md @@ -1,12 +1,13 @@ +> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.1-rc2 - [spaces]
> Author: Jacob Wang
> Date: 2022/03/19
+> Revisor: Falcon
> Project: [RISC-V Linux 内核剖析](https://gitee.com/tinylab/riscv-linux)
> Sponsor: PLCT Lab, ISCAS -> -# RISC-V UEFI 架构支持详解,第 1 部分 - OpenSBI/U-Boot/UEFI 简介 +# RISC-V UEFI 架构支持详解,第 1 部分 - OpenSBI/U-Boot/UEFI 简介 -从 [邮件列表](https://lore.kernel.org/linux-riscv) 中找到了一笔 patchset:[adds UEFI support for RISC-V](https://lore.kernel.org/linux-riscv/20200917223716.2300238-1-atish.patra@wdc.com/)。该 patchset 实现 RISC-V 如下引导启动支撑: +从 [邮件列表][006] 中找到了一笔 patchset:[adds UEFI support for RISC-V][007]。该 patchset 实现 RISC-V 如下引导启动支撑: ``` Qemu (both RV32 & RV64) for the following bootflow @@ -17,9 +18,10 @@ HiFive unleashed using (RV64) for the following bootflow OpenSBI->U-Boot->Linux EDK2->Linux ``` + 本文尝试对 OpenSBI,U-Boot 和 UEFI 的相关概念以及代码进行基本的解析。 -## OpenSBI +## OpenSBI OpenSBI 项目致力于为 RISC-V 平台特有固件提供 RISC-V SBI 规范的开源参考实现,这类固件运行在 RISC-V M 模式。 @@ -35,11 +37,11 @@ RISC-V 架构下有 3 种特权级别,分别是 Machine、Supervisor 和 User OpenSBI 会经历底层初始化阶段,该阶段主要是准备 C 执行环境;然后在布置好的 C 环境执行设备初始化;最后实现二级引导的跳转。 -以下以 [OpenSBI](https://github.com/riscv/opensbi.git) v1.0 版本为例,开展源码分析如下。 +以下以 [OpenSBI][004] v1.0 版本为例,开展源码分析如下。 1. OpenSBI 底层初始化 -其实现在 `/firmware/fw_base.S`, 大体流程如下: +其实现在 `/firmware/fw_base.S`,大体流程如下: ``` _start: @@ -148,7 +150,7 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid) } ``` -关于 `sbi_hart_switch_mode()` 的具体实现以及 `next_arg1`, `next_addr` 等的设定,可能需要分析 `lib/sbi/sbi_hsm.c`,待后续再结合 qemu 调试来详细分解。 +关于 `sbi_hart_switch_mode()` 的具体实现以及 `next_arg1`, `next_addr` 等的设定,可能需要分析 `lib/sbi/sbi_hsm.c`,待后续再结合 QEMU 调试来详细分解。 ## U-Boot @@ -158,7 +160,7 @@ U-Boot 是一种流行的嵌入式 Linux 系统引导加载程序。 - SRAM - 掉电易失(失去电源供电后 SRAM 里存储的数据不存在了),可以随意 **读写** 数据。(容量小,程序运行速度快,价格高,一般在 SoC 里面) + 掉电易失(失去电源供电后 SRAM 里存储的数据不存在了),可以随意 **读写** 数据。(容量小,程序运行速度快,价格高,一般在 SoC 里面) - SDRAM @@ -166,13 +168,13 @@ U-Boot 是一种流行的嵌入式 Linux 系统引导加载程序。 - SPL - U-Boot 分为 uboot-spl 和 uboot 两个组成部分。SPL 是 Secondary Program Loader 的简称,第二阶段程序加载器。 + U-Boot 分为 uboot-spl 和 U-Boot 两个组成部分。SPL 是 Secondary Program Loader 的简称,第二阶段程序加载器。 这里所谓的第二阶段是相对于 SOC 中的 SRAM 来说的,SOC 启动最先执行的是固化的程序。ROM 会通过检测启动方式来加载第二阶段 bootloader。 U-Boot 已经是一个 bootloader 了,那么为什么还多一个 U-Boot SPL 呢? -主要原因是对于一些SOC来说,它的内部 SRAM 可能会比较小,小到无法装载下一个完整的 U-Boot 镜像,那么就需要 SPL。它主要负责初始化外部 RAM 和环境,并加载真正的 U-Boot 镜像到外部 RAM 中来执行。所以由此来看,SPL 应该是一个非常小的 loader 程序,可以运行于 SOC 的内部 SRAM 中,它的主要功能就是加载真正的 U-Boot 并运行。 +主要原因是对于一些 SOC 来说,它的内部 SRAM 可能会比较小,小到无法装载下一个完整的 U-Boot 镜像,那么就需要 SPL。它主要负责初始化外部 RAM 和环境,并加载真正的 U-Boot 镜像到外部 RAM 中来执行。所以由此来看,SPL 应该是一个非常小的 loader 程序,可以运行于 SOC 的内部 SRAM 中,它的主要功能就是加载真正的 U-Boot 并运行。 ### U-Boot 加载过程 @@ -215,13 +217,13 @@ SPL 会先被加载到 SRAM 中,然后初始化 DDR 或者 SDRAM,总之会 ### U-Boot 代码分析 -U-Boot 其启动过程主要可以分为两个部分,Stage1 和 Stage2 。其中 Stage1 是用汇编语言实现的,主要完成硬件资源的初始化。而 Stage2 则是用 C 语言实现。 +U-Boot 其启动过程主要可以分为两个部分,Stage1 和 Stage2。其中 Stage1 是用汇编语言实现的,主要完成硬件资源的初始化。而 Stage2 则是用 C 语言实现。 -以下以 [U-boot](https://github.com/u-boot/u-boot) v2022.04 版本为例,开展源码分析如下。 +以下以 [U-boot][005] v2022.04 版本为例,开展源码分析如下。 第一阶段路径位于 `arch/riscv/cpu/start.S` 文件。 -第二阶段启动阶段中, 会重点涉及到 位于 `common/board_r.c` 的 board_init_f 函数和位于 `common/board_r.c` 文件的的 board_init_r 函数。board_init_f 会初始化必要的板卡和 global_data 结构体,然后调用 board_init_r 进行下一阶段的板卡初始化工作。board_init_r 运行结束之后, 会调用位于 `common/main.c` 的 main_loop() 函数进行。来重点看一下这三个函数。 +第二阶段启动阶段中,会重点涉及到 位于 `common/board_r.c` 的 board_init_f 函数和位于 `common/board_r.c` 文件的的 board_init_r 函数。board_init_f 会初始化必要的板卡和 global_data 结构体,然后调用 board_init_r 进行下一阶段的板卡初始化工作。board_init_r 运行结束之后,会调用位于 `common/main.c` 的 main_loop() 函数进行。来重点看一下这三个函数。 - board_init_f 分析 @@ -351,21 +353,20 @@ void main_loop(void) ## UEFI 大概 20 多年的发展和积累中,UEFI 的代码量已经很庞大,相关标准白皮书也有很多 -> 1999 年:EFI 1.0 推出 -> 2000 年:EFI 1.02 发布 -> 2002 年:EFI 1.10 发布 -> 2006 年:UEFI 2.0 发布 -> 2007 年:UEFI 2.1 +> 1999 年:EFI 1.0 推出 +> 2000 年:EFI 1.02 发布 +> 2002 年:EFI 1.10 发布 +> 2006 年:UEFI 2.0 发布 +> 2007 年:UEFI 2.1 > 2008 年:UEFI 2.2 - 剥离开技术细节,引导软件基本做的就是初始化硬件和提供硬件的软件抽象,并完成引导启动。 启动阶段搞来搞去基本就三个步骤: 1. Rom 阶段 - 该阶段没有内存,没有 C 语言运行需要的栈空间,开始往往是汇编语言,直接在 ROM 空间上运行。在找到临时空间后( Cache As Ram, CAR),C 语言可以使用,然后开始用 C 语言初始化内存。 + 该阶段没有内存,没有 C 语言运行需要的栈空间,开始往往是汇编语言,直接在 ROM 空间上运行。在找到临时空间后 (Cache As Ram, CAR),C 语言可以使用,然后开始用 C 语言初始化内存。 2. Ram 阶段 @@ -380,7 +381,7 @@ void main_loop(void) EFI 在过程中会提供运行时服务和 EFI 引导时服务; -(引导时服务只在 boot time 可用,runtime service 在引导后面的 OS 后还是可以继续被使用的) +(引导时服务只在 boot time 可用,runtime service 在引导后面的 OS 后还是可以继续被使用的) 如上图所示,EFI 在过程中会提供运行时服务和 EFI 引导时服务,其中引导时服务只在 boot time 可用,runtime service 在引导后面的 OS 后还是可以继续被使用的。 @@ -394,7 +395,7 @@ UEFI 启动过程遵循 UEFI 平台初始化(Platform Initialization)标准 -7 个阶段分别为 `SEC (Security)`,`PEI (Pre-EFi Initalization)`,`DXE (Driver Execution Environment)`,`BDS (Boot Device Selection)`,`TSL (Transient System Load)`,`RT (Runtime)`,`AL (After Life)`。前三个阶段是 UEFI 初始化阶段。 下面介绍一下每个阶段的主要任务; +7 个阶段分别为 `SEC (Security)`,`PEI (Pre-EFi Initalization)`,`DXE (Driver Execution Environment)`,`BDS (Boot Device Selection)`,`TSL (Transient System Load)`,`RT (Runtime)`,`AL (After Life)`。前三个阶段是 UEFI 初始化阶段。下面介绍一下每个阶段的主要任务; - SEC 阶段 @@ -438,13 +439,24 @@ EDK2 是一个现代、功能丰富的跨平台固件开发环境,适用于 UE UEFI 的 PEI 和 DXE 阶段,分别对应 Coreboot 的 romstage 和 ramstage 阶段。 -下图比较形象的对比了两者的区别: +下图比较形象的对比了两者的区别: ## 参考文档 -* [UEFI SPEC](https://uefi.org/sites/default/files/resources/UEFI_Spec_2_9_2021_03_18.pdf) -* [riscv-uefi-edk2-docs](https://github.com/riscv-admin/riscv-uefi-edk2-docs) -* [coreboot architecture](https://doc.coreboot.org/getting_started/architecture.html) -* [SPL](https://stackoverflow.com/questions/31244862/what-is-the-use-of-spl-secondary-program-loader) -* [Open-source Firmware and Bootloaders](http://lastweek.io/notes/source_code/firmware-softwares/) + +* [UEFI SPEC][009] +* [riscv-uefi-edk2-docs][003] +* [coreboot architecture][002] +* [SPL][008] +* [Open-source Firmware and Bootloaders][001] + +[001]: http://lastweek.io/notes/source_code/firmware-softwares/ +[002]: https://doc.coreboot.org/getting_started/architecture.html +[003]: https://github.com/riscv-admin/riscv-uefi-edk2-docs +[004]: https://github.com/riscv/opensbi.git +[005]: https://github.com/u-boot/u-boot +[006]: https://lore.kernel.org/linux-riscv +[007]: https://lore.kernel.org/linux-riscv/20200917223716.2300238-1-atish.patra@wdc.com/ +[008]: https://stackoverflow.com/questions/31244862/what-is-the-use-of-spl-secondary-program-loader +[009]: https://uefi.org/sites/default/files/resources/UEFI_Spec_2_9_2021_03_18.pdf