Auto-Loading Linux Kernel Modules at System Boot
Learn how to install and automatically load your out-of-tree kernel modules on every boot using systemd, modules-load.d, modprobe, and depmod — with full Linux 6.x compatibility.
🎓 What You Will Learn
- Why auto-loading kernel modules at boot matters in production embedded Linux projects
- How to install an out-of-tree Linux kernel module to the correct system path
- How
depmodbuilds the module dependency database - How to configure
/etc/modules-load.d/for automatic module loading via systemd - How to pass module parameters at boot time using
/etc/modprobe.d/configuration files - How
modproberesolves load order usingmodules.depandmodules.order - Common mistakes, troubleshooting techniques, and security considerations
⚠ Prerequisites
- Basic understanding of Linux kernel module structure (
module_init,module_exit,MODULE_LICENSE) - Familiarity with writing a simple Makefile for kernel module compilation
- Comfortable using the terminal and basic shell commands
- A Linux system with kernel headers installed (Ubuntu, Debian, Fedora, or any distro running Linux 5.x / 6.x)
Introduction: From Manual Loading to Boot-Time Auto-Loading
When you first start writing Linux kernel modules, you load them manually — using insmod or modprobe from the terminal. This is perfectly fine for development and experimentation. However, in real embedded Linux products, IoT devices, industrial controllers, and automotive systems, you need your kernel modules to be present and active the moment the system finishes booting, without any human intervention.
This is what auto-loading kernel modules at boot means. Modern Linux systems rely on systemd to handle early-boot module loading. systemd reads configuration from /etc/modules-load.d/ and loads any module listed there during the boot sequence — before user-space applications start. This free Linux kernel development tutorial walks you through the complete flow, from building and installing your module to verifying it loads automatically on every boot.
make → Produces mymodule.kosudo make install → Copies to /lib/modules/<ver>/extra/depmod → Updates modules.dep/etc/modules-load.d/mymodule.confmodules-load.dStep 1 — The Makefile Install Target
Before a kernel module can be auto-loaded at boot, it must be installed to a location the kernel’s module management tools know about. The standard install path on any Linux system is /lib/modules/$(uname -r)/. Out-of-tree modules typically land under the extra/ subdirectory within this path.
To make installation easy, your Makefile should include an install target that calls modules_install. Here is a clean, production-grade Makefile for a module called mykmod, written for Linux 6.x:
# Makefile for mykmod — Linux 6.x compatible
obj-m := mykmod.o
# Detect kernel version automatically
KVER := $(shell uname -r)
KDIR := /lib/modules/$(KVER)/build
all:
make -C $(KDIR) M=$(PWD) modules
clean:
make -C $(KDIR) M=$(PWD) clean
install:
@echo "=== Building mykmod before install ==="
make -C $(KDIR) M=$(PWD) modules
@echo "=== Installing mykmod ==="
sudo make -C $(KDIR) M=$(PWD) modules_install
sudo depmod -A
make before make install?If you run
sudo make install without first building the module, the install step has nothing to install. Always build first. The improved Makefile above handles this automatically — the install target calls make internally before installing.
What does modules_install actually do?
When you run sudo make install (which internally calls modules_install via the kernel build system), the following happens:
modules_install Does Internallymykmod.ko to/lib/modules/<ver>/extra/
After installation, verify it landed in the right place:
$ ls -lh /lib/modules/$(uname -r)/extra/
-rw-r--r-- 1 root root 24K Jan 10 09:30 mykmod.ko
You may see warnings like “SSL error: Cannot open file…” during
sudo make install. These are non-fatal. They indicate the kernel tried to sign your module for Secure Boot but could not find a signing key. Your module will still install correctly. For production devices with Secure Boot enabled, you will need to sign your module with a proper key — but that is an advanced topic covered separately.
Step 2 — Understanding depmod: The Module Dependency Tool
depmod is one of those tools that works quietly in the background. Its job is to scan all installed kernel modules and figure out which modules depend on which other modules. It then writes this information into a file called modules.dep, located inside /lib/modules/$(uname -r)/.
When modprobe loads a module, it first consults modules.dep to check if the module has any dependencies that need to be loaded first. Without an up-to-date modules.dep, modprobe may fail to load modules that depend on other modules (also known as module stacking).
depmod scans all .ko files and resolves symbol dependencies
extra/module_B.ko: extra/module_A.koextra/module_C.ko: extra/module_A.ko
Running depmod Manually
The -A flag tells depmod to only update if something changed, which is faster. The -v flag gives verbose output so you can see what it is doing:
# Recommended after installing a new module:
sudo depmod -A
# Full rebuild (slower but thorough):
sudo depmod
# Verbose output to see what depmod is doing:
sudo depmod -Av
# Dry run — shows what modprobe would see for your module:
sudo depmod --dry-run | grep mykmod
After running depmod, verify it picked up your module by checking the generated dependency file:
# View module dependencies for your module:
cat /lib/modules/$(uname -r)/modules.dep | grep mykmod
# Or use modinfo to confirm the module is recognized:
modinfo mykmod
depmod is part of kmod package rather than the older module-init-tools. On modern Ubuntu/Debian systems, ensure you have kmod installed: sudo apt install kmod.
Step 3 — Configuring Auto-Load via /etc/modules-load.d/
This is where the actual “auto-load at boot” magic happens. Modern Linux systems use systemd for the boot process. systemd has a dedicated service called systemd-modules-load.service that reads configuration files from /etc/modules-load.d/ and loads every module listed there during the early boot phase.
reads all
.conf files in /etc/modules-load.d/
modules.conf
mykmod.conf
other.conf
Creating the modules-load.d Configuration File
To tell systemd to load your module at boot, create a .conf file inside /etc/modules-load.d/. The file can have any name, but naming it after your module keeps things tidy. The content is simple — just the module name, one per line:
# Create the config file (requires root)
sudo nano /etc/modules-load.d/mykmod.conf
Contents of /etc/modules-load.d/mykmod.conf:
# Load mykmod kernel module at system boot
# Lines starting with # are comments and are ignored by systemd
mykmod
/etc/modules-load.d/modules.conf file (if it exists on your system). The effect is identical.
Loading Multiple Modules at Boot
You can list multiple module names in a single config file — one module per line. systemd will load them in the order they appear:
# /etc/modules-load.d/myproject.conf
# Modules required for MyProject embedded hardware
module_base # Load the base/core module first
module_driver # Driver depends on module_base
module_helper # Helper utilities
modprobe and modules.dep to handle dependency resolution automatically, rather than manually ordering them.
Step 4 — Passing Module Parameters at Boot Time
Many Linux kernel modules accept parameters that change their behaviour at load time. For example, a UART driver module might accept a baud rate parameter, or a network driver might accept a debug level. When loading modules manually, you pass these with insmod or modprobe directly on the command line. But when auto-loading at boot, you need a different approach.
The answer is the /etc/modprobe.d/ directory. Create a .conf file there with an options line:
# /etc/modprobe.d/mykmod.conf
# Pass parameters to mykmod when modprobe loads it
options mykmod debug_level=2 enable_feature=1
The general syntax is:
options <module-name> <param1>=<value1> <param2>=<value2>
Real-World Example — ALSA Sound Driver Parameters
Here is an example from a real system — the ALSA sound subsystem uses exactly this mechanism to pass hardware-specific parameters to audio drivers:
# /etc/modprobe.d/alsa-base.conf (example from a real Ubuntu system)
options snd-hda-intel model=auto position_fix=0
options snd-usb-audio nrpacks=1
| Config Directory | Purpose | Who Reads It |
|---|---|---|
/etc/modules-load.d/ |
List of modules to load at boot | systemd-modules-load.service |
/etc/modprobe.d/ |
Options, aliases, and blacklists for modules | modprobe |
/lib/modules/<ver>/modules.dep |
Module dependency information | modprobe, depmod |
/lib/modules/<ver>/modules.order |
Build-time module load order | modprobe |
/lib/modules/<ver>/extra/ |
Out-of-tree module binaries | modprobe, depmod |
Passing Parameters via Kernel Command Line (Built-in Modules)
If your module is compiled directly into the kernel (not as a loadable .ko file), you cannot use /etc/modprobe.d/. Instead, parameters are passed through the kernel command line in your bootloader configuration. For GRUB, edit /etc/default/grub and add to the GRUB_CMDLINE_LINUX line:
# /etc/default/grub
GRUB_CMDLINE_LINUX="quiet splash mykmod.debug_level=2 mykmod.enable_feature=1"
# After editing, update grub:
sudo update-grub
How modprobe Resolves Module Load Order
modprobe is the intelligent module loader. Unlike insmod, which blindly loads a single .ko file with no dependency awareness, modprobe uses the database that depmod built to:
- Load all dependency modules first (in the correct order)
- Apply any options specified in
/etc/modprobe.d/ - Handle module aliases (loading
eth0loads the correct network driver automatically) - Remove modules cleanly with
modprobe -r, unloading dependencies in reverse order
- Loads a single
.kofile - Requires full path to
.ko - No dependency resolution
- No parameter file support
- Fails if dependency not loaded
- Lower-level, simpler
- Accepts module name (no path needed)
- Automatically loads dependencies
- Reads
/etc/modprobe.d/for options - Uses
modules.depdatabase - Supports
-rfor clean removal - Preferred in production systems
Using modprobe After Installation
Once your module is installed and depmod has been run, you can use modprobe to load it interactively (without the full path):
# Load the module (modprobe finds it via modules.dep):
sudo modprobe mykmod
# Load with a parameter override:
sudo modprobe mykmod debug_level=3
# Verify it loaded:
lsmod | grep mykmod
# Check the kernel log for module messages:
dmesg | tail -20
# Remove the module cleanly:
sudo modprobe -r mykmod
Understanding modules.order and Module Stacking
When you build multiple kernel modules together (for example, a core module and a hardware-specific driver module that depends on the core), the build system generates a file called modules.order. This file records the order in which modules were built, which hints to modprobe about the preferred load order.
After installation, depmod takes over and generates modules.dep, which maps out the actual symbol-level dependencies between modules. This is the authoritative source that modprobe uses at load time.
# Check the dependency file for your module:
grep mykmod /lib/modules/$(uname -r)/modules.dep
# Example output showing mykmod depends on mykmod_core:
# extra/mykmod.ko: extra/mykmod_core.ko
# modprobe will automatically load mykmod_core first, then mykmod
Complete Step-by-Step Walkthrough for Auto-Loading a Kernel Module
Let’s bring everything together with a complete, end-to-end example. We will create, build, install, and auto-load a simple module called mykmod.
Write the Kernel Module Source
// mykmod.c — Simple demo kernel module for Linux 6.x
#include <linux/module.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("EmbeddedPathashala");
MODULE_DESCRIPTION("Demo module: auto-load at boot tutorial");
MODULE_VERSION("1.0");
static int debug_level = 0;
module_param(debug_level, int, 0644);
MODULE_PARM_DESC(debug_level, "Debug verbosity level (default: 0)");
static int __init mykmod_init(void)
{
pr_info("mykmod: loaded! debug_level = %d\n", debug_level);
return 0;
}
static void __exit mykmod_exit(void)
{
pr_info("mykmod: unloaded.\n");
}
module_init(mykmod_init);
module_exit(mykmod_exit);
Build the Module
cd /path/to/mykmod/
make
# You should see: CC [M] mykmod.o and LD [M] mykmod.ko
ls -l mykmod.ko # Confirm .ko was generated
Install the Module
sudo make install
# This runs: sudo make -C /lib/modules/$(uname -r)/build M=$(PWD) modules_install
# Followed by: sudo depmod -A
# Verify installation:
ls -lh /lib/modules/$(uname -r)/extra/mykmod.ko
Create the Auto-Load Configuration
# Create modules-load.d config file:
sudo tee /etc/modules-load.d/mykmod.conf <<EOF
# Auto-load mykmod at boot
mykmod
EOF
# Optional: if mykmod needs a parameter at load time:
sudo tee /etc/modprobe.d/mykmod.conf <<EOF
options mykmod debug_level=1
EOF
Reboot and Verify
# Reboot cleanly:
sync && sudo reboot
# After reboot — check if module loaded:
lsmod | grep mykmod
# Check kernel log for your module's init message:
dmesg | grep mykmod
# Expected output:
# [ 2.4xxx] mykmod: loaded! debug_level = 1
# Check systemd service status for module loading:
systemctl status systemd-modules-load.service
Verification and Troubleshooting
Key Verification Commands
# 1. Is the module currently loaded?
lsmod | grep mykmod
# 2. Is the module installed on disk?
find /lib/modules/$(uname -r) -name "mykmod.ko"
# 3. Does modprobe know about it?
modinfo mykmod
# 4. Is depmod up to date?
sudo depmod --dry-run | grep mykmod
# 5. Is the modules-load.d config correct?
cat /etc/modules-load.d/mykmod.conf
# 6. Did systemd-modules-load service succeed?
systemctl status systemd-modules-load.service
journalctl -u systemd-modules-load
# 7. What does dmesg say?
dmesg | grep -i mykmod
Common Mistakes and How to Fix Them
| Problem | Root Cause | Solution |
|---|---|---|
| Module not loaded after reboot | Module name in .conf file has a typo, or file is in wrong directory |
Check spelling in /etc/modules-load.d/mykmod.conf. Use exact name from lsmod. |
modinfo mykmod fails with “not found” |
Module not installed or depmod not run after install |
Run sudo make install again, then sudo depmod -A |
| Module loads but parameters are ignored | /etc/modprobe.d/ config has wrong syntax or module name mismatch |
Check cat /etc/modprobe.d/mykmod.conf. Verify module name matches exactly. |
| “Required key not available” taint warning | Secure Boot is enabled but module is not signed | Either sign the module or disable Secure Boot in BIOS for development |
sudo make install copies module but boot fails |
Kernel version mismatch — module compiled for different kernel | Recompile module targeting the boot kernel: check $(uname -r) matches KVER in Makefile |
| Module dependency fails with “Unknown symbol” | Dependent module not installed or not loaded before this module | Install all modules and run sudo depmod -A. Let modprobe handle load order. |
DKMS — Automatic Recompilation After Kernel Updates
Every time the Linux kernel is updated on a system, your installed out-of-tree modules become invalid — they were compiled against the old kernel headers and will not load on the new kernel. Manually recompiling after every kernel update is tedious and error-prone.
DKMS (Dynamic Kernel Module Support) solves this. It stores your module source code in /usr/src/ and automatically recompiles it whenever a new kernel is installed. It is widely used by hardware vendors (NVIDIA GPU drivers, VirtualBox kernel modules, and others use DKMS).
# Install DKMS:
sudo apt install dkms # Debian/Ubuntu
sudo dnf install dkms # Fedora/RHEL
# Register your module with DKMS:
# First, copy source to /usr/src/mykmod-1.0/
sudo cp -r /path/to/mykmod /usr/src/mykmod-1.0
# Create dkms.conf in the source directory:
sudo tee /usr/src/mykmod-1.0/dkms.conf <<EOF
PACKAGE_NAME="mykmod"
PACKAGE_VERSION="1.0"
BUILT_MODULE_NAME[0]="mykmod"
DEST_MODULE_LOCATION[0]="/extra"
AUTOINSTALL="yes"
EOF
# Add module to DKMS:
sudo dkms add -m mykmod -v 1.0
# Build and install:
sudo dkms build -m mykmod -v 1.0
sudo dkms install -m mykmod -v 1.0
# Verify:
dkms status
With DKMS in place, your module will continue to auto-load at boot even after kernel updates, because DKMS will recompile it automatically for the new kernel.
Best Practices for Auto-Loading Linux Kernel Modules
- Always run
depmod -Aafter installation. Never skip this step. Without it,modprobeand systemd cannot find your newly installed module. - Use
modprobeinstead ofinsmodin production scripts and systemd services. It handles dependencies correctly. - Use DKMS for production systems where the kernel may be updated by the package manager.
- Name your
.conffiles descriptively —/etc/modules-load.d/myproject-drivers.confis clearer than/etc/modules-load.d/modules.conf. - Add comments to your
.conffiles explaining what each module does and why it is auto-loaded. - Verify the module loads cleanly with
dmesgafter each reboot, at least during development. - Do not hard-code the kernel version in your Makefile — always use
$(uname -r)or$(shell uname -r)to derive it dynamically. - Test on the target platform before deploying. A module that auto-loads correctly on x86_64 may need cross-compilation adjustments for ARM-based embedded systems.
Security Considerations
Kernel modules run in kernel space — the highest privilege level on the system. A buggy or malicious kernel module can crash the system, corrupt data, or expose security vulnerabilities. Consider the following when auto-loading modules in production:
- Module signing: On systems with Secure Boot enabled, only modules signed with a trusted key are allowed to load. Sign your modules with the platform’s signing key to avoid boot-time failures.
- Restrict
/etc/modules-load.d/permissions: Only root should be able to write to this directory. Verify withls -ld /etc/modules-load.d/. - Audit installed modules: Periodically review what modules are installed in
/lib/modules/$(uname -r)/extra/and what is configured in/etc/modules-load.d/. - Use kernel lockdown mode (Linux 5.4+): The kernel lockdown LSM (Linux Security Module) can prevent unsigned modules from loading even without Secure Boot. Enable with
lockdown=confidentialityon the kernel command line. - Minimize the module surface: Only auto-load modules that are truly required at boot. Modules loaded later by udev or applications do not need to be in
/etc/modules-load.d/.
✅ Key Takeaways
- Auto-loading Linux kernel modules at boot requires three things: installation to
/lib/modules/<ver>/extra/, adepmodrun, and an entry in/etc/modules-load.d/ depmodbuilds the module dependency database (modules.dep) thatmodprobeuses to resolve load order- systemd’s
systemd-modules-load.servicereads/etc/modules-load.d/and usesmodprobeto load each listed module - Module parameters for auto-loaded modules are configured via
/etc/modprobe.d/using theoptionskeyword modprobeis always preferred overinsmodin production — it handles dependencies, applies parameters, and integrates with the module database- Use DKMS to automatically recompile your out-of-tree modules when the kernel is updated
- On Secure Boot systems, modules must be signed with a trusted key to load successfully
🔗 Authoritative References
Conclusion
Auto-loading Linux kernel modules at boot is a fundamental skill for any embedded Linux engineer or Linux device driver developer. The process follows a clear sequence: build your module with the correct Makefile, install it to /lib/modules/$(uname -r)/extra/, run depmod to update the module database, and create a small .conf file in /etc/modules-load.d/ to tell systemd to load your module at every boot.
Understanding how modprobe, depmod, and systemd work together gives you complete control over the module loading lifecycle — from development to production deployment. For long-lived production systems where the kernel is regularly updated, adopting DKMS ensures your auto-loading setup continues to work without manual intervention.
This tutorial is part of EmbeddedPathashala’s free Linux kernel development course. In the next lecture, we explore kernel module security, module signing, and how to handle Secure Boot in embedded Linux products.
Frequently Asked Questions
/etc/modules-load.d/ and /etc/modprobe.d/?/etc/modules-load.d/ tells systemd which modules to load at boot. /etc/modprobe.d/ tells modprobe how to load a module — with what parameters, aliases, or blacklist rules. They work together: systemd reads modules-load.d to get the list of modules, then calls modprobe for each one, and modprobe checks modprobe.d for any options to apply.
depmod every time I install a kernel module?depmod updates the modules.dep database that modprobe uses to locate modules and resolve dependencies. If you skip this step after installing a new module, modprobe mykmod (and therefore systemd’s auto-loading) will fail with a “module not found” error. A good Makefile’s install target should always run sudo depmod -A automatically.
modules-load.d but the module is not installed?modprobe, which will fail silently or log an error to the journal. The boot process will continue normally (the failure is not fatal). You can see the error with journalctl -u systemd-modules-load.service. No harm is done to the system, but your module will not be available.
modprobe but not auto-load at boot?/etc/modules-load.d/mykmod.conf has a typo — it must match the exact module name as seen in lsmod; (2) The config file has wrong permissions or is in the wrong directory; (3) There is a race condition where the module tries to load before a required hardware or driver dependency is ready. Check journalctl -u systemd-modules-load for error messages after booting.
depmod -A, you only need to add the top-level module name to /etc/modules-load.d/. modprobe will automatically read modules.dep and load any dependency modules first. You should not need to manually list each dependency — that is the whole point of depmod.
insmod in /etc/rc.local to auto-load modules instead?rc.local runs very late in the boot process, after all services have started — meaning your module will not be available during early boot. Additionally, insmod does not handle dependencies. The correct, modern approach is to use /etc/modules-load.d/ with systemd, which handles module loading early and correctly.
dmesg output shows “loading out-of-tree module taints kernel” — is this a problem?/etc/modprobe.d/:
# /etc/modprobe.d/blacklist-mymodule.conf
blacklist unwanted_module
You can also add install unwanted_module /bin/true to that file, which is a stronger blacklist that prevents the module from loading even when explicitly requested by other modules. After creating the blacklist file, run sudo update-initramfs -u on Debian/Ubuntu systems to update the initial RAM disk.
# List all modules-load.d config files:
ls /etc/modules-load.d/
# See what modules are configured to auto-load:
cat /etc/modules-load.d/*.conf
# Simulate what systemd-modules-load would do:
systemd-analyze cat-config modules-load.d
The last command is the most comprehensive — it shows all config files and their combined contents in the order systemd would process them.
🎓 Learn Linux Kernel Programming for Free
EmbeddedPathashala offers a completely free, in-depth Linux kernel development course covering kernel modules, device drivers, memory management, Bluetooth/BLE, and more.
Explore All Courses Free Linux Device Drivers Course