Linux kernel development

Building a Linux kernel module on Red Hat-derived distributions requires the kernel-devel package. Place the following in hello.c:

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

int init_module(void)
{
        /* NOTE: See kern_levels.h for level constants. */
        printk(KERN_INFO "Hello, world!\n");

        return 0;
}

void cleanup_module(void)
{
        printk(KERN_INFO "Goodbye, world!\n");
}

MODULE_LICENSE("GPL");

Place the following in Makefile:

obj-m += hello.o

all:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Build the module using make. Load the module using insmod hello.ko, and remove it using rmmod hello; upon completing either, you should see a message recorded by the computer’s logging system.

Receiving parameters at module load time

The module_param and MODULE_PARM_DESC macros aid in declaring and documenting kernel-module parameters, respectively. The module_param macro takes as arguments a parameter name, parameter type, and a series of permission bits which, if non-zero, apply to a sysfs entry that the module might later create. Each use of module_param should correspond with a global variable which shares the name of the parameter.

static char *option = "default value";

module_param(option, charp, 0000);
MODULE_PARM_DESC(option, "An example character string option");

The sample option above could be set using the command insmod hello.ko option=foo.

Reproducing the kernel source used to build the kernel for a Red Hat-derived distribution

These steps require the dnf-utils and rpm-build packages, along with the compiler and other tools needed to build the Linux kernel.

  1. yumdownloader --source kernel
  2. rpm -Uvh kernel...
  3. rpmbuild -bp ~/rpmbuild/SPECS/kernel.spec

This will result in a copy of the kernel source tree at ~/rpmbuild/BUILD/kernel.... One way to build the kernel is to modify this source tree, produce a patch, place the patch in ~/rpmbuild/SOURCES, modify ~/rpmbuild/SPECS/kernel.spec to make use of the patch, and rebuild the kernel using rpmbuild -ba ~/rpmbuild/SPECS/kernel.spec:

  1. Make a vanilla copy of the kernel source: cp -a ~/rpmbuild/BUILD/kernel.../linux.../ ~/rpmbuild/BUILD/kernel.../linux...-vanilla/.
  2. Add pr_notice("Hello, world!\n"); to ~/rpmbuild/BUILD/kernel.../linux.../init/main.c immediately after the kernel prints "Kernel command line: ...".
  3. Set your current directory to ~/rpmbuild/BUILD/kernel.../ and create a patch by running diff -u --recursive linux...-vanilla/ linux.../ >~/rpmbuild/SOURCES/kernel-hello.patch.
  4. Add the patch to the kernel’s RPM specification by adding Patch2: kernel-hello.patch to ~/rpmbuild/SPECS/kernel.spec after the definition of Patch1.
  5. Set the specification to apply your patch by adding ApplyOptionalPatch kernel-hello.patch after the application of patch-%{patchversion}-redhat.patch.
  6. Run rpmbuild -ba ~/rpmbuild/SPECS/kernel.spec to build the result. This will take a long time, and it will use a lot of disk space.

Finally run rpm -ivh ~/rpmbuild/RPMS/x86_64/kernel-* to install your new kernel, and reboot the computer. After booting, you should find that dmesg includes Hello, world! in its output.