Here I'm republishing an old blog post of mine originally from June 2017. The article has been slightly improved.

Building a BSD home router (pt. 3): Serial access and flashing the firmware

Part 1 of this article series was about why you want to build your own router, and how to assemble the APU2 that I chose as the hardware to build this on. Part 2 gave some Unix history and explained what a serial console is.

Building a BSD home router (pt. 1): Hardware (PC Engines APU2)

Building a BSD home router (pt. 2): The serial console (excursion)

In this post we will prepare a USB memstick to update the BIOS and connect to the APU2 using the serial console. Then we'll flash the latest firmware on there.

Cables and serial connections

In the ol' days you would simply connect the COM port on one machine to the COM port on the other. Today a lot of newer laptops don't even have a serial port (if yours still has one of those funny devices that you'd access through /dev/fd0, chances are pretty high though, that it also has a COM port!). Fortunately _USB to serial_ adapter cables exist, solving that problem.

The APU2 has a male DB9 (9 pins) serial port. RS-232 is the common standard for serial communication. According to it, some pins are used to transfer information while others are used to receive information. Now if you connect two machines with a straight serial cable, both will talk on the same pins and listen on the same pins. So both will send data over pins that nobody listens on and never receive anything on the other pins. This is not really useful. To make the connection work, you need a _crossed-over_ cable (a so-called _null modem_ cable or adapter). This means that the receiving pins on one end are paired with transmitting pins on the other end and vice versa.

I thought that I would never need a nullmodem cable at home. I still don't think that I might ever need a straight serial cable. And I could in fact take one home from work and return it the other day. However I could already see what would have happened in that case: When I get some time to tinker with my APU it will be on the weekend and I won't have the cable in reach when I need it. So I bought my own. And while I was at it, I decided to not only get a USB to RS-232 DB9 serial adapter cable (look for the PL2303 chipset translating USB to serial: It's well supported across a wide range of operating systems including FreeBSD). I also bought a null modem adapter and a gender changer. So now I'm completely flexible with my gear. However you probably just want to get a null modem cable USB/female DB9 (or ask somebody who has one if you could borrow it).

Another thing that you have to know is the _baud rate_ (modulation rate) for your connection. A higher baud rate means a faster connection. As long as both connected machines agree on the baud rate, everything is fine. If they disagree, this can lead to displaying garbage instead of the actual console or in seemingly nothing happening at all.

To flash or not to flash

At the time of this writing, PC Engines have released 5 updates [many, many more were released since then] for the APU2's firmware and if you like the improvements, it makes sense to put the newest version on there. They recommend booting TinyCore Linux and then using _flashrom_ to flash the BIOS.

Flashrom is available for FreeBSD, too. I would imagine that it works as well. However I have no experience with that and flashing stuff always bears the risk of bricking your machine (for which case PC Engines offers a small rescue device). If I had thought about this right at the beginning, I would probably have tried it out. But my APU2 is already updated and since this post is public and not just for me... Well, let's just do this by the book and use Linux for that.

PC Engine's rescue device

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

If you're a little anxious and don't feel well about flashing at all, leave it be; in general the old BIOS will do, too. Flashing according to a guide does not have a high risk of bricking your device but even a small risk is a risk.

***Disclaimer: You decide. And it's all your responsibility, of course.***

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Alright, we need to prepare a USB stick with TinyCore and the ROM on it. PC Engines even offer a howto guide showing how to create this using FreeBSD. That guide works, but it clearly shows that those guys know Linux a lot better than (modern) FreeBSD. For that reason I'm going to modify it slightly here and use today's tools.

Preparing the BIOS updater memstick

First we're going to download the _TinyCore_ tarball and the zipped ROM (you might want to take a look if a newer version than shown here is out) and install the _syslinux_ package (containing the that Linux bootloader):

% su -
# mkdir -p /tmp/apu2 && cd /tmp/apu2
# fetch http://pcengines.ch/file/apu_tinycore.tar.bz2 http://pcengines.ch/file/apu2_v4.0.7.rom.zip
# pkg install syslinux

Now attach your USB memstick to the system and after a couple of seconds look at the _dmesg_ if you don't know what device it will be attached to:

# dmesg | tail
[...]
da0 at umass-sim0 bus 0 scbus2 target 0 lun 0
da0: < USB DISK 2.0 PMAP> Removable Direct Access SPC-4 SCSI device
[...]

So for me it's _da0_ in this case and I need to supplement the "X" that I use in the following commands with "0". You should use whatever number you figured out. PC Engine's howto suggests zeroing out the stick and if it isn't a new and unused one that makes sense. In my case this leads to an error:

# dd if=/dev/zero of=/dev/daX bs=1m
dd: /dev/da0: Operation not supported
# mount
[...]
/dev/da0s1 on /media/disk (ext2fs, local, nosuid)

Looks like this is because GhostBSD automatically mounted _da0s1_ when it found an EXT2 filesystem from a previous task on there. So let's unmount that and try again:

# umount /media/disk
# dd if=/dev/zero of=/dev/daX bs=1m

Depending on the speed and size of your memstick (and the generation of your USB port), this can take quite some time to finish. And since dd normally is working quietly, you might want to know how far it came so far. Fortunately FreeBSD implements the SIGINFO signal. Just press _CTRL+T_ while it is running and it print some status information like this:

load: 1.52 cmd: dd 92084 [physwr] 379.15r 0.00u 0.56s 0% 3188k
2512+0 records in
2512+0 records out
2634022912 bytes transferred in 379.208179 secs (6946113 bytes/sec)

When it's done, we can create an MBR partitioning scheme on the now empty stick as well as an MBR partition and write the bootcode on the stick so that we can boot off of it at all:

# gpart create -s mbr daX
da0 created
# gpart add -t fat32 daX
da0s1 added
# gpart bootcode -b /boot/boot0 daX
bootcode written to da0

The next thing to do is putting a FAT32 filesystem on the partition and force install the syslinux bootloader there that will be chainloaded by the bootcode that we wrote into the MBR:

# newfs_msdos /dev/daXs1
newfs_msdos: trim 40 sectors to adjust to a multiple of 63
[...]
# syslinux -if /dev/daXs1

Now we need to mount the new filesystem and put the OS on there:

# mount -t msdosfs /dev/daXs1 /mnt
# tar xjf apu_tinycore.tar.bz2 --no-same-owner -C /mnt

We're writing to a FAT filesystem - and as the primary filesystem from a once popular single user OS it does simply not support concepts like file ownership. That's why we need "--no-same-owner" here (otherwise we'd see harmless but unnecessary warnings). As the next step we'll add the ROM image and check its integrity - we don't want to flash garbage on our APU and brick it, do we?

# unzip -d /mnt apu2_v4.0.7.rom.zip
# grep -c `md5 -q /mnt/apu2_v4.0.7.rom` /mnt/apu2_v4.0.7.rom.md5
1

Make sure that the last command outputs _1_ (in which case the calculated md5 hash matches)! If it does not, delete the zip file, download it again and extract it over the corrupt ROM file. Finally sync the filesystem, unmount it and remove the USB stick:

# sync
# umount /mnt

The memstick is ready. If you want to test it, boot some other PC or laptop from it. If you can read the line "Booting the kernel" and then nothing seems to happen anymore, it means that it's working. TinyCore is configured to use the serial console, that's why you don't see anything on your screen and your keyboard doesn't do anything after that. Just turn your computer off and plug the USB stick out.

Attaching the serial console and flashing the BIOS

Alright, back to the APU2 (finally). Put the memstick into one of the USB ports and attach your serial cable to the COM port. Now connect the other end of the null modem cable with another computer running FreeBSD (or Linux or whatever - any Unix-like should work, you'll just have to figure out how to connect to a serial console on your OS of choice).

Open a terminal, become root and attach the serial console (cuaU0 is the USB to serial adapter, 115,200 the baud rate):

% su -
# cu -l /dev/cuaU0 -s 115200
Connected

Now connect the APU2 to power and see what happens! If you don't do anything, the BIOS should load TinyCore from the memstick after a couple of seconds:

Connected to the serial console - and booting Linux (PNG)

If nothing happens, you might have the wrong cable (is it really crossed-over?). Or maybe you've mistyped the baud rate? The "Connected" by the way only means that your host system has attached to the serial cable. You'll get that message even when the other end is not connected to anything or the machine at the other end is turned off.

Once Linux was loaded, use flashrom to update the APU's firmware like PC Engines show in their howto. Then reboot.

Preparing to flash the BIOS (PNG)

The APU2's BIOS supports the serial console. That means that even before the machine has booted an operating system with serial console capability, you can access and configure the BIOS of the headless machine:

Serial access to the BIOS settings (PNG)

Another nice thing that comes with the APU is the _Memtest_ program. If you want to know whether your new hardware is actually good or might probably have bad ram, put it to the test for a couple of hours or over night:

The firmware comes with Memtest (PNG)

If you're using _Call Unix_ ("cu") as in my example, you can close the serial connection using the character sequence ~. (tilde and dot).

What's next?

You now know how to access your box using the serial console. Next time we'll make use of that skill again to put _pfSense_ as the first of two options on the APU. The other option is _OPNsense_ which will be covered in a later post. Both are FreeBSD-based router/firewall operating systems.

Building a BSD home router (pt. 4): Installing pfSense

BACK TO 2017 OVERVIEW