Linux Loadable Kernel Modules

Table of Contents

Introduction

Linux loadable kernel modules allow code to be added to a running Linux kernel.  Most device drivers in Linux can be built statically in the kernel image or as a Loadable Kernel Module(LKM).  Loadable kernel modules are installed into the kernel at run time from user space.  This page is not intended to be a complete tutorial for Linux loadable kernel modules as there is a lot of documentation for general build and use.  This page focuses on topics which are can be less obvious in the general documentation and are needed for a Xilinx specific solution using PetaLinux and/or Yocto generally.

Module Types

Modules can be in the kernel source tree or out of the kernel source tree referred to as external kernel modules.

Udev

Udev is a user space application that is a device manager for the Linux kernel.  The Linux kernel sends uevents to user space whenever a device is initialized or removed in the system.  A device manager application, such as udev, handles the udev events by creating device nodes and loading loadable kernel modules. Udev works with sysfs and rules from the file system to manage devices. Udev starts early in user space initialization as shown below in the boot log.

[    4.015762] ALSA device list:
[    4.018723]   #0: DisplayPort monitor
[    4.022819] Freeing unused kernel memory: 512K
INIT: version 2.88 booting
Starting udev
[    4.127910] udevd[1920]: starting version 3.2.2
[    4.137023] udevd[1921]: starting eudev-3.2.2
[    4.486308] FAT-fs (mmcblk0p1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.

Module Install

Loadable kernel modules (*.ko) are typically installed into the rootfs by a Linux build system such as PetaLinux or Yocto.  The install also consists of other files that reflect the details about the loadable kernel modules such as modules.alias and modules.dep.  The runtime system in user space uses the other files when loading the kernel modules, such as to load all dependent modules prior to a specific module.  Modules are installed in the /lib/modules/<kernel version> directory of the rootfs by default.  In tree modules are located in the kernel sub-directory and all others are located in the extra sub-directory.

Module Loading

Loadable kernel modules are loaded (inserted) from user space by a number of methods.  Udev is one common method to load kernel modules.  Other methods include initialization scripts in the rootfs and manual user commands using the modprobe or insmod commands.

Programmable Logic (PL) Bitstream

The PL bitstream can be loaded in a number of methods for a Xilinx system with many being early in system boot, such as FSBL.  There may be reasons to postpone the loading of the bitstream such that it is completed from Linux user space.  In this case any loadable kernel modules which are device drivers for the PL must be loaded after the PL bitsream is loaded.

Blacklisting Modules

The ability to load kernel modules automatically with udev is convenient but may not always be desired in some systems.  The ability to prevent udev from loading specific modules is referred to a blacklisting.  A driver can be blacklisted in PetaLinux and Yocto by adding lines to a configuration file such as <plnx-proj-root>/project-spec/meta-user/conf/petalinuxbsp.conf or build/conf/local.conf file as illustrated below with the blacklist of the AXI GPIO driver.

KERNEL_MODULE_PROBECONF += "gpio-xilinx "

module_conf_gpio-xilinx = "blacklist gpio-xilinx"


The previous lines cause the /etc/modprobe.d directory to be created in the target rootfs along with a configuration file for each driver in that directory which specifies to blacklist the driver.  Each configuration file contains a single line with the format of "blacklist <driver ko file base name without the extension>" and causes udev to not load the specified driver.

Which Modules Get Automatically Loaded

Modules, either in tree or out of tree, which are referenced in a device tree node using the appropriate compatible property are typically loaded automatically by udev.  Modules which have no device tree connections are not typically loaded automatically and require another method to cause them to be loaded.

Loading Modules Automatically Without Udev

A PetaLinux created (petalinux-create -t modules --name hello --enable) out of tree module is automatically copied into the target rootfs when the module is enabled in the PetaLinux rootfs configuration. 

In Yocto the driver module copy requires an additional configuration file (such as build/conf/local.conf) change.  The following line illustrates adding the hello kernel module to the target rootfs.

IMAGE_INSTALL_append = " hello"

Assuming the module file (ko) is contained in the target rootfs, the mod-utils.sh script must find a configuration file to cause it to load the driver. The following line is added to a  PetaLinux/Yocto configuration file such as <plnx-proj-root>/project-spec/meta-user/conf/petalinuxbsp.conf or build/conf/local.conf.

KERNEL_MODULE_AUTOLOAD = "hello"

The previous configuration line causes the creation of the /etc/modules-load.d directory together with hello.conf in the directory.  Note that the configuration only contains the name of the driver (without an extension).

Udev Details

Uevents, Device Drivers, and Device Tree

The Linux kernel creates udev events to be sent to user space in a number of frameworks including the device driver framework.  Device tree compatible device drivers include a compatible list which is used to bind to a device to a compatible driver.  The compatible property in the device tree helps the appropriate kernel module for a device be loaded by udev.  The following driver and device tree snippets illustrate a compatible string.

drivers/gpio/gpio-xilinx.c
static const struct of_device_id xgpio_of_match[] = {
        { .compatible = "xlnx,xps-gpio-1.00.a", },
        { /* end of list */ },
};
MODULE_DEVICE_TABLE(of, xgpio_of_match);
AXI GPIO Device Tree Snippet
led_4bits: gpio@40030000 {
	...
	compatible = "xlnx,xps-gpio-1.00.a";
	...
};

The compatible string in the device tree can also be seen in the modules.alias file of the target.

/lib/modules/<kernel version>/modules.alias
alias of:N*T*Cxlnx,xps-gpio-1.00.aC* gpio_xilinx
alias of:N*T*Cxlnx,xps-gpio-1.00.a gpio_xilinx

Udev Debug

Udev provides a user space application, udevadm, that can be helpful for understanding the uevents which udev receives from the kernel.  Any loaded modules, seen by lsmod, can be unloaded and then reloaded using udev while watching uevents in real time on the target as illustrated below.

Remove the UIO modules from the kernel assuming they were automatically inserted.

rmmod uio_pdrv_genirq

rmmod uio

Start the udev admininstration application monitoring all uevents from the kernel and put it in the background.

udevadm monitor &

Stop the udev application, then restart it to simulate a boot up of the kernel.

/etc/init.d/udev stop

/etc/init.d/udev start

A lot of output from udevadm will be seen showing all the uevents from the kernel.  Some typical uevents are shown below.

[ 3270.286742] udevd[3279]: starting version 3.2

[ 3270.297017] udevd[3280]: starting eudev-3.2

KERNEL[3270.322676] add      /module/uio (module)

KERNEL[3270.322701] add      /class/uio (class)

UDEV  [3270.322913] add      /module/uio (module)

KERNEL[3270.322970] add      /module/uio_pdrv_genirq (module)

UDEV  [3270.323051] add      /class/uio (class)

KERNEL[3270.323080] add      /bus/platform/drivers/uio_pdrv_genirq (drivers)

UDEV  [3270.323168] add      /module/uio_pdrv_genirq (module)

UDEV  [3270.323334] add      /bus/platform/drivers/uio_pdrv_genirq (drivers)

References