Tutorial DescTutorial-desc
Tutorial DescTutorial-desc
In my case, $(KVERSION)=3.16.0-4-amd64.
4) Compile module using make command (module build can be done by any user) :
$ make
It will finally creates the foo.ko module in current directory. You can see all actual compile command
stored in .foo* files in same directory.
5) Once module compiled successfully, load it using insmod or modprobe command. You need to be
root user or privileged user to run insmod:
1/19
# insmod foo.ko
2/19
$ make
6) Become a root user (use su or sudo) and load the module:
$ su # insmod hello.ko
Note you can see message on screen if you are logged in as root under run level 3.
7) Verify that module loaded:
# lsmod | less
8) See message in /var/log/message file:
# tail -f /var/log/message
9) Unload the module:
# rmmod hello
10)
Load module when Linux system comes up. File /etc/modules use to load kernel boot time. This file
should contain the names of kernel modules that are to be loaded at boot time, one per line. First copy
your module to /lib/modules/$(uname -r)/kernel/drivers. Following are suggested steps:
(a) Create directory for hello module:
# mkdir -p /lib/modules/$(uname -r)/kernel/drivers/hello
(b) Copy module:
# cp hello.ko /lib/modules/$(uname -r)/kernel/drivers/hello/
(c) Edit /etc/modules file under Debian Linux:
# vi /etc/modules
(d) Add following line to it:
hello
(e) Reboot to see changes. Use lsmod or dmesg command to verify module loaded or not.
# cat /proc/modules
Or
# lsmod | less
3/19
/*
* A non 0 return means init_module failed; module can't be loaded.
*/
return 0;
void cleanup_module(void)
{
printk(KERN_INFO "Goodbye world 1.\n");
}
Kernel modules must have at least two functions: a "start" (initialization) function called
init_module() which is called when the module is insmoded into the kernel, and an "end"
4/19
(cleanup) function called cleanup_module() which is called just before it is rmmoded. Actually,
things have changed starting with kernel 2.3.13. You can now use whatever name you like for the start
and end functions of a module, and you'll learn how to do this in Section 2.3. In fact, the new method is
the preferred method. However, many people still use init_module() and cleanup_module()
for their start and end functions.
Typically, init_module() either registers a handler for something with the kernel, or it replaces one
of the kernel functions with its own code (usually code to do something and then call the original
function). The cleanup_module() function is supposed to undo whatever init_module() did,
so the module can be unloaded safely.
Lastly, every kernel module needs to include linux/module.h. We needed to include
linux/kernel.h only for the macro expansion for the printk() log level, KERN_ALERT, which
you'll learn about in Section 2.1.1.
5/19
From a technical point of view just the first line is really necessary, the "all" and "clean" targets were
added for pure convenience.
Now you can compile the module by issuing the command make . You should obtain an output which
resembles the following:
hostname:~/lkmpg-examples/02-HelloWorld# make
make -C /lib/modules/2.6.11/build M=/root/lkmpg-examples/02-HelloWorld modules
make[1]: Entering directory `/usr/src/linux-2.6.11'
CC [M] /root/lkmpg-examples/02-HelloWorld/hello-1.o
Building modules, stage 2.
MODPOST
CC
/root/lkmpg-examples/02-HelloWorld/hello-1.mod.o
LD [M] /root/lkmpg-examples/02-HelloWorld/hello-1.ko
make[1]: Leaving directory `/usr/src/linux-2.6.11'
hostname:~/lkmpg-examples/02-HelloWorld#
Note that kernel 2.6 introduces a new file naming convention: kernel modules now have a .ko
extension (in place of the old .o extension) which easily distinguishes them from conventional object
files. The reason for this is that they contain an additional .modinfo section that where additional
information about the module is kept. We'll soon see what this information is good for.
Use modinfo hello-*.ko to see what kind of information it is.
6/19
Nothing spectacular, so far. That changes once we're using modinfo on one of our the later examples,
hello-5.ko .
hostname:~/lkmpg-examples/02-HelloWorld# modinfo hello-5.ko
filename:
hello-5.ko
license:
GPL
author:
Peter Jay Salzman
vermagic:
2.6.11 preempt PENTIUMII 4KSTACKS gcc-3.3
depends:
parm:
myintArray:An array of integers (array of int)
parm:
mystring:A character string (charp)
parm:
mylong:A long integer (long)
parm:
myint:An integer (int)
parm:
myshort:A short integer (short)
hostname:~/lkmpg-examples/02-HelloWorld#
Lot's of useful information to see here. An author string for bugreports, license information, even a
short description of the parameters it accepts.
Additional details about Makefiles for kernel modules are available in
linux/Documentation/kbuild/makefiles.txt. Be sure to read this and the related files
before starting to hack Makefiles. It'll probably save you lots of work.
Now it is time to insert your freshly-compiled module it into the kernel with insmod ./hello-1.ko
(ignore anything you see about tainted kernels; we'll cover that shortly).
All modules loaded into the kernel are listed in /proc/modules. Go ahead and cat that file to see
that your module is really a part of the kernel. Congratulations, you are now the author of Linux kernel
code! When the novelty wears off, remove your module from the kernel by using rmmod hello-1. Take
a look at /var/log/messages just to see that it got logged to your system logfile.
Here's another exercise for the reader. See that comment above the return statement in
init_module()? Change the return value to something negative, recompile and load the module
again. What happens?
7/19
So now we have two real kernel modules under our belt. Adding another module is as simple as this:
Example 2-4. Makefile for both our modules
obj-m += hello-1.o
obj-m += hello-2.o
all:
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Now have a look at linux/drivers/char/Makefile for a real world example. As you can see,
some things get hardwired into the kernel (obj-y) but where are all those obj-m gone? Those familiar
with shell scripts will easily be able to spot them. For those not, the obj-$(CONFIG_FOO) entries you
see everywhere expand into obj-y or obj-m, depending on whether the CONFIG_FOO variable has
8/19
been set to y or m. While we are at it, those were exactly the kind of variables that you have set in the
linux/.config file, the last time when you said make menuconfig or something like that.
9/19
In kernel 2.4 and later, a mechanism was devised to identify code licensed under the GPL (and friends)
so people can be warned that the code is non open-source. This is accomplished by the
MODULE_LICENSE() macro which is demonstrated in the next piece of code. By setting the license
to GPL, you can keep the warning from being printed. This license mechanism is defined and
documented in linux/module.h:
/*
* The following license idents are currently accepted as indicating free
* software modules
*
*
"GPL"
[GNU Public License v2 or later]
*
"GPL v2"
[GNU Public License v2]
*
"GPL and additional rights"
[GNU Public License v2 rights and more]
*
"Dual BSD/GPL"
[GNU Public License v2
*
or BSD license choice]
*
"Dual MIT/GPL"
[GNU Public License v2
*
or MIT license choice]
*
"Dual MPL/GPL"
[GNU Public License v2
*
or Mozilla license choice]
*
* The following other idents are available
*
*
"Proprietary"
[Non free products]
*
* There are dual licensed components, but when running with Linux it is the
* GPL that is relevant so this is a non issue. Similarly LGPL linked with GPL
* is a GPL combined work.
*
* This exists for several reasons
* 1.
So modinfo can show license info for users wanting to vet their setup
*
is free
* 2.
So the community can ignore bug reports including proprietary modules
* 3.
So vendors can do likewise based on their own policies
*/
11/19
12/19
Arrays are supported too, but things are a bit different now than they were in the 2.4. days. To keep
track of the number of parameters you need to pass a pointer to a count variable as third parameter. At
your option, you could also ignore the count and pass NULL instead. We show both possibilities here:
int myintarray[2];
module_param_array(myintarray, int, NULL, 0); /* not interested in count */
int myshortarray[4];
int count;
module_parm_array(myshortarray, short, , 0); /* put count into "count" variable */
A good use for this is to have the module variable's default values set, like an port or IO address. If the
variables contain the default values, then perform autodetection (explained elsewhere). Otherwise, keep
the current value. This will be made clear later on.
Lastly, there's a macro function, MODULE_PARM_DESC(), that is used to document arguments that
the module can take. It takes two parameters: a variable name and a free form string describing that
variable.
Example 2-7. hello-5.c
/*
* hello-5.c - Demonstrates command line argument passing to a module.
*/
#include <linux/module.h>
13/19
#include
#include
#include
#include
<linux/moduleparam.h>
<linux/kernel.h>
<linux/init.h>
<linux/stat.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Peter Jay Salzman");
static
static
static
static
static
static
/*
* module_param(foo, int, 0000)
* The first param is the parameters name
* The second param is it's data type
* The final argument is the permissions bits,
* for exposing parameters in sysfs (if non-zero) at a later stage.
*/
module_param(myshort, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
MODULE_PARM_DESC(myshort, "A short integer");
module_param(myint, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(myint, "An integer");
module_param(mylong, long, S_IRUSR);
MODULE_PARM_DESC(mylong, "A long integer");
module_param(mystring, charp, 0000);
MODULE_PARM_DESC(mystring, "A character string");
/*
* module_param_array(name, type, num, perm);
* The first param is the parameter's (in this case the array's) name
* The second param is the data type of the elements of the array
* The third argument is a pointer to the variable that will store the number
* of elements of the array initialized by the user at module loading time
* The fourth argument is the permission bits
*/
module_param_array(myintArray, int, &arr_argc, 0000);
MODULE_PARM_DESC(myintArray, "An array of integers");
static int __init hello_5_init(void)
{
int i;
printk(KERN_INFO "Hello, world 5\n=============\n");
printk(KERN_INFO "myshort is a short integer: %hd\n", myshort);
printk(KERN_INFO "myint is an integer: %d\n", myint);
printk(KERN_INFO "mylong is a long integer: %ld\n", mylong);
printk(KERN_INFO "mystring is a string: %s\n", mystring);
for (i = 0; i < (sizeof myintArray / sizeof (int)); i++)
{
printk(KERN_INFO "myintArray[%d] = %d\n", i, myintArray[i]);
}
printk(KERN_INFO "got %d arguments for myintArray.\n", arr_argc);
return 0;
14/19
}
static void __exit hello_5_exit(void)
{
printk(KERN_INFO "Goodbye, world 5\n");
}
module_init(hello_5_init);
module_exit(hello_5_exit);
15/19
int init_module(void)
{
printk(KERN_INFO "Hello, world - this is the kernel speaking\n");
return 0;
}
void cleanup_module()
{
printk(KERN_INFO "Short is the life of a kernel module\n");
}
16/19
This is the complete makefile for all the examples we've seen so far. The first five lines are nothing
special, but for the last example we'll need two lines. First we invent an object name for our combined
module, second we tell make what object files are part of that module.
In other words, your kernel refuses to accept your module because version strings (more precisely,
version magics) do not match. Incidentally, version magics are stored in the module object in the form
of a static string, starting with vermagic:. Version data are inserted in your module when it is linked
against the init/vermagic.o file. To inspect version magics and other strings stored in a given
module, issue the modinfo module.ko command:
[root@pcsenonsrv 02-HelloWorld]# modinfo hello-4.ko
license:
GPL
author:
Peter Jay Salzman <[email protected]>
description:
A sample driver
vermagic:
2.6.5-1.358 686 REGPARM 4KSTACKS gcc-3.3
depends:
To overcome this problem we could resort to the --force-vermagic option, but this solution is
potentially unsafe, and unquestionably inacceptable in production modules. Consequently, we want to
compile our module in an environment which was identical to the one in which our precompiled kernel
17/19
was built. How to do this, is the subject of the remainder of this chapter.
First of all, make sure that a kernel source tree is available, having exactly the same version as your
current kernel. Then, find the configuration file which was used to compile your precompiled kernel.
Usually, this is available in your current /boot directory, under a name like config-2.6.x. You
may just want to copy it to your kernel source tree: cp /boot/config-`uname -r` /usr/src/linux-`uname
-r`/.config.
Let's focus again on the previous error message: a closer look at the version magic strings suggests that,
even with two configuration files which are exactly the same, a slight difference in the version magic
could be possible, and it is sufficient to prevent insertion of the module into the kernel. That slight
difference, namely the custom string which appears in the module's version magic and not in the
kernel's one, is due to a modification with respect to the original, in the makefile that some distribution
include. Then, examine your /usr/src/linux/Makefile, and make sure that the specified
version information matches exactly the one used for your current kernel. For example, you makefile
could start as follows:
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 5
EXTRAVERSION = -1.358custom
In this case, you need to restore the value of symbol EXTRAVERSION to -1.358. We suggest to keep
a backup copy of the makefile used to compile your kernel available in /lib/modules/2.6.51.358/build. A simple cp /lib/modules/`uname -r`/build/Makefile /usr/src/linux-`uname -r`
should suffice. Additionally, if you already started a kernel build with the previous (wrong)
Makefile, you should also rerun make, or directly modify symbol UTS_RELEASE in file
/usr/src/linux-2.6.x/include/linux/version.h according to contents of file
/lib/modules/2.6.x/build/include/linux/version.h, or overwrite the latter with the
first.
Now, please run make to update configuration and version headers and objects:
[root@pcsenonsrv linux-2.6.x]# make
CHK
include/linux/version.h
UPD
include/linux/version.h
SYMLINK include/asm -> include/asm-i386
SPLIT
include/linux/autoconf.h -> include/config/*
HOSTCC scripts/basic/fixdep
HOSTCC scripts/basic/split-include
HOSTCC scripts/basic/docproc
HOSTCC scripts/conmakehash
HOSTCC scripts/kallsyms
CC
scripts/empty.o
If you do not desire to actually compile the kernel, you can interrupt the build process (CTRL-C) just
after the SPLIT line, because at that time, the files you need will be are ready. Now you can turn back
18/19
to the directory of your module and compile it: It will be built exactly according your current kernel
settings, and it will load into it without any errors.
19/19