《奔跑吧Linux内核(第二版)》第五章笔记

2023-05-16

Linux内核采用宏内核架构,即操作系统的大部分功能都在内核中实现,比如进程管理、内存管理、进程调度、设备管理等,并且都在特权模式下(内核空间)运行。而与之相反的另一种流行的架构是微内核架构,它把操作系统最基本的功能放入内核中,而其他大部分的功能(如设备驱动等)都放到非特权模式下,这种架构有天生优越的动态扩展性。

内核模块全称Loadable Kernel Module(LKM)。在内核运行时加载一组目标代码来实现某个特定的功能,这样在实际使用Linux的过程中可以不需要重新编译内核代码来实现动态扩展。

Linux内核通过内核模块来实现动态添加和删除某个功能。

简单的模块代码

#include <linux/init.h>
#include <linux/module.h>
 
static int __init my_test_init(void)
{
     printk("my first kernel module init\n");
     return 0;
}
  
static void __exit my_test_exit(void)
{
     printk("goodbye\n");
}
 
module_init(my_test_init);
module_exit(my_test_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("rlk");
MODULE_DESCRIPTION("my test kernel module");
MODULE_ALIAS("mytest");

第1行和第2行包含了两个Linux内核的头文件,其中<inux/init.h>头文件对应的是内核源代码的include/inux/init.h文件,在这个头文件中包含了第14行和第15行中的module_inito() 和module_exit() 函数的声明。<linux/module.h>头文件对应的是内核源代码的include/inux/module.h文件,包含了第18-21行的MODULE_AUTHOR()这些宏的声明。

第15行的module init()告诉内核这是该模块的入口。

第16行的module_exit()宏告诉内核这个模块的退出函数是my_test_exit()。

第4-8行是该内核模块初始化函数,这个函数在内核模块被加载时运行,可以使用insmod命令来加载一个内核模块。

第10-13行是该内核模块的退出函数,该函数在模块被卸载时自动运行,可以使用rmmod命令卸载一个内核模块。

第18-21行,MODULE_LICENSE()表示这个模块代码接受的软件许可协议。MODULE_AUTHOR()用来描述该模块的作者信息,可以包括作者的姓名和邮箱等。MODULE_DESCRIPTION()用来简单描述该模块的用途或者功能介绍。MODULE_ALIAS()为用户空间提供一个合适的别名。

下面我们来看编译这个内核模块的Makefile文件。

BASEINCLUDE ?= /lib/modules/`uname -r`/build

mytest-objs := my_test.o
obj-m  := mytest.o

all : 
      $(MAKE) -C $(BASEINCLUDE) M=$(PWD) modules;

clean:
      $(MAKE) -C $(BASEINCLUDE) M=$(PWD) clean;
      rm -f *.ko;

第1行的BASEINCLUDE指向正在运行Linux的内核编译目录,通过"uname -r"命令可以找到对应的内核版本。

第3行表示该内核模块需要哪些目标文件,格式是:
<模块名>-objs := <目标文件>.o

第4行表示要生成的模块。注意,模块名字不能和目标文件名相同。格式是:
obj-m := <模块名>.o

第6-7行表示要编译执行的动作。
这里的$(MAKE)就相当于make,-C 选项的作用是指将当前工作目录转移到你所指定的位置。“M=”选项的作用是,当用户需要以某个内核为基础编译一个外部模块的话,需要在make modules 命令中加入“M=dir”,程序会自动到你所指定的dir目录中查找模块源码,将其编译,生成KO文件。

第9-11行表示执行make clean需要的动作。

编译模块

在终端中输入make命令执行编译,编译完成之后会生成mytest.ko文件。
在这里插入图片描述

安装模块

接下来就可以安装我们的模块:
在这里插入图片描述

你会发现没有输出,别着急,因为例子中的输出函数printk()的默认输出等级,可以使用dmesg命令查看内核的打印信息。

在这里插入图片描述
另外,你可以通过1smod命令查看当前mytest模块是否已经被加载到系统中,它会显示模块之间的依赖关系。

在这里插入图片描述

加载模块之后,系统会在/sys/modules目录下新建一个目录,比如对于mytest模块会建一个名为mytest的目录。
在这里插入图片描述

卸载模块

可以通过rmmod卸载模块
在这里插入图片描述
在这里插入图片描述

模块参数

内核模块作为一个可扩展的动态模块,为Linux内核提供了灵活性。但是有时我们需要根据不同的应用场景给内核模块传递不同的参数。

1. 参数声明及初始化

如果需要向内核模块传递参数,该参数必须事先在模块代码中声明及初始化:

module_param(name,type,perm);
MODULE_PARM_DESC(parm,desc);

module_param()宏由3个参数组成,name表示参数名,type表示参数类型,perm表示参数的读写等权限。参数类型可以是byte,short,ushort,int,uint,long,ulong,char和bool等类型。perm指定在sysfs中相应文件的访问权限,如设置为0表示不会出现在sysfs文件系统中;如设置成S_IRUGO(0444)可以被所有人读取,但是不能修改;如设置成S_IRUGO|S_IWUSR(0644),说明可以让root权限的用户修改这个参数。

MODULE_PARM_DESC()宏为这个参数的简单说明。

例如上面的模块添加参数a,代码如4~6行所示,第11行将该参数打印出来

#include <linux/init.h>
#include <linux/module.h>
 
static int a = 100; 
module_param (a, int, 0644); 
MODULE_PARM_DESC(a, "test for module parameter");

static int __init my_test_init(void)
{
     printk("my first kernel module init\n");
     printk("module parameter=%d\n", a);
     return 0;
}
  
static void __exit my_test_exit(void)
{
     printk("goodbye\n");
}
 
module_init(my_test_init);
module_exit(my_test_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("rlk");
MODULE_DESCRIPTION("my test kernel module");
MODULE_ALIAS("mytest");

编译和加载上面的模块之后,通过dmesg查看内核登录信息,会发现输出a的值为默认值100。

在这里插入图片描述

2. 调用模块参数

当通过"insmod mymodule.ko a=200”命令来加载模块时,可以看到终端dmsg输出为:

在这里插入图片描述

3. 查看模块参数

/sys/module/XXXXX/parameters目录下面可以看到模块参数。

在这里插入图片描述

符号共享

我们在为一个设备编写驱动程序时,会把驱动按照功能分成好几个内核模块,这些内核模块之间有一些接口函数需要相互调用,这怎么实现呢?Linux内核为我们提供两个宏来解决这个问题。

EXPORT_SYMBOL()
EXPORT_SYMBOL_GPL()

EXPORT_SYMBOL()把函数或者符号对全部内核代码公开,也就是将一个函数以符号的方式导出给内核中的其他模块使用。
其中,EXPORT_SYMBOL_GPL()只能包含GPL许可的模块,内核核心的大部分模块导出来的符号都是使用GPL这种形式的。如果要使用EXPORT_SYMBOL_GPL()导出函数,那么需要显式地通过模块申明为"GPL",如MODULE_LICENSE(“GPL”)。

内核导出的符号表可以通过 cat /proc/kallsyms来查看。

在这里插入图片描述

其中,第1列显示的是该符号在内核地址空间的地址;第2列是符号属性,比如T表示该符号在text段中;第3列表示符号的字符串,也就是EXPORT_SYMBOL()导出来的符号;第4列显示哪些内核模块在使用这些符号。

内核模块结构总结

  • 模块加载函数:加载模块时,该函数会被自动执行,通常做一些初始化工作。
  • 模块卸载函数:卸载模块时,该函数也会被自动执行,做一些清理工作。
  • 模块许可声明:内核模块必须声明许可证,否则内核会发出被污染的警告。
  • 模块参数:根据需求来添加,为可选项。
  • 模块作者和描述声明:一般都需要完善这些信息。
  • 模块导出符号:根据需求来添加,为可选项。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

《奔跑吧Linux内核(第二版)》第五章笔记 的相关文章

  • 关于英伟达jetson nano的搭配双目摄像头跑ORB_SLAM2

    1 安装系统 按照商家给的资料安装 xff0c 将Ubuntu18 04LTS镜像拷贝到tf卡中 xff0c 插上jetson nano就可以安装了 2 系统设置 进入系统我先把系统语言设置为中文 xff0c 在右上角的设置中找到系统设置中
  • 双目摄像头(CSI-IMX219)的标定

    1 介绍 网上关于这类标定有挺多教程的 xff0c 但由于这个摄像头的特殊性 xff0c 所以不可能完全安装教程来走 目前来说有3种标定方法 xff1a ROS操作系统来标定 matlab标定 opencv标定 这三种方法我先试了用ROS来
  • 小学生学AD16(入门级别,看这篇就够了)

    1 软件安装 xff1a AD16的安装我就不多介绍了 xff0c csdn一搜一大把 要学一个软件 xff0c 那么软件安装是必经之路 xff0c 不要认为软件安装不重要 xff08 如果你的安装完之后桌面没快捷方式 xff0c 那么可以
  • Arduino串口绘图器双通道绘制

    Serial print val Serial print 34 34 Serial println muBiao 其实只用在两个变量之间加个 xff0c 就行了 参考网址 https www norwegiancreations com
  • 关于神舟笔记本TX8连副屏经常蓝屏的问题

    大概率是3060显卡驱动的问题 xff0c 可以试试重新安装显卡驱动 若还是不行就换个接口 xff0c 不要用hdim的接口 xff0c 那个是直接连3060的 换剩下两个的minidp接口其中一个 xff0c 第一个不要接 xff0c 那
  • 51单片机入门(小学生都能学会)

    序 xff1a 时隔一年 xff0c 我终于从二年级到三年级了 xff01 由于小学三年级这学期要学单片机 xff0c 故写下这篇笔记留下些什么 由于自己也是新手 xff0c 欢迎各位指出本文的各种错误 1 什么是51单片机 为什么要说这个
  • 解决使用WinScp连接Ubantu系统失败的问题---SSH无法连接

    起因 为了互通Linux系统和Windows系统的文件 xff0c 以更好的实现文件管理和资源共享 所以在查阅资料后 xff0c 使用WinScp xff0c WinSCP是一个Windows环境下使用SSH的开源图形化SFTP客户端 它的
  • 小学生51系列之基础知识

    1 单片机的基本结构 说到基本结构 xff0c 就是指51单片机的硬件组成 51单片机由中央处理器CPU 储存器 定时器 I O端口 组成 其中储存器包含数据储存器 xff08 RAM xff09 和程序储存器 xff08 ROM xff0
  • ros 接入Livox Mid-70

    最近在研究3d避障激光 大疆Livox mid 70 xff0c 记录下接入过程 环境信息 xff1a Ubuntu 18 04 ros melodic 1 livox view 点云可视化 xff08 1 xff09 根据livox mi
  • ROS+opencv实践-二维码识别

    一 安装二维码识别的功能包 sudo apt span class token operator span get install ros span class token operator span melodic span class
  • C语言简单链表详细步骤详解

    43 链表 gt 小阿豪带你写链表 xff01 xff01 xff01 xff01 进入正文 span class token number 1 span 首先 xff0c 先想好自己要创建的链表格式以及最后的的显示界面 xff01 xff
  • 滚球控制系统详解 —— (附核心代码)

    最近练习了17年的国赛题 滚球控制系统 这里展示一下画圆 xff1a 观看完整视频点这里 接下来 xff0c 我来分享一下从搭整体结构到调试完的过程 这是我搭完的整体结构 xff08 缩小版 xff09 不管什么题 xff0c 结构部分还是
  • 【Linux网络编程】你了解TIME_WAIT状态吗?

    在Linux网络编程中 xff0c 我相信大多数人觉得最难理解的就是TCP中的TIME WAIT状态了吧 xff0c 那么TIME WAIT的概念到底是什么 xff0c 有几个类型呢 xff0c 以及在面试中经常会问到的TIME WAIT状
  • 【图解】八幅图带你轻松掌握八大排序(上):冒泡排序、选择排序、插入排序、快速排序

    在算法中 xff0c 八大排序算是最简单的也是重中之重 xff0c 所以掌握好八大排序的思想是非常重要的 xff0c 很多人学排序的时候会觉得似懂非懂 xff0c 本篇文章作者耗时两小时绘制了八大排序的详细图解 xff0c 让大家快速理解八
  • 最详细整理STL之vector基础

    前言 xff1a Vector是一种可以存储任意类型的动态数组 xff0c 属于序列式容器 xff0c 可以用sort对其进行排序 xff0c 底层数据结构是数组 xff0c 可以随机访问元素 Vectors 包含着一系列连续存储的元素 其
  • STL之vector扩容机制

    前言 大家好 xff0c 我是萝卜 上期结尾说到vector的push back操作一般情况下时间复杂度为O 1 xff0c 是否存在特殊情况 那么本期就讲讲vector在容器空间不足时进行push back操作会发生什么 vector作为
  • 求职嵌入式软件开发linux kernel/BSP leader/工程师职位

    个人工作说明 xff1a 目前从事linux系统网络设备的开发工作 xff0c 负责bootloader linux kernel文件系统 xff0c driver移植 xff0c 以及开源app移植 主要技能和过去的经验 xff1a 1
  • 【2023最新】计算机网络面试题【收藏持续更新】

    你好 xff0c 我是萝卜 xff0c 我会在本篇文章持续更新关于计算机网络的面试题 最新内容更新日期 xff1a 2023 04 11 基础 说一下计算机网络体系结构 网络体系结构一般有三种 xff1a ISO七层模型 xff0c TCP
  • UDP协议详解

    概述 xff1a UDP只在IP的数据报服务之上增加了两个最基本的服务 xff1a 复用和分用以及差错检测 UDP不保证可靠交付 xff0c 但是不意味着应用对数据的要求是不可靠的 xff0c 只是所有维护可靠性的工作可由用户在应用层完成
  • TCP传输可靠性保证机制之重传机制

    TCP重传机制 tcp重传机制包括超时重传 快速重传 带选择确认的重传 SACK 重复SACK 四种 超时重传 xff1a 超时重传是tcp协议保证数据可靠性的一个重要机制 原理是在发送某一个数据以后开启一个计时器 xff0c 在一定时间内

随机推荐

  • VSCode:终端控制台常用指令

    常用的指令 以下是一些在 Visual Studio Code 终端控制台中常用的指令 xff1a 1 清除终端 xff1a clear 2 列出当前目录中的文件和文件夹 xff1a ls 3 切换到指定目录 xff1a xff1a cd
  • Ubuntu18.04安装ROS时rosdep update报错解决办法

    在安装ros进行rosdep update时经常会报错 xff0c 有时候可以通过换网解决 xff0c 但从我安装那么多次的经验来看 xff0c 仅有一次换手机热点后更新成功了 xff0c 其他都是失败 xff0c 成功率太低 从网上搜到了
  • 【STM32】STM32F103C8T6串口通信,实现3个串口收发数据

    串口通信 xff08 Serial Communications xff09 实现单片机与电脑或者其它外设进行通信 xff0c 通信时只需两根线 xff08 TX xff0c RX xff09 就可以实现数据传输 STM32f103有三个串
  • C语言学习笔记——(2)数组

    数组 1 什么是是数组2 数组的定义2 1数组的表达2 2数组的含义2 3数组的大小 xff1a 3 字符数组4 字符串操作5 二维数组 1 什么是是数组 数组是指有序的元素序列 如果将有限个类型相同的变量的集合命名 xff0c 那么这个名
  • 多线程编程实验

    xff08 一 xff09 查看下列程序并运行 xff0c 掌握如何通过扩展Thread类创建线程 span class token keyword package span span class token namespace case1
  • 实验一:基于Ubuntu系统实现无人机自主飞行

    ps xff1a 为避免出现错误 xff0c 在进行新的一步时 xff0c 需要关闭由于上一步操作打开的终端 xff0c 并开启一个新的终端 例如 xff1a 在开始第5步 安装MAVROS 之前 xff0c 关闭由于第3步 安装ROS 打
  • 5000字学习C语言错误处理的四种方式。

    C错误处理 在C语言中 xff0c 错误处理是一个非常重要的主题 通常情况下 xff0c 程序员需要在代码中处理错误 xff0c 以保证程序能够在出现错误时正确地处理这些情况 C语言中常见的错误类型包括 xff1a 语法错误 逻辑错误 运行
  • yum 源制作

    YUM介绍 YUM主要用于自动升级 安装 移除 rpm 软件包 xff0c 它能自动查找并解决 rpm 包之间的依赖关系 xff0c 要成功的使用 YUM 工具更新系统和软件 xff0c 需要有一个包含各种 rpm 软件包的 reposit
  • MATLAB021b与VS2022混编

    MATLAB2021b与VS2022混编 前言 目前在做一个大创项目 xff0c 其中用到关于Matlab与C的混合编程 xff0c 特此记录 Matlab2021b 如图所示 xff0c 红线划出的是即将使用的 c函数 xff0c 在左侧
  • 香橙派5使用NPU加速yolov5的实时视频推理(一)

    前言 xff1a 寒假里 xff0c 博主完成了树莓派4B搭载yolofastest V2的ncnn加速 xff0c 效果挺不错的 xff0c 但总感觉还是稍微差点意思 xff0c 于是就购买了一块香橙派5 xff0c 想要用RK3588芯
  • 香橙派5使用NPU加速yolov5的实时视频推理(二)

    三 将best onnx转为RKNN格式 这一步就需要我们进入到Ubuntu20 04系统中了 xff0c 我的Ubuntu系统中已经下载好了anaconda xff0c 使用anaconda的好处就是可以方便的安装一些库 xff0c 而且
  • 【STM32学习】——串口通信协议&STM32-USART外设&数据帧/输入数据策略/波特率发生器&串口发送/接受实操

    文章目录 前言一 串口通信1 通信接口2 串口通信 xff08 1 xff09 串口简介 xff08 2 xff09 串口硬件电路 xff08 3 xff09 串口软件部分 二 STM32的USART外设1 USART简介2 图示详解 三
  • 【STM32学习】——USART串口数据包&HEX/文本数据包&收发流程&串口收发HEX/文本数据包实操

    文章目录 前言一 数据包格式 xff08 江科大规定 xff09 1 HEX数据包2 文本数据包3 两者对比 二 数据包收发流程1 HEX数据包接收 xff08 只演示固定包长 xff09 2 文本数据包接收 xff08 只演示可变包长 x
  • buuctf simplerev 中的小头位序

    33条消息 BUUCTF SimpleRev xff08 涉及大小端序存储的问题 xff09 Ireb9z的博客 CSDN博客 buuctfsimplerev https blog csdn net afanzcf article deta
  • 简要分析网络编程——UDP编程

    计算机网络是指两台或更多的计算机组成的网络 xff0c 在同一个网络中 xff0c 任意两台计算机都可以直接通信 xff0c 因为所有计算机都需要遵循同一种网络协议 网络编程中有很多协议 xff0c 如 xff0c TCP协议 UDP协议
  • 数据结构之二叉树 Python实现

    树 树是一种非线性的数据结构 树 xff0c 它是若干结点的集合 xff0c 是由唯一的根和若个棵互不相交的子树组成的 其中 xff0c 每一棵子树又是一棵树 xff0c 也是由唯一的根结点和若干棵互不相交的子树组成的 由此可知 xff0c
  • 《奔跑吧Linux内核(第二版)》第四章笔记

    内核配置 内核配置工具常见的有 xff1a make config make oldconfig make menuconfig 内核配置工具最终会在Linux内核源码的根目录下生成一个隐藏文件 config文件 xff0c 这个文件包含了
  • GDB+QEMU调试Linux内核

    1 使用qemu创建虚拟机 使用qemu创建ARM64架构虚拟机可以参考我的另一篇博客 xff1a Ubuntu18 04使用qemu搭建ARM64架构虚拟机 xff08 二 xff09 2 安装gdb multiarch工具包 span
  • centos7 HA

    本文以两台机器实现双集热备高可用集群 xff0c 主机名node1的IP为192 168 122 168 xff0c 主机名node2的IP为192 168 122 169 一 安装集群软件 必须软件pcs xff0c pacemaker
  • 《奔跑吧Linux内核(第二版)》第五章笔记

    Linux内核采用宏内核架构 xff0c 即操作系统的大部分功能都在内核中实现 xff0c 比如进程管理 内存管理 进程调度 设备管理等 xff0c 并且都在特权模式下 xff08 内核空间 xff09 运行 而与之相反的另一种流行的架构是