Linux Kernel Programming Part 2 – Char Device Drivers and Kernel Synchronization

Linux Kernel Programming Part 2 - Char Device Drivers and Kernel Synchronization

This book has been written with a view to helping you learn the fundamentals of Linux character device driver development in a practical, hands-on fashion, along with the necessary theoretical background to give you a well-rounded view of this vast and interesting topic area. To do the topics justice, that book’s scope is deliberately kept limited to (mostly) learning how to write misc class character device drivers on the Linux OS. This way, you will be able to deeply imbibe the fundamental and necessary driver author skills to then be able to tackle different kinds of Linux driver projects with relative ease.

The focus is on hands-on driver development via the powerful Loadable Kernel Module (LKM) framework; the majority of kernel driver development is done in this manner. The focus is kept on working hands-on with driver code, understanding at a sufficiently deep level the internals wherever required, and keeping security in mind.

A recommendation we can’t make strongly enough: to really learn and understand the details well, it’s really best that you first read and understand this book’s companion, Linux Kernel Programming. It covers various key areas – building the kernel from source, writing kernel modules via the LKM framework, kernel internals including kernel architecture, the memory system, memory alloc/dealloc APIs, CPU scheduling, and more. The combination of the two books will give you a sure and deep edge.

This book wastes no time – the first chapter has you learning the details of the Linux driver framework and how to write a simple yet complete misc class character device driver. Next, you learn how to do something very necessary: efficiently interfacing your driver with user space processes using various technologies (some of which help as debug/diagnostic aids as well!). Understanding, and working with, hardware (peripheral chip) I/O memory is then covered. Detailed coverage of handling hardware interrupts follows. This includes learning and using several modern driver techniques – using threaded IRQs, leveraging resource-managed APIs for drivers, I/O resource allocation, and so on. It covers what top/bottom halves are, working with tasklets and softirqs, and measuring interrupt latencies. Kernel mechanisms you will typically work with – using kernel timers, setting up delays, creating and managing kernel threads and workqueues – are covered next.

The remaining two chapters of this book delve into a relatively complex yet critical-to-understand topic for the modern pro-level driver or kernel developer: understanding and working with kernel synchronization.

The book uses the latest, at the time of writing, 5.4 Long Term Support (LTS) Linux kernel. It’s a kernel that will be maintained (both bug and security fixes) from November 2019 right through December 2025! This is a key point, ensuring that this book’s content remains current and valid for years to come!

We very much believe in a hands-on empirical approach: over 20 kernel modules (besides a few user apps and shell scripts) on this book’s GitHub repository make the learning come alive, making it fun, interesting, and useful.

We really hope you learn from and enjoy this book. Happy reading!

Who this book is for

This book is primarily for Linux programmers beginning to find their way with device driver development. Linux device driver developers looking to overcome frequent and common kernel/driver development issues, as well as understanding and learning to perform common driver tasks – the modern Linux Device Model (LDM) framework, user-kernel interfaces, performing peripheral I/O, handling hardware interrupts, dealing with concurrency, and more – will benefit from this book. A basic understanding of Linux kernel internals (and common APIs), kernel module development, and C programming is required.

What this book covers

Chapter 1, Writing a Simple misc Character Device Driver, first goes through the very basics – what a driver is supposed to do, the device namespace, the sysfs, and basic tenets of the LDM. We then delve into the details of writing a simple character device driver; along the way, you will learn about the framework – in effect, the internal implementation of the “if it’s not a process, it’s a file” philosophy/architecture! You’ll learn how to implement a misc class character device driver with various methods; several code examples help harden the concepts. Basic copying of data between the user-kernel space and vice versa is covered. Also covered are key security concerns and how to address them (in this context); a “bad” driver giving rise to a privilege escalation issue is actually demonstrated!

Chapter 2, User-Kernel Communication Pathways, covers how to communicate between the kernel and the user space, which is critical to you, as a kernel module/driver author. Here, you’ll learn about various communication interfaces, or pathways. This is an important aspect of writing kernel/driver code. Several techniques are employed: communication via traditional procfs, the better way for drivers via sysfs, and several others, via debugfs, netlink sockets, and the ioctl(2) system call.

Chapter 3, Working with Hardware I/O Memory, covers a key aspect of driver writing – the issue with (and the solution to) accessing hardware memory (mapped memory I/O) from a peripheral device or chip. We cover using the common memory-mapped I/O (MMIO) technique as well as the (typically on x86) port I/O (PIO) techniques for hardware I/O memory access and manipulation. Several examples from existing kernel drivers are shown as well.

Chapter 4, Handling Hardware Interrupts, shows how to handle and work with hardware interrupts in great detail. We start with a brief on how the kernel works with hardware interrupts, then move on to how you’re expected to “allocate” an IRQ line (covering modern resource-managed APIs), and how to correctly implement the interrupt handler routine. The modern approach of using threaded handlers (and the why of it), the Non-Maskable Interrupt (NMI), and more, are then covered. The reasons for and using both “top half” and “bottom half” interrupt mechanisms (hardirq, tasklet, and softirqs) in code, as well as key information regarding the dos and don’ts of hardware interrupt handling are covered. Measuring interrupt latencies with the modern [e]BPF toolset, as well as with Ftrace, concludes this key chapter.

Chapter 5, Working with Kernel Timers, Threads, and Workqueues, covers how to use some useful (and often employed by drivers) kernel mechanisms – delays, timers, kernel threads, and workqueues. They come in handy in many real-world situations. How to perform both blocking and non-blocking delays (as the situation warrants), setting up and using kernel timers, creating and working with kernel threads, and understanding and using kernel workqueues are all covered here. Several example modules, including three versions of a simple encrypt decrypt (sed) example driver, serve to illustrate the concepts learned in code.

Chapter 6, Kernel Synchronization – Part 1, first covers the key concepts regarding critical sections, atomicity, what a lock conceptually achieves, and, very importantly, the why of all this. We then cover concurrency concerns when working within the Linux kernel; this moves us naturally on to important locking guidelines, what deadlock means, and key approaches to preventing deadlock. Two of the most popular kernel locking technologies – the mutex lock and the spinlock – are then discussed in depth, along with several (driver) code examples.

Chapter 7, Kernel Synchronization – Part 2, continues the journey on kernel synchronization. Here, you’ll learn about key locking optimizations – using lightweight atomic and (the more recent) refcount operators to safely operate on integers, using RMW bit operators to safely perform bit ops, and using the reader-writer spinlock over the regular one. Inherent risks, such as cache “false sharing,” are discussed as well. An overview of lock-free programming techniques (with an emphasis on per-CPU variables and their usage, along with examples) is then covered. A critical topic, lock debugging techniques, including the usage of the kernel’s powerful lockdep lock validator, is then covered. The chapter is rounded off with a brief look at memory barriers (along with an existing kernel network driver’s usage of memory barriers).

We again stress that this book is for kernel programmers who are new to writing device drivers; several Linux driver topics are beyond this book’s scope and are not covered. This includes other types of device drivers (besides character), working with the device tree, and so on. Packt offers other valuable guides to help you gain traction on these topic areas. This book would be an excellent start.


  • 关于本书的内容介绍、目录、详情等请在 AmazonGoolge Books 等售书网站搜索查看,本站仅展示封面作为参考。
  • 如无特殊说明,本站提供的所有pdf均为文字版(aka True PDF or Digitally Created PDF)。
  • 本站已经列出的所有图书均可以找到。
  • 收到PDF链接之后建议尽快下载或者保存到自己的百度网盘,防止链接过期失效。


扫描下方二维码添加微信号 bookyage 回复本书编号 201409 即可,我们会尽快(一般24小时之内)将本书PDF文件以百度网盘链接的形式发送给您。