内核模块学习实践
该文章为学习内核模块过程中的实验记录,如有谬误敬请指正。
实验目的
通过在内核代码添加printk形式的输出语句跟踪内核重定向模块的大致过程,加深对重定向过程的认识。
实验环境
- 内核版本:2.6.24
- 系统架构:arm32
- 虚拟机:qemu
- 开发环境:BiscuitOS
实验大纲
- 构建BiscuitOS-2.6.24-arm32开发环境
- 修改内核代码
- 编写模块代码
- 配置/编译内核
- 运行系统
实验步骤详解
-
构建BiscuitOS-2.6.24-arm32开发环境
实验的主要目的是跟踪内核处理模块重定位的大致流程,因此需要编译内核并构造能在虚拟机中启动运行的最小操作系统。
因此本实验采用BiscuitOS项目作为开发环境,该项目的重要功能之一是简化了【下载内核源码】【构造交叉编译工具】【构造qemu虚拟机】【构造根文件系统】等琐碎的操作,使得我们很方便地构造不同内核版本的Linux系统并在qemu虚拟机中运行,有利于聚焦于学习、调试以及改进不同版本的内核。
关于BiscuitOS项目的详细介绍可访问其主页BiscuitOS。本次实验为学习《深入Linux内核架构》模块章节的实验,采用了该书介绍的2.6.24版本的内核。关于如何构造BiscuitOS-2.6.24-arm32开发环境,可参考Linux-2.6.12-arm32-Usermanual。官方网站给出的是一般性的指南,因此这里建议在构造BiscuitOS-2.6.24-arm32开发环境时直接参考本地的README文档。
-
修改内核代码
构造好开发环境后,接下来修改kernel/module.c,在相关位置添加printk(……)打印语句,并设置内核只有在加载名称为"ckw"的模块时才打印相关的log。 -
编写模块代码
编写示例驱动代码drivers/BiscuitOS/ckw.c,参考在BIscuitOS项目中添加驱动的文档为该驱动添加kconfig文件以及makefile文件。
在这次实验过程中发现在BiscuitOS-2.6.24-arm32环境下配置kconfig的过程实际上与官网文档有所区别,因此下面列出了此次实验中在内核中添加驱动模块的具体步骤。
- 编写drivers/BiscuitOS/ckw.c,一个简单的helloworld驱动。完整代码见附A
- 编写drivers/BiscuitOS/Kconfig文件,图形化配置菜单项,完成代码见附BA
- 在arch/arm/Kconfig中添加source drivers/BiscuitOS/Kconfig
- 编写drivers/BiscuitOS/Makefile,完成代码见附件B
- 在drivers/Makefile中添加obj-$(CONFIG_BISCUITOS_MODULE_TRACE_CONF) += BiscuitOS/
-
配置/编译内核
按照README的guide配置内核编译项,配置将上述驱动编译成module,配置项如图1、图2所示。编译内核并安装模块。
图1 驱动配置项
- 运行系统
按照README中的guide启动虚拟机,切换到/lib/modules/2.6.24/kernel/drivers/BiscuitOS
目录,执行"insmod ckw.ko"命令。
查看输出。
实验结果与分析
运行系统并执行insmod命令,输出如图3、图4、图5所示。
查看ckw.ko的符号表,如图5所示。其中标记为U的项表示需要重定位。
实验小结
通过打印函数跟踪了内核重定位模块的大概流程,通过nm和readelf工具对结果进行了验证。
参考资料
- 《深入Linux内核架构》
- 2.6.24源码
- BiscuitOS项目
附
- 附A:驱动代码
drivers/BiscuitOS/ckw.c
/*****
*File Name: helloDev.c
*Author: ckw
*Created: 2020-08-18 18:24:08
*Last Modified: 2020-08-18 18:24:08
***/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/slab.h>
#define BUFFER_MAX (10)
#define OK (0)
#define ERROR (-1)
struct cdev * gDev;
struct file_operations *gFile;
dev_t devNum;
unsigned int subDevNum = 1;
int reg_major = 232;
int reg_minor = 2;
char *buffer;
int flag=0;
int hello_open(struct inode *p,struct file* f)
{
printk(KERN_EMERG"hello_open\r\r\n");
return 0;
}
ssize_t hello_write(struct file *f,const char __user *u,size_t s,loff_t *l)
{
printk(KERN_EMERG"hello_write\r\r\n");
return 0;
}
ssize_t hello_read(struct file*ff,char __user *u,size_t s,loff_t *l)
{
printk(KERN_EMERG"hello_read\r\r\n");
return 0;
}
int hello_init(void)
{
devNum=MKDEV(reg_major,reg_minor);
if(OK == register_chrdev_region(devNum,subDevNum,"helloworld")){
printk(KERN_EMERG"register_chrdev_region success!\n");
}else{
printk(KERN_EMERG"register_chrdev_region success!\n");
return ERROR;
}
printk(KERN_EMERG"hello driver INIT\n");
gDev = kzalloc(sizeof(struct cdev),GFP_KERNEL);
gFile =kzalloc(sizeof(struct file_operations),GFP_KERNEL);
gFile->open = hello_open;
gFile->read = hello_read;
gFile->write = hello_write;
gFile->owner = THIS_MODULE;
cdev_init(gDev,gFile);
cdev_add(gDev,devNum,3);
return 0;
}
void __exit hello_exit(void)
{
cdev_del(gDev);
unregister_chrdev_region(devNum,subDevNum);
return;
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
- 附B:配置文件
drivers/BiscuitOS/Kconfig
menuconfig BISCUITOS_MODULE_TRACE_CONF
tristate "BiscuitOS Module Trace Ckw"
if BISCUITOS_MODULE_TRACE_CONF
config BISCUITOS_CKW_MODULE
tristate "biscuitos_ckw_module_trace_ON"
endif
drivers/BiscuitOS/Makefile
obj-$(CONFIG_BISCUITOS_CKW_MODULE) += ckw.o
#obj-m += ckw.o