trusty中,可以通过系统调用陷入kernel,获取kernel服务。
这里记录一下trusty的系统调用框架结构,代码基于google trusty源码
1、应用程序接口
在文件lib/include/trusty_syscalls.h中,申明了上层调用的syscall接口。如:
1 // send_msg()系统调用的号码是0x23 2 #define __NR_send_msg 0x23 3 // send_msg()系统调用原型申明 4 long send_msg (uint32_t handle, ipc_msg_t *msg);
这样,应用层程序可以调用这些接口获取系统服务了。
2、陷入内核
在lib/lib/libc-trusty/arch/arm/trusty_syscall.S文件中,
// 各个系统调用函数对应的汇编代码
.section .text.send_msg FUNCTION(send_msg) ldr r12, =__NR_send_msg // 系统调用号置入r12寄存器 swi #0 // 通过swi陷入内核,执行内核代码 bx lr // 返回lr寄存器位置
用户空间的这些代码是通过脚本解析生成的,看注释。具体生成方式方法需要在明确要再明确一下。
3、内核中系统调用服务函数申明
lk/trusty/lib/syscall目录定好了trusty内核处理系统调用的框架。
在lk/trusty/lib/trusty/include/syscall_table.h定义了一系列宏,其余用户空间的syscall号码一一对应。
形如:DEF_SYSCALL(0x23, send_msg, long, 2, uint32_t handle, ipc_msg_t *msg)
在lk/trusty/lib/syscall/syscall.c文件中其进行展开,得到系统调用函数数组:
#define DEF_SYSCALL(nr, fn, rtype, nr_args, ...) rtype sys_##fn (void);
=》long sys_send_msg(void);
#define DEF_SYSCALL(nr, fn, rtype, nr_args, ...) [(nr)] = (unsigned long) (sys_##fn),
=》[0x23] = (unsigned long) sys_send_msg,
前一个做函数原型申明,后一个定义了函数指针数组,
1 long sys_send_msg(void); 2 3 const unsigned long syscall_table [] = { 4 …… 5 [0x23] = (unsigned long) sys_send_msg, 6 …… 7 };
这些sys_***类似的函数要在kernel中实现功能。
4、系统调用过程
用户调用到swi指令,这是arm软中断指令,此时CPU会强制从系统异常向量表的软中断异常处开始执行(可能为0x00000008),
trusty中这里安排了一条跳转指令,直接跳到arm_syscall符号处。
external/lk/arch/arm/arm/start.S
1 .section ".text.boot" 2 .globl _start 3 _start: 4 b platform_reset 5 b arm_undefined 6 b arm_syscall 7 b arm_prefetch_abort 8 b arm_data_abort 9 b arm_reserved 10 b arm_irq 11 b arm_fiq 12 #if WITH_SMP 13 b arm_reset 14 #endif
该标号在
lk/trusty/lib/syscall/arch/arm/syscall.S中有定义:
1 /* ARM syscall ABI 2 * =============== 3 * Only syscalls with 4 args (max) are currently supported 4 * r0-r3 = args 5 * r0-r1 = return value (r0 only if 32-bit retval) 6 * r12 = syscall number, expected to be trashed. 7 * syscalls run with interrupts enabled 8 */ 9 FUNCTION (arm_syscall) 10 srsdb sp!, #MODE_SVC 11 sub sp, sp, #8 12 stmia sp, { r13-r14 }^ 13 // 保存r13、r14、spsr相关寄存器 14 15 cpsie iaf 16 // 开中断,cpsr中相关位 17 18 ldr r14, =nr_syscalls 19 ldr r14, [r14] 20 // 将nr_syscalls的值放入r14,nr_syscalls是当前系统支持的系统调用个数 21 cmp r12, r14 22 // 比较r12与r14,如r12保存的是中断请求号 23 24 ldrlo r14, =syscall_table 25 // ldrlo是条件加载,如果r12<r14,将syscall_table地址置入r14, 26 // syscall_table就是syscall服务函数数组的地址 27 ldrlo r14, [r14, r12, lsl#2] 28 // 将r14 + r12 * 4的值放入r14寄存器,该值即为对应系统调用号的服务函数地址 29 rsblos r12, r14, #1 /* This will set the same flags as the cmp above */ 30 // rsb逆向减法指令,r12 = 1 - r14,结果影响cpsr 31 ldrhs r14,=sys_undefined 32 // r14置入sys_undefined函数的地址(如果1 >= r14?) 33 blx r14 34 // 跳转执行r14指示的syscall程序 35 36 cpsid iaf 37 // 关中断 38 39 ldmia sp, { r13-r14 }^ 40 add sp, sp, #8 41 rfeia sp! 42 // 恢复之前的r13、r14等寄存器
这样上层请求的系统调用最终会进入内核中对应的服务函数中执行