Ajay on Non-MMU Embedded Linux
Making a buildroot based Hello world Kernel Module for STM32F469

kmod: Hello World

Moving on we build a kernel module that prints hello world when loaded. Simple enough but it is integrated into buildroot so we can build it along with the kernel and rootfs.

1. Skeleton Directory structure

A new package is added to the external tree we created earlier. The folder structure is as below. Again just create empty files for now.

br2-ext-stm32f469/
├─ package/
│  ├─ kmod_hello/
│     ├─ Config.in
│     ├─ kmod-hello.mk
│     ├─ Makefile
│     └─ hello.c

2. External tree boilerplate

This time its a Kernel module and depends on the kernel being built. So we add a dependency in the Config.in file.

package/kmod_hello/Config.in

config BR2_PACKAGE_KMOD_HELLO
    bool "hello kernel module"
    depends on BR2_LINUX_KERNEL      # only make sense if we build a kernel
    help
      Simple out-of-tree hello-world kernel module.

package/kmod_hello/kmod-hello.mk

Kernel modules depend on ARCH and CROSS_COMPILE variables to build. We also need to tell it where the kernel source is. Buildroot provides a variable LINUX_DIR for that. ARCH is an ARM type and CROSS_COMPILE is the toolchain prefix.

################################################################################
#
# kmod-hello
#
################################################################################

KMOD_HELLO_VERSION = 1.0
KMOD_HELLO_SITE = $(BR2_EXTERNAL_SS_STM32F469_EXT_PATH)/package/kmod_hello
KMOD_HELLO_SITE_METHOD = local
KMOD_HELLO_LICENSE = GPL-2.0
KMOD_HELLO_DEPENDENCIES = linux

# Build the module against the kernel Buildroot is building
define KMOD_HELLO_BUILD_CMDS
	$(MAKE) -C $(LINUX_DIR) M=$(@D) \
		ARCH=$(KERNEL_ARCH) CROSS_COMPILE="$(TARGET_CROSS)" \
		modules
endef

# Install into the target rootfs under /lib/modules/$(uname -r)/
define KMOD_HELLO_INSTALL_TARGET_CMDS
	$(MAKE) -C $(LINUX_DIR) M=$(@D) \
		INSTALL_MOD_PATH=$(TARGET_DIR) \
		modules_install
endef

$(eval $(generic-package))

package/kmod_hello/Makefile

This is going to be kernel module, becomes a .ko file when built.

# Kbuild-style makefile for an out-of-tree module
obj-m += hello.o

package/kmod_hello/hello.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ajay Sharma");
MODULE_DESCRIPTION("Hello-world kernel module");
MODULE_VERSION("1.0");

static int __init hello_init(void)
{
    pr_info("kmod-hello: hello from STM32F469!\n");
    return 0;
}

static void __exit hello_exit(void)
{
    pr_info("kmod-hello: goodbye!\n");
}

module_init(hello_init);
module_exit(hello_exit);

3. Enable and Build the kernel module

The default kernel for STM32F469 does not have kernel module support enabled. So first we need to enable that in the kernel config. Check the loadable module support to enable it.

$ make linux-menuconfig

Alt linux-menuconfig 1

Fig 1: make linux-menuconfig

Now enable the kernel module we created.

$ make menuconfig

Alt menuconfig 2

Fig 2: make menuconfig

Esc -> Esc -> Yes to save the config.

4. Kernel Utilities

The kernel module can be loaded using insmod and removed using rmmod commands. These commands are part of the busybox package in buildroot. So we need to enable that too.

$ make busybox-menuconfig

Alt busybox-menuconfig 3

Fig 3: make busybox-menuconfig

Then build the system:

make

After completion the kernel module will be built and installed into the rootfs. It usually stored in the following folder

buildroot/output/images/rootfs/lib/modules/5.15.176/extra/hello.ko

5.15.176 is my kernel version, it may vary. Use your version.

5. Test the kernel module

Copy the rootfs to your SD card using the method we did before: bmaptool and boot the board. Login to the board using serial console.

Now we can load the kernel module using insmod command.

Alt insmod hello

Fig 4: insmod hello

The message from the kernel module can be seen using dmesg command.

Alt dmesg hello

Fig 5: dmesg hello

This article was originally published on My Blog.

Next we continue doing something interesting …