Category Archives: freebsd

PC Engines APU2C4

Installing FreeBSD on PC Engines APU2

PC Engines APU2C4

The PC Engines APU2C low-power network computer on my desk, with serial console, the first ethernet port and a USB stick connected.

PC Engines has been producing small, low-power systems with AMD CPUs for a long time. Among the great features for building your own router are built-in serial console and multiple quality Ethernet controllers. For a project I selected the apu2c4, a system with three gigabit Ethernet ports and 4 GB of RAM. Together with a small M2 SSD module, you have a decently powerful machine to run as a router. In fact, it has enough capacity to run some applications as well, or even small VMs if you’re so inclined!

Installing FreeBSD

Installing FreeBSD on the APUs is fairly straightforward; however, a small number of gotchas might trip you up. Here’s how I managed to complete the install, and update the APU firmware once I had FreeBSD installed.

  1. Download the FreeBSD memstick installer image. I used my closest FreeBSD mirror to download FreeBSD-11.2-RELEASE-amd64-memstick.img.
  2. Copy the image to a USB stick that is at least as large as the image; 1 GB should be sufficient. I had trouble when I did the copying on my Mac with the resulting stick not working properly; using a FreeBSD box did the trick for me.
  3. Before booting from the USB stick, mount the UFS partition on a FreeBSD machine. For 11.2, that’s da0s2a; for other releases, it might be different. You can use gpart list to identify the UFS partition to mount.
  4. Add the following lines to /mnt/boot/loader.conf to properly enable just the serial console, and give the USB subsystem enough time to attach the USB stick:
  5. vfs.mountroot.timeout="10"
    comconsole_speed="115200"
    console="comconsole"
  6. Unmount /mnt and move the stick to the APU.
  7. Connect a serial terminal to the APU console port; I usually use an USB dongle and a null modem cable or adapter, and my own simple serial console program or cu(1), using 115200 baud.
  8. Boot from the USB stick and install FreeBSD as you would on any other PC. Before you reboot:
  9. Make sure to add the console and comconsole_speed variables to /boot/loader.conf on the installed system on the APU as well. Unless you add them, you won’t be able to log in to the console.

If you forget to edit /boot/loader.conf, not all is lost: you can change the settings during boot. But because the loader detects both the serial console and a keyboard (although the APU has no support for a keyboard or built-in graphics), it is somewhat cumbersome, as the console output will be screwed up.

Updating the BIOS

The APUs use CoreBoot as their BIOS. PC Engines has ready to use CoreBoot images on their own GitHub page. You can update the BIOS using flashrom, a command line tool to program firmware devices across many devices and platforms.

To update the APU BIOS:

  1. Download the correct CoreBoot image for your model of APU from pcengines.github.io, directly to the APU. I picked apu2 v4.8.0.1, which was the newest at the time of this post.
  2. Extract the firmware file:
  3. $ fetch http://pcengines.ch/file/apu2_v4.8.0.1.rom.tar.gz
    apu2_v4.8.0.1.rom.tar.gz                      100% of  852 kB 4100 kBps 00m00s
    $ tar xf apu2_v4.8.0.1.rom.tar.gz 
    $ ls -l
    total 862
    -rw-r--r--  1 stb  wheel  8388608 Jun  8  2018 apu2_v4.8.0.1.rom
    -rw-r--r--  1 stb  wheel       52 Jun  8  2018 apu2_v4.8.0.1.rom.md5
    -rw-r--r--  1 stb  wheel   873087 Jun 26  2018 apu2_v4.8.0.1.rom.tar.gz
  4. Install the utility:
    $ sudo pkg install flashrom
    Updating FreeBSD repository catalogue...
    FreeBSD repository is up to date.
    All repositories are up to date.
    Checking integrity... done (0 conflicting)
    The following 1 package(s) will be affected (of 0 checked):
    
    New packages to be INSTALLED:
            flashrom: 1.0
    
    Number of packages to be installed: 1
    
    Proceed with this action? [y/N]: y
    [1/1] Installing flashrom-1.0...
    [1/1] Extracting flashrom-1.0: 100%
  5. Check that flashrom can talk to your motherboard OK:
  6. $ sudo flashrom -p internal
    flashrom v1.0 on FreeBSD 11.2-RELEASE (amd64)
    flashrom is free software, get the source code at https://flashrom.org
    
    Using clock_gettime for delay loops (clk_id: 4, resolution: 2ns).
    coreboot table found at 0xcfde9000.
    Found chipset "AMD FCH".
    Enabling flash write... OK.
    Found Winbond flash chip "W25Q64.V" (8192 kB, SPI) mapped at physical address 0x00000000ff800000.
    No operations were specified.
  7. Verify the version currently installed:
  8. $ sudo dmidecode -t bios
    # dmidecode 3.1
    Scanning /dev/mem for entry point.
    SMBIOS 2.7 present.
    
    Handle 0x0000, DMI type 0, 24 bytes
    BIOS Information
            Vendor: coreboot
            Version: v4.8.0.1
            Release Date: 20180608
            ROM Size: 8192 kB
            Characteristics:
                    PCI is supported
                    PC Card (PCMCIA) is supported
                    BIOS is upgradeable
                    Selectable boot is supported
                    ACPI is supported
                    Targeted content distribution is supported
            BIOS Revision: 4.0
            Firmware Revision: 0.0
  9. Program the new version to the flash chip:
  10. $ sudo flashrom -p internal -w apu2_v4.8.0.1.rom
  11. If flashrom complains about the image not matching the mainboard, you need to force the programming as suggested in this forum post.
  12. Reboot the APU to activate the new firmware.

(Astute readers will notice that the above output already shows version 4.8.0.1 being installed; I took that output after successfully upgrading.)

I tried to update the BIOS using the procedure suggested by PC Engines, using TinyCore, but I had trouble creating a TinyCore USB stick. Luckily I came across this BSD Foren post and realised that I could just use FreeBSD directly.

Hooking up Harmony Hub and generic ZigBee Lights to HomeKit

Home automation seems to be the rage this christmas, with gadgets to control lights, heating and entertainment systems wirelessly, maybe even with only your voice.

I’ve been using Logitech’s Harmony Hub for many years now, and are very happy being able to switch on all devices needed and set them to the right channels: the TV, the surround receiver, the TV and an Apple TV, Fire TV or Bluray player, with single button press on a single remote.

Harmony Hub isn’t supported by Apple’s HomeKit, but so far, that wasn’t really a concern, since I wasn’t using anything else that would be able to be controlled by HomeKit. But in December, I broke down and got a bunch of Philips Hue lights. Naturally, tying Hue and Harmony together became a challenge.

I also have a number of light fixtures that Philips has no bulbs for; I decided to get an Osram Lightify Smart Plug to be able to at least turn the light off and on through the system. While it’s simple to connect the Smart Plug to the Hue controller, Philips somehow fails to offer up 3rd-party devices to either HomeKit or Hub. (Ikea Tradfri components seem to suffer the same fate.)

So I started looking around, to find a way to control everything through a single interface. It seems that HomeKit together with homebridge manages to do exactly what I want: offer all devices connected to the Hue hub to HomeKit (through homebridge-hue), and allow me to control the Harmony Hub (through homebridge-harmonyhub).

Here’s how I got this all working in FreeBSD.

Installing homebridge on FreeBSD

Creating a user

homebridge is a daemon process that mediates between HomeKit, Hue and Harmony. As such, it needs to run permanently. For security reasons, we do not want to run homebridge as root, but as a less privileged user homebridge. To create the user, I used vipw and consulted /usr/ports/GIDs to look for an id in the range below 1000 that is not yet used by any port. Instead of vipw, you can use adduser(1). I gave the user /usr/sbin/nologin as a shell since we’re never going to log in directly as a user.

Installing packages

There is no FreeBSD port for homebridge, but the installation is relatively straightforward. The installation instructions for homebridge insist that the NPM must be installed globally; I briefly tried to install locally, but couldn’t get it work.

Let’s start with the prerequisites, and a hack:

# pkg install npm-node8 avahi-libdns
# ln -s /usr/local/include/avahi-compat-libdns_sd/dns_sd.h /usr/local/include

The FreeBSD port for avahi-libdns puts the include file into its own subdirectory (so it won’t conflict with mDNSResponder), but the NPM packages expect it to be in /usr/local/include. The easiest way to fix this is to create the symlink. Since I’m running avahi, I have not investigated how to run homebridge with mDNSResponder.

After this, we can starting installing the NPM packages:

# npm install -g mdns
# npm install -g --unsafe-perm homebridge
# npm install -g homebridge-hue homebridge-harmonyhub

As of homebridge-harmonyhub 0.2.1, you’ll need to hack the broadcast address that it uses to find the Harmony Hub. Edit /usr/local/lib/node_modules/homebridge-harmonyhub/node_modules/harmonyhubjs-discover/lib/ping.js and change the address in line 9 to the appropriate broadcast address for the network that your Hub is connected to. For example:

this.address = '192.168.1.255';

Configuring Homebridge

Create a config file in the homebridge users’ home directory, as .homebridge/config.json. I created the initial file like this:

{
    "bridge": {
        "name": "Homebridge",
        "username": "CC:22:3D:E3:CE:30",
        "port": 51826,
        "pin": "031-45-154"
    },
    
    "description": "My Homebridge",

    "accessories": [
    ],

    "platforms": [
        {
            "platform" : "Hue",
            "name" : "Hue",
            "users": {
            },
            "lights": true,
            "nativeHomeKit": false,
            "sensors": true,
            "excludeSensorTypes": ["CLIPPresence", "Geofence"]
        },
        {
            "platform": "HarmonyHub",
            "name": "Hub",
        }
    ]
}

Then, start homebridge for the first time:

sudo -u homebridge homebridge

The output from this is important in two ways: homebridge-hue will connect to the Hue bridge, wait for you to press the button to authorise the pairing, and then display the username and token for this connection. You’ll need to copy the output and add it to the users key for the Hue platform entry in the configuration. You will need to restart homebridge for this config change to become effective.

Also, the terminal output will show a QR code you can use to connect homebridge as a bridge to HomeKit, using the Home app on your phone or iPad. You can also enter the code manually, in this example the code is 031-45-154.

Running homebridge as a daemon

There’s (at least) two ways to run homebridge in the background: using tmux(1) or daemon(8)

WIth tmux(1) (or screen(1)), you can run a terminal session independent of the current login. You can detach from that session at any time, and it will continue to run; you can also re-attach at a later time. This allows you to start homebridge, observe all the log output, and then detach from the session, keeping it running. If you need to look at the log output, you can reattach. This is most useful while you’re optimising the configuration, or trying out additional plugins.

For a more production-oriented setup, you can use daemon(8) and an rc(8) script. The following script /usr/local/etc/rc.d/homebridge creates a service homebridge that you can enable and disable from rc.conf(5):

#!/bin/sh
#
# PROVIDE: homebridge
# REQUIRE: NETWORKING SYSLOG
# KEYWORD: shutdown
#
# Add the following lines to /etc/rc.conf to enable homebridge:
#
#homebridge_enable="YES"

. /etc/rc.subr

name="homebridge"
rcvar="homebridge_enable"

load_rc_config $name

: ${homebridge_user:="homebridge"}
: ${homebridge_enable:="NO"}
: ${homebridge_facility:="daemon"}
: ${homebridge_priority:="debug"}

command="/usr/local/bin/${name}"
procname="/usr/local/bin/${name}"
home="$(eval echo ~${homebridge_user})"

pidfile="/var/run/${name}.pid"

start_cmd="${name}_start"

homebridge_start() {
	/usr/sbin/daemon -S -l ${homebridge_facility} -s ${homebridge_priority} \
		-u ${homebridge_user} -p ${pidfile} \
		/usr/bin/env -i \
		"HOME=${home}" \
		"PATH=/usr/local/bin:${PATH}" \
		$command
}

run_rc_command "$1"

Now the last thing I need to figure out is which Siri commands to use to activate a scene. Then I can switch on the entertainment center and dim the lights with a single voice command!

nsupdate woes

Over the past three days, I’ve been trying unsuccessfully to set up a fresh name server (using Ansible and Vagrant) to play around with nsupdate and some potential middleware to automate updating DNS zones. Unfortunately, I couldn’t find any good documentation on all the specifics, just a lot of how-tos that somehow all did’t really work for me. I kept getting this error:

client 127.0.0.1#60530: request has invalid signature: TSIG example.com: tsig verify failure (BADKEY)

I will upload my Ansible role for this to Github shortly, but I felt it necessary to spare the next person the pain of getting it all to work.

To use nsupdate, you need to give bind a key, associate that with a zone, and then use that key with nsupdate. Sounds easy enough, right? What all the tutorials fail to mention is that the key files and the name of the key entries in named.conf are all significant.

First, you need to decide what to call your key. It doesn’t matter for which zones you will use it, or from which hosts you will run nsupdate, but you will need to pick a name and stick to it. You can’t change it later, you will need to create a new key if you don’t like the name.

$ dnssec-keygen -a HMAC-MD5 -n HOST -b 512 mysamplekey

This will create two files. You need both of them, and you can’t change the files’ names.

Next up, you need to add the key to named.conf, and allow requests signed by that key to update a zone (or more):

key "mysamplekey" {
    algorithm hmac-md5;
    secret "base 64 encoded key";
};

zone "example.com" {
    allow-update { key "mysamplekey"; };
    type master;
    file "dynamic/example.com";
};

It is important to remember that “mysamplekey” needs to be the exact same string as from the key generation!

Armed with this configuration, you should be able to update example.com:

$ nsupdate -k Kmysamplekey+123+45678
debug yes
server 127.0.0.1
zone example.com
update add foobar 10 A 192.0.2.1
send

Ab Herbst muss man auch seinen PC rooten

Wer noch nichts davon gehört hat: Mit Windows 8 hat Microsoft die BIOS- und Systemhersteller „überzeugt“, dass PC nur dann mit Windows 8 geliefert werden dürfen, wenn diese SecureBoot unterstützen und per Default aktiviert haben. Gnädigerweise erlaubt Microsoft den Herstellern, SecureBoot abschaltbar zu machen. Wie einfach das geht, und ob es überhaupt implementiert wird, bleibt aber den Herstellern überlassen. Soweit so schlecht.

Fedora hat sich jetzt entschieden, über das Microsoft-Programm ihren Bootloader zu signieren, damit man in Zukunft Fedora booten (und installieren) kann, ohne SecureBoot auszuschalten.

Booting from an USB disk – even when your system doesn’t support it

I like using VMware Fusion on my Mac, but it has one shortcoming: it cannot boot from USB devices. You can use disk images (floppy, CD/DVD and harddisk) as well as a physical optical drive, but USB devices are not available. That’s unfortunate if you want to use VMware to prepare a hard disk for a machine, and want to test booting off that system before installing it in the machine.

When I install a new FreeBSD machine, I often start out from an existing FreeBSD machine and install directly from that running system, instead of booting off an install DVD. Obviously, using a virtual machine for this bootstrapping system, together with a USB hard disk adapter, is very convenient. But without being able to boot the VM off that USB disk, testing can be cumbersome.

I was very happy to come across Plop, a boot manager with many features. The most interesting one for me is it’s support for booting off USB devices without BIOS support. Plop includes its own U/O/EHCI driver, supporting standard USB 1.1 and USB 2.0 devices and ports.

Also very important: Plop can be run off a CD or floppy image, so you don’t need to (re-)configure your main hard disk. If I feel adventurous, I might look into patching the Plop BIOS extension into VMware, making booting even easier. For the time being, I’m using the floppy image, since none of my virtual (nor physical) machines have floppy drives any more.

Also, when you have an older machine which BIOS does not support booting off USB devices, Plop might be very helpful!

Getting sshd to start as early as possible

In FreeBSD, sshd by default gets started quite late in the boot process, about the same time a console will show the login prompt. There’s quite a few services that can make trouble and hang before that. Annoyingly, you can’t fix a stuck system via ssh, since it’s not started yet. But as it turns out, sshd can be started quite a bit earlier than FreeBSD does by default.

The rcorder keywords in /etc/rc.d/sshd normally look like this:

# PROVIDE: sshd
# REQUIRE: LOGIN cleanvar
# KEYWORD: shutdown

Change the rcorder keywords like so:

# PROVIDE: sshd
# REQUIRE: NETWORKING cleanvar
# BEFORE: mountcritremote
# KEYWORD: shutdown

 

Now sshd will be started right after the network has been configured.

Note that starting sshd before certain parts of the system are ready might give you temporary or permanent errors. For example, starting sshd before the user home directories are mounted might cause problems with logins. However, if your machine has all critical filesystems on local disks, making these changes should not pose any problems, and will allow you to log in while the rc scripts are still running, giving you the opportunity to fix any misbehaving services.

Running bash as root’s shell only when it’s not broken

I like bash, mostly for its interactive features over FreeBSD’s standard Bourne-compatible shell, ash.

Setting bash as the default shell for the root user however has a big downside: if you ever break bash or any of the libraries it depends on, you can’t log in as root anymore to fix it. I’ve tried quite a few ways to work around this, and I think I’ve finally figured out a good solution: leave the root shell as /bin/sh, and add this snippet at the end of /root/.profile:

[ -z "$BASH" ] && /usr/local/bin/bash -c 'true' && exec /usr/local/bin/bash

This will start bash, but only if the shell sourcing .profile isn’t bash, and bash can actually successfully be executed.

In FreeBSD 9, ash has apparently grown command name completion. Together with the editing functions (already available in FreeBSD 7), this might allow me to switch to ash as the default shell.

 

FreeBSD, CUPS and iPad printing

For the longest time, I couldn’t get CUPS configured on my FreeBSD server successfully. Between CUPS access rules, foomatic drivers and avahi announcements, I had terrible trouble making heads or tails of the nondescript error messages I was getting.

Spurned on by the arrival of an iPad, I finally sat down and worked through configuring CUPS and avahi. So I don’t have to go through all the fiddling again, here’s a recipe of what I did.

TEMPer USB Thermometer

Measuring temperature in a PC should be easy: after all, most mainboards have extensive monitoring capabilities for temperature and voltage levels built-in. Unfortunately, very few of these facilities are documented properly, and software support is lacking. Instead of trying to navigate the maze that is lm-sensors (which isn’t even available for FreeBSD), I decided to look for some USB-based solution.

There’s a reasonably cheap chinese USB thermometer called TEMPer. I got mine from Brando for 12 Euros. It’s a USB-to-serial chip from WinChipHead. It’s DTR, RTS, and CTS lines are used to connect a LM75 I²C temperature sensor. To talk to the LM75, you need some bit-banging driver.

I’ve put together a command line utility for the TEMPer that can program the built-in thermostat (TEMPer has a LED connected to that output) and print out temperature measurement data. It does it’s job, and might serve as an example on how to do I²C over a simple interface.

Patch to vmmouse to make it work in FreeBSD

Here’s a patch to the vmmouse port that activates the driver unconditionally. This makes the VMware mouse driver work in the default configuration in FreeBSD (7 and 8).

When xorg moved to use hal by default, the vmmouse driver needed to be registered with hal. This would work fine, except for the the current port version of hal (hal-0.5.11_25) not supporting a command line option that the probe script for vmmouse needs, and the matching code that determines whether to probe for VMware never matching on FreeBSD.

The patch unconditionally activates the vmmouse driver. This should be fine even when not running in VMware, as vmmouse should be compatible with the default xorg mouse driver.