CSCI 3753: Operating Systems Programming Assignment Two solution


Original Work


5/5 - (3 votes)

Goal: Using Linux Kernel Module Programming to Code a Character Device Driver
This assignment is all about getting familiar with Linux Modules and Linux Device Drivers. At first you
will learn how to code a Linux kernel module (LKM), how to install the module and how to run the
module. Then you will write a module that will enable you to install a Linux device driver. This
assignment write-up is structured as follows:
1. What is a Linux kernel module?
2. How Linux kernel module works.
3. How to code a Linux kernel module.
4. What are Linux device drivers?
5. How do device drivers work?
6. How to code a device driver using Linux kernel module programming.
You may use the VM from the first programming assignment, or any Linux installation that runs on your
laptop. It will be useful to obtain the current version of the Linux kernel running on your machine if you
choose the latter option. It is recommended that you use the VM. To obtain the current version of Linux
kernel, follow the steps below:
1. Go to a shell terminal and type uname –r
2. You will get an output like x.y.z-ab-something else
a. X is the major number
b. Y is the minor number. If even that means the version is stable. If it’s odd that means it’s
still in experimental version
c. Z is the revision number.
3. To check the source code, you can go to this folder /usr/src/$(uname -r)
Loadable Kernel Modules (LKM)
LKMs are object files that are used to extend the running kernel’s functionalities of the current operating
system. This is basically a piece of binary code that can be inserted and installed in the kernel on the fly.
As you know if you want to make a change in the current OS, after you make changes, you have to reboot
your computer, like what you did in the first assignment when adding a system call. After you reboot, the
changes that you made are installed in the kernel.
Now as you can see, this approach is a bit painstaking. To make this approach more dynamic, LKMs are
introduced where you can add extensions to the kernel on the fly without the need to reboot. This comes
very handy when you are trying to work with some device and just be done with it very fast and then
uninstall the device without needing to reboot, thus saving time and energy and also space, because you
can uninstall the module after your work is done.
How to work with modules
1. Get the file helloModule.c and store it in a folder named “module”
2. Open the file
3. The init.h is required for the initialization of the module and the module.h is required to let the
kernel know that this is an LKM.
4. I have coded two simple functions in the module code namely hello_init() and hello_exit(). I want
hello_init to execute when the module starts to work and hello_exit when the module gets
uninstalled. To make sure this happens, at the end of the code I have added these two lines.
a. module_init (hello_init)
b. module_exit (hello_exit)
What this means is that when the module is getting started, the kernel follows the function
pointed to by module_init() and executes that function. Similarly, when the module is uninstalled,
the kernel follows the function pointed to by module_exit(), in this case, the function hello_exit().
5. As you are coding in the kernel, you cannot use the printf( ) function. Instead you have to use the
function printk. The KERN_ALERT is used to let the kernel know the importance of the
message you are trying to print with the printk function. If it’s KERN_ALERT then the message
will be written in the log file in the location /var/log/syslog file. The contents of the log file can
be seen from the terminal using the command dmesg or sudo tail –f /var/log/syslog. There are
other kernel message importance levels too (KERN_INFO, KERN_EMERG etc).
6. To check what is happening, you can type dmesg or sudo tail –f /var/log/syslog in another
terminal and check what is happening when you are trying to install the module.
7. Now you have to write a makefile. Create a file named Makefile and type the following line in it
a. obj-m:=helloModule.o
b. here m means module. You are telling the compiler to create a module object named
8. Now to compile the module, type in the terminal “make –C /lib/modules/$(uname -r)/build
M=$PWD modules”
9. Now in the command prompt type the following: ls
10. You will see there is a file named helloModule.ko. This is the kernel module (.ko) object you
will be using to insert in the basic kernel image.
11. Now in the terminal type “sudo insmod helloModule.ko”.
12. Now if you type lsmod you will see your module is now inserted in the kernel.
13. Now type “dmesg” or “sudo tail /var/log/syslog” and you will see expected output is printed,
because the hello_init() function was executed when the module was installed.
14. Now to remove the kernel type “sudo rmmod helloModule” and then the module will be
removed as it can be ascertained by typing the lsmod command. Type dmesg to see if the
expected output is printed .
Device Driver
Remember that in Linux, device I/O is modeled using files. Reading from and writing to a file will
invoke the associated device driver to do the actual reading and writing. All device drivers have two
numbers associated with it, namely major and minor numbers. The major number is a number that is
unique to every device driver and the minor number is to differentiate all the devices belonging to that
device driver. So for example, for a hard disk, there are many partitions. To differentiate the hard disk
device driver, major number is used whereas to differentiate the different partitions, minor number is
Kernel major number
As it can be seen from the above diagram, there are three drivers namely Driver1, Driver2 and Driver 3.
The numbers 1, 2 and 3 are the major numbers. These major numbers are associated with device drivers
in the kernel to differentiate one device driver from another. To code a Device Driver, the major number
has to be unique.
Also, Device Driver 1 works with Device 11, Device 22, Device 33. The numbers 11, 22 and 33
associated with the devices are called the minor numbers that are used to differentiate the devices
associated with one particular device driver.
For example, if you type ls –l /dev | grep sda, this will give you all the device files (or the current
partitions) associated with the hard disk device drivers. You will see the partitions are listed with their
corresponding major and minor numbers.
There are two kinds of device drivers namely Character Device Driver and Block Device Driver.
Driver 1
Driver 2
Driver 3
Device 11
Device 22
Device 33
Character Device Driver
1. Reads from the device character by character
2. Writes to the device character by character
3. Operates blocking mode, which means when a user writes info to the device, he/she must wait
until the device completes execution. They are most common of all device drivers.
Block Device Driver
1. Reads large chunks of information.
2. Very CPU intensive, takes some time to finish the execution.
3. They are asynchronous, a user does not need to wait for the reading and writing to be completed.
Creating Device File for a Device Driver
To work with device drivers, you have to work with the corresponding device files. These files are stored
in the /dev folder. If you type in the terminal “ls /dev” you can see all the device files in the machine. You
have to create a file in this folder to work with the character device driver you will be coding. The
command to do that is “sudo mknod -m