- 固件
- 嵌入式
- 操作系统
- 驱动开发
【免费下载链接】coreboot
Read-only mirror of https://review.coreboot.org/coreboot.git. Synced every hour. We don't handle Pull Requests.
导读
本文基于 coreboot 仓库中 SiFive HiFive Unleashed 主板的官方文档与移植代码,完整讲解这块「首个足以运行多用户操作系统的 RISC-V 开发板」上 coreboot 的移植结构、MSEL 引导模式配置,以及通过板内 Linux、USB/JTAG(OpenOCD)和外部 SPI 编程器三种途径烧写 32 MiB SPI Flash 的完整流程。读完本文,你将掌握 HiFive Unleashed 上 coreboot 固件从构建、选择引导模式到烧录排错的端到端实战技能。
HiFive Unleashed 与 FU540 平台概览
SiFive HiFive Unleashed 是市场上首批资源足以承载多用户操作系统的 RISC-V 开发板(原文表述为 "the first RISC-V board on the market with enough resources to run a multiuser operating system")。其核心是 SiFive FU540 SoC,从 coreboot 的设备树描述(fu540-c000.dtsi)可以看到典型配置:
- 1 个 E51 管理核心(
rv64imac,status = "disabled"),作为 boot ROM 中的引导核心; - 4 个 U54 应用核心(
rv64imafdc,支持 Sv39 MMU),对应 Kconfig 中MAX_CPUS = 5的设定; - 板载 8 GiB DDR4(
memory@80000000,reg = <0x0 0x80000000 0x2 0x00000000>); - 两个 UART、一个 I2C、三个 QSPI 控制器、一个千兆以太网控制器(GEM)。
在 coreboot 中,该主板的移植代码位于 src/mainboard/sifive/hifive-unleashed,SoC 支持代码位于 src/soc/sifive/fu540,配套的 RISC-V 架构说明可参考 Documentation/arch/riscv/index.md(其中指出 coreboot 各阶段在 M 模式下运行,ramstage 交给 payload 前会完成 trap 委派,OpenSBI 以 M 模式运行在 RAM 中)。
coreboot 移植的源码结构
主板代码布局
主板目录下的每个文件各司其职,对应 coreboot 的不同启动阶段:
| 文件 | 阶段 | 职责 |
|---|---|---|
| Kconfig | 构建期 | 定义板级选项与依赖的 SoC/特性 |
| Kconfig.name | 构建期 | 声明BOARD_SIFIVE_HIFIVE_UNLEASHED菜单项 |
| Makefile.mk | 构建期 | 按阶段挂载源文件、生成 DTB 并写入 CBFS |
| board_info.txt | 元数据 | 记录板卡分类、ROM 封装(SOIC-16)、SPI 协议、Flashrom 支持情况 |
| media.c | bootblock/romstage/ramstage | 依据 MSEL 选择引导介质(SPI Flash 或 SD 卡) |
| romstage.c | romstage | 初始化串口、时钟、DDR,随后进入 ramstage |
| mainboard.c | ramstage | 向资源分配器注册 DRAM 范围 |
| fixup_fdt.c | ramstage | 运行时修正设备树(MAC 地址、内存大小) |
| devicetree.cb | 构建期 | 声明soc/sifive/fu540芯片与 CPU 簇设备 |
| hifive-unleashed-a00.dts | 构建期 | 板级设备树源文件,编译为fallback/DTB放入 CBFS |
关键 Kconfig 配置
在 Kconfig 中,选中 HiFive Unleashed 后会自动启用以下关键选项:
SOC_SIFIVE_FU540:FU540 SoC 支持;BOARD_ROMSIZE_KB_32768:ROM 大小为 32 MiB,与板载 SPI Flash 容量一致;MISSING_BOARD_RESET:该板没有实现复位逻辑(烧录后需要手动断电重启);FLATTENED_DEVICE_TREE:启用扁平设备树支持;SPI_SDCARD:支持从 SPI 接口挂接的 SD 卡引导。
SoC 侧 Kconfig 进一步明确了体系结构细节:ARCH_RISCV_RV64、ABI 为lp64、代码模型medany、工作 hart 为 0(RISCV_WORKING_HARTID)、OpenSBI 平台为generic、OPENSBI_TEXT_START默认0x80000000(即 DRAM 起始地址)。
启动流程与内存布局
从 memlayout.ld 与各阶段代码可以看出完整的启动路径:
- bootblock(bootblock.c):在 L2LIM(
0x08000000)中运行,打印当前FU540_MSEL寄存器中的引导模式值,并完成 UART、CLINT、SPI 等最基础的初始化; - romstage(romstage.c):依次执行
console_init()、clock_init()(PLL 配置)、UART 重初始化、sdram_init()(DDR4 初始化与训练)、cbmem_initialize_empty(),最后run_ramstage(); - ramstage:在 DRAM(
0x80000000 + 256K起,2 MiB)中运行,其中内存布局还预留了 OpenSBI 空间(DRAM 起始处 256 KiB),最终由 OpenSBI 跳转到真正的 payload。
时钟配置在 clock.c 中:core PLL 输出 1 GHz(divr=0、divf=59、divq=2),DDR PLL 输出 933 MHz,GEMGXL PLL 输出 125 MHz;tlclk = coreclk / 2,SPI/UART 等外设时钟分频也在此统一配置。DDR 初始化则在 sdram.c 中通过ux00ddr_*系列寄存器操作完成写/读 leveling、范围保护等流程,sdram_size_mb()目前固定返回 8 GiB(8 * 1024)。
构建 coreboot 固件
构建前需要先配置:运行make menuconfig,在Mainboard菜单下选择SiFive→HiFive Unleashed(对应Kconfig.name中的BOARD_SIFIVE_HIFIVE_UNLEASHED布尔项)。
一个值得注意的构建细节:SiFive 的 ZSBL(第零级引导程序)只会从 GPT 分区中加载 FSBL,而 coreboot 的 bootblock 正是用来替代 FSBL 的。因此 src/soc/sifive/fu540/Makefile.mk 中有一条特殊规则,调用 util/riscv/sifive-gpt.py 把bootblock.raw.bin包装成带保护性 MBR + GPT 头 + FSBL 类型分区(分区类型 GUID 为5B193300-FC78-40CD-8002-E86C45580B47)的镜像,生成最终的bootblock.bin。同时 Makefile.mk 会用dtc把 hifive-unleashed-a00.dts 编译成 DTB,作为fallback/DTB(raw 类型)打包进 CBFS,供 ramstage 的fixup_fdt.c在运行时加载并修正。
引导模式(Boot Modes)详解
MSEL 拨码开关
HiFive Unleashed 使用标号为MSEL0~MSEL3的拨码开关组合出16 种引导模式(MSEL 值即拨码组合对应的数值)。文档重点强调以下三种:
- MSEL=1:直接跳入 SPI Flash,绕过 ROM1(ZSBL 不加载 FSBL);
- MSEL=11:从 SD 卡加载 FSBL;
- MSEL=15:默认引导模式,从 SPI Flash 上的 GPT 分区加载 FSBL/coreboot。
coreboot 对 MSEL 的处理
主板层代码 media.c 对 MSEL 的实现比文档列出的三种更细,其中注释直接说明:coreboot 的 bootblock 即 ZSBL 眼中的 FSBL,而 MSEL 决定了 FSBL 的引导介质。完整的 MSEL 映射宏如下:
| 宏 | 取值 | 含义 |
|---|---|---|
MSEL_SPI0x1 | 5、14 | 从 SPI0 以 1 线(memory-mapped)引导 |
MSEL_SPI0x4 | 6、10、15 | 从 SPI0 以 Quad(4 线)memory-mapped 引导 |
MSEL_SPI1x1 | 12 | 从 SPI1 以 1 线引导 |
MSEL_SPI1x4 | 7、13 | 从 SPI1 以 Quad 引导 |
MSEL_SPI1SD | 8 | 从挂接在 SPI1 的 SD 卡引导 |
MSEL_SPI2x1 | 9 | 从 SPI2 以 1 线引导 |
MSEL_SPI2SD | 11 | 从挂接在 SPI2 的 SD 卡引导(即文档中的 MSEL=11) |
在boot_device_init()/boot_device_ro()中,coreboot 读取FU540_MSEL(地址0x1000,见 addressmap.h):
- 命中
MSEL_SPI0x1/MSEL_SPI0x4时,通过fu540_spi_mmap()(见 spi.c)配置 QSPI0 的 memory-mapped 读模式,把 0x20000000 处 256 MiB 的 Flash 映射窗口直接作为只读引导设备(MEM_REGION_DEV_RO_INIT((void *)0x20000000, CONFIG_ROM_SIZE))。配置使用 0xEC 命令码(Quad I/O Fast Read)、4 字节地址、6 个 pad 时钟; - 命中
MSEL_SPI2SD时,通过spi_sdcard_init(&card, 2, 0)把 SD 卡封装成引导设备; - 其他取值会直接
die("Wrong configuration of MSEL\n")—— 也就是说 coreboot 的引导设备逻辑只接受上表中的值。
提示:文档中的 MSEL=1(绕过 ROM1 直跳 Flash)属于 ZSBL 层面行为,而 coreboot 的
boot_device_ro()仅支持上述表格中的取值,实际操作时请以板卡当前 MSEL 是否落在 coreboot 支持范围为准。
刷写 coreboot 固件
HiFive Unleashed 板载一颗32 MiB 的 SPI NOR Flash:ISSI IS25WP256D。板卡设备树(hifive-unleashed-a00.dts)中将其声明为compatible = "issi,is25wp256", "jedec,spi-nor",挂在 QSPI0 上,spi-max-frequency = <50000000>(50 MHz)且启用 4 线收发。烧录途径有三种。
板内编程(Internal programming)
在板上的 Linux 系统中,SPI Flash 会以 MTD 设备形式暴露,直接操作/dev/mtd0即可读写。这是最快捷的路径,适合先用 coreboot 引导起 Linux、再在系统内刷写新固件的场景。
USB/JTAG(OpenOCD)
- 将板上的 USB 端口连接到电脑;
- 板子上电后,主机侧会出现两个串口设备,例如
/dev/ttyUSB0和/dev/ttyUSB1:第一个是 JTAG 接口,第二个连接 SoC 的 UART(串口控制台); - 下载并构建 RISC-V 版本的 OpenOCD,并获取 Freedom Unleashed 对应的 OpenOCD 脚本;
- 启动 OpenOCD:
openocd -f openocd.cfg; - 通过 telnet 连接 OpenOCD 的命令行接口,输入下面示例中
>之后的内容:
> flash write_image erase unlock build/coreboot.rom 0x20000000 auto erase enabled auto unlock enabled wrote 33554432 bytes from file build/coreboot.rom in 1524.943848s (21.488 KiB/s)需要注意,写入地址0x20000000正是 FU540 的 QSPI0 Flash 内存映射基址(FU540_QSPI0FLASH)。从输出可以看到,用 OpenOCD 整片烧写 32 MiB 并不快,上例耗时约 25 分钟。文档给出的提速建议是:构建并烧写一个更小的镜像 —— OpenOCD 不会校验镜像与 Flash 的大小是否一致,因此可以显著缩短等待时间。
外部 SPI 编程器
使用 SPI 适配器配合 flashrom 进行外部编程理论上可行,但文档明确说明该路径尚未经过测试,并且板卡信息(board_info.txt)也标注Flashrom support: n。如果确实要走这条路,务必先仔细研读板卡原理图,确认 Flash 引脚与供电连接无误后再动手。
ZSBL 错误码解析
当引导失败时,ROM1 中的第零级引导程序(ZSBL)会在串口控制台上打印错误码,其格式如下(原文引用自 SiFive 论坛):
// Error codes are formatted as follows: // [63:60] [59:56] [55:0] // bootstage trap errorcode // If trap == 1, then errorcode is actually the mcause register with the // interrupt bit shifted to bit 55.即一个 64 位值:最高 4 位([63:60])表示引导阶段(bootstage),随后 4 位([59:56])是 trap 标志,低 56 位([55:0])为错误码。当trap == 1时,errorcode字段实际存放的是 RISC-V 的mcause寄存器值(其中断位被移位到 bit 55)。配合 FU540 手册与 mcause 编码表,即可据此定位 ZSBL 是在哪个阶段、因何种异常而终止引导。
移植现状与已知 TODO
官方文档列出了该移植尚未完成的事项,这也是评估"生产可用性"的重要边界,原文清单如下:
- 支持从 Flash 运行 romstage(修复栈问题)以支持引导模式 1;
- 启动 U54 核心;
- FU540 引脚配置与 GPIO 访问宏;
- 向 payload 提供序列号(例如写入设备树);
- 实现指令模拟(instruction emulation);
- 支持在 RISC-V 上引导 Linux;
- trap handler 中的 SMP 支持。
结合源码现状可以印证其中几项:例如 fixup_fdt.c 已经在做"向设备树写入板卡信息"的工作——它会从 OTP 读取序列号(otp.c 实现,OTP 位于FU540_OTP即0x10070000),以70:b3:d5:92:f0:00为基址前缀逐字节 OR 出local-mac-address属性,并按sdram_size_mb()修正memory节点的reg大小(dt_add_reg_prop写入0x80000000起始、8 GiB 大小的内存范围),最后扁平化并写入各 hart 的 HLS;而"提供序列号"仍未完成,因为 MAC 派生自 OTP 但序列号本身还没有作为独立属性暴露给 payload。另外 memlayout.ld 中 romstage 放在 L2LIM 的 128 KiB 区域内运行,而非直接从 Flash 执行,这与 TODO 中"从 Flash 运行 romstage"的现状一致。
附:可继续深入阅读的仓库路径
- 主板移植:src/mainboard/sifive/hifive-unleashed(含 media.c、fixup_fdt.c、hifive-unleashed-a00.dts)
- SoC 支持:src/soc/sifive/fu540(含 bootblock.c、clock.c、sdram.c、spi.c、memlayout.ld)
- 引导镜像打包工具:util/riscv/sifive-gpt.py
- RISC-V 架构说明:Documentation/arch/riscv/index.md
- 同系列后续板卡对比:src/mainboard/sifive/hifive-unmatched
- 固件
- 嵌入式
- 操作系统
- 驱动开发
【免费下载链接】coreboot
Read-only mirror of https://review.coreboot.org/coreboot.git. Synced every hour. We don't handle Pull Requests.
相关推荐
Tock 在 BBC HiFive Inventor 上的移植与烧录调试实战:基于 FE310-G003 RISC-V 开发板
Tock 在 BBC HiFive Inventor 上的移植与烧录调试实战:基于 FE310 G003 RISC V 开发板 BBC HiFive Inven
操作系统嵌入式嵌入式OScoreboot 刷机实战:HP Compaq 8200 Elite SFF 移植与固件烧录完全指南
coreboot 刷机实战:HP Compaq 8200 Elite SFF 移植与固件烧录完全指南 本篇技术指南以 coreboot 官方移植文档为主体,讲解
固件嵌入式操作系统驱动开发MaaAssistantArknights:明日方舟一键日常自动化指南
MaaAssistantArknights:明日方舟一键日常自动化指南 每天睡前刷两把日常、给基建换个班、把公招点完,十几分钟就这么没了,第二天原样再来一遍。M
计算机视觉GUI自动化RPA
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考