A huge benefit of Linux is the design of the kernel. Kernel modules break out pieces of code that provide support and functionality for hardware and software on your system. These pieces can be loaded and unloaded on the fly without requiring a reboot to the system. From a programming standpoint this also makes it easier to identify bugs in the kernel, as well as creating fixes without having to create a new kernel image for ever new test. Compiling a kernel module differs slightly from user space processes you may have compiled before, and unlike your user space processes a kernel module with an invalid pointer can kill your system. Sounds like fun, doesn’t it!
If you want to build the kernel module for your running system, then you need the header files of your running kernel, this can be achieved by:
# apt-get install linux-headers-`uname -r`
This will auto-magically download the headers for your running kernel. If you built your own kernel at some obscure version then you probably already know how to do all this.
Okay, now with the headers we need a working directory in which we will build our module.
$ mkdir do_work $ cd do_work
This is the beauty of the kernel makefile, you can have the kernel headers and source somewhere else and work in your own directory with just your source code, but build your module for the running kernel. If you want to modify some pre-existing kernel module you can download the kernel source code and copy the modules *.c to your working directory. You may have to fidget with the includes but for the most part it can be its own existing entity.
So what does the kernel makefile for our own module look like?
Kernel Module Makefile
It is actually more basic than most of your user space C applications.
1 2 3 4 5 6 7 8
# Makefile for compiling Kernel # modules on the fly. obj-m = erik_calc.o KVERSION = $(shell uname -r) all: make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules clean: make -C /lib/modules/$(KVERSION)/build M=$(PWD) clean
So from the command line you can execute the commands you are familiar with, make and make clean to remove all the .o files and such. Lets build our module and check out the output.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
$ make make -C /lib/modules/2.6.32-23-generic/build M=/***/**/do_work/ modules make: Entering directory `/usr/src/linux-headers-2.6.32-23-generic' Building modules, stage 2. MODPOST 1 modules make: Leaving directory `/usr/src/linux-headers-2.6.32-23-generic' --------- Current Directory After Compilation --------- $ ls -l total 28 -rw-r--r-- 1 erik erik 438 2011-04-06 15:57 erik_calc.c -rw-r--r-- 1 erik erik 3619 2011-04-06 16:01 erik_calc.ko -rw-r--r-- 1 erik erik 690 2011-04-06 16:01 erik_calc.mod.c -rw-r--r-- 1 erik erik 2568 2011-04-06 16:01 erik_calc.mod.o -rw-r--r-- 1 erik erik 1864 2011-04-06 16:01 erik_calc.o -rw-r--r-- 1 erik erik 173 2011-04-06 16:02 Makefile -rw-r--r-- 1 erik erik 44 2011-04-06 16:03 modules.order -rw-r--r-- 1 erik erik 0 2011-04-06 16:01 Module.symvers
The most important file we are looking for is the *.ko file, or kernel object file. This is the file that we can load into our running kernel using modprobe or insmod. So that basic Makefile will compile a kernel module for our running kernel…crazy! But what if you need to cross-compile your kernel module for a different architecture? Guess what, you can do that too!
Kernel Makefile For Cross-Compilation
To cross-compile our kernel module we just have to specify the compiler and architecture that should be used during the compilation phase. Lets say we want to cross compile this module for the ARM architecture. ARM is becoming very popular these days due to its use in smart phones because of its low energy usage. This example shows how to cross-compile to a different architecture using a different kernel from the running kernel, we just have to specify where that kernel source is. I have the armeb-linux compiler within my Bash $PATH variable, if your compiler lives somewhere else you can pass the entire path in.
1 2 3 4 5 6 7 8
# Cross compilation Makefile for ARM KERN_SRC=/home/erik/linux-126.96.36.199 obj-m := erik_calc.o all: make -C $(KERN_SRC) ARCH=arm CROSS_COMPILE=armeb-linux- M=`pwd` modules clean: make -C $(KERN_SRC) ARCH=arm CROSS_COMPILE=armeb-linux- M=`pwd` clean
Pay special note to ARCH and the CROSS_COMPILE arguments that are passed in during the build phase. If you wanted to compile for MIPS you could just specify ‘mips’ as long as you have the ‘mips’ compiler. There you have it, now you can compile your own kernel module…you just have to code something now.