OpenHarmony LiteOS-A内核实现态与内核态的区分隔离,用户态程序不能直接访问内核资源,而系统调用则为用户态程序提供了一种访问内核资源、与内核进行交互的通道。如下图所示,用户程序通过调用System API(系统API,通常是系统提供的POSIX接口)进行内核资源访问与交互请求,POSIX接口内部会触发SVC/SWI异常,完成系统从用户态到内核态的切换,然后对接到内核的Syscall Handler(系统调用统一处理接口)进行参数解析,最终分发至具体的内核处理函数。
Syscall Handler的具体实现在kernel/liteos_a/syscall/los_syscall.c中OsArmA32SyscallHandle函数,在进入系统软中断异常时会调用此函数,并且按照kernel/liteos_a/syscall/syscall_lookup.h中的清单进行系统调用的入参解析,执行各系统调用最终对应的内核处理函数。
1. 涉及的系统调用文件目录介绍
先介绍下系统调用相关的内核态代码、用户态代码所在的文件目录。
1.1 syscall/syscall_lookup.h文件
kernel/liteos_a/syscall/syscall_lookup.h
文件中维护内核向用户态提供的系统调用接口。文件中包含虚拟文件系统VFS、动态加载DYNLOAD、PIPE、SHELL、LWIP、SECURITY_CAPABILITY等模块的系统调用接口,文件内容片段如下。每一个系统调用有宏函数SYSCALL_HAND_DEF
定义,包含系统调用编号、系统调用处理函数,返回值类型,系统调用处理参数数目,下文详细介绍。
......
SYSCALL_HAND_DEF(__NR_write, SysWrite, ssize_t, ARG_NUM_3)
SYSCALL_HAND_DEF(__NR_open, SysOpen, int, ARG_NUM_7)
SYSCALL_HAND_DEF(__NR_close, SysClose, int, ARG_NUM_1)
SYSCALL_HAND_DEF(__NR_creat, SysCreat, int, ARG_NUM_2)
......
文件syscall/syscall_lookup.h
被文件syscall/los_syscall.c
中的系统调用初始化函数OsSyscallHandleInit
调用,调用代码如下。可以看出第一个参数是系统调用函数编号,编号定义在文件third_party/musl/porting/liteos_a/kernel/include/bits/syscall.h
;第二个是系统调用函数,函数原型声明在文件kernel/liteos_a/syscall/los_syscall.h
,函数实现一般在kernel/liteos_a/syscall
目录下的源代码文件中实现; 第三个是返回值类型,暂时没有使用;第四个函数是系统调用函数的参数数目。
下面看下宏函数的代码,⑴处把定义的系统调用函数都维护在全局数组g_syscallHandle
。⑵处由于参数数量不会特别大,记录系统调用处理函数参数数目的全局数组g_syscallNArgs
的类型是UINT8,每4个bit位维护一个系统调用的参数数目。
...
static UINTPTR g_syscallHandle[SYS_CALL_NUM] = {0};
static UINT8 g_syscallNArgs[(SYS_CALL_NUM + 1) / NARG_PER_BYTE] = {0};
...
void OsSyscallHandleInit(void)
{
#define SYSCALL_HAND_DEF(id, fun, rType, nArg) \
if ((id) < SYS_CALL_NUM) { \
⑴ g_