Risc-V 设备从上电到运行
本节目录
流程(OpenSbi 和 U-boot)
这一部分,我们以常用的基于 U-Boot 和 OpenSBl 的启动流程为例。
通过上一章的学习,我们知道,在上电之后,会从 ROM 中开始执行代码, 在 SoC(System on Chip)架构下, 芯片内部包含一块 ROM,保存了一些简单的驱动,同时会从 SD 卡或 fash 加载 U-Boot SPL 到一块小内存中(单独的 SRAM 或 L2cache-as-RAMM)。然后会又 U-Boot SPL 进行最早的初始化,主要是初始化 DDR 内存、时钟等最重要的设备,并且从 SD 卡加载 OpenSBI 和 U-Boot 本体到 DDR 内存,然后跳转到 OpenSBI 运行。
对于 OpenSBI 和 U-Boot 来说,它们执行下面工作: OpenSBI:
- 初始化 IPI 和时钟设备
- 初始化自身准备好提供 SBI 服务
- 切换到 Supervisor mode,跳转到 U-Boot
U-Boot:
- 从预先配置的启动设备加载内核到内存(来源可以是 SD 卡、NVMe、网络……)
- 跳转到内核入口点
之后,操作系统就能够开始运行了。
DeviceTree
那么,软件如何获知机器上有哪些功能和设备呢?
对于 ROM 来说,其内部的代码比较固定,可以在直接代码里对照硬件资源编写。但对于通用的操作系统,例如 Linux 内核,如何在各种机器上都可以运行?
对于嵌入式设备来说,解决获知设备问题的方法是 Devicetree。
- 文本格式(Devicetree source,DTS)和二进制格式(Flattened devicetree,FDT 或 DTB)
- 包含设备信息、MMIO 地址、中断连接方式、时钟复位电源连接方式等信息
- 与内核同时加载到内存中,跳转到各软件入口点时传入地址
- 惯例:a0 是当前核心的 hartid,a1 是内存中 FDT 的物理地址
- (U-Boot 和 OpenSBl 为了方便及复用 devicetree 已经完成的工作,也用 FDT 获得硬件配置)
Risc-V UEFI
RISC-V 机器固件也可以提供 UEFI 接口
- 提供 PCle 控制器的驱动,可以以通用方式访问 PCle 设备
- 提供 PCle Option ROM 支持,在早期启动时就可以用上外部设备的功能(显卡的显示功能、网卡的网络启动功能.)
操作系统通过 ACPI 获知硬件信息
- 比 devicetree 提供更多的信息,还提供更多接口,如通用的 PCle 设备访问,热插拔通知,电源管理接口
- 当然也比 devicetree 复杂
- (在比较简单的设备上 UEFI 也可以不提供 ACPI 而提供 devicetree)
对比
定制化的主板(常见的 RISC-V 开发板,通常不再扩展其他设备)
- 需要初始化具体主板相关硬件如 GPIO 和内存等
- 从 devicetree 获知有哪些设备
- 操作系统中需要很多设备相关的驱动
通用的主板(常见如 PC,通常需要再插入其他设备)
- 系统配置情况在开机时候是不知道的
- 需要探测(Probe)、Training(内存和 PCle)和枚举(PCle 等等即插即用设备)
- UEFI/ACPI 提供了整个主板、包括主板上外插的设备的软件抽象,通过定义的接口把这些信息传递给 OS,使 OS 不改而能够适配到所有机型和硬件
Risc-V 嵌入式设备启动的特点
通常与设备强相关
- ROM 通常是闭源的
- 早期启动流程通常是厂商提供的代码,例如 DDR 内存控制器的初始化代码,即使有 C 源码,一般也是无法理解其中很多魔法数字
缺点:对可插拔外设的兼容性
- 如 RISC-V 嵌入式设备支持 PCle 外设,需要操作系统内核包含具体硬件上的 PCle 控制器驱动