赞
踩
1.什么是内核模块 .ko
驱动程序已编译通过、未经连接的目标文件.ko,不能独立运行
需要使用时,动态加载 insmod *.ko
不需要时卸载 rmmod
优点:
(1)减小内核镜像的尺寸,灵活加载卸载
(2)不需要重新编译内核,缩短项目开发时间
缺点:
(1)降低系统运行效率
(2)模块本身有缺陷的话,使用不当会导致内核崩溃
2.如何设计一个内核模块程序
linux内核模块程序没有main函数,至少有两个函数:入口(初始化)函数、出口(卸载)函数
加载模块时,入口函数被内核调用
卸载模块时,出口函数被内核调用
static int __init xxx_init(void)
{
//由驱动程序员决定
return 0;----函数正常执行结束
}
static void __exit xxx_exit(void)
{
//由驱动程序员决定
}
module_init(xxx_init);—告诉内核xxx_init是入口函数
module_exit(xxx_exit);—告诉内核xxx_exit是出口函数
MODULE_LICENSE(“GPL”);—声明该模块程序遵循GPL协议
3.内核模块程序的编译
条件:(1)需要内核源码
(2)内核源码针对硬件平台配置过
(3)内核源码正确地编译通过
编写Makefile
obj-m += module.o #obj-m编译成内核模块*.ko 思考:+= := ?= = 有何区别
CROSS_DIR=/home/gec/6818GEC/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-
KERNEL_DIR=/home/gec/6818GEC/kernel
all:
#用编译内核源码的编译规则来编译当前目录下的内核模块程序,编译成*.ko
make ARCH=arm CROSS_COMPILE=$(CROSS_DIR) -C $(KERNEL_DIR) M=`pwd` modules
clean:
make ARCH=arm CROSS_COMPILE=$(CROSS_DIR) -C $(KERNEL_DIR) M=`pwd` modules clean
4.传输*.ko到开发板的根文件系统
(1)串口方式
[root@GEC6818 /]#rx module.ko------->点击“传输”---->点击发送Xmodem—>选中*.ko
CCCCC
xmodem trl+C ?
(2)tftp
[root@GEC6818 /]#tftp -g -r module.ko 192.168.11.3
(3)nfs
[root@GEC6818 /]#mount -t nfs -o nolock 192.168.11.3:/opt/nfs /mnt
[root@GEC6818 /]#cd /mnt
[root@GEC6818 /mnt]#ls
[root@GEC6818 /mnt]#ls
module.ko
加载模块时,入口函数被内核调用
insmod module.ko
问题1:
[root@GEC6818 /mnt]#insmod module.ko
[ 4452.871000] module: version magic '3.4.39-xxx SMP preempt mod_unload ARMv7 p2v8 ’ should be '3.4.39-1862 SMP preempt mod_unload ARMv7 p2v8 ’
insmod: can’t insert ‘module.ko’: invalid module format
[root@GEC6818 /mnt]#uname -r
3.4.39-1862
编译内核模块使用的内核版本是3.4.39-xxx ,开发板上运行的内核的版本是3.4.39-1862 ,不一致导致加载失败
解决:
方法(1)把版本为3.4.39-xxx 的内核镜像刷机
方法(2)把编译内核模块使用的内核源码版本改为3.4.39-1862
a.进入内核源码目录
b. make menuconfig
General setup --->
(-1862) Local version - append to kernel release
c.保存退出
d.gec@ubuntu:~/6818GEC/kernel$ cp .config arch/arm/configs/GEC6818_defconfig
gec@ubuntu:~/6818GEC/kernel$ cd …
gec@ubuntu:~/6818GEC$ ./mk -k
e.重新编译内核模块
内核模块相关的几个命令
modinfo-----查看内核模块文件的相关信息
gec@ubuntu:/mnt/hgfs/driver/3.module/code/module1$ modinfo module.ko
filename: /mnt/hgfs/driver/3.module/code/module1/module.ko
description: just a test module
author: XLG
license: GPL
depends:
vermagic: 3.4.39-1862 SMP preempt mod_unload ARMv7 p2v8
lsmod-----罗列出系统中动态加载的内核模块
[root@GEC6818 /mnt]#lsmod
module 720 0 - Live 0xbf000000 (O)
rmmod -----------卸载内核模块
[root@GEC6818 /mnt]#rmmod module
rmmod: can’t change directory to ‘3.4.39-1862’: No such file or directory
问题2:卸载模块时,提示3.4.39-1862目录文件没有
解决:
[root@GEC6818 /lib/modules]#mkdir 3.4.39-1862
问题3:
加载卸载内核模块时,printk并没有打出信息
原因:printk输出的信息是有优先级的,低级别的信息没有打印出来
printk.h (include\linux) 9233 2016/7/18
#define KERN_EMERG “<0>” /* system is unusable /
#define KERN_ALERT “<1>” / action must be taken immediately /
#define KERN_CRIT “<2>” / critical conditions /
#define KERN_ERR “<3>” / error conditions /
#define KERN_WARNING “<4>” / warning conditions /
#define KERN_NOTICE “<5>” / normal but significant condition /
#define KERN_INFO “<6>” / informational /
#define KERN_DEBUG “<7>” / debug-level messages */
[root@GEC6818 /lib/modules]#cat /proc/sys/kernel/printk
7 7 1 7
int console_printk[4] = {
DEFAULT_CONSOLE_LOGLEVEL, /* console_loglevel /
DEFAULT_MESSAGE_LOGLEVEL, / default_message_loglevel /
MINIMUM_CONSOLE_LOGLEVEL, / minimum_console_loglevel /
DEFAULT_CONSOLE_LOGLEVEL, / default_console_loglevel */
};
7------只有级别比该级别高的信息才会打印显示
7------默认的消息日志信息级别,printk(“xxx_init\n”);没有指定级别时,默认的级别
1-----控制台日志信息所能设置的最高级别
7-----默认的控制台日志级别
解决办法:
方法(1):printk("<4>"“xxx_init\n”) 或者printk(KERN_ALERT"xxx_init\n")
方法(2):[root@GEC6818 /mnt]#echo “7 4 1 7” > /proc/sys/kernel/printk
临时有效,系统重启,变回"7 7 1 7"
方法(3):重新配置编译内核,刷机
a.进入内核源码目录
b. make menuconfig
Kernel hacking —>
(4) Default message log level (1-7)
c.保存退出
d.gec@ubuntu:~/6818GEC/kernel$ cp .config arch/arm/configs/GEC6818_defconfig
gec@ubuntu:~/6818GEC/kernel$ cd …
gec@ubuntu:~/6818GEC$ ./mk -k
e.得到新的内核镜像后,刷机
1.一个驱动模块调用了另一个驱动模块的某个函数
修改Makefile
obj-m += module.o #obj-m编译成内核模块*.ko 思考:+= := ?= = 有何区别
obj-m += add.o
在add.c中
int xxx_add(int x,int y)
{
return (x+y);
}
EXPORT_SYMBOL(xxx_add);----把xxx_add导入到内核的全局函数符号表
[root@GEC6818 /mnt]#cat /proc/kallsyms | grep “xxx_add”
bf024064 r __kstrtab_xxx_add [add]
bf024038 r __ksymtab_xxx_add [add]
bf024000 T xxx_add [add]
注意:
加载时,先加载add.ko 后加载module.ko
卸载时,先卸载module.ko ,后卸载add.ko
2.如何把多个*.c,编译成一个*.ko
修改Makefile
obj-m += xxx.o
xxx-objs += add.o module.o
add.c中只保留函数xxx_add的定义
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。