JH7110 使用U-Boot启动非 Linux 内核 RT-Smart

JH7110 是 StarFive 出的 4 核 RISC-V 64 位 CPU,主频达 1.5GHz,具有丰富的外设。

StarFive 官方目前支持了 Linux 、Linux + RT-Thread 异构 AMP 架构双系统,可以在 https://github.com/starfive-tech/VisionFive2 下找到源码。

Linux + RT-Thread 异构 AMP 架构双系统中的 RT-Thread 运行在 M 态,不支持最新的 S 态下运行的 RT-Smart 。

在 S 态下运行 RT-Smart ,需要先实现将编译好的 RT-Smart 镜像 Image 通过 U-Boot 引导到 S 态下运行,然后逐步实现 RT-Smart 启动运行,4 核均运行RT-Smart 以及最终的 Linux + RT-Thread 混合运行形态。

通过此过程可以详细学习 RT-Thread SMP、SMART 模式以及混合部署等深度知识。

本文主要介绍如果将已经编译出来的 S 态下的 RT-Smart 镜像 Image 通过 U-Boot 下载到 S 态下运行,为后续移植做好准备。

Linux 下载流程介绍

在 U-Boot 下可以运行以下命令,通过网络下载启动Linux Image:


$ setenv ipaddr 192.168.xxx.xxx; setenv serverip 192.168.xxx.xxx;

$ tftpboot ${loadaddr} image.fit;

$ bootm start ${loadaddr};bootm loados ${loadaddr};run chipa_set_linux;run cpu_vol_set; booti ${kernel_addr_r} ${ramdisk_addr_r}:${filesize} ${fdt_addr_r};

进一步分析 U-Boot 的环境变量可以获知变量的值:

  • loadaddr=0x60000000

  • kernel_addr_r=0x40200000

  • ramdisk_addr_r=0x46100000

  • fdt_addr_r=0x46000000

可以看到内核的加载地址是 0x40200000

接下来我们通过层层分解介绍内核镜像文件生成过程。

image.fit

接下重点分析一下 image.fit 文件生成流程,通过分析 Makefile 文件,找到 image.fit 文件的生成流程。

在 Linux 编译完成后, image.fit 文件生成在 work/image.fit,该文件通过 work/u-boot/tools/mkimage -f conf/visionfive2-fit-image.its -A riscv -O linux -T flat_dt work/image.fit 命令生成。

FIT 镜像是一种灵活的镜像格式,可以包含:

  • 内核镜像

  • 设备树文件

  • 根文件系统

  • 其他启动所需的文件

mkimage 是 U-Boot 提供的镜像处理工具,其中:

  • -f 参数指定 FIT 镜像的描述文件

  • .its 文件是 FIT 镜像的配置文件,定义了镜像的结构和内容

  • -A 参数指定目标架构为 RISC-V,告诉 mkimage 为 RISC-V 架构生成相应的镜像格式

  • -O 参数指定操作系统类型为 Linux,决定了镜像的加载和启动方式

  • -T 参数指定镜像类型为 flat_dt (Flattened Device Tree),表示这是一个包含设备树信息的镜像

  • image.fit 输出的 FIT 镜像文件路径,.fit 是 FIT 格式的标准扩展名

### visionfive2-fit-image.its

visionfive2-fit-image.its 文件是 FIT 镜像的配置文件,它定义了:

  1. 需要打包哪些文件(内核、设备树、根文件系统等)

  2. 这些文件的路径和属性

  3. 镜像的结构和配置


/dts-v1/;

/ {

description = “U-Boot FIT image for visionfive2”;

#address-cells = <2>;

images {

vmlinux {

description = “vmlinux”;

data = /incbin/(“../work/linux/arch/riscv/boot/Image.gz”);

type = “kernel”;

arch = “riscv”;

os = “linux”;

load = <0x0 0x40200000>;

entry = <0x0 0x40200000>;

compression = “gzip”;

};

ramdisk {

description = “buildroot initramfs”;

data = /incbin/(“../work/initramfs.cpio.gz”);

type = “ramdisk”;

arch = “riscv”;

os = “linux”;

load = <0x0 0x46100000>;

compression = “none”;

};

fdt {

data = /incbin/(“../work/linux/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-v1.3b.dtb”);

type = “flat_dt”;

arch = “riscv”;

load = <0x0 0x46000000>;

compression = “none”;

hash-1 {

algo = “sha256”;

};

};

};

configurations {

default = “config-1”;

config-1 {

description = “visionfive2 with opensbi”;

kernel = “vmlinux”;

fdt = “fdt”;

loadables = “ramdisk”;

};

};

};

visionfive2-fit-image.its 文件中我们可以看到内核镜像采用 gzip 压缩,最终位于 work/linux/arch/riscv/boot/Image.gz

### 内核镜像

Makefile 中调用 gzip -n -f -9 Image > Image.gz 命令压缩内核镜像为 Image.gz

以上梳理完成了从内核镜像压缩、打包的全过程。

## RT-Smart 打包与下载

RT-Smart 是基于 RT-Thread 操作系统衍生,面向带 MMU(Memory Management Unit),中高端应用的芯片,例如 ARM Cortex-A,MIPS,带 MMU 的 RISC-V 芯片等。RT-Smart 在 RT-Thread 操作系统的基础上启用独立、完整的进程方式,同时以混合微内核模式执行。

RT-Smart 工作在 S 态,需要 MMU 支持,和工作在 M 态的 RT-Thread 标准版有较多不同。关于 RT-Smart 适配相关的内容涉及的面很多,这里不展开,后续再详细介绍。

因为 RT-Smart 和 Linux 一样都是运行在 RISC-V 的 S 态,所以我们就可以依照 RT-Smart 编译后的内核文件,可以依照上面介绍的流程完成 gzip 镜像压缩Image.fit 文件生成。

### 下载

打包完成后,在 U-Boot 下通过网络,使用 tftp 下载下载至内存即可:


$ setenv ipaddr 192.168.xxx.xxx; setenv serverip 192.168.xxx.xxx;

$ tftpboot ${loadaddr} image.fit;

### 加载

要重点讲一下 RT-Smart 镜像加载,如直接使用与 Linux 一样的加载命令 bootm start ${loadaddr};bootm loados ${loadaddr};run chipa_set_linux;run cpu_vol_set; booti ${kernel_addr_r} ${ramdisk_addr_r}:${filesize} ${fdt_addr_r};,就会记载失败,提示:


\## Loading kernel from FIT Image at 60000000 …

Using ‘config-1’ configuration

Trying ‘vmlinux’ kernel subimage

Description:  vmlinux

Type:         Kernel Image

Compression:  gzip compressed

Data Start:   0x600000c8

Data Size:    150280 Bytes = 146.8 KiB

Architecture: RISC-V

OS:           Linux

Load Address: 0x40200000

Entry Point:  0x40200000

Verifying Hash Integrity … OK

\## Loading fdt from FIT Image at 60000000 …

Using ‘config-1’ configuration

Trying ‘fdt’ fdt subimage

Description:  unavailable

Type:         Flat Device Tree

Compression:  uncompressed

Data Start:   0x60443094

Data Size:    52430 Bytes = 51.2 KiB

Architecture: RISC-V

Load Address: 0x46000000

Hash algo:    sha256

Hash value:   10316006cf096dc6675a571d94c9223c4a433def973b9623ea306e8d57637869

Verifying Hash Integrity … sha256+ OK

Loading fdt from 0x60443094 to 0x46000000

Booting using the fdt blob at 0x46000000

\## Loading loadables from FIT Image at 60000000 …

Trying ‘ramdisk’ loadables subimage

Description:  buildroot initramfs

Type:         RAMDisk Image

Compression:  uncompressed

Data Start:   0x60024c84

Data Size:    4318097 Bytes = 4.1 MiB

Architecture: RISC-V

OS:           Linux

Load Address: 0x46100000

Entry Point:  unavailable

Verifying Hash Integrity … OK

Loading loadables from 0x60024c84 to 0x46100000

Uncompressing Kernel Image

Bad Linux RISCV Image magic!

StarFive #

运行 RT-Smart 的镜像文件报错 Bad Linux RISCV Image magic! ,而 Linux 镜像就不会。

经过分析后发现是在 U-Boot 中使用了 booti 命令启动镜像。

### booti 命令

booti 命令是 U-Boot 中专门用于启动 Linux 内核的命令,特别针对 ARM64 和 RISC-V 架构设计。

  1. 命令语法

$ booti \[addr \[initrd\[:size\]\] \[fdt\]\]

参数说明:

  • addr: 内核镜像的内存地址

  • initrd[:size]: initrd/ramdisk的地址和可选大小

  • fdt: 设备树(Device Tree)的地址

  1. 命令功能

主要作用:

  • 验证内核镜像格式:检查 Linux 内核头部的魔数和结构

  • 解析内核头部信息:获取加载地址、入口点、镜像大小等

  • 设置启动参数:配置内核启动所需的环境

  • 跳转到内核:将控制权移交给Linux内核

  1. 支持的镜像格式:
  • Image:未压缩的内核镜像

  • Image.gz:gzip压缩的内核镜像

  • zImage:自解压的内核镜像

  1. 内核头部验证

booti命令会验证Linux内核的64字节头部结构:


struct linux_image_header {

uint32_t code0;        /\* 可执行代码 \*/

uint32_t code1;        /\* 可执行代码 \*/

uint64_t text_offset;  /\* 镜像加载偏移 \*/

uint64_t image_size;   /\* 有效镜像大小 \*/

uint64_t flags;        /\* 内核标志 \*/

uint32_t version;      /\* 头部版本 \*/

uint32_t res1;         /\* 保留 \*/

uint64_t res2;         /\* 保留 \*/

uint64_t res3;         /\* 保留 \*/

uint32_t magic;        /\* 魔数1: “RISCV” \*/

uint32_t magic2;       /\* 魔数2: “RSC\\x05” (0x05435352) \*/

};

  1. 使用示例

基本用法:


\# 指定内核地址

$ booti 0x40200000

  1. 与其他启动命令的区别

| 命令 | 适用架构 | 镜像格式 | 验证机制 |

| -------- | ---------- | ---------- | ---------- |

| booti | ARM64/RISC-V | Image/Image.gz | 严格头部验证 |

| bootz | ARM32 | zImage | 简单验证 |

| bootm | 通用 | uImage/FIT | U-Boot头部验证 |

| go | 通用 | 任意 | 任意 | 无验证 |

  1. 常见错误信息:

\# 魔数错误

“Bad Linux RISCV Image magic!”

\# 镜像大小错误

“RISCV Image size exceeded”

\# 加载地址错误

“RISCV Image load address out of range”

  1. 在U-Boot配置中:

CONFIG_CMD_BOOTI=y      # 启用booti命令

CONFIG_RISCV=y          # RISC-V架构支持

CONFIG_OF_LIBFDT=y      # 设备树支持

  1. 内核镜像转换

转换为二进制格式

objcopy -O binary -R .note -R .note.gnu.build-id -R .comment -S vmlinux Image

经过以上分析,我们可以理解到,在使用 booti 命令加载 RT-Smart 镜像时因为没有匹配到魔数,所以启动失败了,需要更换为 go 启动。

### 启动 RT-Smart 镜像

更换启动命令后,使用 go 命令加载 image.fit 文件后即可启动 RT-Smart。


$ bootm start ${loadaddr};bootm loados ${loadaddr};run chipa_set_linux;run cpu_vol_set; go ${kernel_addr_r} ${fdt_addr_r};

\## Loading kernel from FIT Image at 60000000 …

Using ‘config-1’ configuration

Trying ‘vmlinux’ kernel subimage

Description:  vmlinux

Type:         Kernel Image

Compression:  gzip compressed

Data Start:   0x600000c8

Data Size:    150280 Bytes = 146.8 KiB

Architecture: RISC-V

OS:           Linux

Load Address: 0x40200000

Entry Point:  0x40200000

Verifying Hash Integrity … OK

\## Loading fdt from FIT Image at 60000000 …

Using ‘config-1’ configuration

Trying ‘fdt’ fdt subimage

Description:  unavailable

Type:         Flat Device Tree

Compression:  uncompressed

Data Start:   0x60443094

Data Size:    52430 Bytes = 51.2 KiB

Architecture: RISC-V

Load Address: 0x46000000

Hash algo:    sha256

Hash value:   10316006cf096dc6675a571d94c9223c4a433def973b9623ea306e8d57637869

Verifying Hash Integrity … sha256+ OK

Loading fdt from 0x60443094 to 0x46000000

Booting using the fdt blob at 0x46000000

\## Loading loadables from FIT Image at 60000000 …

Trying ‘ramdisk’ loadables subimage

Description:  buildroot initramfs

Type:         RAMDisk Image

Compression:  uncompressed

Data Start:   0x60024c84

Data Size:    4318097 Bytes = 4.1 MiB

Architecture: RISC-V

OS:           Linux

Load Address: 0x46100000

Entry Point:  unavailable

Verifying Hash Integrity … OK

Loading loadables from 0x60024c84 to 0x46100000

Uncompressing Kernel Image

\## Starting application at 0x40200000 …

heap: \[0x0x000000008028a8f0 - 0x0x0000000080a8a8f0\]

\\ | /

- RT -     Thread Operating System

/ | \\     5.2.1 build Jul 27 2025 23:12:45

2006 - 2024 Copyright by RT-Thread team

msh />

由于目前 RT-Smart 未使用设备树,也可以使用 bootm start ${loadaddr};bootm loados ${loadaddr};run chipa_set_linux;run cpu_vol_set; go ${kernel_addr_r}; 启动。

完成镜像下载及启动后,就可以开始下一步的适配工作了。

5 个赞
4 个赞