内核是如何运行ko文件的--系统调用

简介: 内核是如何运行ko文件的--系统调用

现在我们己经知道insmod命令做了什么事情,当我们使用insmod命令加载ko文件的时候,会调用系统调用init_module和finit_module。那什么是系统调用呢?

什么是系统调用

系统调用是操作系统扌是供给编程人员的接囗,当编程人员写程序时,因为上层应用不能直接操作硬件,所以就要利用系统调用接囗来请求操作系统的照务,如访问硬件。系统调用是和CPU架进行绑定的。和内核版本也有关系。

回到init_module和finit_module这俩个系统调用就是应用程序调用系统调用,内核就会执行运行ko文件的操作。

系统调用的流程

以为init_module例,原型为:

#define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)

syscall函数原型:

long int syscall(long int sysno,.....)

参数sysno为系统调用号,每个系统有一个唯一的系统调用号来标识对应的函数。

…是可变参数,是系统调用所以带的参数。

作用:根据系统调用号,调用相应的系统调用。

那__NR_init_module和个函数绑定了呢?打开include/uapi/asm-generic/unistd.h文件,找到以下代码:

/* kernel/module.c */
#define __NR_init_module 105
__SYSCALL(__NR_init_module, sys_init_module)
#define __NR_delete_module 106
__SYSCALL(__NR_delete_module, sys_delete_module)

__SYSCALL将系统调用号与sys_init_module函数绑定。这里有一个规律,在用户空间

我们使用xxx函数,对应的系统调用的函数就是sys_xxx;

sys_init_module函数定义在kernel/module.h文件中。sys_init_module函数定义是一个宏

定义。如下图所示

SYSCALL_DEFINE3(init_module, void __user *, umod,
        unsigned long, len, const char __user *, uargs)
{
    int err;
    struct load_info info = { };
    err = may_init_module();
    if (err)
        return err;
    pr_debug("init_module: umod=%p, len=%lu, uargs=%p\n",
           umod, len, uargs);
    err = copy_module_from_user(umod, len, &info);
    if (err)
        return err;
    return load_module(&info, uargs, 0);
}
SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)
{
    int err;
    struct load_info info = { };
    err = may_init_module();
    if (err)
        return err;
    pr_debug("finit_module: fd=%d, uargs=%p, flags=%i\n", fd, uargs, flags);
    if (flags & ~(MODULE_INIT_IGNORE_MODVERSIONS
              |MODULE_INIT_IGNORE_VERMAGIC))
        return -EINVAL;
    err = copy_module_from_fd(fd, &info);
    if (err)
        return err;
    return load_module(&info, uargs, flags);
}

我们来看一下这个宏定义。这个宏定义定义在:include/linux/syscall.h中。如下图所示:

#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)

SYSCALL_DEFlNE3宏定义中的3代表3个参数。这里一共有6个宏定义,所以我们最多可以带6个参数。

__VA_ARGS__等价于void __user *, umod,unsigned long, len, const char __user *, uargs
#define SYSCALL_DEFINE0(sname)                    \
    SYSCALL_METADATA(_##sname, 0);                \
    asmlinkage long sys_##sname(void)
#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)
#define SYSCALL_DEFINEx(x, sname, ...)                \
    SYSCALL_METADATA(sname, x, __VA_ARGS__)            \
    __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
#define __PROTECT(...) asmlinkage_protect(__VA_ARGS__)
#define __SYSCALL_DEFINEx(x, name, ...)                    \
    asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))    \
        __attribute__((alias(__stringify(SyS##name))));        \
    static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__));    \
    asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__));    \
    asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__))    \
    {                                \
        long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__));    \
        __MAP(x,__SC_TEST,__VA_ARGS__);                \
        __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__));    \
        return ret;                        \
    }                                \
    static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__))

向系统中添加一个系统调用

步骤

1.在内核源码中添加自己的服务,需要编译进入内核

#include <linux/kernel.h>
#include <linux/syscall.h>
SYSCALL_DEFINE0(helloworld){
    printk("this is my syscall helloworld\n");
    return 0;
}

2.添加系统调用号

修改include/uapi/asm-generic/unistd.h

vi include/uapi/asm-generic/unistd.h

加入

#define __NR_helloworld 1080
__SYSCALL(__NR_helloworld, sys_helloworld)

修改

#undef __NR_syscalls
#define __NR_syscalls (__NR_helloworld+1)

3.编译烧写

4.测试

#include <stdio.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#define __NR_helloworld 1080
int main(int argc,char *argv[]){
   syscall(__NR_helloworld);
        printf("here\n");
        return 0;
}


目录
相关文章
|
1月前
|
NoSQL 编译器 Linux
征服黑盒:手把手教你在QNX系统里玩转编译器与调试器
本文深入解析QNX微内核系统原理与开发实践:从“极简稳定”的微内核架构、核心消息传递机制,到交叉编译(qcc)、远程调试(GDB+pdebug)、性能分析(System/Application Profiler)及共享内存等高阶技术,覆盖驱动开发、C++移植、ROS 2集成与实战IPC服务构建,助力嵌入式开发者掌握车规级实时系统开发全栈能力。(239字)
274 9
|
10月前
|
开发者
HarmonyOS实战:GIF图下载突破5M限制保存到相册
本文介绍了在鸿蒙开发中解决图片下载问题的方法,包括突破5M流限制及识别图片真实格式(如GIF)。通过分段下载和类型判断,有效解决了大图下载失败及格式错误问题,适合开发者参考实践。
289 0
|
存储 NoSQL 关系型数据库
什么是DBMS及其类型
【8月更文挑战第3天】
1745 6
什么是DBMS及其类型
|
弹性计算 JSON 网络协议
记一次饱经挫折的ROS部署经历
阿里云资源编排服务ROS(Resource Orchestration Service)是一个基础设施即代码(IaC)工具,用于自动化部署和管理阿里云上的多种资源。ROS通过JSON或YAML格式的模板来定义资源栈,模板中包括资源类型、参数、依赖关系等,简化了云资源的创建和更新流程。
|
Android开发
基于Amlogic 安卓9.0, 驱动简说(五):基于GPIO、LED子系统的LED驱动
这篇文章是关于如何在基于Amlogic T972的Android 9.0系统上,使用GPIO和LED子系统来实现LED驱动的教程,包括了DTS设备树配置、驱动源码编写以及如何在用户空间控制LED的亮度和开关。
752 0
基于Amlogic 安卓9.0, 驱动简说(五):基于GPIO、LED子系统的LED驱动
|
存储 Java 数据库
基于全志H713 Android 11:给TvSettings添加default.xml默认值
本文介绍了在全志H713 Android 11平台上为TvSettings应用添加HDMI CEC功能的默认设置值的方法,通过修改SettingsProvider的源码和配置文件来实现默认值的设置,并提供了详细的步骤和测试结果。
828 0
基于全志H713 Android 11:给TvSettings添加default.xml默认值
|
JavaScript 前端开发
WebView2 控件(基于 Microsoft Edge (Chromium) 的嵌入式浏览器控件),获取网页加载后的标题
在使用 WebView2 控件(基于 Microsoft Edge (Chromium) 的嵌入式浏览器控件)时,要获取网页加载后的标题,可以监听 WebView2 的 NavigationCompleted 事件。这个事件被触发时,表示导航已完成,此时执行JavaScript代码可以安全地获取网页的标题。
1008 0
WebView2 控件(基于 Microsoft Edge (Chromium) 的嵌入式浏览器控件),获取网页加载后的标题
|
存储 Linux 芯片
OpenSBI三种固件的区别
OpenSBI三种固件的区别
|
监控 Java 应用服务中间件
tomcat目录结构及配置文件详解
上篇文章讲解了怎么去安装tomcat,本篇文章讲解一下tomcat的目录及配置文件
|
消息中间件 Unix Linux
【ZMQ polling机制】ZMQ异步接收机制以及与epoll/select的对比分析
【ZMQ polling机制】ZMQ异步接收机制以及与epoll/select的对比分析
1278 0

热门文章

最新文章