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 控制器驱动