老僧非是爱花红

导航

内核模块学习实践

该文章为学习内核模块过程中的实验记录,如有谬误敬请指正。

实验目的

通过在内核代码添加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 驱动配置项

图2 驱动配置项
  • 运行系统
    按照README中的guide启动虚拟机,切换到/lib/modules/2.6.24/kernel/drivers/BiscuitOS
    目录,执行"insmod ckw.ko"命令。
    查看输出。

实验结果与分析

运行系统并执行insmod命令,输出如图3、图4、图5所示。

图3 插入ckw模块时的内核输出-0

图4 插入ckw模块时的内核输出-1

图5 插入ckw模块时的内核输出-2

查看ckw.ko的符号表,如图5所示。其中标记为U的项表示需要重定位。

图5 ckw模块的符号表
查看系统加载ckw.ko模块后的内核符号表,如图6所示。注意属于[ckw]模块的符号kmem_cache_alloc与属于内核的符号kmem_cache_alloc地址相同,说明模块[ckw]的符号表已被正确地重定位。

图6 插入ckw模块后的符号表

实验小结

通过打印函数跟踪了内核重定位模块的大概流程,通过nm和readelf工具对结果进行了验证。

参考资料




  • 附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

posted on 2020-10-23 03:11  老僧非是爱花红  阅读(147)  评论(0编辑  收藏  举报