0%

字符设备驱动的Makefile,驱动的插入和卸载

字符设备驱动的Makefile,驱动的插入和卸载

1 字符设备驱动的Makefile

1
2
3
4
5
6
7
8
9
10
ifneq ($(KERNELRELEASE),)
obj-m := hello_dev.o
else
PWD := $(shell pwd)
KDIR := /lib/modules/`uname -r`/build
all:
make -C $(KDIR) M=$(PWD)
clean:
rm -rf *.o *.ko *.mod.c *.symvers *.c~ *~
endif
  • 首先判断 KERNELRELEASE 变量是否为空,刚开始这个变量肯定没有被定义,于是控制流跳转到else 分支
  • 在 else 分支中,定义变量 PWD 表示当前所在目录,定义变量 KDIR 表示内核所在目录,make -C $(KDIR) M=$(PWD)这一行的规则是:先进入 -C 指定的内核所在目录执行Makefile文件,在这个Makefile文件中会设置变量 KERNELRELEASE;“M=”选项的作用是,当用户需要以某个内核为基础编译1个外部模块,程序会自动到 “M=” 指定的 dir 目录中查找模块源码,将其编译,生成 .ko 文件
  • 这里的 M 是内核根目录下 Makefile 中使用的变量,
1
2
3
4
5
6
7
8
9
10
# Use make M=dir to specify directory of external module to build
# Old syntax make ... SUBDIRS=$PWD is still supported
# Setting the environment variable KBUILD_EXTMOD take precedence
ifdef SUBDIRS
KBUILD_EXTMOD ?= $(SUBDIRS)
endif

ifeq ("$(origin M)", "command line")
KBUILD_EXTMOD := $(M)
endif
  • obj-m 指定目标文件,表示将由 c 代码编译成 .o 文件,然后生成独立的 .ko 模块,不会编译到 zImage
  • 在驱动源码目录下执行 make 命令,
1
2
3
4
5
6
7
8
9
10
$ make 
make -C /lib/modules/`uname -r`/build M=/home/lnhoo/workspace/c/src/hello_dev
make[1]: Entering directory `/usr/src/linux-headers-4.4.0-142-generic'
LD /home/lnhoo/workspace/c/src/hello_dev/built-in.o
CC [M] /home/lnhoo/workspace/c/src/hello_dev/hello_dev.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/lnhoo/workspace/c/src/hello_dev/hello_dev.mod.o
LD [M] /home/lnhoo/workspace/c/src/hello_dev/hello_dev.ko
make[1]: Leaving directory `/usr/src/linux-headers-4.4.0-142-generic'

2 驱动的插入和卸载

2.1 插入

  • 执行 insmod 命令加载驱动模块到内核中,
1
$ sudo insmod hello_dev.ko

此时查看内核模块列表,

1
2
3
4
5
6
7
$ lsmod
Module Size Used by
hello_dev 16384 0
crct10dif_pclmul 16384 0
crc32_pclmul 16384 0
ghash_clmulni_intel 16384 0
......

hello_dev 驱动出现在列表中

  • 清空内核日志,
1
$ sudo dmesg -c

此时加载驱动模块,然后查看内核日志,

1
2
3
4
5
$ dmesg
[ 331.039816] hello_dev: loading out-of-tree module taints kernel.
[ 331.039869] hello_dev: module verification failed: signature and/or required key missing - tainting kernel
[ 331.040488] register_chrdev_region ok
[ 331.040490] hello driver init

hello_dev 字符设备驱动程序入口函数中的 printk 成功将消息写入内核日志

2.2 卸载

  • 执行 rmmod 命令卸载驱动程序,
1
$ sudo rmmod hello_dev

执行 lsmod 命令查看内核模块列表,此时 hello_dev 驱动已不在列表中