How to write a FreeBSD Kernel Module

You may be think that writing your first kernel module is going to be a long, painful, grueling task, but really it is only slightly harder than writing your first program, Hello World!, in C or C++.

Lets break this into nice easy steps.

Prerequisites

It is assumed you have installed FreeBSD already. If not, follow the instructions below with one change: Install the FreeBSD source during the “Choose Distribution” section.

How do I install FreeBSD?

Step 1 – Create a basic module file

A FreeBSD kernel module is written in C. This is going to be only a slightly harder than writing hello world in C. We are going to create a single text file with a .c extension and put some C code in it.

  1. Create a folder to hold you project. I used this directory:
    /usr/home/jared/code/kernel/hwm
  2. Create the file to hold your code. I named my file this:
    hello_world_kmod.c
  3. Edit the file with you favorite editor, vi, vim, emac, ee. I used easy editor (ee):
    ee hello_world_kmod.c
  4. Add the following code to the file.I have broken the code of the simplest kernel module into four parts or steps:
    1. Add four required #include statements.
    2. Create the kernel load/unload event handler.
    3. Create a struct to name the module and point to the event handler function.
    4. Call the DECLARE_MODULE macro.
    /*
     * Step 1 - Add the four needed libraries to include
     */
    #include <sys/param.h>
    #include <sys/module.h>
    #include <sys/kernel.h>
    #include <sys/systm.h>
    
    /*
     * Step 2 - Handle the load/unload event
     */
    static int EventHandler(struct module *inModule, int inEvent, void *inArg)
    {
            // Set return code to 0
            int returnCode = 0;
    
            switch (inEvent)
            {
              case MOD_LOAD:
                    uprintf("Hello, World! \n");
                    break;
              case MOD_UNLOAD:
                    uprintf("Bye, World! \n");
                    break;
              default:
                    returnCode = EOPNOTSUPP;
                    break;
            }
    
            return(returnCode);
    }
    
    /*
     * Step 3 - Name the module and the event hander function
     *          This is done using a struct of type moduledata_T
     */
    static moduledata_t  moduleData = {
            "hello_world_kmod",     // Module Name
            EventHandler,           // Event handler function name
            NULL                    // Extra data
    };
    
    /*
     * Step 4 - Declare the module
     *          This is done with the DECLARE_MODULE macro
     */
    DECLARE_MODULE(hello_world_kmod, moduleData, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
    
  5. Save and close the file.

Step 2 – Create a Makefile

Creating a Makefile to build a kernel module is quite easy because almost all the work is done for you. FreeBSD has a file that you include, /usr/src/share/mk/bsd.kmod.mk, that does most of the work for you and all you have to do is include it.

  1. In the same directory where you put your .c file, create a new text file called Makefile.
  2. There are three basic parts to the kernel module Makefile:
    1. Module name
    2. Source files
    3. Include of bsd.kmod.mk
    # Module Name
    KMOD = hello_world_kmod
    
    # Source files
    
    SRCS = hello_world_kmod.c
    
    # Include <bsd.kmod.mk>
    .include <bsd.kmod.mk>
    
  3. Save and close the file.

Step 3 – Run make to build the module

  1. In the command prompt, in the directory where you have created your code and make file, run make.
    > cd /usr/home/jared/code/kernel/hwm
    > make
    Warning: Object directory not changed from original /usr/home/jared/code/kernel/hwm
    @ -> /usr/src/sys
    machine -> /usr/src/sys/amd64/include
    x86 -> /usr/src/sys/x86/include
    cc -O2 -pipe -fno-strict-aliasing -Werror -D_KERNEL -DKLD_MODULE -nostdinc   -I. -I@ -I@/contrib/altq -finline-limit=8000 --param inline-unit-growth=100 --param large-function-growth=1000 -fno-common  -fno-omit-frame-pointer  -mno-sse -mcmodel=kernel -mno-red-zone -mno-mmx -msoft-float  -fno-asynchronous-unwind-tables -ffreestanding -fstack-protector -std=iso9899:1999 -fstack-protector -Wall -Wredundant-decls -Wnested-externs -Wstrict-prototypes  -Wmissing-prototypes -Wpointer-arith -Winline -Wcast-qual  -Wundef -Wno-pointer-sign -fformat-extensions  -Wmissing-include-dirs -fdiagnostics-show-option -c hello_world_kmod.c
    ld  -d -warn-common -r -d -o hello_world_kmod.ko hello_world_kmod.o
    :> export_syms
    awk -f /sys/conf/kmod_syms.awk hello_world_kmod.ko  export_syms | xargs -J% objcopy % hello_world_kmod.ko
    objcopy --strip-debug hello_world_kmod.ko
    >
    

Step 4 – Test loading an unloading the module

Loading and unloading kernel modules must be done as root. If you have sudo installed, use it, otherwise install it (Configuring sudo on FreeBSD) or su to root.

  1. Use kldload to load the module and kldunload to unload the module.
    > sudo kldload ./hello_world_kmod.ko
    Hello, World!
    > sudo kldunload ./hello_world_kmod.ko
    Bye, World!
    >
    

You have now performed the Hello World version of a FreeBSD kernel module.

Resources

One Comment

  1. [...] Jared Barneck says, You may be think that writing your first kernel module is going to be a long, painful, grueling task, but really it is only slightly harder than writing your first program, Hello World!, in C or C++. Lets break this into nice easy steps. Read more. [...]

Leave a Reply

Powered by sweetCaptcha