। जय श्री भगवान् ।
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 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,
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.
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!