【笔记】Linux驱动学习第一章
2015-06-25 14:51
621 查看
作者:Exculivor
日期:2015年6月25日
本次学习内容
简单模块Hello的编写
代码分析
简单Makefile的编写以及分析
模块的加载和卸载
代码分析
简单Makefile的编写以及分析
模块的加载和卸载
首先来看代码:
包含了模块初始化所需要的函数,
则包含了动态的将模块加载到内核中去的一些函数。
接下来的的宏定义内容:
则负责告诉内核,本模块采用的许可证是自由许可证;
“如果没有这样的许可证,内核在装载该模块时会产生抱怨。”
《linux设备驱动程序》中如是说,但是并没有详细阐明原因以及结果。我们将之注释掉后运行测试的结果为:
[13979.742518] hello: module license ‘unspecified’ taints kernel.
[13979.742572] Disabling lock debugging due to kernel taint
[13979.750285] hello module init
Linux遵循GPL协议,通常排斥非GPL软件。强行加入没有GPL许可证的模块直接导致内核判断自己被污染!
Linux内核识别的许可证有:
我们可根据相关协议的具体内容判断自己应该使用哪个协议,并包含进去。
接下来就是重点了。
这个模块的两个函数:
的作用为打印一条语句:
hello module init
至于使用的打印函数则要注意并不是我们常用的
这两个函数的功能类似,区别是printf的运行需要C库,而printk是内和自己的打印输出函数,并不依赖C库。
当模块加载到内核之中后,就可以访问内核的公用符号(包括函数和变量)。
后面的
根据不同的使用环境还有不同的的优先级:
第二个函数:
作用为输出另一条语句:
hello module exit
函数有了,按照我们的预想,加载模块的时候输出hello module init卸载模块的时候输出hello module exit。
但是写到这里还没完,内核并不知道什么时候该用哪个函数。所以我们需要为内核标记一下。于是我们调用两个函数:
加载模块时,内核会调用模块内传递给module_init的参数对应的函数,这里即
注意格式,Makefile对格式要求严格。
在此的构造过程中,该Makefile将被读取两次。
当从命令行执行make命令时,该Makefile将会被调用,此时是第一次读取该Makefile,变量KERNELRELEASE没有设置,ifeq条件不满足,所以会运行默认分支,定义
并且执行默认编译选项
从而第二次运行make命令,此次由于前面定义了
不成立,执行
即通过hello.o文件来生成一个目标模块,将目标模块名为hello.ko。
如果我们需要从多个文件生成目标模块,则可以使用:
之后可以通过shell命令
模块的卸载使用shell命令:
另外还可以通过shell命令:
来列出当前加载运行的模块。
日期:2015年6月25日
本次学习内容
简单模块Hello的编写
代码分析
简单Makefile的编写以及分析
模块的加载和卸载
本次学习内容:
简单模块——Hello的编写代码分析
简单Makefile的编写以及分析
模块的加载和卸载
简单模块——Hello的编写
按照惯例,我们仍然通过helloworld这个简单的小程序来进入驱动编写的世界。首先来看代码:
#include <linux/init.h> #include <linux/module.h> MODULE_LICENSE("Dual BSD/GPL"); static int hello_init(void) { printk(KERN_ALERT "hello module init\n"); return 0; } static void hello_exit(void) { printk(KERN_ALERT "hello module exit\n"); } module_init(hello_init); module_exit(hello_exit);
代码分析
代码中包含的两个头文件:#include <linux/init.h>
包含了模块初始化所需要的函数,
#include <linux/module.h>
则包含了动态的将模块加载到内核中去的一些函数。
接下来的的宏定义内容:
MODULE_LICENSE("Dual BSD/GPL");
则负责告诉内核,本模块采用的许可证是自由许可证;
“如果没有这样的许可证,内核在装载该模块时会产生抱怨。”
《linux设备驱动程序》中如是说,但是并没有详细阐明原因以及结果。我们将之注释掉后运行测试的结果为:
[13979.742518] hello: module license ‘unspecified’ taints kernel.
[13979.742572] Disabling lock debugging due to kernel taint
[13979.750285] hello module init
Linux遵循GPL协议,通常排斥非GPL软件。强行加入没有GPL许可证的模块直接导致内核判断自己被污染!
Linux内核识别的许可证有:
协议 | 简介 |
---|---|
GPL | 任意版本的GNU通用公共许可证 |
GPL v2 | GPL第二版 |
GPL and additional rignts | GPL及附加权利 |
Dual BSD/GPL | BSD/GPL双许可证 |
Proprietary | 专有 |
接下来就是重点了。
这个模块的两个函数:
static int hello_init(void) { printk(KERN_ALERT "hello module init\n"); return 0; }
的作用为打印一条语句:
hello module init
至于使用的打印函数则要注意并不是我们常用的
printf而是
printk。
这两个函数的功能类似,区别是printf的运行需要C库,而printk是内和自己的打印输出函数,并不依赖C库。
当模块加载到内核之中后,就可以访问内核的公用符号(包括函数和变量)。
后面的
KERN_ALERT定义了这条消息的优先级。
根据不同的使用环境还有不同的的优先级:
字符串 | 优先级 | 简介 |
---|---|---|
KERN_EMERG | 0 | 紧急事件消息,系统崩溃之前提示,表示系统不可用 |
KERN_ALERT | 1 | 报告消息,表示必须立即采取措施 |
KERN_CRIT | 2 | 临界条件,通常涉及严重的硬件或软件操作失败 |
KERN_ERR | 3 | 错误条件,驱动程序常用KERN_ERR来报告硬件错误 |
KERN_WARNING | 4 | 警告条件,对可能出现问题的情况进行警告 |
KERN_NOTICE | 5 | 正常但又重要的条件。常用于与安全相关的消息 |
KERN_INFO | 6 | 提示信息,如驱动程序启动时,打印硬件信息 |
KERN_DEBUG | 7 | 调试级别的消息 |
static void hello_exit(void) { printk(KERN_ALERT "hello module exit\n"); }
作用为输出另一条语句:
hello module exit
函数有了,按照我们的预想,加载模块的时候输出hello module init卸载模块的时候输出hello module exit。
但是写到这里还没完,内核并不知道什么时候该用哪个函数。所以我们需要为内核标记一下。于是我们调用两个函数:
module_init和
module_exit来为内核指路。
加载模块时,内核会调用模块内传递给module_init的参数对应的函数,这里即
hello_init函数。同样,退出时会调用传递给module_exit的参数对应的函数,这里是
hello_exit。
简单Makefile的编写以及分析
接下来我们需要编写Makefile来编译代码ifeq ($(KERNELRELEASE),) KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean: rm -rf *.o *.ko *.mod.c *.order *.symvers .PHONY: modules clean else obj-m := hello.o endif
注意格式,Makefile对格式要求严格。
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
-C指定内核源代码目录,此处保存有顶层的Makefile,这个顶层Makefile即Linux内核编译系统的入口。
M=指定在构造modules目标之前返回到当前目录,即把要生成的modules目标放在当前目录下。
在此的构造过程中,该Makefile将被读取两次。
当从命令行执行make命令时,该Makefile将会被调用,此时是第一次读取该Makefile,变量KERNELRELEASE没有设置,ifeq条件不满足,所以会运行默认分支,定义
KERNELDIR和
PWD:
KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd)
并且执行默认编译选项
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
从而第二次运行make命令,此次由于前面定义了
KERNELDIR故
ifeq ($(KERNELRELEASE),)
不成立,执行
else分支:
obj-m := hello.o
即通过hello.o文件来生成一个目标模块,将目标模块名为hello.ko。
如果我们需要从多个文件生成目标模块,则可以使用:
obj-m := module.o module-objs := file1.o file2.o
之后可以通过shell命令
make来生成hello.ko和通过shell命令
make clean来清除构造生成的文件。
模块的加载和卸载
模块的加载使用shell命令:insmod
模块的卸载使用shell命令:
rmmod
另外还可以通过shell命令:
lsmod
来列出当前加载运行的模块。
相关文章推荐
- OMAP3630 Linux I2C总线驱动分析
- Linux设备驱动开发环境的搭建
- C#学习进阶Hello World的17种写法代码分享
- Linux/Unix环境下的Make和Makefile详解
- Android 初识 Helloworld 详解
- Cocos2d-x学习入门之HelloWorld程序
- C语言之没有main函数的helloworld示例
- java 学习笔记(入门篇)_java程序helloWorld
- Python实现生成简单的Makefile文件代码示例
- (转)自动生成 Makefile 的全过程详解
- Git之`Hello, World`
- u-boot的Makefile分析
- 设备控制接口(ioctl 函数) 主要是在驱动中
- 关于linux模块驱动简单的Makefile
- 编译单个驱动的Makefile文件。
- makefile完全教程
- Linux内核Makefile文件
- Linux内核的Makefile
- Makefile 文件的相关知识(2)