Gentoo Wiki


Merge-arrows.gifIt has been suggested that this article be Merged into one article with Linksys NSLU2    (Discuss)
This article is part of the Hardware series.
Laptops TV Tuner Cards Wireless Servers Storage Other Hardware Motherboards Related

Some time ago, Linksys, a subsidiary company of Cisco Systems has released their NAS-device based on the embedded-arm architecture, which is called "NSLU2". This article is meant to provide you an insight into the world and to explain step by step, how to put a complete gentoo linux onto the Linksys NSLU2.


The device

The Linksys NSLU2 is a NAS ("network-attached-storage") device, which means that you can plug some hard disks on the USB-Ports and the device will export them via Samba onto your local network. Delivered by Linksys, the devices comes with a modified 2.4 linux-kernel, samba and a small webinterface. This is quite nice, but when we look at the Hardware of the device, we see that the device can be used for much more things. But it requires a really good Distribution and a actual linux-kernel to really "use" the device for everything we want. So nothing sounds better as putting a nice 2.6 Linux-kernel together with a regular Gentoo on our device!



The NSLU2 ships with an Intel IXP420 CPU. The XScale core is based on the ARMv5TE architecture and is designed for an operational clocking of 266 MHz. Nevertheless that specific device ships with an "underclocked" variant running on 133 MHz only. Through a simple modification it is possible to re-adjust the core clocking to 266 MHz. How that can be achieved is described here. Update 04/10/07: most NSLU2s appear to ship with the standard clocking of 266 MHz.


The CPU is connected to an 8mb Flash-Memory(0x50000000 - 0x50800000) which is designed as follows:

Additional to the NV-Memory we have 32 MB of RAM which are addressed within the range 0x00000000 to 0x02000000. Following this guide it is possible to upgrade RAM by soldering chips of common SD-RAM modules onto the board.


The device has two outside USB (2.0) connectors. The USB controller is recognized as "USB Controller: NEC Corporation USB 2.0 (rev 04)" (as shown by lspci) and is fully supported by the ohci/ehci drivers. Connecting an USB-Hub works great, but most likely it should be an active one to supply enough power to a bigger number of devices. In a tested stable setup 4 HDD's and one RFID-reader (connected via serial2USB converter) have been connected to the controller and and were in use at the same time.


The network controller is integrated into the CPU. Therefore it's based on the IXP420 chip. Detailed information can be obtained here. The proprietary driver for the ethernet interface is included in portage and can be built against kernel 2.6.


At delivery time the device uses a bootloader called "RedBoot". Although it is possible to replace it by the APEX bootloader, we will stick with RedBoot, since it's absolutely sufficient for what we want to achieve.

Serial port

Additional to the outside connectors, the NSLU2 also has an onboard serial port which uses TTL levels. Upgrading to a "real" usable RS232 port is no miracle: It's either possible to solder the little circuit on your own or to simply buy a ready-to-use PCB. Another possibility is using a data cable of an old cellphone, which connects to the computer's USB port. Those cable's mostly base on the Prolific PL2301 USB-Serial converter, which delivers TTL levels on the serial side. So adding a "serial" port (which connects to the host via USB) simply means soldering 3 wires on the NSLU2's PCB. Additional information on this topic can be found here. It is highly recommended to use that serial interface (for a serial console) when tampering with the NSLU's internals like bootloader, kernel, and so on. The serial console is the one and only possibility for convenient debugging of the boot process. Although you do not need a serial console for gentoofying, the time will come for sure, that you're really glad about having a serial console!


to be translated


Setup and boot of an installation system

Although the NSLU2 ships with an installed Linux OS, we cannot use it as a starting point for installation, because we have no possibility to access the installed OS in the necessary way. That's why we need a fully functional linux, on which we can work comfortably during installation. Chilla has built a little fully featured linux- system for that purpose, which bases on uClibc and busybox and also offers an SSH-access, bash and screen. The whole thingy resides comfortably in the flash memory of the device and can be installed without great efforts.

We'll access the installation system via SSH. The system is preconfigured with the IP address (remember: this is only temporary for installation. The resulting system can be configured to match your needs.) The ready-to-run image of that base system can be downloaded from:


If the IP is already in use within your network, or if you want the installation system to be reachable under another address, you first have to change the network configuration in the root-filesystem and create an jffs-image afterwards:

 tar xvjpf nslu2-startup-image.tar.bz2
 vim nslu2-startup-image/etc/inittab

Change the IP in this line (and the default router in the next one if appropriate):

 null::sysinit:/sbin/ifconfig ixp0 up

Now create the jffs-image:

 emerge sys-fs/mtd
 mkfs.jffs2 -d nslu2-startup-image --faketime -o nslu2-startup-image.jffs2 -pad --big-endian --eraseblock=0x20000

Now we need a possibility to transfer fs-image and kernel to the flash memory of the device. That's what the fantastic tool called "upslug2" is meant for, which is included in portage:

 # echo "dev-embedded/upslug2 ~x86" > /etc/portage/package.keywords
 # emerge upslug2

For testing purposes we just run the program:

[19:25:49]|[chilla@chucky]|~$ upslug2
[no NSLU2 machines found in upgrade mode]

If that output appears, everything is OK. As you can see, the program cannot access the slug automatically - the device has to be switched to upgrade mode first:

For verification that upgrade mode is really activated, you can simply call upslug2 again, which now should produce an output similar to:

 [19:37:38]|[chilla@chucky]|~$ upslug2
 NSLU2     00:13:10:d6:1d:f2 Product ID: 1 Protocol ID: 0 Firmware Version: R23V29 [0x2329]

Now we transfer rootfilesystem and kernel image to the slug:

 [19:42:38]|[chilla@chucky]|~/tmp/slughowto$ upslug2 --rootfs=nslu2-startup-image.jffs2 --kernel=nslu2-startup-kernel-
 NSLU2     00:13:10:d6:1d:f2 Product ID: 1 Protocol ID: 0 Firmware Version: R23V29 [0x2329]
 Upgrading LKGD61DF2 00:13:10:d6:1d:f2
   . original flash contents  * packet timed out
   ! being erased             - erased
   u being upgraded           U upgraded
   v being verified           V verified

   <status> <address completed>+<bytes transmitted but not completed>
   * timeout occured          + sequence error detected

 Rebooting... done

As described in the output, the NSLU2 now reboots and should be accessible via SSH after a short while:

 ssh root@

The root password for that image is "nslu2". After logging in, we have reached the first step on the way to holy gentoo: A fully featured linux system is running on the NSLU2, which we can shell access via SSH.

If you are interested in how to build such a tiny OS image for use on the embedded device, have a look here.

Setting up the harddisk

After transferring filesystem and kernel image to the slug and the following reboot, it should be acessible via after a short while. Log in using "root" with password "nslu2". For the following setup process the use of "screen" is highly recommended. Screen is a terminal multiplexer, which allows detaching of a session from a terminal and reattach to the session from another terminal. The most essential commands are:

So now we are ready for setting up our gentoo system on the NSLU2. Let's start with configuration of the harddisk:

First, connect your USB-disk to the slug. After a few seconds, dmesg should show the following:

root@gentooslug ~ # dmesg | grep sd
SCSI device sda: 156301488 512-byte hdwr sectors (80026 MB)
sda: assuming drive cache: write through
SCSI device sda: 156301488 512-byte hdwr sectors (80026 MB)
sda: assuming drive cache: write through
 sda: sda1 sda2
Attached scsi disk sda at scsi0, channel 0, id 0, lun 0

In that case, the disk already had partitions on it. To create new partitions or change the layout, use

 # fdisk /dev/sda

Spending plenty space for swap is highly recommended, because the build system will consume plenty memory during compilation. 500 MB to 1 GB should be a good value. Since the installation system only supports EXT2, your new root should be formatted as EXT2. Later (after installing your own kernel), you still can upgrade to EXT3 via "tune2fs -j".

A sample partition scheme might look like that one:

root@gentooslug ~ # fdisk -l /dev/sda

Disk /dev/sda: 80.0 GB, 80026361856 bytes
255 heads, 63 sectors/track, 9729 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes 

   Device Boot    Start       End    Blocks   Id  System
/dev/sda1   *           1        2432    19535008+  83  Linux
/dev/sda2            2433        2554      979965   82  Linux swap

The partitions are formatted accordingly:

mkfs.ext2 /dev/sda1
mkswap /dev/sda2

Now we mount the partition which will host our new root filesystem to /mnt/gentoo, where /proc and /dev also have to be mounted. Further on we activate the swap space:

mount /dev/sda1 /mnt/gentoo
mkdir /mnt/gentoo/proc
mount -t proc none /mnt/gentoo/proc
mount --bind /dev /mnt/gentoo/dev
swapon /dev/sda2

Installing a stage tarball and a portage snapshot

The next steps are well-known to gentoo users: We fetch a stage tarball and a portage snapshot and then chroot into the new environment. Fortunately, a few guys'n'gals from the embedded-gentoo project accomplished a great work up to now, so we have now the possibility to use a fully functional stage3 tarball which is compatible with the NSLU2, since it is compiled for xscale CPUs and creates binaries which are big-endian.

That stage3 tarball can be found on nearly every gentoo-mirror, a list can be found here. Download the tarball to the NSLU2 using "wget":

echo "nameserver" > /etc/resolv.conf
cd /mnt/gentoo
wget http://<gentoo-mirror>/pub/mirrors/gentoo/experimental/arm/embedded/stages/stage3-armeb-uclibc-softfloat-2005.1.tar.bz2

The second thing to fetch from the mirror at that time is the latest portage snapshot:

wget http://<gentoo-mirror>/pub/mirrors/gentoo/snapshots/portage-latest.tar.bz2

Both have to be inflated according to the official gentoo documentation:

tar xvjpf stage3-armeb-uclibc-softfloat-2005.1.tar.bz2
tar xjf portage-latest.tar.bz2 -C /mnt/gentoo/usr

And now the time has come: We chroot into our new environment and start with configuration of our system:

chroot /mnt/gentoo /bin/bash

Setup and configuration of the base system

After the chroot we are in our new root directory. Nice, but now we have to prepare the system for being boot- and runable. Further on we want to update it to the latest stable versions. The stage archive we used, still uses gcc 3.3 and is configured for use of a kernel 2.4 with devfsd. Since we want to use kernel 2.6 with udev, we have to apply some changes.

First we have a look on emerge and its profile, which will be set to "/usr/portage/profiles/uclibc/arm/":

 rm /etc/make.profile
 ln -s /usr/portage/profiles/uclibc/arm/ /etc/make.profile

Now we have to adjust /etc/make.conf, which should look like that:

bgentooslug / # cat /etc/make.conf
CFLAGS="-march=armv5t -Os"
CXXFLAGS="-march=armv5t -Os"
USE="pam -bitmap-fonts -truetype-fonts -type1-fonts -expat"
FEATURES="ccache -noman -noinfo -nodoc"

An emerge --info shows us the configuration of emerge:

gentooslug / # emerge --info
Portage (uclibc/arm, gcc-3.4.4, uclibc-0.9.27-r0, armv5teb)
System uname: armv5teb XScale-IXP42x Family rev 1 (v5b)
Gentoo Base System version 1.6.13
dev-lang/python:     2.3.5
sys-apps/sandbox:    1.2.12
sys-devel/autoconf:  2.13, 2.59-r6
sys-devel/automake:  1.4_p6, 1.5, 1.6.3, 1.7.9-r1, 1.8.5-r3, 1.9.5
sys-devel/binutils:  2.16-r1
sys-devel/libtool:   1.5.18-r1
virtual/os-headers:  2.4.26-r1
CFLAGS="-march=armv5t -Os"
CONFIG_PROTECT="/etc /usr/kde/2/share/config /usr/kde/3/share/config /usr/share/config /var/qmail/control"
CONFIG_PROTECT_MASK="/etc/gconf /etc/terminfo /etc/env.d"
CXXFLAGS="-march=armv5t -Os"
FEATURES="autoconfig ccache distlocks sandbox sfperms strict"
USE="arm bzip2 ncurses pam perl python readline uclibc zlib userland_GNU kernel_linux elibc_uclibc"

After defining the nameserver, which lets us resolve domainnames, we startover and have a look on what emerge offers for updating:

echo "nameserver" > /etc/resolv.conf
emerge -puvDN world

This probably will show a rather long list. Fortunately we can get rid of some of the packages, which will reduce the number of packages to be updated:

emerge -C busybox dropbear devfsd

Now let's rock'n'roll: We update the system, therefore adjust it to the new profile and make.conf. This procedure might take a _very_ long time - go along and read a couple of books in the meanwhile. Hops and malt might also sweeten the waiting time. :-) (Sorry, I'm native bavarian) Oh, just one hint: If you plan to de-underclock your NSLU2 (resulting in twice the clock rate), now is the perfect time!

emerge sync
emerge -uDN world

On a 266-MHz (de-underclocked) NSLU2, the whole procedure took around 12 hours. Have a look on the slug from time to time, some packages might have problems at compile time. For me, uclibc-0.9.28 made me some headaches, because emerge built some objects for i386 instead of arm. I hassled around with that a few hours, the result (a binary package) can be downloaded here. When the update process has finished, we have to do an etc-update. Since we didn't modify any configuration files yet, we simply can use "-5" to merge changes automatically without interaction.

Before proceeding with installation of further packages or configuring a new kernel, it's time to create the login credentials:


Also, make sure, that openssh is installed and configured correctly, it is the only door into your system! If it ever should happen to you (be sure, it will!) that you're locked out, you only have two practible solutions: Either log in using the serial console or power off the slug, plug the disk to your workstation and configure the missing things.

Compiling a kernel

We will use a standard open source linux kernel. But instead of compiling the kernel on the NSLU2 itself, I prefer the usage of a crosscompile environment on my normal (Gentoo) workstation for sake of speed and convenience. Since the NSLU2 is a specialized piece of hardware, we need several patches since the plain vanilla kernel doesn't implement all needed drivers yet. Fortunately, the nslu2-linux project created a complete build environment, which does most of the tasks almost automatically. So let's rock:

1.) Set up your crosscompile-environment:

 # crossdev armeb-softfloat-linux-uclibc

2.) Get the build system:

 # svn co $WD
 # export WD=$WD/trunk
 # cd $WD
 # mkdir downloads

3.) Get the intel driver stuff

For me it's the following which worked (dunno, if some of those is unneeded):

Since this stuff is rather hard to find, I packaged the GPL & BSD licensed parts for convenience:


Find the IPL zip by intel download center : (or by googling the zip filename)


Place all the files in $WD/downloads

4.) Patch Makefile / set correct endianess & crosscompile settings:

 # cd $WD
 # wget
 # patch -p1 < makefile.patch 

5.) Patching the sources

If not already on your system, you need to emerge quilt (patch manager)

 # emerge quilt

Real patching will be done automatically when running "make menuconfig" for the first time. So skip over to step 6.)

6.) Now it's time to create a working .config, the delivered one didn't make sense for me at all and most likely won't work due to a erroneous kernel cmdline. Here' the link to my (working) .config, which requires an ext3-rootfs:


Start menuconfig to load & edit that configuration as needed:

 # cd $WD (NOT cd $WD/linux-2.6.17 !!!)
 # make menuconfig

7.) During the compilation, you will need devio (currently masked) :

 # echo sys-block/devio >> /etc/portage/package.keywords
 # emerge sys-block/devio

Now it's time to build all the stuff:

 # cd $WD
 # make

Kernel compilation should work flawlessly. When compiling the intel ixp-drivers, you might encounter an error referencing a wrong GCC/LD option (-mabi=apcs-gnu). The following will fix that issue:

 # cd $WD
 # find . -type f -exec grep -l abi=apcs {} \; | while read line
 > do cat $line | sed 's:-mabi=apcs-gnu::g' > $line.bak
 > mv $line $line.orig
 > mv $line.bak $line
 > echo "Processed $line"
 > done 

The following

 # cd $WD; make

should now run without errors.

When encountering errors, I discovered, that removing all stuff already built can help, so a

 # cd $WD
 # rm -rf ixp* lib vmlinuz* 
 # make

might be helpful.

8.) Now transfer the kernel to the slug:

Start the slug into transfer mode. Therefore power off the device and disconnect all cables except power and ethernet. Then press the reset button and keep it pressed while powering on the device. After about 10 seconds (always keep reset pressed) the status LED turns from amber to red. Now release the reset button immediately, the status LED should now flash red and amber.

 # cd $WD/trunk
 # upslug2 --kernel=vmlinuz-nslu2-2.6.17

9.) For convenience, you can now download a fully operational root-Image from my server, which is a bzipped dump-file (use "restore" to recover):


(This is currently for 2.6.17).

please read the remarks in


10.) If you want to use your own root filesystem instead:

- Install the built modules on your rootfs

- copy $WD/ixp400_xscale_sw/lib/linuxbe/IxNpeMicrocode.dat to $ROOTFS/lib/firmware

- modify $ROOTFS/etc/init.d/bootmisc: In the start section, insert these lines:

   /sbin/depmod -a
   /sbin/modprobe ixp400
   /usr/bin/mknod /dev/ixNpe c 241 0
   cat /lib/firmware/IxNpeMicrocode.dat > /dev/ixNpe
   modprobe ixp400_eth

- make sure, that there's a network configuration for "eth0" which is started in your default runlevel!

- for the RTC device (rtc0) to be linked to /dev/rtc (where hwclock expects it), create an appropriate udev rule:

 # echo "KERNEL==\"rtc0\", SYMLINK=\"rtc\"" > $ROOTFS/etc/udev/rules.d/10-rtc.rules
Retrieved from ""

Last modified: Thu, 25 Sep 2008 07:50:00 +0000 Hits: 8,099