AMP 异构 启动控制与资源管理
小核启动和初始化
首先说明下小核启动和小核初始化的概念,小核的启动指的是让小核开始运行代码,而小核的初始化则指的是 Linux remoteproc 框架初始化 remoteproc 的操作,完成初始化后才可以和小核通信。
目前 SDK 里支持如下几种小核启动和初始化方式:
- 小核在 bootloader 阶段启动,在 Linux 内核 阶段初始化
- 小核在 bootloader 阶段启动,在 Linux 应用 阶段初始化
- 小核在 Linux 应用阶段启动并初始化
:::tips V821 注意
一般主要使用第1种方式和第3种方式,由于 V821 小核负责 WIFI 功能,所以当前SDK默认使用第1种方式。NAND 常电方案则是内核启动小核。
::: SDK 默认方案如下配置
| 方案 | 读取方式 | 启动从阶段 | 镜像位置 |
|---|---|---|---|
| SPI NOR | 从分区表读取镜像 | BOOT0 阶段 | 分区表 riscv0 分区 |
| SPI NOR 安全 | 从分区表读取镜像 | U-Boot 阶段 | 分区表 riscv0 分区 |
| SPI NOR 快起 | 从分区表读取镜像 | BOOT0 阶段 | 分区表 riscv0 分区 |
| SPI NAND | 内核启动小核 | 内核阶段启动小核 | 分区表 riscv0 分区 |
| SPI NAND 快起 | 从 RAW 分区读取镜像 | BOOT0 阶段 | NAND RAW 分区固定地址 |
| MMC | 从分区表读取镜像 | BOOT0 阶段 | 分区表 riscv0 分区 |
| MMC 快起 | 从分区表读取镜像 | BOOT0 阶段 | 分区表 riscv0 分区 |
| 卡量产 | 从 boot_package 读取镜像 | BOOT0 阶段 | device/config/chips/v821/configs/default/boot_package.cfg 配置镜像 |
BOOT0 启动小核
BOOT0 启动小核包括两个过程:
- 读取 RTOS 镜像
- 配置小核启动地址,时钟,复位
读取 RTOS 镜像
RTOS 镜像支持从两个地方读取:
- 从
boot_package读取镜像(支持 NOR,MMC,NAND) - 从分区表读取镜像(对于 NAND 是从 RAW 分区读取)
配置小核启动地址,时钟,复位
读取到 elf 固件后,便可 以从 boot_e907 函数中解析出固件的运行地址,将其放到目标地址执行。
brandy/brandy-2.0/spl/board/sun300iw1p1/board.c
void boot_e907(phys_addr_t base, unsigned long fdt_addr)
{
u32 run_addr = 0;
/* assert e907 */
sunxi_e907_clock_reset();
/* get boot address */
run_addr = elf_get_entry_addr(base);
/* load elf to target address */
load_elf_image(base);
flush_dcache_all();
/* de-assert e907 */
sunxi_e907_clock_init(run_addr);
}
U-Boot 启动小核
大核 U-Boot 的 menuconfig 配置
采用 U-Boot 启动小核的方法,大核 Linux 环境下 U-Boot 需要选中对应配置来提供启动小核的命令,SDK 中已默认选中,此章节对所需配置进行介绍。
进入 Linux 环境的 U-Boot 目录,可采用 cboot 命令快速切换到该目录,make menuconfig 选中以下配置:
CONFIG_CMD_SUNXI_BOOTRV=y
CONFIG_BOOT_RISCV=y
小核固件的分区信息和小核启动命令
sys_partition.fex中添加小核固件的分区信息,内容如下:
sys_partition.fex | sys_partition_nor.fex
[partition]
name = riscv0
size = 2048
downloadfile = "amp_rv0.fex"
user_type = 0x8000
提示
其中 size 以 128 对齐,可根据实际的小核固件文件大小调整。
:::
env.cfg文件中添加启动小核的命令并修改bootcmd环境变 量,内容如下:
env.cfg
boot_riscv=bootrv 82000000 200000 0 riscv0 riscv0-r
bootcmd=run setargs_nand boot_riscv boot_normal
提示
U-Boot 中 bootrv 命令的参数分别为固件文件加载内存地址、加载内存区域大小、小核ID、小核固件分区名、小核固件备份分区名,其中加载内存区域大小需要大于等于小核固件大小。
Linux 设备树中,fw-partition-sectors 需要配置与其相对应
:::
小核RTOS环境配置
小核在 U-Boot 阶段启动时,RTOS 端 OpenAMP 框架中部分逻辑是需要等待 Linux 端初始化小核后才能继续执行的,因此小核 RTOS 环境需要启用配置CONFIG_SLAVE_EARLY_BOOT。
注意
小核 RTOS 端 OpenAMP 框架默认是放在线程中初始化的,在开启上述配置后会导致用户程序先于 OpenAMP 框架初始化完成前运行(不开启上述配置时也有可能,但概率较低),用户编写代码时需要注意这一点。
:::
Linux 启动和初始化小核
Linux 里启动和初始化小核的操作可分为如下 2 种组合:
- 启动和初始化小核,一般用于 bootloader 阶段未启动小核的场景
- 初始化小核,一般用于 bootloader 阶段已启动小核的场景
备注
目前不会出现Linux内核只启动小核但不初始化小核的情况。
:::
RemoteProcessor (remoteproc)
remoteproc 是一种 Linux 内核框架,用于支持多核处理器系统中,大核与小核之间的协作。它提供了启动和管理外部处理器(如 DSP、FPGA、小核等)的机制,在一个多核系统中,通常大核负责运行 Linux,而小核则运行其他任务(如 RTOS 或专用的固件)。这个框架特别适用于那些带有多个处理单元的系统,其中大核和小核需要进行互相通信和同步。
主要功能
- 启动小核:
remoteproc允许 Linux 大核启动并管理小核。它负责加载固件、启动小核、以及在必要时停止小核。大核和小核之间的协调通常是通过共享内存、消息传递等方式来完成的。 - 固件管理:
remoteproc负责加载固件到小核内存,并启动小核进行执行。固件可以通过设备树或其他配置文件来指定。 - 进程隔离:在多核系统中,大核和小核之间可以通过
remoteproc实现不同的进程隔离,从而确保每个核的任务不互相干扰。 - 共享内存和通信:
remoteproc提供了共享内存区域和通信接口,确保大核和小核之间可以高效地交换数据和同步状态。 - 生命周期管理:
remoteproc提供了小核的生命周期管理功能,包括小核的启动、暂停、重启和停止等操作,确保系统在运行时能够可靠地管理多个处理器的状态。
工作流程
- 固件加载(若 Bootloader 未加载):大核通过
remoteproc框架加载小核固件,通常固件文件包含了用于小核的启动程序及其必要的初始化代码。 - 小核启动(若 Bootloader 未加载):加载固件后,
remoteproc启动小核,并为其分配必要的资源(如内存、寄存器等)。 - 运行和通信:小核启动后,它可以开始执行固件中的任务。大核与小核之间可以通过共享内存、消息队列、信号等进行通信。
- 小核管理:大核可以随时暂停、恢复、重启或停止小核,以便进行系统管理或处理异常情况。
主要组件
- remoteproc 驱动:负责管理小核的启动、停止、加载固件等任务。
- 固件加载器:负责将固件从文件系统加载到内存中,并提供适当的接口供
remoteproc使用。 - 设备树(Device Tree):通过设备树中的配置指定大核和小核的通信方式及固件位置。
remoteproc 状态
在 Linux 的 remoteproc 框架中,remoteproc 有七种状态,分别如下:
- offline:关机状态,表示小核没有启动,处于关机状态。
- suspended:休眠状态,小核已经启动,但当前被暂停或挂起。
- running:运行状态,小核处于正常运 行状态,正在执行固件中的任务。
- crashed:崩溃状态,小核进入了异常状态,通常表示发生了错误或崩溃。此时需要恢复小核。
- deleted:删除状态,该状态表明小核已经被删除,这种情况通常不会出现。
- attached:附加状态,表示小核已在更早的阶段启动,且 Linux 已初始化
remoteproc。一般来说,小核会在 Linux 系统启动时进入此状态。 - detached:分离状态,表示小核已在更早的阶段启动,如在 bootloader 阶段,但还未初始化
remoteproc。
在实际开发中,通常会接触到以下四种状态:
- offline:表示小核未启动。
- running:表示小核正在运行。
- attached:表示小核已被 Linux 初始化。
- detached:表示小核在 bootloader 阶段已启动,但尚未初始化
remoteproc。
目前的 SDK 默认在 bootloader 阶段启动小核,在 Linux 内核阶段初始化小核。因此,在大核 Linux 系统完全启动后,小核的状态通常会为 attached。
remoteproc生命周期管理相关命令
remoteproc 生命周期管理一般会用到两个命令,分别用于启动和停止 remoteproc,具体如下:
- 启动 remoteproc:
echo start > /sys/class/remoteproc/remoteprocx/state - 停止 remoteproc:
echo stop > /sys/class/remoteproc/remoteprocx/state
其中的 x 表示 remoteproc 的 ID,在 Linux 系统的 remoteproc 框架中是唯一的。如果一个具体芯片平台有多个不同架构的小核,那么 remoteproc 的 ID 是不会重复的。在执行 start remoteproc 时,系统会根据 remoteproc 当前的状态执行不同的操作:
- 如果 remoteproc 处于 offline 状态,系统会执行小核的启动和初始化操作,执行完成后,remoteproc 会进入 running 状态。
- 如果 remoteproc 处于 detached 状态(意味着小核已在 bootloader 阶段启动),系统只会执行小核的初始化操作,执行完成后,小核将进入 attached 状态。
查看 remoteproc 状态
- 查看 remoteproc 状态:
cat /sys/class/remoteproc/remoteprocx/state - 查看对应 remoteproc 的节点名:
cat /sys/class/remoteproc/remoteprocx/name,该命令可以帮助识别具体的小核,根据节点名在 dts 文件中查找对应的小核信息。
bootloader 阶段已启动小核
在这种情况下,Linux 系统只需要初始化小核即可。具体操作如下:
- 在内核阶段初始化小核时,只需要在对应的 remoteproc 节点中增加
auto-boot空属性。 - 在应用阶段初始化小核时,只需执行
start remoteproc命令即可启动小核。
bootloader 阶段未启动小核
在这种情况下,小核的固件通常会保存在文件系统中。在应用阶段,启动和初始化小核时,只需执行 start remoteproc 命令即可。
注意
虽然在此情况下增加 auto-boot 属性可以让内核尝试启动和初始化小核,但由于 remoteproc 框架的初始化过程发生得较早,而此时文件系统还未完全加载,因此会导致启动失败。通常情况下,内核并不会在此时启动和初始化小核。
:::
Linux 与小核建立通讯
当小核启动完成,会等待大核解析 elf 固件,大核将解析 elf 固件的地址表,获取到 .resource_table section 的偏移地址,然后对这个地址的结构体赋值,将大核预留的共享内存地址配置给小核,体现在日志中便是这部分打印:

大核将维护与小核一致的结构体,直接在小核的对应地址进行赋值,将资源表初始化给小核

当赋值完成,小核便拥有了大核分配的可使用的地址,此时便可开始异构通讯。
Linux 调试节点
在 remoteproc 框架中的 remoteproc_debugfs.c 和 remoteproc_sysfs.c 中分别创建了debugfs和sysfs节点。
sysfs 节点
在remoteproc框架中向用户提供了coredump、recovery、firmware、state、name节点,其路径如下:
/sys/class/remoteproc/remoteproc0/state
/sys/class/remoteproc/remoteproc0/name
/sys/class/remoteproc/remoteproc0/firmware
/sys/class/remoteproc/remoteproc0/recovery
/sys/class/remoteproc/remoteproc0/coredump
其作用分别为:
- state:通过输入不同的命令来控制远程处理器的状态;
- name:显示远程处理器的名称;
- firmware:通过输入来修改固件名称;
- recovery:recovery 的内容可以是 enabled、disabled 或 recovery 三者之一,用于控制恢复机制的行为。
- enabled 表示远程处理器将在崩溃时可以自动恢复;
- disabled 表示远程处理器在崩溃时将保持崩溃状态;
- recovery 表示如果远程处理器处于崩溃状态,此功能将触发立即恢复,而不用手动更改或检查恢复状态(启用/禁用)。
- coredump:coredump的内容可以是 inline、disabled 或default三者之一,用于控制核心转储机制的行为。
- inline 表示coredump 不会被复制到单独的缓冲区,恢复过程必须等到数据被用户空间读取;
- disabled 表示这是默认的核心转储机制。恢复将在不收集任何转储的情况下继续进行;
- enabled 表示当 remoteproc 崩溃时,整个核心转储将被复制到一个单独的缓冲区并暴露给用户空间。
debugfs 节点
在 remoteproc 框架中向用户提供了name、recovery、crash 、resource_table、carveout_memories、coredump、aw_trace_log、aw_trace_event节点,其路径如下:
/sys/kernel/debug/remoteproc/remoteproc0/name
/sys/kernel/debug/remoteproc/remoteproc0/recovery
/sys/kernel/debug/remoteproc/remoteproc0/crash
/sys/kernel/debug/remoteproc/remoteproc0/resource_table
/sys/kernel/debug/remoteproc/remoteproc0/carveout_memories
/sys/kernel/debug/remoteproc/remoteproc0/coredump
/sys/kernel/debug/remoteproc/remoteproc0/aw_trace_log
/sys/kernel/debug/remoteproc/remoteproc0/aw_trace_event
其作用分别为:
- name:显示远程处理器的名称;
- recovery:recovery 的内容可以是 enabled、disabled 或 recovery 三者之一,用于控制恢复机制的行为。
- enabled 表示远程处理器将在崩溃时可以自动恢复;
- disabled 表示远程处理器在崩溃时将保持崩溃状态;
- recovery 表示如果远程处理器处于崩溃状态,此功能将触发立即恢复,而不用手动更改或检查恢复状态(启用/禁用)。
- crash:记录系统崩溃时候的有关信息;
- resource_table:记录了小核的资源信息(资源表);
- carveout_memories:记录小核的内存分配情况;
- coredump:coredump的内容可以是 inline、disabled 或default三者之一,用于控制核心转储机制的行为。
- inline 表示coredump 不会被复制到单独的缓冲区,恢复过程必须等到数据被用户空间读取;
- disabled 表示这是默认的核心转储机制。恢复将在不收集任何转储的情况下继续进行;
- enabled 表示当 remoteproc 崩溃时,整个核心转储将被复制到一个单独的缓冲区并暴露给用户空间。
- aw_trace_log:查看小核系统运行过程中的日志。
- aw_trace_event:查看小核的trace event
小核AMP控制台
当前SDK中小核的控制台分为 2 个,一个是通过串口进入的串口控制台,另外一个 是在 Linux 端通过 amp_shell 命令进入的 AMP 控制台,AMP 控制台主要提供在 Linux 端远程执行小核固件里的命令并查看命令的输出结果,一般在实际设备未引出小核串口的情况下使用。而串口控制台除了执行命令和查看命令输出结果外还可查看小核系统运行过程中打印的一些日志。AMP控制台配置步骤如下。
配置信息
- 大核 Linux 环境需要启用内核配置
CONFIG_AW_RPMSG_CTRL

- 软件包配置
CONFIG_PACKAGE_amp_shell

小核 RTOS 环境需要启用如下配置:
- CONFIG_RPMSG_CLIENT
- CONFIG_MULTI_CONSOLE
- CONFIG_UART_MULTI_CONSOLE
- CONFIG_UART_MULTI_CONSOLE_AS_MAIN
- CONFIG_RPMSG_MULTI_CONSOLE
- CONFIG_RPMSG_CONSOLE_CACHE
使用示例
在 Linux 终端运行 amp_shell -d /dev/rpmsg_ctrl-e907_rproc@43030000 可以进入 RV 核AMP控制台。
amp_shell -d /dev/rpmsg_ctrl-e907_rproc@43030000
amp_shell 命令参数说明:
-d devname:指定要与哪个远端处理器建立连接,可使用ls /dev/rpmsg_ctrl*查看可用的设备文件。-e: cmd:不进入交互式控制台,只执行命令
提示
可使用命令 amp_exit 退出 AMP 控制台
:::
注意事项
如果出现 Failed to create auto free endpoint 则是小核没有开启 CONFIG_RPMSG_MULTI_CONSOLE 和 CONFIG_RPMSG_CONSOLE_CACHE 配置

小核日志获取
由于 AMP 控制台只能用来执行命令并查看命令输出结果,因此在未引出小核串口的情况下若需要获取小核系统运行过程中打印的日志则需要使用 AMP trace log 功能。
AMP trace log 的实现机制说明:
- 异构系统会从 DDR SDRAM 中开辟(carveout)出一段空间用作小核的运行内存,代码段、数据段、BSS段、堆栈都在这段内存当中;
- 小核在 BSS 段中定义一个全局的数组
amp_log_buffer,将这个trace buffer的address和len,通过resource table传递给大核 - 小核的
printf打印日志接口会同步将日志写入amp_log_buffer - 大核解析
resource table获得trace buffer的address和len,然后从相应的内存中,读取trace log
cat /sys/kernel/debug/remoteproc/remoteproc0/aw_trace_log

如果希望大核实时输出小核的日志到控制台,使用这个命令即可
tail -f /sys/kernel/debug/remoteproc/remoteproc0/aw_trace_log > /dev/console &
如果出现找不到 tail 命令,需要在 make menuconfig 将其开启。