<<

Topic 10:

Tongping Liu

University of Massachusetts Amherst 1 Administration

• Today it is the deadline of Project3 • Homework5 is posted, due on 05/03 • Bonus points: ECE570 – 3 points, ECE670-5 points – Design exam questions – &threads, , synchronization, IPC, , device driver/virtualization – Due: 05/01 • Survey project (ECE570/ECE670): 05/12

University of Massachusetts Amherst 2 Objectives

• Understanding concepts of device driver, e.g., device number, • Understand the difference of kernel modules and device drivers • Learn how to implement a simple kernel module • Learn how to implement a simple device driver

University of Massachusetts Amherst 3 Outline

• Basic concepts • Kernel module • Writing device driver

University of Massachusetts Amherst 4 Device Driver

• A special kind of program that operates or controls a particular type of device that is attached to a computer

University of Massachusetts Amherst 5 Device Driver

• A special kind of that operates or controls a particular type of device that is attached to a computer – Needs to execute privileged instructions – Must be integrated into the OS kernel, with a specific format – Interfaces both to kernel and to hardware

University of Massachusetts Amherst 6 Whole System Stack

Note: This picture is excerpted from Write a Hardware Device Driver, Andrew O’Shauqhnessy, world

University of Massachusetts Amherst 7 Another View from OS

University of Massachusetts Amherst 8 Type of Devices

• Character device – Read or write one byte at a time as a stream of sequential data – Examples: serial ports, parallel ports, sound cards, keyboard

• Block device – Randomly access fixed-sized chunks of data (block) – Examples: hard disks, USB cameras

University of Massachusetts Amherst 9 Linux Device Driver

• Manage data flow between programs and device • Typically a self-contained kernel module – Add and remove dynamically • Device is a special file in /dev that user can access, e.g. /dev/lp0 • Can be only programed with C/

University of Massachusetts Amherst 10 Device Files

• Unix-like systems handle device files with separate subdirectory of /dev for each type of device: disk, block etc.

• Device files are created with mknod: mknod filename type major minor - filename is the device file to be created. - type is c for a character device or b for a block device. - major and minor are the major and minor device numbers.

University of Massachusetts Amherst 11 Device Numbers

• Major device number – Identify the driver that the file is associated with.

• Minor device number – Identify which particular device in a given type. – Called as unit number or instance of the device.

• Both values are stored in the file’s structure.

University of Massachusetts Amherst 12 Device Jump Table

• Each driver supports some or all of the following functions:

probe attach open close read reset stop select strategy dump psize write

• Addresses of these functions are stored in a structure called a jump table, which are indexed by major number

University of Massachusetts Amherst 13 Device Jump Table

• Two tables exists - One for character device - One for block devices.

• Upon operations on a device file – Kernel catches the reference, looks up the appropriate function name in the jump table, and transfers control to it.

• For unusual operation (ejecting ) – () to pass a message directly from into the driver

University of Massachusetts Amherst 14 Character Device Driver

• No buffering is required (only a byte) • Seeking is not allowed • Easy to program, since there is only one position and cannot move back and forth • read() and write() calls do not return until the operation is complete • The kernel doesn’t have to provide an entire subsystem to the character device, since it is less complex

University of Massachusetts Amherst 15 Block Device Driver

• Accessed through a cache so buffering is required. • Seeking is possible, which can move back and forth between any location • Kernel provides an entire subsystem, since it is too complex • Reads and write done by buffer cache mechanism by bread(), bwrite(). These request may be asynchronous.

University of Massachusetts Amherst 16 Outline

• Basic concepts • Kernel module • Writing device driver

University of Massachusetts Amherst 17 Device Driver

Device driver typically exist as kernel modules

Note: This picture is excerpted from Write a Linux Hardware Device Driver, Andrew O’Shauqhnessy, Unix world

University of Massachusetts Amherst 18 Kernel Modules

• Definition: modules are pieces of code that can be loaded and unloaded into the kernel upon demand. – They extend the functionality of the kernel without the need to rebuild/reboot the system. – Without modules, we would have to build monolithic kernels and add new functionality directly into the kernel image. • Advantages: – We do not need to build the entire kernel, saving time – Help us to save memory, due to load on demand

University of Massachusetts Amherst 19 Kernel Modules vs. Device Drivers

• Most modules are device drivers – But some are not, such as IPv6 support or some file systems • Device drivers: drive the hardware – They can be built as kernel modules so that it can be dynamically loaded later. – They can also be built statically into the kernel file on disk.

University of Massachusetts Amherst 20 Device Drivers

• Device drivers are not always kernel modules: – A driver necessary to help the system bootup. – In embedded systems, if you know exactly which drivers will always be needed and that this will never change, then you could statically build it into the kernel – Provide additional security and stability at the expense of flexibility by disabling kernel modules

Device drivers can exist without driving a hardware

University of Massachusetts Amherst 21 Module Interfaces

• lsmod: what modules are already loaded into the kernel by reading the file /proc/modules.

[root@localhost~ ]#lsmod

University of Massachusetts Amherst 22 Module Interfaces

• modprobe: load the designated specific module, or a group of interdependent module . [root@localhost~ ]#modprobe [-lcfr] modules_name

University of Massachusetts Amherst 23 Module Interfaces

• modinfo: show the information of a module.

[root@localhost~ ]#modinfo module_name

University of Massachusetts Amherst 24 Module Interfaces

• insmod: Load the modules that aren’t in /lib/modules/***/kernel

[root@localhost~ ]#insmod module_name.ko

• rmmod: remove modules

[root@localhost~ ]#rmmod module_name

NCHU System & Network Lab University of Massachusetts Amherst 25 Hello, World: The Simplest Module

/* * hello.c − The simplest kernel module. */ #include /* Needed by all modules */ #include /* Needed for KERN_INFO */ int init_module(void) { printk("Hello world!\n"); return 0; } void cleanup_module(void) { printk("Goodbye world!\n"); } MODULE_LICENSE(“GPL")

University of Massachusetts Amherst 26 Hello, World: The Simplest Module

/* * hello.c − The simplest kernel module. */ #include /* Needed by all modules */ #include /* Needed for KERN_INFO */ int init_module(void) { printk("Hello world!\n"); return 0; } void cleanup_module(void) { printk("Goodbye world!\n"); } MODULE_LICENSE(“GPL")

University of Massachusetts Amherst 27 Basics of Kernel Module

• init_module() – Start/initialization function that is called when the module is insmoded into the kernel – Registers a handler for something with the kernel, or replaces one of the kernel functions with its own code • cleanup_module() – Called just before it is rmmoded – Undo whatever init_module() did

• MODULE_LISCENSE: avoids warning

University of Massachusetts Amherst 28 Outline

• Basic concepts • Kernel module • Writing device driver

https://www.linuxjournal.com/article/2476

https://www.apriorit.com/dev-blog/195-simple-driver-for-linux-os

https://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN121

University of Massachusetts Amherst 29 Device Driver Interface

Device driver typically exist as kernel modules

Note: This picture is excerpted from Write a Linux Hardware Device Driver, Andrew O’Shauqhnessy, Unix world

University of Massachusetts Amherst 30 Implementation Steps

1. Understand the device characteristic and supported commands. 2. Map device specific operations to unix file operations 3. Select the device name () 4. Select a major number and minor number for VFS interface: mapping to right device sub-routines 5. Implement file interface subroutines 6. Compile the device driver 7. Install the device driver module with (LKM) or rebuild (compile) the kernel

University of Massachusetts Amherst 31 Common Operations

• Compile -Wall -DMODULE -D__KERNEL__ -DLINUX –DDEBUG -I /usr/include/linux/version.h -I/lib/modules/`uname -r`/build/include • Install the module %insmod module.o • List the module %lsmod • If you let the system pick Major number, you can find the major number (for special creation) by % more /proc/devices • Make a special file % mknod /dev/device_name c major minor

University of Massachusetts Amherst 32 Implementation Steps

1. Understand the device characteristic and supported commands. 2. Map device specific operations to unix file operations 3. Select the device name (user interface) 4. Select a major number and minor number for VFS interface: mapping to right device sub-routines 5. Implement file interface subroutines 6. Compile the device driver 7. Install the device driver module with loadable kernel module (LKM) or rebuild (compile) the kernel

University of Massachusetts Amherst 33 Principal Interfaces

University of Massachusetts Amherst 34 File Operation Structure struct file_operations • file_operations Fops = { NULL, /* seek */ structure is defined in xxx_read, linux/fs.h xxx_write, NULL, /* readdir */ • Holds pointers to NULL, /* select */ functions defined by NULL, /* ioctl */ NULL, /* mmap */ the driver that xxx_open, perform various NULL, /* flush */ xxx_release operations on the }; device.

University of Massachusetts Amherst 35 File Operation Structure

• Some operations are not implemented by a driver. – A driver that handles a won't need to read from a directory structure. – Then the corresponding entries will be set to NULL • Gcc extension to support the initialization

University of Massachusetts Amherst 36 Implementation

• Assuming that your device name is Xxx • Xxx_init() initialize the device when OS is booted • Xxx_open() open a device • Xxx_read() read from kernel memory • Xxx_write() write • Xxx_release() clean-up (close) • init_module() • cleanup_module()

University of Massachusetts Amherst 37 Register and Unregister Device int init_module(void) /*used for all initialition stuff*/ { /* Register the character device (atleast try) */ Major = register_chrdev(0, DEVICE_NAME, &Fops); …… } void cleanup_module(void) /*used for a clean shutdown*/ { ret = unregister_chrdev(Major, DEVICE_NAME); ...... } Adding a driver needs to register it with the kernel.

University of Massachusetts Amherst 38 Register Device

int register_chrdev(unsigned int major, char *name, struct file_operations *fops);

• major is the major number you want to request • name is the name of the device as it'll appear in /proc/devices • fops is a pointer to the file_operations table for your driver • A negative return value means the registration failed. • We didn't pass the minor number to register_chrdev. That's because the kernel doesn't care about the minor number, and only the driver uses it.

University of Massachusetts Amherst 39 Register Device

• It is careful to use major number – Avoid hijack one that's already in use • To avoid this, we could pass 0 instead and let the OS to assign one (return value of register function) • The downside is that we can't make a device file without the major number – Let the driver print major number – Read /proc/devices to find out – Let the driver to invoke mknod to create

University of Massachusetts Amherst 40 Kernel Functions

• get_user() – Allows a driver to access data in user space, a memory area distinct from the kernel • kfree() – Frees memory previously allocated with kmalloc() • kmalloc() – Allocates a chunk of memory • MAJOR() – Reports the major device number for a device. • MINOR() – Reports the minor device number for a device.

University of Massachusetts Amherst 41 Kernel Functions

• outb(), outb_p() – Writes a byte to a port. Here, outb() goes as fast as it can, while outb_p() pauses before returning. • printk() – A version of printf() for the kernel. • put_user() – Allows a driver to write data in user space. • register_*dev() – Registers a device with the kernel.

University of Massachusetts Amherst 42 A Simple Example 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); return SUCCESS; } void cleanup_module(void) { int ret = unregister_chrdev(Major, DEVICE_NAME); if (ret < 0) printk(KERN_ALERT "Error in unregister_chrdev: %\n", ret); } https://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN569

University of Massachusetts Amherst 43 A Simple Example

//Called when the device file is opened static int device_open(struct inode *inode, struct file *file) { static int counter = 0; Device_Open++; sprintf(msg, "I told you %d times Hello world!\n", counter++); msg_Ptr = msg; return SUCCESS; } static int device_release(struct inode *inode, struct file *file) { Device_Open--; /* We're now ready for our next caller */ module_put(THIS_MODULE); return 0; } https://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN569

University of Massachusetts Amherst 44 A Simple Example 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; }

https://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN569

University of Massachusetts Amherst 45 Outline

• Basic concepts • Kernel module • Writing device driver

University of Massachusetts Amherst 46