
Explore how a device driver integrates code parts—user space access and hardware communication—treats devices as files and uses character devices for byte-wise data with system calls like open and read.
Learn how the name-based connection between a user application and the device file contrasts with major and minor numbers, where the major identifies the driver and the minor distinguishes devices.
Major numbers are statically assigned and documented by government sources, showing used device numbers; the lecture contrasts static and dynamic assignment and explains how dynamic mode allocates the last number.
Explore the /proc/devices file to see the devices currently present on the system, including their major numbers and names. The content is shown in two sections.
Explore the static allocation of device numbers for character device drivers, illustrating default values and how explicit IDs are assigned and verified within the system.
Explore test cases on a previous example within character device drivers. Examine arguments discussed in the caption to understand how the topic unfolds.
Explore what happens when two character device drivers register the same major number, and why dynamic allocation prevents conflicts unlike static allocation.
Explain how one major number supports multiple minor numbers via the magic number, with 126 majors and minor numbers starting at zero or ten, illustrating registration and overflow.
Explore automatic device node creation using device_create in character device drivers, covering major and minor numbers, device class creation, and clean removal of devices.
Learn how to implement a Linux character device using struct file_operations with open, close, read, and write handlers, including owner, permissions, and translating user-space parameters to driver parameters.
Compare cdev_init and cdev_alloc in character device drivers, showing how memory allocation and dynamic setup affect device activation and protection against module unload.
Explore creating a Linux kernel module character device with cdev_alloc, registering with a major number, and handling open, read, and release.
Explore how open and release calls behave in fork scenarios for character device drivers, highlighting that open and release may occur only once and how close is involved.
Explore how many times open and release are invoked when multiple processes access character device drivers.
Explore the inode structure and its file metadata. Understand size, blocks, block size, timestamps, and device numbers, and how stat reveals them and how major and minor numbers identify devices.
Showcases how struct inode and struct file interact during file open and creation, and highlights behavior when a file exists, is created anew, or is deleted.
Accessing a user space buffer from kernel space is discussed, highlighting security issues and the risks of copying from user space in character device drivers.
Explore how put_user in character device drivers handles 64-bit values, stores data, and manages timing with sleeps to illustrate concurrent device interactions.
Explore get_user in character device drivers, showing how to retrieve device values and manage a global variable versus a local property as the latest values change.
Examine why passing a structure with one member on the stack and the other in the heap fails in character device driver operations, and analyze practical implications.
Learn how kernel utilities print dev_t using print_dev_t and format_dev_t, extract major and minor numbers with macros, write to a buffer, and return the number of characters written.
Learn how strnlen_user checks the length of a null-terminated string from userspace by passing a userspace pointer and a maximum length, returning the size including the terminating null.
Learn to pass a structure with a stack and a heap member by copying from user twice and using pointers to access both parts.
Reveal a flaw in a character driver when reading data byte by byte. Improper buffer handling and copying to user space can repeat the first character rather than advancing.
Explore creating multiple character device nodes by allocating several device numbers, initializing each device in a loop, and ensuring each uses a separate buffer to prevent data sharing.
Learn how to add support for private data in a character device driver by initializing device messages, linking devices, and accessing the base address, service name, and file pointers.
Learn how ioctl BLKGETSIZE retrieves a block device size by returning the number of 512-byte blocks, so you can compute disk size.
Learn an ioctl example with BLKGETSIZE64 to obtain a block device size in bytes and sectors, and see how user space can issue device specific custom commands.
Explore how the access_ok macro validates user-space pointers in a character device driver, including when to verify addresses without data transfer and version-specific argument usage.
Explore how to update character device driver code with the access_ok macro to validate userspace arguments, perform access checks, and safely manage addresses in kernel space.
Explore how ioctl command sizes affect data transfer in character device drivers, showing why mismatched argument sizes can yield incorrect data and how to ensure you pass the exact size.
On a 64-bit machine, the unsigned long size changes, complicating ioctl handling for 32-bit processes. Map or redefine command numbers to match the actual command size.
Use open and release to ensure only one process can open the device at a time, avoiding concurrency issues.
Explore how capabilities assign only the necessary privileges to processes, instead of full privileges, and how extended attributes store these capabilities to safeguard privileged operations.
Presents an example of using the cap_sys_module capability to load modules within character device drivers. Shows how this capability enables observing system interactions and managing module execution.
Learn to work with character device drivers by allocating major and minor numbers, registering and unregistering devices, using misc devices, and implementing init and exit sequences.
Explore a basic example of a misc driver, showing a single function, its dynamic creation, and how delays and messages illustrate simple driver behavior.
All the files used in the course
Updated on Oct 10: Added Downloads section
What will you learn from this course?
Introduction to character drivers
What is device number and device file
Allocating device number - statically and dynamically
Creating device file - Manually(mknod) and automatically (udev)
Registering character device and its file operation with Kernel
Copying data from user space to kernel space and vice versa
Understanding the various structures - struct file and struct inode
Implementation of open, release, read, write, llseek, ioctl file operations
How to create multiple device nodes and add support for private data
Flow of write system call from kernel system call entry point to driver write file operations
Handling all the error cases in ioctl implementation
Sending a signal to user space from kernel space
Various access control mechanisms and capabilities
Misc Driver
API's covered in this course:
MAJOR
MINOR
MKDEV
register_chrdev_region
alloc_chrdev_region
class_create
device_create
class_destroy
device_destroy
unregister_chrdev_region
imajor
iminor
copy_from_user
copy_to_user
put_user
get_user
print_dev_t
format_dev_t
strnlen_user
container_of
access_ok
Commands used in this course:
mknod
udevadm monitor