自定义系统调用
本节主要介绍 ECS 容器版本中自定义系统调用的方法。
操作须知
ECS 容器为了实现系统内核的安全性,只有处于内核态时才具有使用内核资源和访问外设驱动的权限,处于容器内的用户态程序必须通过系统调用进入内核才能进行这些访问操作。
ECS 容器默认提供了必要的系统调用接口,但对于某些场景,用户需要新增自定义系统调用才能够满足应用使用需求。新增系统调用实现须由内核态工程实现,如 BSP 工程、SylixOS Kernel Module 工程等。
操作步骤
步骤 1:创建内核模块工程
下述示例在内核模块工程中定义了 func00 和 func11 两个函数,将其提供给上层应用程序使用。
#define __SYLIXOS_KERNEL
#include <SylixOS.h>
#include <module.h>
/*
* SylixOS call module_init() and module_exit() automatically.
*/
int module_init (void)
{
printk("hello_module init!\n");
return 0;
}
void module_exit (void)
{
printk("hello_module exit!\n");
}
/*
* module export symbols
*/
LW_SYMBOL_EXPORT void func00 (void)
{
printk("func00() run!\n");
}
/*
* module export symbols
*/
LW_SYMBOL_EXPORT void func11 (void)
{
printk("func11() run!\n");
}
步骤 2:创建描述文件
如下所示,在工程内创建 .scd 描述文件,用于对系统调用进行描述。
描述文件格式如下:
#define __SYLIXOS_KERNEL
#include <SylixOS.h>
void func00(void){}
void func11(void){}
说明:
每个函数占用一行, 以 {} 作为结尾标志。
步骤 3:生成系统调用文件
在该 .scd 文件上单击右键,选择 Container > Generate System Call Source。
在弹出的对话框中,编辑起始系统调用号 Start Number 和生成文件名称 SysCall Name,单击 OK。
说明:
- ECS 中每一个系统调用都对应唯一的系统调用号,其中内核默认支持的系统调用号约 600 个,并且 xsiipc 占用了 20 个,用户自定义的起始系统调用号建议从 1200 开始。
- 系统调用号不能重复。
工程中会自动生成 mySysCallArg.h、mySysCallHandler.c、mySysCallNr.h、mySysCallWrapper.c 文件。
其中 mySysCallWrapper.c 需要移动到应用程序中进行编译,内核模块工程将剩余文件参与编译。
步骤 4:注册系统调用
- 在内核模块工程的入口函数 module_init 中调用 API_SystemCallRegister 函数添加系统调用自定义接口。
- 在内核模块工程的出口函数 module_exit 中调用 API_SystemCallUnregister 函添加系统调用注销接口。
示例代码如下:
#define __SYLIXOS_KERNEL
#include <SylixOS.h>
#include <module.h>
#include "syscall/sysCall.h"
#include "mySysCallNr.h"
extern ULONGFUNCPTR _G_pfuncModuleScHandlerTbl[];
/*
* SylixOS call module_init() and module_exit() automatically.
*/
int module_init (void)
{
printk("hello_module init!\n");
API_SystemCallRegister("syscall_test",
LW_MODULE_SC_BASE,
LW_MODULE_SC_CNT,
_G_pfuncModuleScHandlerTbl);
return 0;
}
void module_exit (void)
{
printk("hello_module exit!\n");
API_SystemCallUnregister(LW_MODULE_SC_BASE);
}
/*
* module export symbols
*/
LW_SYMBOL_EXPORT void func00 (void)
{
printk("func00() run!\n");
}
/*
* module export symbols
*/
LW_SYMBOL_EXPORT void func11 (void)
{
printk("func11() run!\n");
}
步骤 5:修改应用实现
将生成工具生成的 mySysCallArg.h、mySysCallWrapper.c、mySysCallNr.h 复制到应用程序工程中进行编译。
在应用工程代码中调用 func00、func11 函数,以测试自定义系统调用功能。
#include <stdio.h> void func00 (void); void func11 (void); int main (int argc, char **argv) { printf("Hello SylixOS!\n"); func00(); func11(); return (0); }
在工程编译设置中,定义
__SYLIXOS_SRTPE
宏,生成的应用即可支持在容器内调用自定义的系统调用。
步骤 6:加载内核模块
使用
insmod
命令将内核模块部署到宿主环境。加载完成后,使用
syscalls
命令查看当前已经注册的系统调用信息。
步骤 7:执行系统调用
将应用可执行文件部署到容器内并执行。
在系统终端可看到系统调用被执行后的打印信息。
容器外应用场景兼容
通过上述步骤,用户可以在容器内调用内核模块,然而在容器外部则会调用失败,如下图所示。
针对容器内外均需要使用同一 app 的场景,需要如下操作:
步骤 1:新建 mk 文件
新建用于容器内使用的 srtp 库 mk 文件和用于容器外使用的非 srtp 库文件,具体模板如下所示:
include $(CLEAR_VARS_MK)
#*********************************************************************************************************
# Target
#*********************************************************************************************************
LOCAL_TARGET_NAME := libsys_app_srtp.so
#*********************************************************************************************************
# Source list
#*********************************************************************************************************
LOCAL_SRCS := \
src/mySysCallWrapper.c \
#*********************************************************************************************************
# Header file search path (eg. LOCAL_INC_PATH := -I"Your header files search path")
#*********************************************************************************************************
LOCAL_INC_PATH :=
#*********************************************************************************************************
# Pre-defined macro (eg. -DYOUR_MARCO=1)
#*********************************************************************************************************
LOCAL_DSYMBOL := \
-D__SYLIXOS_SRTPE
#*********************************************************************************************************
# Compiler flags
#*********************************************************************************************************
LOCAL_CFLAGS :=
LOCAL_CXXFLAGS :=
LOCAL_LINKFLAGS :=
#*********************************************************************************************************
# Depend library (eg. LOCAL_DEPEND_LIB := -la LOCAL_DEPEND_LIB_PATH := -L"Your library search path")
#*********************************************************************************************************
LOCAL_DEPEND_LIB :=
LOCAL_DEPEND_LIB_PATH :=
#*********************************************************************************************************
# Linker specific
#*********************************************************************************************************
LOCAL_NO_UNDEF_SYM := no
#*********************************************************************************************************
# C++ config
#*********************************************************************************************************
LOCAL_USE_CXX := no
LOCAL_USE_CXX_EXCEPT := no
#*********************************************************************************************************
# Code coverage config
#*********************************************************************************************************
LOCAL_USE_GCOV := no
#*********************************************************************************************************
# OpenMP config
#*********************************************************************************************************
LOCAL_USE_OMP := no
#*********************************************************************************************************
# Use short command for link and ar
#*********************************************************************************************************
LOCAL_USE_SHORT_CMD := no
#*********************************************************************************************************
# User link command
#*********************************************************************************************************
LOCAL_PRE_LINK_CMD :=
LOCAL_POST_LINK_CMD :=
LOCAL_PRE_STRIP_CMD :=
LOCAL_POST_STRIP_CMD :=
#*********************************************************************************************************
# Depend target
#*********************************************************************************************************
LOCAL_DEPEND_TARGET :=
include $(LIBRARY_MK)
#*********************************************************************************************************
# End
#*********************************************************************************************************
注意:
srtp 版本库 mk 文件在
LOCAL_DSYMBOL
位置需要添加-D__SYLIXOS_SRTPE
。
LOCAL_DSYMBOL := \
-D__SYLIXOS_SRTPE
非 srtp 版本库 mk 文件在
LOCAL_DSYMBOL
位置为空。
LOCAL_DSYMBOL :=
步骤 2:修改 IDE 设置
由于 IDE 会自动修改 mk 文件配置,因此需要进行修改,具体修改方式如图所示,选中 Do not scan source files
即可。
步骤 3:配置修改
应用 mk 文件需要注意修改以下部分:
LOCAL_SRCS
仅包含 app.c, 若出现 mySysCallWrapper.c 需要删除。
#*********************************************************************************************************
# Source list
#*********************************************************************************************************
LOCAL_SRCS := \
src/sys_app.c
LOCAL_DSYMBOL
若出现-D__SYLIXOS_SRTPE
,需要删除。
#*********************************************************************************************************
# Pre-defined macro (eg. -DYOUR_MARCO=1)
#*********************************************************************************************************
LOCAL_DSYMBOL := \
- 链接库添加如下配置:
#*********************************************************************************************************
# Depend library (eg. LOCAL_DEPEND_LIB := -la LOCAL_DEPEND_LIB_PATH := -L"Your library search path")
#*********************************************************************************************************
LOCAL_DEPEND_LIB := \
-lsys_app
LOCAL_DEPEND_LIB_PATH := \
-L"$(WORKSPACE_sys_app)/$(Output)/strip"
步骤 4: 工程编译
- 在工程
Makefile
文件中,增加步骤2添加的 mk 文件,如图所示:
#*********************************************************************************************************
# Include targets makefiles
#*********************************************************************************************************
include libsys_app.mk
include libsys_app_srtp.mk
include sys_app.mk
注意:
include 库 mk 位置需要在应用 mk 上方,否则会出现编译错误
应用编译成功后,会在 Release 文件夹下生成两个版本库文件,如图所示。其中 srtp 版本为容器内使用,另一个则为容器外使用。
步骤 5:执行系统调用
将应用执行文件部署在容器外部可正常使用。
容器内使用需要在 config.json
文件中 "mounts"
部分添加内容,将 srtp 版本库映射到容器内,且名称和非 srtp 版本一致,具体设置参考如下所示:
{
"destination": "/lib/libsys_app.so",
"source": "/lib/libsys_app_srtp.so",
"options":["rx"]
},
配置完成后,即可在容器内正常使用,如图。