Harmony南向驱动开发: LiteOS-内核系统调用指南

185 篇文章 0 订阅
181 篇文章 2 订阅

OpenHarmony LiteOS-A内核实现态与内核态的区分隔离,用户态程序不能直接访问内核资源,而系统调用则为用户态程序提供了一种访问内核资源、与内核进行交互的通道。如下图所示,用户程序通过调用System API(系统API,通常是系统提供的POSIX接口)进行内核资源访问与交互请求,POSIX接口内部会触发SVC/SWI异常,完成系统从用户态到内核态的切换,然后对接到内核的Syscall Handler(系统调用统一处理接口)进行参数解析,最终分发至具体的内核处理函数。

OpenHarmony LiteOS-A内核文档之学习--系统调用-鸿蒙开发者社区

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_syscallHandle[(id)] = (UINTPTR)(fun);                                            \
⑵      g_syscallNArgs[(id) / NARG_PER_BYTE] |= ((id) & 1) ? (nArg) << NARG_BITS : (nArg); \
    }                                                                                      \

    #include "syscall_lookup.h"
#undef SYSCALL_HAND_DEF
}

LOS_MODULE_INIT(OsSyscallHandleInit, LOS_INIT_LEVEL_KMOD_EXTENDED);

1.2 syscall/los_syscall.h文件

kernel/liteos_a/syscall/los_syscall.h文件中维护内核的系统调用对接函数声明。函数实现一般在目录/kernel/liteos_a/syscall下的源代码文件中。该文件主要被如下源文件include使用。

./kernel/liteos_a/fs/vfs/vfs_cmd/vfs_shellcmd.c:50:#include "los_syscall.h"
./kernel/liteos_a/kernel/extended/blackbox/los_blackbox_core.c:46:#include "los_syscall.h"
./kernel/liteos_a/kernel/user/src/los_user_init.c:33:#include "los_syscall.h"
./kernel/liteos_a/syscall/fs_syscall.c:49:#include "los_syscall.h"
./kernel/liteos_a/syscall/los_syscall.c:38:#include "los_syscall.h"
./kernel/liteos_a/syscall/net_syscall.c:37:#include "los_syscall.h"

1.3 系统调用函数编号

维护系统调用编号文件有2个,需要分别在用户态和内核态维护系统调用函数编号。除了文件porting/liteos_a/kernel/include/bits/syscall.h中多个几个参数数目的宏定义外,下述两个文件的内容基本相同。

  • third_party/musl/porting/liteos_a/user/arch/arm/bits/syscall.h.in

  • third_party/musl/porting/liteos_a/kernel/include/bits/syscall.h

2. 系统调用开发示例

当需要新增一个系统调用接口时,可以参考下述步骤:

  • 在LibC库中确定并添加新增的系统调用号。
  • 在LibC库中新增用户态的函数接口声明及实现。
  • 在内核系统调用头文件中确定并添加新增的系统调用号及对应内核处理函数的声明。
  • 在内核中新增该系统调用对应的内核处理函数。

2.1 在LibC库中确定并添加新增的系统调用号

编辑文件porting/liteos_a/user/arch/arm/bits/syscall.h.in,如下所示,其中⑴处的__NR_new_syscall_sample为新增系统调用号。需要注意同时更新下⑵处的编号。

2.2 在LibC库中新增用户态的函数接口声明及实现。

系统调用提供基础的用户态程序与内核的交互功能,不建议开发者直接使用系统调用接口,推荐使用内核提供的对外POSIX接口。需要在LibC库中新增用户态接口的声明与实现。为了简化,我们在现成的一个源文件里增加一函数实现代码,如third_party/musl/porting/liteos_a/user/src/aio/aio.c文件中增加:

/* 新增系统调用用户态的接口实现 */
void newSyscallSample(int num)
{
     printf("user mode: num = %d\n", num);
     __syscall(SYS_new_syscall_sample, num);
     return;
}

2.3 在内核系统调用头文件中新增系统调用号

在内核系统调用头文件中新增系统调用号,如下所示,在third_party/musl/porting/liteos_a/kernel/include/bits/syscall.h文件中,__NR_new_syscall_sample为新增系统调用号。用户态代码和内核态代码增加系统调用号方式相同,编号相同。

/* OHOS customized syscalls, not compatible with ARM EABI */
#define __NR_OHOS_BEGIN         500
#define __NR_pthread_set_detach (__NR_OHOS_BEGIN + 0)
...
#define __NR_sysconf            (__NR_OHOS_BEGIN + 21)
#define __NR_new_syscall_sample (__NR_OHOS_BEGIN + 22) /* 新增的系统调用号 __NR_new_syscall_sample:522 */
#define __NR_syscallend         (__NR_OHOS_BEGIN + 23)
...

kernel/liteos_a/syscall/syscall_lookup.h中,增加一行,如下。

...
/* 当前现有的系统调用清单 */
SYSCALL_HAND_DEF(__NR_chown, SysChown, int, ARG_NUM_3)
SYSCALL_HAND_DEF(__NR_chown32, SysChown, int, ARG_NUM_3)
#ifdef LOSCFG_SECURITY_CAPABILITY
SYSCALL_HAND_DEF(__NR_ohoscapget, SysCapGet, UINT32, ARG_NUM_2)
SYSCALL_HAND_DEF(__NR_ohoscapset, SysCapSet, UINT32, ARG_NUM_1)
#endif
/* 新增系统调用 */
SYSCALL_HAND_DEF(__NR_new_syscall_sample, SysNewSyscallSample, void, ARG_NUM_1)
...

2.4 在内核中新增系统调用对应的处理函数

需要在内核中新增系统调用函数声明及函数实现,并加入编译构建文件。首先,如下所示,在kernel/liteos_a/syscall/los_syscall.h中,SysNewSyscallSample为新增系统调用的内核处理函数声明。

...
/* 当前现有的系统调用内核处理函数声明清单 */
...
extern int SysTimerGettime64(timer_t timerID, struct itimerspec64 *value);
...
/* 新增的系统调用内核处理函数声明 */
extern void SysNewSyscallSample(int num);
...

然后在kernel/liteos_a/syscall目录下新建个源文件syscall_demo.c,新增系统调用的内核处理函数实现如下。

#include "los_printf.h"
/* 新增系统调用内核处理函数的实现 */
void SysNewSyscallSample(int num)
{
    PRINTK("kernel mode: num = %d\n", num);
    return;
}

最后,在文件kernel/liteos_a/syscall/BUILD.gn中增加对syscall_demo.c源文件的编译管理。

import("//kernel/liteos_a/liteos.gni")

module_switch = defined(LOSCFG_KERNEL_SYSCALL)
module_name = get_path_info(rebase_path("."), "name")
kernel_module(module_name) {
  sources = [
    "fs_syscall.c",
......
    "syscall_demo.c"
  ]
}

2.5 调用并验证

参考官网Hello World示例,修改示例applications/sample/camera/apps/src/helloworld.c,增加系统调用内容newSyscallSample(10)

#include <stdio.h>
#include "syscall.h"

/* 新增系统调用用户态的接口实现 */
void newSyscallSample(int num)
{
     printf("user mode: num = %d\n", num);
     __syscall(SYS_new_syscall_sample, num);
     return;
}

int main(int argc, char **argv)
{
    printf("\n************************************************\n");
    printf("\n\t\tHello OHOS!\n");
    printf("\n************************************************\n\n");
    newSyscallSample(10);
    return 0;
}

在工程根目录,hb set选择产品ipcamera_hispark_taurus,然后hb build构建,使用Device Tool工具烧录Hi3516开发板,运行在串口得到输出结果如下。用户态接口与内核态接口均有输出,证明系统调用已使能。

OpenHarmony LiteOS-A内核文档之学习--系统调用-鸿蒙开发者社区

最后

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。 

点击领取→【纯血版鸿蒙全套最新学习资料】(安全链接,放心点击希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!

这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、(南向驱动、嵌入式等)鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。

 鸿蒙(HarmonyOS NEXT)最新学习路线

有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

HarmonyOS Next 最新全套视频教程

 《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

《鸿蒙开发基础》

  • ArkTS语言
  • 安装DevEco Studio
  • 运用你的第一个ArkTS应用
  • ArkUI声明式UI开发
  • .……

《鸿蒙开发进阶》

  • Stage模型入门
  • 网络管理
  • 数据管理
  • 电话服务
  • 分布式应用开发
  • 通知与窗口管理
  • 多媒体技术
  • 安全技能
  • 任务管理
  • WebGL
  • 国际化开发
  • 应用测试
  • DFX面向未来设计
  • 鸿蒙系统移植和裁剪定制
  • ……

《鸿蒙进阶实战》

  • ArkTS实践
  • UIAbility应用
  • 网络案例
  • ……

大厂面试必问面试题

鸿蒙南向开发技术

鸿蒙APP开发必备

鸿蒙生态应用开发白皮书V2.0PDF


请点击→纯血版全套鸿蒙HarmonyOS学习资料

总结
总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。 

                   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值