Custom kernel on Nokia N900

 

Changelog:

 

This page describe how to recompile and install a new kernel on the device. The specific purpose of this work is to enable Mobile IPv6 support in the kernel but you may find the page useful if you need to add support for a specific kernel option.

I make the hypothesis you already have a working Maemo 5 SDK installed on your development box. There is a lot of good documentation available on maemo.org website to setup a development environment. You can start here.

Note however, that even if scratchbox environment is suitable for most build tasks, it is not the recommended way to build kernels, as described on Scratchbox Wiki. Nonetheless, if you do not intend to spend time installing an arm cross compilation toolchain on your development box (like the one provided by Emdebian project, which is the one I use), scratchbox is still a safe bet.

For completeness, I should add that there is a kernel guide on maemo wiki you may be interested in.

For the sake of clarity, oslo is my N900 and small is my laptop (the development box).

With scratchbox

The N900 comes with a 2.6.28-omap1 kernel compiled with a gcc 4.2.1. This is also the version available in scratchbox environment:

oslo:~# cat /proc/version 
Linux version 2.6.28-omap1 [...] (gcc version 4.2.1) #1 PREEMPT Wed Oct 28 15:32:55 EET 2009
[sbox-FREMANTLE_ARMEL: ~/kernel] > gcc --version
sbox-arm-none-linux-gnueabi-gcc (GCC) 4.2.1
Copyright (C) 2007 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Let's first grab the kernel sources and compile a basic kernel using the default configuration file for the N900 (rx-51 board):

[sbox-FREMANTLE_ARMEL: ~/kernel] > apt-get update
[sbox-FREMANTLE_ARMEL: ~/kernel] > apt-get source kernel-source
Reading package lists... Done
Building dependency tree... Done
Need to get 69.7MB of source archives.
Get:1 http://repository.maemo.org fremantle/sdk/free kernel 2.6.28-20094102.3+0m5 (dsc) [534B]
Get:2 http://repository.maemo.org fremantle/sdk/free kernel 2.6.28-20094102.3+0m5 (tar) [67.4MB]
Get:3 http://repository.maemo.org fremantle/sdk/free kernel 2.6.28-20094102.3+0m5 (diff) [2277kB]
Fetched 69.7MB in 50s (1387kB/s)        
dpkg-source: warning: extracting unsigned source package (./kernel_2.6.28-20094102.3+0m5.dsc)
dpkg-source: extracting kernel in kernel-2.6.28
dpkg-source: unpacking kernel_2.6.28.orig.tar.gz
dpkg-source: applying ./kernel_2.6.28-20094102.3+0m5.diff.gz

[sbox-FREMANTLE_ARMEL: ~/kernel] > cd kernel-2.6.28
[sbox-FREMANTLE_ARMEL: ~/kernel/kernel-2.6.28] > find . -name '*51*' | grep config
./arch/sh/configs/rts7751r2dplus_qemu_defconfig
./arch/sh/configs/rts7751r2d1_defconfig
./arch/sh/configs/se7751_defconfig
./arch/sh/configs/rts7751r2dplus_defconfig
./arch/arm/configs/omap_generic_1510_defconfig
./arch/arm/configs/rx51_tiny_defconfig
./arch/arm/configs/rx51_defconfig
./arch/arm/configs/omap_innovator_1510_defconfig

[sbox-FREMANTLE_ARMEL: ~/kernel/kernel-2.6.28] > make rx51_defconfig

[sbox-FREMANTLE_ARMEL: ~/kernel/kernel-2.6.28] > make

[sbox-FREMANTLE_ARMEL: ~/kernel/kernel-2.6.28] > ls -l arch/arm/boot/zImage 
-rwxrwxr-x  1 arno 1000 1739704 Dec  3 21:16 arch/arm/boot/zImage

Flasher-3.5 is the right tool to install the kernel image on the device. Flasher-3.5 is available here and documented here, here and

As discussed on previous links, Flasher-3.5 can be used to:

Anyway, know that we have our zImage, installing it on the device can be done in the following way: after having powered off your N900 (it should not be connected via USB to your development box), type the following command on your development box (outside scratchbox):

arno@small:~$ sudo flasher-3.5 -k /tmp/zImage -f -R
flasher v2.5.2 (Oct 21 2009)

Suitable USB device not found, waiting.

Then, connect the device via USB. It should be detected, vibrate and the image will then be installed by flasher tool:

arno@small:~$ sudo flasher-3.5 -k /tmp/zImage -f -R
flasher v2.5.2 (Oct 21 2009)

Suitable USB device not found, waiting.
USB device found found at bus 001, device address 021.
Found device RX-51, hardware revision 2101
NOLO version 1.4.13
Version of 'sw-release': <no version>
Sending kernel image (1700 kB)...
100% (1700 of 1700 kB, avg. 21528 kB/s)
Flashing kernel... done.

Your device should have rebooted and be usable as usual. Your N900 should report the following:

oslo:~# cat /proc/version 
Linux version 2.6.28-omap1 [...] (gcc version 4.2.1) #1 PREEMPT Fri Dec 4 20:37:29 CET 2009

Now that you have everything working, you can start modifying your kernel configuration in order to add (or remove) options. If you try and do a "make menuconfig" directly from scratchbox, you will get the following (as discussed on Scratchbox Wiki):

[sbox-FREMANTLE_ARMEL: ~/kernel/kernel-2.6.28] > make menuconfig
  HOSTCC  scripts/kconfig/lxdialog/checklist.o
  HOSTCC  scripts/kconfig/lxdialog/inputbox.o
  HOSTCC  scripts/kconfig/lxdialog/menubox.o
  HOSTCC  scripts/kconfig/lxdialog/textbox.o
  HOSTCC  scripts/kconfig/lxdialog/util.o
  HOSTCC  scripts/kconfig/lxdialog/yesno.o
  HOSTCC  scripts/kconfig/mconf.o
  HOSTLD  scripts/kconfig/mconf
scripts/kconfig/mconf.o: In function `main':
mconf.c:(.text+0x16e0): undefined reference to `stdscr'
scripts/kconfig/lxdialog/checklist.o: In function `print_arrows':
checklist.c:(.text+0x24): undefined reference to `wmove'
checklist.c:(.text+0x48): undefined reference to `waddch'

...

scripts/kconfig/lxdialog/menubox.o:menubox.c:(.text+0x1004): more undefined ref to `delwin' follow
scripts/kconfig/lxdialog/menubox.o: In function `dialog_menu':
menubox.c:(.text+0x108c): undefined reference to `stdscr'
menubox.c:(.text+0x1090): undefined reference to `LINES'
menubox.c:(.text+0x1094): undefined reference to `COLS'
menubox.c:(.text+0x109c): undefined reference to `acs_map'
collect2: ld returned 1 exit status
make[1]: *** [scripts/kconfig/mconf] Error 1
make: *** [menuconfig] Error 2

As a matter of fact, the kernel configuration can be done outside of scratchbox environment, using the usual "make menuconfig". Once this has been done, you can do the usual compilation step inside scratchbox, as presented above.

Once the compilation step is over, the first thing to do is to check the size of the resulting image. I don't know precisely yet what's the maximum size is but 2Mo is a safe bet (this was the maximum size of the image on the N810).

Now, before shutting down the device to install the kernel image using Flasher-3.5, we need to install the freshly compiled modules instead of the existing ones on the N900. Because we build for the same version of kernel (2.6.28-omap1), some care is needed in case we screw up (but still have enough luck for the device not requiring a complete reflashing step).

We first grab all compiled modules and store them somewhere. Then, we create a temporary directory on the N900 and upload the modules in that directory:

arno@small:~/kernel/kernel-2.6.28 $ mkdir ../modules
arno@small:~/kernel/kernel-2.6.28 $ find . -name '*.ko' -exec cp '{}' ../modules/ \;
arno@small:~/kernel/kernel-2.6.28 $ cd ../modules
arno@small:~/kernel/modules $ ssh root@oslo mkdir /lib/modules/tmp
arno@small:~/kernel/modules $ scp *.ko root@oslo:/lib/modules/tmp/

Then, on the N900, we backup the old modules and replace them with the uploaded ones.

oslo:~ # cd /lib/modules/
oslo:/lib/modules/ # mv 2.6.28-omap1 2.6.28-omap1.back
oslo:/lib/modules/ # mv tmp 2.6.28-omap1

Then we call depmod to built the various missing files on the device.

oslo:/lib/modules/ # mv tmp 2.6.28-omap1
oslo:/lib/modules/ # cd 2.6.28-omap1
oslo:/lib/modules/2.6.28-omap1 # depmod 2.6.28-omap1
oslo:/lib/modules/2.6.28-omap1 # ls | grep -v ko
modules.alias
modules.ccwmap
modules.dep
modules.ieee1394map
modules.inputmap
modules.isapnpmap
modules.ofmap
modules.pcimap
modules.seriomap
modules.symbols
modules.usbmap
oslo:/lib/modules/2.6.28-omap1 # sync

As /lib/modules/current still points to /lib/modules/2.6.28-omap1, the link does not need to be updated.

Now, just shutdown the N900 and install the kernel as described above. If everything goes fine ... your device should be usable.

Using Emdebian arm cross compilation toolchain

As already discussed above, the kernel compilation can easily be done outside scratchbox ... once you have installed the toolchain: last time I did it, it took me some time due to missing dependencies but this may have been corrected and the installation may work flawlessly for you.

Anyway, after some struggle, here is what I have on my development box:

arno@small: ~kernel/kernel-2.6.28$ arm-linux-gnueabi-gcc --version
arm-linux-gnueabi-gcc (GCC) 4.2.4 (Debian 4.2.4-6)
Copyright (C) 2007 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

arno@small ~kernel/kernel-2.6.28$ ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- make rx51_defconfig
arno@small ~kernel/kernel-2.6.28$ CROSS_COMPILE=arm-linux-gnueabi- make

Just in case, if you encounter the same problem with a broken emdebian.org mirror, take a look at the packages available here. After some wget and calls to dpkg -i you should have the following on your system:

$ dpkg --get-selections | grep arm
binutils-arm-linux-gnueabi                      install
cpp-4.3-arm-linux-gnueabi                       install
gcc-4.3-arm-linux-gnueabi                       install
gcc-4.3-arm-linux-gnueabi-base                  install
gcc-4.3-base-armel-cross                        install
libc6-armel-cross                               install
libc6-dev-armel-cross                           install
libgcc1-armel-cross                             install
linux-libc-dev-armel-cross                      install

What about a 2.6.28.10-omap1 on your N900?

As of today (March 6th 2010), the N900 kernel is a Nokia-patched 2.6.28-omap1. Current stable version of 2.6.28 kernel series is version 10 (i.e. 2.6.28.10). The associated patch is more than 850 KB (wc reports 26418 lines for that baby).

Let's switch from 2.6.28-omap1 to 2.6.28.10-omap1. You need current N900 2.6.28 kernel sources, with Nokia patches applied :

arno@small ~$ ls -l 
-rw-r--r--  1 arno arno  2295414 Jan 20 16:13 kernel_2.6.28-20094803.3+0m5.diff.gz
-rw-r--r--  1 arno arno      546 Jan 20 16:13 kernel_2.6.28-20094803.3+0m5.dsc
-rw-r--r--  1 arno arno 67389527 Jan 20 16:13 kernel_2.6.28.orig.tar.gz

arno@small ~$ dpkg-source -x kernel_2.6.28-20094803.3+0m5.dsc 
dpkg-source: warning: extracting unsigned source package (kernel_2.6.28-20094803.3+0m5.dsc)
dpkg-source: info: extracting kernel in kernel-2.6.28
dpkg-source: info: unpacking kernel_2.6.28.orig.tar.gz
...

Let's now grab upstream stable patch:

arno@small ~$ wget -q http://www.kernel.org/pub/linux/kernel/v2.6/patch-2.6.28.10.bz2
arno@small ~$ wget -q http://www.kernel.org/pub/linux/kernel/v2.6/patch-2.6.28.10.bz2.sign
arno@small ~$ gpg --verify patch-2.6.28.10.bz2.sign 
gpg: Signature made Sat 02 May 2009 10:18:06 PM CEST using DSA key ID 517D0F0E
gpg: Good signature from "Linux Kernel Archives Verification Key <ftpadmin@kernel.org>"

If you try to apply the patch directly on top of Nokia-patched kernel sources, it will fail. The reason is that some Nokia patches are also available in upstream stable patch. I spent the time considering all fuzzy applications, duplicated hunks and conflicts (notes available here) to created a modified version of 2.6.28.10 stable patch:

Let's apply previous result to our 2.6.280094803.3+0m5 kernel:

arno@small ~$ wget -q http://natisbad.org/N900/n900-2.6.28.10-20094803.patch
arno@small ~$ wget -q http://natisbad.org/N900/n900-2.6.28.10-20094803.patch.sign
arno@small ~$ gpg --verify n900-2.6.28.10-20094803.patch.sign 
gpg: Signature made Sat 06 Mar 2010 09:59:32 PM CET using RSA key ID A7AE341B
gpg: Good signature from "Arnaud Ebalard <arno@natisbad.org>"
arno@small ~$ cd kernel-2.6.28
arno@small ~/kernel-2.6.28$ patch -p1 -i ../n900-2.6.28.10-20094803.patch
arno@small ~/kernel-2.6.28$ CROSS_COMPILE=arm-linux-gnueabi- make rx51_defconfig
arno@small ~/kernel-2.6.28$ CROSS_COMPILE=arm-linux-gnueabi- make menuconfig
arno@small ~/kernel-2.6.28$ CROSS_COMPILE=arm-linux-gnueabi- make

You can now install the moduules on the device and then flash the new kernel:

arno@small ~/kernel-2.6.28$ mkdir ../modules
arno@small ~/kernel-2.6.28$ find . -name '*.ko' -exec cp '{}' ../modules/ \;
arno@small ~/kernel-2.6.28$ ssh root@oslo mkdir /lib/modules/2.6.28.10-omap1
arno@small ~/kernel-2.6.28$ scp ../modules/*.ko root@oslo:/lib/modules/2.6.28.10-omap1
arno@small ~/kernel-2.6.28$ ssh root@oslo depmod 2.6.28.10-omap1
arno@small ~/kernel-2.6.28$ sudo flasher-3.5 -k arch/arm/boot/zImage -f -R
flasher v2.5.2 (Oct 21 2009)

Suitable USB device not found, waiting.
USB device found found at bus 001, device address 021.
Found device RX-51, hardware revision 2101
NOLO version 1.4.13
Version of 'sw-release': <no version>
Sending kernel image (1700 kB)...
100% (1934 of 1934 kB, avg. 21528 kB/s)
Flashing kernel... done.

After your N900 has rebooted, you should have something like the following:

arno@small ~$ ssh root@oslo uname -a
Linux oslo 2.6.28.10-omap1 #1 PREEMPT Sat Mar 6 14:39:52 CET 2010 armv7l unknown

What about applying grsecurity patch now?

Now that we have a 2.6.28.10-omap1 kernel running on our N900, we can try and get a 2.6.28.10-omap1-grsec, i.e. apply grsecurity patch on top of previous work.

Considering the annoucement of official grsecurity/PaX support on ARM, it would obviously be better to be able to get a more recent stable kernel running on the device (e.g. a 2.6.32). But that is another story.

Let's first grab the latest grsecurity kernel for 2.6.28 kernel series, i.e. grsecurity-2.1.13-2.6.28.8-200903191958.patch. It is intended for 2.6.28.8.

SITE=http://wolfram.schlich.org/linux/misc/kernel/grsecurity
arno@small ~$ wget -q ${SITE}/grsecurity-2.1.13-2.6.28.8-200903191958.patch
arno@small ~$ wget -q ${SITE}/grsecurity-2.1.13-2.6.28.8-200903191958.patch.sig
arno@small ~$ gpg --verify grsecurity-2.1.13-2.6.28.8-200903191958.patch.sig 
gpg: Signature made Fri 20 Mar 2009 12:59:44 AM CET using DSA key ID 4245D46A
gpg: Good signature from "Bradley Spengler (spender) <spender@grsecurity.net>"

The patch almost applies, except for two hunks:

arno@small ~: cd k.2.6.28.10
arno@small ~k.2.6.28.10: patch --dry-run -p1 -i ../grsecurity-2.1.13-2.6.28.8-200903191958.patch

...

patching file mm/mmap.c
Hunk #37 FAILED at 1789.
1 out of 61 hunks FAILED -- saving rejects to file mm/mmap.c.rej
-> Hunk merged upstream in stable version 10 of 2.6.28. Removing
   the hunk from grsecurity patch does the job.

...

patching file net/ipv4/netfilter/Makefile
Hunk #1 FAILED at 61.
1 out of 1 hunk FAILED -- saving rejects to file net/ipv4/netfilter/Makefile.rej
-> Hunk fails due to the addition of ipt_IDLETIMER.o by Nokia
   in the list of Makefile's targets. Modifying hunk in
   grsecurity patch.

...

You can do the changes yourself or download a ready-to-use version below:

Let's apply the result:

arno@small ~$ wget -q http://natisbad.org/N900/grsecurity-2.1.13-2.6.28.10-omap1.patch
arno@small ~$ wget -q http://natisbad.org/N900/grsecurity-2.1.13-2.6.28.10-omap1.patch.sig
arno@small ~$ gpg --verify grsecurity-2.1.13-2.6.28.10-omap1.patch.sig
gpg: Signature made Sun 07 Mar 2010 01:19:54 PM CET using RSA key ID A7AE341B
gpg: Good signature from "Arnaud Ebalard <arno@natisbad.org>"
arno@small ~: cd k.2.6.28.10
arno@small ~k.2.6.28.10: patch -p1 -i ../grsecurity-2.1.13-2.6.28.10-omap1.patch

You can then configure (being the longest part probably) and compile your kernel as described above. In the end, you should manage to get a running 2.6.28.10-omap1-grsec kernel on your device:

N900 running 2.6.28.10-omap1-grsec kernel