如何从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入口传递命令号和参数,而非直接调用函数。
正确的汇编实现步骤
- 切换到SVC特权模式,确保有足够权限调用API。
- 从
api_address指向的结构体中取出api_call函数的地址。 - 传递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
相关产品推荐
相关产品推荐

