21

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?

25
+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

| improve this answer | |
  • 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. – PNDA 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. – PNDA 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. – PNDA Jan 2 '16 at 8:51
6

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.
| improve this answer | |
  • 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. – PNDA 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". – PNDA 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
2

in getKernel.sh file add

sudo modprobe configs

before

zcat /proc/config.gz >.config

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

| improve this answer | |

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