Cross compile linux kernel module for specific kernel

This post will revolve around the Netgear DGND3300v2 router and compiling the dm9601 drivers. I am not an expert and so this post might be missing certain key points relevant to your target platform. In short: There are two distinct issues. One is cross compiling for a specific architecture, for this you need a toolchain. This is fine for compiling executables. But, if you want to compile a LKM (loadable kernel module) you need to use the kbuild system with the kernel source of the specific platform you are compiling for. This is the tricky part.

Compiling an executable

As mentioned compiling for another platform requires a cross-compiling toolchain, for the router it was MIPS III Big Endian. Fortunately, there are prebuilt binaries for this here. Now at this point you can compile code to be compiled!

./mips-linux-gnu-gcc helloworld.c -o hello -Wall -static -muclibc

Notice the uClibc flag, this was needed as my router uses it instead of glibc.

Compiling a kernel module

To use the kbuild system (link) you need to use a Makefile. A simple example from tldp.org (which you need the source file from):

obj-m += hello-1.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

then run:

./make

This builds an external module file hello-1.ko from hello-1.c. In the first few lines "-C /lib/modules/$(shell uname -r)/build " points make towards your kernel headers. Header files and module.symvers are required (has to be built).

Compiling a kernel module for another platform

Using the same Makefile (hopefully), you can cross-compile the module using the ARCH and CROSS_COMPILE paramters of Make. ARCH needs to be the platform name and CROSS_COMPILE the path of your toolchain. For example:

make ARCH=mips CROSS_COMPILE="/home/chris/mips/mips-linux-uclibc-"

Notice the ending hyphen, the files under that location are the toolchain: e.g

mips-linux-uclibc-c++
mips-linux-uclibc-cpp
mips-linux-uclibc-gcc-4.2.3
mips-linux-uclibc-gdb
mips-linux-uclibc-ldconfig

Cross compile for another platform.

Now the only difference with the previous example is changing the path to the kernel source in the Makefile like so:

obj-m += hello-1.o

all:
make -C /home/chris/linux-headers M=$(PWD) modules

clean:
make -C /home/chris/linux-headers M=$(PWD) clean

running it with the same command as before will give the kernel module:

make ARCH=mips CROSS_COMPILE="/home/chris/mips/mips-linux-uclibc-"

Conclusion:

Disclaimer: I am extremely inexperienced and I only learnt what I had to to get the drivers to work.
But in this scenario there were two distinct parts. 1. The first was getting the correct toolchain for your platform, this turned out to be rather tricky as the target was compiled using glibc so my first few downloaded toolchains didn't work. 2. The second having the correct kernel headers, this again turned out to be rather tricky as my router kernel version seems to be specifically patched for MIPS.
Luckily through different places Netgear has GPL released both the toolchain and kernel source.

Add new comment

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.