> ## Documentation Index
> Fetch the complete documentation index at: https://dragonwingdocs.qualcomm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Manage out-of-tree kernel modules

Most Qualcomm<sup>®</sup> Linux drivers are compiled directly from the kernel source tree.
Some drivers are maintained outside that tree—called out-of-tree or
Dynamically Loadable Kernel Module (DLKM) drivers—and are built separately
using either a standalone `Makefile` or the Yocto build system.

The Qualcomm kernel graphics support layer (KGSL) GPU driver is an example: its
recipe at `recipes-graphics/kgsl-dlkm/kgsl-dlkm_git.bb` builds and installs the
driver as an out-of-tree module.

## Build and autoload modules

### Standalone Makefile

Create a `Makefile` that delegates to the kernel build system via `$(MAKE) -C`:

```makefile theme={null}
all: modules
obj-m := hello.o

SRC := $(shell pwd)

modules:
	$(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules $(KBUILD_OPTIONS)

modules_install:
	$(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install
```

Set `KERNEL_SRC` to the path of the configured kernel source tree before
invoking `make`.

### Yocto recipe

Integrate an out-of-tree module into the Yocto build by inheriting the `module`
class. The class handles `make modules` and `make modules_install` automatically.

```bitbake theme={null}
DESCRIPTION = "${SUMMARY}"
LICENSE = "GPL-2.0-only"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/${LICENSE};md5=801f80980d171dd6425610833a22dbe6"

inherit module

SRC_URI += "file://Makefile \
            file://hello.c  \
            file://COPYING  \
            "
S = "${WORKDIR}"

EXTRA_OEMAKE += "MACHINE='${MACHINE}'"
MAKE_TARGETS = "modules"
MODULES_INSTALL_TARGET = "modules_install"

# Autoload the module on boot
KERNEL_MODULE_AUTOLOAD += "hello"

# The inherit of module.bbclass names packages with the "kernel-module-" prefix
RPROVIDES_${PN} += "kernel-module-hello"
```

The `KERNEL_MODULE_AUTOLOAD` variable writes the module name into
`/etc/modules-load.d/` in the target rootfs, causing `systemd-modules-load` to
insert it on every boot.

### Real-world example: KGSL

The KGSL recipe illustrates a production out-of-tree module:

```bitbake theme={null}
inherit module

DESCRIPTION = "Qualcomm KGSL driver for managing Adreno GPU"
LICENSE = "GPL-2.0-only"
LIC_FILES_CHKSUM = "file://adreno.c;beginline=1;endline=1;md5=fcab174c20ea2e2bc0be64b493708266"

PV = "0.0+git"
SRCREV = "553c972604f739564d6bb70e18e3857c041984b1"
SRC_URI = " \
    git://github.com/qualcomm-linux/kgsl.git;branch=gfx-kernel.le.0.0;protocol=https \
    file://kgsl.rules \
"

do_install:append() {
    install -m 0644 ${WORKDIR}/sources/kgsl.rules -D ${D}${nonarch_base_libdir}/udev/rules.d/kgsl.rules
}

KERNEL_MODULE_PROBECONF += "msm_kgsl"
module_conf_msm_kgsl = "blacklist msm_kgsl"

FILES:${PN} += "${nonarch_base_libdir}/udev/rules.d"

COMPATIBLE_MACHINE = "^$"
COMPATIBLE_MACHINE:aarch64 = "(.*)"
```

Note the `blacklist msm_kgsl` entry: it prevents the upstream in-tree stub from
loading when the out-of-tree KGSL module is present.

For more information about out-of-tree modules in Yocto, see
[Working with Out-of-Tree Modules](https://docs.yoctoproject.org/kernel-dev/common.html#working-with-out-of-tree-modules).

## Module versioning strategy

### Kernel symbol versioning (MODVERSIONS)

When `CONFIG_MODVERSIONS=y` is set in the kernel configuration, the kernel
embeds a CRC checksum for each exported symbol. A module is loaded only when
its per-symbol CRCs match those of the running kernel, preventing silently
binary-incompatible modules from being inserted.

To verify whether MODVERSIONS is active on the target:

```bash theme={null}
zcat /proc/config.gz | grep CONFIG_MODVERSIONS
```

A module built against a different kernel tree or a different `defconfig` will
produce a load-time error if any CRC mismatches:

```text theme={null}
insmod: ERROR: could not insert module hello.ko: Invalid module format
```

### vermagic compatibility

Every `.ko` file embeds a `vermagic` string that encodes the kernel version,
SMP flag, and compiler version used at build time. The running kernel rejects
any module whose `vermagic` does not match exactly.

Inspect a module's vermagic before deployment:

```bash theme={null}
modinfo hello.ko | grep vermagic
```

**Table: vermagic fields**

|    **Field**   | **Example** |           **Description**           |
| :------------: | :---------: | :---------------------------------: |
| Kernel version |   `6.12.0`  | Must match `uname -r` on the target |
|       SMP      |    `SMP`    |    Symmetric multiprocessing flag   |
|    `preempt`   |  `preempt`  |           Preemption model          |
|    Compiler    |   `gcc-14`  |  Toolchain used to build the kernel |

### Version-pinning in Yocto

To ensure an out-of-tree module is always built against the same kernel
version as the running image, set `DEPENDS` and `RDEPENDS` to the kernel
recipe in the module's `.bb` file:

```bitbake theme={null}
DEPENDS += "virtual/kernel"
RDEPENDS_${PN} += "kernel-${KERNEL_VERSION}"
```

The Yocto `module` class automatically sets `KERNEL_SRC` and `KERNELRELEASE`
to values from the selected kernel recipe, so the module Makefile picks up the
correct headers and symbol tables without any manual configuration.
