Как добавить модуль ядра ядра Linux в качестве пакета Buildroot?

В настоящее время я создаю встроенный Linux для своей платформы Zybo от Xilinx. Для этого я использую Buildroot. Теперь я хочу добавить драйвер, написанный на C, который может использоваться пользовательской программой для записи в определенные регистры, позволяя ей управлять некоторые светодиоды. Когда я проверил manual, в основном говорится, что первое, что нужно сделать, это создать Config.in в новой папке пакета, где вы пишете некоторый текст, объясняющий водителя. Хорошо, я сделал это. Но теперь make файл: я не совсем понимаю, что должно быть там. Это просто команда компиляции, например gcc -o ledcontrol hellofunc.c? Есть ли что-то еще, что мне нужно сделать, помимо Config.in и Makefile?

Ответ 1

Полностью автоматизированный пример QEMU из дерева

https://github.com/cirosantilli/linux-kernel-module-cheat/tree/753cbe68ff50bea0982e1791c8a2178a999d8377/buildroot_packages/kernel_modules

Исходное дерево:

  • buildroot/: подмодуль Buildroot 2017.02
  • kernel_module/: внешний пакет с некоторыми модулями
    • Config.in
    • external.mk
    • Makefile
    • hello.c: модуль Hello World

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/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

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)

Использование:

cd buildroot
make BR2_EXTERNAL="$(pwd)/../kernel_module" qemu_x86_64_defconfig
echo 'BR2_PACKAGE_KERNEL_MODULE=y' >> .config
make BR2_JLEVEL="$(($(nproc) - 2))" 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 -net nic,model=virtio -net user

QEMU открывается, затем запускается:

root
modprobe hello
modprobe -r hello

dmesg показывает:

hello init
hello exit

Ключевой линией является $(eval $(kernel-module)) в external.mk, которая все настраивает для нас и устанавливает модули, где modprobe их найдет (/lib/modules/*/extra/hello.ko), включая modules.dep для межмодульных зависимостей: Как вызвать экспортированные функции модуля ядра из другого модуля?

Как выполнить отладку модулей ядра в GDB: Как отлаживать модули ядра Linux с помощью QEMU?

Для автоматической загрузки модулей при запуске используйте BR2_ROOTFS_OVERLAY="../rootfs_overlay" и файл rootfs_overlay/etc/init.d/S99modules, который выполняет modprobe.

Пример в дереве: https://github.com/cirosantilli/buildroot/tree/9580078b98f885ca94e4dfc896265a8a491f6ae1 Он менее чистый, но также работает.

Протестировано на хосте Ubuntu 16.04.

Ответ 2

Что вам нужно, так это инфраструктура модулей ядра. Вы можете взглянуть на руководство по Buildroot здесь:

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

Или на многочисленных примерах использования инфраструктуры модулей ядра, предоставляемой Buildroot, которая помогает в добавлении модулей ядра в 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))

Да, думаю, я мог бы написать длинный ответ, но я бы просто скопировал руководство по Buildroot. Так что позвольте почтить смелых разработчиков, которые написали такую чистую документацию и такой чистый код (ядро Buildroot действительно чистое, и каждый пакет тщательно проверяется, поэтому они, как правило, тоже очень хорошо написаны).

Ответ 3

Все в посте Ciro является точным. Однако для любого новичка в buildroot может быть не сразу очевидно, что любые изменения в конфигурации Linux через make linux-menuconfig потребуют либо полной перестройки проекта, либо перестройки вашего модуля вручную. Смотрите эту ветку обсуждения и эти обновления документации.