《奔跑吧Linux内核(第二版)》第五章笔记
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`/buildmytest-objs := my_test.o
obj-m := mytest.oall : $(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列显示哪些内核模块在使用这些符号。
内核模块结构总结
- 模块加载函数:加载模块时,该函数会被自动执行,通常做一些初始化工作。
- 模块卸载函数:卸载模块时,该函数也会被自动执行,做一些清理工作。
- 模块许可声明:内核模块必须声明许可证,否则内核会发出被污染的警告。
- 模块参数:根据需求来添加,为可选项。
- 模块作者和描述声明:一般都需要完善这些信息。
- 模块导出符号:根据需求来添加,为可选项。
《奔跑吧Linux内核(第二版)》第五章笔记相关推荐
- 琢石成器――windows环境下32位汇编语言程序设计(第三版)笔记
琢石成器――windows环境下32位汇编语言程序设计(第三版)笔记 2011年12月20日 基础篇 第1章 背景知识 1 1.1 Win32的软硬件平台 1.1.1 80x86系列处理器简史 1.1 ...
- Windows环境下32位汇编语言程序设计(典藏版)(含CD光盘1张)
Windows环境下32位汇编语言程序设计(典藏版)(含CD光盘1张)(畅销10年,经典再现!) 罗云彬 著 ISBN 978-7-121-20759-4 2013年7月出版 定价:99.00元 75 ...
- Windows环境下32位汇编语言程序设计 相关资料
Windows环境下32位汇编语言程序设计.pdf:https://474b.com/file/15153148-465076702 <Windows环境下32位汇编语言程序设计>随书光盘 ...
- Windows环境下32位汇编语言程序设计(典藏版)
<Windows环境下32位汇编语言程序设计(典藏版) > 基本信息 作者: 罗云彬 出版社:电子工业出版社 ISBN:9787121207594 上架时间:2013-7-8 出版日期:2 ...
- windows环境下32位汇编语言程序设计 90盘_Python 0基础详细教程 环境安装01
Python语言有什么用,首先让大家了解Python语言的基本知识: Python语言是一种解释型,面向对象,动态数据类型的高级程序设计语言,Python语言是数据分析师的首选数据分析语言,通过数据挖 ...
- windows环境下32位汇编语言程序设计 90盘_程序设计作业题汇总
C语言程序的基本单位是函数 程序设计语言经历了"机器语言"-"汇编语言"-"高级语言"的发展过程. 编写C语言代码文件的拓展名为.c/编写C ...
- 《Windows环境下32位汇编语言程序设计》 第五章笔记
WM_COMMAND产生的条件:点击菜单, 点击加速键,点击子窗口按钮,点击工具栏按钮,点击列表框.这些时候都有command消息产生 wParam 高16位通知码,低16位命令ID, lParam ...
- Windows环境下32位汇编程序设计C版code--第四章
采用的编译环境为VC++6.0 (一)第一个窗口函数 FirstWindow.c#include <windows.h> LRESULT CALLBACK ProcWinMain(HWND ...
- Windows环境下32位汇编程序设计C版code--第五章(三)
(三)窗口子控件 #include <windows.h> #include "resource.h" HINSTANCE hInst; TCHAR szBuffer[ ...
- Windows环境下32位汇编程序设计C版code--第五章(二)
(二)图标和光标 #include <windows.h> #include "Resource.h" TCHAR szName[] = TEXT("Icon ...
最新文章
- java对象排序_java对象排序(Comparable)详细实例
- 修改自动生成get/set方法模板代码
- flowable支持的mysql版本_Flowable3-配置
- 华为发布基于第二代英特尔®至强®可扩展处理器家族的新一代服务器
- Nancy 学习-进阶部分 继续跨平台
- JVM优化系列-JVM内存溢出的原因
- 非旋Treap——维护数列
- YUV、YUV420P(YU12和YV12)、NV12、NV21编码
- Android优雅地判断软键盘弹出状态
- 【干货】Excel中的换行符,这几种用法你会哪些?
- WIN10删除微软拼音输入法,设置默认输入法为英文
- cyclone小知识(四)——利用cyclone和PS制作点云剖面图(包括画直角坐标系)
- mysql面试题50
- 如何利用CustomFont+PS制作字体
- LaTeX:pgf usepackage(宏包)的中译
- PS作业-Camera Raw滤镜练习
- 详解HTML的相对路径写法
- gihub上传本地项目简单步骤
- Linq to Sql 事务处理
- Kubernetes 网络入门
热门文章
- 获取impala下所有的数据库建表语句
- 宁波专业SEO,如何让网站快速排名?
- Matlab 遗传算法解决智能排课算法 一天四节课,上午两节,下午两节,同一门课不能相邻,特殊课程不能相邻(语文和英语,数学和科学),求可行方案?
- 如何查询202118山东高考成绩,往年高考成绩怎么查询 查询成绩的方法
- Mac环境下生成ssh密钥
- AndroidStudio项目组件化maven上传gradle-module aar上传
- WEB安全:什么是Cookie,Cookie数据泄漏的危害
- wait millis 60010, active 20, maxActive 20 处理 com.alibaba.druid.pool.GetConnectionTimeout
- foxmail配置qq邮箱(需要在QQ邮箱设置第三方授权码
- 人像摄影的美姿和构图技巧