Linksys NSLU2

The Linksys NSLU2 (aka 'Slug') is sold as a NAS device (just plug it into your network, add a USB hard disk, and away you go!) but in reality it is much more useful than that. It is a complete, cheap, embedded Linux system. It features an Intel IXP420 (ARM) CPU, 32 MB of RAM, 8 MB of flash, an Intel IXP425 Ethernet PHY, and a dual-port USB controller. Best of all is the fact that the official Linksys firmware uses the Linux kernel, and so Linksys released the source code. This led to some excellent custom firmware projects like Unslung and SlugOS.

This document is a guide to installing and running a Gentoo root filesystem on a hard disk attached to your NSLU2, using parts of SlugOS. It assumes a good working knowledge of Linux in general, and Gentoo in particular. It also assumes you have successfully flashed SlugOS to your NSLU2.

This document is a work in progress! Please expand it with your experiences/knowledge/problems (this is a wiki, after all!). In particular, SlugOS experts (and Gentoo experts) are encouraged to fill in the parts where I had to just guess.

How?
As mentioned above, SlugOS provides the basis for the Gentoo installation.

The SlugOS firmware installs a 2.6 kernel and a very basic, but fully usable, root filesystem in flash. When you first flash an SlugOS image to your NSLU2 you log into this rootfs.

Included on this rootfs are some boot scripts which will then chainload another rootfs (either on an attached hard disk, NFS, ...), by chroot-ing and exec-ing init. The turnup script, when run, writes some configuration information to /linuxrc on the flash rootfs which instructs the boot script how and what to actually boot.

With an ordinary SlugOS installation you create a rootfs on your attached hard disk that is very similar to the flash rootfs — just without the space restriction. The flash rootfs then loads the disk rootfs on every boot. We are going to completely replace the disk rootfs with a Gentoo installation (with a few important modifications). We will still be relying on the SlugOS folks to provide a kernel and flash rootfs, which can be updated whenever SlugOS produce a new release.

If things turn ugly ...
If you run into problems that render the Gentoo system unbootable you can resolve them by booting into the standard SlugOS environment again. To do so, reboot your slug with no disk attached. Once booted and connected via ssh, reconnect the disk and try to resolve the error.

Building a basic working Gentoo root
All the hard work of preparing a basic working system has been taken care of by the excellent Gentoo Embedded project. As pointed out by Ned Ludd on the gentoo-embedded list, you can download an appropriate stage from one of the Gentoo mirrors under experimental/arm/embedded/stages (many mirrors don't carry this directory, but at the very least OSU Open Source Lab do).

Although the IXP420 CPU can dynamically switch between big- and little-endian modes, the NSLU2 ships set to run in big-endian mode. Since we will still be using Redboot and the SlugOS kernel installed on the flash, we will need to keep everything big-endian. This means we will need a stage for the armeb host type (not arm). Gentoo Embedded provides only armeb stages that are based on uClibc (as opposed to glibc), but this should be an advantage on the slug because of the smaller memory footprint. Ned Ludd in his post also suggests using softfloat, since the IXP420 lacks a floating-point unit.

The kernel will emulate floating-point operations anyway, but you will have to switch to kernel (trap) for each and every float point operation, and it isn't very fast. On the other side, size of applications with float point operations will be larger, depending on a number of operations even very much larger. You can consider it as a kind of 'inlining'.

So the stage we want is stage3-armeb-uclibc-softfloat-2005.1.tar.bz2 (as of January 2009, there's no more recent stage ...). Unpacking this will give a fully working Gentoo installation, but you will need to make a few changes to it before you can boot it from the SlugOS flash image.

Burn the SlugOS firmware to your NSLU2
First, get the SlugOS (BE) firmware from http://www.slug-firmware.net/s-dls.php. You will also need the upslug2 flash program. As it is in portage, you can simply do

when using a Gentoo box. It's also available on http://nslu2-linux.org.

To be able to flash the slug, make sure you do not have any devices (hard drives, etc.) connected to it. Next, get the NSLU2 into 'upgrade mode'. Hold the reset button in while powering on, for example with a paper clip, until the LED turns from amber to red (really more of a dark amber). Then release the reset button. When in upgrade mode the LED will blink between green and red.

Now, we can flash SlugOS to the NSLU2:

If you are running multiple NSLU2 devices then you will also need to specify the MAC address of the device to upgrade. Either way, the output of the program will look similar to this:

Burn SlugOS firmware to a specific device

Once that has finished the NSLU2 will automatically reboot and come up onto your network using a DHCP-assigned address, or 192.168.1.77 if DHCP is not available. Rebooting will take around 2 minutes. The ready/status LED indicates the boot progress, it should stay green when the system is booted. You now should be able to ssh into the SlugOS firmware.

Ssh to your slug and do some basic settings
When no DHCP is available, the NSLU2 will choose an IP address of 192.168.1.77. So, for example, do:

The preset root password is 'opeNSLUg'. Now run the turnup script to prepare the firmware, answering the questions when prompted:

Running 'turnup'

Create a filesystem and unpack the stage
Note: This section can either be completed from SlugOS running on your slug, or to speed things up you can attach your USB disk to another Linux system. Then attach the disk to the slug and do the rest there.

Create a new filesystem on a partition of your hard disk. Space required depends on what you will be installing; 1.5 GB is a reasonable minimum. You have to use a filesystem supported by SlugOS (as of 4.8 Beta, these are ext2 and ext3). For example:

You can then mount it and unpack the stage:

Mount the filesystem and unpack the stage (assuming you have downloaded the stage to your home dir)

Now is also a good time to install the Portage tree. You can copy your local portage tree if you are using a Gentoo box. If the disk is attached to this box, simply do

You can also use scp if the disk is attached to the NSLU2:

Alternatively, you can download a snapshot, just as you would do when setting up a new Gentoo box. See The Handbook.

Another alternative would be, if you are running a Gentoo system with NFS installed, to mount portage (including distfiles) from the other machine to save disk space. Also, when the time comes to emerge --sync, just syncing the larger Gentoo box will update the portage on the slug as well

Mounting Portage using NFS from 192.168.1.2

Copy kernel modules
You will need to provide your Gentoo system with the kernel modules for the SlugOS kernel. In particular your Gentoo installation needs to load the ixp4xx module in order to bring up the network. You should copy all the kernel modules from /lib/modules/ in an existing SlugOS installation to the same path on your new Gentoo root:

chroot into the Gentoo system
You are now ready to chroot into the new filesystem. Note that this should be done on the slug itself (from SlugOS), not on another Linux machine. chroot into the filesystem

Since the NSLU2 only has 32MB RAM, you will likely need to enable swap space. This is recommended when using emerge or gcc.

Create a swap partition on the USB drive and mount it. (sda2 used in this example).

Basic configuration
Note: This section corresponds to chapters 8 and 9 of part one of the Gentoo Handbook.

Checking the relevant config files
You should have a look in all the important config files to make sure they are set up the way you want:


 * /etc/fstab


 * /etc/conf.d/hostname
 * /etc/conf.d/net


 * /etc/hosts
 * /etc/resolv.conf
 * /etc/conf.d/clock

If you want your NSLU2 to run with a different timezone than UTC, you have to set the TZ environment variable (/etc/localtime will not work with uclibc). See this FAQ entry for more details. The value of the TZ variable can be stored in /etc/TZ. An example value for CEST would be:


 * /etc/rc.conf
 * /etc/conf.d/rc

Don't forget to set the password for root:

Making the Ethernet interface work
Since you certainly want the Ethernet interface to be available we add the following two items to /etc/modules.autoload.d/kernel-2.6 in order to load the network driver during bootup:

If you are using a proxy server to access the internet on your slug, you will need to add the following settings to /etc/profile

making sure the correct IP addresses and ports are specified. then type

The proxy settings should now work.

Make sure the Ethernet controller gets started at system boot :

Installing the relevant system tools
Also install any system tools you want; at a bare minimum you should have a syslogger, for example metalog.

If applicable add syslogger and/or DHCP client to the default runlevel

You will need to install an SSH server to access the Slug, since the SSH server on the flash disk will not be used. Dropbear is really simple and lightweight server, whereas OpenSSH is the "industry standard" with lots of options. The compile will take a while, since there's not a lot of CPU to go around.

or

Add the ssh server to the default runlevel:

or

You should have a cron daemon (vixie-cron is recommended).

Create the flash mount point
When the SlugOS flash image boots your Gentoo installation, it "swivels" the root so that Gentoo ends up mounted as root and the flash filesystem is mounted in a subdirectory underneath it. SlugOS will use as the mount point /initrd, if found on the Gentoo filesystem; otherwise it falls back to /mnt (which is pretty much guaranteed to exist).

The Gentoo stage does not include a /initrd directory so you should create it:

This will keep /mnt free for mounting other filesystems as usual.

Symlink chroot
SlugOS will try to use the chroot image on the Gentoo system when booting. It will search for it in /usr/sbin, but Gentoo has chroot in /bin, so you should add a symlink:

Ensure /.recovery is removed
One final important step is to add the following line to /etc/conf.d/local.start:

The /.recovery file is touched by the boot scripts on the flash rootfs, with the assumption that once booting is finished it will be removed. If you try to reboot with /.recovery present, the flash boot scripts will assume that the previous boot attempt failed and will fall back to booting from flash.

Rebooting into your new system
Before you are able to use your new Gentoo system you first need to tell SlugOS to boot off of your hard disk rather than the flash rootfs. Luckily this is not as hard as it sounds. First you need to exit from your chrooted environment and un-mount your drive:

Exit from the chrooted environment

Now all that remains is to tell SlugOS to boot off of your hard disk and reboot (assuming that the device that you want to boot off of is /dev/sda1 and that it is an ext3 partition):

Code: Change the root device and reboot

Swap
Portage itself (particularly emerge metadata), as well as many of the compiles (Perl, I'm looking at YOU!) are extremely memory-hungry. Make sure you have lots of swap enabled before attempting any of these. I think 128 MB is probably enough, but I am using 512 MB. If you are doing anything serious with your slug you will probably need plenty of swap anyway. In the case that your swap partition isn't big enough and your compiles fail due to lack of memory you can add a swap file on your attached disk. Consulting man mkswap should give enough info already but here's an example for the impatient:

Swap esample

When you're done using it, just do a

to get rid of the swap file again. If you however want to add the swap file permanently, edit your /etc/fstab accordingly.

CFLAGS
The armeb stages are compiled for a generic big-endian ARM target, with the -Os ("optimise for small size") CFLAG set, but perhaps better performance could be had by telling GCC exactly what type of CPU you are using. Apparently SlugOS uses -march=armv5te -mtune=xscale. I would suggest adding this to your CFLAGS in /etc/make.conf. The reason for not using -march=xscale is simply that there are no such valid value according to: http://gcc.gnu.org/onlinedocs/gcc-3.3/gcc/ARM-Options.html.

You could run emerge -e system to recompile everything, if you wanted to make sure every part of your system takes advantage of the new CFLAGS. But be warned — only do this if you don't need your slug for a few days! On mine it took around 36 hours to compile everything, Perl and GCC being the worst culprits. Also see above regarding swap. I would suggest that you don't bother doing this, as pretty much everything will eventually be recompiled when you update it. Note: The above is certainly needed when you want to use distcc to cross-compile on another host.

Kernel headers
The uclibc embedded stages use the uclibc/arm/2.4 profile by default, which will prevent you from installing newer versions of the kernel headers. This is not harmful, but prevents uclibc from taking advantage of newer features provided by the 2.6 kernels.

If you change your /etc/make.profile symlink to point to the uclibc/arm profile instead (no 2.4 subdir) Portage will let you upgrade to the 2.6 headers. This is recommended. Note that you will also need to re-emerge uclibc after this, to take advantage of the new headers.

Notes from users
This repeatedly caused my system updates to crash with endless uclibc-errors. If you know the cause of this, please post. If not, and you encounter similar problems, it should be safe to omit this part. ---Daniel

I too have had issues with this. so suggest not doing this.

I had the same grief but a potential solution appears to be emerging ('scuse the pun) I am past all my previous failures and currently well into an emerge -e system compile. Will confirm as success if everything completes. uclibc is confirmed to emerge without problem.

Steps:


 * start with an up to date portage tree and an up to date portage


 * Update make.conf to optimise for processor and ensure libc set to uclibc. Setting processor should improve speed.


 * Do the above rm and ln if you haven't already
 * Downgrade your linux-headers from latest (I used 2.6.11-r3)

[>=2.6.19 do not work, 2.6.17.* are suspected to work but hung my nslu2 on emerge]


 * update system. I have shown a complete system upgrade, but technically you may get away with just an "emerge uclibc" instead of the "emerge -e system" if you are of the impatient type. Don't forget that you must "emerge linux-headers" first though.

The /dev tree
The uclibc/arm/2.4 profile, which is selected by default in the stage (see above), includes devfsd (although it is not run by default). I suggest setting Gentoo to use a simple static /dev tree :

inittab
The default Gentoo /etc/inittab runs six instances of agetty on the first six virtual ttys, as well as two instances on ttyS0 and ttyS1. Since we don't have a console on the NSLU2 we can save memory (and error messages in /var/log/messages!) by commenting out the lines for the six virtual ttys. I have also commented the lines for the serial ports, but if you have a serial connection on your slug you will of course want to leave in the line for ttyS0.

syslog-ng
The default Gentoo /etc/syslog-ng/syslog-ng.conf instructs syslog-ng to display all messages on /dev/tty12, as well as logging them to /var/log/messages. Ordinarily this is really helpful (just hit Alt+F12 to see the latest log entries) but of course on the headless NSLU2 this is just a waste. Two lines need to be commented out:

LEDs
SlugOS uses the NSLU2 LEDs to signal the various stages of the boot process. Gentoo will of course do nothing of the sort by default, so you will end up with a flashing amber status LED even once bootup is finished. I would suggest adding a few boot scripts to (roughly) mimic the SlugOS behavior.

SlugOS 3.10 and above
You can use the file from /initrd/sbin/leds - copy it to the /usr/local/sbin/ directory

and edit line 10 and 11 to change the path to /initrd/etc/default/rcS and /initrd/etc/defaults/functions.

To get the same effect during booting as with SlugOS, create /etc/init.d/leds.boot as follows

and add it to the boot runlevel as above:

Add this line to local.start to set the status LED green once everything has finished booting:

Add this line to local.stop to have a flashing green/amber status LED at system shutdown and reboot:

OpenSlug 2.7 and below
Firstly, you will need to compile and install the OpenSlug leds program. Just pull out leds.h and leds.c from the OpenSlug source tarball (or from Subversion) and compile them (under your Gentoo system) with

{Root |gcc -Os -march=armv5te -mtune=xscale -o leds leds.c}}

and copy the resulting output leds to /usr/local/sbin. You will also need to create /dev/leds with

You can now use this program to set the LEDs. I created an initscript:

and added it to the boot runlevel:

Add leds.boot to the boot runlevel

I also added a line to local.start to set the status LED green once everything has finished booting:

Add this line to local.stop to have a flashing green/amber status LED at system shutdown and reboot:

Power Button
The default behaviour under SlugOS is to power off when the power button on the front is pressed. The default Gentoo behaviour is to restart when the button is pressed. To get the same behaviour as SlugOS, alter the "ctrlaltdel" entry in /etc/inittab:

Make app-misc/beep beep again
The standard app-misc/beep does not work on the slug. See http://bugs.gentoo.org/show_bug.cgi?id=235428 for an ebuild patching beep and also symlinking /usr/bin/beep to /bin/beep so that the leds script can also beep again.

Fixing hwclock
I had an issue where I couldn't sync the hwclock with the system time on my Slug. I could set the time on the Slug but after a reboot the time would always be current time - 4 hours. Trying to sync the hwclock via the command "hwclock --systohc" would return a fatal error. The reason is unknown to me. But, a fellow Slugger passed this tip on to me. To fix (as root):

Fixing hwclock

The chmods put the permissions on the /dev/rtc device that were on the original. I don't know if it necessary, but I did it anyway. After this run:

to set the proper time, and then

to sync the hwclock to system time. The hwclock command should work at this point. Reboot and check the system time - it should be okay. Worked for me!

MAC address
As of OpenSlug 3.10 and newer versions and with SlugOS-4.8beta at least the MAC address is correctly detected and handled by the kernel. Its unlikely that you will need this work around (and it actually stops udhcpc from working properly), however if you notice that the Slug changed its MAC address that's because their address is not fixed, but stored in flash memory and configured at each boot. To let Gentoo use this address, you might find it useful to add the following to you network configuration:

Note that /etc/default/sysconf referred to above is stored on the flash filesystem, so its path will depend on where the flash ends up mounted in your Gentoo filesystem (see above).

Attention: Be aware: with that little workaroud my MAC address changes every bootup, and looks like this: 42:10:BE:xx:xE:2C. Insert nothing in there will keep the right one!