Linux内核模块开发(笔记)
个人笔记。。在不放过来都快找不到了。有空还得好好整理一下了。
调试方法
kernel oops messages
内核模块简单介绍
最简单的内核模块
注:如果是 redhat 安装的话,需要安装 kernel-devel 才能写内核模块,如果是自己编译内核,记的不要删除源码,不然没法开发模块。
#include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> /* __init 的标记是内核模块的入口,这个函数加载完后就会释放内存空间 */ static int __init hello_init( void ) { printk(KERN_INFO "Hello world" ); /* 打印的信息会出现在 dmesg 中 释放*/ return 0; /* 返回 0 是正常 */ } /* __exit 的标记是退出内核模块,当这个模块卸载时会执行 */ static void __exit hello_exit( void ) { printk(KERN_INFO "Goodbye world" ); } /* 下面这二个是宏,初始化和消除函数时使用和上面的装载卸载模块没关系。 */ module_init(hello_init); module_exit(hello_exit); |
放个编译上面模块的 Makefile
obj-m := hello.o all: make -C /lib/modules/$(shell uname -r )/build M=$(shell pwd) modules clean: make -C /lib/modules/$(shell uname -r )/build M=$(shell pwd) clean |
给 Makefile 放到上面 hello.c 的相同的目录中(如果上面写的模块代码叫 hello.c 的话)。然后使用 make 就能编译了。
insmod lsmod rmmod
调用 insmod 时会给需要的模块加载进内核,会给 ko 的文件以目标代码加载。装载时会调用 module_init 指定的函数。退出也调用相应的 module_exit.
lsmod 可以显示你写的模块,其实是读 /proc/modules 。接下来我写写怎么样自己通过内核来建 proc 文件。
模块加载参数
如果在模块加载时,想指定参数,也提供了相应的头文件
#include <linux/moduleparam.h> static int test; module_param(test, int , 0644); |
这样以后,直接在内核模块内使用 test 的变量就行了。
模块的信息
在程序中可以为模块加一些描述,发行版权声明,和作者。
MODULE_LICENSE( "GPL" ); MODULE_DESCRIPTION( "Test" ); MODULE_AUTHOR( "xxx" ); |
模块的符号导出
在 Perl 中,模块是可以导出变量和方法到其它的模块中的。在 Linux 内核中也有这样的方法。
EXPORT_SYMBOL(name); EXPORT_SYMBOL_GPL(name); |
这二个可以导出指定的全局变量,也可以是方法。这个要加载 <linux/module.h> 的头文件,不要忘记了。
其它的模块要使用这个,直接使用 extern void name(void); 就可以使用了。这些导出的函数只能内核和内核模块使用。不能用户调用,可以由 /proc/kallsyms 来查看导出的变量和方法
实例
写个内核模块,通过 proc 可以见到一些信息,通过 proc 的读和写的功能。来实现设置和读取信息。
proc 介绍
proc 是一个非常方便的用来动态的向 Linux 内核加入和禁用代码的一个方法。
proc/sys 中是用来配置内核的参数,可以通过 sysctl -w key=value
象普通文件可以支持 open,read,write,close
例如
读
cat /proc/cpuinfo |
写
echo fukei-name > /proc/sys/kernel/hostname |
proc 的功能实现
proc 在 c 中是一个结构体来实现的,是 struct proc_dir_entry 。它可以给读写绑定到特定的函数上。然后通过别人对 proc 中文件的操作来触发和回调相应的绑定的函数。
read_proc 和 write_proc 是这个结构体的成员,也是一种结构体。函数就注册在这个上面。有兴趣的同学可以看看 include/linux/proc_fs.h 中的 read_proc_t 和 write_proc_t 的定义。
实现起来也简单。
struct proc_dir_entry *proc_entry = create_proc_entery(....); int my_read_proc() { } proc_entry->read_proc = my_read_proc(); |
在这的 create_proc_entery 会返回一个 proc_dir_entry 的结构体的引用。失败就是 NULL 。
这样,当用户空间进行 read 的系统调用时,如使用 cat proc 中的内容时。内核会调用注册到 read_proc 上的这个 my_read_proc 来实现的.
#include <linux/module.h> #include <linux/proc_fs.h> #include <linux/sched.h> #include <linux/mm.h> #define MODULE_NAME "Memory" int my_read_proc( char *page, char **start, off_t off, int count, int *eof, void *data) { struct task_struct *tsk = current; int len; len = sprintf ( page, "This module info: task %s pid %d\n" ,tsk->comm, tsk->pid ); return len; } struct proc_dir_entry *proc_entry; int init_module( void ) { proc_entry = create_proc_entry(MODULE_NAME, 0644, NULL); if (proc_entry==NULL){ remove_proc_entry(MODULE_NAME, NULL); } proc_entry->read_proc = my_read_proc; return 0; } void cleanup_module( void ) { remove_proc_entry(MODULE_NAME, NULL); // 退出和出错记的删除 } MODULE_LICENSE( "GPL" ); |
建议继续学习:
- linux内核研究笔记(一)内存管理 – page介绍 (阅读:8509)
- PHP内核介绍及扩展开发指南―Extensions 的编写 (阅读:4614)
- 我的内核配置文件 (阅读:3669)
- Linux内核协议栈对于timewait状态的处理 (阅读:3665)
- PHP内核介绍及扩展开发指南―高级主题 (阅读:3562)
- PHP内核介绍及扩展开发指南―基础知识 (阅读:3362)
- 在 Dell PowerEdge 1950 上安装 Linux 2.6.32-rc8 内核的问题与解决 (阅读:3019)
- 在Ubuntu上使用SystemTap (阅读:3001)
- 内核编译升级失败了以后的处理方案 (阅读:2926)
- [Linux]编译一个 RHEL 定制的内核 rpm 包 (阅读:2815)
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:扶凯 来源: 扶凯
- 标签: 内核
- 发布时间:2011-11-21 00:21:11
- [66] Go Reflect 性能
- [66] Oracle MTS模式下 进程地址与会话信
- [65] 如何拿下简短的域名
- [59] android 开发入门
- [59] IOS安全–浅谈关于IOS加固的几种方法
- [59] 图书馆的世界纪录
- [58] 【社会化设计】自我(self)部分――欢迎区
- [53] 视觉调整-设计师 vs. 逻辑
- [47] 界面设计速成
- [47] 读书笔记-壹百度:百度十年千倍的29条法则