Listing 1: The Hello World Linux Loadable Kernel Module (LKM) Code
In addition to the points described by the comments in Listing 1, there are some additional points:
  • Line 16: The statement MODULE_LICENSE("GPL") provides information (via modinfo) about the licensing terms of the module that you have developed, thus allowing users of your LKM to ensure that they are using free software. Since the kernel is released under the GPL, your license choice impacts upon the way that the kernel treats your module. You can choose "Proprietary" for non-GPL code, but the kernel will be marked as “tainted” and a warning will appear. There are non-tainted alternatives to GPL, such as "GPL v2", "GPL and additional rights", "Dual BSD/GPL", "Dual MIT/GPL", and "Dual MPL/GPL". See linux/module.h for more information.
  • Line 21: The name (ptr to char) is declared as static and is initialized to contain the string “hello”. You should avoid using global variables in kernel modules — it is even more important than in application programming, as global variables are shared kernel wide. You should use the static keyword to restrict a variable’s scope to within the module. If you must use a global variable, add a prefix that is unique to the module that you are writing.
  • Line 22: The module_param(name, type, permissions) macro has three parameters: name (the parameter name displayed to the user and the variable name in the module), type (the type of the parameter — i.e., one of byte, int, uint, long, ulong, short, ushort, bool, an inverse Boolean invbool, or a char pointer charp), and permissions (this is the access permissions to the the parameter when using sysfs and is covered below. A value of 0 disables the entry, but S_IRUGO allows read access for user/group/others — See the Mode Bits for Access Permissions Guide)
  • Line 31 and 40: The functions can have whatever names you like (e.g., helloBBB_init() and helloBBB_exit()), however, the same names must be passed to the special macros module_init() and module_exit() on lines 48 and 49.
  • Line 31: The printk() is very similar in usage to the printf() function that you should be familiar with, and you can call it from anywhere within the kernel module code. The only significant difference is that you should specify a log level when you call the function. The log levels are defined in linux/kern_levels.h as one of KERN_EMERG, KERN_ALERT, KERN_CRIT, KERN_ERR, KERN_WARNING, KERN_NOTICE, KERN_INFO, KERN_DEBUG, and KERN_DEFAULT. This header is included via the linux/kernel.h header file, which includes it via linux/printk.h.
Essentially, when this module is loaded the helloBBB_init() function will execute, and when the module is unloaded the helloBBB_exit() function will execute.
The next step is to build this code into a kernel module.

Building the Module Code

A Makefile is required to build the kernel module — in fact, it is a special kbuild Makefile. The kbuild Makefile required to build the kernel module in this article can be viewed in Listing 2.
Listing 2: The Makefile Required to Build the Hello World LKM
The first line of this Makefile is called a goal definition and it defines the module to be built (hello.o). The syntax is surprisingly intricate, for example obj-m defines a loadable module goal, whereas obj-y indicates a built-in object goal. The syntax becomes more complex when a module is to be built from multiple objects, but this is sufficient to build this example LKM.
The reminder of the Makefile is similar to a regular Makefile. The $(shell uname -r) is a useful call to return the current kernel build version — this ensures a degree of portability for the Makefile. The -C option switches the directory to the kernel directory before performing any make tasks. The M=$(PWD) variable assignment tells the make command where the actual project files exist. The modules target is the default target for external kernel modules. An alternative target is modules_install which would install the module (the make command would have to be executed with superuser permissions and the module installation path is required).
All going well, the process to build the kernel module should be straightforward, provided that you have installed the Linux headers as described earlier. The steps are as follows:
molloyd@beaglebone:~/exploringBB/extras/kernel/hello$ ls -l
total 8
-rw-r--r-- 1 molloyd molloyd 154 Mar 17 17:47 Makefile
-rw-r--r-- 1 molloyd molloyd 2288 Apr 4 23:26 hello.c
molloyd@beaglebone:~/exploringBB/extras/kernel/hello$ make
make -C /lib/modules/3.8.13-bone70/build/ M=/home/molloyd/exploringBB/extras/kernel/hello modules
make[1]: Entering directory '/usr/src/linux-headers-3.8.13-bone70'
CC [M] /home/molloyd/exploringBB/extras/kernel/hello/hello.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/molloyd/exploringBB/extras/kernel/hello/hello.mod.o
LD [M] /home/molloyd/exploringBB/extras/kernel/hello/hello.ko
make[1]: Leaving directory '/usr/src/linux-headers-3.8.13-bone70'
molloyd@beaglebone:~/exploringBB/extras/kernel/hello$ ls
Makefile Module.symvers hello.c hello.ko hello.mod.c hello.mod.o hello.o modules.order

You can see that there is now a hello loadable kernel module in the build directory with the file extension .ko.

Testing the LKM

This module can now be loaded using the kernel module tools as follows:
molloyd@beaglebone:~/exploringBB/extras/kernel/hello$ ls -l *.ko
-rw-r--r-- 1 molloyd molloyd 4219 Apr 4 23:27 hello.ko
molloyd@beaglebone:~/exploringBB/extras/kernel/hello$ sudo insmod hello.ko
molloyd@beaglebone:~/exploringBB/extras/kernel/hello$ lsmod
Module Size Used by
hello 972 0
g_multi 50407 2
libcomposite 15028 1 g_multi
omap_rng 4062 0
mt7601Usta 639170 0

You can get information about the module using the modinfo command, which will identify the description, author and any module parameters that are defined:
molloyd@beaglebone:~/exploringBB/extras/kernel/hello$ modinfo hello.ko
filename: /home/molloyd/exploringBB/extras/kernel/hello/hello.ko
description: A simple Linux driver for the BBB.
author: Derek Molloy
license: GPL
srcversion: 9E3F5ECAB0272E3314BEF96
depends:
vermagic: 3.8.13-bone70 SMP mod_unload modversions ARMv7 thumb2 p2v8
parm: name:The name to display in /var/log/kernel.log. (charp)
The module can be unloaded using the rmmod command:
molloyd@beaglebone:~/exploringBB/extras/kernel/hello$ sudo rmmod hello.ko
You can repeat these steps and view the output in the kernel log that results from the use of the printk() function. I recommend that you use a second terminal window and view the output as your LKM is loaded and unloaded, as follows:
molloyd@beaglebone:~$ sudo su -
[sudo] password for molloyd:
root@beaglebone:~# cd /var/log
root@beaglebone:/var/log# tail -f kern.log
...
Apr 4 23:34:32 beaglebone kernel: [21613.495523] EBB: Hello world from the BBB LKM!
Apr 4 23:35:17 beaglebone kernel: [21658.306647] EBB: Goodbye world from the BBB LKM!
^C
root@beaglebone:/var/log#

Testing the LKM Custom Parameter

The code in Listing 1 also contains a custom parameter, which allows an argument to be passed to the kernel module on initialization. This feature can be tested as follows:
molloyd@beaglebone:~/exploringBB/extras/kernel/hello$ sudo insmod hello.ko name=Derek

If you view /var/log/kern.log at this point then you will see “Hello Derek” in place of “Hello world”. However, it is worth having a look at /proc and /sys first.
Rather than using the lsmod command, you can also find out information about the kernel module that is loaded, as follows:
molloyd@beaglebone:~/exploringBB/extras/kernel/hello$ cd /proc
molloyd@beaglebone:/proc$ cat modules|grep hello
hello 972 0 - Live 0xbf903000 (O)

This is the same information that is provided by the lsmod command but it also provides the current kernel memory offset for the loaded module, which is useful for debugging.
The LKM also has an entry under /sys/module, which provides you with direct access to the custom parameter state. For example:
molloyd@beaglebone:/proc$ cd /sys/module
molloyd@beaglebone:/sys/module$ ls -l|grep hello
drwxr-xr-x 6 root root 0 Apr 5 00:02 hello
molloyd@beaglebone:/sys/module$ cd hello
molloyd@beaglebone:/sys/module/hello$ ls -l
total 0
-r--r--r-- 1 root root 4096 Apr 5 00:03 coresize
drwxr-xr-x 2 root root 0 Apr 5 00:03 holders
-r--r--r-- 1 root root 4096 Apr 5 00:03 initsize
-r--r--r-- 1 root root 4096 Apr 5 00:03 initstate
drwxr-xr-x 2 root root 0 Apr 5 00:03 notes
drwxr-xr-x 2 root root 0 Apr 5 00:03 parameters
-r--r--r-- 1 root root 4096 Apr 5 00:03 refcnt
drwxr-xr-x 2 root root 0 Apr 5 00:03 sections
-r--r--r-- 1 root root 4096 Apr 5 00:03 srcversion
-r--r--r-- 1 root root 4096 Apr 5 00:03 taint
--w------- 1 root root 4096 Apr 5 00:02 uevent
-r--r--r-- 1 root root 4096 Apr 5 00:02 version
molloyd@beaglebone:/sys/module/hello$ cat version
0.1
molloyd@beaglebone:/sys/module/hello$ cat taint
O

The version value is 0.1 as per the MODULE_VERSION("0.1") entry and the taint value is 0 as per the license that has been chosen, which is MODULE_LICENSE("GPL").
The custom parameter can be viewed as follows:
molloyd@beaglebone:/sys/module/hello$ cd parameters/
molloyd@beaglebone:/sys/module/hello/parameters$ ls -l
total 0
-r--r--r-- 1 root root 4096 Apr 5 00:03 name
molloyd@beaglebone:/sys/module/hello/parameters$ cat name
Derek

You can see that the state of the name variable is displayed, and that superuser permissions where not required to read the value. The latter is due to the S_IRUGO argument that was used in defining the module parameter. It is possible to configure this value for write access but your module code will need to detect such a state change and act accordingly. Finally, you can remove the module and observe the output:
molloyd@beaglebone:/sys/module/hello/parameters$ sudo rmmod hello.ko
As expected, this will result in the output message in the kernel logs:
root@beaglebone:/var/log# tail -f kern.log

Apr 5 00:02:20 beaglebone kernel: [23281.070193] EBB: Hello Derek from the BBB LKM!
Apr 5 00:08:18 beaglebone kernel: [23639.160009] EBB: Goodbye Derek from the BBB LKM!

Conclusions

Click for the HTML and PDF version of the auto-generated Doxygen code documentation
Hopefully you have built your first loadable kernel module (LKM). Despite the simplicity of the functionality of this module there was a lot of material to cover — by the end of this article: you should have a broad idea of how loadable kernel modules work; you should have your system configured to build, load and unload such modules; and, you should be able to define custom parameters for your LKMs.
The next step is to build on this work to develop a kernel space LKM that can communicate with a user space C/C++ program by developing a basic character driver. See “Writing a Linux Kernel Module — Part 2: A Character Device“. Then we can move on to the more interesting task of interacting with GPIOs.