一.Linux内核介绍
1.Linux 内核很庞大,相应的包含的组件也非常多。Linux文件就是常说的zImage和bzImage,在内核启动期间会被解压到内存。
2.新的使用组件的思路:动态加载和卸载。也就是需要这个组件的时候才去加载,不需要的时候,就卸载。即内核模块机制。
3.关于内核模块。有以下特征:
(1)不被编译进内核文件
(2)可以动态加载和卸载
4.关于内核模块的操作
(1)加载insmod
(2)卸载rmmod
(3)查看lsmod
二.设计和编写
1.分析和结构概括
2.代码编写
#include <linux/init.h>
#include <linux/module.h>
static int hello_init()
{
printk(KERN_WARNING"Hello world!\n");
return 0;
}
static void hello_exit()
{
printk(KERN_WARNING"hello exit!\n");
}
module_init(hello_init);
module_exit(hello_exit);
(1)一般init函数是static int类型的,exit函数式static void类型的
(2)printk和printf的区别是printk最前面需要的是表示优先级的参数
三.Makefile编写
1.需要一个变量指明我们最终产生的内核模块的名字
(1)如果内核模块只有一个源文件,一般模块名称和原文件一样,只是把.c改成.o
obj-m := helloworld.o
(2)如果有多个源文件,那么就应该是模块名可以随便,但是还要多一条语句
模块名-objs := file1.o file2.o file3.o
2.定义一个变量指明内核代码所在的路径。因为模块是基于内核的,你用什么版本的内核作为基础,编译出来的模块只能在同版本的内核使用。
KIR := /内核源代码路径
3.编写规则,只有目标all,但是没有依赖,却有命令。
make -C
(KDIR)M=
(pwd) modules CROSS_COMPILE = arm-linux ARCH = arm
-C指明要进入-C后面的路径(内核路径)编译模块,M指明了模块文件的路径
4.最后编写clean伪指令,清除产生的中间文件和.ko文件。将ko文件复制到文件系统。
obj-m := helloworld.o
KDIR := /home/S5-driver/lesson7/linux-tq2440
all:
make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm
clean:
rm -f *.o *.ko *.order *.symvers
5.rmmod的时候要在/lib/modules目录下面有和内核模块的内核版本一致的目录名
经常用(uname -r)来获取内核版本
mkdir -p /lib/modules/$(uname -r)
6..用tftp 地址 文件名的命令下载内核到sdram,然后用nfs挂载文件系统,启动Linxu系统,之后对内核模块进行操作。
四.模块可选项
1.模块申明
(1)MODULE_LICENSE(“遵守的协议”)
没有这一个申明,在加载模块的时候会报警告。
(2)MODULE_AUTHOR(“作者”)
(3)MODULE_VERSION(“版本”)
(4)MODULE_DESCRIPTION(“功能描述”)
2.模块参数
(1)和普通应用程序一样,在加载模块的时候,可以给模块传递一些参数。
(2)区别在于,要事先申明这些参数的数据类型和变量名字,而且要用到
module_param(name,type,perm)这个宏定义。他用来指明保存模块参数的变量。
name:变量名
type:变量类型,一般是int,bool以及charp(字符串类型,记住是charp,不是char和char*)
perm:权限。一般分为S_IRUGO和S_IWUSR。通常情况下将他们按位或。
3.模块符号导出
(1)当一个模块要使用另一个模块的函数(变量)的时候,如果没有符号导出,不仅要实现这个函数,还要申明这个函数导出给其他模块使用,否则在其他模块使用这个函数的时候会出错,甚至不能加载要使用它的模块。
(2)使用EXPORT_SYMBOL(符号名)或者EXPORT_SYMBOL_GPL(符号名)来申明。后者只可以用于遵循GPL协议的模块。