二 Linux设备驱动程序——建立和运行模块

文章目录三、内核模块相比于应用程序 四、编译和加载 五、内核符号表六、预备知识七、初始化和关停 八、模块参数 九、在用户空间做十、快速参考
前言
本章介绍所有的关于模块和内核编程的关键概念,通过一个 hello world 模块来认识驱动加载的流程及相关细节 。
一、设置测试系统
我是在虚拟机上进行的开发,查看当前 Linux 系统的内核版本:
uname -r
二、Hello World 模块 1、代码详解
hello.c
#include #include MODULE_LICENSE("Dual BSD/GPL");static int hello_init(void){printk(KERN_ALERT "Hello, world\n");return 0;}static void hello_exit(void){printk(KERN_ALERT "Goodbye, cruel world\n");}module_init(hello_init);module_exit(hello_exit);
ifneq ($(KERNELRELEASE),)obj-m := hello.oelseKERNELDIR ?= /lib/modules/$(shell uname -r)/buildPWD := $(shell pwd)default:$(MAKE) -C $(KERNELDIR) M=$(PWD) modulesendif
?= /lib//$(shell uname -r)/buildPWD := $(shell pwd)$(MAKE) -C $() M=$(PWD)
这个在一次典型的建立中要被读 2 次,当从命令行中调用这个 ,它注意到变量没有设置,它利用这样一个事实来定位内核源码目录,即已安装模块目录中的符号连接指回内核建立树,如果你实际上没有运行你在为其而建立的内核,你可以在命令行提供一个 = 选项,设置环境变量,或者重写中设置的那一行 。一旦发现内核源码树,调用 : 目标,来运行第 2 个 make 命令( 在里参数化成 $(MAKE)) 象前面描述过的一样来调用内核建立系统,在第 2
次读,设置 obj-m,并且内核的文件完成实际的建立模块工作 。
2、执行效果
①、准备好 hello.c 和
②、make 编译
make
查看当前目录下编译产物,其中 hello.ko 是我们需要用到的驱动模块
③、加载 hello.ko 模块
sudo insmod hello.ko
④、lsmod 显示已经加载到内核中的模块的状态信息
lsmod
⑤、查看加载时的打印信息
sudo dmesg -c
⑥、卸载 hello.ko 模块
⑦、查看卸载时的打印信息
【二Linux设备驱动程序——建立和运行模块】sudo dmesg -c
三、内核模块相比于应用程序1、用户空间和内核空间2、内核的并发
常见引起并发原因:
3、当前进程
struct task_struct *current;current->id :当前进程的idcurrent->comm. :当前进程的命令名
4、几个别的细节四、编译和加载 1、编译模块
上面已讲解,这里不再讲述 。
2、加载和卸载模块3、版本依赖
如果你编写一个模块想用来在多个内核版本上工作(特别地是如果它必须跨大的发行版本)你可能只能使用宏定义和 #ifdef 来使你的代码正确建立,利用 linux/.h 中发现的定义 。这个头文件,自动包含在 linux/.h,定义了下面的宏定义:
(major,minor,)五、内核符号表六、预备知识.h 包含了大量加载模块需要的函数和符号的定义,你需要 init.h 来指定你的初始化和清理函数 。不是严格要求的,但是你的模块确实应当指定它的代码使用哪个许可 。做到这一点只需包含一行 :内核认识的特定许可有"GPL"(适用 GNU 通用公共许可的任何版本),“GPL v2”(只适用 GPL 版本 2),“GPL and”,“Dual BSD/GPL”,"Dual MPL/GPL"和 “”;除非你的模块明确标识是在内核认识的一个自由许可下,否则就假定它是私有的,内核在模块加载时被"弄污浊"了 。可以在模块中包含的其他描述性定义有 (声明谁编写了模块) 。(一个人可读的关于模块做什么的声明),(一个代码修订版本号; 看的注释以便知道创建版本字串使用的惯例),(模块为人所知的另一个名子),以及( 来告知用户空间,模块支持那些设备 ) 。七、初始化和关停