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

这篇具有很好参考价值的文章主要介绍了内核是如何运行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)

finit_module,Linux驱动,# 内核模块,linux,驱动开发,c语言,arm,嵌入式

__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);
}

finit_module,Linux驱动,# 内核模块,linux,驱动开发,c语言,arm,嵌入式

我们来看一下这个宏定义。这个宏定义定义在: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__)

finit_module,Linux驱动,# 内核模块,linux,驱动开发,c语言,arm,嵌入式

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)

finit_module,Linux驱动,# 内核模块,linux,驱动开发,c语言,arm,嵌入式文章来源地址https://www.toymoban.com/news/detail-791380.html

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;
}

到了这里,关于内核是如何运行ko文件的--系统调用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【嵌入式Linux】编译应用和ko内核模块Makefile使用记录

    在Makefile中,变量的赋值可以使用以下几种方式: = :最基本的赋值符号,表示简单的延迟展开(lazy expansion)方式。变量的值将会在使用变量的时候进行展开。 := :立即展开(immediate expansion)的赋值方式。变量的值在赋值的时候立即展开,并且在后续的使用中不再改变。

    2024年02月08日
    浏览(50)
  • RK3568驱动指南|驱动基础进阶篇-进阶1 编译进内核的驱动系统是如何运行的?

    瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统,主要面向物联网

    2024年02月01日
    浏览(53)
  • KO之间互相调用

    假设有两个KO,命名为moduleA.KO,moduleB.KO,现在要实现在moduleB.KO中调用moduleA.KO中的函数。 源码: moduleA导出符号moduleA_func。 编译Makefile实现: 编译: 可以看出,moduleA_func已经在导出的符号表中了。 源码: 编译Makefile: 1、插入moduleA.ko 2、插入moduleB.ko 可以看出,moduleB成功调

    2024年02月05日
    浏览(39)
  • 基于Ko-time的Springboot单体化调用链追踪实践

    目录 前言 一、关于Ko-Time 1、是什么?  2、ko-time更新时间线 二、Ko-time怎么用? 1、依赖引入 2、配置集成 3、权限放行 三、链路追踪  1、系统运行  2、链路追踪  3、长时间调用模拟  总结         熟悉微服务的老司机一定了解,在微服务模式下,在一次调用链路中,可

    2024年02月15日
    浏览(42)
  • Linux内核学习(四)—— 系统调用(基于Linux 2.6内核)

    在现代操作系统中,内核提供了用户进程与内核进行交互的一组接口,这些接口在应用程序和内核之间扮演了使者的角色。这些接口保证了系统的稳定可靠,避免应用程序肆意妄行。 系统调用在用户空间进程和硬件设备之间添加了一个中间层。有三个作用: 第一,它为用户

    2024年02月12日
    浏览(41)
  • 【Linux 内核源码分析笔记】系统调用

    在Linux内核中,系统调用是用户空间程序与内核之间的接口,它允许用户空间程序请求内核执行特权操作或访问受保护的内核资源。系统调用提供了一种安全可控的方式,使用户程序能够利用内核功能而不直接访问底层硬件。 系统调用: 通过系统调用,用户程序可以请求内核

    2024年02月03日
    浏览(40)
  • 探索操作系统:内核、启动和系统调用的奥秘

    首先,对于有科班背景的读者,可以跳过本系列文章。这些文章的主要目的是通过简单易懂的汇总,帮助非科班出身的读者理解底层知识,进一步了解为什么在面试中会涉及这些底层问题。否则,某些概念将始终无法理解。这些计算机基础文章将为你打通知识的任督二脉,祝

    2024年02月11日
    浏览(55)
  • Windows系统下如何运行.sh脚本文件

    前言: .sh文件是一种命令脚本文件,在Windows系统下可以通过命令行工具打开运行。通常可以使用Git工具来打开运行.sh脚本文件。不过很多第一次使用Git的人,可能对Git工具不熟悉。.sh文件在命令行运行时是有固定写法的,下面介绍详细步骤。 1.下载并安装Git 首先,建议先挂

    2024年02月11日
    浏览(39)
  • 《Linux内核源码分析》(2)进程原理及系统调用

    操作系统的作用 :作为硬件的使用层,提供使用硬件资源的能力, 进程的作用 :作为操作系统使用层,提供使用操作系统抽象出的资源层的能力 进程、线程和程序的区别 :进程指计算机中已运行的程序。进程本身不是基本的运行单位,而是线程的容器。 程序本身只是指令

    2024年02月07日
    浏览(47)
  • 调试linux内核(2): poll系统调用的实现

    linux内核为用户态进程提供了一组IO相关的系统调用: select/poll/epoll, 这三个系统调用功能类似, 在使用方法和性能等方面存在一些差异. 使用它们, 用户态的进程可以\\\"监控\\\"自己感兴趣的文件描述符, 当这些文件描述符的状态发生改变时, 比如可读或者可写了, 内核会通知进程去处

    2024年02月11日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包