Abstract
- Coding and compile a simple dynamic driver module - HelloWorld
- loading module and unloading module
- dmesg
- Kernel symbol table
Create a Simple Dynamic Driver Module - HelloWorld
hello.c
#include <linux/init.h> #include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void) { printk(KERN_ALERT "TEST: hello world, this is hello world module "); return 0; } static void hello_exit(void) { printk(KERN_ALERT "TEST: Good bye, from hello world module "); } module_init(hello_init); module_exit(hello_exit);
> #include <linux/init.h>
This header contains the definition of the functions used in this module.
> module_init() is a macro which defines the function to be called at module insertion time or at system boot time.
> module_exit() is a macro which defines the function to be called at module removal time. This function is also called clean up function
> Kernel modules must always contain these two functions: init_module and cleanup_module
> #include <linux/module.h>
This header is included to add support for Dynamic loading of the module into the Kernel.
A special macro like MODULE_LICENSE is defined in this header.
> MODULE_LICENSE
This macro is used to tell the kernel that this module bears a free license; without such a declaration, the kernel complains when the module is loaded.
> printk
int printk(const char *fmt, ...);
printk(KERN_DEBUG "Debug message shown! ");
Different Loglevels, along with their numerical values, are shown here:
0 | KERN_EMERG | Emergency condition, system is probably dead |
1 | KERN_ALERT | Some problem has occurred, immediate attention is needed |
2 | KERN_CRIT | A critical condition |
3 | KERN_ERR | An error has occurred |
4 | KERN_WARNING | A warning |
5 | KERN_NOTICE | Normal message to take note of |
6 | KERN_INFO | Some information |
7 | KERN_DEBUG | Debug information related to the program |
MakeFile Version 1
This can tell you which header file you need in Makefile:
obj-m +=hello.o KDIR=/usr/src/linux-headers-$(shell uname -r)
all: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules clean: rm -rf *.o *.ko *.mod *.syvers *.order
> "-C" option tells make command to switch to $(KDIR) which is kernel directory
MakeFile Version 2
obj-m :=hello.o KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) all: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules clean: rm -rf *.o *.ko *.mod *.syvers *.order
yubao@yubao-ThinkPad-E560:~$ uname -r 4.13.0-36-generic
Compiling the Module
Make
yubao@yubao-ThinkPad-E560:~/Documents/LinuxStudy$ make
make -C /usr/src/linux-headers-4.13.0-36-generic SUBDIRS=/home/yubao/Documents/LinuxStudy modules
make[1]: Entering directory '/usr/src/linux-headers-4.13.0-36-generic'
CC [M] /home/yubao/Documents/LinuxStudy/hello.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/yubao/Documents/LinuxStudy/hello.mod.o
LD [M] /home/yubao/Documents/LinuxStudy/hello.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.13.0-36-generic'
yubao@yubao-ThinkPad-E560:~/Documents/LinuxStudy$ ls
hello.c hello.ko hello.mod.c hello.mod.o hello.o Makefile modules.order Module.symvers
Loading Kernel Modules
Two Kernel Utilities to load the modules:
> insmod
> modprobe
insmod
> Insmod is a kernel utility that installs loadable Kernal modules into the kernel.
> It actually loads the module code and data into the Kernal land, links any unresolved symbols in the module to the symbol table of the Kernal.
> Insmod accepts a number of command line options and it can assign a value to parameters in a module before linking it to the current kernel.
> Note that if a module is correctly designed, it can be configured at load time by passing arguments to insmod.
yubao@yubao-ThinkPad-E560:~/Documents/LinuxStudy$ sudo insmod hello.ko
[sudo] password for yubao:
modprobe
> It's a Linux utility which offers more features than basic insmod
> It has the ability to decide which modules to load /lib/modules/$(uname -r)
> Its aware of module dependencies
> It supports resolution of recursive module dependencies
I encountered this error:
yubao@yubao-ThinkPad-E560:/lib/modules/4.13.0-36-generic$ sudo modprobe hello modprobe: FATAL: Module hello not found in directory /lib/modules/4.13.0-36-generic
The reason is that modprobe
looks into /lib/modules/$(uname -r)
for the modules and therefore won't work with local file path. That's one of differences between modprobe
and insmod
.
Therefore:
$ dmesg -c
yubao@yubao-ThinkPad-E560:~/MyProjects/Linux/driver/HelloWorld$ sudo cp hello.ko /lib/modules/4 .13.0-36-generic/extra/
yubao@yubao-ThinkPad-E560:~/MyProjects/Linux/driver/HelloWorld$ sudo depmod
yubao@yubao-ThinkPad-E560:~/MyProjects/Linux/driver/HelloWorld$ sudo modprobe hello
yubao@yubao-ThinkPad-E560:~/MyProjects/Linux/driver/HelloWorld$ dmesg
dmsg
dmseg -c : clear history
[ 6384.761442] TEST: hello world, this is hello world module
Remove Module
> rmmod
yubao@yubao-ThinkPad-E560:~/Documents/LinuxStudy$ sudo rmmod hello.ko
>Modprobe
$modprobe -r module-name
yubao@yubao-ThinkPad-E560:~/MyProjects/Linux/driver/HelloWorld$ sudo modprobe -r hello yubao@yubao-ThinkPad-E560:~/MyProjects/Linux/driver/HelloWorld$ dmesg [15909.539018] TEST: Good bye, from hello world module
How to debug symbol error?
Sample code with Symbol Undefine Error:
#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> //Just declared extern int g_value; static int hello_init(void) { printk(KERN_ALERT "TEST: hello world, this is hello world module "); printk("Hello world!!. Value of g_value is %d ",g_value); return 0; } static void hello_exit(void) { printk(KERN_ALERT "TEST: Good bye, from hello world module "); } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("yubao"); MODULE_DESCRIPTION("Kernal Sybmol Table");
Makefile
obj-m +=hello.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Error description:
yubao@yubao-ThinkPad-E560:~/MyProjects/Linux/driver/SybolError$ sudo insmod hello.ko [sudo] password for yubao: insmod: ERROR: could not insert module hello.ko: Unknown symbol in module
Use "nm" to debug
yubao@yubao-ThinkPad-E560:~/MyProjects/Linux/driver/SybolError$ nm hello.ko 0000000000000030 T cleanup_module U __fentry__ U g_value 0000000000000030 t hello_exit 0000000000000000 t hello_init 0000000000000000 T init_module 0000000000000068 r __module_depends U printk 0000000000000000 D __this_module 0000000000000020 r __UNIQUE_ID_author9 0000000000000000 r __UNIQUE_ID_description10 000000000000002d r __UNIQUE_ID_license8 0000000000000071 r __UNIQUE_ID_name9 0000000000000040 r __UNIQUE_ID_srcversion10 000000000000007c r __UNIQUE_ID_vermagic8
How to solve this problem?
Replace "extern int g_value;" with "extern int g_value;". Then "make clean &make".
Is it mandatory to export your module symbols?
yes
> "static" - visible only within their own source file
> "external" - potentially visible to any other code built into the kernel itself
>"exported" - visible and available to any loadable module