Sunday, September 28, 2008

First Steps with Linux Kernel Programming

Like any programming endeavour, this one begins by saying hello to the world and remembering MAHAKALI : The supreme consciousness and the creatrix of the universe.

So without much ado, here are the steps :-

1. create a file called hello.c.Use an editor of your choice. Some people like vi/emacs whereas others use kate or gedit. Suit yourselves guys.

2. your first kernel program looks like this :-

#include <> /* for __init and __exit */
#include <> /* for MODULE related macros */
#include <>

/* this is the function which is invoked on issuing the "insmod" command */
/* unlike userland programs, there is no main function. Init module is the entry point */

static int __init hello_init(void)
{
printk(KERN_ALERT "Jai Mahakali: Jai Bhawani: Welcome !\n");
return 0;
}

/* ths is the function which is invoked on issuing the "rmmod" command */
/* it is an indication to the kernel that this module is no longer needed and can be unloaded */
static void __exit hello_exit(void)
{
printk(KERN_ALERT "Jai Kaal Bhairav : Adieus \n");
}

/* module_init : adds a special section to module's object code indicating the module initialization func */
/* module exit : ditto */

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("Dual BSD\GPL"); /* add this if you dont want to get kernel taint warnings */
MODULE_AUTHOR("Nemesis KERNELEXPLOIT@GMAIL.COM");
MODULE_DESCRIPTION("Hello World");

3. Write the make file (courtesy Linux Device Drivers 3rd Edition). I don't exactly enjoy writing makefiles. Infact I am yet to meet a person who does.

-------------------------------------------x-------------------------------------------------x------------------------------------x------------------------

# To build modules outside of the kernel tree, we run "make"
# in the kernel source tree; the Makefile these then includes this
# Makefile once again.
# This conditional selects whether we are being included from the
# kernel Makefile or not.
ifeq ($(KERNELRELEASE),)

# Assume the source tree is where the running kernel was built
# You should set KERNELDIR in the environment if it's elsewhere
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
# The current directory is passed to sub-makes as argument
PWD := $(shell pwd)

modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

.PHONY: modules modules_install clean

else
# called from kernel build system: just declare what our modules are
obj-m := hello.o

endif

-------------------------------------------x-------------------------------------------------x------------------------------------x-----------------------

4. issue the following command

nemesis@tantra:~/device-drivers$ make
make -C /lib/modules/2.6.18-6-686/build M=/home/nemesis/device-drivers modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.18-6-686'
CC [M] /home/nemesis/device-drivers/hello.o
/home/nemesis/device-drivers/hello.c:19:1: warning: unknown escape sequence '\G'
/home/nemesis/device-drivers/hello.c:21:35: warning: no newline at end of file
Building modules, stage 2.
MODPOST
CC /home/nemesis/device-drivers/hello.mod.o
LD [M] /home/nemesis/device-drivers/hello.ko
make[1]: Leaving directory `/usr/src/linux-headers-2.6.18-6-686'
nemesis@tantra:~/device-drivers$

5. Wonderful!!! we have our shiny new module ready!!! Execute the insmod command. Well you need to be root to be able to insert a module into the kernel. If you are not a part of the sudoer's group you will not be able to proceed further. But we are not going to be daunted by a little glitch are we now ?

here is what to do:
sudo /usr/sbin/visudo
add the following line at the end of this file
your-username ALL=(ALL) ALL

Now that we have this out of our way , proceed with insmod

nemesis@tantra:~/device-drivers$sudo /sbin/insmod hello.ko
nemesis@tantra:~/device-drivers$dmesg

here is what you see at the end of the output
Jai Mahakali: Jai Bhawani: Welcome !

Now its time we unload the module
nemesis@tantra:~/device-drivers$sudo /sbin/rmmod hello.ko
nemesis@tantra:~/device-drivers$dmesg

here is what you see at the end of the output
Jai Kaal Bhairav : Adieus


6 . Its time we gather some info about our module
nemesis@tantra:~/device-drivers$sudo /sbin/modinfo hello.ko
filename: hello.ko
license: Dual BSDGPL
author: Nemesis KERNELEXPLOIT@GMAIL.COM
description: Hello World
vermagic: 2.6.18-6-686 SMP mod_unload 686 REGPARM gcc-4.1
depends:

Some Kernel Modules may accept user-specified parameters.


modinfo -p ${modulename}

The command above shows a current list of all parameters of a loadable
module. Loadable modules, after being loaded into the running kernel, also
reveal their parameters in /sys/module/${modulename}/parameters/. Some of these parameters may be changed at runtime by the command

echo -n ${value} > /sys/module/${modulename}/parameters/${parm}

7. at a final look at the elf-object code of hello.ko to see the __init section. Just to let you guys know that I wasnt bluffing !

nemesis@tantra:~/device-drivers$readelf -a hello.ko
Symbol table '.symtab' contains 32 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 SECTION LOCAL DEFAULT 1
2: 00000000 0 SECTION LOCAL DEFAULT 2
3: 00000000 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 SECTION LOCAL DEFAULT 4
5: 00000000 0 SECTION LOCAL DEFAULT 5
6: 00000000 0 SECTION LOCAL DEFAULT 6
7: 00000000 0 SECTION LOCAL DEFAULT 7
8: 00000000 0 SECTION LOCAL DEFAULT 8
9: 00000000 0 SECTION LOCAL DEFAULT 9
10: 00000000 0 SECTION LOCAL DEFAULT 10
11: 00000000 0 SECTION LOCAL DEFAULT 11
12: 00000000 0 SECTION LOCAL DEFAULT 12
13: 00000000 0 SECTION LOCAL DEFAULT 13
14: 00000000 0 SECTION LOCAL DEFAULT 14
15: 00000000 0 SECTION LOCAL DEFAULT 15
16: 00000000 0 SECTION LOCAL DEFAULT 16
17: 00000000 0 SECTION LOCAL DEFAULT 17
18: 00000000 0 FILE LOCAL DEFAULT ABS hello.c
19: 00000000 12 FUNC LOCAL DEFAULT 2 hello_exit
20: 00000000 14 FUNC LOCAL DEFAULT 4 hello_init
21: 00000000 20 OBJECT LOCAL DEFAULT 7 __mod_license19
22: 00000020 36 OBJECT LOCAL DEFAULT 7 __mod_author20
23: 00000044 24 OBJECT LOCAL DEFAULT 7 __mod_description21
24: 00000000 0 FILE LOCAL DEFAULT ABS hello.mod.c
25: 00000060 57 OBJECT LOCAL DEFAULT 7 __mod_vermagic5
26: 00000000 128 OBJECT LOCAL DEFAULT 8 ____versions
27: 00000099 9 OBJECT LOCAL DEFAULT 7 __module_depends
28: 00000000 608 OBJECT GLOBAL DEFAULT 10 __this_module
29: 00000000 12 FUNC GLOBAL DEFAULT 2 cleanup_module
30: 00000000 14 FUNC GLOBAL DEFAULT 4 init_module
31: 00000000 0 NOTYPE GLOBAL DEFAULT UND printk

Well Adieus for now! Next up is a dummy char driver.

No comments: