ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

全志SoC异构多核启动与调试实践:RISC-V从核电源时钟与OpenSBI

全志SoC异构多核启动与调试实践:RISC-V从核电源时钟与OpenSBI 先说点背景。这篇文章是“Bringing Up Heterogeneous RISC-V on Allwinner SoCs”的第二部分。第一部分主要聊了怎么把最小系统跑起来比如串口、时钟、DDR 初始化还有怎么把 OpenSBI 引导进内核。这一部分重点完全不同我们要面对的是真正的深水区异构多核。全志的 SoC 上RISC-V 核心往往不是孤零零一个而是和 Arm 主核、DSP、NPU 混在一颗芯片里有各自的内存视图、中断控制器和电源域。把其中一个 RISC-V 核拉起来只是开始让它们协同工作、不掉链子才是真正考验功夫的地方。这篇文章适合谁适合已经在嵌入式 Linux 或 RTOS 里摸爬滚打、做过一些板级 bring-up但还没系统性处理过异构多核的人。看完之后你应该能理清全志异构平台的启动链路知道电源域和时钟域要按什么顺序处理理解 SBI/HSM 和 CPU hotplug 在启动从核时扮演的角色也知道内存一致性和消息通信该怎么验证。内容会比较硬核但我会尽量把每一步的“为什么”讲清楚而不是直接甩一段寄存器操作让你照着抄。1. 异构架构与启动链路全景解读1.1 异构从哪来一颗SoC里住着几套“CPU世界观”先明确一个概念这里的“异构”不是简单的“大核小核”同构多核比如四颗 Cortex-A53而是指同一颗 SoC 里集成了不同指令集架构、不同特权级设计、甚至不同总线主控权的 CPU 核心组合。在全志的平台上你经常能看到这样的组合一颗或几颗 Arm Cortex-A 系列核心作为主控跑 Linux一到两个 RISC-V 核心常见的是平头哥 E907、C906、C910 这类用来做协处理、实时控制、低功耗侦听或者干脆做 DSP 替代外加 NPU、DSP 这类加速器。为什么这么设计典型的场景是Arm 核跑复杂的应用系统但实时性不够稳定RISC-V 核跑 FreeRTOS 或者裸机任务专门处理中断密集的 I/O 和传感器数据。两者共享 DDR各自又有私有的 SRAM。从硬件视角看它们就是“两个世界”——不同的启动地址、不同的时钟源头、不同的中断号分配甚至看到的外设地址空间都有一部分是私有的。这对做 bring-up 的人来说意味着什么意味着你不能再用“一颗 SoC 一套 CPU 一套外设”的思维。你要同时管理至少两套启动流程协调两个运行域的资源还要保证它们没有互相踩踏。很多人第一次做这种平台时最容易犯的错就是只盯着自己要带起来的那颗 RISC-V 核忽略了它和主核之间共享的资源PLL、DDR 控制器、MBUS、中断控制器其实早就被对方初始化过了。1.2 启动链路拆解从 ROM 到多核协作的完整旅程全志异构 SoC 的典型启动链路我把它拆成了下面这几个阶段阶段执行主体主要任务是否涉及 RISC-V 核ROM BootSoC 内置 ROM从 boot device 加载下一级引导SPL/Boot0通常不ROM 固定只会拉起主控核SPL/Boot0Arm 主核初始化 PLL、DDR、串口、存储控制器不直接涉及但会配置到 RISC-V 核的电源和时钟门控固件层OpenSBI/U-BootArm 主核进入 EL2/M-mode加载内核和设备树准备启动 Linux会用到 SBI 的 HSM 扩展来管理从核内核启动Arm 主核SMP 初始化时依次唤醒 RISC-V 从核从核通过 SBI 调用或 DT 里的 enable-method 被拉起运行期协作所有核核间通信、共享内存、设备中断分发多核同时运行需要一致性保障这里有个很关键的点全志的 ROM 和 BootROM 阶段默认只负责把主控核一般是 Arm 核带起来。RISC-V 从核在系统上电后处于什么状态通常是电源域未开启、时钟被关闭、复位拉死。也就是说它并不是悄悄地“空转”而是彻底“断电休眠”。所以整个 RISC-V 从核的 bring-up本质上就是在启动后期由主核主动完成一次“上电、解复位、加载固件、释放启动”的完整动作。搞清楚这条链路后面所有工作都是倒着往前推先让主核的系统稳定跑起来再一点点把从核的资源打开。2. 电源域与时钟把从核“通电”是第一步2.1 电源域管理为什么不能一开始就把所有核都上电很多第一次做的人会有一个直觉上电就把所有核心的电源打开不就省事了吗全志的 SoC 设计恰恰相反——它把不同核心的电源域做成可以独立控制的目的就是让你在低功耗场景下可以随时关掉用不到的核心。这也是“异构”的真正价值之一按需供电。在全志的电源管理框架里你需要注意几类寄存器电源开关控制POWER_SW_CTRL控制某个 CPU 域或 CPU 逻辑域的开关。复位控制CPU_CFG / CPU_RST控制每个核的复位释放。时钟门控CLK_GATING控制 CPU 核的时钟开关。以我调试过的平台为例RISC-V 从核的电源域在默认状态下是“已关闭且保持复位”的。你要按下面这个顺序操作先把 CPU 电源域的供电开关打开等待电源稳定通常需要轮询电源状态寄存器或者简单延时几十微秒再从时钟树里把 RISC-V 核的时钟门控打开最后才释放复位信号。这个顺序不能乱。如果你先释放复位再打开时钟核心会处于“时钟不存在却开始执行指令”的状态轻则挂死重则总线访问异常导致整个系统卡住。我曾经因为图快跳过电源稳定等待在 10 次启动里有 3 次出现从核取指异常后来查了好久才发现是电源未稳就释放了复位。2.2 时钟树与分频配置从核跑多快不是你说了算全志的时钟树比较复杂但核心原则就一条CPU 核的时钟来自 PLL 分频而 PLL 通常已经被主核初始化过了。你不需要自己创建一个新 PLL但你必须知道从核的时钟源挂在哪个 PLL 的哪条分频链路上。实操层面的步骤大致是找到该 SoC 用户手册里的时钟树框图定位 RISC-V 核的时钟源比如“CPU1_CLK_SRC”或“RISC-V_CLK”确认它的父时钟是哪个 PLL以及当前频率配置分频系数让从核运行在目标频率打开时钟门控并等待时钟稳定。这里最容易踩的坑是全志经常把两个核的时钟源放在同一颗 PLL 上但允许独立分频。比如主核跑 1.2GHz从核可以通过分频跑到 600MHz 或 400MHz。如果你在调整分频系数时改错了父 PLL很可能直接把主核的时钟也带偏整个系统瞬间死机。分享一个我常用的检查方法改动任何时钟相关寄存器之前先把当前的寄存器值完整 dump 出来并存到一个文件里。如果系统死机可以通过 JTAG 反复对比确认是哪一步改出了问题。不要凭记忆写寄存器这种平台寄存器的 bit 位定义五花八门同一个偏移在不同型号上可能含义完全不同。2.3 实操心得电源和时钟操作的安全写法按我现在的习惯凡是做从核电源/时钟初始化的操作我都会摆成下面这个伪代码结构。具体的寄存器基址和偏移以你手头 SoC 的用户手册为准。void riscv_core_power_on(uint32_t core_id) { // 1. 打开核心电源域开关 writel(1U core_id, POWER_SW_CTRL_BASE CPU_POWER_ON_OFFSET); // 2. 等待电源域状态确认 while (!(readl(POWER_STAT_BASE CPU_POWER_STAT_OFFSET) (1U core_id))) ; // 3. 配置时钟源和分频 writel(CLK_SRC_SEL_A 8 | DIV_VALUE, CLK_BASE RISC_V_CLK_CFG_OFFSET); // 4. 打开时钟门控 writel(readl(CLK_BASE CLK_GATING_OFFSET) | (1U core_id), CLK_BASE CLK_GATING_OFFSET); // 5. 释放复位 writel(readl(CPU_CFG_BASE CPU_RST_OFFSET) | (1U core_id), CPU_CFG_BASE CPU_RST_OFFSET); }这个顺序我跑了多款全志平台都很稳。但请记住不同芯片的寄存器布局差异很大比如有的平台通过“写 1 清 0”的方式控制复位有的用“写 1 置位”有的在电源域稳定之后还要求先写一个“ack 寄存器”。拿到新的开发板第一步永远是先读一遍参考固件fex/SCP 固件里对应的初始化序列而不是自己发明轮子。3. 固件层搭建OpenSBI、M-mode 与从核唤醒3.1 为什么要先谈 M-mode 固件RISC-V 特权级模型RISC-V 和 Arm 的一个显著区别在于它的特权级设计非常清晰M-mode机器模式、S-mode监管模式、U-mode用户模式。Linux 内核跑在 S-modeOpenSBI 跑在 M-mode。这意味着所有涉及 CPU 硬件状态的操作比如修改 mstatus、处理 IPI、管理内存物理映射都不能由内核直接做而要经过 SBI 调用。全志平台上的 RISC-V 从核跑系统时通常有两种模式跑裸机或者 RTOS全程留在 M-mode不需要 OpenSBI自己直接操作所有硬件。跑 Linux必须先把 OpenSBI 加载到从核的 M-mode然后从核的 Linux 才能启动到 S-mode。对于异构 Linux 场景主流方案是每个 RISC-V 核都跑一份 OpenSBI通过 SBI 的 HSMHibernate Suspend Mechanism扩展来协调启动与休眠。HSM 扩展定义了一组标准调用比如sbi_hsm_hart_start、sbi_hsm_hart_stop用来让一个 hart 启动另一个 hart。这可比你自己写一套跨核启动协议要可靠得多。3.2 用 SBI HSM 扩展唤醒从核标准路径怎么走假设你的系统现在这样Arm 主核已经跑起了 LinuxRISC-V 从核的电源和时钟已经准备好复位也已经释放。接下来就是要让从核的 PC 跳到一段合法的启动代码。用 SBI HSM 的方式整个流程是主核上的软件通常是内核里的 cpu_ops发起sbi_hsm_hart_start调用OpenSBI 在 M-mode 检查目标 hart 的状态OpenSBI 将目标 hart 的启动地址写入它的stvec并设置启动参数目标 hart 从复位向量开始执行先进入 OpenSBI 的冷启动或 warm start 路径OpenSBI 初始化完成后跳转到内核的启动入口。这个过程里最常出的问题是从核的复位向量和stvec之间的关系没理清。RISC-V 从核上电后第一件事是从芯片规定的复位地址取指——这个地址通常是一个 Boot ROM 或者固定的 SRAM 地址。但 OpenSBI 接管后真正做的是把启动入口写到stvec而stvec必须指向 OpenSBI 自己的 trap handler。如果你直接让从核跳到一个裸地址比如你编译的 Linux 内核入口除非你完全绕过了 OpenSBI否则几乎不可能成功。3.3 启动代码细节从核第一次“睁眼”看到的世界从核的启动汇编我习惯写成非常朴素的版本先做最基本的栈指针初始化、bss 清零然后跳到 C 代码。下面是一段典型的从核启动入口以 RISC-V 汇编为例.section .text.init .globl _start _start: /* 关中断 */ csrw mie, zero csrw mip, zero /* 设置临时栈 */ la sp, _stack_top /* 清零 bss */ la a0, __bss_start la a1, __bss_end 1: bge a0, a1, 2f sd zero, 0(a0) addi a0, a0, 8 j 1b 2: /* 跳转 C 初始化 */ call riscv_secondary_main loop: wfi j loop这段代码本身没什么玄机但有两个细节需要特别留意。第一个细节是wfi死循环必须有。从核如果在初始化完成之前被踩到未定义状态至少还有一个低功耗等待的退路如果没有这个循环从核会直接乱跳把总线搞得乌烟瘴气。第二个细节是栈指针。很多从核的私有 SRAM 非常小可能只有 64KB 或者 128KB。你如果在链接脚本里把栈放得太大从核一启动就把 SRAM 踩穿接着盖掉 OpenSBI 或者内核的关键数据。我一般会把从核的栈放在私有 SRAM 的最高地址并且限定大小不超过 16KB因为从核启动阶段根本用不了那么多栈空间。4. Linux 内核侧适配设备树与 SMP4.1 设备树里怎么描述异构多核设备树是 Linux 内核了解硬件拓扑的主要途径。异构多核要正常工作必须在 DT 里把每个核的cpunode 以及enable-method写对。一段典型的多核描述长这样cpus { #address-cells 1; #size-cells 0; cpu0: cpu0 { compatible arm,cortex-a53; reg 0x0; device_type cpu; enable-method psci; }; cpu1: cpu1 { compatible riscv; reg 0x1; device_type cpu; riscv,isa rv64imafdc; mmu-type riscv,sv39; enable-method sbi; cpu-release-addr 0x0 0x45000000; }; };注意几个容易搞错的地方。enable-method必须匹配实际使用的启动方式。Arm 核继续用psciRISC-V 核用sbi这俩不能混。riscv,isa必须和实际硬件一致。如果你写的是rv64imafdc但实际核不支持 F 扩展内核在检测到非法指令时会直接 panic。用cat /proc/cpuinfo检查实际导出的 ISA 是排查这类问题的第一步。cpu-release-addr只在旧式 spin-table 方式下需要。如果你走 SBI HSM这个字段可以省略但有些老内核或者定制内核还是会参考它。4.2 PSCI、SBI、spin-table三套 enable-method 怎么选全志平台上的异构多核可能的组合我列个表方便你看组合主核RISC-V 从核典型 enable-method适用场景主核 Linux 从核裸机ArmRISC-V无从核直接跑裸机实时协处理、I/O 侦听主核 Linux 从核 RTOSArmRISC-Vremoteproc 或自定义需要框架管理生命周期同构 RISC-V SMPRISC-VRISC-Vsbi通用 SMP LinuxArm Linux RISC-V LinuxArmRISC-Vsbi通过 OpenSBI双系统异构 AMP实际操作中我见过最多的是第一种Arm 主核跑 LinuxRISC-V 从核跑裸机或 FreeRTOS 完成特定实时任务。这种场景并不一定需要在内核设备树里给从核建 node反而用 remoteproc 框架管理更合适一个固件文件负责描述加载地址、启动地址和资源表。如果你坚持要让从核也跑 Linux那就要走完整 SBI 路线。SBI HSM 比 spin-table 的优势在于它不仅能热插拔还能处理休眠和低功耗状态。但代价是每个从核都要有一份独立的 OpenSBI而且在共享 DDR 上要处理好内存空洞和保留区域否则主核 Linux 的内存管理会覆盖掉从核的代码段。4.3 启动日志解读怎么看从核有没有被真正拉起判断从核是否成功启动最直接的办法是看主核内核日志里有没有类似下面的信息smp: Bringing up secondary CPUs ... [ 0.186093] smp: Booting CPU1 (cpu 1) [ 0.190216] CPU1: RISC-V CPU (rv64imafdc) running at 600 MHz如果你看到的是CPU1: failed to boot或者干脆没有任何Booting CPU1的日志那么问题大概率出在三个地方电源和时钟配置有问题从核根本没有运行从核的启动地址不正确OpenSBI 找不到入口SBI 调用失败主核 OpenSBI 返回错误码。排查时我一般会做两件事第一在从核固件入口处加一个 GPIO 翻转逻辑通过示波器或者逻辑分析仪看从核是否真的执行到了 C 代码。第二打开 OpenSBI 的详细日志-DOPENSBI_ENABLE_DEBUG看主核发起 HSM 调用时返回了什么状态。5. 内存一致性与共享通信5.1 多核共享 DDR 的“假一致”陷阱异构平台最容易出问题的不是性能而是内存一致性。Arm 核和 RISC-V 核共享同一个 DDR 控制器时硬件上通常有一致性总线比如 CCI 或 MBUS但并不意味着 CPU 的 L1/L2 缓存天然一致。如果你的 RISC-V 核没有参与硬件缓存一致性协议很多协处理核不支持那么主核对一段内存的写入从核读到的可能是旧值。举个真实例子。我在一个平台上让 Arm 核往共享内存写一批描述符然后通过 doorbell 中断通知 RISC-V 核去读。从核读到的数据有一半是 0xff另一半是旧数据。查了总线协议、DMA 配置最后发现就是缓存一致性问题Arm 核的数据还留在 L2 cache 里没有写穿到内存。解决这类问题的方式有三种共享内存区域标注为 non-cacheable。在设备树里用dma-coherent或者直接在页表里关掉 cache bit。每次通信前做显式 cache clean/invalidate。用硬件支持的一致性端口如果有的话把从核纳入一致性域。最省事、也最稳妥的方案是第一种牺牲一点性能换正确性。全志这类平台的共享内存通常本来就在 MBUS 和 SRAM 之间带宽也不高强行追求 cache 优化意义不大。5.2 缓存维护操作的“放之四海而皆准”写法哪怕你决定走 cacheable 路线也要知道缓存维护指令怎么发。RISC-V 上常见的操作是fence.i和sfence.vma。前者用于指令缓存同步后者用于地址转换缓存失效。void flush_icache_range(unsigned long start, unsigned long end) { asm volatile(fence.i ::: memory); }听起来简单但真正容易出问题的是跨核场景。Arm 核写了一段从核要执行的代码然后你让从核去取指——如果从核的 I-cache 里还缓存着旧指令它执行的仍然是旧代码。这种情况fence.i需要在从核上执行一次才能清掉它自身的指令缓存。实际操作中我建议在共享代码区更新之后除了主核做一次 clean还要让从核在启动路径最开头执行一次fence.i。虽然会损失几条指令的性能但换来的是“无论如何都不会执行到旧代码”的确定性。这在调试初期非常重要等你把整个链路调稳定了再考虑优化掉。5.3 核间通信选型mailbox、共享内存还是信号量全志 SoC 上核间通信的方案不外乎下面几种纯共享内存 标志位最简单但需要自己处理并发和缓存维护。适合大数据量、低频通知的场景。共享内存 interruptdoorbell全志平台每个核都有一组中断控制器你可以在写完成数据之后给对端核发一个 IPI。这是最常见的方案。硬件 mailbox部分型号有专用的 mailbox 硬件可以发送短消息比如最多 8 个字。适合控制类小消息不需要复杂缓存管理。我个人的建议是初期调试优先选择“共享内存 IPI”灵活且可控。你先通过 GPIO 或者串口打印验证 IPI 通路是否正常然后再去搞共享内存协议。千万不要一上来就搞一个复杂的消息框架否则一旦出错你分不清是中断没到、内存不一致还是协议解析踩空排查成本极高。6. 调试与验证从“能跑”到“跑得稳”6.1 调试手段选择JTAG、串口日志、还是内核辅助异构平台的调试最大的痛苦在于“不知道从核到底在干什么”。串口日志是必须的但对核间这种时序敏感性极高的问题串口本身可能掩盖问题——你加的打印延迟足够把问题“治好”。我一般按下面优先级组织调试手段串口日志用于确认从核启动进度、打印关键分支GPIO 翻转用示波器测时序判断执行路径上几个关键节点是否按预期到达JTAG/OpenOCD用于查看从核的 PC、堆栈、通用寄存器内核侧辅助比如从核跑 Linux 时用/sys/devices/system/cpu/cpu1/online控制热插拔测试。调试时要有一个理念每次只改一个变量。比如你先验证电源域和复位不要同时调时钟和内核配表。用 GPIO 在从核入口处翻转一次如果翻出来了说明电源、时钟、复位这条链路没问题如果没有你才需要往下查。6.2 验证指标不只是“能开机”多核 bring-up 的验证阶段我给自己定的标准不是“能开机交差”而是下面这几个指标验证项目标验证方法从核启动时间从释放复位到执行第一个用户代码 50msGPIO/示波器测量核数识别内核能看到所有预期核/proc/cpuinfo热插拔稳定性CPU off/on 循环 1000 次无失败脚本自动化核间通信正确性100000 次消息传输零错误共享内存回环测试长时间稳定性双核满载运行 72 小时无崩溃stress 工具加自定义负载不要小看热插拔测试。SBI HSM 的 warm start 路径和冷启动路径往往不同很多平台“冷启动一切正常一执行 CPU hotplug 就死机”。这个问题在异构平台上尤其典型因为主核和从核共享了某些低功耗资源停核的时候没有正确关掉该关的下次启动时就会踩到未初始化状态。6.3 压力测试脚本逼出隐藏问题下面是一个简单但实用的热插拔测试脚本跑在 Linux 主核上#!/bin/bash CPU1 FAIL0 for i in $(seq 1 1000); do echo 1 /sys/devices/system/cpu/cpu${CPU}/online if [ $? -ne 0 ]; then echo online failed at iteration $i FAIL1 break fi sleep 0.01 echo 0 /sys/devices/system/cpu/cpu${CPU}/online if [ $? -ne 0 ]; then echo offline failed at iteration $i FAIL1 break fi done if [ $FAIL -eq 0 ]; then echo Hotplug test passed: 1000 cycles else echo Hotplug test failed fi跑这个脚本之前建议先在从核的固件里加一个计数器每次启动时自增并写到一个固定内存地址。主核热插拔一千次之后去读那个地址确认从核确实全新启动了一千次而不是只启动了一次、后面都在假装成功。这种“假成功”在 SBI 路径上非常隐蔽我甚至遇到过从核第一次启动后根本没死只是被错误地标记为下线结果每次 on/off 操作只是在主核软件层面打转的情况。7. 常见问题与排查技巧实录7.1 问题速查表我踩过的那些坑下面是我在多个全志异构平台上实际遇到过的典型问题总结成表方便你遇到类似情况时快速定位现象可能原因排查方向从核一点反应都没有电源域未打开/复位未释放检查电源控制寄存器状态测量核心供电从核启动后 PC 跑飞启动地址错误或入口处中断未关用 JTAG 看 PC 值确认 stvec 和复位向量从核代码执行到一半挂死私有 SRAM 溢出或栈溢出检查链接脚本确认栈大小和内存边界主核内核报 CPU1 failed to bootHSM 调用返回错误打开 OpenSBI 调试日志返回码逐项比对从核能启动但乱打印串口波特率/UART 时钟配置不一致确认从核侧 UART 时钟源和主核侧是否一致热插拔第二次失败停核时未正确关闭缓存/中断检查 SBI 停止路径和缓存维护操作共享数据读到旧值缓存一致性未处理共享内存改 non-cacheable 或显式 clean7.2 独家避坑几个文档里不会写的细节第一个坑是关于“从核启动延迟”。很多时候你释放复位后从核不会立刻开始取指而是要等几十毫秒的 PLL 锁定时间。如果你在释放复位后立刻去检查从核状态寄存器的某个标志位大概率会失败。正确做法是释放复位后先等待一个固定的、足够长的延时我一般用 100ms再去做后续检查。第二个坑是内存保留区。主核 Linux 跑起来后默认会管理整个 DDR它根本不知道哪一块内存是从核的固件和堆栈。如果你在设备树里没有用reserved-memory把这些区域圈出来Linux 的 page allocator 就可能把从核正在执行的代码页面重新分配给其他进程后果就是从核毫无征兆地死掉。在你的 devicetree 里务必要有类似这样的保留区reserved-memory { #address-cells 1; #size-cells 1; ranges; riscv_fw_mem: riscv-fw45000000 { reg 0x45000000 0x1000000; no-map; }; };no-map关键字非常关键它告诉内核这块内存不允许做页表映射从而避免任何虚拟地址别名问题。第三个坑是 IPI 中断号。全志平台上不同核的中断控制器看到的 IRQ 编号空间可能不一样。你在主核上发 IPI 给从核时用的中断号未必等于从核处理时看到的中断号。一定要先在从核固件里通过csrr读取中断号确认值之后再写正式处理函数不要想当然地复用同一个数字。7.3 排查方法论一步一步缩小范围多核系统排查最忌讳的是“东改一下西试一下”。我建议你每次调试都按下面五步走确认目标核的硬件状态电源是否打开、时钟是否稳定、复位是否释放确认最小启动路径从核是否执行到了我们加的 GPIO 翻转点确认固件加载是否正确目标内存区域的字节内容是否和编译产物一致确认 SBI/启动协议交互主核的调用是否返回成功从核的入口地址是否正确确认系统软件适配设备树、DMA 内存圈定、中断路由是否和硬件一致。这五步一层层下来大部分问题都能在第五步之前暴露。我见过最多的失败案例都是因为跳过前四步直接在内核日志里找原因最后绕了一大圈发现只是某个 GPIO 复位信号没拉高。8. 实测体会与后续扩展做异构多核 bring-up 这件事跟我们平时做普通单核或多核系统最大的不同是你要同时维护两套“世界观”。主核的世界里Linux 管理一切资源从核的世界里你可能只有一个裸机循环和几个中断处理函数。一条共享内存报文从主核发到从核中间隔着的不仅是硬件总线还有两个完全不同的软件栈。我在实际调试中最深的体会是严格遵循“一次只动一个变量”的原则。异构平台上变量太多了电源、时钟、复位、固件地址、DT 配置、缓存属性任何一个地方都有可能是问题。如果你同时改了三个地方然后系统跑起来了你永远不知道自己到底是怎么调好的。反过来下次换一颗芯片你又要从头开始踩坑。这套流程如果跑顺了后面的扩展方向其实很丰富。可以往 AMP 方向走让 RISC-V 从核独立跑 FreeRTOS负责实时控制也可以往 SMP 方向走让多个 RISC-V 核共同分担 Linux 负载还可以用 remoteproc 框架把从核的生命周期纳入 Linux 管理实现运行时加载和卸载从核固件。我自己比较推荐先把“共享内存 IPI”的通信基建打磨稳这是所有后续功能的地基。最后再分享一个小技巧如果你手头的全志平台上有多个相同型号的板子务必在从核固件里加一个可配置的延时参数或者打印开关通过板子上的拨码开关或调试串口输入来调节。异构 bring-up 阶段很多问题都是时序相关的能快速调节从核启动时序比什么高级调试器都管用。祝你们调板顺利。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表