Confluence will be unusable 23-July-2024 at 06:00 due to a Crowd upgrade.
Stock versions of the Linux kernel will boot, but often times it does not have support (a driver) for hardware devices that we use at SLAC. It's also possible that the driver exists in the Linux kernel but we need a different version of it.
This document describes how to add a kernel module to buildroot, which is what we use to build our Linux RT kernels.
What we don't want to do is put the source code for a kernel module outside our buildroot customizations. While it is technically possible to build the kernel module outside buildroot, the next time we have a new buildroot (artifacts) the kernel module that you build may not work with the kernel, and definitely won't work if we change the version identifier of the kernel. Because we need to differentiate our kernel versions, we really want to change the version identifier of the kernel.
We also don't want to have source code contributing to our buildroot (artifacts) saved in various locations.
Buildroot (tool) provides a mechanism for integrating just about every kind of project you could possibly think of. One of them is a kernel module. Another one of them is a kernel module with user space library (.a / .so) support, as is very typical.
If we use the buildroot-defined mechanism for including projects, then the kernel module will always work (modulo bugs, etc.) with the built kernel, and the source code for the kernel and user space libraries will stay with buildroot (tool).
Buildroot has great documentation. Mostly follow the documentation here, but also the generic documentation for adding packages starting here. Be aware that the documentation for your specific version of buildroot may vary slightly, so make sure you compare with the documentation that you download when you download and unzip buildroot, which you can find at docs/manual/manual.text.
What I write about in the remainder of this document is distilled from buildroot's documentation, and having gone through this exercise once with an Intel driver.
Your kernel module is a customization, so it must be in the "site" directory. This is what gets checked into git, and applied (overlayed) to buildroot.
Create a directory in site/br2-external/packages/. I will call my directory intel-i40e as that's the driver I needed to upgrade. In that directory, you must create a makefile with the same name as the directory. So, I have intel-i40e.mk. You also need a file named Config.in that defines your config option in "make menuconfig". Your config option will appear under "External options" in "make menuconfig" and I'm not sure if that is customizable. The format of Config.in is well defined in the buildroot documentation. The coding style is also important, as your code will not build it it's the wrong style!
Inside your makefile (intel-i40e.mk) you must define how the source code is found, how it is compiled/linked, and how to install it on (in) the rootfs. Generally, the buildroot (tool) has macros available that make it easy to define this. For example, if your code is available for download as a .tar.gz, you simply supply the URL, as you see on lines 7-9 here.
1 ################################################################################ 2 # 3 # intel-i40e 4 # 5 ################################################################################# 6 7 INTEL_I40E_VERSION = 2.23.17 8 INTEL_I40E_SOURCE = i40e-$(INTEL_I40E_VERSION).tar.gz 9 INTEL_I40E_SITE = https://downloadmirror.intel.com/786085 10 INTEL_I40E_INSTALL_STAGING = YES 11 INTEL_I40E_LICENSE = GPL-2.0 12 INTEL_I40E_LICENSE_FILES = COPYING 13 14 define INTEL_I40E_BUILD_CMDS 15 touch $(BUILD_DIR)/intel-i40e-$(INTEL_I40E_VERSION)/Makefile 16 $(TARGET_MAKE_ENV) KSRC=$(LINUX_DIR) $(MAKE) $(TARGET_CONFIGURE_OPTS) -C $(BUILD_DIR)/intel-i40e-$(INTEL_I40E_VERSION)/src default 17 gzip -v $(BUILD_DIR)/intel-i40e-$(INTEL_I40E_VERSION)/src/i40e.ko 18 gzip -v $(BUILD_DIR)/intel-i40e-$(INTEL_I40E_VERSION)/src/intel_auxiliary.ko 19 endef 20 21 define INTEL_I40E_INSTALL_STAGING_CMDS 22 $(INSTALL) -d -m 0777 $(STAGING_DIR)/lib/modules/4.14.139-rt66/kernel/drivers/ethernet 23 $(INSTALL) -D -m 0644 $(BUILD_DIR)/intel-i40e-$(INTEL_I40E_VERSION)/src/*.ko.gz $(STAGING_DIR)/lib/modules/4.14.139-rt66/kernel/drivers/ethernet 24 endef 25 26 define INTEL_I40E_INSTALL_TARGET_CMDS 27 $(INSTALL) -d -m 0777 $(TARGET_DIR)/lib/modules/4.14.139-rt66/kernel/drivers/ethernet 28 $(INSTALL) -D -m 0644 $(STAGING_DIR)/lib/modules/4.14.139-rt66/kernel/drivers/ethernet/* $(TARGET_DIR)/lib/modules/4.14.139-rt66/kernel/drivers/ethernet/ 29 endef 30 31 $(eval $(kernel-module)) 32 $(eval $(generic-package))
In my case the Intel driver was peculiar. The downloaded .tar.gz file, after unpacking, wants to be built from within the src directory. I could have moved the src code, or not unzipped anything except the src directory, or had the top-level build call another build in the src directory. But what I did was implement a custom build command, using the <package>_BUILD_CMDS macro. It directly calls make in the src directory. And because we already have a custom build command, I also gzip the resulting kernel modules, just because I noticed the other kernel modules in our Linux RT were gzipped.
On line 15 I am creating an empty Makefile, just because buildroot (tool) expects a Makefile to be present in the top-level directory. The package would not build without it.
I define where I want the resulting kernel modules to be installed in the rootfs on lines 27 and 28. There is probably a macro that defines this, so you don't need <package>_TARGET_CMDS, but I could not find the macro.
Lines 31 and 32 call the appropriate targets - this is boilerplate from buildroot (tool).
Now if you run "make menuconfig" you should see "External options" and in there you will find your config option as you defined it in your Config.in.
Now when you run "make" your package will follow the rules that you have defined.
Note that you can put "echo" statements in the defined rules, just to follow the progress to see what passed or failed, or what values macros have.
Also note that if you're building a kernel module, you must reference the buildroot (artifact) kernel and kernel header files. Not the host's kernel and kernel header files. The kernel module's Makefile will probably give you a way to define where to find those things. In my case, I needed to define the KSRC macro when calling "make" (line 16).