1、Linux驱动开发:模块_加载卸载

目录

点击这里查看所有博文

  随着自己工作的进行,接触到的技术栈也越来越多。给我一个很直观的感受就是,某一项技术/经验在刚开始接触的时候都记得很清楚。往往过了几个月都会忘记的差不多了,只有经常会用到的东西才有可能真正记下来。存在很多在特殊情况下有一点用处的技巧,用的不多的技巧可能一个星期就忘了。

  想了很久想通过一些手段把这些事情记录下来。也尝试过在书上记笔记,这也只是一时的,书不在手边的时候那些笔记就和没记一样,不是很方便。

  很多时候我们遇到了问题,一般情况下都是选择在搜索引擎检索相关内容,这样来的也更快一点,除非真的找不到才会去选择翻书。后来就想到了写博客,博客作为自己的一个笔记平台倒是挺合适的。随时可以查阅,不用随身携带。

  同时由于写博客是对外的,既然是对外的就不能随便写,任何人都可以看到。经验对于我来说那就只是经验而已,公布出来说不一定我的一些经验可以帮助到其他的人。遇到和我相同问题时可以少走一些弯路。

  既然决定了要写博客,那就只能认真去写。不管写的好不好,尽力就行。千里之行始于足下,一步一个脚印,慢慢来 ,写的多了慢慢也会变好的。权当是记录自己的成长的一个过程,等到以后再往回看时,就会发现自己以前原来这么菜。

  本系列博客所述资料均来自互联网资料,并不是本人原创(只有博客是自己写的)。出于热心,本人将自己的所学笔记整理并推出相对应的使用教程,方面其他人学习。为国内的物联网事业发展尽自己的一份绵薄之力,没有为自己谋取私利的想法。若出现侵权现象,请告知本人,本人会立即停止更新,并删除相应的文章和代码。

前言

  一个基础模块的源代码,应有c文件,h文件(可选)和makefile文件构成 。

C文件

  c文件中除了必要的函数申明以及头文件导入外,还要分别为模块声明载入函数和销毁函数。载入函数使用module_init声明,当模块被加载进入内核的时候该函数会被调用。销毁函数使用module_exit声明,当从内核中移除模块时该函数会被调用。

  宏MODULE_LICENSE宏用于声明此模块的许可证,宏MODULE_AUTHOR的用于声明内核模块的作者。

#include 
#include 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("PD");
static int hello_init(void)
{
	printk(KERN_SOH"hello_init \n");
	return 0;
}
static void hello_exit(void)
{
	printk("hello_exit \n");
	return;
}
module_init(hello_init); //insmod
module_exit(hello_exit);//rmmod

  从2.4.10版本内核开始,模块必须通过MODULE_LICENSE宏声明此模块的许可证,否则在加载此模块时,会收到内核被污染 “kernel tainted” 的警告。从linux/module.h文件中可以看到,被内核接受的有意义的许可证有 “GPL”,“GPL v2”,“GPL and additional rights”,“Dual BSD/GPL”,“Dual MPL/GPL”,“Proprietary”。

/*
 * The following license idents are currently accepted as indicating free
 * software modules
 *
 *	"GPL"				[GNU Public License v2 or later]
 *	"GPL v2"			[GNU Public License v2]
 *	"GPL and additional rights"	[GNU Public License v2 rights and more]
 *	"Dual BSD/GPL"			[GNU Public License v2
 *					 or BSD license choice]
 *	"Dual MIT/GPL"			[GNU Public License v2
 *					 or MIT license choice]
 *	"Dual MPL/GPL"			[GNU Public License v2
 *					 or Mozilla license choice]
 *
 * The following other idents are available
 *
 *	"Proprietary"			[Non free products]
 *
 * There are dual licensed components, but when running with Linux it is the
 * GPL that is relevant so this is a non issue. Similarly LGPL linked with GPL
 * is a GPL combined work.
 *
 * This exists for several reasons
 * 1.	So modinfo can show license info for users wanting to vet their setup
 *	is free
 * 2.	So the community can ignore bug reports including proprietary modules
 * 3.	So vendors can do likewise based on their own policies
 */
#define MODULE_LICENSE(_license) MODULE_INFO(license, _license)

makefile文件

  此makefile可作为一个通用示例。

ifneq ($(KERNELRELEASE),)
$(info "makebuild2")
obj-m:=hello.o
else
KDIR :=/lib/modules/$(shell uname -r)/build
PWD  :=$(shell pwd)
all:
	$(info "makebuild1")
	make -C $(KDIR) M=$(PWD) modules
clean:
	rm -f *.ko *.o *.mod.o *.symvers *.cmd  *.mod.c *.order
	rm -rf .*.cmd .*.mk .*/
endif

  在编译模块运行make命令时。首先由于KERNELRELEASE变量不存在,会直接进入else分支,执行内核modules的make流程。

root@ubuntu:# make
"makebuild1"
make -C /lib/modules/4.15.0-142-generic/build M=/home/peng/Desktop/driver/example/1_module modules
make[1]: Entering directory '/usr/src/linux-headers-4.15.0-142-generic'

  第二步再次从头开始重新执行该makefile,由于第一步中已经指定了内核模块编译,此时KERNELRELEASE不为空,会进入到ifneq分支,完成*.o的生成。

"makebuild2"
  CC [M]  /home/peng/Desktop/driver/example/1_module/hello.o
  Building modules, stage 2.

  完成hello.o的编译后,最后一步会执行一个转化和链接的操作。该makefile被再次调用。将*.o转化为*.mod.o,最后完成内核模块的链接生成*.ko

"makebuild2"
  MODPOST 1 modules
  CC      /home/peng/Desktop/driver/example/1_module/hello.mod.o
  LD [M]  /home/peng/Desktop/driver/example/1_module/hello.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.15.0-142-generic'

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aHqKKr91-1690035344898)(/imgs/2023-07-22/S3NYRHyl7RwQ6RJc.png)]

加载卸载

  加载模块前建议先清除dmesg的日志信息。否则影响调试

root@ubuntu:$ dmesg -c

  使用insmod加载模块,加载完成可通过dmesg查看载入函数的日志打印,也可以通过lsmod查看模块是否被正常加载。

root@ubuntu:# insmod ./hello.ko
root@ubuntu:# dmesg
[ 6891.682070] hello_init 
root@ubuntu:# lsmod | grep hello
hello                  16384  0

  使用rmmod卸载模块,卸载完成可通过dmesg查看卸载函数的日志打印,也可以通过lsmod查看模块是否被正常卸载。

root@ubuntu:# rmmod ./hello.ko
root@ubuntu:# dmesg
[ 6891.682070] hello_init 
[ 7087.613847] hello_exit 
root@ubuntu:# lsmod | grep hello

常用操作

  • lsmod:显示模块
  • insmod/rmmod:安装/卸载模块
  • dmesg -c:清除log信息
  • dmesg:打印log信息

  那么本篇博客就到此结束了,这里只是记录了一些我个人的学习笔记,其中存在大量我自己的理解。文中所述不一定是完全正确的,可能有的地方我自己也理解错了。如果有些错的地方,欢迎大家批评指正。如有问题直接在对应的博客评论区指出即可,不需要私聊我。我们交流的内容留下来也有助于其他人查看,说不一定也有其他人遇到了同样的问题呢。

你可能感兴趣的:(Linux驱动开发,linux,驱动开发,运维,内核模块)