You are on page 1of 5

Introduction to Linux Device Driver Development

Prepared by: Richard A. Sevenich, rsevenic@netscape.net


Chapter 1. An Environment for Linux Device Driver Development
1.0 Introductory Comments
The kernel developers use a simple version numerology, a dotted triple of form X.Y.Z e.g. 2.3.4 or 2.4.1. If the
second number (Y) is odd then the kernel is a development version; whereas, if the second number is even, then the
kernel is a stable, production version. Hence, 2.3.4 is from the development tree and 2.4.1 is from the stable tree.
The ordinary user should pick from the stable tree and, when possible, make a choice that seems to be particularly
stable. Developers might be running a machine with separate partitions affording various choices. To keep track of
what is happening with current kernel development, browse the Kernel Traffic website at http://kt.zork.net/. This
also gives useful links. For example, this is a place to start a search for descriptions of changes to the API when the
kernel undergoes a major revision (e.g. 2.2.x to 2.4.x). In this course we will work with the current stable kernel
version, available from http://www.kernel.org/.
1.1 Kernel Mode Versus User Mode
Linux operates in one of two available modes, either user mode or kernel mode. This impacts how one writes code
for operating in these two modes, as well. When one programs for user mode, one may use libc and include the
related header files. However, when developing for kernel mode, one is constrained to using functions/symbols that
it exports. For example, a function as commonplace as printf is not available - there fortunately is a kernel mode
replacement, printk.
To see the kernel symbols available, look in /proc/ksyms. There, for example, you would find printk listed. If you
find something such as
c0112d1c printk_Rdd132261
with the suffix attached to printk, then your kernel is configured with the CONFIG_MODVERSIONS setting true. If
there is no such suffix, CONFIG_MODVERSIONS is not set. So what is the meaning of this suffix? The answer lies
in understanding version dependency.
There can be significant changes from one version of the kernel to the next. For example, the prototype for get_user
changed from kernel version 2.0 to 2.2. One way to compensate for this possibility is to recompile your module for
each different kernel in which it is used. In fact, insmod checks the kernel version, under which the module was
compiled, against the currently running kernel. With this convention, recompilation of the module using header files
consistent with the currently running kernel is necessary - even if none of the involved function prototypes and
underlying data structures have changed.
There is a somewhat flexible way to avoid unnecessary recompilation. What is done is to parse the function
prototypes and the data structure definitions and create a representative 32-bit CRC, which is appended to the kernel
symbol name. For the printk example above the 32-bit CRC would be 0xdd132261. Then insmod checks for
consistent CRC values instead of for the kernel version number. To enable this option, the
CONFIG_MODVERSIONS setting is active. When you later recompile the kernel, this option will be chosen as
true.
R.A. Sevenich 2004 Introduction to Linux Device Driver Development 1-
1
1.2 Include Files
The header files for use in our drivers are typically drawn from these directories:
/usr/src/linux/include/linux/ - chip architecture independent
/usr/src/linux/include/asm/ - chip architecture dependent
There may be links to these directories from the traditional locations (but sometimes aren't), which are, respectively,
/usr/include/linux
/usr/include/asm
Include statements will then be in this sort of style
#include <linux/kernel.h> - chip architecture independent
#include <asm/uaccess.h> - chip architecture dependent
1.3 Kernel Data Types
The data sizes for standard C types may vary across a set of architectures. For example, for the IA-32 we have (in
bytes)
sizeof(long) = 4
whereas for the alpha we have
sizeof(long) = 8
Clearly, wherever size is a potential issue, the driver writer must take care. For this purpose, linux defines these
signed and unsigned size-specific types (in bits - see <asm/types.h>):
s8, s16, s32, s64
u8, u16, u32, u64
Further, in <linux/types.h> we find the list of '_t' types found, for example, in prototypes. These are based on
typedef statements intended to ensure portability. Here is an example,
ssize_t (*read) (struct file *, char *, size_t, loff_t *);
which is intended as portable across diverse architectures.
1.4 Getting and Installing the Kernel Sources
It is useful to work through a concrete example, making specific choices which will provide later flexibility. Assume
that your machine is currently operating with kernel version 2.4.23 and that you wish to install a newer version.
2.4.24. To download kernel sources, you can start by browsing the website http://www.kernel.org/pub/ . This will
lead you to a mirror site for whatever country is most convenient for downloading, not necessarily the USA. You
can download from two possible formats, either '*.tar.gz' or '*.tar.bz2', and with file sizes for the latter currently on
the order of 30 MB. Place the downloaded linux-2.4.24.tar.bz2 (or equivalent) into '/usr/src/', the conventional
location.
It will be asumed here that you are about to install a kernel version different from that currently on your machine.
[Note: On the other hand, if you are recompiling your current version, protecting your original version is somewhat
more involved. In that case, get guidance from your instructor.]
R.A. Sevenich 2004 Introduction to Linux Device Driver Development 1-
2
Here are the necessary steps (to be taken as root):
1. From within /usr/src, explode the newly downloaded tzarball e.g.
tar xvfj linux-2.4.24.tar.bz2
and then change to the just created directory e.g.
cd linux-2.4.24
2. Enter the command
make mrproper
Note: This does a lot of cleanup, which may or may not be necessary. Among other files, it destroys any existing dot
files e.g. '.config'. If that file is one you've worked hard to achieve, you'd better back it up (but not to a dot file).
3. Enter the command
make xconfig
or else
make menuconfig
Note: In either case, this then requires you to make lots of choices - some obvious and some arcane. An intimate
knowledge of your machine is useful. Some distributions now provide some default choices for your machine based
on the original Linux install. Ask your instructor about your particular distribution. One of the results of this step is a
new '.config' file. Once a '.config' exists it provides default choices when/if this step is repeated.
4. Enter the command
make dep
5. Enter the command
make bzImage
Note: This produces a compressed kernel image based on the choices made in step 3. If the compressed image is not
too large, you can also make a boot floppy via 'make bzdisk'.
6. Enter the command
make modules
Note: This creates any modules you requested in step 3.
7. Enter the command
make modules_install
Note: This installs the modules created in step 6 to a directory hierarchy in /lib/modules e.g. to /lib/modules/2.4.24.
The target directory name, e.g. 2.4.2, can be made unique by placing a unique name in the 'EXTRAVERSION' field
found very near the start of the Makefile, i.e /usr/src/linux-2.4.24/Makefile.
8. Copy the new system map to /boot e.g.
cp System.map /boot/System.map-2.4.24
9. Copy the new kernel image to /boot e.g.
cp arch/i386/boot/bzImage /boot/vmlinuz-2.4.24
1.5 Safely Booting the Freshly Compiled Kernel with lilo
We'll assume that your system currently boots by using 'lilo', the Linux loader, which typically writes boot code to
the master boot record. We also assume that you have a boot floppy or other rescue disk or cdrom available in case
the installation goes badly awry. For in-depth documentation on 'lilo' see the manual which can be found in
'/usr/doc/lilo'.
The system was already working and booting properly - so we don't want to lose access to that former kernel if
things don't work out well with the new kernel. It is assumed that your system boots using the Linux loader, lilo. The
configuration file for lilo governs the boot process and is found as the ASCII file '/etc/lilo.conf'.
R.A. Sevenich 2004 Introduction to Linux Device Driver Development 1-
3
Here is a typical lilo.conf for a machine with a single working kernel:
#/etc/lilo.conf
boot=/dev/hda
verbose=2
compact
install=/boot/boot.b
map=/boot/map
vga=normal
prompt
message=/boot/message
image=/boot/vmlinuz-2.4.23
root=/dev/hda1
label=linux-2.2.12
initrd=/boot/initrd-2.4.23.img
read-only
The 'prompt' keyword indicates that a prompt will be issued to the user. The prompt is based on the contents of /
etc/lilo.conf as encoded in the binary file /boot/message. This may display a distribution specific graphic as well.
The preceding lilo.conf file assumes that the appropriate hard drive is connected as the master (/dev/hda) on the first
IDE controller connector. This may be otherwise for your machine and your existing lilo.conf will give the essential
guidance in this regard. In particular, it is not necessarily /dev/hda etc. The idea now is to modify the boot process to
allow as a second boot possibility, the replacement kernel. One might proceed as follows (the order is important):
Step 1
Edit '/etc/lilo.conf', adding a new boot image to obtain this:
#/etc/lilo.conf
boot=/dev/hda
verbose=2
compact
install=/boot/boot.b
map=/boot/map
vga=normal
prompt
message=/boot/message
image=/boot/vmlinuz-2.4.23
root=/dev/hda1
label=linux-2.2.12
initrd=/boot/initrd-2.4.23.img
read-only
image=/boot/vmlinuz-2.4.24
root=/dev/hda1
label=linux-2.4.24
read-only
Step 2 [Don't miss this one!]
After saving your new /etc/lilo.conf, run 'lilo' at the command line by typing
/sbin/lilo
which should give reassuring messages as it writes the new master boot record.
R.A. Sevenich 2004 Introduction to Linux Device Driver Development 1-
4
Note: If your system boots using grub, you must add a boot stanza to /boot/grub/menu.lst. This process is similar to
that used for /etc/lilo.conf; in particular, menu.lst will have at least one preexisting boot stanza which can be used as
template to copy and modify appropriately (be sure to retain the original boot stanza in menu.lst). We won't discuss
this in detail. Once menu.lst is modified, there is no further step analogous to running lilo as described in Step 2 of
the lilo discussion i.e. the system is ready to reboot once menu.lst is modified appropriately.
1.6 Activities
Activity 1
Download a recent kernel version (as specified by your instructor), configure it, and compile it for your hardware.
Ensure that module versioning is configured. Also, in preparation for a later case study, ensure that the use of the
parallel port is not configured. The instructor may have other configuration suggestions.
Activity 2
Minor modifications are added to the kernel by a process called 'patching'. Investigate how to do this by reading the
man page for 'patch'. Then download a patch intended for your kernel and update your kernel. We suggest the kdb
patch set (two files) as a candidate (see http://oss.sgi.com/projects/kdb/).
R.A. Sevenich 2004 Introduction to Linux Device Driver Development 1-
5

You might also like