我本仁慈,奈何苍天不许
分类: LINUX
2013-12-26 16:45:05
Linux内核模块开发
{//?什么是内核模块
可在运行时添加到内核中的代码被称为“模块”。
{//?内核模块和应用程序有何不同
应用 -- 模块
从头到尾单任务 预先注册进内核,被动的被调用的
应用空间 内核空间,权限大
段错误对系统危害小 段错误常会导致系统崩溃
}
}
{//?为何要用内核模块
1、减小内核体积,因为模块本身不被编译到内核镜像里面。
2、可以在内核中添加或删除功能而不用重新编译内核
}
{//?重点在那
掌握如何去创建和使用一个内核模块
}
{//?一个最简单的内核模块如何实现和使用的 重点
//---/hello_module/hello.c
#include
#include
#include
MODULE_LICENSE ("GPL"); //模块许可声明, 如果没GPL回导致报错内核被污染,或调用不了
static int __init hello_init (void) // 为安全起见,模块中使用的函数都用static,
/* __init 标记其后面的函数和数据被放入特定段中。
当模块被装载后,该函数会被仍掉,以释放其占用的内存。
*/
{
printk("Hello world\n");
return 0;
}
static void __exit hello_exit (void)
{
printk("Goodbye world\n");
}
module_init (hello_init); //模块加载入口声明
module_exit (hello_exit); //模块卸载入口声明
//---Makefile
ifeq ($(KERNELRELEASE),) /* 如果KERNELRELEASE 未定义则执行下面语句
(KERNELRELEASE 是内核源码的顶层Makefile定义的变量,在第一次读取执行此Makefile时,KERNELRELEASE没有被定义)*/
KERNELDIR ?= /lib/modules/$(shell uname -r)/build //linux 内核源码位置 这里是指ubuntu 的
#KERNELDIR ?= /root/linux-2.6.35 //对应arm板子的内核源码
PWD := $(shell pwd)
all: //make 时从该目标执行
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules /* -C $(KERNELDIR) 跳转到内核源码目录下读取那里的Makefile
M=$(PWD) 返回到当前目录继续读入、执行当前的Makefile,而此时 KERNELRELEASE已被定义
故执行下面的obj-m := hello.o 生成.ko 模块文件
最后的modules 它指向的是读入的kernel顶层Makefile里的modules
*/
clean: //清除编译生成的文件
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module* modules*
else
obj-m := hello.o //指明用目标文件hello.o 建立一个模块文件hello.ko
endif
//---使用
#make //编译生成模块文件hello.ko
#file hello.ko //查看一下格式,看编译的是 电脑的(Intel 80386), 还是板子的(ARM)
#insmod hello.ko //加载模块 ,另用modprobe也可,它会自动加载依赖的模块
/*
可能保错 insmod: can't insert 'hello.ko': invalid module format
原因就是格式不对(file hello.ko可查看)如编译的是电脑的hello.ko 缺放到板子上运行。
*/
#lsmod | grep hello //检测是否已加载 , lsmod 实际是读取/proc/modules
#rmmod hello /*卸载模块
在板子上可能报错 rmmod: chdir(/lib/modules): No such file or directory
rmmod: chdir(2.6.35-g9c29226-dirty): No such file or directory
需要建立对应的/lib/modules/2.6.35-g9c29226-dirty 目录
当报 rmmod: module 'hello' not found 时,原因是
busybox制作时选择简单module配置,会找/lib/modules 让内核导出依赖关系文件,所以rmmod 会坚持依赖关系,
其实已经卸载成功了的,可不必理会
*/
#dmesg //查看打印的信息
}
{//---扩展
1. 添加模块参数
static int myint = 420;
module_param (myint, int, 0400); //添加模块参数, 参数名,参数类型,参数读/写权限
#insmod hello.ko myint=500
#dmesg
2. 附加一些模块信息
MODULE_AUTHOR("Song Baohua"); //作者是谁
MODULE_DESCRIPTION("A simple Hello World Module"); //模块信息描述
#modinfo hello.ko //查看驱动模块信息
3. 模块间函数调用
//--module1.c
static int func1(void)
EXPORT_SYMBOL(func1); //EXPORT_SYMBOL 宏用于将符号导出到内核符号表/prob/kallsyms
//导出的符号,其他模块可使用,但要声明extern int func1(void);
//--module2.c
extern int func1(void);
static int func2(void)
{
func1();
}
}