目录
一 内核模块结构
例子:
#include <linux/kernel.h> //需要包含的内核头文件
#include <linux/module.h> //模块头文件
//模块的入口函数 __init 是linux定义的关键字,表示这是一个入口函数
static int __init hello_module_init(void)
{
printk("Hello,module is installed !\n");
return 0;
}
//模块出口函数 __exit linux定的关键字,表示出口
static void __exit hello_module_cleanup(void)
{
printk("Good-bye, module was removed!\n");
}
//这两个函数分别是模块加载函数和模块卸载函数
module_init(hello_module_init);
module_exit(hello_module_cleanup);
//表示模块许可声明,这个声明是必须的,如果没有这个声明,在加载模块是会出现内核污染警告
MODULE_LICENSE("GPL");
二 模块编译测试
2.1 编译
2.1.1 Makefile 文件的书写
编译使用 makefile 文件编译,具体书写方法:
obj-m += module_001.o
//内核所在目录
KDIR:=/root/workdir/linux-3.5/
all:
make -C $(KDIR) M=$(PWD) modules
//调用内核编译时的makefile文件,便宜当前文件夹下的文件
clean:
rm -f *.o *.mod.o *.mod.c *.symvers *.markers *.order
2.1.2编译方法
[root@localhost 001]# make
make -C /root/workdir/linux-3.5/ M=/rootfs/root/driver/001 modules
make[1]: Entering directory `/root/workdir/linux-3.5'
CC [M] /rootfs/root/driver/001/module_001.o
Building modules, stage 2.
MODPOST 1 modules
CC /rootfs/root/driver/001/module_001.mod.o
LD [M] /rootfs/root/driver/001/module_001.ko
make[1]: Leaving directory `/root/workdir/linux-3.5'
2.2 加载模块
[root@TXM 001]#insmod /root/driver/001/module_001.ko
[ 113.885000] this is a init of my first module !
2.3 卸载模块
[root@TXM /]#rmmod /root/driver/001/module_001.ko
[ 126.075000] this is a exit of my first module !
三 模块参数
与c语言函数一样,模块也可以有函数
3.1 c语言主函数的参数形式
int main(int argc,char *argv[],char **envarg)
3.2 linux内核模块参数形式
//使用特定的函数向模块接口函数加载参数
module_param(num, int, 0644);
//num传入参数,int参数类型,0644 参数权限(与文件权限一样)
参数类型有:
int
char
uint
charp
long
short
bool
//向模块接口函数传入数组
module_param_array(a, int,&num, 0644);
//a数组,int类型,num 个数(系统自动生成,一定加 & ),0644权限
例:
#include <linux/kernel.h>
#include <linux/module.h>
int num;
int a[10];
module_param(num,int,0644);
module_param_array(a, int,&num, 0644);
static int __init module_002_init(void)
{
int i;
printk("this is a init of my second module !\n");
printk("num = %d\n",num);
for(i=0;i<num;i++)
printk("%d\n",a[i]);
return 0;
}
static void __exit module_002_exit(void)
{
printk("this is a exit of my second module !\n");
}
module_init(module_002_init );
module_exit(module_002_exit);
MODULE_LICENSE("GPL");
有参数时加载内核模块的方法:
[root@TXM 002]# insmod module_002.ko a=1,2,3
[ 4504.475000] this is a init of my second module !
[ 4504.475000] num = 3
[ 4504.475000] 1
[ 4504.475000] 2
[ 4504.475000] 3
四 多模块同时编译
4.1 程序
模块1:
#include <linux/kernel.h>
#include <linux/module.h>
#include "print.h"
int num;
int a[10];
module_param(num,int,0644);
module_param_array(a, int,&num, 0644);
static int __init module_001_init(void)
{
printk("this is a init of my first module !\n");
printk("num = %d\n",num);
print_me(num,a);
return 0;
}
void print_me(int num,int *a)
{
int i;
for(i=0;i<num;i++)
printk("%d\n",a[i]);
}
EXPORT_SYMBOL(print_me);
static void __exit module_001_exit(void)
{
printk("this is a exit of my first module !\n");
}
module_init(module_001_init );
module_exit(module_001_exit);
MODULE_LICENSE("GPL");
模块2:
#include <linux/kernel.h>
#include <linux/module.h>
#include "print.h"
int num;
int a[10];
module_param_array(a, int,&num,0644);
static int __init tiny4412_hello_module_init(void)
{
printk("Hello, Tiny4412 module is installed !\n");
print_me(num,a);
return 0;
}
static void __exit tiny4412_hello_module_cleanup(void)
{
printk("Good-bye, Tiny4412 module was removed!\n");
}
module_init(tiny4412_hello_module_init);
module_exit(tiny4412_hello_module_cleanup);
DULE_LICENSE("GPL");
Makefile文件:
obj-m += module_002.o module_003.o
KDIR:=/root/workdir/linux-3.5/
all:
make -C $(KDIR) M=$(PWD) modules
rm -f *.o *.mod.o *.mod.c *.symvers *.markers *.order
clean:
rm -f *.o *.mod.o *.mod.c *.symvers *.markers *.order
4.2 编译结果
[root@localhost 002]# make
make -C /root/workdir/linux-3.5/ M=/rootfs/root/driver/002 modules
make[1]: Entering directory `/root/workdir/linux-3.5'
CC [M] /rootfs/root/driver/002/module_002.o
CC [M] /rootfs/root/driver/002/module_003.o
Building modules, stage 2.
MODPOST 2 modules
CC /rootfs/root/driver/002/module_002.mod.o
LD [M] /rootfs/root/driver/002/module_002.ko
CC /rootfs/root/driver/002/module_003.mod.o
LD [M] /rootfs/root/driver/002/module_003.ko
make[1]: Leaving directory `/root/workdir/linux-3.5'
rm -f *.o *.mod.o *.mod.c *.symvers *.markers *.order
4.3 加载卸载
[root@TXM 002]# insmod module_003.ko a=1,2,3
[ 4485.560000] module_003: Unknown symbol print_me (err 0)
insmod: can't insert 'module_003.ko': unknown symbol in module, or unknown parameter
[root@TXM 002]# insmod module_003.ko
[ 4495.560000] module_003: Unknown symbol print_me (err 0)
insmod: can't insert 'module_003.ko': unknown symbol in module, or unknown parameter
可见先加载 module_003 会出错,因为没有函数 print_me
[root@TXM 002]# insmod module_002.ko a=1,2,3
[ 6160.900000] this is a init of my first module !
[ 6160.900000] num = 3
[ 6160.900000] 1
[ 6160.900000] 2
[ 6160.900000] 3
[root@TXM 002]# insmod module_003.ko a=1,2,3
[ 6166.995000] Hello, Tiny4412 module is installed !
[ 6166.995000] 1
[ 6166.995000] 2
[ 6166.995000] 3
[root@TXM 002]# rmmod module_002.ko
rmmod: can't unload 'module_002': Resource temporarily unavailable
[root@TXM 002]# rmmod module_003.ko
[ 6189.220000] Good-bye, Tiny4412 module was removed!
[root@TXM 002]# rmmod module_002.ko
[ 6196.330000] this is a exit of my first module !
由上面运行结果可以看出,如果先卸载 module_002.ko 会出错,无法卸载,因为 module_003.ko 正在使用。
五 多文件编译成一个模块
5.1 程序
主函数
#include <linux/kernel.h>
#include <linux/module.h>
#include "print.h"
int num;
int a[10];
module_param_array(a, int,&num, 0644);
static int __init module_001_init(void)
{
printk("this is a init of my first module !\n");
printk("num = %d\n",num);
print_me(num,a);
return 0;
}
static void __exit module_001_exit(void)
{
printk("this is a exit of my first module !\n");
}
module_init(module_001_init );
module_exit(module_001_exit);
MOD`
LE_LICENSE("GPL");
子函数
#include "print.h"
void print_me(int num,int *a)
{
int i;
for(i=0;i<num;i++)
printk("%d\n",a[i]);
}
Makefile文件
obj-m += module_004_1.o
/*
module_004_1.o相当于打包生成的文件
module_004.o & print.o 是依赖的文件
*/
module_004_1-objs:=module_004.o print.o
#KDIR:=/lib/modules/$(shell uname -r)/build
KDIR:=/root/workdir/linux-3.5/
all:
make -C $(KDIR) M=$(PWD) modules
rm -f *.o *.mod.o *.mod.c *.symvers *.markers *.order
clean:
rm -f *.o *.mod.o *.mod.c *.symvers *.markers *.order
5.2 编译
[root@localhost 003]# make
make -C /root/workdir/linux-3.5/ M=/rootfs/root/driver/003 modules
make[1]: Entering directory `/root/workdir/linux-3.5'
CC [M] /rootfs/root/driver/003/module_004.o
CC [M] /rootfs/root/driver/003/print.o
LD [M] /rootfs/root/driver/003/module_004_1.o
Building modules, stage 2.
MODPOST 1 modules
CC /rootfs/root/driver/003/module_004_1.mod.o
LD [M] /rootfs/root/driver/003/module_004_1.ko
make[1]: Leaving directory `/root/workdir/linux-3.5'
rm -f *.o *.mod.o *.mod.c *.symver *.markers *.order
5.3 挂载卸载
[root@TXM 003]# insmod module_004_1.ko a=1,2,3
[ 9760.095000] this is a init of my first module !
[ 9760.095000] num = 3
[ 9760.095000] 1
[ 9760.095000] 2
[ 9760.095000] 3
[root@TXM 003]# rmmod module_004_1.ko
[10228.120000] this is a exit of my first module !
[root@TXM 003]#