Why Linux Kernel Modules?
It’s 2016, and Linux kernel is about to turn 25 in a few days from now. Why am I writing about a “Hello World” Linux kernel module now? There is tons of material, both written and audiovisual, available on this topic. The reason I can think of doing this is because I myself stumbled upon a lot of popular blogs and materials about kernels while learning about Linux. Popular, in our times, is what google search serves us on its first page. Whatever algorithm the search may be using, there is a fair chance of a particular keyword combination to make it to the reader’s eyes through google. So, I feel even if this article comes up against one search string and helps even one person learn, the purpose is served.
What are kernel and modules?
Linux kernel is an operating system kernel which acts as a bridge between the user and the computer hardware. It is the first program to be loaded into the memory when the system boots and takes care of other programs like reading/writing from devices or peripherals attached to the computer once its up. After the take off, kernel’s responsibility is to handle running of background processes, handling interrupts and system calls from other programs, handling devices etc.
The beauty of a Linux kernel is that it’s modular in nature. It can boot up with a bare minimum functionality itself and programs needed to handle additional functionality can be attached on-the-go to this kernel (device drivers are the best example). These attachable programs are known as Modules or Loadable Kernel Modules.
Let’s start
Linux kernel is available free of cost for download at https://www.kernel.org/. The code is written in C language. One can compile the kernel with changed configuration to suit one’s requirements. As far as module development is concerned, the C language program needs header files to compile which are provided by the same kernel code.
Important tools and commands
There are some handy tools and commands you would need while writing the first kernel modules:
- vi/nano/gedit editors ( I would be using vim)
- Makefile and make command
- Linux module commands:
- lsmod – lists the current modules attached to the kernel
- modinfo – lists information about the module
- insmod – inserts/attaches a module to kernel
- rmmod – removes a module
- dmesg – prints kernel logs ( also can read /var/log/messages file for logs)
The C program
Create a new directory named “modules” in /tmp
/tmp$ mkdir module
change into this directory now
/tmp$ cd module /tmp/module$
Create a new .c file by
/tmp/module$ vi Module1.c
This opens up the vi editor
Use !wq to save the .c file
The header files module.h is required by all modules, kernel.h is required because we are using KERN_INFO (basically a log level used a parameter with printk, which is an equivalent of printf() in C ) and init.h is required for using the __init and __exit macros which are used by program to manage kernel memory.
The function “hello_init” uses no parameters but returns an integer, 0(zero) in case there are no errors, there might be a non zero value returned in case of any exceptions. Our program simply prints a message while loading and unloading so we can safely return a zero always.
The code is done, we need to compile the code to get a .ko file (kernel object file). Yes, its an object file, a binary file which is linked dynamically at the time of attaching to the kernel.
We now need to compile the code and this is not the ordinary C executable. We use Makefile for this purpose.
This is one example of Makefile you need to compile the code. Again use a vi editor to create a Makefile
/tmp/module$ vi Makefile
The path I am using in this makefile is my the one specific for my system. You can get this path for your system by viewing the /usr/src folder. This is one way of writing a Makefile, there is another one as well
Notice the difference between the paths used for compiling the code in make command
Once the Makefile is there, all that’s left is running a “make” command (the Makefile I used is the one in first example)
/tmp/module$ make
the output looks like:
/tmp/module$ make make -C /usr/src/linux-headers-3.13.0-71-generic SUBDIRS=/tmp/module modules make[1]: Entering directory `/usr/src/linux-headers-3.13.0-71-generic' Building modules, stage 2. MODPOST 1 modules make[1]: Leaving directory `/usr/src/linux-headers-3.13.0-71-generic'
You get a number of files generated now, what we need is the Module1.ko file. Run the command “modinfo Module1.ko”
/tmp/module$ modinfo Module1.ko filename: /tmp/module/Module1.ko description: A HelloWorld Module author: Hrmeet license: GPL srcversion: 9C73E1D2DD70C36B10ED118 depends: vermagic: 3.13.0-71-generic SMP mod_unload modversions
To get a list of modules that are currently loaded on the kernel, use the lsmod command
/tmp/module$ lsmod Module Size Used by nfsv3 39326 1 vboxsf 43798 2 nfsd 284385 2 auth_rpcgss 59338 1 nfsd binfmt_misc 17468 1 nfs_acl 12837 2 nfsd,nfsv3 nfs 236726 2 nfsv3 lockd 93977 3 nfs,nfsd,nfsv3 sunrpc 289260 19 nfs,nfsd,auth_rpcgss,lockd,nfsv3,nfs_acl fscache 63988 1 nfs dm_crypt 23177 0 joydev 17381 0 crct10dif_pclmul 14289 0 crc32_pclmul 13113 0 ghash_clmulni_intel 13216 0 video 19476 0 serio_raw 13462 0
Time now to insert your first module to the kernel. Use insmod with a sudo.
/tmp/module$ sudo insmod Module1.ko
If everything goes fine, you wont see any errors or messages, run the lsmod command again to find what modules it lists now
/tmp/module$ lsmod
Module Size Used by
Module1 12428 0
nfsv3 39326 1
vboxsf 43798 2
nfsd 284385 2
auth_rpcgss 59338 1 nfsd
binfmt_misc 17468 1
nfs_acl 12837 2 nfsd,nfsv3
nfs 236726 2 nfsv3
lockd 93977 3 nfs,nfsd,nfsv3
sunrpc 289260 19 nfs,nfsd,auth_rpcgss,lockd,nfsv3,nfs_acl
fscache 63988 1 nfs
dm_crypt 23177 0
joydev 17381 0
crct10dif_pclmul 14289 0
crc32_pclmul 13113 0
ghash_clmulni_intel 13216 0
video 19476 0
The module “Module1” appears on the top now. It can be removed by using the
/tmp/module$ sudo rmmod Module1.ko
The removal of module in this case is simple, as our module has not been using any peripheral device or file to read or write data. In modules with more complex functions, removal is a very critical part.
What did our module do when it was attached to the kernel? use command dmesg
/tmp/module$ dmesg
dmesg shows all kernel activity starting from when the kernel boots up. If you dont include the licensing information in your module program, you may see warning like the following in dmesg output.
Kernel tainting by missing licensing information is one of the ways you get a warning from the kernel. It means that your action has made changes to the kernel which is not recommended by the developer community and you may not get help resolving any errors you may face. Tread with caution here.
That’s all. A simple module registering into the kernel is just a foot in the door. This further opens up the possibility of creating programs like device drivers which can be used for more complex tasks.
Thanks for reading and please leave a comment/suggestion.