内核模块编程
1、准备工做
虚拟机:VMware Workstation 12
操做系统:ubuntu
当前内核版本:linux-headers-4.4.0-22-genericlinux
2、有关于内核模块的知识
模块是具备独立功能的程序,它能够被单独编译,但不能独立运行。它在运行时被连接到内核做为内核的一部分在内核空间运行,这与运行在用户空间的进程是不一样的。模块一般由一组函数和数据结构组成,用来实现一种文件系统、一个驱动程序或其余内核上层的功能。shell
内核模块的相关指令:编程
查看内核版本ubuntu
uname –a
模块编译好后,将模块放入内核数据结构
insmod 1.ko
查看程序的输出函数
dmesg
卸载模块spa
rmmod 1
3、编译造成新内核操作系统
根据学姐的代码:code
Makefileblog
1 obj-m:=1.o 2 CURRENT_PATH:=$(shell pwd) 3 LINUX_KERNEL_PATH:=/usr/src/linux-headers-4.4.0-22-generic 4 all: 5 make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules 6 clean: 7 make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean
第1行:产生1模块的目标模块
第2行:模块所在的当前路径
第3行:LINUX_KERNEL_PATH后面要写你本身的内核版本对应的内核源码包地址。
make-C $(LINUX_KERNEL_PATH) 指明跳转到内核源码目录下读取那里的Makefile,M=$(CURRENT_PATH) 代表返回到当前目录继续执行当前的Makefile。
第5行:模块编译
第7行:清理
1.c
1 #include <linux/kernel.h> 2 #include <linux/module.h> 3 #include <linux/init.h> 4 #include <linux/sched.h> 5 6 static struct task_struct *pcurrent; 7 static int __init print_init(void) 8 { 9 printk(KERN_INFO "print current task info\n"); 10 printk("pid\ttgid\tprio\tstate\n"); 11 for_each_process(pcurrent){ 12 printk("%d\t",pcurrent->pid); 13 printk("%d\t",pcurrent->tgid); 14 printk("%d\t",pcurrent->prio); 15 printk("%ld\n",pcurrent->state); 16 } 17 return 0; 18 } 19 20 static void __exit print_exit(void) 21 { 22 printk(KERN_INFO "Finished\n"); 23 } 24 module_init(print_init); 25 module_exit(print_exit);
第1行:linux/kernel.h包含了经常使用的内核函数。
第2行:linux/module.h是必要的头文件,内核模块代码中必须包含。
第3行:linux/init.h含了宏_init和_exit,它们容许释放内核占用的内存。
第12行:Printk的功能相似于C语言中的printf,这个函数是由内核定义的。
先make生成1.ko文件等,在insmod 1.ko将模块放入内核,最后dmesg查看所编译程序的输出
4、遇到问题
在make这一步所遇到的基本全部问题都是由于.c文件出错所形成的。
还有一个问题就是在以前加载过模块以后再进行加载时会出现错误,这时将模块卸载了再进行加载就能够了。