操作系统实验 | 您所在的位置:网站首页 › linux操作系统课程标准 › 操作系统实验 |
参考用书:《操作系统实践:基于Linux的应用与内核编程》 一.添加一个内核模块 1.1需求分析 对于一个应用程序而言,源代码经编译后与标准运行库链接,通过系统调用执行操作系统内核中的特权指令,指令返回的结果通过系统调用返回给用户,完成程序。 由于Linux是单内核多模块的操作系统,整个操作系统只包含一个由多个不同功能模块组成的内核,通过Linux系统的这种特性,可以动态添加自己编写的内核模块,并由系统每次启动时进行加载。 通过内核模块的动态添加和删除,可以直观的感受到内核模块的编写以及动态添加和删除的过程。可以通过此次实验理解用户态(User Model)和内核态(Kernel Model)的关系。并掌握内核模块代码中的一些常见宏和参数以及内核模块程序和应用程序的差异。 实验流程为:编写kello.c文件和Makefile文件,并使用insmod和rmmmod命令对内核模块进行安装和卸载。观察终端输出的不同信息。同时编写代码时应注意安全问题,不要对内核进行不当访问从而使系统出现错误。 输入:使用insmod安装所编写的内核模块。 输出:通过dmesg命令观察安装内核模块和卸载内核模块所输出的信息。 1.2概要设计 本次实验包含两个文件:kello.c和编译所需的Makefile文件,kello.c文件包含模块初始化函数hello_init,在模块初始化时被调用,以及模块回收函数hello_exit,在模块被撤销时使用。 在该文件的最后,需要添加两行声明module_init(hello_init)和module_exit(hello_exit),使模块被更高效的加载执行和撤销,加快内存的分配和回收 对于Makefile文件内容,KERNELRELEASE定义在linux内核源代码中的顶层makefile,boj-m表示所安装内核模块的名称,需要和c文件名字相同。 KDIR和PWD目录分别代表内核的源代码目录和当前的工作路径,defult中为编译命令以及一些文件的删除命令。 1.3详细设计 Kello.c的hello_init调用printk输出一段初始化信息,hello_exit调用printk输出模块回收时打印的信息。 对于Makefile文件,KERNELRELEASE是在Linux内核源代码顶层Makelile中定义的一个变量,在第一次读取执行此 Makefile文件时,KERNELRELEASE没有被定义,所以make将读取执行else之后的内容。 如果make的目标是clean. 直接执行clean操作,然后结束。 当没有声明make的目标时,make执行默认操作,即default 后的指令,此时-C$ (KDIR)指明跳转到内核源代码目录下读取那里的Makefiles SUBDIRS $ (PWD) 表明需要返回到当前目录继续读入并执行当前的Makefile.当从内核源代码目录返回时, KERNELRELEASE已被定义,kbuild也被启动去解析kbuild语法的语句,make将继续读取else之前的内容。 实验过程: 在当前文件夹下执行make命令 ![]() 观察当前文件夹是否生成所需文件 ![]() sudo insmod 安装LKM ![]() 观察安装LKM后dmesg输出的内核初始化信息 ![]() sudo rmmod 卸载LKM ![]() 观察卸载LKM后dmesg输出的内核初始化和撤销信息 ![]() 1.4调试分析 分析一:make命令提示空变量名错误 ![]() 首先遇到的错误为,make命令报告空变量名。是make文件的格式问题,注意在$(MAKE) -C $(KDIR) SUBDIRS =$(shell pwd) modules,SUBDIRS的后没有空格,去掉空格后问题解决。 分析二:mkdir创建目录权限不够 ![]() ![]() mkdir创建目录权限不够,错误定位在fixdep.c文件的404行,fatal error打开依赖文件的权限不够,并显示compilation terminated(编译结束)。 fixdep.c文件是make的一个工具,由make在编译时调用。问题出在make -C SUBDIRS=处,应修改为make -C M=。二者的区别在于,$(MAKE)相当于make,-C 选项的作用是指将当前工作目录转移到所指定的位置。“M=”表示当用户需要以某个内核为基础编译一个外部模块的话,需要在make modules 命令中加入“M=dir”,程序会到所指定的dir目录中查找模块源码,将其编译,生成.ko文件。 M并非随意命名,在新的内核模块编程中的make命令中有个M选项,是makefile脚本中的一个变量,$(MAKE) -C $(KDIR) M=$(PWD)与$(MAKE) -C $(KDIR) SUBDIRS =$(PWD)的作用是一样的,不过SUBDIRS是过时的使用方法,修改后问题得以解决。 ![]() make文件和c文件如下: ifneq ($(KERNELRELEASE),) obj-m := kello.o else KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KDIR) M=$(shell pwd) modules rm -r -f .tmp_versions *.mod.c .*.cmd *.o *.symvers endif #include /* 此函数为模块初始化实例, 将在模块初始化时被调用 */ int hello_init(void) { printk("\nI AM HERE IN KERNEL:)\n"); return 0; } /* 此函数为模块回收实例, 将在模块被撤销时使用 */ void hello_exit(void){ printk("\n I AM OUT BYE BYE :)\n"); } MODULE_AUTHOR("zhuoge04");//描述模块作者为本人 MODULE_LICENSE("GPL"); /* 以下两行声明可以使模块被更高效的加载执行和撤销, 加快内存的分配和回收 */ module_init(hello_init); module_exit(hello_exit); |
CopyRight 2018-2019 实验室设备网 版权所有 |