From today’s perspective, one of the most important courses during my computer science education in college was the one that taught me about how operating systems work. And while many things that I learned at college are no longer relevant, the material of that course is still as relevant today as it was then. Sure, everything has become much more sophisticated, and operating systems now manage resources that are orders of magnitudes beyond what was available at that time. However, the fundamentals of how an operating system works when it comes to multitasking, memory management, file system handling, etc. are still the same. I find this knowledge absolutely essential in my everyday work and every couple of years, I have to compile a Linux kernel on my own, just for the fun of it. These days, it was time again, and after having expanded my knowledge a lot around Docker, Kubernetes, ‘the cloud’, CI/CD and other related things over the past year, I now went into the opposite direction for a while and had a look at the software that makes all of this work: The Linux kernel. To my surprise, quite a number of books on Linux kernel and driver development have recently been published, and I chose ‘Linux Kernel Programming’ by Kaiwan N Billimoria as my guide.
Based on the Linux Long Term Support 5.4 kernel, it’s easy to install Ubuntu 20.04 in a virtual machine and get going with the book and the exercises. The book is definitely not for beginners, the reader should have a grasp of the C programming language and the basics of how an operating system works from a theoretical point of view.
The author has a very engaging and entertaining writing style, and I could quickly go through the first 200 pages of the book, which explain how to get going with Virtualbox and Ubuntu 20.04 and how to configure, compile and use a Linux kernel in that environment and on a Raspberry Pi. The author then goes on to explain how Grub is used to load and run the kernel, how the initial RAM disk (initramfs) is assembled, and many exercises demonstrate how the process works in detail and how it can be customized. Not only in theory, but in practice. Temporarily or permanently changing the boot options in configuration files or the GRUB boot menu was a hairy thing to do for me in the past. Not anymore now. There is also a good discussion around Kernel security and it made me think a lot about Secure Boot and DKMS.
Once this ground work is laid, the book then turns to how memory can be allocated in the kernel. Direct kernel pages, the slab allocator / cache, contiguous physical and virtual memory assignments are discussed, all in combination how the kernel resides in memory and how it can be accessed from user space. The virtual ‘/proc’ filesystem now shines more brightly for me as ever! A romantic notion of many is that the Linux kernel is ‘something’ that always runs in the background and benevolently manages user space programs. The book reminds with many examples that this is not the case, and demonstrates, that a great deal of kernel code is executed in context of the calling (user-space) program. Again, lots of examples and practical exercises demonstrate how ‘the kernel’ works.
Next, the book discusses the Linux scheduler, how it works in some detail, and it was surprising for me to see that the actual re-scheduling, i.e. giving another process a CPU, is actually done in the context of the current process, and not by some magical piece of kernel code running somewhere in the background. The final part of the book then deals with kernel synchronization, i.e. making sure that different program threads do not try to modify the same resource at the same time. Spinlocks, mutexes and other things are your friend.
After 700 pages, I have learned a lot, but I certainly wouldn’t yet be able yet to write a kernel module to drive a new piece of hardware. How that is done is explained in ‘Linux Kernel Programming – Part 2’, which is a 450 page book on its own. So that’s where I might go next once I have a bit of time again.