Kernel Modules and Device Drivers, Demystified
Kernel Modules and Device Drivers, Demystified
M.A. KHURESHI
Head, CSE Department, AGPIT, Solapur, Haq123.275@gmail.com
S. M. KUMBAR
Assistant Prof. CSE Department, SVERI, Pandharpur,sharan64.kumbar@gmail.com
9|P a g e www.ijrpet.org
NOVATEUR PUBLICATIONS
INTERNATIONAL JOURNAL OF RESEARCH PUBLICATIONS IN ENGINEERING AND TECHNOLOGY [IJRPET]
NATIONAL CONFERENCE ON INNOVATIVE TRENDS IN ENGINEERING & TECHNOLOGY-2017
15TH & 16TH MARCH 2017
CONFERENCE PROCEEDINGS ISSN NO - 2454-7875
______________________________________________________________________________________________________________________________________________________________________________________
Now let us see kernel module in contrast with system calls If any other module gets inserted which uses this
and kernel processes. module, the earlier module’s uses count will be
Kernel modules are not supposed to run forever incremented.
like kernel processes. rmmod decrements the uses count of the given
These are not called by user programs like system module and removes it if the uses count reaches 0.
calls. lsmod displays all modules currently inserted in the
Their executable / binary code need not exist all kernel. It is a module variant command for ls.
the time. For example mod.c can be the source code for
Kernel module source code has a definite entry module. Compiling without linking will produce
and exit point but does not have a main () mod.ko. It can be inserted in kernel as follows.
function. # insmod mod.ko
If binary can be linked with kernel, it will be part Whether the insertion succeeded or not can be
of resident kernel. checked by
If the binary is not linked with kernel and is # lsmod | grep mod.ko
loaded when needed, it will not be part of resident This will also list us the size of the module inserted
kernel. and its uses count.
In this view of load or link approach – module can D) Makefile for compiling Modules
be part of static or dynamic kernel. Modules may have internal dependencies. Instead of
Module linked statically with kernel will require manually keeping track of such dependencies, it is
recompilation and reboot of kernel. wiser to use a makefile for compiling modules.
Load and remove of module can be done during Following file namely Makefile can be used. It is generic in
run of the kernel. syntax and uses shell variables. So the same can be used
for different modules also, provided the module name in
B) MODULE, APPLICATION PROGRAM AND SYSTEM Makefile is changed.
CALLS With mod.c as module name, mod.ko can be prepared by
# cat fname this file by make command.
(Shell Level) KERNEL_BUILD := /lib/modules/`uname –r’/build
CC := gcc
PROG := app
read ( fd, buff , count )
obj-m := mod.o
(System Call Level)
modules:
@$(MAKE) -C $(KERNEL_BUILD) M=$(PWD) $@
sys_read ( ) $(PROG): $(PROG).c
(Indexes into dev driver
module)
@$(CC) -o $(PROG) $(PROG).c
Following operations can be thus made.
# make ( prepares mod.ko )
my_read ( ) # insmod mod.ko ( inserts mod.ko )
(Dev Driver’s function )
# lsmod | grep mo ( verifies insertion )
Let us say an application program app.c uses this module.
copy_to_user ( ) Its binary can be prepared by
(copy from kernel
space to user space)
# make app
During the make, inside Makefile,
Figure No 1. Hierarchy of calls happening from user `uname –r ‘ will get replaced by the present Linux
application to device driver version name path.
PROG will get replaced by app
Figure no 1 illustrates the programming levels viz. PWD will get replaced by present working
application level, shell level, system call and device driver directory.
level.
GENERIC KERNEL MODULE
C) UTILITIES FOR WORKING WITH MODULES Let us see what might be the minimal source code for a
Having logged in as super - user following utilities are kernel module that may get repeated for most of the
available for working with modules. modules. We may have to add up additional functionality
Insmod allows us to insert a module dynamically into this as per the task for which the module is designed.
into kernel when needed. It will remain in system A) OBSERVATIONS FOR A GENERIC KERNEL MODULE
unless we remove. insmod internally calls module_init ( ) function
and rmmod internally calls module_exit ( )
function. So the module must map his
13 | P a g e www.ijrpet.org
NOVATEUR PUBLICATIONS
INTERNATIONAL JOURNAL OF RESEARCH PUBLICATIONS IN ENGINEERING AND TECHNOLOGY [IJRPET]
NATIONAL CONFERENCE ON INNOVATIVE TRENDS IN ENGINEERING & TECHNOLOGY-2017
15TH & 16TH MARCH 2017
CONFERENCE PROCEEDINGS ISSN NO - 2454-7875
______________________________________________________________________________________________________________________________________________________________________________________
initialization and clean up functions to these release : my_release, owner
functions, respectively. :THIS_MODULE};
In order to be able to give our chosen names to Now depending upon the functionality the device needs to
init and clean up function the mapping can be provide, the device driver writer needs to define his
done as follows. functions and assign these pointers to his functions. Such
module_init ( mod_init ); file operations structure then needs to be passed to the
module_exit ( mod_clean ); following function.
Module writer is responsible to define mod_init( ) struct file_operations my_fops;
and mod_clean( ). Kernel will make sure to call reg_chrdev ( MAJOR_NO , " mydevice " , &my_fops ) ;
these during module insertion and clean up. This registers the driver’s functions with the kernel; thus
The modules cannot make any user level function the driver is registered.
calls. As user calls the functions kernel uses this structure to
It cannot make system calls or library function locate driver’s functions that you define.
calls. For example calling printf ( ), read ( ), fread Here MAJOR_NO is the major number for the device file
() from a module will not be permitted. namely mydevice. This file represents our driver at kernel
Module init and exit functions must have their file system. This is created as by
execution time pretty small. # mknod /dev/mydevice c 250 0
A module cannot output on standard output but c here indicates it is a character device and 250 is its major
its output can been seen by # dmesg. This will number and 0 is minor number.
show all messages logged in by modules till now. Kernel thus calls our driver’s functions. At that instant it
# dmesg –c will clear the log. gives us file *, inode * and other information as parameters
B) ALGORITHM TO WRITE A MODULE depending upon the file user wants to work upon.
Following algorithm helps one write a generic module. struct file *
1) Include the files init.h and module.h from linux folder struct inode *
2) Announce the license as Dual BSD / GPL Using these pointers to structures the driver functions can
3) Write definition for functions which will do module dig into file relevant details like major number, minor
initialization and module clean up – say F1 and F2, number, size of file, owner, access permissions etc. There
respectively are nested structures inside structures giving us more
4) By using module_init () and module_exit() function information.
calls, associate these names F1 and F2 for init and Driver can assign his own buffers for storing transient data
cleanup work. during transfer. Ideally this data should be allocated using
kalloc ( ) and care should be taken that its use is
DEVICE DRIVER AS A KERNEL MODULE synchronized between multiple instances of driver calls.
A device driver is a kernel module that can be statically That is driver routines should be re entrant.
linked with or dynamically inserted in kernel. Kernel
reaches out to such driver by treating it as a file in A GENERIC DEVICE DRIVER
directory /dev. For example /tty represents keyboard – Let us consider a generic device driver, that is the driver
monitor combination. The major number and minor functionally that must be common between all the drivers.
number fields of the inode of such file map into the specific This code will be architecture independent and should be
device driver. found in most of the drivers.
The major number decides a class of devices and hence Let us say we want to provide my open, myriad, mis write ,
their driver. And minor number differentiates between the my close and my IOCtl functions inside device driver
various devices that the driver can handle. module. So we will map these using fops structure.
When user calls system calls like open (), read (), close ( ), Also we decide to make a device file entry by name “my
ioctl () kernel refers to the file’s inode and internally uses device” under / dev directory by using mknod.
its major and minor numbers. The kbuf array and DriverData represents driver level
Kernel uses a data structure called as file operations data data.
structure. This data structure has fields as pointers to User’s read system call will receive data from kbuf during
functions as shown below. my_read ( ) routine of driver. This is managed by
copy_to_user ( ) kernel function. Also from user’s data
struct file_operations { given in write system call kbuf will get filled in during
llseek : my_llseek, my_write ( ) routine of driver. This is managed by
read : my_read, copy_from_user ( ) kernel function.
write : my_write, This will complete the interface from user application to
ioctl : my_ioctl, kernel to the device driver. Now depending upon different
open : my_open, devices and their functionality the other section of the
driver that is interacting with actual device will change.
14 | P a g e www.ijrpet.org
NOVATEUR PUBLICATIONS
INTERNATIONAL JOURNAL OF RESEARCH PUBLICATIONS IN ENGINEERING AND TECHNOLOGY [IJRPET]
NATIONAL CONFERENCE ON INNOVATIVE TRENDS IN ENGINEERING & TECHNOLOGY-2017
15TH & 16TH MARCH 2017
CONFERENCE PROCEEDINGS ISSN NO - 2454-7875
______________________________________________________________________________________________________________________________________________________________________________________
This other section will demand for studying the actual It calls ioctl and passes over the string "I came
behavior and architecture of the specific device. Before we from application" to the driver. In a specific driver
discuss such device specific changes, let us see the sample other information needed for controlling device
source code for such generic device driver. can be passed over here.
It calls read ( ) and accepts the string given by the
A) ALGORITHM TO WRITE A GENERIC DEVICE DRIVER driver. This can be the actual data that has been
1) Define MAJOR_NO as 250 read from the device by the driver.
2) Include the files module’s, init.h, fs.h and uaccess.h It calls write and passes over the string “Take this
from linux folder from application“, to the driver. This can then be
3) consider major as integer and kbuf as char array written to the data space of the device at hand.
4) DriverData structure holds val as long and str as
char array – as members. C) OBSERVATIONS FOR SUCH GENERIC DEVICE DRIVER
5) struct inode * and struct file * parameters are This sample device driver implements read, write, ioctl,
available to my_open function. Define such function open calls for the device represented by the file name
to find minor number using following call mydevice and major number of 250.
minor = MINOR(filp->f_dentry->d_inode->i_rdev) When an application calls
6) In the similar manner define my_close function. read ( ) driver’s my_read ( ) gets called. Being a generic
7) In the same manner define my_read function and iit driver it simply copies it’s kbuf’s data into the application
will call the function copy_to_user ( buf, kbuf, count to cater his read request.
) write ( ) driver’s my_write ( ) gets called. Being a generic
8) Define my_write function and it will call driver it simply retrieves data from the application and
copy_to_user ( buf, kbuf, count ) copies it into the driver’s kbuf.
9) Functions my_read and my_write take following
parameters (struct file * filp, char * buf, size_t D) HOW TO TACKLE SPECIFIC DEVICES
count, loff_t * offset) Herein we have not tackled where does kbuf gets data
10) Function for control operations take following from before giving to application, and also what does
parameters ( struct inode * inode , struct file * fp , driver do with the kbuf data after taking it from the user
unsigned int cmd , unsigned long arg ) application.
11) Following will find driver data for control data = ( Answers to these questions depend upon what device
struct DriverData * ) arg ; after this data -> val driver we are designing and what are the ways to interact
integer and data -> str string is available for use. with the device.
12) Now define file operations structure where we
assign read to my_read, write to my_write, open to CONCLUSION:
my open, release to my close, IOCtl to my control Device drivers have a generic section that is similar in
and owner to THIS_MODULE most of the drivers. As per its interaction with devices the
other section will change
B) ALGORITHM FOR PROGRAM USING THIS DRIVER It works as a lower layer to kernel system calls.
Following algorithm may use such driver code. It is considered as a sub layer below kernel file system.
1) Ubuff is character array Keeping it static and loadable during testing phase is
2) User Data is structure with val as integer and str advisable. It can be linked with kernel once tested
as string – say we take data as variable of this completely.Future work in this can be as follows.
structure Obeying the same skeleton various other device drivers
3) We open the file /dev/mydevice in read write can be tackled. These will have similar approach except
mode few device specific changes. In order to achieve this,
4) We proceed to assign value say 100 to data. Val following areas needs to be focused namely PCI
5) We assign some string say “I Came From Architecture, Port IO Provision, Memory IO Provision.
Application" to data.str Modules can be developed on Linux and cross compiled for
6) Now we call ioctl ( fd, 0, &data ) working on other architectures like ARM.
7) Then we call read ( fd, ubuff, 15 )
8) This should give us value for ubuff REFERENCES
9) Now we may change ubuff to say “Take this from 1) Jonathan Corbet, Alessandro Rubini, and Greg Kroah-
application “ Hartman, Linux Device Drivers, Third Edition
10) And we may then call write ( fd , ubuff , strlen ( 2) Maurrice J. Bach, Design of UNIX
ubuff ) ); 3) W. R. Stevens, UNIX Network Programming
11) This should copy it to kernel and device through
our driver functions. We can then close file.
15 | P a g e www.ijrpet.org