C Prototype

系统调用函数必须以__syscall开头,在include/SYSCALL_INCLUDE_DIRS目录下被声明。

scripts/build/parse_syscalls.py会parse__syscall这个标记,并且函数有以下限制:

  • 参数不能传入数组,比如int foo[] or int foo[12], 必须用int *foo代替。
  • 函数指针不能正常解析,需要先对函数指针typedef,再传入。

定义了系统调用的xxx.h头文件必须要文件末尾加上同名的#include <syscall/xxx.h>

Invocation Context 调用上下文

  • 如果定义了CONFIG_USERSPACE,所有的system call APIs都会直接调用对应的implementation function。
  • 如果定义了__ZEPHYR_SUPERVISOR__,表示所有code都在supervisor mode下运行,直接调用对应的implementation function。
  • 如果定义了__ZEPHYR_USER__

Implementation Detail 实现细节

scripts/build/gencalls.py会把parse到的system calls放进/build/include/generated/syscall_list.h中。以K_SYSCALL_前缀加上API。

所有可以调用的system calls被保存在syscall_dispatch.c中的_k_syscall_table中。

system calls的API实现被保存在了/build/include/generated/syscalls/xxx.h 这些文件被/include/xxx.h文件最后include进去,完成函数的定义。e.g

// include/i2c.h
__syscall int i2c_configure(const struct device *dev, uint32_t dev_config); //声明

static inline int z_impl_i2c_configure(const struct device *dev,
				       uint32_t dev_config)
{
	const struct i2c_driver_api *api =
		(const struct i2c_driver_api *)dev->api;

	return api->configure(dev, dev_config);
}
//...
#include <syscalls/i2c.h>

// build/include/generated/syscalls/i2c.h
extern int z_impl_i2c_configure(const struct device * dev, uint32_t dev_config);

__pinned_func
static inline int i2c_configure(const struct device * dev, uint32_t dev_config)
{
#ifdef CONFIG_USERSPACE
        if (z_syscall_trap()) {
                union { uintptr_t x; const struct device * val; } parm0 = { .val = dev };
                union { uintptr_t x; uint32_t val; } parm1 = { .val = dev_config };
                return (int) arch_syscall_invoke2(parm0.x, parm1.x, K_SYSCALL_I2C_CONFIGURE);
        }
#endif
        compiler_barrier();
        return z_impl_i2c_configure(dev, dev_config);
}