FreeBSD & Raspberry Pi GPS/NTP

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:

1	#
2	# PPS -- Generic kernel configuration file for FreeBSD RPI/ARM PPS
3	#
4	include RPI-B
5	ident PPS-RPI-B
6	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:

  1	#!/bin/sh
  2	# © Louis Kowolowski 2014
  3	# Script to handle getting source, compiling, generating and customizing image for
  4	# Raspberry Pi
  5
  6	# Stop on errors (we should always handle things properly so this can be enabled)
  7	set -e
  8
  9	while getopts "nbuit" COMMAND_LINE_ARGUMENT ; do
 10	    case "${COMMAND_LINE_ARGUMENT}" in
 11	        b) BUILD="YES"
 12	         ;;
 13	        i) IMAGE="YES"
 14	            ;;
 15	        n) NEW="YES"
 16	         ;;
 17	        u) UPDATE="YES"
 18	         ;;
 19	        t) test_mode="YES"
 20	         ;;
 21	        \?) echo "-h <host> is required, -p <password> is required"
 22	         exit 1
 23	         ;;
 24	    esac
 25	done
 26	
 27	# Change these to suite your build and network environment
 28	export SRCROOT="/src/FreeBSD/head"
 29	export MNTDIR="/mnt"
 30	export MAKEOBJDIRPREFIX="/src/FreeBSD/obj"
 31	export GPU_MEM="128"
 32	export IMG="/src/FreeBSD/obj/bsd-pi.img"
 33	export IMG_SIZE="7"
 34	export NS1="198.18.3.10"
 35	export NS2="198.18.3.11"
 36	export DOMAIN="cmhome"
 37
 38	export TARGET_ARCH="armv6"
 39	export MAKESYSPATH="$SRCROOT/share/mk"
 40	export KERNCONF="PPS-RPI-B"
 41	export _ncpu="`sysctl -n hw.ncpu`"
 42
 43	mkdir -p $SRCROOT
 44	mkdir -p $MAKEOBJDIRPREFIX
 45
 46	export KERNEL=`realpath $MAKEOBJDIRPREFIX`/arm.armv6/`realpath $SRCROOT`/sys/$KERNCONF/kernel
 47	export UBLDR=`realpath $MAKEOBJDIRPREFIX`/arm.armv6/`realpath $SRCROOT`/sys/boot/arm/uboot/ubldr
 48	export DTB=`realpath $MAKEOBJDIRPREFIX`/arm.armv6`realpath $SRCROOT`/sys/$KERNCONF/rpi.dtb
 49
 50	get_source() {
 51	    cd $SRCROOT
 52	    cd ..
 53	    mv head head.old
 54	    rm -Rf head.old &amp;
 55	    mv obj obj.old
 56	    rm -Rf obj.old &amp;
 57	    svn co http://svn0.us-west.freebsd.org/base/releng/10.0 head
 58	}
 59
 60	update_source() {
 61	    cd $SRCROOT
 62	    svn up
 63	}
 64
 65	generate_kernel_config() {
 66	    cd $SRCROOT/sys/arm/conf
 67	    cat > $KERNCONF <<__EOC__
 68	    #
 69	    # PPS -- Generic kernel configuration file for FreeBSD Raspberry Pi PPS
 70	    #
 71	    include RPI-B
 72	    ident $KERNCONF
 73	    options PPS_SYNC
 74	    __EOC__
 75	}
 76
 77	build() {
 78	    cd $SRCROOT
 79	    make -C $SRCROOT kernel-toolchain
 80	    cat $SRCROOT/sys/arm/conf/$KERNCONF
 81	    make -C $SRCROOT KERNCONF=$KERNCONF WITH_FDT=yes buildkernel
 82	    make -j${_ncpu} -C $SRCROOT buildworld
 83
 84	    buildenv=`make -C $SRCROOT buildenvvars | sed 's/MACHINE_ARCH=armv6/MACHINE_ARCH=arm/'`
 85	    cd sys/boot
 86	    eval $buildenv make -C $SRCROOT/sys/boot clean
 87	    eval $buildenv make -C $SRCROOT/sys/boot obj
 88	    eval $buildenv make -C $SRCROOT/sys/boot UBLDR_LOADADDR=0x2000000 clean obj all
 89	}
 90
 91	generate_image() {
 92	    rm -f $IMG
 93	    dd if=/dev/zero of=$IMG bs=1024m count=$IMG_SIZE
 94	    MDFILE=`mdconfig -a -f $IMG`
 95	    gpart create -s MBR ${MDFILE}
 96
 97	    # Boot partition
 98	    gpart add -s 32m -t '!12' ${MDFILE}
 99	    gpart set -a active -i 1 ${MDFILE}
100	    newfs_msdos -L boot -F 16 /dev/${MDFILE}s1
101	    mount_msdosfs /dev/${MDFILE}s1 $MNTDIR
102	    fetch -q -o - \
103	        http://people.freebsd.org/~gonzo/arm/rpi/freebsd-uboot-20121129.tar.gz | \
104	        tar -x -v -z -C $MNTDIR -f -
105
106	    cat >> $MNTDIR/config.txt <<__EOC__
107	    gpu_mem=$GPU_MEM
108	    device_tree=devtree.dat
109	    device_tree_address=0x100
110	    disable_commandline_tags=1
111	    __EOC__
112
113	    cp $UBLDR $MNTDIR
114	    cp $DTB $MNTDIR/devtree.dat
115	    umount $MNTDIR
116
117	    # FreeBSD partition
118	    gpart add -t freebsd ${MDFILE}
119	    gpart create -s BSD ${MDFILE}s2
120	    gpart add -t freebsd-ufs ${MDFILE}s2
121	    newfs /dev/${MDFILE}s2a
122
123	    # Turn on Softupdates
124	    tunefs -n enable /dev/${MDFILE}s2a
125	    # Turn on SUJ with a minimally-sized journal.
126	    # This makes reboots tolerable if you just pull power on the BB
127	    # Note: A slow SDHC reads about 1MB/s, so a 30MB
128	    # journal can delay boot by 30s.
129	    tunefs -j enable -S 4194304 /dev/${MDFILE}s2a
130	    # Turn on NFSv4 ACLs
131	    tunefs -N enable /dev/${MDFILE}s2a
132
133	    mount /dev/${MDFILE}s2a $MNTDIR
134
135	    make -C $SRCROOT DESTDIR=$MNTDIR installkernel
136	    make -C $SRCROOT DESTDIR=$MNTDIR installworld
137	    make -C $SRCROOT DESTDIR=$MNTDIR distribution
138
139	    echo 'fdt addr 0x100' > $MNTDIR/boot/loader.rc
140
141	    echo '/dev/mmcsd0s2a / ufs rw,noatime 1 1' > $MNTDIR/etc/fstab
142
143	    cat > $MNTDIR/etc/resolv.conf <<__EORC__
144	    search $DOMAIN
145	    nameserver $NS1
146	    nameserver $NS2
147	    __EORC__
148
149	    cat > $MNTDIR/etc/rc.conf <<__EORC__
150	    hostname="fbsd-pi.cmhome"
151	    ifconfig_ue0="DHCP"
152	    sshd_enable="YES"
153	    ntpd_enable="YES"
154	    ntpd_sync_on_start="YES"
155
156	    # Turn off a lot of standard stuff
157	    # for more free memory.
158	    sendmail_submit_enable="NO"
159	    sendmail_outbound_enable="NO"
160	    sendmail_msp_queue_enable="NO"
161	    #ifconfig_ue0="198.18.3.5/24"
162	    #defaultrouter="198.18.3.1"
163	    __EORC__
164
165	    cat > $MNTDIR/etc/ttys <<__EOTTYS__
166	    ttyv0 "/usr/libexec/getty Pc" xterm on secure
167	    ttyv1 "/usr/libexec/getty Pc" xterm on secure
168	    ttyv2 "/usr/libexec/getty Pc" xterm on secure
169	    ttyv3 "/usr/libexec/getty Pc" xterm on secure
170	    ttyv4 "/usr/libexec/getty Pc" xterm on secure
171	    ttyv5 "/usr/libexec/getty Pc" xterm on secure
172	    ttyv6 "/usr/libexec/getty Pc" xterm on secure
173	    ttyv7 "/usr/libexec/getty Pc" xterm on secure
174	    ttyu0 "/usr/libexec/getty 3wire.115200" dialup on secure
175	    __EOTTYS__
176
177	    # Generate loader.conf. W/o this, we seem to drop to a debugger.
178	    cat > $MNTDIR/boot/loader.conf <<__EOF__
179	    hw.bcm2835.sdhci.hs=0
180	    __EOF__
181
182	    # Extra config bits to make things better
183	    # Set time to UTC
184	    cp -iv $MNTDIR/usr/share/zoneinfo/UTC /mnt/etc/localtime
185	    # Setup syslog to log to our loghost
186	    echo "*.* @log.cmhome/" >> $MNTDIR/etc/syslog.conf
187	    # Set SSH to be pubkey only
188	    sed -i -e 's/##ChallengeResponseAuthentication\ yes/ChallengeResponseAuthentication\ no/' \
189	        $MNTDIR/etc/ssh/sshd_config
190
191	    # Add user louisk, create $HOME, copy pubkey, set permissions/ownership
192	    mkdir -p $MNTDIR/home/louisk/.ssh
193	    pw -V /mnt/etc useradd louisk -u 1001 -s /bin/tcsh -d /home/louisk
194	    echo "password" | pw -V /mnt/etc usermod louisk -h 0
195	    pw -V $MNTDIR/etc groupmod wheel -n louisk
196	    cp ~louisk/.ssh/authorized_keys $MNTDIR/home/louisk/.ssh
197	    chmod 700 $MNTDIR/home/louisk/.ssh
198	    chmod 600 $MNTDIR/home/louisk/.ssh/authorized_keys
199	    chown -R 1001 $MNTDIR/home/louisk
200
201	    umount $MNTDIR
202	    mdconfig -d -u $MDFILE
203
204	    # compress image
205	    gzip $IMG
206	}
207
208	# main()
209	if [ "$UPDATE" == "YES" ] ; then
210	    update_source
211	fi
212
213	if [ "$NEW" == "YES" ] ; then
214	 get_source
215	 generate_kernel_config
216	fi
217
218	if [ "$BUILD" == "YES" ] ; then
219		build
220	fi
221
222	if [ "$IMAGE" == "YES" ] ; then
223		generate_image
224	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

Copyright

Comments