Chapter 30: Kernel configuration deep-dive¶
rootfs: root filesystem, the directory tree mounted at / that contains /bin, /etc, /dev, and libraries. MCU bridge: Think of the rootfs as the firmware image’s file-backed runtime environment. On an MCU you link everything into flash. On Linux, programs and config live in this mounted tree.
What: the kernel’s Kconfig system,
make menuconfig, the.configfile, defconfig snapshots, and the dozen config options that matter most for an i.MX6ULL embedded image. By the end you should be able to enable/disable any kernel feature, save a cleandefconfig, and explain to a teammate why each option is set.Why: Through Chapter 29 we used
imx_v6_v7_defconfigas a black box. For real products you’ll customise: smaller kernels for smaller flash, PREEMPT_RT for real-time, specific debug options on engineering builds. Knowing where each knob lives lets you build a kernel that fits your product, not just one that boots. PREEMPT_RT: the Linux real-time patch set that makes more kernel paths preemptible and reduces latency.Focus:
.configis the canonical file.menuconfig,xconfig, and the others are just UIs that edit it. Read it, edit through the UI, and rebuild.
30.1 The Kconfig system¶
The kernel has ~7000 configurable options across hundreds of Kconfig files scattered through the source tree. Each is a CONFIG_FOO symbol that ends up as =y (compiled in), =m (loadable module), or absent (compiled out) in the final .config.
Five make targets cover 95% of use:
Target |
What it does |
|---|---|
|
Use the default config ( |
|
Use a named per-board/per-arch starting point (e.g., |
|
Interactive ncurses-based config editor |
|
Update an existing |
|
Distill the current |
Other UIs exist (nconfig, xconfig, gconfig), same functionality, different UIs. menuconfig is the one everyone uses.
30.3 The .config file¶
Privilege boundary: $ means normal user. # or sudo means root and can change host or target state. After a privileged command, verify the expected device, service, or file appears before continuing. Roll back by undoing the config change or stopping the service you just enabled.
After saving in menuconfig, the entire state lives in .config at the kernel-tree root. It is plain text. Each line is one of: CONFIG_FOO=y, CONFIG_FOO=m, CONFIG_FOO="string", CONFIG_FOO=10, or # CONFIG_FOO is not set.
$ wc -l .config
2147 .config
$ head -10 .config
#
# Automatically generated file; DO NOT EDIT.
# Linux/arm 6.6.0 Kernel Configuration
#
CONFIG_CC_VERSION_TEXT="arm-none-linux-gnueabihf-gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0"
CONFIG_GCC_VERSION=110400
CONFIG_CLANG_VERSION=0
CONFIG_AS_IS_GNU=y
CONFIG_AS_VERSION=24200
...
You can edit .config by hand, but the comment is honest: changes you make can be silently undone the next time make runs, because the Kconfig dependencies might reject your edit. Always go through make olddefconfig or make oldconfig after a manual edit to let the system reconcile.
30.4 defconfigs, capturing your customisation¶
A defconfig is the minimum set of options that, applied on top of the architecture’s defaults, reproduces your .config. It’s how you preserve a customisation without saving the full 2000-line .config.
$ make ARCH=arm savedefconfig
$ ls defconfig
defconfig
$ wc -l defconfig
324 defconfig
That defconfig file (324 lines vs 2147 for full .config) contains only the lines that differ from the architecture default. Save it as arch/arm/configs/myboard_defconfig, commit it to git, and anyone can reproduce your build:
$ make ARCH=arm myboard_defconfig
$ make ARCH=arm -j$(nproc) zImage
With those two commands, the second engineer has the same kernel. This is why upstream ships imx_v6_v7_defconfig instead of full .configs.
30.5 The dozen knobs that matter most¶
Reading every help text in menuconfig takes hours and is not the fastest way to learn what matters. Here are the dozen options that matter most on the path from defconfig to an i.MX6ULL image:
Preemption model, CONFIG_PREEMPT_*¶
General setup
Preemption Model --->
( ) No Forced Preemption (Server)
(X) Voluntary Kernel Preemption (Desktop) ← default
( ) Preemptible Kernel (Low-Latency Desktop)
( ) Fully Preemptible Kernel (Real-Time)
Determines how long kernel code can hold the CPU before letting another thread run. PREEMPT_NONE maximizes throughput, PREEMPT_VOLUNTARY (the default) is a reasonable compromise, PREEMPT improves desktop responsiveness, PREEMPT_RT turns the kernel into a real-time kernel with bounded, low latency (Chapter 52A is dedicated to this).
For a typical embedded product, PREEMPT_VOLUNTARY is fine. For motion control or audio with hard latency budgets, PREEMPT_RT. For a router pushing packets, PREEMPT_NONE.
Tick rate, CONFIG_HZ¶
Kernel Features
Timer frequency --->
( ) 100 Hz
(X) 250 Hz
( ) 300 Hz
( ) 1000 Hz
How often the kernel scheduler tick fires. Higher = better latency, more overhead. 250 Hz is the modern default for non-server workloads. For battery-powered devices, lower. For low-latency, 1000 Hz.
Tickless idle, CONFIG_NO_HZ_*¶
General setup
Timers subsystem
Timer tick handling --->
( ) Periodic timer ticks (constant rate, no dynticks)
(X) Idle dynticks system (tickless idle)
( ) Full dynticks system (tickless)
NO_HZ_IDLE lets the CPU sleep longer when idle by stopping the tick. Saves power. The default for v6.x.
Devtmpfs, CONFIG_DEVTMPFS + CONFIG_DEVTMPFS_MOUNT¶
Device Drivers
Generic Driver Options
[*] Maintain a devtmpfs filesystem to mount at /dev
[*] Automount devtmpfs at /dev, after the kernel mounted the rootfs
Required for the modern /dev model: kernel populates /dev/* from device probes. Without it, you need udev or mdev in userspace. Always enable both.
udev: the user-space device manager that reacts to kernel device events and creates policy-driven /dev nodes.
Initramfs, CONFIG_BLK_DEV_INITRD + CONFIG_INITRAMFS_SOURCE¶
General setup
[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
() Initramfs source file(s) ← optional, embeds an initramfs
Required for Chapter 29. The source field embeds a cpio archive directly into zImage.
Modules, CONFIG_MODULES and CONFIG_MODULE_UNLOAD¶
[*] Enable loadable module support --->
[*] Module unloading
[*] Forced module unloading ← off in production usually
Enables =m-style driver loading. Useful for development (load/unload a driver without reboot). Off if you want a monolithic kernel.
console= defaults via DT, already covered¶
The kernel reads chosen.stdout-path from DT plus the console= cmdline. Both are independent of .config.
USB, CONFIG_USB + CONFIG_USB_EHCI_HCD + CONFIG_USB_GADGET¶
Device Drivers
[*] USB support --->
<*> Support for Host-side USB
<*> EHCI HCD (USB 2.0) support
[*] USB Gadget Support
EHCI host = USB host port on i.MX6ULL. Gadget = device-mode (Chapter 55).
Network drivers, CONFIG_FEC for the i.MX FEC¶
Device Drivers
[*] Network device support --->
Ethernet driver support --->
<*> Freescale devices --->
<*> FEC (Freescale FEC and i.MX6UL/ULL)
Without CONFIG_FEC, your Ethernet won’t work. Default imx_v6_v7_defconfig enables this. If you start from a stripped-down config you may have to add it back.
MMC / SD, CONFIG_MMC + CONFIG_MMC_SDHCI_ESDHC_IMX¶
Device Drivers
<*> MMC/SD/SDIO card support --->
<*> Secure Digital Host Controller Interface support
<*> Freescale eSDHC/uSDHC i.MX controller
Required to access SD card and eMMC.
Filesystem support, CONFIG_EXT4_FS, CONFIG_F2FS_FS, CONFIG_VFAT_FS¶
File systems --->
<*> The Extended 4 (ext4) filesystem
<*> F2FS filesystem support
<*> DOS/FAT/EXFAT/NT Filesystems --->
<*> VFAT (Windows-95) fs support
Need at least one filesystem matching your root=. Most embedded systems use ext4 on eMMC, F2FS on eMMC for flash longevity, FAT for boot partitions.
Kernel debug options, CONFIG_DEBUG_KERNEL + CONFIG_DEBUG_INFO¶
Kernel hacking --->
[*] Kernel debugging
Compile-time checks and compiler options --->
Debug information --->
(X) Generate DWARF Version 5 debuginfo
For development, keep these on, gdb stack traces and oops decoding need DWARF symbols. For production, off, they bloat vmlinux by 100+ MB (though zImage stays small).
30.6 Building a smaller kernel¶
Default imx_v6_v7_defconfig produces a ~6 MB zImage. For a tighter image:
$ make ARCH=arm imx_v6_v7_defconfig
$ make ARCH=arm menuconfig
Aggressive trimming:
Disable unused architectures/SoCs.
System Type → Multiple platform selection: turn offARM_AT91,ARM_OMAP,ARCH_BCM, etc., keep onlyARCH_MXC. Saves ~500 KB.Disable unused drivers.
Device Drivers → Sound card support → ALSA for SoC audio support, off if you don’t have audio. Saves ~200 KB.
ALSA: Linux’s kernel and user-space audio stack.
Disable unused filesystems. Only ext4 needed? Disable F2FS, FAT, etc. Saves ~100 KB.
Disable IPv6 / IPv4 sub-features you don’t need. TCP / UDP / unicast routing, yes. Multicast routing / fib_rules / netfilter, no. Saves ~500 KB.
Disable debug info.
Kernel hacking → Kernel debugging → off. Cutsvmlinuxsize dramatically.zImageshrinks by ~1 MB. Keep your dev build separate.
A trimmed image for i.MX6ULL can reach ~3 MB. Below that requires turning off things you usually want (e.g., loadable modules → +200 KB savings, but you lose modprobe).
30.7 Useful Kconfig idioms¶
Find an option by name¶
( ) Inside menuconfig, press / and type CONFIG_FOO
The search results include the menu path. Quote: “Symbol: PREEMPT_RT [=n]. Defined at kernel/Kconfig.preempt:64. Location: Main menu → General setup → Preemption Model → ...”. You can jump there with Enter.
See dependencies¶
( ) Highlight an option and press ? for help; the "Depends on:" lines list its preconditions
If CONFIG_FOO depends on BAR && BAZ, enabling FOO requires both BAR and BAZ. Menuconfig hides FOO if its dependencies aren’t met. Search to find the missing dependency.
Strip a feature from a defconfig¶
$ make ARCH=arm imx_v6_v7_defconfig
$ ./scripts/config --disable AUDIT
$ make ARCH=arm olddefconfig
scripts/config is the headless command-line equivalent of menuconfig, invaluable for CI.
Combine multiple defconfigs¶
$ make ARCH=arm imx_v6_v7_defconfig
$ ./scripts/config --enable PREEMPT_RT
$ make ARCH=arm olddefconfig
You start from a known baseline and apply targeted changes. Easier to maintain than committing a full bespoke defconfig.
30.8 Lab¶
Read the help for ten random options. Press
/to search for something innocuous (PREEMPT,DEVTMPFS, etc.), press?on each, read the help. Get a feel for how Kconfig documentation reads.Trim the kernel. Starting from
imx_v6_v7_defconfig, disable five features you’re confident you don’t need on the i.MX6ULL MINI. Rebuild. MeasurezImagesize before and after.Generate a custom defconfig. After trimming, run
make ARCH=arm savedefconfig. Inspectdefconfig. Save asarch/arm/configs/myboard_defconfig. Verify anothermake distclean && make myboard_defconfig && makereproduces the same trimmed kernel.Enable a kernel module. Find a driver currently
=y(e.g.,CONFIG_USB_F_MASS_STORAGE). Change it to=m. Rebuild. Confirm a corresponding.koappears underdrivers/usb/gadget/function/.Read
Documentation/admin-guide/kernel-parameters.txtfor any 10 cmdline tokens. Cross-reference with the.configoptions that produce them.
30.9 Pitfalls¶
Editing
.configdirectly and not runningmake oldconfig. Your edits may be silently reverted on next build because of dependency rules. Always go through Kconfig.Forgetting
ARCH=arm. Without it,make menuconfigshows you the host’s Kconfig (x86 or arm64), not the cross target’s. Always export.make defconfigoverwrites.config. If you’ve made customisations and runmake defconfig, those changes are gone. Save withmake savedefconfigfirst.Different defconfigs in different parts of the tree.
arch/arm/configs/imx_v6_v7_defconfigis for ARM 32-bit i.MX6/i.MX7.arch/arm64/configs/defconfigis for everything ARM 64-bit. Don’t cross them.Disabling
CONFIG_MMU. There is aCONFIG_MMUsymbol you can clear. Don’t. The result isnommuLinux for parts without an MMU, which won’t run on Cortex-A7 anyway.
MCU bridge: Think of the MMU as a hardware address translator in front of every load/store. Cortex-M usually runs physical addresses directly. Linux relies on virtual addresses and page permissions. MMU: Memory Management Unit, hardware that translates virtual addresses to physical addresses and enforces permissions.
Disabling
CONFIG_PREEMPT_VOLUNTARYto “make it faster”. If you turn offCONFIG_PREEMPT_VOLUNTARY, the build falls back toCONFIG_PREEMPT_NONE, which is the server profile (higher latency, higher throughput). On an interactive system this is a regression. Read the help on each Preemption Model option before changing.
30.10 Going deeper¶
Documentation/kbuild/kconfig-language.rst: the canonical Kconfig syntax reference.Documentation/kbuild/kconfig.rst: operational guide formake menuconfigand friends.scripts/kconfig/: the Kconfig parser and UI source. Worth a skim if you write your own Kconfig.Documentation/admin-guide/: runtime-tunable options many of which correspond to.configchoices.
Next chapter: Chapter 30A: Kernel lifecycle decision framework. Now that you can configure any kernel, the question becomes which kernel, mainline, stable, LTS, or vendor BSP. The single most important architectural decision in any product. BSP: Board Support Package: vendor patches, configs, bootloader files, and scripts needed to boot one board.