Chapter 2 • Lecture 9
Inside the Linux Kernel Source Tree
A guided tour of every important directory — what each one does, what you will find inside, and how they all connect to form a working operating system kernel
20+
Top-Level Directories
60%+
Code in drivers/ alone
Free
This Linux device drivers course
Keywords — free Linux kernel development course, Linux device drivers
free Linux device drivers course
kernel/ mm/ fs/ explained
free Linux kernel programming
VFS virtual filesystem
io_uring kernel directory
rust/ kernel directory
free embedded systems course
What You Will Learn
This lecture is the second part of the Linux kernel source tree topic in EmbeddedPathashala’s free Linux kernel programming course. In Lecture 8 we got the source and checked the version. Now we go inside. By the end you will be able to:
- Describe the purpose of every major directory in the Linux kernel source tree
- Explain the VFS (Virtual Filesystem Switch) and why it is central to the kernel design
- Understand the role of the rust/ and io_uring/ directories introduced since kernel 5.x
- Trace a real I/O operation through multiple kernel directories and see how subsystems connect
- Know exactly which directories matter most for Linux device driver writing
The Complete Linux Kernel Source Tree Map
Before drilling into each directory, study this annotated map of the full source tree layout. Keep this picture in mind throughout the lecture — it shows where everything lives at a glance. In this free Linux kernel development course we will visit every major area shown here.
Linux Kernel Source Tree — Full Annotated Layout (kernel 6.x / 7.x)
|
+– kernel/ Core OS: scheduler, signals, locking, cgroups, timers, modules
+– mm/ Memory management: page allocator, vmalloc, mmap, OOM killer
+– fs/ Filesystems: VFS layer + ext4, btrfs, nfs, fat, f2fs, erofs …
+– block/ Block I/O: page cache, I/O schedulers, generic block layer
+– net/ Full networking stack: TCP, UDP, IP, eBPF, netfilter, XDP
+– ipc/ IPC: pipes, message queues, shared memory, semaphores
+– init/ Kernel startup: contains start_kernel() in main.c
|
+– arch/ CPU-specific: x86/ arm/ arm64/ riscv/ mips/ powerpc/ …
+– drivers/ Device drivers: THE LARGEST DIRECTORY (>60% of codebase)
| +– usb/ USB host and device drivers
| +– net/ Network interface card (NIC) drivers
| +– gpu/ GPU and display drivers (DRM subsystem)
| +– i2c/ I2C bus drivers and client drivers
| +– spi/ SPI bus drivers
| +– gpio/ GPIO controller drivers
| +– mmc/ eMMC/SD card drivers (critical for embedded boards)
| +– bluetooth/ Bluetooth HCI drivers
| +– clk/ Clock framework and clock drivers
| +– nvme/ NVMe SSD drivers
| +– serial/ Serial / UART drivers
| +– … Hundreds more subsystem driver folders
|
+– sound/ ALSA audio subsystem: codecs, sound cards, PCM
+– virt/ Virtualisation: KVM hypervisor implementation
+– security/ LSM: SELinux, AppArmor, Tomoyo, capabilities
+– crypto/ Cryptography: AES, SHA-256, RSA, RNGs
|
+– rust/ Rust language infrastructure [NEW in 6.1, stable in 7.0]
+– io_uring/ Async I/O ring buffer subsystem
|
+– include/ Kernel headers: internal + uapi/ (exported to user space)
+– lib/ Utility library: string ops, data structures, compression
+– scripts/ Build helpers: checkpatch.pl, get_maintainer.pl, kbuild
+– tools/ User-space tools: perf, bpftool, selftest suite
+– samples/ Example code: module samples, eBPF samples, Rust examples
+– Documentation/ Official kernel docs — written by kernel developers
+– certs/ Kernel signing certificates for secure boot
+– usr/ initramfs generation helpers
|
+– Makefile TOP-LEVEL MAKEFILE — entry point for all build commands
+– Kconfig Root kernel configuration menu
+– COPYING License: GPL-2.0 for the vast majority of code
+– MAINTAINERS Who maintains every subsystem and how to contact them
+– README Points to Documentation/ — read this first
Important Top-Level Files — Not Directories
Before entering any directory, it helps to understand the key files sitting right at the root. These are not source code — they are the administrative and build foundation everything else depends on.
📄 Makefile — The Build Entry Point
Every kernel build starts here. When you type make menuconfig or make all, the build system reads this file first. It defines the kernel version numbers, sets compiler flags, and orchestrates the entire build process by descending into subdirectories. This Makefile is also called the top-level Makefile or the kbuild root Makefile. As a kernel developer you will interact with it constantly through make targets — never by editing it directly.
📄 COPYING — The License
The Linux kernel is released under the GNU General Public License version 2 (GPL-2.0). This is a “copyleft” open-source license with a key implication for embedded developers: if you ship a product containing a modified Linux kernel, you must make the source code of your modified kernel available to recipients. Understanding this is practically important when working on commercial embedded Linux products.
📄 MAINTAINERS — Who Owns What
This is a structured list of every kernel subsystem, driver, and component — who is responsible for it, which mailing list to use when reporting bugs or sending patches, and the status of the component. When you are about to submit your first patch in this free Linux device drivers course, you use scripts/get_maintainer.pl to read this file and find the exact right person to contact. No guessing, no emailing the wrong list.
📄 Kconfig — The Configuration Root
When you run make menuconfig the kernel configuration system starts from this file and then recursively includes Kconfig files from every subdirectory. The result is the nested menu system you navigate to enable or disable kernel features. Every directory in the source tree has its own Kconfig listing what can be turned on or off for that subsystem.
Core Operating System Directories — The Heart of the Kernel
kernel/ — The Core Scheduler and OS Services
This is the directory that implements the most fundamental operating system services — the things that make Linux a multitasking operating system. If something happens for every process on the system, its code is here.
Key Subdirectories Inside kernel/
sched/ CPU scheduler — EEVDF (since 6.6) replaced the older CFS
Decides which thread runs next on which CPU core
locking/ Mutex, spinlock, rwlock, semaphore implementations
These are what prevent two CPUs touching shared data at once
cgroup/ Control groups — resource limits per group of processes
Foundation for Docker, systemd, and container isolation
bpf/ eBPF infrastructure — the kernel’s programmable subsystem
Used for tracing, networking, security policy
irq/ Software interrupt management
time/ High-resolution timers, clock sources, jiffies
module.c Kernel module loading and unloading
signal.c Signal delivery between processes
fork.c Process creation (the fork() system call)
The scheduler deserves a special mention. The Linux CPU scheduler determines which process or thread gets to run on which CPU core at any given moment. Since kernel 6.6 the scheduler uses the EEVDF (Earliest Eligible Virtual Deadline First) algorithm, which replaced the older CFS (Completely Fair Scheduler). Understanding the basics of scheduling is important for performance-critical embedded systems work.
mm/ — Memory Management
Memory management is one of the most complex and consequential parts of the kernel. The mm/ directory contains the code that decides how physical RAM is allocated, how virtual address spaces are created for each process, how data is moved between RAM and storage, and what happens when the system runs out of memory.
| Component | What it Does | Embedded Relevance |
|---|---|---|
| Page allocator | Allocates and frees physical pages of RAM | kmalloc() and vmalloc() call this |
| Virtual memory (mmap) | Each process gets its own virtual address space | Process isolation on embedded boards |
| MGLRU (since 6.1) | Better page reclaim under memory pressure | Helps low-RAM embedded systems avoid OOM |
| OOM killer | Terminates a process when RAM is truly exhausted | Critical to understand for embedded products |
📌 Why mm/ Matters for Embedded Linux Developers
Many embedded systems have constrained RAM (256 MB, 512 MB) and no swap partition. Understanding how the kernel allocates and reclaims memory — and how the OOM killer behaves when memory runs low — is critical for building stable products. The DMA memory allocation functions (in mm/ and include/) are also essential for writing DMA-capable device drivers, which are extremely common in embedded work.
fs/ — Filesystems and the VFS
The fs/ directory implements two distinct but tightly coupled things: the Virtual Filesystem Switch (VFS) abstraction layer, and the individual driver for each specific filesystem type. This two-layer design is one of the most elegant pieces of kernel architecture.
How the VFS Works — The Filesystem Abstraction Layer
|
| open() read() write() close() mkdir()
| (same system calls regardless of filesystem type)
v
+——–+———————————-+——–+
| VFS Layer (fs/namei.c, |
| fs/read_write.c, fs/inode.c …) |
| Defines: inode, dentry, file, super_block |
+—+———-+———-+———-+———-+—-+
| | | | |
v v v v v
ext4/ btrfs/ fat/ nfs/ f2fs/
driver driver driver driver driver
(on a (on a (USB stick) (network (NAND
hard disk) SSD) formatted) share) flash)KEY POINT: The application always calls the same open()/read()/write().
The VFS routes each call to the correct filesystem driver below.
You as a developer can write a new filesystem driver (in fs/myfs/)
by implementing the VFS interface — the rest of the kernel just works.
Filesystems you will encounter most in embedded Linux work:
📌 Filesystems in fs/ Most Relevant to Embedded Developers
ext4 — The default on most Linux systems. Solid, well-tested, general-purpose. Used on eMMC-based embedded boards. | f2fs — Flash-Friendly Filesystem. Designed specifically for NAND flash (eMMC, UFS). Reduces write amplification and wear. | erofs — Enhanced Read-Only Filesystem. Excellent for read-only root filesystems on embedded products — fast, compressed, no write support needed. | fat/vfat — FAT32. Used on SD cards and USB sticks. No permissions, simple, universally readable. | squashfs — Compressed read-only filesystem. Common in firmware images.
block/ — The Block I/O Layer
The block layer sits between the filesystem code (fs/) and the actual storage device drivers. Every read from or write to a block storage device — hard disk, SSD, eMMC — passes through this layer. Its job is to make storage I/O efficient by batching requests, reordering them for the physical device, and caching frequently accessed data.
Block Layer Position in the Storage Stack
|
v
fs/ (VFS + ext4 driver) <– finds which disk sectors hold the file
|
v
block/ (block I/O layer) <– batches sector requests efficiently
Page cache <– serves from RAM cache if already cached
I/O scheduler <– reorders requests for best throughput
Multi-queue block layer <– dispatches to multiple CPU queues (NVMe)
|
v
drivers/ata/ or drivers/nvme/ or drivers/mmc/
(actual hardware driver) <– talks to the physical storage chip
net/ — The Full Networking Stack
The net/ directory contains a complete, standard-compliant implementation of the networking protocol stack. This is the code that lets a Linux system send and receive data over Ethernet, WiFi, Bluetooth, and other network interfaces. It is one of the most mature and heavily tested parts of the entire kernel.
Key Areas Inside net/ — The Networking Stack
core/ Network device layer — the bridge between protocols and drivers
net/core/dev.c is where packets enter and leave the stack
ipv4/ IPv4 implementation: IP routing, TCP, UDP, ICMP, ARP
ipv6/ IPv6 implementation: same protocols, 128-bit addresses
socket.c The BSD socket interface — connect(), bind(), send(), recv()
filter.c Classic BPF and eBPF filter attachment to sockets
netfilter/ Packet filtering framework — foundation of iptables / nftables
xdp/ eXpress Data Path — packet processing before kernel allocation
Used in high-frequency trading, CDNs, DDoS mitigation
bluetooth/ Bluetooth protocol stack (L2CAP, RFCOMM, HCI interface)
wireless/ cfg80211 WiFi management framework
ipc/ — Inter-Process Communication
Processes need to talk to each other. The ipc/ directory implements all the kernel-side mechanisms for letting separate processes exchange data or synchronise with each other. These mechanisms are used everywhere — from shell pipes to real-time systems to database shared memory.
| IPC Mechanism | How It Works | Best Used When |
|---|---|---|
| Pipe / FIFO | One-way byte stream between processes | Shell piping, simple producer-consumer |
| Message queues | Structured messages through a named queue | Typed, bounded-size messages between services |
| Shared memory | Same physical RAM mapped into two processes | Fastest IPC — large data sharing, real-time |
| Semaphores | Counting variable for synchronisation | Controlling access to shared resources |
Hardware-Facing Directories — Where Driver Writers Spend Their Time
arch/ — CPU Architecture Code
This directory contains all code that is specific to a particular CPU family. When Linux is ported to a new processor — or when a new feature is added that requires CPU-specific handling — the work happens here. The directory is structured with one subdirectory per supported architecture.
arch/ Subdirectories — One Per CPU Architecture
x86/ Intel and AMD 32-bit and 64-bit processors
arm/ 32-bit ARM (Cortex-A, Cortex-R, Cortex-M Linux support)
arm64/ 64-bit ARM (Cortex-A53, A72, A78 — Raspberry Pi 4/5, phone SoCs)
riscv/ RISC-V open ISA — rapidly growing in embedded and servers
mips/ MIPS32 and MIPS64 — networking equipment, embedded routers
powerpc/ IBM PowerPC and Power ISA — servers and some embedded
loongarch/ LoongArch (Chinese CPU architecture, added in 6.0)
s390/ IBM mainframe architectureInside each architecture directory you find:
boot/ Boot code and compressed kernel image assembly
mm/ Architecture-specific page table format
kernel/ Arch-specific interrupt, exception, and context switch code
include/ Architecture-specific header files
configs/ Default .config files for common boards in this arch
boot/dts/ Device Tree Source files for specific boards (ARM, RISC-V)
📌 Embedded Developer Note — arch/arm64/ and arch/arm/
If you work on embedded boards — Raspberry Pi, BeagleBone, i.MX boards, Qualcomm Snapdragon SoCs — you will spend significant time in arch/arm64/ or arch/arm/. The Device Tree Source (DTS) files in arch/arm64/boot/dts/ describe the specific hardware layout of each board to the kernel. Adding support for a new board means writing or modifying a DTS file here, then implementing any missing drivers in drivers/.
drivers/ — The Largest Directory in the Linux Kernel Source Tree
By sheer volume, drivers/ is the biggest part of the Linux kernel source tree. It accounts for more than 60% of all kernel code. The reason is simple: there are thousands of different hardware devices in the world and each one needs its own driver. Every WiFi chip, GPU, USB controller, I2C sensor, SPI display, and storage controller has code somewhere inside this directory.
Key Subdirectories Inside drivers/ — What Lives Where
net/ Network interface card (NIC) drivers
Ethernet (Intel e1000e, Realtek r8169), WiFi, virtual NICs
gpu/ GPU drivers — DRM (Direct Rendering Manager) framework
drm/i915/ (Intel), drm/amdgpu/, drm/msm/ (Qualcomm)
usb/ USB host controllers and device class drivers
HID (keyboards/mice), CDC (serial/network), mass storage
i2c/ I2C bus controller drivers + client device drivers
Most embedded sensors connect via I2C
spi/ SPI bus controller drivers
Displays, flash chips, ADCs commonly use SPI
gpio/ GPIO controller drivers
Every SoC has dozens of configurable GPIO pins
mmc/ eMMC, SD, SDIO drivers
Primary storage on most embedded Linux boards
bluetooth/ Bluetooth HCI transport drivers (USB, UART, PCIe)
serial/ UART/serial port drivers
Foundation for console output on embedded boards
clk/ Clock framework and clock tree drivers
Every peripheral clock on an SoC needs a driver here
pwm/ PWM (Pulse Width Modulation) drivers
Motor control, LED brightness, buzzer frequency
nvme/ NVMe SSD protocol driver
ata/ SATA and PATA storage drivers
pinctrl/ Pin controller drivers — mux between GPIO and peripherals
iio/ Industrial I/O: ADCs, DACs, IMUs, temperature sensors
watchdog/ Hardware watchdog timer drivers
🎓 Most of Your Work in This Free Linux Device Drivers Course Happens Here
When you write a Linux device driver — whether for a custom I2C sensor, an SPI display, a GPIO expander, or a UART-based module — you are adding code into one of these subdirectories under drivers/. The patterns for how drivers are structured (platform_driver, i2c_driver, spi_driver, usb_driver) are consistent across all of them. Once you learn the pattern in one subdirectory, you can read and write drivers in any other.
Modern Additions Not Covered in Older Linux Kernel Books
If you are learning from a book or blog post that covers kernel 4.x or early 5.x, these two important top-level directories will not be mentioned. They represent significant evolution of the Linux kernel source tree since those older resources were written.
rust/ — Rust Language Infrastructure (New in Kernel 6.1)
The rust/ directory did not exist before kernel 6.1. It was introduced in December 2022 as the foundation for writing kernel code in the Rust programming language. As of Linux 7.0 (2025), Rust support is fully stable — the experimental label has been removed entirely.
What Lives Inside rust/ — The Kernel’s Rust Foundation
kernel/ Safe Rust wrappers around core kernel C APIs
printk!() macro, memory allocation, locking, device model
macros/ Rust procedural macros for kernel module boilerplate
#[module] attribute — replaces MODULE_AUTHOR(), MODULE_LICENSE()
bindings/ Auto-generated Rust bindings to kernel C functions and structs
Generated by bindgen from kernel header files
alloc/ Kernel-specific Rust allocator
Uses kmalloc() underneath instead of the standard library heap
helpers.c C helper functions that Rust code needs to callA minimal Rust kernel module looks like this:
use kernel::prelude::*;
module! {
type: MyModule,
name: “my_rust_module”,
license: “GPL”,
}
struct MyModule;
impl kernel::Module for MyModule {
fn init(_module: &’static ThisModule) -> Result {
pr_info!(“Hello from Rust kernel module\n”);
Ok(MyModule)
}
}
| Aspect | C Kernel Module | Rust Kernel Module |
|---|---|---|
| Memory safety | Manual — developer responsibility | Compiler-enforced at build time |
| Existing APIs accessible | All of them natively | Growing subset via rust/bindings/ |
| Status in 7.0 | Dominant, stable, well-documented | Fully stable, production drivers shipping |
| When to use | Any kernel work, always needed | New drivers where memory safety matters |
io_uring/ — Async I/O Ring Buffers
The io_uring/ directory contains the implementation of Linux’s modern asynchronous I/O interface. Before io_uring, doing efficient async I/O in Linux required using epoll or POSIX AIO — both of which have limitations and overhead. io_uring redesigns this from scratch using a pair of shared ring buffers.
How io_uring Works — The Ring Buffer Design
App submits I/O request –> syscall (overhead)
App checks for results –> another syscall (overhead)
Each I/O needs at least 2 system calls.IO_URING APPROACH:
+———————————+
| Shared Memory Region |
| (mapped in BOTH app and kernel)|
| |
| [SQ] Submission Queue | <– App WRITES here (no syscall needed)
| [ ][ ][ ][ ][ ][ ][ ][ ] |
| |
| [CQ] Completion Queue | <– Kernel WRITES here when done
| [ ][ ][ ][ ][ ][ ][ ][ ] | App READS here (no syscall needed)
+———————————+App submits 1000 I/O requests by writing to SQ directly.
Kernel processes them asynchronously.
App polls CQ for completions — zero syscalls in the steady state.
Result: 5-10x better throughput for I/O-intensive workloads
(databases, web servers, storage benchmarks)
Other Directories Worth Knowing
sound/ — ALSA Audio Subsystem
Contains the Advanced Linux Sound Architecture (ALSA) — the kernel’s audio subsystem. It covers sound card drivers, audio codec drivers, PCM playback/capture, and the ALSA control interface. On embedded boards with audio hardware (a Raspberry Pi with a HiFiBerry card, or an i.MX board with an audio codec), you interact with this through Device Tree and codec drivers in sound/soc/codecs/.
virt/ — KVM Hypervisor
Contains the KVM (Kernel Virtual Machine) implementation. KVM turns the Linux kernel itself into a type-1 hypervisor, allowing multiple isolated virtual machines to run with near-native performance. Tools like QEMU use the /dev/kvm device exposed by this code. Understanding virt/ is relevant if you are working on embedded virtualisation, automotive hypervisors, or cloud infrastructure based on Linux KVM.
init/ — Where the Kernel Starts Running
A small but critically important directory. It contains main.c, which defines start_kernel() — the function that is called after architecture-specific boot code sets up the CPU and hands control to the generic kernel. start_kernel() initialises every kernel subsystem in sequence: memory management, the scheduler, interrupt handling, device drivers, and more. It ends by launching the first user-space process (PID 1, usually systemd). This function is the kernel’s equivalent of main().
Documentation/ — The Most Overlooked Resource
Do not skip this. The Documentation/ directory contains the authoritative documentation for every kernel subsystem, driver writing guide, coding standard, and subsystem API — written by the same people who wrote the code. For anything you are trying to understand in the kernel, check Documentation/ first. It is also available online at docs.kernel.org in a nicely formatted version. For example, Documentation/driver-api/ is essential reading for this free Linux device drivers course.
scripts/ — Tools for Kernel Developers
Contains build system helpers and development tools. The two most important for beginners: scripts/checkpatch.pl — run this on every patch you write before submitting, it checks for kernel coding style violations and will catch many issues that maintainers will otherwise reject your patch for. And scripts/get_maintainer.pl — pass it any source file path and it tells you exactly who to send your patch to and which mailing list to use.
How Kernel Directories Connect — Tracing a Real Operation
It is tempting to think of each directory as isolated. In practice, almost every real operation touches multiple kernel directories simultaneously. Here is a concrete trace that shows exactly how the directories we covered in this lecture are connected during a single real-world operation.
Scenario: Your App Reads a File from an NFS Network Share
|
v
fs/ (VFS layer) VFS receives the call, looks up the file’s inode,
identifies it is mounted over NFS
|
v
fs/nfs/ NFS filesystem driver takes over,
prepares an RPC request to fetch the data
|
v
net/ipv4/tcp.c TCP/IP stack packages the RPC into TCP segments,
routes the packets, manages flow control
|
v
drivers/net/ The NIC driver (e.g. drivers/net/ethernet/intel/)
DMA-copies the packet to the hardware transmit buffer
|
… network round trip …
|
Reply arrives — NIC driver raises interrupt
|
v
kernel/irq/ Interrupt handler runs, wakes the network stack
|
v
mm/ Memory manager provides kernel buffers throughout
for packet reassembly, page cache storage
|
v
kernel/sched/ Scheduler wakes your sleeping process
schedules it back onto a CPU core
|
v
Your application read() returns — data is in your bufferDIRECTORIES TOUCHED IN ONE read() CALL:
fs/, net/, drivers/net/, kernel/irq/, kernel/sched/, mm/
Key Takeaways from Lecture 9
✓ kernel/ handles scheduling, signals, locking, cgroups — the core OS services
✓ mm/ manages all memory — page allocation, virtual memory, OOM — critical for embedded work
✓ fs/ implements the VFS abstraction plus individual filesystem drivers like ext4, f2fs, erofs
✓ drivers/ is the largest directory — over 60% of kernel code, where most driver work happens
✓ arch/ contains CPU-specific code — arm64/ is key for modern embedded boards
✓ rust/ and io_uring/ are modern top-level directories not in older kernel textbooks
✓ A single system call can traverse six or more kernel directories simultaneously
Frequently Asked Questions
Q1. What is the VFS and why is it important?
The VFS (Virtual Filesystem Switch) is an abstraction layer in fs/ that provides a uniform interface for all filesystem operations — open, read, write, close, mkdir, and so on. It is important because Linux supports dozens of filesystems (ext4, btrfs, FAT, NFS, f2fs). Without the VFS, every application would need to know which filesystem it is talking to and call filesystem-specific functions. The VFS hides this — applications always use the same POSIX system calls and the VFS routes each call to the right filesystem driver automatically.
Q2. Why is drivers/ so much larger than any other directory?
Because hardware diversity is enormous. There are thousands of different WiFi chipsets, hundreds of GPU models, dozens of USB controller variants, and countless embedded peripheral ICs. Each one needs its own driver. The core kernel logic — scheduling, memory management, the VFS — is relatively compact. It is the drivers that multiply the codebase. This is actually a sign of Linux’s success: the breadth of hardware it supports is unmatched by any other OS kernel.
Q3. What is the difference between arch/ and drivers/?
arch/ contains code specific to a CPU architecture — how that CPU boots, how its interrupts work, how its page tables are structured, assembly-language routines. drivers/ contains code for peripheral hardware devices — USB controllers, I2C sensors, NIC cards. The key distinction: arch/ code runs differently on an x86 vs an ARM CPU. drivers/ code (for, say, an I2C sensor) can run on any CPU as long as the I2C bus controller is present — architecture-independent logic sitting on top of the arch/ abstraction.
Q4. Where is the kernel’s entry point — the equivalent of main()?
The kernel’s entry point is the function start_kernel() in init/main.c. After the architecture-specific boot code (in arch/) sets up the CPU, it calls this function. start_kernel() then initialises every kernel subsystem in order — memory management first, then the scheduler, then interrupts, then device drivers — before starting the very first user-space process (PID 1, typically systemd or init).
Q5. I am an embedded developer working on ARM boards. Which directories matter most?
In rough order of how much time you will spend: (1) drivers/ — writing or modifying drivers for your peripherals; (2) arch/arm64/boot/dts/ — Device Tree Source files describing your board’s hardware; (3) arch/arm64/ or arch/arm/ — processor-specific boot code; (4) mm/ — if you deal with DMA, custom memory regions, or memory pressure; (5) Documentation/driver-api/ — the single most useful reference for driver writing. Also become very familiar with scripts/checkpatch.pl and scripts/get_maintainer.pl.
Q6. What is KVM and what directory implements it?
KVM (Kernel Virtual Machine) is a hypervisor built into the Linux kernel. When KVM is enabled the kernel can run multiple isolated virtual machines alongside regular Linux processes, using the CPU’s hardware virtualisation extensions (Intel VT-x or AMD-V). KVM’s implementation lives in the virt/ directory. Tools like QEMU use the /dev/kvm device that this code exposes to manage and run VMs at near-native performance.
Q7. What filesystems should I care about as an embedded developer?
Focus on: ext4 for general-purpose read-write storage on eMMC; f2fs (Flash-Friendly Filesystem) for better NAND flash wear management; erofs for read-only root filesystems in firmware images; squashfs for compressed read-only images; and fat/vfat for SD card compatibility. All of these filesystem drivers live inside fs/ in the kernel source tree.
Q8. Can I write a new filesystem and add it to fs/?
Yes. The VFS layer defines a set of interfaces — specifically the file_operations, inode_operations, and super_operations structures — that any filesystem driver must implement. You create a directory under fs/myfs/, implement these operation structures with your filesystem’s logic, register the filesystem type with the VFS, and the rest of the kernel can immediately use it through standard system calls. The kernel’s Documentation/filesystems/ directory has a guide for filesystem writers.
Q9. Is this a free Linux device drivers course or does it cost money?
EmbeddedPathashala is completely free. This entire Linux kernel programming series — including the Linux device driver writing modules, the embedded Linux porting content, and the Bluetooth/BLE deep dives — is provided at no cost. The site is supported by the community and by advertisers, not by course fees. Every lecture, diagram, code example, and interview question pack you see here is free to access.
Q10. Where should I look when I do not understand a kernel API or concept?
In this order: (1) Documentation/ inside the kernel source tree — or its web version at docs.kernel.org; (2) The source code of an existing driver that uses the same API — reading real code is the fastest way to understand usage; (3) The LKML (Linux Kernel Mailing List) archives at lore.kernel.org — discussions, patch reviews, and design decisions are all archived there; (4) elixir.bootlin.com — cross-reference to find every place the API is defined and used; (5) lwn.net — high-quality kernel development articles written for developers.
