如何添加Linux内核驱动模块作为Buildroot包?

问题描述 投票:0回答:3

我目前正在为 Xilinx 的 Zybo 开发板构建嵌入式 Linux。为此,我使用 Buildroot。现在我想添加一个用 C 语言编写的driver,用户程序可以使用它来写入一些特定的寄存器,从而使其能够控制一些 LED。当我检查手册时,它基本上说要做的第一件事是在新的包文件夹中创建一个 Config.in,您可以在其中编写一些解释驱动程序的文本。好吧,我就是这么做的。但现在 makefile:我不太明白里面需要什么。它只是像

gcc -o ledcontrol hellofunc.c
这样的编译命令吗?除了 Config.in 和 Makefile 之外,我还需要做些什么吗?

c embedded-linux xilinx buildroot
3个回答
19
投票

全自动树外 QEMU 示例

此处还提供了以下设置的版本:https://github.com/cirosantilli/linux-kernel-module-cheat/tree/753cbe68ff50bea0982e1791c8a2178a999d8377/buildroot_packages/kernel_modules并记录在: https://cirosantilli.com/linux-kernel-module-cheat/kernel-modules-buildroot-package 下面的设置是从该存储库中完全提取的,并且可以独立工作。

源树:

  • buildroot/
    :Buildroot 2017.02,最好作为 git 子模块
  • kernel_module/
    :带有一些模块的外部包,最好在 git 存储库中跟踪
    • Config.in
    • external.mk
    • external.desc
    • Makefile
    • hello.c
      :你好世界模块
    • overlay/etc/inittab
      :只是一个让 shell 工作的小修复,与内核模块本身无关

内核模块/Config.in

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

内核模块/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

内核模块/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

内核模块/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)

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

用途:

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 打开,然后运行:

modprobe hello
modprobe -r hello

dmesg
显示:

hello init
hello exit

关键行是

$(eval $(kernel-module))
中的
external.mk
,它为我们设置了所有内容,并安装了
modprobe
可以找到它们的模块 (
/lib/modules/*/extra/hello.ko
),包括用于模块间依赖关系的
modules.dep
如何从另一个模块调用导出的内核模块函数?

如何使用 GDB 单步调试内核模块:如何使用 QEMU 调试 Linux 内核模块?

要在启动时自动加载模块,请使用

BR2_ROOTFS_OVERLAY="../rootfs_overlay"
和执行
rootfs_overlay/etc/init.d/S99modules
操作的
modprobe
文件。

树内示例:https://github.com/cirosantilli/buildroot/tree/9580078b98f885ca94e4dfc896265a8a491f6ae1它不太干净,但也有效。

在 Ubuntu 16.04 主机上测试。


6
投票

您正在寻找的是内核模块基础设施。您可以在此处查看Buildroot手册:

https://buildroot.org/downloads/manual/manual.html#_infrastruct_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 核心非常干净,每个包都经过了广泛的审查,因此它们通常也写得很好)。


2
投票

Ciro 帖子中的所有内容都是准确的。 然而,对于刚接触 buildroot 的人来说,通过

make linux-menuconfig
对 Linux 配置进行的任何更改都需要完全重建项目或手动重建模块,这一点可能并不明显。 请参阅此讨论主题这些文档更新

© www.soinside.com 2019 - 2024. All rights reserved.