Obtaining and Configuring Kernel Sources

To build kernel modules, you need kernel headers that match your target kernel version. This chapter covers obtaining kernel sources and preparing them for driver development.

Understanding Kernel Versions

Linux kernel versions follow the format major.minor.patch:

  • Major: Rarely changes (we’re on 6.x)
  • Minor: New features, released every ~9 weeks
  • Patch: Bug fixes and security updates

LTS vs Mainline

Type Example Support Use Case
LTS 6.6.70 ~6 years Production drivers
Mainline 6.12.7 ~3 months Bleeding edge

This guide targets 6.6 LTS for stability. We’ll note differences for 6.1 LTS and 6.12.

Downloading Kernel Sources

Using Our Script

Inside the development container:

cd /workspace/scripts
./download-kernel.sh

This downloads kernel 6.6 LTS to /kernel/linux-6.6.x/.

For a different version:

./download-kernel.sh 6.1   # Download 6.1 LTS
./download-kernel.sh 6.12  # Download 6.12 LTS

Manual Download

KERNEL_VERSION="6.6.70"
cd /kernel
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${KERNEL_VERSION}.tar.xz
tar xf linux-${KERNEL_VERSION}.tar.xz
ln -s linux-${KERNEL_VERSION} linux

Kernel Source Structure

linux/
├── arch/           # Architecture-specific code
│   ├── arm64/
│   ├── x86/
│   └── ...
├── drivers/        # Device drivers (we'll study this!)
│   ├── gpio/
│   ├── i2c/
│   ├── spi/
│   └── ...
├── include/        # Header files
│   └── linux/      # Public kernel API
├── kernel/         # Core kernel code
├── Documentation/  # Kernel documentation
├── scripts/        # Build scripts
├── Kconfig         # Configuration system
└── Makefile        # Top-level Makefile

Configuring the Kernel

Before building modules, configure the kernel for your target architecture.

For ARM64

cd /kernel/linux
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig

For x86_64

cd /kernel/linux
make defconfig

Custom Configuration

For a customized config:

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig

This opens an interactive configuration menu.

Preparing Headers for Module Building

After configuration, prepare the kernel for external module building:

cd /kernel/linux
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- modules_prepare

This creates:

  • Version information files
  • Generated headers
  • Module symbol information

You don’t need to build the entire kernel - just modules_prepare is sufficient for external modules.

Verifying the Setup

Check that headers are ready:

ls /kernel/linux/include/generated/autoconf.h
# Should exist

ls /kernel/linux/Module.symvers
# Should exist (may be empty for fresh config)

Environment Variables

Set these for convenience:

export KERNEL_DIR=/kernel/linux
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

Add to ~/.bashrc to persist across sessions.

Multiple Kernel Versions

To work with multiple kernels:

/kernel/
├── linux-6.1.125/
├── linux-6.6.70/
├── linux-6.12.7/
└── linux -> linux-6.6.70   # Symlink to default

Switch versions by updating the symlink:

cd /kernel
ln -sfn linux-6.12.7 linux

Building Against Host Kernel

If developing for your host system (not cross-compiling):

# Headers are typically at:
/lib/modules/$(uname -r)/build

# Build example:
make KERNEL_DIR=/lib/modules/$(uname -r)/build

Adding a Driver to the Kernel Source Tree

All examples in this guide build out-of-tree (external modules). But production drivers live inside the kernel source tree. Here’s how to add one.

Step 1: Create Your Driver Directory

cd /kernel/linux/drivers/misc
mkdir my_driver

Step 2: Add Source and Kconfig

Create drivers/misc/my_driver/my_driver.c (your driver code) and a Kconfig entry:

# drivers/misc/my_driver/Kconfig
config MY_DRIVER
    tristate "My example driver"
    help
      This is an example in-tree driver.
      Say M to build as a loadable module.

Step 3: Add Makefile

# drivers/misc/my_driver/Makefile
obj-$(CONFIG_MY_DRIVER) += my_driver.o

obj-$(CONFIG_MY_DRIVER) means: build as module when CONFIG_MY_DRIVER=m, build-in when =y, skip when =n.

Step 4: Hook into Parent Kconfig and Makefile

# Append to drivers/misc/Kconfig (before the final "endmenu" if present)
echo 'source "drivers/misc/my_driver/Kconfig"' >> drivers/misc/Kconfig

# Append to drivers/misc/Makefile
echo 'obj-$(CONFIG_MY_DRIVER) += my_driver/' >> drivers/misc/Makefile

Step 5: Configure and Build

# Enable via menuconfig (Device Drivers → Misc → My example driver → M)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig

# Or enable directly in .config
echo "CONFIG_MY_DRIVER=m" >> .config
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- olddefconfig

# Build just your module
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- M=drivers/misc/my_driver

Out-of-Tree vs In-Tree

Aspect Out-of-Tree In-Tree
Build Separate Makefile with M= Integrated with kernel build
Config Always built Controlled by Kconfig (y/m/n)
Distribution Separate .ko file Included in kernel packages
Upstream Not possible Required for mainline
Dependencies Manual Kconfig handles automatically

Develop out-of-tree for fast iteration, then move in-tree when preparing for upstream submission. See Appendix F: Upstreaming for the full submission process.

Troubleshooting

“No rule to make target ‘modules’”

The kernel isn’t configured:

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- modules_prepare

Missing Headers

Ensure modules_prepare completed:

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- modules_prepare

Version Mismatch Warnings

When loading modules, kernel and module versions must match. For development, this is usually fine. For production, ensure exact version alignment.

Kernel Documentation

The kernel includes extensive documentation:

# Read a documentation file
less /kernel/linux/Documentation/driver-api/index.rst

# Generate HTML docs (optional)
make htmldocs
# Output in Documentation/output/

Next Steps

With kernel sources ready, let’s write your first module.


Back to top

Linux Driver Development Guide is a community resource for learning kernel driver development. Not affiliated with the Linux Foundation. Content provided for educational purposes.

This site uses Just the Docs, a documentation theme for Jekyll.