FreeBSD & Raspberry Pi GPS/NTP

 23.01.2014 -  Louis Kowolowski -  ~5 Minutes

I’ve been needing to have a reliable time server and yet I don’t need something that is large, or consumes a lot of power.

Enter the Raspberry Pi. I picked up a Cana Kit   , Model B, a 700MHz ARM SoC (System on Chip), 512MB RAM, USB, Ethernet, SD slot. It came with all the bits needed to get started. A bit of google work turned up some hints on putting FreeBSD   on it.

FreeBSD, PPS kernel config

FreeBSD offers the ability to provide PPS (pulse per second) to facilitate better time tracking (used as input to NTP). If you wish to do this, you need to create a new kernel config file, define the PPS option, and include the generic config. Something like this:

	#
	# PPS -- Generic kernel configuration file for FreeBSD RPI/ARM PPS
	#
	include RPI-B
	ident PPS-RPI-B
	options PPS_SYNC

Define your KERNCONF in /etc/make.conf:

Build script

If you want an automated way to build these images, I’ve cobbled a script. It requires the following: FreeBSD 10.0 or newer (10.0 should be released this week, so that shouldn’t be an issue) - VM is fine Ensure that Subversion installed

Ensure that the auditdistd user exists:

The script looks like this:

	#!/bin/sh
	# © Louis Kowolowski 2014
	# Script to handle getting source, compiling, generating and customizing image for
	# Raspberry Pi

	# Stop on errors (we should always handle things properly so this can be enabled)
	set -e

	while getopts "nbuit" COMMAND_LINE_ARGUMENT ; do
	    case "${COMMAND_LINE_ARGUMENT}" in
	        b) BUILD="YES"
	         ;;
	        i) IMAGE="YES"
	            ;;
	        n) NEW="YES"
	         ;;
	        u) UPDATE="YES"
	         ;;
	        t) test_mode="YES"
	         ;;
	        \?) echo "-h <host> is required, -p <password> is required"
	         exit 1
	         ;;
	    esac
	done
	
	# Change these to suite your build and network environment
	export SRCROOT="/src/FreeBSD/head"
	export MNTDIR="/mnt"
	export MAKEOBJDIRPREFIX="/src/FreeBSD/obj"
	export GPU_MEM="128"
	export IMG="/src/FreeBSD/obj/bsd-pi.img"
	export IMG_SIZE="7"
	export NS1="198.18.3.10"
	export NS2="198.18.3.11"
	export DOMAIN="cmhome"

	export TARGET_ARCH="armv6"
	export MAKESYSPATH="$SRCROOT/share/mk"
	export KERNCONF="PPS-RPI-B"
	export _ncpu="`sysctl -n hw.ncpu`"

	mkdir -p $SRCROOT
	mkdir -p $MAKEOBJDIRPREFIX

	export KERNEL=`realpath $MAKEOBJDIRPREFIX`/arm.armv6/`realpath $SRCROOT`/sys/$KERNCONF/kernel
	export UBLDR=`realpath $MAKEOBJDIRPREFIX`/arm.armv6/`realpath $SRCROOT`/sys/boot/arm/uboot/ubldr
	export DTB=`realpath $MAKEOBJDIRPREFIX`/arm.armv6`realpath $SRCROOT`/sys/$KERNCONF/rpi.dtb

	get_source() {
	    cd $SRCROOT
	    cd ..
	    mv head head.old
	    rm -Rf head.old &amp;
	    mv obj obj.old
	    rm -Rf obj.old &amp;
	    svn co http://svn0.us-west.freebsd.org/base/releng/10.0 head
	}

	update_source() {
	    cd $SRCROOT
	    svn up
	}

	generate_kernel_config() {
	    cd $SRCROOT/sys/arm/conf
	    cat > $KERNCONF <<__EOC__
	    #
	    # PPS -- Generic kernel configuration file for FreeBSD Raspberry Pi PPS
	    #
	    include RPI-B
	    ident $KERNCONF
	    options PPS_SYNC
	    __EOC__
	}

	build() {
	    cd $SRCROOT
	    make -C $SRCROOT kernel-toolchain
	    cat $SRCROOT/sys/arm/conf/$KERNCONF
	    make -C $SRCROOT KERNCONF=$KERNCONF WITH_FDT=yes buildkernel
	    make -j${_ncpu} -C $SRCROOT buildworld

	    buildenv=`make -C $SRCROOT buildenvvars | sed 's/MACHINE_ARCH=armv6/MACHINE_ARCH=arm/'`
	    cd sys/boot
	    eval $buildenv make -C $SRCROOT/sys/boot clean
	    eval $buildenv make -C $SRCROOT/sys/boot obj
	    eval $buildenv make -C $SRCROOT/sys/boot UBLDR_LOADADDR=0x2000000 clean obj all
	}

	generate_image() {
	    rm -f $IMG
	    dd if=/dev/zero of=$IMG bs=1024m count=$IMG_SIZE
	    MDFILE=`mdconfig -a -f $IMG`
	    gpart create -s MBR ${MDFILE}

	    # Boot partition
	    gpart add -s 32m -t '!12' ${MDFILE}
	    gpart set -a active -i 1 ${MDFILE}
	    newfs_msdos -L boot -F 16 /dev/${MDFILE}s1
	    mount_msdosfs /dev/${MDFILE}s1 $MNTDIR
	    fetch -q -o - \
	        http://people.freebsd.org/~gonzo/arm/rpi/freebsd-uboot-20121129.tar.gz | \
	        tar -x -v -z -C $MNTDIR -f -

	    cat >> $MNTDIR/config.txt <<__EOC__
	    gpu_mem=$GPU_MEM
	    device_tree=devtree.dat
	    device_tree_address=0x100
	    disable_commandline_tags=1
	    __EOC__

	    cp $UBLDR $MNTDIR
	    cp $DTB $MNTDIR/devtree.dat
	    umount $MNTDIR

	    # FreeBSD partition
	    gpart add -t freebsd ${MDFILE}
	    gpart create -s BSD ${MDFILE}s2
	    gpart add -t freebsd-ufs ${MDFILE}s2
	    newfs /dev/${MDFILE}s2a

	    # Turn on Softupdates
	    tunefs -n enable /dev/${MDFILE}s2a
	    # Turn on SUJ with a minimally-sized journal.
	    # This makes reboots tolerable if you just pull power on the BB
	    # Note: A slow SDHC reads about 1MB/s, so a 30MB
	    # journal can delay boot by 30s.
	    tunefs -j enable -S 4194304 /dev/${MDFILE}s2a
	    # Turn on NFSv4 ACLs
	    tunefs -N enable /dev/${MDFILE}s2a

	    mount /dev/${MDFILE}s2a $MNTDIR

	    make -C $SRCROOT DESTDIR=$MNTDIR installkernel
	    make -C $SRCROOT DESTDIR=$MNTDIR installworld
	    make -C $SRCROOT DESTDIR=$MNTDIR distribution

	    echo 'fdt addr 0x100' > $MNTDIR/boot/loader.rc

	    echo '/dev/mmcsd0s2a / ufs rw,noatime 1 1' > $MNTDIR/etc/fstab

	    cat > $MNTDIR/etc/resolv.conf <<__EORC__
	    search $DOMAIN
	    nameserver $NS1
	    nameserver $NS2
	    __EORC__

	    cat > $MNTDIR/etc/rc.conf <<__EORC__
	    hostname="fbsd-pi.cmhome"
	    ifconfig_ue0="DHCP"
	    sshd_enable="YES"
	    ntpd_enable="YES"
	    ntpd_sync_on_start="YES"

	    # Turn off a lot of standard stuff
	    # for more free memory.
	    sendmail_submit_enable="NO"
	    sendmail_outbound_enable="NO"
	    sendmail_msp_queue_enable="NO"
	    #ifconfig_ue0="198.18.3.5/24"
	    #defaultrouter="198.18.3.1"
	    __EORC__

	    cat > $MNTDIR/etc/ttys <<__EOTTYS__
	    ttyv0 "/usr/libexec/getty Pc" xterm on secure
	    ttyv1 "/usr/libexec/getty Pc" xterm on secure
	    ttyv2 "/usr/libexec/getty Pc" xterm on secure
	    ttyv3 "/usr/libexec/getty Pc" xterm on secure
	    ttyv4 "/usr/libexec/getty Pc" xterm on secure
	    ttyv5 "/usr/libexec/getty Pc" xterm on secure
	    ttyv6 "/usr/libexec/getty Pc" xterm on secure
	    ttyv7 "/usr/libexec/getty Pc" xterm on secure
	    ttyu0 "/usr/libexec/getty 3wire.115200" dialup on secure
	    __EOTTYS__

	    # Generate loader.conf. W/o this, we seem to drop to a debugger.
	    cat > $MNTDIR/boot/loader.conf <<__EOF__
	    hw.bcm2835.sdhci.hs=0
	    __EOF__

	    # Extra config bits to make things better
	    # Set time to UTC
	    cp -iv $MNTDIR/usr/share/zoneinfo/UTC /mnt/etc/localtime
	    # Setup syslog to log to our loghost
	    echo "*.* @log.cmhome/" >> $MNTDIR/etc/syslog.conf
	    # Set SSH to be pubkey only
	    sed -i -e 's/##ChallengeResponseAuthentication\ yes/ChallengeResponseAuthentication\ no/' \
	        $MNTDIR/etc/ssh/sshd_config

	    # Add user louisk, create $HOME, copy pubkey, set permissions/ownership
	    mkdir -p $MNTDIR/home/louisk/.ssh
	    pw -V /mnt/etc useradd louisk -u 1001 -s /bin/tcsh -d /home/louisk
	    echo "password" | pw -V /mnt/etc usermod louisk -h 0
	    pw -V $MNTDIR/etc groupmod wheel -n louisk
	    cp ~louisk/.ssh/authorized_keys $MNTDIR/home/louisk/.ssh
	    chmod 700 $MNTDIR/home/louisk/.ssh
	    chmod 600 $MNTDIR/home/louisk/.ssh/authorized_keys
	    chown -R 1001 $MNTDIR/home/louisk

	    umount $MNTDIR
	    mdconfig -d -u $MDFILE

	    # compress image
	    gzip $IMG
	}

	# main()
	if [ "$UPDATE" == "YES" ] ; then
	    update_source
	fi

	if [ "$NEW" == "YES" ] ; then
	 get_source
	 generate_kernel_config
	fi

	if [ "$BUILD" == "YES" ] ; then
		build
	fi

	if [ "$IMAGE" == "YES" ] ; then
		generate_image
	fi

With this, I can (relatively) easily test new builds and images somewhat independently. Nice when I just want to make a change to an rc script, or config file and don’t need to rebuild the entire system. Once you have the image, you can copy it to the system with the SD card and then use dd(1) to write out the image.

NOTE: Rather than do this very manual approach, I’d now suggest using crochet