跳到主要内容

FASTBOOT 异构 RAMDISK

在快启流程中,除了启动 BOOT、KERNEL 阶段的性能优化,还有启动到内核中 ROOTFS 加载速度提升。

SDK 支持异构 RAMDISK 模式,相较于传统快启 RAMDISK 模式,异构 RAMDISK 通过异构系统,加速 RAMDISK 的读取和解压启动。并且保证系统的独立与并行。

传统快启 RAMDISK 的加载流程如下

  • BOOT 初始化 FLASH,加载内核和 RAMDISK
  • 加载后将 FLASH 驱动,DMA 参数保存到预留内存,跳转进入内核
  • Linux 在初始化阶段,启动一个内核线程使用 BOOT 阶段预留的 RAMDISK 压缩的地址,开始解压,使用硬件或软件解压
  • 解压后启动 RAMDISK 中的应用程序,执行应用

传统 RAMDISK 模式

传统快启 RAMDISK 的缺点也很明显,需要内核参与,需要预留内存给 RAMDISK 使用,RAMDISK 需要打包在一起,OTA 更新 KERNEL 的时候也需要 OTA RAMDISK。

异构 RAMDISK 通过最大化系统资源,在 BOOT 阶段就启动双核系统,单独使用一个核心操作 FLASH 进行 RAMDISK 的读取解压操作,此时内核无需调度解压读取,当 RAMDISK 解压完成的同时通知内核可以挂载 RAMDISK,此时直接启动 RAMDISK 中的应用程序。

其优点如下:

  • 无需魔改内核,增加解压线程
  • 复用内核 RAMDISK 流程,对于内核来说与主线标准 RAMDISK 无差异
  • RAMDISK 可以放到分区上,支持直接 dd 命令 OTA 更新 RAMDISK
  • SDK 配置简单,SDK 支持自动打包 RAMDISK,支持 Quick Config 一键切换

异构 RAMDISK

异构 RAMDISK 功能配置

Linux 端相关配置

设备树预留内存配置

首先设备树需要配置 RAMDISK 的预留内存,与标准配置无异

linux,initrd-start = <0x47800000>;
linux,initrd-end = <0x48000000>;

RAMDISK 预留内存

预留内存的大小需要参考 RAMDISK 的大小,一般布局如下:

RAMDISK 数据布局

举个例子,RAMDISK 的大小是 6M,经过 LZ4 压缩后的大小是 2M,所以这里需要配置总共 8M 内存

  • RAMDISK 解压后的数据:0x47800000~0x47e00000
  • RAMDISK 压缩后的数据:0x47e00000~0x48000000
  • 设备树预留内存的配置:0x47800000~0x48000000

这部分内存在内核加载完成 RAMDISK 后会释放,所以不需要担心这部分内存有浪费或者无法被使用到

如果系统使用多媒体内存池,建议将 RAMDISK 的地址安排到多媒体内存池之前,多媒体内存池是从内存末尾申请的,如果内存末尾配置了 RAMDISK,则会导致多媒体内存池占用在内存中部,造成内存碎片化。一般建议可释放的内存连续排布,释放后可以改善内存碎片化的情况。

如下图,多媒体内存池占用了 32M 的内存,则按照之前的排布修改如下

  • RAMDISK 解压后的数据:0x45800000~0x45e00000
  • RAMDISK 压缩后的数据:0x45e00000~0x46000000
  • 设备树预留内存的配置:0x45800000~0x46000000

带多媒体内存池的放啊

设备树驱动配置

对于使用 RAMDISK 的情况,一般来说存储控制器驱动加载就可以延后了,因为存储控制器驱动比较占用启动时间,需要通讯识别等操作。所以推荐对于系统存储的控制器节点配置为 deferred-device,例如这里将 SPIF 控制器配置为 deferred-device

SPIF 控制器配置 deferred-device

内核选项配置

内核还需要配置启用 RAMDISK 功能

CONFIG_BLK_DEV_INITRD

配置位于

General setup  --->
[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support

RAMDISK 内核配置

由于不需要内核解压 RAMDISK,所以下面的 RAMDISK 压缩配置可以全部取消。

# CONFIG_RD_GZIP is not set
# CONFIG_RD_BZIP2 is not set
# CONFIG_RD_LZMA is not set
# CONFIG_RD_XZ is not set
# CONFIG_RD_LZO is not set
# CONFIG_RD_LZ4 is not set
# CONFIG_RD_ZSTD is not set

配置异构 RAMDISK 内核服务模块

CONFIG_AW_PARALLEL_RAMDISK=y
CONFIG_AW_RAMDISK_DELAYINIT_RPROC_NAME="6010000.e907_rproc"

内核配置选项是

General setup  --->
[*] Parallel decompress ramdisk
(6010000.e907_rproc) Ramdisk Delay Init Rproc Name

RAMDISK 内核服务模块

备注

这里的 Ramdisk Delay Init Rproc Name 配置的名字是异构核心的名字,可以在系统启动后运行

ls /dev/rpmsg_ctrl*

获取异构核的名字

这里的 e907_rproc@06010000 就是异构核心的名字,填入的时候需要改一下格式,改为 6010000.e907_rproc 即可

如果不方便启动系统看配置,可以检查内核设备树 bsp/configs/linux-6.6-xuantie/sun252iw1p1.dtsi

内核设备树看名称

RTOS 端功能配置

异构 RAMDISK 的主要操作基本上在 RTOS 端,所以 RTOS 端的配置需要更加注意。

配置 RTOS 存储驱动

SPI NOR 存储驱动配置

Drivers Options  --->
soc related device drivers --->
AW Flash Drivers --->
[*] Tina Flash Read
Select Storage Type (SPINOR) --->
[*] Flash Wait for Flag
(0) Flash Wait RTC Data Index
(2) Flash Wait RTC Data Bit
(4064) Flash GPT Offset
(128) Flash Boot Package Offset

存储配置驱动项如下:

CONFIG_DRIVERS_AW_FLASH_READ=y
CONFIG_DRIVERS_AW_FLASH_READ_SPINOR=y
# CONFIG_DRIVERS_AW_FLASH_READ_EMMC is not set
# CONFIG_DRIVERS_AW_FLASH_READ_SPINAND is not set
CONFIG_DRIVERS_AW_FLASH_WAIT_FLASH=y
CONFIG_DRIVERS_AW_FLASH_WAIT_FLASH_WAIT_INDEX=0
CONFIG_DRIVERS_AW_FLASH_WAIT_FLASH_WAIT_BIT=2
# CONFIG_DRIVERS_AW_FLASH_WRITE is not set
CONFIG_DRIVERS_AW_FLASH_GPT_OFFSET=4064
CONFIG_DRIVERS_AW_FLASH_BOOTPKG_OFFSET=128
# CONFIG_DRIVERS_AW_FLASH_DEBUG is not set
# CONFIG_DRIVERS_AW_FLASH_USE_HWLOCK is not set

RTOS Flash 驱动配置

  1. 选择 CONFIG_DRIVERS_AW_FLASH_READ 驱动
  2. 配置使用的 FLASH 类型,这里选择 SPI NOR
  3. 配置 [*] Flash Wait for Flag,设置 FLASH 的等待标志,这里按默认即可
  4. 配置 FLASH 的 GPT OFFSET,配置需要与 FLASH MAP 一致,需要找到 uboot-board.dts 中的 flash_map 参考下图配置即可

FLASH MAP 配置

配置 RTOS 解压组件

一般 RAMDISK 支持多组压缩格式,这里就以常用的 LZ4 为例,示意驱动配置。进入如下配置界面:

System components  --->
thirdparty components --->
[*] Compress Support --->
[*] LZ4 Compress

配置项目如下:

CONFIG_COMPONENTS_COMPRESS=y
CONFIG_COMPONENTS_COMPRESS_LZ4=y

配置 LZ4 压缩格式

如果需要使用其他压缩格式,这里也可以配置其他压缩,勾选上即可,组件会自动识别加载的 RAMDISK 是哪一种压缩格式。

配置 RTOS 异构 RAMDISK 组件

配置完成后,另外还需要配置 RTOS 的异构 RAMDISK 组件,配置路径如下所示:

System components  --->
aw components --->
AW Fastboot Preloads Compenents --->
[*] Fastboot Preloads Compenents
(spif) Preloads compenents rpmsg notify name
Select Preload Components Type (Ramdisk) --->
[*] Load kernel ramdisk
(0x47e00000) kernel ramdisk load address
(0x200000) kernel ramdisk compress size
(0x47800000) kernel ramdisk decompress address
(0x600000) kernel ramdisk decompress size

相关的地址需要参考设备树配置的预留地址。配置项如下

CONFIG_PRELOAD_COMPENENTS=y
CONFIG_PRELOAD_COMPENENTS_RPMSG_NOTIFY_NAME="spif"
CONFIG_PRELOAD_COMPENENTS_RPMSG_NOTIFY_PARA=""
CONFIG_USE_PRELOAD_RAMDISK=y
# CONFIG_USE_PRELOAD_ROOTFS is not set
CONFIG_PRELOAD_RAMDISK=y
CONFIG_RAMDISK_LOADADDR=0x47e00000
CONFIG_RAMDISK_PARTITION_SIZE=0x200000
CONFIG_RAMDISK_DECOMPRESS_ADDR=0x47800000
CONFIG_RAMDISK_DECOMPRESS_SIZE=0x600000

组件配置方式

增加异构 RAMDISK 启动流程

修改 RTOS 的 main 函数,新增 RAMDISK 启动流程代码,例如在 rtos/lichee/rtos/projects/v861_e907/bga_perf1/src/main.c 中,找到 cpu0_app_entry 函数,这样添加代码

#ifdef CONFIG_PRELOAD_COMPENENTS
extern void flash_load_data_async(void);
flash_load_data_async();
#endif

增加加载流程

配置打包 RAMDISK 功能

SDK 提供一套简单的脚本去打包 RAMDISK,在执行 PACK 命令的时候,自行去打包 RAMDISK,生成 RAMDISK 镜像,配置方法如下:

首先复制 device/config/chips/v861/configs/default/ramdisk 文件夹到板级目录下,作为 RAMDISK 的基础环境。

然后在板级目录下新建一个 ramdisk_json 配置文件作为打包配置文件。使用脚本自动打包 RAMDISK 环境。

ramdisk_list

{
"compress": "lz4",
"src": "${configs}/ramdisk",
"auto_copy": {
"lib/ld-musl-riscv32.so.1": "${rootfs}/lib/ld-musl-riscv32.so.1",
"lib/libgcc_s.so.1": "${rootfs}/lib/libgcc_s.so.1",
"usr/lib/libc.so": "${rootfs}/usr/lib/libc.so"
},
"cmd": [
"mkdir -p ${src}/bin",
"find ${rootfs}/bin/ -type l -exec cp -d {} ${src}/bin \\;",
"[ -e ${rootfs}/bin/busybox ] && cp ${rootfs}/bin/busybox ${src}/bin"
]
}

这个配置的含义解释:

  1. compress: 指定了 RAMDISK 的压缩格式,这里使用的是 lz4。LZ4 是一种快速压缩算法,通常用于高效地压缩数据,尤其是在 RAMDISK 中能显著减少内存占用。
  2. src: 这是 RAMDISK 固件的源文件位置。${configs}/ramdisk 是一个变量,表示实际路径应该在配置文件中定义。
  3. auto_copy: 这个字段定义了一系列文件的自动复制操作,将源文件复制到目标文件系统的指定位置。具体文件及其对应的目标路径。这些操作确保了 RAMDISK 中所需的共享库和可执行文件被正确地放置在文件系统的相应位置。
  4. cmd: 这是一个命令数组,包含一些 shell 命令,要在执行时运行。命令的功能如下:
    • mkdir -p ${src}/bin: 创建一个名为 bin 的目录,位于指定的 RAMDISK 源位置。如果路径中某些目录不存在,-p 参数将确保创建它们。
    • find ${rootfs}/bin/ -type l -exec cp -d {} ${src}/bin \\;: 查找 ${rootfs}/bin/ 目录下的所有符号链接,并将其复制到刚刚创建的 ${src}/bin 目录中。-d 参数确保复制符号链接而不是链接指向的文件。
    • [ -e ${rootfs}/bin/busybox ] && cp ${rootfs}/bin/busybox ${src}/bin: 如果 ${rootfs}/bin/busybox 存在,则将其复制到 ${src}/bin 目录中。
备注

这里 auto_copy 主要是拷贝用户程序和相关的依赖库到 RAMDISK 中,如果有新增的 app 需要在这里添加,注意不要让 RAMDISK 变太大,否则加载速度可能会更慢。

cmd 主要是拷贝 busybox 运行环境到 RAMDISK 中,一般不需要改。

如果需要新增一个 app 打包到 RAMDISK 中,在 auto_copy 里新增相关的拷贝即可。如果文件不需要拷贝,可以直接放到 ramdisk 文件夹中,也会打包进去。

配置打包 RAMDISK 分区

修改分区表,新增一个 RAMDISK 分区,名称必须是 ramdisk,大小依照打包出的文件大小可以裁剪

新增分区

新增分区之后别玩同步分区布局到设备树,执行 quick_config sync_partition_{xxx}_to_bootargs 同步修改到 bootargs 中.

否则会出现分区表不同步导致加载不上 rootfs 的问题

加载不上 rootfs

配置 RAMDISK 启动脚本

设备树,配置 RAMDISK 和正常 INIT 的脚本为 RAMDISK 的路径,这样配置使 Kernel 初始化可以找到运行的 init 环境。

配置 init 路径

修改 RAMDISK 中的 init 脚本,路径 device/config/chips/v861/configs/bga_perf1/ramdisk/init

RAMDISK init 脚本

可以在红框处添加应用的启动命令,当 RAMDISK 初始化的时候便去执行相关命令。

添加启动命令

测试 RAMDISK 功能

此时编译系统,打包烧录,查看启动时的大核和小核日志。

在小核的日志中,可以看到 RAMDISK 的相关打印

RAMDISK 相关打印

可以看到 Linux 端也是通过 RAMDISK 启动的

Linux 端打印

至此快启异构 RAMDISK 功能就算配置完毕了

常见问题

RTOS 打印 get_boot_param failed

get_boot_param failed

请确认配置 FLASH 的 GPT OFFSET,配置需要与 FLASH MAP 一致,需要找到 uboot-board.dts 中的 flash_map 参考下图配置即可

FLASH MAP 配置