10

I am currently building an Embedded Linux for my Zybo Board from Xilinx. For this I use Buildroot. Now I want to add a driver, written in C, which can be used by a user program to write to some specific registers, enabling it to control some LEDs. When I checked the manual, it basically says the first thing to do is create a Config.in in a new package folder, where you write some text explaining the driver. Okay, I did that. But now the makefile: I don't quite understand what needs to be in there. Is it just a compile command like gcc -o ledcontrol hellofunc.c? Is there something else I need to do apart from the Config.in and Makefile?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Daiz
  • 357
  • 1
  • 3
  • 20
  • Possible duplicate of [Adding new driver code to linux source code](http://stackoverflow.com/questions/11710022/adding-new-driver-code-to-linux-source-code) – geek Nov 10 '16 at 19:38

3 Answers3

18

Fully automated out-of-tree QEMU example

A version of the setup below is also present here: https://github.com/cirosantilli/linux-kernel-module-cheat/tree/753cbe68ff50bea0982e1791c8a2178a999d8377/buildroot_packages/kernel_modules and documented at: https://cirosantilli.com/linux-kernel-module-cheat/kernel-modules-buildroot-package The setup below is full extracted from that repository however, and will work standalone.

Source tree:

  • buildroot/: Buildroot 2017.02, ideally as a git submodule
  • kernel_module/: external package with some modules, ideally tracked in the git repository
    • Config.in
    • external.mk
    • external.desc
    • Makefile
    • hello.c: hello world module
    • overlay/etc/inittab: just a minor fix to make the shell work, nothing related to the kernel module itself

kernel_module/Config.in

config BR2_PACKAGE_KERNEL_MODULE
        bool "kernel_module"
        depends on BR2_LINUX_KERNEL
        help
                Linux Kernel Module Cheat.

kernel_module/external.mk

KERNEL_MODULE_VERSION = 1.0
KERNEL_MODULE_SITE = $(BR2_EXTERNAL_KERNEL_MODULE_PATH)
KERNEL_MODULE_SITE_METHOD = local
$(eval $(kernel-module))
$(eval $(generic-package))

kernel_module/external.desc

name: KERNEL_MODULE

kernel_module/Makefile

obj-m += $(addsuffix .o, $(notdir $(basename $(wildcard $(BR2_EXTERNAL_KERNEL_MODULE_PATH)/*.c))))
ccflags-y := -DDEBUG -g -std=gnu99 -Wno-declaration-after-statement

.PHONY: all clean

obj-m += $(addsuffix .o, $(notdir $(basename $(wildcard $(BR2_EXTERNAL_KERNEL_MODULE_PATH)/*.c))))
ccflags-y := -DDEBUG -g -std=gnu99 -Wno-declaration-after-statement

.PHONY: all clean

all:
    $(MAKE) -C '$(LINUX_DIR)' M='$(PWD)' modules

clean:
    $(MAKE) -C '$(LINUX_DIR)' M='$(PWD)' clean

kernel_module/hello.c

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

MODULE_LICENSE("GPL");

static int myinit(void)
{
    printk(KERN_INFO "hello init\n");
    return 0;
}

static void myexit(void)
{
    printk(KERN_INFO "hello exit\n");
}

module_init(myinit)
module_exit(myexit)

overlay/etc/inittab

::sysinit:/bin/mount -t proc proc /proc
::sysinit:/bin/mount -o remount,rw /
::sysinit:/bin/mkdir -p /dev/pts
::sysinit:/bin/mkdir -p /dev/shm
::sysinit:/bin/mount -a
::sysinit:/bin/hostname -F /etc/hostname
::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
::shutdown:/etc/init.d/rcK
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r

Usage:

sudo apt install make gcc file bzip2 build-essential wget cpio python unzip rsync bc

git clone https://github.com/buildroot/buildroot
cd buildroot
git checkout 2017.2
make BR2_EXTERNAL="$(pwd)/../kernel_module" qemu_x86_64_defconfig
echo '
BR2_PACKAGE_KERNEL_MODULE=y
BR2_TARGET_ROOTFS_EXT2_EXTRA_BLOCKS=1024
BR2_ROOTFS_OVERLAY="overlay"
' >> .config
make olddefconfig
make BR2_JLEVEL="$(nproc)" all

qemu-system-x86_64 -M pc -kernel output/images/bzImage -drive file=output/images/rootfs.ext2,if=virtio,format=raw -append 'root=/dev/vda console=ttyS0' -net nic,model=virtio -nographic -serial mon:stdio -net user

QEMU opens up, then run:

modprobe hello
modprobe -r hello

dmesg shows:

hello init
hello exit

The key line is $(eval $(kernel-module)) in external.mk, which sets everything up for us, and installs the modules where modprobe will find them (/lib/modules/*/extra/hello.ko), including modules.dep for inter-module dependencies: How to call exported kernel module functions from another module?

How to GDB step debug the kernel modules: How to debug Linux kernel modules with QEMU?

To autoload modules at startup, use BR2_ROOTFS_OVERLAY="../rootfs_overlay" and a rootfs_overlay/etc/init.d/S99modules file that does the modprobe.

In-tree example: https://github.com/cirosantilli/buildroot/tree/9580078b98f885ca94e4dfc896265a8a491f6ae1 It is less clean, but also works.

Tested on a Ubuntu 16.04 hoste.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
6

What you are looking for is the kernel-modules infrastructure.You can take a look at the Buildroot manual here:

https://buildroot.org/downloads/manual/manual.html#_infrastructure_for_packages_building_kernel_modules

Or at the numerous examples using the kernel-modules infrastructure provided by Buildroot that assists in kernel modules addition to Buildroot:

$ git grep "(kernel-module)" -- package/
package/amd-catalyst/amd-catalyst.mk:$(eval $(kernel-module))
package/batman-adv/batman-adv.mk:$(eval $(kernel-module))
package/cryptodev-linux/cryptodev-linux.mk:$(eval $(kernel-module))
package/emlog/emlog.mk:$(eval $(kernel-module))
package/freescale-imx/kernel-module-imx-gpu-viv/kernel-module-imx-gpu-viv.mk:$(eval $(kernel-module))
package/igh-ethercat/igh-ethercat.mk:$(eval $(kernel-module))
package/iqvlinux/iqvlinux.mk:$(eval $(kernel-module))
package/ktap/ktap.mk:$(eval $(kernel-module))
package/linux-backports/linux-backports.mk:$(eval $(kernel-module))
package/lttng-modules/lttng-modules.mk:$(eval $(kernel-module))
package/nvidia-driver/nvidia-driver.mk:$(eval $(kernel-module))
package/ocf-linux/ocf-linux.mk:$(eval $(kernel-module))
package/on2-8170-modules/on2-8170-modules.mk:$(eval $(kernel-module))
package/owl-linux/owl-linux.mk:$(eval $(kernel-module))
package/pkg-kernel-module.mk:#   $(eval $(kernel-module))
package/pkg-kernel-module.mk:#   $(eval $(kernel-module))
package/rtl8188eu/rtl8188eu.mk:$(eval $(kernel-module))
package/rtl8821au/rtl8821au.mk:$(eval $(kernel-module))
package/simicsfs/simicsfs.mk:$(eval $(kernel-module))
package/sysdig/sysdig.mk:$(eval $(kernel-module))

Yeah, I guess I could write a longish reply, but I would be just copying the Buildroot manual. So let's honor the braves developers that have written such clean documentation and such clean code (Buildroot core is really clean, and each package is extensively reviewed so they are usually very well written too).

Ezequiel Garcia
  • 1,037
  • 8
  • 20
  • Thank you for the link! In the first example they state a *.tar file as source. How do I use the source code of the driver (written in C)? Can I simply use it as source? – Daiz Oct 28 '16 at 21:05
  • @Daiz, SITE_METHOD=local is meant for that. Take a look at 17.5.2. generic-package reference here https://buildroot.org/downloads/manual/manual.html#_infrastructure_for_packages_with_specific_build_systems – Ezequiel Garcia Oct 31 '16 at 22:34
2

Everything in Ciro's post is accurate. However for anyone new to buildroot it might not be immediately obvious that any changes to Linux configuration through make linux-menuconfig will require either a full rebuild of the project or a manual rebuild of your module. See this discussion thread and these documentation updates.

dan
  • 31
  • 1
  • 5
  • Hi Dan, a separate answer is fine in this case to me so you can get deserved reputation on corrections. Just one thing, are you sure that this dependency is needed? From the manual, it seems to be that this should be done automatically by `$(eval $(kernel-module))` https://buildroot.org/downloads/manual/manual.html#_infrastructure_for_packages_building_kernel_modules "The dependency on linux is automatically added, so it is not needed to specify it in FOO_DEPENDENCIES.". – Ciro Santilli OurBigBook.com Sep 29 '19 at 18:25
  • 1
    Hi Ciro, thanks for the pointer. I agree the documentation is clear this should not be required, and the related documentatation change and dependency addition logic [here](https://github.com/buildroot/buildroot/blame/master/package/pkg-kernel-module.mk#L53) came after the mailing list post I referenced. I noticed a case where my module rebuild was failing, which appeared to resolve after I noticed the mailing list post and added the dependency manually. I'll need to look into this further to understand what was really happening. Thanks for your post. – dan Sep 30 '19 at 19:29
  • OK, let me know if you find anything Dan. – Ciro Santilli OurBigBook.com Sep 30 '19 at 20:51
  • 1
    @CiroSantilli新疆改造中心法轮功六四事件 this was my fundamental misunderstanding about how Buildroot dependencies work, confirmed with [this thread on the mailing list](http://lists.busybox.net/pipermail/buildroot/2019-October/262685.html) and addressed with [this documentation patch](http://lists.busybox.net/pipermail/buildroot/2019-October/262834.html) – dan Oct 17 '19 at 05:23