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 &
mv obj obj.old
rm -Rf obj.old &
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