Tuesday, July 10, 2007

Checklist July 10, 2007

Topics I need to cover next in details are:

1. Character Devices and Block Devices
2. Major Number and Minor Numbers
3. Routines

Linux Device Driver Architecture Components

I have discussed about the module structures before. Now lets have a look on overall linux device driver architecture components. So that we can sort out, what should be the next step of my research work.

Device Drivers as modules

Linux device drivers are managed by kernel itself. Modules works here as device drivers. Modules can interact with kernels directly. When we write device drivers, we use the module structure to specify custom routines. (I have posted the basic module structure before, you can take a look on that).

To load the driver we use module_init and to unload we use module_exit. When the module_init is executed, the first routine is executed as well. We have seen this example when we wrote the elementary module on previous post. The kernel registers the driver by using a registration routine
register_chrdev while loading the module and when unloading the module it uses unregister_chrdev. By the way, these are for character devices. I still don't know what actually these does, I'll find it out later.

Naming Devices

In linux, devices are labeled by numbers (0-255). These 256 numbers are known as major numbers. A major number is assigned to a particular device. So, Linux can handle 256 devices all together. Only 256 devices? No, they are major devices. Each major device can handle additional 256 devices of that type. Lets recalculate the number 256x256 = 65535. Well, now nobody can call this a small number. kernels documentation/devices.txt file is supposed to have the list of all major devices. I'll upload that file once I boot into ubuntu (Now I'm on Vista). By the way, the 0-th device is known as null device.

Applications can not access the device by the major number directly. Rather, apps use something called file system entries. I guess I didn't mention it earlier. The beauty of linux is, it can treat all physical devices, virtual devices and real file systems as file systems. The benefit of this is we can use the generic structure for all of them, without knowing what type of device we are using, still it is not that easy as it sounds right now. All driver entry points are located on a directory "/dev". For example, /dev/tty1 is the serial port 1 [COM1] . Applications which want to use any driver uses a system call to get the handle of the device. Once it gets the handle, it can gain access of the devices and can use the device by other system calls.


Driver Installation

Driver Installation is varied by linux distribution. As I have mentioned earlier. Linux uses modules as device drivers. All drivers are installed as modules and are located in directory "/lib/modules/kernel_x.x.xx". A configuration file located on /etc/modules.conf is used by the kernel [and user if you want to override it] to load and unload the modules. Module installing and uninstalling can be done by kernel module utilities like insmod, rmmod [we have used it on previous examples] and modprobe. Installing/inserting a module isn't everything, the module has to be registered as a device entry in the directory "/dev". The utility mknod does this job.

To see what drivers have been installed, we can see the contents of "/proc/module". Which will show the list of all loaded modules/devices.

A little break and back to business

Last week was midterm week. In addition I got fever on the weekend. So couldn't do much things on my research. Now I am back on my mission.

Now I know how a basic Linux driver works, I was wondering how a Microsoft Windows Driver works. Well, I tried to study MS driver stuff before, but it seemed Hebrew to me. Now I could understand most of the things as I know linux stuff better. Thanks to a thesis paper DOWNLOAD called "A Comparison of the Linux and Windows Device Driver Architectures" by Melekam Tsegaye and Richard Foss [Rhodes University, South Africa]. I was looking for something exactly like this. This paper answered too many things I was looking for. If I want to give you the summary, I have to copy and paste the whole document. The document is concise and each and every word is descriptive.

I'll do what I was doing. I'll post later was useful for me.

My supervisor [Dr. Mumit Khan] gave me a couple of links yesterday. The site was down for maintenance. Now it is working, I'm going through those as well.

My next post will be based on another review over linux device drivers.

Tuesday, June 26, 2007

3 more features for a basic module

Just learned few things which are useful.

1. Licensing and Documentation
2. Passing Arguments to a module and
3. Writing a driver on more than one file.

I am still working on it. All are tested though, I am experimenting them on different situations.
I'll be posting sample codes and outputs soon.

Here's a sample module info of the modified hello.c

filename: hello.ko
description: A sample driver
author: Raihan Hasnain
license: GPL
srcversion: 76F9BD32BB1DECDFF563E8E
depends:
vermagic: 2.6.20-16-generic SMP mod_unload 586



Friday, June 22, 2007

3. Simulate a Device Driver

Now I have to simulate a device driver.

The easiest simulation is to insert a test module into kernel (which essentially does nothing) then removing it from the kernel.

We ca use this hello.c source file to make a module

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

int init_module (void) /* Loads a module in the kernel */
{
printk(KERN_INFO "Hello kernel\n");
return 0;
}

void cleanup_module(void) /* Removes module from kernel */
{
printk(KERN_INFO "GoodBye Kernel\n");
}


(Somehow I knew that I need linux-headers linstalled in my linux to compile these sort of codes. )
I tried to compile it for the first time

gizmo@ububtu:~/mod$ gcc -c hello.c
hello.c:1:26: error: linux/module.h: No such file or directory
hello.c: In function ‘init_module’:
hello.c:6: error: ‘KERN_INFO’ undeclared (first use in this function)
hello.c:6: error: (Each undeclared identifier is reported only once
hello.c:6: error: for each function it appears in.)
hello.c:6: error: expected ‘)’ before string constant
hello.c: In function ‘cleanup_module’:
hello.c:12: error: ‘KERN_INFO’ undeclared (first use in this function)
hello.c:12: error: expected ‘)’ before string constant

See the red line. There is an error. I tried to find if there is any module.h is in my include directory.
I always knew that when a header file is included, compiler searches /usr/src/linux-headers-2.x.xx-xx/ directory and attached the header (*.h) file/files.

So I searched the /usr/src/linux-headers-2.6.20-16-generic/include/linux folder (2.6.20-16-generic is my kernel version) and I found module.h. Well I was wrong.

I went to my advisor and he let me know some secrets of GCC which I never knew and still can't find them by Google.

One of them is compiling on verbose mode, by adding -v parameter. Which gives line by line logging when compiling. And another is -save-temps parameter, which saves the intermediate file *.i and some other intermediate files. *.i file is a concatenated file of the header files and the source file (*.c/*.cc/*.cpp).

Let's see what happened to my module code in verbose mode.

gizmo@ububtu:~/mod$ gcc -c hello.c -v
Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v --enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --program-suffix=-4.1 --enable-__cxa_atexit --enable-clocale=gnu --enable-libstdcxx-debug --enable-mpfr --enable-checking=release i486-linux-gnu
Thread model: posix
gcc version 4.1.2 (Ubuntu 4.1.2-0ubuntu4)
/usr/lib/gcc/i486-linux-gnu/4.1.2/cc1 -quiet -v hello.c -quiet -dumpbase hello.c -mtune=generic -auxbase hello -version -fstack-protector -fstack-protector -o /tmp/ccQ7Kn8b.s
ignoring nonexistent directory "/usr/local/include/i486-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/i486-linux-gnu/4.1.2/../../../../i486-linux-gnu/include"
ignoring nonexistent directory "/usr/include/i486-linux-gnu"
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/usr/lib/gcc/i486-linux-gnu/4.1.2/include
/usr/include
End of search list.
GNU C version 4.1.2 (Ubuntu 4.1.2-0ubuntu4) (i486-linux-gnu)
compiled by GNU C version 4.1.2 (Ubuntu 4.1.2-0ubuntu4).
GGC heuristics: --param ggc-min-expand=63 --param ggc-min-heapsize=63380
Compiler executable checksum: c0d954aeefbb96d795ff3f6b3b72ef51
hello.c:1:26: error: linux/module.h: No such file or directory
hello.c: In function ‘init_module’:
hello.c:6: error: ‘KERN_INFO’ undeclared (first use in this function)
hello.c:6: error: (Each undeclared identifier is reported only once
hello.c:6: error: for each function it appears in.)
hello.c:6: error: expected ‘)’ before string constant
hello.c: In function ‘cleanup_module’:
hello.c:12: error: ‘KERN_INFO’ undeclared (first use in this function)
hello.c:12: error: expected ‘)’ before string constant


Check out the red lines. I was wrong! GCC 4.1.2 never looks on /usr/src/linux-headers-2.6.20-16-generic/ directory. Now I need to know a way, which can tell GCC to look up on appropriate folder.

In my university lab where PCs are powered by Fedora Core 5, this module code compiled without any error! I use ubuntu fiestly fawn (7.04) at my home. I thought ubuntu has this problem with gcc. So I chosen a shortcut, which led me to a disaster.

This part is kind of an offtopic!
I consider last week as my disaster week. As I saw ubuntu is not doing good, I considered installing Debian 4.0. I took it from a senior student, well I had to take it twice! Both time my DVD's had faults when burning. Then I tried to install fedora core 6. By the way, my DVD-ROM drive was faulty, when I was in the middle of installing FC6, installation corrupted, and I ended up with a broken GRUB (boot loader). Finally, no boot loader to boot any OS, no DVD drive to install anything else. I had to waste a whole week because of this, then bought a new DVD drive and Fedora Core 7 DVD.

FC7 started a new era for Fedora Cores, as it has a community repository now. Which is now letting FC to be a general purpose OS for all. Why? It has no kernel-header installed, no ant installed, most of the dev packages are vanished and it has a nice looking interface!

Guess what ...


when I tried to compile this code again
gizmo@desktop:~/mod$ gcc -c hello.c
the output is ...
hello.c:2:26: error: linux/module.h: No such file or directory


Meanwhile I posted an important thread on www.ubuntuforums.org

You can visit this thread here http://ubuntuforums.org/showthread.php?t=474991

I decided to get back on ubuntu fiesty. Installed it again, updated it up to date. Installed the things I needed and now I'm back to business!

Moral: For developing purpose, DO use whatever you want to use or you were using. DO NOT change distros, it won't help you at all.

Thanks to
alexOoO for showing me a nice example of Makefile and the_unforgiven for giving me a superb link of "The Kernel Module Programming Guide". I am follwing this guide now, as the book I was following previously was for older kernels.

Now I just made a Makefile with these codes.

obj-m += hello.o

all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Then I tried to compile with 'make' command, and the output is

gizmo@ububtu:~/mod$ make
make -C /lib/modules/2.6.20-16-generic/build M=/home/gizmo/mod modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.20-16-generic'
CC [M] /home/gizmo/mod/hello.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/gizmo/mod/hello.mod.o
LD [M] /home/gizmo/mod/hello.ko
make[1]: Leaving directory `/usr/src/linux-headers-2.6.20-16-generic'

NICE! Let's just ignore the warning messages, I can fix that later. At least the module could be compiled by my distro. Lets see if the module information.

gizmo@ububtu:~/mod$ modinfo hello.ko
filename: hello.ko
srcversion: 4C36855B98BAF2C01D9C1E9
depends:
vermagic: 2.6.20-16-generic SMP mod_unload 586


Let's try to insert the module into kernel.
NOTE: Inserting/Removing needs root/superuser permission.

gizmo@ububtu:~/mod$ sudo insmod ./hello.ko

Compiler doesn't show any error, so the module is inserted.
The code was supposed to print "Hello Kernel" on the log when the module is inserted. Let's check out the log if the message is printed.

gizmo@ububtu:~/mod$ cat /var/log/messages
...
...
Jun 22 14:05:20 ububtu -- MARK --
Jun 22 14:08:54 ububtu kernel: [ 6237.218196] hello: module license 'unspecified' taints kernel.
Jun 22 14:25:21 ububtu -- MARK --
Jun 22 14:32:42 ububtu kernel: [ 7662.119510] Hello kernel

Now let's try to remove the module
gizmo@ububtu:~/mod$ sudo rmmod ./hello.ko

and the log file says ...

gizmo@ububtu:~/mod$ cat /var/log/messages
...
...
Jun 22 14:05:20 ububtu -- MARK --
Jun 22 14:08:54 ububtu kernel: [ 6237.218196] hello: module license 'unspecified' taints kernel.
Jun 22 14:25:21 ububtu -- MARK --
Jun 22 14:32:42 ububtu kernel: [ 7662.119510] Hello kernel
Jun 22 14:34:24 ububtu kernel: [ 7764.009453] GoodBye Kernel

Done!

It was the simplest module than can be inserted. Next time I'll try to understand the module structure in more depth and how to work on module licenses.

Now I have to do compiler assignment PA2, I have wasted too much time looking for distros. Wish me luck.

2. Structure of Kernel Module

Kernel modules can be developed for two types of devices.

Block Devices

As the name says, Kernel accesses block devices by blocks (usually 1kb). It is generally used for hosting file systems.

Character Devices
Kernel accesses char devices like a file. Parallel port, Serial ports are char devices.

Kernel modules can be loaded or unloaded into kernel dynamically in runtime. So kernel module has a generic structure*.

struct module
{
unsigned long size_of_struct;
struct module *next;
const char *name;
unsigned long size;
long usecount;
unsigned long flags;
unsigned int nsyms;
unsigned int ndeps;
struct module_symbol *syms;
struct module_ref *deps;
struct module_ref *refs;
int (*init)(void);
void (*cleanup)(void);
const struct exception_table_entry *ex_table_start;
const struct exception_table_entry *ex_table_end;
#ifdef __alpha__
unsigned long gp;
#endif
};


Return Values

On success, zero is returned. On error, -1 is returned
and errno is set appropriately.


I still don't know how this structure works. I only know about two methods (marked blue). First one initializes a module to be inserted, second one does the job of removing.

I'll study abouth the other methods eventually.

*courtesy: module structure, http://www.freeos.com/articles/2677/

1. What is Device Driver?

In short, device driver is a software program which talks to the computer and controls the device. If you really want a bookish definition, you better check this site CLICK HERE. I'd rather post a simple definition which makes sense.

NOTE: From next time, whenever you see me mentioning 'drivers' or 'dd', consider it as device drivers.

Before getting into device drivers, I should mention that OS has a vital role here. One of the most important features of OS is resource management, which includes I/O operation with devices. Devices are connected with I/O ports. Interfacing does the physical connection, OS can send the requests to the device. Here comes the role of drivers. Driver is the OS of the device itself, it can talk to the computers OS and thus computers OS recognizes the device. Later drivers can control the device, which is essentially the I/O instructions by the computers OS.


Lets narrow down a bit more. OS is a huge entity to consider. By OS here we mean the kernel of an OS. Kernel is the core of the OS. Drivers has to either be inside the kernel to recognize devices or has to be somewhere near the kernel so that it can easily communicate with the kernel.

Check out the diagram*.



So here comes the kernel. I just mentioned that the driver can be inside the kernel, that is known as monolithic kernel, which actually has to come with the kernel package. There is another way of implementing drivers, that is by kernel modules.

My concern is now with kernel modules only.

Kernel modules are pieces of codes. Which can be loaded and unloaded upon demand. Letting us not worry about rebuilding the kernel again and again.

On my next post, I'll show the structure of the kernel module.


*Image courtesy: http://www.linuxjournal.com/article/2476