Linux模块编程
1.1 模块学习什么
1.认识什么是模块?跟我学习的驱动有什么关系?
2.熟悉模块的安装,卸载,查看
3.熟悉模块的基本框架
4.熟悉模块的编程方法
1.2 内核模块概述
Linux 内核的整体结构非常庞大,其包含的组件也非常多。我们怎样把需要的部分都包含在内核中呢?一种方法是把所有需要的功能都编译到 Linux 内核。这会导致两个问题,一是生成的内核会很大,二是如果我们要在现有的内核中新增或删除功能,将不得不重新编译内核。
有没有一种机制使得编译出的内核本身并不需要包含所有功能,而在这些功能需要被使用的时候,其对应的代码可被动态地加载到内核中呢?
Linux 提供了这样的一种机制,这种机制被称为模块(Module),可以实现以上效果。模块具有以下特点。
1.模块本身不被编译入内核映像,从而控制了内核的大小。
2.模块一旦被加载,它就和内核中的其他部分完全一样。
1.3 认识模块
我们在配置内核的时候,在配置菜单看到有一种选项可以选择为<M> <*> < > 。
其中,<M>表示编译成模块,即modules,这个便于选项编译的代码不编译进内核zImage,而是编译成一个单独的文件,通常为后缀.ko(2.6以上内核版本是.ko,2.6内核之前是.o)文件,那么我们可以像软件一样选择安装和卸载这些.ko模块文件。
<*>表示编译进内核,就是将这一段模块代码编译到了zImage镜像文件去了,在内核启动的时候自动安装执行我们的模块代码,这样做类似于一些安装系统的时候自带的驱动,在安装系统的时候就已经安装好了。
< > 表示没有选择,不做任何事情。
所以,我们所说的模块就是linux下的那些.ko文件。
1.3.1 tiny4412提供的模块测试程序
在我们学习的Tiny4412提供的 Linux3.5 源码中有一项模块测试选项,如下:
Tiny4412module sample.
Symbol:TINY4412_HELLO_MODULE [=m]
Type: tristate
Prompt:Tiny4412 module sample
Definedat drivers/char/Kconfig:49
Dependson: ARCH_EXYNOS4 [=y]
Location:
-> DeviceDrivers
->Character devices
注意:因为有依赖项,所以它的依赖必须被选上,即ARCH_EXYNOS4 [=y]。
CONFIG_ARCH_EXYNOS4:
Samsung EXYNOS4 SoCs based systems
Symbol: ARCH_EXYNOS4[=y]
Type :boolean
Prompt: SAMSUNGEXYNOS4
Defined at arch/arm/mach-exynos/Kconfig:14
Depends on: ARCH_EXYNOS [=y]
Location:
-> SystemType
-> SAMSUNGEXYNOS SoCs Support
Selects: HAVE_SMP [=y] && MIGHT_HAVE_CACHE_L2X0 [=y]
这个测试文件在drivers/char/目录下的tiny4412_hello_moduls.c。当把它选择为<M>之后,编译就会在同级目录下生成.ko文件。
编译命令:make modules
在 Linux 系统中,几乎所有驱动都可以编译模块的形式。
总之,模块代码我们可以在系统启动后再安装(zImage文件中并不包含该选项对应的C代码)。也可以编译到内核,像内核配置菜单中选择为y的选项,对应的C代码会被编译到zImage文件中。
这里记住一句话:linux下模块不一定是驱动,但是驱动肯是一种模块。
示例:编译成模块
1)在linux内核内核配置菜单makememuconfig上把模块测试选项为M,然后退出保存。
2)编译成模块,如下:
[root@localhost linux-3.5]# make modules
scripts/kconfig/conf--silentoldconfig Kconfig
CHK include/linux/version.h
CHK include/generated/utsrelease.h
make[1]: “include/generated/mach-types.h”是最新的。
CALL scripts/checksyscalls.sh
CC [M] crypto/ansi_cprng.o
CC [M] drivers/char/tiny4412_hello_module.o
CC [M] drivers/scsi/scsi_wait_scan.o
Building modules, stage 2.
MODPOST 3 modules
CC crypto/ansi_cprng.mod.o
LD [M] crypto/ansi_cprng.ko
CC drivers/char/tiny4412_hello_module.mod.o
LD [M] drivers/char/tiny4412_hello_module.ko
CC drivers/scsi/scsi_wait_scan.mod.o
LD [M] drivers/scsi/scsi_wait_scan.ko
[root@localhost linux-3.5]#
以上就会在drivers/char/生成了tiny4412_hello_module.ko文件。
然后我们可以查看一下它的存在:
[root@localhost linux-3.5]# cd drivers/char/
[root@localhost char]# ls tiny4412_hello_module.ko -l
-rw-r--r--. 1root root 29062 9月 25 11:26 tiny4412_hello_module.ko
[root@localhost char]#
有了.ko文件,那么我们可在以外部独立的来加载到内核,怎么加载呢?又怎么卸载呢?
Linux系统提供专业的命令来完成这样的事情,下面来介绍这几个命令。
1.3.2 Linux模块安装,卸载,查看
Linux下模块提供有安装,卸载,查看安装了那个模块以及查看模块信息等命令。
1.3.1、模块相关命令
insmod <file name.ko> |
安装模块进内核 |
rmmod <file name> |
卸载指定的模块 |
lsmod |
查看当前系统安装了哪些模块 |
modinfo <file name> |
查看模块信息 |
1.insmod -- 安装模块
示例:
[root@JUNJIA /home]# insmod tiny4412_hello_module.ko
[ 140.030000] Hello, Tiny4412 module is installed !
[root@JUNJIA /home]#
2.lsmod -- 列出当前系统已经安装的模块及模块间的依赖关系(不包含被编译的内核的模块代码)
示例:
[root@JUNJIA /home]# lsmod
tiny4412_hello_module 773 0 - Live 0xbf000000
第1列:模块名
第2列:模块大小
第3列:被引用多少次(本模块的代码被多少个模块调用)
第4列:被哪个模块引用
说明:
lsmod 命令实际上读取并分析/proc/modules文件。
在安装模块的时候我们可能会遇到这样的问题,模块版本和要装的linux内核版本不同会出现问题。
比如我修改了编译模块的内核版本号,然后编译查看模块信息:
[root@localhostlinux-3.5]# modinfo drivers/char/tiny4412_hello_module.ko
filename: drivers/char/tiny4412_hello_module.ko
license: GPL
depends:
intree: Y
vermagic: 3.5.0-FriendlyARM_JUNJIASMP preempt mod_unload ARMv7 p2v8
[root@localhostlinux-3.5]#
安装会出现以下问题:
[root@JUNJIA/home]# insmod tiny4412_hello_module.ko
[3212.730000] tiny4412_hello_module: version magic '3.5.0-FriendlyARM_JUNJIASMP preempt mod_unload ARMv7 p2v8 ' should be '3.5.0-FriendlyARMSMP preempt mod_unload ARMv7 p2v8 '
insmod:can't insert 'tiny4412_hello_module.ko': invalid module format
[root@JUNJIA/home]#
这个错误是说模块 版本号是3.5.0-FriendlyARM_JUNJIA,而内核版本号是3.5.0-FriendlyARM,不匹配不能进行加载。那么我就只能
结论:模块版本和内核版本不同是不能安装模块的。
3.rmmod -- 卸载模块(编译在内核的模块代码不可以移除)
示例: