Linux Kernel Module Programming : a simple device driver and a user-level program accessing it.
Creation of a simple kernel module; that will create a new device on the /proc file-system and just the basic operations of read/write are to be introduced.
In the first place we will inspect the code for the kernel module that will be called mine.c
In the previews code, first of all we indicating the function that will run when the module will be loaded into the Linux Kernel and the function that have to run when the module(device driver) is unloaded from it. We can specify those functions as arguments within’ module_init and module_exit function’s arguments.
Notice that instead of using pointers in the kernel level we do us in this example the functions copy_from_user and copy_to_user to transfer data between kernel space and user-level space.
The general idea of this example is that , in the module will be hold a character array that consists very much actually of the alphabet. So 26 letters an array 0–25 indexes. We are also defining in the file_operations structure fops that we are implementing mread, and mwrite functions for reading writing the device. Device is created in /proc after the invocation of proc_create and is actually implementing as we can see in the last argument the &fops file_operations.
We can see that after our module is inserted into the Kernel, as we will explain later we can find a file “mydev” within’ /proc.
In our design , when a system call tries to read, or write in the /proc/mydev file, will be actually using our mread and mwrite functions that we implemented into the Kernel level. We will be reading from the alpha array that is initialized to hold the alphabet. Here we will be having a look into the Makefile that will be used to compile our code so far.
When compiling there are a bunch of generated files and the question arising is how will we load this module in the kernel. One of the files called mine.ko(kernel object) is to be used. Switching to root and typing the following command : ‘sudo insmod mine.ko ‘ will load the module into the kernel and produce the output as seen in the next picture at 20121.815765- 92. “ Module loaded into Kernel … Buffer initialized to : abc…z “. Thas was the code written in the module_init0 function, and it was what it was executed while loading with success the module in the kernel.
To see the output in the picture above a new terminal is needed executing the following command preferred while been in superuser mode, ‘dmesg — w’.
In the second step, a user level C program will be created that will access the newly created device( of course to access it , we need to have the module loaded into the kernel.)
Compiling this program will produce the executable needed to access our device. As we can see, first we try to open our device , then reading 12 characters from it, next we are trying to write “hello” to it and finally to read ten characters. If the module is not present in the kernel when we run this program we will have an abnormal exit with “Error opening file”.
Running the program , we can inspect in the figure below, the two print outs when reading characters from the device(when we wrote “hello” we didn’t print anything) , and we can inspect that when reading the second time the first five letters are changed. In their positions are the letters of the world “hello” as written by the function write(fd, buffer, 5) .
To unload the module from the kernel command “rmmod mine.ko” is need.
Notice that rmmod will fail if there are processes using the module at the moment.
You can find more kernel programming examples here in my Github profile.