Sunday, August 01, 2010

FreeBSD on the SheevaPlug HOWTO

Six months ago I purchaged a SheevaPlug computer. After sharing my experiences about the device with my friend Minas, he managed to get his hands on the similar Sheeva computer and he installed FreeBSD on it. The following article/HOWTO, on installing FreeBSD on the Sheeva is written by him. Minas is a FreeBSD advocate for many years now.

Recently my friend Jim, bought the plugcomputer Sheeva eSata, which is just like the SheevaPlug but with an eSata II port. My friend asked me to change the factory installed
operating system Ubuntu, with FreeBSD. In my opinion FreeBSD is better suited for 24h/365d servers. The installation process took me almost 3 days and had some difficult parts I needed to overcome. I will share this process here with other FreeBSD supporters. Following these steps you will have a running FreeBSD in less than a few hours.

At first, my friend and I, contacted our seller, requesting support for installing FreeBSD on the plug, but they responded that they could not offer such an option. However, they provided some URLs and instructions of how to do it. Unfortunately, not all the required information was found in a single page, but this hopefully will change with this article.

The Sheeva FreeBSD HOWTO:

  • A Running FreeBSD PC
  • eSata SheevaPlug
  • eSata external disk that supports USB also
  • Basic knowledge of FreeBSD (read at least 1 time the FreeBSD handbook)

There are 6 steps in my HOWTO. Do the 6 steps and you will 100% succeed.

1) Setting Up Console
The only way to change crucial parameters (specifically boot-up, firmware update)
is by connecting through a serial port emulator, using the USB cable provided by the company.

If you have a Windows PC then you just install the driver that is provided, you attach the cable to the plug and the computer, you open a terminal application and you see the login prompt. Of course Sheeva should be already powered on.

If you have successfully connected to the serial console of Sheeva go to step 2. If you were unable to connect to serial console of Sheeva, or want to use a FreeBSD machine to connect to Sheeva then continue.

In order to communicate with Sheeva using the tools of FreeBSD (I will name the FreeBSB box 'TerminalFreeBSD'), load the appropriate kernel modules. As root issue:

kldload ucom
kldload uftdi

ucom is required for USB tty support and uftdi is required for USB support for the serial adapter of SheevaPlug.

Attach the provided USB cable to the mini USB on the SheevaPlug and on a USB port on the computer which will be used as terminal (FreeBSD or windows).

After attaching this on the TerminalFreeBSD, you will see in the console messages such as:

ugen1.2: <FTDI> at usbus1
uftdi0: <SheevaPlug JTAGKey FT2232D B> on usbus1
uftdi1: <SheevaPlug JTAGKey FT2232D B> on usbus

and you will notice in the /dev directory the automatic creation of some special character devices that have a capital 'U' in the name (denoting USB). Verify this as:

ls -l /dev/*U*

and you will see entries like the following:

crw-rw---- 1 uucp dialer 0, 80 Jul 28 12:25 /dev/cuaU0
crw-rw---- 1 uucp dialer 0, 81 Jul 28 12:25 /dev/cuaU0.init
crw-rw---- 1 uucp dialer 0, 82 Jul 28 12:25 /dev/cuaU0.lock
crw-rw---- 1 uucp dialer 0, 95 Jul 28 12:48 /dev/cuaU1
crw-rw---- 1 uucp dialer 0, 96 Jul 28 12:25 /dev/cuaU1.init
crw-rw---- 1 uucp dialer 0, 97 Jul 28 12:25 /dev/cuaU1.lock
crw------- 1 root wheel 0, 77 Jul 28 12:25 /dev/ttyU0
crw------- 1 root wheel 0, 78 Jul 28 12:25 /dev/ttyU0.init
crw------- 1 root wheel 0, 79 Jul 28 12:25 /dev/ttyU0.lock
crw------- 1 root wheel 0, 83 Jul 28 12:25 /dev/ttyU1
crw------- 1 root wheel 0, 84 Jul 28 12:25 /dev/ttyU1.init
crw------- 1 root wheel 0, 90 Jul 28 12:25 /dev/ttyU1.lock

Lets connect from the TerminalFreeBSD to the console of Sheeva. You have to use the 'cu' with appropriate parameters. After trial and error, I found that you have to use speed 115200 (otherwise it will show garbage or it wont work). In my example
I have two outgoing serial interfaces cuaU0 and cuaU1. In order to find out which one is attached to USB, I tried with cuaU0 but even though it said 'connected' pressing the enter did not reveal a 'login:' prompt. Using cuaU1 I worked. So in
my case in order to connect through terminal I issued:

cu -s 115200 -l /dev/cuaU1

If you give this command and after pressing enter nothing happens, press the
escape sequence by is issuing the following 3: (1) enter (2) ~ (3) ctrl+d
and you will escape to login prompt. Try next cuaU* port until you find the one working.

Remember: If you have windows as a terminal pc you dont need the above sequence. You
just install the drivers, plug the cable and you are ok.

2) Enabling the eSata drive

eSata Sheeva has a USB port and a eSata port. FreeBSD has to be installed on an
external storage, because it does not provide NAND support until this point.
You can install FreeBSD on USB or in eSata disk, but note the following:

  1. If you install on USB you will have a hard time to make it work, because during the kernel load, USB is detected after root mount, which means that you won't be able to mount the root partition/label unless using some special patches, which they have serious problems (they dont apply cleanly to stable version, because they target a specific version like 8.0). So DO NOT use USB.
  2. If you install on eSata this is the best. eSata is detected very early as an /dev/ad* disk, so you won't have any problem. Trust me. Go with the eSata and the procedure will be very easy.
From now on, I will assume that you continue with eSata.

Plug the eSata on the powered-off SheevaPlug, and power it on. In the Terminal console, you will see some boot up messages, and a prompt to press enter if you want to interrupt the boot loader. Press enter as soon as you see this prompt, to go to boot loader.

Issue the command:

ide reset

if you hard disk gets detected you are lucky to have the updated u-boot loader version. Skip to part 3.

If you see a message that reports nothing detected, then you have to go to step 2b to update the U-boot firmware. Dont worry is very easy.

2b) Updating the boot loader of eSata Sheeva in case your eSata disk is not detected

In order to update the U-boot firmware you will need a USB flash drive, that is FAT formatted.

Download from: the version that has eSata in the title. I download the file uboot-sata-090903.bin and also the md5 signature of this.

If you like, verify that the download is ok, by calculating the md5 of the file uboot-sata-090903.bin (issue: 'md5 uboot-sata-090903.bin') and compare it with the contents of the file: uboot-sata-090903.bin.md5

Place the file uboot-sata-090903.bin on the USB Flash drive and plug it on Sheeva.

In order to perform the update you have to (a) enable the USB (b) load the image (c) erase NAND memory (d) write u-boot image to NAND memory (e) reset the Sheeva. These 5 items are performed with the following commands, respectively:

usb start
fatload usb 0:1 0x0800000 uboot-sata-090903.bin
nand erase 0x0 0xa0000
nand write 0x0800000 0x0 0xa0000

ide reset

If you see your hard disk now (as in my case) you can continue to step 3. Otherwise check that your eSata has power, or it is working or perform again the update of sata u-boot with another version (if exist).

3) Partition (fdisk) & Labeling (bsdlabel) eSata hard disk

A common practice in installing FreeBSD is to have separate partitions of major areas of disk. Some people like to have one big flat partition, but I disagree with this. So in this step, we will partition the disk.

Plug the eSata disk on the FreeBSD in the USB port. USB port is hot plug and play, but eSata is not. eSata should be connected with PC powered-off.

After attaching the USB external disk you should see messages that da* disk was detected. If not, you should load kernel modules that support this

kldload usb
kldload umass

You should partition your disk using 'sysinstall'. Go to 'Configure', Then select 'fdisk' then select the da* disk.

In the fdisk screen you should create 2 partitions: One partition 20MB for FAT (for loading kernel) and leave the rest for freeBSD.
Save (write) and exit to command prompt.

You should label your FreeBSD slice as follows (this is not required but is very helpful to have different parts of the disk for different directories). Use 'sysinstall'. Go to 'Configure', Then select 'label' then select the da* disk.

The slices that you will create will be mounted temporary on the /mnt subdirectory. This will be done just for the installation.

Create the following slices:
  1. a label 512MB, without softupdates, mounted on /mnt
  2. a label 1G, for swap
  3. a label 512MB, mounted on /mnt/var
  4. a label 15GB, mounted on /mnt/usr

You can create a label for /mnt/home (as I did for home folders) and a label for /mnt/store (for the rest of the disk)

On a piece of paper write down all the label letters and the folders. In my case I had
  • slice: 2 label: d (root)
  • slice: 2 label: b (swap)
  • slice: 2 label: e (usr)
  • slice: 2 label: f (var)
  • slice: 2 label: g (home)
  • slice: 2 label: h (store)
Save(write) and exit to command prompt.

4) cross-building FreeBSD world and kernel for Sheeva

The following steps will be done on the TerminalFreeBSD.

Update your /usr/src to the latest version of FreeBSD. In my case I selected 8-STABLE.

Build world for Sheeva as follows:

cd /usr/src
make -j 8 buildworld TARGET_ARCH=arm

(remember if you have trouble compiling buildworld try to remove the '-j 8')

Build kernel for Sheeva as follows:
Create a kernel file named MYSHEEVA and place it on /usr/src/sys/arm/conf/

I optimized my Sheeva Kernel by removing lines that I did not need. I included support for 'ad', and specified the root device (ROOTDEVNAME=). I had to specify the ROOTDEVNAME because, by default FreeBSD kernel mounts the 'a' label of the currently slice. Unfortunately, I had created thelabel for root partition to be 'd' (*I tried with bsdlabel to change it but I had the error "GEOM Class not supported"),thus I had to hardcode in the FreeBSD the root device name.

NOTE: If your root device label is different than mine (mine was: d), then change appropriate the label ROOTDEVNAME=...

This is my MYSHEEVA:

------CUT HERE-----
include "../mv/kirkwood/std.sheevaplug"
options SCHED_4BSD #4BSD scheduler
options INET #InterNETworking
options FFS #Berkeley Fast Filesystem
device md
device ata
device atadisk # ATA disk drives
options ATA_STATIC_ID # Static device numbering
# Root fs on device
options ROOTDEVNAME=\"ufs:/dev/ad2s2d\"

options SYSVSHM #SYSV-style shared memory
options SYSVMSG #SYSV-style message queues
options SYSVSEM #SYSV-style semaphores
options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions

# Pseudo devices
device random
device pty
device loop

# Serial ports
device uart

# Networking
device ether
device mge # Marvell Gigabit Ethernet controller
device mii
device e1000phy
device bpf
options HZ=1000
device vlan
options USB_DEBUG # enable debug msgs
device usb
device ehci
device umass
device scbus
device pass
device da
------CUT HERE-----

Build kernel of MYSHEEVA as follows

cd /usr/src

5) Installing the world and kernel of Sheeva.

You have completed succesfully the cross-compilation of world+kernel. The next step is to install them. You have already mounted the slice and labels of the external disk to /mnt. Verify this by using


Issue the following commands to install the world.

make DESTDIR=/mnt TARGET=arm TARGET_ARCH=arm distrib-dirs
make DESTDIR=/mnt TARGET=arm TARGET_ARCH=arm distribution
make DESTDIR=/mnt TARGET=arm TARGET_ARCH=arm installworld

Create a basic fstab file on /mnt/etc and put the following (which you will have to change them accordingly to your case):

/dev/ad2s2d / ufs rw,noclusterr,noclusterw 0 0
/dev/ad2s2b none swap sw 0 0
/dev/ad2s2e /usr ufs rw,noclusterr,noclusterw 1 1
/dev/ad2s2f /var ufs rw,noclusterr,noclusterw 2 2
/dev/ad2s2g /home ufs rw,noclusterr,noclusterw 2 2
/dev/ad2s2h /store ufs rw,noclusterr,noclusterw 2 2

Note that our disk on SheevaPLUG will be on eSata so we have to use ad as the device name. You may have to change the number after 'ad', in case that your disk gets detected at other channel, as it will be shown. In my case, it was ad2.

Note also, that you have to issue the parameters 'noclusterr,noclusterw' in mount options, otherwise you will have corruption on file systems (as I find out after some hours of strange problems).

Edit /mnt/etc/ttys

and go to line that starts with


After the word vt100 there is a word 'off' or 'on'. Change this to 'on' because we would like to have a console on serial port. Also the other lines before this should have 'off' because there are no ttyv? devices.

The first lines of my file are:

console none unknown off secure
ttyv0 "/usr/libexec/getty Pc" cons25 off secure
# Virtual terminals
ttyv1 "/usr/libexec/getty Pc" cons25 off secure
ttyv2 "/usr/libexec/getty Pc" cons25 off secure
ttyv3 "/usr/libexec/getty Pc" cons25 off secure
ttyv4 "/usr/libexec/getty Pc" cons25 off secure
ttyv5 "/usr/libexec/getty Pc" cons25 off secure
ttyv6 "/usr/libexec/getty Pc" cons25 off secure
ttyv7 "/usr/libexec/getty Pc" cons25 off secure
#ttyv8 "/usr/local/bin/xdm -nodaemon" xterm off secure
# Serial terminals
# The 'dialup' keyword identifies dialin lines to login, fingerd etc.
ttyu0 "/usr/libexec/getty std.9600" vt100 on secure

At this point it will be very nice to update your /usr/ports tree and then copy to Sheeva.

cp -R /usr/ports /mnt/usr

In order to have the latest /usr/ports which is needed in order to install programs. Remember, that there are no pre-build packages for arm architecture, and thus you cannot do a 'pkg_add -r'. You have to build all packages by your own.

The installation is now complete, you have to umount the filesystems
of the external disk. In my case was:

umount /mnt/usr
umount /mnt/var
umount /mnt

The last step is to put the kernel file on the slice 1.

First you have to newfs as FAT partition the slice 1. Do this as:

newfs_msdos /dev/da0s1

(remember that if your USB disk is attached to other /dev/da? change the number accordingly).

Mount the slice as msdos

mount -t msdosfs /dev/da0s1 /mnt

and copy the kernel to fat partition.

cp /usr/obj/arm/usr/src/sys/MYSHEEVA/kernel.bin /mnt
umount /mnt

6) Connecting eSata on Sheeva and first boot of FreeBSD

umount all the da* partitions of /mnt and verify that there are no da* mounted by:


Connect the disk to the powered-off eSata.
Connect to the TerminalFreeBSD using the procedure highlighted in previous
step with 'cu'.

Power-on the Sheeva.
Interrupt the u-boot by pressing enter.

First take note of your existing uboot bootcmd environment variable using and placing it somewhere safe:

printenv bootcmd

The default should be something like:

bootcmd=nand read.e 0x800000 0x100000 0x400000; bootm 0x800000

Then in the loader issue the following to (a) change boot sequence, (b) save this so from now on you will be loading the kernel from the external device (c) boot the device

setenv bootcmd 'ide reset;fatload ide 1:1 900000 kernel.bin;go 900000'

NOTE: If you have an error on boot, like the image not found, check that you have copied the kernel.bin on the fat partition. Also you may change the 1:1 line to 0:0, 0:1, 1:0 , 1:1 . One of these combinations will surely work. This depends to what channel the hard disk is detected. Mine was on 1:1, and this was found as: ad2.

After issuing boot, then you see the kernel loading. You will see the line

ad? XXXX

If you see a line starting ad2:

ad2: 305245MB at ata1-master UDMA100 SATA 3Gb/s)

then you are ok for fstab, otherwise note the number of ad? and you have to put the drive back to the TerminalFreeBSD and mount the USB slice 2, label of rootpartition (you did not it previously) and change the /mnt/etc/fstab from ad2
to ad? with ? the number that is detected by the Sheeva. Also, you have to rebuild a kernel by changing the ROOTDEVNAME= to the new ad? number.

Congratulations. You should now have an up and running FreeBSD Sheeva!

Some workarounds are mentioned here for problems that I've encountered:

==workaround 1==
If you have not copied /usr/ports from your freebsd machine, you can do a 'portsnap fetch' which will fetch an updated /usr/ports.

Unfortunately, I found out the hard way that portsnap has a bug (not documented) that does not fetch an updated /usr/ports/Mk but an outdated (or buggy one).

This results in many errors when building ports like 'duplicate script' and other makefile options. In order to alleviate this problem, you should grab the /usr/ports/Mk from your updated TerminalFreeBSD, rm -rf your SheevaPlug /usr/ports/Mk and place it there. All the Makefile problems are now solved. If you had copied all the /usr/ports as I had suggested earlier then you are OK.

==workaround 2==
If you install some ports, that use the 'xz' compression, you will notice some core dumps. It seems that 'xz' compression that is included by default in 8 world is broken on ARM architecture. The workaround is to compile it from ports.

You can go to /usr/ports/archivers/xz but you cannot just do a 'make', because it will say that 'xz' is already in the base system'. So you have to do a simple trick. open the Makefile on this directory and before the end comment (put a '#') in front of the check of the operating system.

My lines are now:

#.if ${OSVERSION} >= 900012 || (${OSVERSION} <>= 800505)
#IGNORE= is already in the base system

Then do a

mv /usr/bin/xz /usr/bin/xz-2


cd /usr/ports/archivers/xz ; make ; make install

and xz now works flawlessly!

Additional Info:
The following URLs helped out, but most of the work was trial and error because a comprehensive how-to guide as this one was not found.