linux内核模块基础知识

linux内核模块

linux内核模块机制:动态将组件加入到内核
内核模块本身并不被编译进内核文件(zImage或bzImage),在内核运行期间动态的安装或卸载

内核模块的程序结构:

  1. 模块加载函数(必须):module_init()的宏来指定
  2. 模每一种y块卸载函数(必须):module_exit()的宏来指定

每一种语言第一次都是从hello world开始的,内核模块也不例外
下面是一个简单的内核模块程序

		#include <linux/init.h>
		#include <linux/module.h>
		
		MODULE_LICENSE("Dual BSD/GPL");
		
		static int hello_init(void)
		{
				printk(KERN_ALERT "Hello, world\n");
				return 0;
		}
		
		static void hello_exit(void)
		{
				printk(KERN_ALERT "Goodbye, cruel world\n");
		}
		
		module_init(hello_init);
		module_exit(hello_exit);

这个模块定义了两个函数, 一个在模块加载到内核时被调用( hello_init )以及一个在模
块被去除时被调用( hello_exit ). moudle_init 和 module_exit 这几行使用了特别的内
核宏来指出这两个函数的角色. 另一个特别的宏 (MODULE_LICENSE) 是用来告知内核, 该模块带有一个自由的许可证; 没有这样的说明, 在模块加载时内核会抱怨。

printk 函数在 Linux 内核中定义并且对模块可用; 它与标准 C 库函数 printf 的行为相
似. 内核需要它自己的打印函数, 因为它靠自己运行, 没有 C 库的帮助. 模块能够调用
printk 是因为, 在 insmod 加载了它之后, 模块被连接到内核并且可存取内核的公用符号
字串 KERN_ALERT 是消息的优先级.

linux模块的安装与卸载命令

  • 加载 insmod (insmod hello.ko)
  • 卸载 rmmod (rmmod hello)
  • 查看 lsmod
  • 加载 modprobe (modprobe hello)

modprobe如同insmod,也是加载一个模块到内核,他们的不同之处在于它会根据文件系统 /lib/modules/($version)/module.dep 来查看加载的模块,看它们还依赖于其他模块,如果是:modprobe会先找到这些模块,把它们加载到内核

模块还有一些可选的信息:

  1. 作者: MODULE_AUTHOR(" ");
  2. 描述: MODULE_DESCRIPTION(" ");
  3. 模块版本: MODULE_VERSION(" ");
  4. 别名: MODULE_ALIAS(" ");

模块的参数:

  • module_param:模块参数用于加载模块时的传递参数给模块,类似int main(int argc,char **argv)

module_param(name,type,perm)
参数:
name:模块参数名称
type :参数类型
perm:参数访问权限
perm常见值:

  1. S_IRUGO :任何用户对 /sys/module 中出现的参数有读权限
  2. S_IWUSR:允许root用户修改 /sys/module 中出现的该参数

hello.ko内核模块的安装与卸载现象

编写过程序之后需要编写Makefile,如下:

 ifneq ($(KERNELRELEASE),)
  
  	 obj-m := hello.o
  	 else
  	  
  	 KDIR := /home/zhangbin/mini6410/linux-2.6.38
  	 all:
  	       make -C $(KDIR) M=$(PWD) 
 	 clean:
 	       rm -f *.ko *.o *.mod.c *.symvers *.order
  
 	 endif

执行make 后会有hello.ko文件.效果如下:

  root@xxx#:  insmod ./hello.ko
  Hello,world
  root@xxx#:  rmmod hello
  Goodbye cruel world
  root@xxx#: 

但是在内核模块加载中也会出现问题:常见的问题是:版本不匹配:
解决方法;

  1. 使用modprobe --force -modversion 强行插入 (不推荐)
  2. 确保编译内核模块时,所依赖的内核代码版本等同与当前正在运行的内核
    (uname -r 查看正在运行的内核版本)

补充:内核打印

printk 和 printf比较:中s

  • 相同点:都是打印信息
  • 不同点:printk 在内核打印中使用,printf 在应用程序中使用; printk允许根据严重程度,通过附加优先级来对消息分类

在 linux/kernel.h 中定义了8种记录级别:按优先级的递减顺序分:

  1. KERN_EMERG “<0>” 用于紧急消息,通常是崩溃信息
  2. KERN_ALERT “<1>” 立刻行动的信息
  3. KERN_CRIT “<2>” 严重情况
  4. KERN_ERR “<3>” 错误情况
  5. KERN_WARNING “<4>” 有问题的警告
  6. KERN_NOTICE “<5>” 正常情况,但是仍然值得注意
  7. KERN_INFO “<6>” 信息型消息
  8. KERN_DEBUG “<7>” 用作调试信息

没有指定级别的话,默认 DEFAULT_MESSAGE_LOGLEVEL 4

猜你喜欢

转载自blog.csdn.net/qq_41782149/article/details/89226205