1.1.1 nuttx系统调用
既然将应用程序和地址空间分为M-Mode和U-Mode可访问,那就需要提供两者沟通的渠道,从原则上来说内核不应该直接访问应用程序的函数或服务,而应用程序则需要访问内核的服务,所以只需提供应用程序访问内核服务的接口即可。
在nuttx系统中,运用mksyscall工具,根据文件system.csv,分别生成供用户调用的接口,以及在内核中与其对用的接口。在编译时,生成libproxies.a以及libstubs.a。
mksyscall -p system.csv生成供用户调用的接口;
mksyscall -s system.csv生成内核中调用的接口;
系统调用的接口定义在syscall/syscall.csv中。第一个参数标识函数名字,第二个参数标识这个接口需要的头文件,第三个参数标识函数的返回值类型,接着的参数标识这个接口需要的参数类型;
Ø 内核中对应的系统调用接口
在sys/syscall.h中,通过enum获得到接口对应的枚举值:
展开之后:
enum
{
SYS__exit = 0,
SYS_accept,
…,
SYS_massyscall
}
在syscall/syscall_stublookup.c中,通过一个数组把系统调用接口给管理起来:
展开之后:
uintptr_t g_stublookup[SYS_nsyscalls] =
{
uintptr_t STUB__exit(int nptr,int),
uintptr_t STUB_accept(int nptr, uintptr_t parm1, uintptr_t parm2, uintptr_t parm3),
…
}
Stub对应的内核接口如下:
Ø 用户系统调用接口实现如下:
通过mksyscall -p system.csv生成供用户调用的接口,
在Nuttx中实现此功能的部分叫做系统调用,与Linux类似都是通过ecall命令作为桥梁实现U-Mode/M-Mode的转换,并且通过通用寄存器来传递参数。
在nuttx系统中,提供了7个系统调用函数:sys_call0 ~ sys_call6,分别对应系统调用时包含0~6个参数的场景,参数通过a0~a6进行传递,其中a0用来传递syscall no,a1~a6的含义则由具体syscall进行确定,比如在syscall no为0是实现任务context的转储,则a1用来传递context转储的目的地址,a2~a6不用。
由于系统调用通过ecall来实现,对ecall的处理在中断中处理。在系统初始化时注册了相应的处理函数riscv_swint(ecall for machion/ecall for user)。