Integrating a Linux kernel module directly into the Linux kernel source tree can streamline development and testing by keeping everything in one place. This process involves modifying the kernel source tree to include your module, allowing you to build and test the module as part of the kernel. This guide provides a detailed, step-by-step approach to integrating a Linux kernel module into the kernel source, complete with practical examples.
Why Integrate a Kernel Module?
- Streamlined Development: Keeps your module within the kernel source tree, simplifying development and testing.
- Consistency: Ensures that your module is built and tested with the exact kernel version you are working on.
- Ease of Maintenance: Makes it easier to manage and maintain kernel modules alongside kernel source changes.
Follow, steps from “Cross Compilation and Booting of Linux kernel for Raspberry Pi3 – Manual Compilation” to clone kernel source code for Raspberry Pi, toolchain and setup the environment to cross compile kernel image zImage and modules from the default configuration.
$ cd linux
create a directory to write a kernel module as,
$ mkdir drivers/helloworld/
Now, lets write our basic helloworld kernel module / device driver in drivers/helloworld/helloworld.c
$ vim drivers/helloworld/helloworld.c
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
static int __init hello_init(void) {
printk(KERN_INFO "Hello, world\n");
return 0;
}
static void __exit hello_exit(void) {
printk(KERN_INFO "Goodbye, world\n");
}
module_init(hello_init);
module_exit(hello_exit);
To, get this driver module compiled as part of kernel, we need to write Makefile and Kconfig file by following Linux kernel build mechanism, the contents of those files will be as below,
$ vim drivers/helloworld/Makefile
obj-$(CONFIG_HELLOWORLD) += helloworld.o
$ vim drivers/helloworld/Kconfig
#
# Helloworld driver as part of kernel source
#
menu "Helloworld Driver"
config HELLOWORLD
depends on ARM
tristate "helloworld module"
default y
help
Helloworld kernel module integrated as part of kernel source.
endmenu
here, as part of Kconfig, we are telling the Kernel build framework, that this driver can have 3 states for configuration as, “not selected”, “y” i.e. selected as part of kernel image and “m” selected to build as kernel module which is indicated by “tristate” , configuration parameter “depends” tells build framework to select this kernel module if “ARM” has been selected, ( you can change as you want to set dependency ), parameter “default y” selects this Confifuration parameter HELLOWORLD as “CONFIG_HELLOWORLD=y” in the default configuration, where as “help” shows the respective information in “make menuconfig”
Now, we need to tell the kernel build framework to consider our newly created driver directory for the compilation, by appending following line into “drivers/Kconfig” as,
$ vim drivers/Kconfig
source "drivers/helloworld/Kconfig"
and
append following line to drivers/Makefile as,
$ vim drivers/Makefile
obj-$(CONFIG_HELLOWORLD) += helloworld/
Now, we are ready to start the compilation of the kernel, currently because we have mentioned “config HELLOWORLD” as “default y” , if we do
$ make ARCH=arm CROSS_COMPILE=arm-bcm2708-linux-gnueabi- menuconfig
In above command, you need to use toolchain “arm-bcm2708-linux-gnueabi” as per your build system.
we will see following things in “Device Drivers —> Helloworld Driver —> <*> helloworld module” in “Help”
You can use space bar to select and deselect “helloworld module” for,
1. deselect as < > helloworld module
2. select as module, helloworld module
3. select as in built to kernel image as, <*> helloworld module
after selecting proper type as above, click “Exit” till you see following window,
Do you wish to save your new configuration?
│ (Press to continue kernel configuration.)
│ ├──────────────────────────────────────────────────────────┤
| < Yes > < No >
select “yes” in this as if you open updated, .config file you will see a new option added as,
#
# Helloworld Driver
#
CONFIG_HELLOWORLD=y
Now, lets build kernel image, as
$ make ARCH=arm CROSS_COMPILE=arm-bcm2708-linux-gnueabi- zImage
CHK include/config/kernel.release
CHK include/generated/uapi/linux/version.h
CHK include/generated/utsrelease.h
CHK include/generated/bounds.h
CHK include/generated/timeconst.h
CHK include/generated/asm-offsets.h
CALL scripts/checksyscalls.sh
CHK include/generated/compile.h
CC drivers/helloworld/helloworld.o
LD drivers/helloworld/built-in.o
LD drivers/built-in.o
LD vmlinux.o
MODPOST vmlinux.o
GEN .version
CHK include/generated/compile.h
UPD include/generated/compile.h
CC init/version.o
LD init/built-in.o
KSYM .tmp_kallsyms1.o
KSYM .tmp_kallsyms2.o
LD vmlinux
SORTEX vmlinux
SYSMAP System.map
OBJCOPY arch/arm/boot/Image
Kernel: arch/arm/boot/Image is ready
GZIP arch/arm/boot/compressed/piggy_data
AS arch/arm/boot/compressed/piggy.o
LD arch/arm/boot/compressed/vmlinux
OBJCOPY arch/arm/boot/zImage
Kernel: arch/arm/boot/zImage is ready
Now to compile same driver as kernel module, select it as “m” in kernel menuconfig as,
$ make ARCH=arm CROSS_COMPILE=arm-bcm2708-linux-gnueabi- menuconfig
we will see following things in “Device Drivers —> Helloworld Driver —> helloworld module”
and then compile as,
$ make ARCH=arm CROSS_COMPILE=arm-bcm2708-linux-gnueabi- modules
scripts/kconfig/conf --silentoldconfig Kconfig
CHK include/config/kernel.release
CHK include/generated/uapi/linux/version.h
CHK include/generated/utsrelease.h
CC kernel/bounds.s
CHK include/generated/bounds.h
CHK include/generated/timeconst.h
CC arch/arm/kernel/asm-offsets.s
CHK include/generated/asm-offsets.h
CALL scripts/checksyscalls.sh
CC scripts/mod/empty.o
MKELF scripts/mod/elfconfig.h
HOSTCC scripts/mod/modpost.o
CC scripts/mod/devicetable-offsets.s
GEN scripts/mod/devicetable-offsets.h
HOSTCC scripts/mod/file2alias.o
HOSTCC scripts/mod/sumversion.o
HOSTLD scripts/mod/modpost
GZIP kernel/config_data.gz
CHK kernel/config_data.h
UPD kernel/config_data.h
CC [M] kernel/configs.o
CC [M] drivers/helloworld/helloworld.o
Building modules, stage 2.
MODPOST 1561 modules
CC drivers/helloworld/helloworld.mod.o
LD [M] drivers/helloworld/helloworld.ko
CC kernel/configs.mod.o
LD [M] kernel/configs.ko
Now, we have to install this modules for copying into hardware, to do that we have to create separate directory for output binaries and setting INSTALL_MOD_PATH to this directory,
$ mkdir out
$ make ARCH=arm CROSS_COMPILE=arm-bcm2708-linux-gnueabi- modules_install INSTALL_MOD_PATH=./out
$ make ARCH=arm CROSS_COMPILE=arm-bcm2708-linux-gnueabi- modules_install INSTALL_MOD_PATH=./out