Saturday, June 14, 2014

KBuild System and Hello World Module Part 1

। जय श्री भगवान् ।
In this post I'll talk about how to put your code with a running kernel. We'll start of pretty basic stuff and then start to understand Kbuild system in detail. We'll see how to compile a module spanning multiple files and how to use Kbuild to include files in project specific directories.

A Very Simple Hello World Kernel Module

Let's write some code for our hello world module, the following listing shows that

#include <common.h>
#include <my_module1.h>
static int __init module1_init(void)
{
        pr_err("Hello World module 1\n");
        return 0;
}
static void __exit module1_exit(void)
{
        pr_debug("Unloading module 1\n");
}
module_init(module1_init);
module_exit(module1_exit);

In the above code both the includes are created by me for this demonstration so it's not something provided by kernel. We'll see how can we specify the path to include directories in the Kbuild system but before doing that let's understand what the above code does. As you would've guessed the pr_ functions are being used to print to the system log.

These output will not appear on console when you load the module albeit they are logged in the system logged depending on the Log Level of the system. Usually you can see these messages via dmesg or you can also look in /var/log/messages but you should see if that's the file where your distribution's logs are logged.

I've used two ways to print the messages to system log. The difference is the way in which they are put in the code. The pr_debug message is put in the compiled code only if you've defined DEBUG while compiling. So let's check where and how to do that. Don't worry about __init and __exit for now as your module will compile even without using these. (Yes ok try ahead compile it see for yourself.... :-D)

The Kbuild File 


obj-m := module1.o
module1-objs := my_module1.o
DEBUG_FLAGS := -DDEBUG
ccflags-y := -I$(src)/../common $(DEBUG_FLAGS)

The above Kbuild file is fairly easy to understand. Line 1 says what is your module called, that is when every thing is done successfully we'll have a file by the name of module1.ko along with several others. This is the actual kernel module we are interested in so you won't put more than one name here and it can be anything since it's just a file name.

Line 2 tells the Kbuild system what comprises this module file. So in short this is a dependency list that tells Kbuild system which files need to be compiled to make this module. In this case we only have one file by the name of my_module1.c and we are saying that my_module1.o is required to make module1.o.

Line 3 is a normal make variable which we'll use in Line 4 where we are specifying the flags required to compile all the files. These ccflags can be on a file-by-file basis as well. We'll see an example of this for a module spanning multiple files. For now all the files compiled by this invocation of Kbuild will use the above defined ccflags.

When make is called, each invocation of Kbuild is separate in each directory so every invocation is isolated however it inherits the Kbuild variables passed from the parent directory. The variable src accessed using $(src) contains the absolute path where the Kbuild is running currently. So in the above case we use that information to tell which directory to look for includes. There's no space between -I and $, if you've more directories just add another one like above. At the end of the include flag I've set the DEBUG_FLAGS defined by me earlier. My directory listing looks like the following,

pranay@linux-y7pi:~/pks_modules> ls -d */
common/  module_1/  module_2/  test/

So when we invoke make in module_1 directory then the include would need to be a directory up in common. The current directory is always searched for include directory, that's why I didn't do an -I$(src)/.,  however if you've created another sub-directory then you'll need to tell Kbuild about it just like above.

So if you change DEBUG_FLAGS to be just a space instead of -DDEBUG then you'll see that pr_debug string will not be printed however pr_err would still be printed.


The Makefile

The following is the Makefile for the above module

KDIR ?=/lib/modules/$(shell uname -r)/build
all:
        make -C $(KDIR) M=$(PWD) modules

clean:
        make -C $(KDIR) M=$(PWD) clean

install:
        make -C $(KDIR) M=$(PWD) install

The KDIR is just a make variable we are using. In case somebody supplies this variable while invoking make then we'll use that as our kernel source directory. There's nothing you need to do here, but you can add any more targets in case you want to just like a normal Makefile. So nothing special here.


A word about __init and __exit

In my earlier post I told you a bit about sections. Well these __init and __exit are created for that purpose exactly. The idea is that the initialization code is usually one shot thing so there's no point holding that code after the module has been loaded. The same goes while un-loading the module, since the module is gone therefore there's no point to hold it's cleanup code since it's going to waste memory space.

To be able to free up the space these two macros are used by the kernel module loader. What these macros does is that they put the marked code into separate sections. So any function with __init goes into a section while __exit goes into another section. We need two sections since while loading the module the code is page aligned and kernel's memory allocation granularity is page oriented rather than any arbitrary size.

So when allocation is required for __init section then kernel knows how many pages it requires and it can free after initialization is done. The same way for __exit. The rest of the code, that is not marked with __init or __exit would still go in the normal .text section as we saw earlier. The following is the readelf output of the module1.ko

There are 35 section headers, starting at offset 0x13e18:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .note.gnu.build-i NOTE            00000000 000034 000024 00   A  0   0  4
  [ 2] .text             PROGBITS        00000000 000058 000000 00  AX  0   0  4
  [ 3] .init.text        PROGBITS        00000000 000058 000011 00  AX  0   0  1
  [ 4] .rel.init.text    REL             00000000 014390 000010 08     33   3  4
  [ 5] .exit.text        PROGBITS        00000000 000069 000028 00  AX  0   0  1
  [ 6] .rel.exit.text    REL             00000000 0143a0 000020 08     33   5  4
  [ 7] .rodata           PROGBITS        00000000 000091 00000d 00   A  0   0  1
  [ 8] .rodata.str1.1    PROGBITS        00000000 00009e 000034 01 AMS  0   0  1
  [ 9] .rodata.str1.4    PROGBITS        00000000 0000d4 00002f 01 AMS  0   0  4
  [10] .eh_frame         PROGBITS        00000000 000104 000050 00   A  0   0  4
  [11] .rel.eh_frame     REL             00000000 0143c0 000010 08     33  10  4
  [12] .modinfo          PROGBITS        00000000 000154 000069 00   A  0   0  1
  [13] __versions        PROGBITS        00000000 0001c0 0000c0 00   A  0   0 32
  [14] .data             PROGBITS        00000000 000280 000000 00  WA  0   0  4
  [15] __verbose         PROGBITS        00000000 000280 000018 00  WA  0   0  8
  [16] .rel__verbose     REL             00000000 0143d0 000020 08     33  15  4
  [17] .gnu.linkonce.thi PROGBITS        00000000 0002a0 000178 00  WA  0   0 32
  [18] .rel.gnu.linkonce REL             00000000 0143f0 000010 08     33  17  4
  [19] .bss              NOBITS          00000000 000418 000000 00  WA  0   0  4
  [20] .comment          PROGBITS        00000000 000418 000086 01  MS  0   0  1
  [21] .note.GNU-stack   PROGBITS        00000000 00049e 000000 00      0   0  1
  [22] .debug_aranges    PROGBITS        00000000 00049e 000040 00      0   0  1
  [23] .rel.debug_arange REL             00000000 014400 000020 08     33  22  4
  [24] .debug_info       PROGBITS        00000000 0004de 00b701 00      0   0  1
  [25] .rel.debug_info   REL             00000000 014420 005198 08     33  24  4
  [26] .debug_abbrev     PROGBITS        00000000 00bbdf 0005d2 00      0   0  1
  [27] .debug_line       PROGBITS        00000000 00c1b1 000b19 00      0   0  1
  [28] .rel.debug_line   REL             00000000 0195b8 000010 08     33  27  4
  [29] .debug_str        PROGBITS        00000000 00ccca 006fdc 01  MS  0   0  1
  [30] .debug_ranges     PROGBITS        00000000 013ca6 000030 00      0   0  1
  [31] .rel.debug_ranges REL             00000000 0195c8 000040 08     33  30  4
  [32] .shstrtab         STRTAB          00000000 013cd6 000142 00      0   0  1
  [33] .symtab           SYMTAB          00000000 019608 000280 10     34  35  4
  [34] .strtab           STRTAB          00000000 019888 0000e5 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)


Another important point about __exit is that when the module is built-in that is part of kernel not any separate .ko file then it doesn't do anything. The reason being it's possible that .text section's last page still has space that can be filled with code. So the build system optimizes this to pack __exit in text section since it knows you can't unload the module. However __init still works since initialization space can still be reclaimed.

Listing of Common.h


/*
 * Put all common includes here.
 */
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/net.h>



Exercise 1.1

Try to print a variable using pr_error and pr_debug just like printf. Try to print the addresses of the functions pr_debug and pr_error.

No comments :

Post a Comment

Thanks for commenting!