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

如何从U-Boot加载的ARM程序调用U-Boot API?附getc调用崩溃案例

在U-Boot go命令加载的ARM程序中调用U-Boot API的方法

可以调用,但必须严格遵循U-Boot API的调用规范,你之前的代码崩溃主要是因为错误直接访问syscall_table、未处理特权模式切换,以及不符合API的调用约定。

核心要点:U-Boot API的调用逻辑

U-Boot的api_address指向的是一个struct api_descriptor结构体,而非直接的函数指针数组。这个结构体包含API的版本信息、统一调用入口api_call——所有API函数都必须通过这个入口发起调用,不能直接跳转至syscall_table中的函数地址。

错误代码的问题分析

  • 直接访问偏移32的地址:struct api_descriptor的结构并非直接存储函数指针数组,这个偏移位置的内容不是合法的函数入口。
  • 未切换特权模式:U-Boot通常运行在SVC特权模式,而go命令加载的程序默认可能处于用户模式,用户模式下调用特权级API会触发异常崩溃。
  • 未遵循API调用约定:U-Boot API要求通过统一的api_call入口传递命令号和参数,而非直接调用函数。

正确的汇编实现步骤

  1. 切换到SVC特权模式,确保有足够权限调用API。
  2. 从api_address指向的结构体中取出api_call函数的地址。
  3. 传递API命令号(如API_GETC的命令号,需对应U-Boot版本的定义),调用api_call。

以下是适配ARM1176JZF-S的示例代码:

.global _start

_start:
    /* 切换到SVC特权模式 */
    mrs     r0, cpsr
    bic     r0, r0, #0x1F        ; 清除模式位
    orr     r0, r0, #0x13        ; 设置为SVC模式
    msr     cpsr, r0

    /* 读取api_descriptor中的api_call入口地址 */
    ldr     r0, =0x1BB89148      ; 替换为你的api_address实际值
    ldr     r1, [r0, #8]         ; api_call的偏移:前两个成员是u32(magic+version),偏移8字节

    /* 调用API_GETC:命令号参考U-Boot的api_public.h,通常为1 */
    mov     r0, #1               ; API_GETC的命令号
    blx     r1                   ; 调用api_call,返回值r0为读取到的字符

    /* 可选:处理返回的字符,比如后续逻辑 */
loop:
    b       loop                 ; 死循环防止程序跑飞

额外注意事项

  • 确认API命令号:查看U-Boot源码中include/api_public.h,API_GETC的定义可能因版本不同略有差异。
  • 结构体偏移验证:根据U-Boot版本对应的struct api_descriptor定义,确认api_call的偏移(比如部分版本可能有额外成员,偏移需调整)。
  • 寄存器保护:若需要保留调用前的寄存器状态,需在调用api_call前保存r4-r11(ARM调用约定中这些寄存器需要调用者保存)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 19:38:12