Kernel Modules
Kernel Module
• Pieces of code that can be loaded and unloaded into the kernel upon demand.
• Compiled as an independent program• With appropriate flags to indicate that it is kernel
code.• Can be linked into the kernel by installation.
– Static/Dynamic loading– “/proc/modules” or “lsmod”
• Enhance the functionality of the kernel.• Example:
– Device Drivers
Functions in Kernel Module
• int init_module(void) – Invoked when the module is inserted to kernel– Return 0 if success.
• void cleanup_module(void) – Invoked when the module is removed from kernel
• printk() – /usr/src/linux-2.6.5-1.358/include/linux/kernel.h
#include <linux/kernel.h>#include <linux/module.h>
int init_module(void){
printk(KERN_ALERT "Hello world.\n“);
return 0;}
void cleanup_module(void){
printk(KERN_ALERT "Goodbye world.\n");}
MODULE_LICENSE("GPL"); //GNU Public License v2 or later
Makefile
ifneq ($(KERNELRELEASE),)
obj-m += hello.o
else
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
endif
• insmod hello.ko• lsmod or “/proc/modules”• tail -f /var/log/messages• rmmod hello
Modules vs. Programs
• Programs– main()
– performs a single task from beginning to end
– Run in user mode
– Can call the libc functions
• Modules– init_module & cleanup_module
– registers itself in order to serve future requests
– Run in kernel mode• Part of kernel program
– Only can call the ones exported by the kernel.
• include/linux
• include/asm
• Export all non-static symbols
Device Drivers
• Character devices– one that can be accessed as a stream of
bytes – Keyboard driver
• Block devices– One that can be accessed as multiples of a
block, usually 1KB per block– Disk driver
Device Drivers
• To communicate with hardware– Each piece of hardware is represented by a file located in /dev– An application do some operations on that file– The kernel finds corresponding device driver for that file.– Each operation on that file will trigger a function in the device dri
ver for that hardware– The file in /dev is not regular file
• To find the device driver for that file– ls -l /dev/b*– Major number
• Match with driver– Minor number
• used by the driver to distinguish between the various hardware it controls
• ls -l /dev/fd0u*
Device Drivers
• Defines functions on the file operation– Read, write, open, close, etc
• Register the device to kernel
• creates a file in “/dev” using “mknod”
Device Drivers
• Function mapping
struct file_operations fops = {
.read = device_read,
.write = device_write,
.open = device_open,
.release = device_release
};
• vi /usr/src/linux-2.6.5-1.358/include/linux/fs.h• int register_chrdev(unsigned int major, const char *name, struct file_
operations *fops); • int unregister_chrdev(unsigned int major, const char *name);
#include <linux/kernel.h>#include <linux/module.h>#include <linux/fs.h>#include <asm/uaccess.h>
#define DEVICE_NAME "chardev"#define BUF_LEN 80
static int Major;static char msg[BUF_LEN];static char *msg_Ptr;
static int device_open(struct inode *inode, struct file *file)
{static int counter = 0;sprintf(msg, "This device is opened %d times!\n", counter++);msg_Ptr = msg;try_module_get(THIS_MODULE);
return 0;}
static int device_release(struct inode *inode, struct file *file)
{module_put(THIS_MODULE);return 0;
}
• We cannot remove the device driver while device file is opened by a process.
• There's a counter which keeps track of how many processes are using your module – the 3rd column in lsmod
• try_module_get(THIS_MODULE);– Increment the use count
• module_put(THIS_MODULE);– Decrement the use count
static ssize_t device_read(struct file *filp,char *buffer, size_t length,
loff_t * offset){
int bytes_read = 0;
if (*msg_Ptr == 0)return 0;
while (length && *msg_Ptr) {put_user(*(msg_Ptr++), buffer++);
length--;bytes_read++;
}
return bytes_read;}
• put_user(char src, char* dst);– src is in kernel code segment– dst is in user code segment
• get_user(char dst, char* src);– src is in user code segment– dst is in kernel code segment
• A pointer into userspace should never be simply dereferenced
• #include <asm/uaccess.h>
• buffer is in user data segment• length: length of the buffer
static ssize_t
device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
{
printk("<1>This operation isn't supported.\n");
return -EINVAL;
}
static struct file_operations fops = {.read = device_read,.write = device_write,.open = device_open,.release = device_release
};
int init_module(void){
Major = register_chrdev(0, DEVICE_NAME, &fops);
if (Major < 0) {printk("Failed to register char device.\n");return Major;
}
printk(KERN_ALERT "chardev is assigned to major number %d.\n", Major);
return 0;}
void cleanup_module(void){
int ret = unregister_chrdev(Major, DEVICE_NAME);if (ret < 0)
printk("Error in unregister_chrdev: %d\n", ret);}
mknod
• Create a file in /dev
• And match the file with a device driver• mknod /dev/hello c Major 0
– This Major number is from the output of /var/log/messages
References
• Linux Device Drivers, 2nd Edition – http://www.xml.com/ldd/chapter/book/index.html
• The Linux Kernel Module Programming Guide – http://tldp.org/LDP/lkmpg/2.6/html/