Loadable Kernel Modules, I will demonstrate the whole process on embedded system, for your information,

1) Development station with debian distro,

2) Embedded Artists LPC OEM 3250 (ARM 9) development board, are the basic requirement for any embedded system.

Linux Kernel

Unfortunately, my development board was quite old, I was unable to locate the default configuration file from latest Kernel sources. So I decided to go back in search of old Kernel sources (v2). I found linux kernel version 2.6.34 is appropriate for my board, board’s manual from vendor helped me alot for choosing kernel.

After downloading, I had same problem, absence of default configuration. Fortunately I found a patch, which made the kernel suitable for my EA 3250 board.

$ tar -xf linux-2.6.34.xz

 

$ cd linux-2.6.34/

Applied patch,

$ patch -p1 < ../patchfile

Kernel configuration,

$ make ARCH=arm CROSS_COMPILE=arm-linux- ea3250_defconfig

Building uImage

$ make ARCH=arm CROSS_COMPILE=arm-linux- uImage

So, Kernel Image is available at arch/arm/boot/uImage.

I booted kernel using tftp and had access to Network root file system (NFS). So my development board and work station is ready to work further.

Kernel Module Source code

Create a hello.c inside /root directory of NFS root file system after booting board.

$ vim hello.c

#include <linux/init.h>
#include <linux/module.h>

#include <linux/moduleparam.h>

MODULE_LICENSE(“GPL”);
MODULE_AUTHOR(“S MOHAMMED AUDHIL”);

static char *data = “world”;
module_param(data, charp, 0); // Declaring Module parameter

static int howmany = 1;
module_param(howmany, int, 0); // Declaring Module parameter

static int secs; // to display number of seconds elapsed since my module was loaded into kernel
struct timeval tv; // Required structure for do_gettimeofday() function

static int __init hello_init(void)
{
int i;
do_gettimeofday(&tv); // It is function to return number of seconds 
secs = tv.tv_sec; // storing value in local variable
for (i = 1; i <= howmany; i++)
printk(KERN_ALERT “(%d) Hello %s\n”, i, data);
return 0;
}

static void __exit hello_exit(void)
{
printk(KERN_ALERT “Program Over..\n”);
printk(KERN_ALERT “Module loaded for %d seconds”, secs – 613416); // I found this 613416 to get exact one second time
}

module_init(hello_init);
module_exit(hello_exit);

$ vim Makefile

obj-m := hello.o

KDIR := $(HOME)/Desktop/Kernel_dd_training/felabs/linux/modules/linux-2.6.34
PWD := $(shell pwd)

default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules

Cross compiling module suitable for ARM architecture NOTE : I cross compiled at development workstation

$ make ARCH=arm CROSS_COMPILE=arm-linux- 

Now loading, module NOTE : This is to be done at target architecture

$ insmod hello.ko howmany=2

Checking

$ dmesg

[ 78.312925] (1) Hello world

[ 78.312925] (2) Hello world

$ rmmod hello.ko

Checking

$ dmesg

[ 87.312925] Program over..

[ 87.312925] Module loaded for 19 seconds

So every thing works fine…

Linux Coding Standards,

It is mandatory for any source code to be liable for standards, hence others can read / modify our source code accordingly.

Fortunately, the Linux kernel community provides you with a utility to find coding standards violations.

Run the scripts/checkpatch.pl -h command in the kernel sources, to find which options are available. Now, run:

scripts/checkpatch.pl –file –no-tree <path>/<to>/hello.c

And See how many violations are reported on your code,  fix your code until there are no errors left.

Time to add new module into Kernel Source directory

1) Add hello.c inside Drivers/misc/ directory of Kernel source

2) Describe the configuration interface for your new driver by adding the following lines to the Kconfig file in this directory:

config HELLO_DRIVER
tristate “mY OWN DRIVER”
depends on ARM
help
mY HAND ROLLED DRIVER

3) Add a line in the Makefile file based on the Kconfig setting:

obj-$(CONFIG_HELLO_DRIVER) += hello.o

During Kernel Configuration for ARM architecture you may see our driver at

Device Drivers —>

              Misc devices —>

                        mY OWN DRIVER

You can configure it as module, as other options you select at configuration…

Creating Patch

You can be proud of your new module! To be able to share it with others, create a patch which adds your new files to the mainstream kernel.

Before making your changes, make sure you have two kernel trees:

$ cp -a linux-x.x.xx/ linux-x.x.xx-patch/

Make your changes in linux-x.x.xx-patch/

Run make distclean to keep only source files.

$ make distclean

Create a patch file:

$ diff -Nur linux-x.x.xx/ linux-x.x.xx-patch/ > patchfile 

Congrats…! you can apply this patch to fresh kernel source of same version and add new driver.

Share your patchfile to friends and let them analyse new driver…!

Enjoy..!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s