Compiling Kernel Modules for Raspberry Pi

3 minute read,

image

I tried loading rpi-pwm on my Raspberry Pi, but ran into some issues. After some tinkering I was able to compile rpi-pwm.c on the Raspberry Pi, but I kept running into Invalid Format issues anytime I tried to insmod rpi-pwm.ko which had the following dmesg:

rpi_pwm: disagrees about version of symbol module_layout

I guess this generally means I need to compile my module in the same way the kernel is compiled on the Raspberry Pi. Otherwise, the kernel will reject the module.

I’ve found that cross-compiling works best. This means, building your kernel and modules on a different platform rather than on the Raspberry Pi hardware directly. I did NOT have any luck compiling my kernel module directly on Raspberry Pi hardware.

In detail, first you’ll want to cross-compile the Raspberry Pi Linux kernel so it builds Module.symvars and other intermediates. You won’t actually use the kernel that is being cross-compiled, just the intermediates to compile your module. Next, you’ll cross-compile your module using those intermediates. Once your module is cross-compiled, copy the .ko module to your running Raspberry Pi and you should be able to load it along with the stock kernel. The following is a quick how-to cross-compile the Raspberry Pi Kernel modules on Ubuntu 12.04:

First, know what version of RPi you’re running:

uname -r and uname -a

[email protected]:/# uname -r 
3.2.27+ 
[email protected]:/# uname -a 
Linux raspberrypi 3.2.27+ #250 PREEMPT Thu Oct 18 19:03:02 BST 2012 armv6l GNU/Linux

I’ve downloaded everything into a directory called ~/rpi on my Ubuntu machine.

1. Compile the Kernel

For 3.2.27+:

(instructions generally flow from: http://elinux.org/RPi_Kernel_Compilation)

  • Install Ubuntu
  • Get the rpi-3.2.27.tar.gz tarball
  • Get the tools tarball
  • tar xzf rpi-3.2.27.tar.gz and tar xzf master.tar.gz (tools)
  • Set the environment variable CCPREFIX:
    export
    CCPREFIX=  
    /home/cowboy/rpi/tools-master/arm-bcm2708/arm-bcm2708-linux-gnueabi/bin/arm-bcm2708-linux-gnueabi-
    
  • Set the environment variable KERNEL_SRC:
    export KERNEL_SRC=/home/cowboy/rpi/linux-rpi-3.2.27
  • In KERNEL_SRC: execute make mrproper to ensure you have a clean kernel source tree.
  • Pull /proc/config.gz from your running Raspberry Pi and extract it into KERNEL_SRC on your Ubuntu machine.

    scp [email protected]:/proc/config.gz ./ (transfers it to Ubuntu)
    zcat config.gz \> .config (uncompresses .config)
    mv .config $KERNEL_SRC (moves the uncompressed .config to KERNEL_SRC) 

  • On Ubuntu: Prime kernel with the old config:
    make ARCH=arm CROSS\_COMPILE=${CCPREFIX} oldconfig
  • On Ubuntu: Build the kernel:
    make ARCH=arm CROSS\_COMPILE=${CCPREFIX}

This will produce a fresh Module.symvers and since you’re using the cross-compile tools, the intermediates the tools generate should be binaurally compatible with Raspberry Pi.

2. Compile your kernel module

Next, make a separate directory outside of KERNEL_SRC (or example: ~/pwm) and write a quick Makefile for your kernel module:

obj-m += rpi-pwm.o

all: 
    make ARCH=arm CROSS_COMPILE=${CCPREFIX} -C /home/cowboy/rpi/linux-rpi-3.2.27 M=$(PWD) modules

clean: 
    make -C /home/cowboy/rpi/linux-rpi-3.2.27 M=$(PWD) clean

(learn more about compiling Linux kernel modules here)

When you’re ready to compile your module, go ahead and execute make and you should be gold. Copy your rpi-pwm.ko to your RPI then use modinfo rpi-pwm.ko to review the module information:

[email protected]:/# modinfo rpi-pwm.ko 
filename:       /home/pi/temp/rpi-pwm.ko 
alias:          platform:bcm2708_pwm 
author:         Sean Cross <[email protected]> for Adafruit Industries <www.adafruit.com> 
license:        GPL 
srcversion:     44D62553C321E91B0CB1996 
depends:        
vermagic:       3.2.27 preempt mod_unload modversions ARMv6

Last but not least, you should be able to insmod rpi-pwm.ko without any problems. My dmesg:

[email protected]:/# dmesg | tail -5 
[18852.504621] rpi_pwm: disagrees about version of symbol module_layout 
[19043.461377] rpi_pwm: disagrees about version of symbol module_layout 
[21401.160720] rpi_pwm: disagrees about version of symbol module_layout 
[22026.927225] rpi_pwm: disagrees about version of symbol module_layout 
[26733.475758] Adafruit Industries' Raspberry Pi PWM driver v1.0

If you want your module to auto start:

  • Copy your .ko module to /lib/modules/3.2.27+
  • Edit /etc/modules and append your module to the end of the list.
    Mine looks like:

    # /etc/modules: kernel modules to load at boot time. 
    # 
    # This file contains the names of kernel modules that should be loaded 
    # at boot time, one per line. Lines beginning with "#" are ignored. 
    # Parameters can be specified after the module name.
        
    snd-bcm2835 
    spi-bcm2708 
    i2c-bcm2708 
    i2c-dev 
    rpi-pwm
    
  • Next, run: depmod -a

  • Next, run: modprobe <yourmodulename>

Then reboot and your module should auto start on boot.

Hope that helps!
Brian Chavez

Updated:

Comments

JoeDeb

Brian, thank you very much for writing this!

Actually -with my limited knowledge in linux- i have been struggling for almost 6 days to compile a stk1160 Module for my new Raspberry Pi.
Following your explanation (simple copy and paste ;)) i was successful!!! I used a VM with Ubuntu 12.04 for cross-compiling.

I hope you don’t mind that i tell you about a few things i stubled across:

1) Its not “tar xzf tools.tar.gz” but “tar xzf master.tar.gz”

2) “In KEREL_SRC”: should be: “In KERNEL_SRC”

3) 2 things in this line:

scp [email protected]:/proc/config.gz ./; zcat config.gz > .config; mv .config $KEREL_SRC

did not work…

sudo scp [email protected]:/proc/config.gz ./; zcat config.gz > .config; mv .config $KERNEL_SRC

..did.

Thanks again

Joerg

Heri

Brian, this is actually a concise explanation as to how to compile a kernel for the RPi, kudos.
However, the most recent O/S contains a WiFi driver module which is not suitable for the EDIMAX-EW7811 (requires Realtek rtl8192cu driver). Since compiling is not my forte, I wonder if you could expand your explanation to cover this issue in order to add or compile this driver to the Kernel.
I think that this would help quite few of us who struggle with the same predicament.

Brain_ReCall

Great guide, thanks!

For those using a 64-bit install of Ubuntu, you have to have the ia32-libs package otherwise you get some very strange errors about missing files. For a fresh install of Ubuntu, its best to just do: “sudo apt-get install build-essential ia32-libs”

Martin

Great guide, I was also stuck trying to compile a module on the rpi itself, but your guide works like a charm and cross compiling is better anyway for performance reasons.

Heri

Hi Brian,

I ran into a problem trying to follow your section 2. above.

The driver (directory) supplied by Realtek for the Edimax WiFi device contains a bunch of subdirectories and files such as:Makefile, include, clean,etc.

1. Would the driver directory be the equivalent of your example ~/pwm ?
2. Should the driver directory be part of the KERNEL_SRC directory?

The issue is somwhat confusing since the KERNEL_SRC and the WIFi driver directory contain a Makefile albeit dissimilar in contents.

Your help very much appreciated.
BTW-Compiling the Kernel, as per your instructions of para.1, went without problems.

rpi

Great guide. Martin, thanks a lot. I ran into the same issue on 64-bit ubuntu. your suggestion works fine. thanks

Krishna

The instructions worked with 3.6.11 source as well when I replaced 3.2.27 with 3.6.y in the instructions given above. Thanks a ton for your guide!

fabrizio

I did all the steps, but didn’t work. I’ve noticed that my modinfo says 3.6.11 preempt mod_unload modversions ARMv5, instead of v6.

I used ubuntu 12.04

Saurabh

Hi, I have compiled a kernel successfully using cross tool chain.

I am using Ubuntu installed in VM and Raspbian V3.6.11 running in Raspberry pi board.

I have written a simple code for device driver and compiled it using make file.

I got following errors

make ARCH=arm CROSS_COMPILE= -C /home/saurabh/rpiRaspi M= modules
make[1]: Entering directory /home/saurabh/rpiRaspi'<br /> CHK include/linux/version.h<br /> CHK include/generated/utsrelease.h<br />make[2]: include/generated/mach-types.h’ is up to date.
CC kernel/bounds.s
cc1: error: unrecognized command line option ‘-mlittle-endian’
cc1: error: unrecognized command line option ‘-mno-thumb-interwork’
kernel/bounds.c:1:0: error: unknown ABI (aapcs-linux) for -mabi= switch
kernel/bounds.c:1:0: error: bad value (armv5t) for -march= switch
kernel/bounds.c:1:0: error: bad value (strongarm) for -mtune= switch
make[2]: ** [kernel/bounds.s] Error 1
make[1]: **
[prepare0] Error 2
make[1]: Leaving directory `/home/saurabh/rpiRaspi’
make: *** [all] Error 2

Please provide suggestion to solve it!!

praneeth

I am using 64bit ubuntu 12.4 to cross compile rpi (3.6.11) kernel modules. I followed the above steps and compiled the kernel crc successfully. But, I am seeing errors when I compile kernel modules. Here is the errors I am seeing.

make ARCH=arm CROSS_COMPILE= -C /home/rppendya/rpi/linux-rpi-3.6.y M=/home/rppendya/workspace/ds1307 modules
make[1]: Entering directory /home/rppendya/rpi/linux-rpi-3.6.y'<br /> CC [M] /home/rppendya/workspace/ds1307/ds1307.o<br />cc1: error: unrecognized command line option ‘-mlittle-endian’<br />cc1: error: unrecognized command line option ‘-mno-thumb-interwork’<br />/home/rppendya/workspace/ds1307/ds1307.c:1:0: error: unknown ABI (aapcs-linux) for -mabi= switch<br />/home/rppendya/workspace/ds1307/ds1307.c:1:0: error: bad value (armv5t) for -march= switch<br />/home/rppendya/workspace/ds1307/ds1307.c:1:0: error: bad value (strongarm) for -mtune= switch<br />make[2]: *** [/home/rppendya/workspace/ds1307/ds1307.o] Error 1<br />make[1]: *** [_module_/home/rppendya/workspace/ds1307] Error 2<br />make[1]: Leaving directory /home/rppendya/rpi/linux-rpi-3.6.y’
make: *** [all] Error 2

Any help and advise would be appreciated

Simon

For Saurabh, paraneeth, and others who find this page later and are looking for a solution to that problem,
The problem is you are invoking the standard, x86 gcc and asking it to compile for arm. Naturally, standard x86 gcc has no idea how to do this, so is throwing a bunch of errors back at you.
If you’re coping Brian’s Makefile, be sure you have your CCPREFIX set to point to your cross-toolkit, as Brian did in step 1. export CCPREFIX=
/home/cowboy/rpi/tools-master/arm-bcm2708/arm-bcm2708-linux-gnueabi/bin/arm-bcm2708-linux-gnueabi- (Your toolkit will probably be somewhere different! You should have downloaded it as part of the tools tarball)

TIK

hi Brian and everyone:
thank you for this writing!!

I have some problem in the kernel building. After Build the kernel:
“make ARCH=arm CROSS_COMPILE=${CCPREFIX}”
([email protected]:/media/sf_F_DRIVE/TI_D/RaspberryPi/srcTree/linux-rpi-3.12.y$ sudo make ARCH=arm CROSS_COMPILE=/home/firmament/rpi/tools/arm-bcm2708/arm-bcm2708-linux-gnueabi/bin/arm-bcm2708-linux-gnueabi-
)


This error happened
———————————
mkdir -p include/generated
scripts/kconfig/conf –silentoldconfig Kconfig

** Error during update of the configuration.

make[2]: **
[silentoldconfig] Error 1
make[1]: ** [silentoldconfig] Error 2
make: **
No rule to make target include/config/auto.conf’, needed by include/config/kernel.release’.
————————————

could you give me some suggestions or tell me which part I need to check first
Thank you very much

TIK

Hi Brian& everyone:
first time I tried to compile kernel was failed at
“make ARCH=arm CROSS_COMPILE=${CCPREFIX}”
with error:

scripts/kconfig/conf –silentoldconfig Kconfig

** Error during update of the configuration.

make[2]: **
[silentoldconfig] Error 1
make[1]: ** [silentoldconfig] Error 2

The reason was related to the permission in my Ubuntu. After I moved the source tree to my home folder, this problem had been solved.

But after about an hour compiling, another error happened. Could you give me some suggestions? Thanks

make[1]: include/generated/mach-types.h' is up to date.<br /> CALL scripts/checksyscalls.sh<br /> CHK include/generated/compile.h<br /> CHK kernel/config_data.h<br />make[2]: *** No rule to make target net/bridge/br_fdb.o’, needed by `net/bridge/bridge.o’. Stop.
make[1]: **
[net/bridge] Error 2
make: *** [net] Error 2

Ray

Thanks!

FYI To get the latest 3.12.32+ source I did.
mkdir ~ray/meinberg
cd ~ray/meinberg
wget https://github.com/raspberrypi/tools/archive/master.zip
unzip master.zip

git clone https://github.com/raspberrypi/linux.git

export CCPREFIX=/home/ray/meinberg/tools-master/arm-bcm2708/arm-bcm2708-linux-gnueabi/bin/arm-bcm2708-linux-gnueabi-
export KERNEL_SRC=/home/ray/meinberg/linux
cd linux/
make mrproper

etc.

One hiccup for me. NEWBIE ALERT. When copying the Makefile example above, make sure that the character before ‘make’ is a TAB and not multiple spaces. Arrgh. Otherwise you get the error: “make: Nothing to be done for `all’.” Took me ages to find that.

Ganesh

Hello,
When I try to set up an environment it gives following error
bash: export: `/home/ganesh/RPICComp/tools-master/arm-bcm2708/arm-bcm2708-linux-gnueabi/bin/arm-bcm2708-linux-gnueabi-‘: not a valid identifier

I have stored my tool master folder in home/ganesh/RPICComp/
and Kernel virsion is 3.18.y

I am using following command for setting up the Environment
export CCPREFIX= /home/ganesh/RPICComp/tools-master/arm-bcm2708/arm-bcm2708-linux-gnueabi/bin/arm-bcm2708-linux-gnueabi-

Kindly Guide Me
Thank You

John

This doesn’t work at least not for building an rpi module for the edimax ew-7811uac ac600. i got a bunch of warnings/errors when i ran the ARCH=arm CROSS_COMPILE=${CCPREFIX} oldconfig step. i have no clue how to configure the kernel so i accepted the defaults so i got a bunch of errors instead when i tried to build the kernel. but i was able to build the kernel (error free) merely by copying the proc/config.gz from my rpi and overwriting the .config in linux-rpi-3.18.y directory and skipping the above mentioned step.

I’m doing this on linux mint 17.1 (more or less ubuntu) which may or may-not (i suspect not) make a difference.

I put everything as indicated in my home directory
ls -1 ~/EDIMAX-COMPILE/RPI
linux-rpi-3.18.y
rtl8812au-master
tools-master

I created a directory outside the RPI directory and created the makefile as follows:
obj-m += 8812au.o

all:
make ARCH=arm CROSS_COMPILE=${CCPREFIX} -C /home/maihoa/EDIMAX-COMPILE/RPI/linux-rpi-3.18.y M=$(PWD) modules

clean:
make -C /home/maihoa/EDIMAX-COMPILE/RPI/linux-rpi-3.18.y M=$(PWD) clean

and made sure i had the TAB before make

The evn vars appear to be correct
echo $CCPREFIX
/home/maihoa/EDIMAX-COMPILE/RPI/tools-master/arm-bcm2708/arm-bcm2708-linux-gnueabi/bin/arm-bcm2708-linux-gnueabi-
[email protected] ~/EDIMAX-COMPILE/RPI-8812au-module $ echo $KERNEL_SRC
/home/maihoa/EDIMAX-COMPILE/RPI/linux-rpi-3.18.y

My rpi kernel is: uname -a
Linux raspberrypi 3.18.14+ #794 PREEMPT Sun Jun 7 12:02:04 BST 2015 armv6l GNU/Linux

what i don’t understand in the Makefile script is how does it know that i want to build a module for rtl8812au-master. I can’t get it to work.

What am i doing wrong?

Thanks
John

Sai

Thanks for this blog, it works, now i can able to compile module files on my PC and tested on rspi board.

thankyou.

Leave a comment

Your email address will not be published. Required fields are marked *

Loading...