You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

带OpenSBI的Linux内核跳转至0x80100000后无法正常启动排查

问题:跳转加载OpenSBI Payload后内核无法执行的原因分析

问题背景

我通过以下命令构建OpenSBI payload与Linux内核镜像:

make PLATFORM=generic FW_FDT_PATH=$WORKLOAD_BUILD_ENV_HOME/dts/build/xiangshan.dtb FW_PAYLOAD_PATH=$RISCV_LINUX_HOME/arch/riscv/boot/Image

获取fw_payload.bin后,我编写了简单的跳转逻辑,将该payload加载到新地址0x80100000并跳转执行,预期内核能正常启动。但在模拟器运行时,仅能看到OpenSBI的输出,无法看到内核输出;而直接运行fw_payload.bin时,内核可正常运行。

我的链接脚本(linker.lds)

OUTPUT_ARCH( "riscv" )

ENTRY( jump_payload )

SECTIONS
{
  . = ALIGN(4);

  begin = .;

  .header.code :
  {
    *(.header.code)
  }

  end = .;


  . = begin + 0x100000;
  .payload :
  {
     PROVIDE(_payload_start = .);
     *(.payload)
     . = ALIGN(8);
     PROVIDE(_payload_end = .);
  }
}

跳转逻辑汇编代码

.section ".header.code", "ax", %progbits
.globl jump_payload
jump_payload:
  li t0, 0x80100000
  jr t0
  add t0, x0,x0

  .section ".payload", "ax", %progbits
  .align 4
  .global payload_bin
payload_bin:
  .incbin PAYLOAD_PATH

原因分析与解决建议

1. OpenSBI Payload是位置相关代码

fw_payload.bin默认是位置相关代码(PDC),编译时基于RISCV通用平台的默认起始地址0x80000000生成。当你把它加载到0x80100000后,代码中的绝对地址引用(比如全局变量、函数跳转地址)依然指向0x80000000附近的原始位置,执行时会访问错误地址,导致内核初始化失败。

2. 缺少正确的启动参数传递

直接运行fw_payload.bin时,模拟器会按照RISCV启动规范设置初始环境:

  • a0寄存器:当前hart的ID(通常为0)
  • a1寄存器:设备树(DTB)的物理地址
  • a2寄存器:预留参数(通常为0)

而你的跳转逻辑只是单纯跳转到0x80100000,没有设置这些寄存器参数,OpenSBI无法完成正确的初始化流程,自然无法启动内核。

3. 链接脚本与实际加载地址不匹配

你的链接脚本将.payload段放在begin + 0x100000的位置,但如果整个镜像的加载起始地址不是0x80000000,那么.payload的实际加载地址会和预期的0x80100000不符;再加上fw_payload.bin内部地址已固定,双重地址偏移会彻底打乱执行流程。


解决建议

  • 编译位置无关的OpenSBI Payload:编译时添加FW_PAYLOAD_ALIGN=0x100000参数,或启用位置无关编译选项,让fw_payload.bin支持任意地址加载执行。
  • 传递正确的启动寄存器参数:在跳转至0x80100000前,设置好a0、a1、a2寄存器的值,匹配模拟器的初始启动环境。
  • 保持加载地址与编译地址一致:如果必须使用位置相关版本,要么将fw_payload.bin加载到默认的0x80000000地址,要么重新编译OpenSBI时指定平台加载地址为0x80100000。

内容的提问来源于stack exchange,提问作者XM Zg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 17:52:21