Out-of-Tree Kernel Modules

This topic provides details on how to prepare, build, and load/unload out-of-tree kernel drivers.

Linux kernel modules can be loaded/unloaded in runtime, which allows for smaller core kernel images and more flexibles systems.

Also see Kernel Module Definition .mdef

Install Toolchain to Build Kernel Modules

This process involves changing the make configuration before you build the kernel, to do this it is recommended that you install another separate version of the toolchain for this purpose.

Create an install directory and open a Linux shell to ensure the top directory is known like this:

mkdir yocto-install
cd yocto-install
export TOPDIR=${PWD}

Then download the appropriate toolchain for your environment from the Legato Downloads page. You can use wget after you know the filename.

Ensure you have appropriate access to run the toolchain install script:

chmod 755 <toolchain filename>

Start installation:

./poky-swi-ext-glibc-x86_64-meta-toolchain-swi-ext-armv7a-vfp-neon-toolchain-swi-ext-1.7.3.sh

When asked type, enter this:

Enter the target directory for SDK (default: /opt/swi/y17-ext): ./y17-ext

Then press <ENTER> twice:

  • once to confirm the command
  • once to answer "Y" to the following question.

Check to ensure the toolchain is in your path:

export PATH=$PATH:${PWD}/y17-ext/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi

It's recommended to add the toolchain path to your ~/.profile file so it's available every time you log in.

Set Build Environment

To overcome a current deficiency in the Yocto kernel-dev package, you need to set the module build environment:

cd ./y17-ext/sysroots/armv7a-vfp-neon-poky-linux-gnueabi/usr/src/kernel
ARCH=arm CROSS_COMPILE=arm-poky-linux-gnueabi- make scripts

Make Kernel Module

First, ensure the kernel module support root directory is known:

export B_KDIR=${PWD}
cd $TOPDIR

Next, make an example kernel module directory, and go to it

mkdir kmodule
cd kmodule

C File Example

Create a kernel file like this simple ktest_module.c example:

#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
 
static int __init ktest_module_init(void)
{
printk(KERN_INFO "Driver version %s\n", VERSION);
printk(KERN_INFO "Buona Sera :)\n");
return 0;
}
 
static void __exit ktest_module_exit(void)
{
printk(KERN_INFO "Ciao!\n");
}
 
module_init(ktest_module_init);
module_exit(ktest_module_exit);

Makefile Example

Create a makefile like this simple example:

# Kernel module build command for ARM targets is:
# make ARCH=arm CROSS_COMPILE=arm-poky-linux-gnueabi-
#
# List of object file(s) to be built
obj-m+=ktest_module.o
#
# Point to the directory containing sources for the kernel running on target
# system. The kernel directory must have the configuration build step executed,
# i.e. it must contain the target system's .config file.
#
# Legato tools contain such a directory, point to it.
KBUILD_DIR=/opt/swi/y17-ext/sysroots/armv7a-vfp-neon-poky-linux-gnueabi/usr/src/kernel
#
# Kernel module build dependency
all:
make -C $(KBUILD_DIR) M=$(PWD) modules
#
# Kernel module clean dependency
clean:
make -C $(KBUILD_DIR) M=$(PWD) clean

Build Kernel

Then add the example kernel module source ktest_module.c file and its Makefile to kmodule directory.

You're then ready to build the example kernel module:

make

You should then have a ktest_module.ko located in kmodule directory.

Warning
Ensure the kernel sources version used to compile the module matches the kernel version running on the target.
Note
The y17-ext directory could be relocated to directory of your choice. If relocated, PATH and B_KDIR variables must be changed accordingly.

Load Driver

You can load the driver onto the target device manually or use Legato's mdef File Load.

Manual Load

This section shows how to:

  • copy a module to a target
  • manually install a module on a target
  • remove a module from a target

This is how to use scp to copy a kernel module (driver) onto the target:

scp ktest_module.ko root@$target_IP:/home/root/ktest_dir

This is how to install a module, and check it installed:

root@swi-mdm9x15:~/ktest_dir# insmod ktest_module.ko
root@swi-mdm9x15:~/ktest_dir# lsmod |grep ktest
ktest_module 648 0 - Live 0xbf0eb000 (PO)

This is how to check the log file:

root@swi-mdm9x15:~/ktest_dir# logread |tail -n 2
Nov 10 18:16:30 swi-mdm9x15 user.info kernel: [88600.728022] Driver version 1.0.0
Nov 10 18:16:30 swi-mdm9x15 user.info kernel: [88600.728053] Buona Sera :)

This is how to remove the module, and check the log that it was removed:

root@swi-mdm9x15:~/ktest_dir# rmmod ktest_module.ko
root@swi-mdm9x15:~/ktest_dir# logread |tail -n 2
Nov 10 18:16:30 swi-mdm9x15 user.info kernel: [88600.728053] Buona Sera :)
Nov 10 18:19:38 swi-mdm9x15 user.info kernel: [88789.028495] Ciao!
root@swi-mdm9x15:~/ktest_dir#

mdef File Load

You can also use Legato's mdef to load the pre-built kernel module.

Create Kernel Module Definition .mdef hello.mdef file in any location with this preBuilt section:

preBuilt: /path/to/kernel/module/ktest_module.ko

Modify $LEGATO_ROOT/system.sdef (in Legato root dir) to include the kernelModule path:

kernelModules:
{ <path_to_hello.mdef> }

Build and Install

Then build and install Legato on a WP85 module.

If the driver load succeeds, a console log message like this should display:

Jul 14 17:58:28 swi-mdm9x15 user.info Legato: INFO | supervisor[23722]/supervisor T=main | kernelModules.c ModuleGetParams() 119 | Module ktest_module.ko uses no parameters.
Jul 14 17:58:28 swi-mdm9x15 user.info Legato: INFO | supervisor[23722]/supervisor T=main | kernelModules.c ModuleInsert() 286 | New kernel module 'ktest_module'
Jul 14 17:58:28 swi-mdm9x15 user.info kernel: [244746.908837] Driver version 1.0.0
Jul 14 17:58:28 swi-mdm9x15 user.info kernel: [244746.911157] Buona Sera

Then use lsmod on the target to check that your kernel module is listed (installed).

root@swi-mdm9x15:~# lsmod
ktest_module 648 0 - Live 0xbf0c0000 (O) <===============
ipv6 290588 14 [permanent], Live 0xbf060000
usb_storage 41365 0 - Live 0xbf04c000
sd_mod 29567 0 - Live 0xbf03f000
scsi_mod 133355 2 usb_storage,sd_mod, Live 0xbf00d000
unix 29432 659 - Live 0xbf000000