Linux Device Drivers by Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman
In my continuing attempts to get to grips with operating system kernels, I’ve been playing around with Linux. This all started out when I took a Coursera course on malware, which had a section on Android malware, which included lectures on the virtual machine and covered how it sits on top of a Linux operating system. Interprocess communication happens at a high level in an Android application via Intents, but this maps down to calls via the Binder at the kernel level, where the Binder is driven using a range of IOCTL calls on the respective device.
Wanting to learn a bit more, I found the free section of this course which takes you through the steps of building a Linux kernel and booting into it. With my copy of VmWare it was easy to download the latest copy of Ubuntu, apt-get the relevant tools (like git), clone the kernel sources and then build a new version of the kernel – though the compilation of the kernel inside a virtual machine on my laptop took several hours. It was however easy to change the banner message for the new kernel and boot it, and then check that we were running my new kernel.
The free part of the tutorial gets to the point of writing a trivial kernel module, and so I started looking for more resources around the subject of device drivers. I was lucky enough to come across this book.
Let me start by saying that the content is outstanding!
It takes you through device drivers – character, block and network. It discusses the parts of the kernel that a device driver author needs to understand, such as interrupt handling, memory mapping and timers. It discusses how modern hardware interacts with devices – I had no idea how PCI and USB drivers worked before reading this, and discusses why the traditional Unix model of character and block devices doesn’t abstract network devices correctly. The explanations are clear, and the text always seems to answer the questions that you have while reading.
That is all really interesting material, but the book is also practical. From chapter two, we start writing device drivers, initially for devices which simply remember and return the data that was written to them, but later things become more complicated and we even implement a fake network adapter. The examples have been kept up to date by the authors (as the Linux kernel has changed) and are available on GitHub here.
I would have been happy just reading about all of this, but it has been interesting actually building and running their example code. If you want to understand operating systems at a low level, then this book is a must read!