The Linux kernel source tree contains millions of lines of code across tens of thousands of files — intimidating the first time you open it. This lecture in our free linux kernel development course gives you a practical map of the top-level directories, so you always know roughly where to look for a given piece of functionality instead of grepping the entire tree blindly.
drivers directory
arch directory
kernel documentation
device driver location
free embedded systems course
What You Will Learn
Where driver code lives versus architecture-specific code
How to quickly locate the code for a given subsystem
Why serial port drivers live outside the arch tree
Practical commands for exploring a fresh checkout
Prerequisites
A cloned or extracted kernel source tree on disk (covered in the previous lecture of this free linux development course) and basic command-line navigation skills.
Why the Layout Matters
A recent mainline kernel contains well over 70,000 files and tens of millions of lines of code across C source, headers, and assembly. Nobody memorizes all of it — what experienced kernel developers actually have is a mental map of where things generally live, built from the tree’s consistent top-level organization. Learn this map once and it applies to every kernel version and every architecture you’ll ever work with.
Exploring the Top Level
Start any new kernel tree the same way — list the top-level directories:
$ cd ep-linux
$ ls -1
arch
block
certs
crypto
Documentation
drivers
fs
include
init
io_uring
ipc
kernel
lib
LICENSES
mm
net
rust
samples
scripts
security
sound
tools
usr
virt
Makefile
Kconfig
COPYING
...
The directories that matter most for day-to-day embedded and driver work are a smaller subset. Here’s what each one actually contains:
| Directory | Contents |
|---|---|
arch/ |
Architecture-specific code — one subdirectory per CPU architecture (arm64, x86, riscv, …) |
Documentation/ |
Kernel documentation in reStructuredText — always check here first for a subsystem’s official docs |
drivers/ |
Device drivers, organized into subdirectories by device class (tty, net, gpio, i2c, …) |
fs/ |
Filesystem implementations (ext4, btrfs, overlayfs, VFS core, …) |
include/ |
Kernel header files, including the ones exposed to user space and needed by a cross toolchain |
init/ |
Kernel start-up / boot sequence code |
kernel/ |
Core scheduler, locking primitives, timers, power management, tracing infrastructure |
mm/ |
Memory management — page allocator, virtual memory, swap |
net/ |
Network protocol stacks (TCP/IP, netfilter, Bluetooth core, …) |
scripts/ |
Build-time tooling, including the device tree compiler dtc |
tools/ |
Standalone user-space tools shipped with the kernel, such as perf |
├── arch/ architecture-specific (arm64, x86, riscv…)
├── Documentation/ official docs, check first
├── drivers/ device drivers by class
├── fs/ filesystems
├── include/ kernel + toolchain headers
├── init/ boot-time startup code
├── kernel/ scheduler, locking, timers, PM
├── mm/ memory management
├── net/ networking stacks
├── scripts/ build tooling (incl. dtc)
└── tools/ user-space tools (incl. perf)
The Key Insight: Drivers vs Architecture Code
The single most common confusion for newcomers is guessing that a peripheral driver lives under arch/$ARCH/ because that’s “where the SoC-specific stuff is.” In reality, the arch/ tree only holds code that’s central to bringing up and running that CPU architecture itself — boot entry points, low-level interrupt handling, machine descriptors, and similar plumbing.
An actual device driver — a serial port controller, an I2C bus driver, a GPIO expander — lives under drivers/, organized by device class, not by which SoC it happens to run on. A UART driver for an ARM SoC and a UART driver for a RISC-V SoC both live side-by-side under drivers/tty/serial/, not scattered across different arch/ subtrees.
# finding a serial driver — correct place to look
$ ls drivers/tty/serial/ | grep -i imx
# NOT here — arch/ holds boot/platform plumbing, not device drivers
$ ls arch/arm64/mach-* # this pattern doesn't even exist on modern arm64
Practical Exercise: Locating a Subsystem
Say you need to find the GPIO framework core. A quick, targeted search beats an unfocused grep across the entire multi-million-line tree:
$ ls drivers/gpio/ | head
$ ls Documentation/driver-api/gpio/
Expected output gives you both the implementation directory and its official documentation in one pass — exactly the pattern to repeat for any subsystem: check Documentation/ for the concept, then the matching drivers/<class>/ directory for real implementations to read as examples.
Real-World Use Case: Onboarding to an Unfamiliar Codebase
When you join a project with an existing vendor kernel fork, the fastest way to get oriented isn’t reading it front-to-back — it’s using this same top-level map to jump straight to the areas relevant to your task. Bringing up a new sensor driver? Go straight to drivers/iio/ or drivers/hwmon/ depending on its class, check Documentation/ for the relevant subsystem binding docs, and use existing drivers in that directory as your template.
Common Mistakes and Troubleshooting
- Searching
arch/for device driver code — you’ll rarely find it there on a modern kernel; go todrivers/instead. - Ignoring
Documentation/— it’s frequently more current and authoritative than blog posts or older books, and it’s already sitting right there in the tree you cloned. - Grepping the whole tree for every question — a targeted look in the right top-level directory is faster and teaches you the layout; blind full-tree greps get slower as the codebase grows.
- Assuming directory names are architecture-specific when they’re class-specific —
drivers/gpio/, for instance, holds GPIO controller drivers for every architecture, not one.
Best Practices
- Always check
Documentation/before diving into implementation code for an unfamiliar subsystem. - Use
drivers/<class>/as your default search location for any actual peripheral driver. - Reserve
arch/$ARCH/searches for boot, low-level interrupt, or machine-descriptor questions. - Use existing drivers in the same class directory as working references when writing something new.
Summary / Key Takeaways
- The kernel source tree’s top-level layout is consistent across versions and architectures — learn it once.
drivers/holds device drivers organized by class;arch/holds architecture plumbing, not peripheral drivers.Documentation/is the first place to check for any subsystem’s official explanation.- Targeted searches in the right directory beat blind full-tree greps.
Conclusion
Once you can navigate the tree confidently, the kernel stops feeling like an impenetrable multi-million-line codebase and starts feeling like a well-organized project you can find your way around in seconds. The next lecture in this free linux kernel development course moves on to the configuration system — Kconfig and Kbuild — that decides which of this code actually ends up in your build.
Frequently Asked Questions
Why isn’t my board’s driver under arch/arm64/?
Because arch/ only contains architecture-level plumbing, not device drivers. Actual peripheral drivers live under drivers/, organized by device class rather than by SoC or architecture.
Is Documentation/ always up to date?
It’s actively maintained alongside the code and generally the most reliable first stop, though like any large project some corners lag behind — cross-check against the actual source when something seems off.
How many files are actually in a modern kernel tree?
It varies by release, but recent mainline kernels run well into the tens of thousands of files and tens of millions of lines across C, headers, and assembly — checking your specific checkout with a tool like cloc gives an exact count.
Where do I find the device tree compiler source?
The dtc tool lives under scripts/dtc/ in the kernel tree.
What’s the difference between fs/ and drivers/?
fs/ contains filesystem implementations and the virtual filesystem (VFS) core; drivers/ contains the code that talks to hardware devices. A block device driver lives in drivers/, while the filesystem that sits on top of it lives in fs/.
Continue the Free Linux Kernel Development Course
Next up: understanding Kconfig and Kbuild, the kernel’s configuration system.
