内核是如何运行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;
}


目录
相关文章
|
3月前
|
NoSQL Linux Android开发
内核实验(三):编写简单Linux内核模块,使用Qemu加载ko做测试
本文介绍了如何在QEMU中挂载虚拟分区、创建和编译简单的Linux内核模块,并在QEMU虚拟机中加载和测试这些内核模块,包括创建虚拟分区、编写内核模块代码、编译、部署以及在QEMU中的加载和测试过程。
207 0
内核实验(三):编写简单Linux内核模块,使用Qemu加载ko做测试
|
3月前
|
存储 Linux 索引
Linux0.11 系统调用进程创建与执行(九)(上)
Linux0.11 系统调用进程创建与执行(九)
78 1
|
3月前
|
C语言
Linux0.11 系统调用进程创建与执行(九)(下)
Linux0.11 系统调用进程创建与执行(九)
34 1
|
2月前
|
Linux
linux内核执行fork时对写时复制的设置
linux内核执行fork时对写时复制的设置
|
6月前
|
Linux 编译器 调度
xenomai内核解析--双核系统调用(二)--应用如何区分xenomai/linux系统调用或服务
本文介绍了如何将POSIX应用程序编译为在Xenomai实时内核上运行的程序。
204 1
xenomai内核解析--双核系统调用(二)--应用如何区分xenomai/linux系统调用或服务
|
6月前
|
存储 Linux API
xenomai内核解析--双核系统调用(一)
本文介绍了Xenomai内核系统调用的实现,探讨了在Linux内核与Xenomai实时内核共存时,系统调用如何区分和交互。系统调用是用户空间与内核空间通信的关键,它提供了硬件抽象、系统稳定性、安全性和可移植性。在32位系统中,通过`int 0x80`指令触发,而在64位系统中,使用`syscall`指令。Xenomai通过I-pipe拦截系统调用,区分实时与非实时任务,并通过`cobalt_syscalls`表执行相应操作。文章还详细解析了系统调用表的生成和权限控制机制。
166 1
xenomai内核解析--双核系统调用(一)
|
6月前
|
API 调度
xenomai内核解析--双核系统调用(三)--如何为xenomai添加一个系统调用
本文介绍了如何在Xenomai中添加自定义系统调用`get_timer_hits()`,该调用用于获取CPU定时器中断次数。首先,在`syscall.h`中定义127号系统调用,并在`clock.h`和`clock.c`中声明和实现该函数。接着,更新libcobalt库以包含新接口。最后,提供了一个示例应用,演示如何在实时任务中使用此系统调用。编译内核和库后,运行示例程序显示定时器中断次数,体现了Xenomai的tickless特性。
85 1
|
Linux 编译器
内核是如何运行ko文件的--insmod命令
内核是如何运行ko文件的--insmod命令
621 0
|
Linux 开发工具
|
Linux 测试技术
linux内核探索--系统调用(传参)
linux内核探索--系统调用(传参)
169 0
linux内核探索--系统调用(传参)