Linux Kernel Modules – 101

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

Screen Shot 2016-07-19 at 4.03.52 PM

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

Screen Shot 2016-07-19 at 4.38.24 PM

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

 

Screen Shot 2016-07-19 at 5.36.23 PM

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

 

Screen Shot 2016-07-19 at 5.18.26 PM

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.

 

Screen Shot 2016-07-19 at 8.42.11 PM

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.

Advertisements
Linux Kernel Modules – 101