How to get started writing a kernel module

As I have set up the build system, I want to cross-compile a sample kernel module and load it into my physical device as an experiment. Is there any source like that?

You need to have a kernel built for at least that device arch first, what is the device you are using?

Raspberry Pi 3 Model B

Then it's easy, basically the same as building an image.
Just after that, you add a package and can compile whatever you want.
You can use the mt7621-qtn-rgmii as an example

Is every kernel module a package? Can't I write a kernel module and generate the .ko by cross-compilation and take the .ko file and load it to the real device?
FYI, my RPi device is running an image alredy.

In OpenWrt yes, the easiest way is to make it a package and then you can take its .ko as output or just install it as a package
Otherwise you would have to patch the kernel

1 Like

// You can use the mt7621-qtn-rgmii as an example//
Can you please tell why whenever I want to make it, it says:

root@vision:~/openwrt# make ./package/kernel/mt7621-qtn-rgmii
make: 'package/kernel/mt7621-qtn-rgmii' is up to date.

Again, wrong!!

make package/kernel/mt7621-qtn-rgmii/compile V=s

1 Like

My bad. Thank you. But this time it says make[2]: Nothing to be done for 'compile'. the .ko file is not generated.

root@vision:~/openwrt# make package/kernel/mt7621-qtn-rgmii/compile V=s
make[2]: Entering directory '/root/openwrt/scripts/config'
make[2]: 'conf' is up to date.
make[2]: Leaving directory '/root/openwrt/scripts/config'
make[1]: Entering directory '/root/openwrt'
make[2]: Entering directory '/root/openwrt/package/kernel/mt7621-qtn-rgmii'
make[2]: Nothing to be done for 'compile'.
make[2]: Leaving directory '/root/openwrt/package/kernel/mt7621-qtn-rgmii'
time: package/kernel/mt7621-qtn-rgmii/compile#0.24#0.04#0.27
make[1]: Leaving directory '/root/openwrt'

Because it depends on MT7621 being the architecture, just use the package to copy/paste it and edit to suit your needs

1 Like

I've actually changed the the source code (the .c file) keeping the Makefile unchanged.

You have to remove the dependecy on mt7621 target, and hidden property so you can select it in menuconfig so it actually compiles.

The kernel module I linked to was just as an example. It has a very simple Makefile, only one source file so I figured since you already wrote kernel modules for Ubuntu it shouldn't be to hard to modify to you actual needs.

As others have stated: building the .ko file and transferring to your device during development is faster (easier) than patching your source into the kernel and having to recompile the whole kernel. If you want you should be able to actually compile directly on the RPi3 but I'm not sure if the time to set that up plus likely longer waiting times to compile would actually benefit you. (see: building openwrt on openwrt )

1 Like

Thanks for your time.
I have no problem with cross-compiling, in fact, I've set up the build system on a powerful machine. The Makefile I used to use to compile modules in ubuntu seemed to me easier and easy to understand. But in this case the module you linked, I'm really struggling to figure out where I should make the change in the Makefile to work with this .c file.

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

static int __init hello_init(void)
    printk(KERN_INFO "Hello, world\n");
    return 0;

static void __exit hello_exit(void)
    printk(KERN_INFO "Goodbye, world\n");



I made this commented Helloworld Makefile when I first started building. Not geared to kmods, but might give some insight into buildroot Makefile Structure.

include $(TOPDIR)/

# Name, version and release number
# The name and version of your package are used to define the variable to point to the build directory of your package: $(PKG_BUILD_DIR)

# Source settings (i.e. where to find the source code)
# This is a custom variable, used below

include $(INCLUDE_DIR)/

# Package definition; instructs on how and where our package will appear in the overall configuration menu ('make menuconfig')
define Package/helloworld
        TITLE:=Hello, World!

# Package description; a more verbose description on what our package does
define Package/helloworld/description
        A simple "Hello, world!" -application.

# Package preparation instructions; create the build directory and copy the source code.
# The last command is necessary to ensure our preparation instructions remain compatible with the patching system.
define Build/Prepare
        mkdir -p $(PKG_BUILD_DIR)
        cp $(SOURCE_DIR)/* $(PKG_BUILD_DIR)

# Package build instructions; invoke the target-specific compiler to first compile the source file, and then to link the file into the final executable
define Build/Compile
        $(TARGET_CC) $(TARGET_CFLAGS) -o $(PKG_BUILD_DIR)/helloworld.o -c $(PKG_BUILD_DIR)/helloworld.c
        $(TARGET_CC) $(TARGET_LDFLAGS) -o $(PKG_BUILD_DIR)/$1 $(PKG_BUILD_DIR)/helloworld.o

# Package install instructions; create a directory inside the package to hold our executable, and then copy the executable we built previously into the folder
define Package/helloworld/install
        $(INSTALL_DIR) $(1)/usr/bin
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/helloworld $(1)/usr/bin

# This command is always the last, it uses the definitions and variables we give above in order to get the job done
$(eval $(call BuildPackage,helloworld))

Your Makefile is quite similar to what I got in this guide:
Unfortunately, I've followed this guide, and though I've got no error the .ipk file is not generated in the expected directory.

Create a folder: since you are making a kernel module, put in in ~/openwrt/package/kernel and lets call it "hello-world"
Inside that folder create a sub-folder called "src"
Inside the "hello-world" folder create a almost minimal Makefile like:

# Copyright (C) 2006-2009
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.

include $(TOPDIR)/
include $(INCLUDE_DIR)/


include $(INCLUDE_DIR)/

define KernelPackage/hello-world
  CATEGORY:=Kernel modules
  SUBMENU:=Other modules
  TITLE:=Hello World Kernel Module

define Build/Compile
	$(MAKE) -C "$(LINUX_DIR)" \
		M="$(PKG_BUILD_DIR)" \

$(eval $(call KernelPackage,hello-world))

In your "src" sub-folder you should have a file with the source code from your post above. Lets call that: "hello-world.c"

Now add another Makefile INSIDE the src folder:

obj-m += hello-world.o

Again: those are simple files, add more fancy stuff as you get more comfortable (or need extra).

from ~/openwrt and as normal user:

make package/hello-world/compile V=s

V=s is optional but I would recommend to see any errors.
Change the source and I recommend:

make package/hello-world/{clean,compile} V=s

you will end up the an kmod-hello-world_(kernel version)(version)(target).ipk in ~/openwrt/bin/target/(whatever your target)/packages

in ~/openwrt/build_dir/(target)/(linux)/hello-world you end up the everything the original "src" folder plus anything that was needed to build the .ko file and the .ipkg stuff.

DON'T forget to do a "make menuconfig" and select your module (either as * or M, but I would use M for clarity). Inside "kernel modules/Other modules" as defined in the "top" Makefile.


Do I need to select it in menuconfig before running make package/hello-world/compile V=s?

Thanks a lot. I've successfully created the .ipk files and .ko.
I've loaded the .ko and installed the .ipk. When the module is loaded I see the log messages in the system log as written in the source code. But what are the similar outcomes for the installed package? Can a package be used just like its corresponding module? What is the relation between them?

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.