I have read quite a bit about how to compile a kernel module on (and for) the Raspberry Pi, but I'm still not quite able to figure out why it's not working. I have been able to build the module, but it reports Invalid module format when I try to insmod the result. Here is the process I followed. First, as root under /root I executed the following shell script:

getKernel.sh

#! /usr/bin/bash
FIRMWARE_HASH=$(zgrep "* firmware as of" /usr/share/doc/raspberrypi-bootloader/changelog.Debian.gz | head -1 | awk '{ print $5 }')
KERNEL_HASH=$(wget https://raw.githubusercontent.com/raspberrypi/firmware/$FIRMWARE_HASH/extra/git_hash -O -)
git clone https://github.com/raspberrypi/linux 
cd linux
git checkout $KERNEL_HASH
wget https://raw.githubusercontent.com/raspberrypi/firmware/$FIRMWARE_HASH/extra/Module.symvers 
zcat /proc/config.gz >.config
make oldconfig
make modules_prepare
ln -s /root/linux /lib/modules/$(uname -r)/build 

The first few lines are from http://lostindetails.com/blog/post/Compiling-a-kernel-module-for-the-raspberry-pi-2

The rest I wrote to automate more of the process. Once all of that runs successfully, I have the source that should exactly match the running kernel, the configuration to match and a symlink. There were some redirects from the github web location (apparently it's now https://raw.githubusercontent.com/ ) but no actual errors.

Then I become the default pi user and in a directory named /home/pi/projects/lkm I have this source code for a very simple toy module:

hello.c

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

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Do-nothing test driver");
MODULE_VERSION("0.1");

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");
}

module_init(hello_init);
module_exit(hello_exit);

Finally, I build the module with this Makefile

Makefile

MODSRC=/home/pi/projects/lkm
obj-m+=hello.o

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

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

Finally, I attempt to load the module:

sudo insmod hello.ko

The result, however, is disappointing:

insmod: ERROR: could not insert module hello.ko: Invalid module format

Possibly relevant details

I'm using the currently latest jessie version of Raspbian on a Raspberry Pi2.

$ uname --kernel-release --kernel-version
4.1.13-v7+ #826 SMP PREEMPT Fri Nov 13 20:19:03 GMT 2015
$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabihf/4.9/lto-wrapper
Target: arm-linux-gnueabihf
Configured with: ../src/configure -v --with-pkgversion='Raspbian 4.9.2-10' --with-bugurl=file:///usr/share/doc/gcc-4.9/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.9 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.9 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libitm --disable-libquadmath --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.9-armhf/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.9-armhf --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.9-armhf --with-arch-directory=arm --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-sjlj-exceptions --with-arch=armv6 --with-fpu=vfp --with-float=hard --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf
Thread model: posix
gcc version 4.9.2 (Raspbian 4.9.2-10) 

Unfortunately, I'm not sure how to further troubleshoot this or fix it. Any clues?

up vote 17 down vote accepted
+50

First of all, make sure you use the proper kernel headers. I assume that your kernel headers and source code are more updated than the kernel you're running.

Try to do an apt-get update && apt-get upgrade then reinstall the module. If the problem persists, triple check that your kernel headers match your current kernel, recompile again then try to install.


Note: I'm using Jessie.

UPDATE: Run these as root.

# The usual update routine
apt-get update -y
apt-get upgrade -y

# Update the kernel!
rpi-update

You may need to reboot. After that, proceed with the commands below, still using the root account.

# Get rpi-source
sudo wget https://raw.githubusercontent.com/notro/rpi-source/master/rpi-source -O /usr/bin/rpi-source

# Make it executable
sudo chmod +x /usr/bin/rpi-source

# Tell the update mechanism that this is the latest version of the script
/usr/bin/rpi-source -q --tag-update

# Get the kernel files thingies.
rpi-source

If rpi-source throws a GCC error (something about a version mismatch), it's okay as long as your current GCC version is higher. Run rpi-source --skip-gcc instead of rpi-source

Then, proceed with your Hello World example. Create the folder and cd into it. Then, create the files.

mkdir hello
cd hello

Files:

hello.c

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

int hello_init(void)
{
    pr_alert("Hello World :)\n");
    return 0;
}
void hello_exit(void)
{
    pr_alert("Goodbye World!\n");
}
module_init(hello_init);
module_exit(hello_exit);

Makefile (case-sensitive?)

obj-m := hello.o

Now that you have your files, you can go ahead and run the usual Hello World build commands:

make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
insmod hello.ko

You should now check dmesg. The last line should print Hello World :) highlighted in red.

If you do, congratulations. You just made and installed a kernel module.

Now remove it using rmmod hello. dmesg should now print Goodbye World! highlighted in red.

Sources: 1 2 3

  • When you say to "check that your kernel headers match your current kernel" how exactly do you mean I should do that? – Edward Jan 2 '16 at 1:54
  • @Edward updated. – pandalion98 Jan 2 '16 at 8:16
  • @Edward Take note that this is the hello world example. I built your module, but I realized it's the same. The only difference is that your code does not have the red highlight. – pandalion98 Jan 2 '16 at 8:47
  • @Edward In your case, I think following the instructions up until the rpi-source part is enough. You can try building yours from that point. – pandalion98 Jan 2 '16 at 8:51

There is a much simpler version here, tested on jessie and stretch.

sudo apt-get install raspberrypi-kernel-headers

and then when your files are in place :

make -C /lib/modules/$(uname -r)/build M=$(pwd) modules

Example

Create the hello directory, go inside and create the following files : hello.c and Makefile.

I recommend working as your normal user, not root, only insmod, rmmod, and make modules_install commands require root permissions, and the necessary sudo is shown in the following commands.


hello.c (unchanged, your file)

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

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Do-nothing test driver");
MODULE_VERSION("0.1");

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");
}

module_init(hello_init);
module_exit(hello_exit);

Makefile (changed)

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

modules_install: all
    $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install
    $(DEPMOD)   

Usage

  • Build : make (in the same directory as the Makefile)
  • Test
    • Insert the module with sudo insmod hello.ko
    • Find Hello World :) in the output of dmesg
    • Remove the module with sudo rmmod hello
    • Find Goodbye, world. int the output of dmesg
  • Install, when your module is working, sudo make modules_install will install the module where it belongs, so modprobe will work.
  • 1
    works very well for kernels installed by means of the 'raspberrypi-kernel' package. Contrary to that the description issued by 'pandalion98' refers to kernels installed by means of 'rpi-update'. Both methods are mutually exclusive right? – sparkie Dec 6 '17 at 9:38
  • 1
    I think this is a valid answer since OP (Edward) never talked about rpi-update, rpi-update was suggested in the pandalion98's answer – pim Dec 6 '17 at 9:44
  • @sparkie At the time of posting, the kernel was still not integrated into Raspbian's apt repository, if I'm not mistaken. Updating the kernel meant running Hexxeh's rpi-update script. These days, updating raspberrypi-kernel or running rpi-update do pretty much the same thing. – pandalion98 Dec 7 '17 at 2:22
  • As for raspberrypi-kernel-headers, it usually installs mismatched kernel headers, from experience (the headers tend to be a newer version than the kernel), hence why I opted to "go manual". – pandalion98 Dec 7 '17 at 2:25
  • there appears to be some difference between 'raspberrypi-kernel' and 'rpi-update': the one results in '4.9.66+' the other in '4.9.59+' at this moment. So I think we still have to handle both build procedures separately – sparkie Dec 7 '17 at 6:43

in getKernel.sh file add

sudo modprobe configs

before

zcat /proc/config.gz >.config

(now in default rpi image /proc/config.gz not exist)

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.