Building FreeBSD for Kirkwood

  • Prepare a drive
  • Obtain the source
  • Patching
  • Build world
  • Build the Kernel
  • Install the kernel
  • Install world
  • Configure some niceties

Prepare a drive

I’m using a slow, generic 2GB flash drive, but anything with at least a GiB or so of space should do.

Delete any existing partitions.

  1. gpart delete -i 1 da0
  2. gpart destroy da0

Create a 32MiB FAT partition and fill the rest of the drive with a FreeBSD slice.

  1. gpart create -s MBR da0
  2. gpart add -s 32M -t freebsd da0
  3. gpart add -t freebsd da0

Format the FAT partition.

  1. newfs_msdos /dev/da0s1

Label the UFS slice, create the filesystem, and add a filesystem volume label so the kernel can find it later.

  1. bsdlabel -w /dev/da0s2
  2. newfs -n da0s2a
  3. tunefs -L kirkwoodroot /dev/da0s2a

Obtain the source

Use csup to grab the source for FreeBSD if you don’t already have it. Check here for the available release tags.

  1. *default host=cvsup8.freebsd.org
  2. *default base=/var/db
  3. *default prefix=/usr
  4. *default release=cvs tag=RELENG_8_1
  5. *default delete use-rel-suffix
  6. *default compress src-all

Patching

FreeBSD requires a few patches to run comfortably and properly on these devices. The patches are available from my FreeBSD-Kirkwood repo on GitHub.

A patch to vfs_mount.c is only required until [pr]usb/138798[/pr] is fixed. Until then, we need to insert a delay before mounting the root filesystem, since our USB drive might not be enumerated.

  1. --- /usr/src/sys/kern/vfs_mount.c.orig 2010-07-04 22:50:00.613726077 -0400
  2. +++ /usr/src/sys/kern/vfs_mount.c 2010-07-05 12:11:09.986561693 -0400
  3. @@ -1651,6 +1651,9 @@
  4. int error, i, asked = 0;
  5. options = NULL;
  6. +
  7. + /* NASTY HACK: wait for USB sticks to appear */
  8. + pause("usbhack", hz * 10);
  9. root_mount_prepare();

This patch, shamelessly stolen from the mailing list, will give us the option to force fsck on the root filesystem. Otherwise, an unclean shutdown would lock us out of FreeBSD unless we had serial console access.

  1. --- /usr/src/etc/rc.d/fsck.orig 2010-07-07 13:02:41.765255856 -0400
  2. +++ /usr/src/etc/rc.d/fsck 2010-07-07 13:02:46.286575144 -0400
  3. @@ -27,7 +27,16 @@
  4. if checkyesno background_fsck; then
  5. fsck -F -p
  6. else
  7. - fsck -p
  8. + if checkyesno force_fsck; then
  9. + echo "Force fsck enabled"
  10. + for filesystem in ${force_fsck_list}
  11. + do
  12. + echo "Force check $filesystem"
  13. + fsck -y $filesystem
  14. + done
  15. + else
  16. + fsck -p
  17. + fi
  18. fi
  19. case $? in

Patch master.passwd to give root a default password of “root”. There’s probably a better way to do this.

  1. --- /usr/src/etc/master.passwd.orig 2010-06-13 22:09:06.000000000 -0400
  2. +++ /usr/src/etc/master.passwd 2010-07-08 02:27:52.148993197 -0400
  3. @@ -1,6 +1,6 @@
  4. # $FreeBSD: src/etc/master.passwd,v 1.40.22.1.4.1 2010/06/14 02:09:06 kensmith Exp $
  5. #
  6. -root::0:0::0:0:Charlie &:/root:/bin/csh
  7. +root:$1$jr4u13xy$GivPnOZ5kslfsJL4LmLK41:0:0::0:0:Charlie &:/root:/bin/csh
  8. toor:*:0:0::0:0:Bourne-again Superuser:/root:
  9. daemon:*:1:1::0:0:Owner of many system processes:/root:/usr/sbin/nologin
  10. operator:*:2:5::0:0:System &:/:/usr/sbin/nologin

Patch atomic.h to make BIND in the base system not segfault, stolen from this mailing list thread.

  1. --- /usr/src/contrib/bind9/lib/isc/arm/include/isc/atomic.h.orig 2010-08-04 02:02:01.194401084 -0400
  2. +++ /usr/src/contrib/bind9/lib/isc/arm/include/isc/atomic.h 2010-08-04 02:04:53.462379414 -0400
  3. @@ -49,26 +49,22 @@
  4. static inline isc_int32_t
  5. isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val)
  6. {
  7. - register int done, ras_start;
  8. + register int done, ras_start = 0xffff1004;
  9. __asm __volatile("1:\n"
  10. "adr %1, 1b\n"
  11. - "mov %0, #0xe0000004\n"
  12. "str %1, [%0]\n"
  13. - "mov %0, #0xe0000008\n"
  14. "adr %1, 2f\n"
  15. - "str %1, [%0]\n"
  16. + "str %1, [%0, #4]\n"
  17. "ldr %1, [%2]\n"
  18. "cmp %1, %3\n"
  19. "streq %4, [%2]\n"
  20. "2:\n"
  21. "mov %3, #0\n"
  22. - "mov %0, #0xe0000004\n"
  23. "str %3, [%0]\n"
  24. "mov %3, #0xffffffff\n"
  25. - "mov %0, #0xe0000008\n"
  26. - "str %3, [%0]\n"
  27. - : "=r" (ras_start), "=r" (done)
  28. + "str %3, [%0, #4]\n"
  29. + : "+r" (ras_start), "=r" (done)
  30. ,"+r" (p), "+r" (cmpval), "+r" (val) : : "memory");
  31. return (done);

Patch config.h to fix liblzma on ARM (as reported by Crest!)

  1. --- /usr/src/lib/liblzma/config.h.orig 2010-09-24 13:42:10.346344850 -0400
  2. +++ /usr/src/lib/liblzma/config.h 2010-09-24 13:44:29.568683203 -0400
  3. @@ -66,7 +66,7 @@
  4. #define SIZEOF_SIZE_T 8
  5. #define STDC_HEADERS 1
  6. #define TUKLIB_CPUCORES_SYSCONF 1
  7. -#define TUKLIB_FAST_UNALIGNED_ACCESS 1
  8. +/* #define TUKLIB_FAST_UNALIGNED_ACCESS 1 */
  9. #define TUKLIB_PHYSMEM_SYSCONF 1
  10. #ifndef _ALL_SOURCE
  11. # define _ALL_SOURCE 1

This patch disables a warning about unsupported TCP offload for IPv6 packets in if_mge.

  1. --- if_mge.c.orig 2011-05-11 14:27:51.692628521 -0400
  2. +++ if_mge.c 2011-05-11 14:28:20.950873599 -0400
  3. @@ -1607,9 +1607,9 @@
  4. }
  5. if (etype != ETHERTYPE_IP) {
  6. - if_printf(sc->ifp,
  7. + /*if_printf(sc->ifp,
  8. "TCP/IP Offload enabled for unsupported "
  9. - "protocol!\n");
  10. + "protocol!\n");*/
  11. return;
  12. }

Patch conf/files to allow us to build runfw into the kernel for if_run wireless controllers. Normally it’s only loadable as a module via loader, but the way we load the kernel bypasses that.

  1. --- /usr/src/sys/conf/files.orig 2011-01-02 17:33:24.330796637 -0500
  2. +++ /usr/src/sys/conf/files 2011-01-02 17:33:52.730749215 -0500
  3. @@ -1759,6 +1759,22 @@
  4. #
  5. dev/usb/wlan/if_rum.c optional rum
  6. dev/usb/wlan/if_run.c optional run
  7. +
  8. +runfw.c optional runfw \
  9. + compile-with "${AWK} -f $S/tools/fw_stub.awk runfw:runfw -mrunfw -c${.TARGET}" \
  10. + no-implicit-rule before-depend local \
  11. + clean "runfw.c"
  12. +runfw.fwo optional runfw \
  13. + dependency "runfw" \
  14. + compile-with "${LD} -b binary -d -warn-common -r -d -o ${.TARGET} runfw" \
  15. + no-implicit-rule \
  16. + clean "runfw.fwo"
  17. +runfw optional runfw \
  18. + dependency "$S/contrib/dev/run/rt2870.fw.uu" \
  19. + compile-with "uudecode -o ${.TARGET} $S/contrib/dev/run/rt2870.fw.uu"\
  20. + no-obj no-implicit-rule \
  21. + clean "runfw"
  22. +
  23. dev/usb/wlan/if_uath.c optional uath
  24. dev/usb/wlan/if_upgt.c optional upgt
  25. dev/usb/wlan/if_ural.c optional ural

Finally, if you’re using RELENG_8_2, pull in post-8.2 revision 1.12.2.19 of if_axe.c and revision 1.3.2.5 of if_axereg.h to fix a frequent problem where if_axe usb ethernet controllers would stop working until re-initialized. Discussion in this thread and usb/140883.

Build world

Build world for ARM, but don’t install anything.

  1. make -j 8 buildworld TARGET_ARCH=arm

Build the Kernel

My kernel configuration file is much more fully-featured than the stock SHEEVAPLUG config file. It includes support for GEOM, filesystems, USB ethernet controllers, USB audio hardware, and PF/ALTQ.

  1. #
  2. # Custom kernel for DockStar devices.
  3. # http://cooltrainer.org 20100705
  4. #
  5. # $FreeBSD: src/sys/arm/conf/DOCKSTAR,v 1.1.2.3.2.1 2010/06/14 02:09:06 kensmith Exp $
  6. #
  7. ident DOCKSTAR-COOLTRAINER
  8. include "../mv/kirkwood/std.sheevaplug"
  9. options SOC_MV_KIRKWOOD
  10. makeoptions MODULES_OVERRIDE=""
  11. #DockStar has 128MiB of memory, not 512 like the reference design
  12. #(512 is defined in std.sheevaplug and should be commented out)
  13. options PHYSMEM_SIZE=0x8000000
  14. #makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
  15. makeoptions WERROR="-Werror"
  16. options SCHED_4BSD #4BSD scheduler
  17. options INET #InterNETworking
  18. options INET6 #IPv6 communications protocols
  19. options FFS #Berkeley Fast Filesystem
  20. options NFSCLIENT #Network Filesystem Client
  21. options NFSLOCKD #Network Lock Manager
  22. options NFS_ROOT #NFS usable as /, requires NFSCLIENT
  23. #options BOOTP
  24. #options BOOTP_NFSROOT
  25. #options BOOTP_NFSV3
  26. #options BOOTP_WIRED_TO=mge0
  27. options GEOM_PART_BSD
  28. options GEOM_PART_GPT
  29. options GEOM_PART_MBR
  30. options GEOM_LABEL # Provides labelization
  31. options SOFTUPDATES # Enable FFS soft updates support
  32. options MSDOSFS # MSDOS Filesystem
  33. options PROCFS # Process filesystem (/proc)
  34. options PSEUDOFS # Pseudo-filesystem framework
  35. # Root fs on USB device
  36. options ROOTDEVNAME=\"ufs:/dev/ufs/root\"
  37. options SYSVSHM #SYSV-style shared memory
  38. options SYSVMSG #SYSV-style message queues
  39. options SYSVSEM #SYSV-style semaphores
  40. options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
  41. options MUTEX_NOINLINE
  42. options RWLOCK_NOINLINE
  43. options NO_FFS_SNAPSHOT
  44. options NO_SWAPPING
  45. # Debugging
  46. #options ALT_BREAK_TO_DEBUGGER
  47. #options DDB
  48. #options KDB
  49. # Pseudo devices
  50. device random
  51. device pty
  52. device loop
  53. device firmware # firmware assist module (for wlan)
  54. # Serial ports
  55. device uart
  56. # Networking
  57. device ether
  58. device mge # Marvell Gigabit Ethernet controller
  59. device mii
  60. device e1000phy
  61. device bpf
  62. options HZ=1000
  63. options DEVICE_POLLING
  64. device vlan
  65. # USB
  66. options USB_DEBUG # enable debug msgs
  67. device usb
  68. device uhci
  69. device ohci
  70. device ehci
  71. device umass
  72. device scbus
  73. device pass
  74. device da
  75. #USB Ethernet
  76. device miibus
  77. device aue # ADMtek USB Ethernet
  78. device axe # ASIX Electronics USB Ethernet
  79. device cdce # Generic USB over Ethernet
  80. device cue # CATC USB Ethernet
  81. device kue # Kawasaki LSI USB Ethernet
  82. device rue # RealTek RTL8150 USB Ethernet
  83. device udav # Davicom DM9601E USB
  84. #OpenBSD Packet Filter
  85. device pf
  86. device pflog
  87. device pfsync
  88. #ALTQ (QoS)
  89. options ALTQ
  90. options ALTQ_CBQ # Class Bases Queuing (CBQ)
  91. options ALTQ_RED # Random Early Detection (RED)
  92. options ALTQ_RIO # RED In/Out
  93. options ALTQ_HFSC # Hierarchical Packet Scheduler (HFSC)
  94. options ALTQ_PRIQ # Priority Queuing (PRIQ)
  95. #options ALTQ_NOPCC # Required for SMP build
  96. #Swap space (Yes, just in case)
  97. device md # Memory "disks"
  98. #USB audio
  99. device sound
  100. device snd_uaudio
  101. #USB Wireless
  102. # Wireless NIC cards
  103. device wlan # 802.11 support
  104. options IEEE80211_DEBUG # enable debug msgs
  105. options IEEE80211_AMPDU_AGE # age frames in AMPDU reorder q's
  106. options IEEE80211_SUPPORT_MESH # enable 802.11s draft support
  107. device wlan_wep # 802.11 WEP support
  108. device wlan_ccmp # 802.11 CCMP support
  109. device wlan_tkip # 802.11 TKIP support
  110. device rum # Ralink Technology RT2501USB wireless NICs
  111. device uath # Atheros AR5523 wireless NICs
  112. device ural # Ralink Technology RT2500USB wireless NICs
  113. device zyd # ZyDAS zb1211/zb1211b wireless NICs
  114. device urtw # Realtek RTL8187B/L USB
  115. device upgt # Conexant/Intersil PrismGT SoftMAC USB

Comment out PHYSMEM_SIZE in /usr/src/sys/arm/mv/kirkwood/std.sheevaplug, or your kernel might only boot as far as the copyright declaration on the DockStar.

Then build the kernel.

  1. make buildkernel TARGET_ARCH=arm KERNCONF=DOCKSTAR-COOLTRAINER

Install the kernel

  1. mount -t msdosfs /dev/da0s1 /root/usb
  2. cp /usr/obj/arm/usr/src/sys/DOCKSTAR-COOLTRAINER/kernel.bin /root/usb
  3. umount /root/usb

Install world

  1. mount /dev/da0s2a /root/usb
  2. export DESTDIR=/root/usb
  3. make installworld distrib-dirs distribution TARGET_ARCH=arm

Configure some niceties

Set the hostname, turn on DHCP, and enable SSHd.

  1. echo 'hostname="pochan"' > $DESTDIR/etc/rc.conf
  2. echo 'ifconfig_mge0="DHCP"' >> $DESTDIR/etc/rc.conf
  3. echo 'sshd_enable="YES"' >> $DESTDIR/etc/rc.conf

Enable automatic fsck, so we can get back into the OS in the event of power loss or an unclean shutdown.

  1. echo 'fsck_y_enable="YES"' >> $DESTDIR/etc/rc.conf
  2. echo 'background_fsck="NO"' >> $DESTDIR/etc/rc.conf
  3. echo 'force_fsck="YES"' >> $DESTDIR/etc/rc.conf
  4. echo 'force_fsck_list="/"' >> $DESTDIR/etc/rc.conf

Turn on NTPd. The DockStar has no real time clock, so this is required to set the time and date on boot. The -g flag makes NTPd ignore the first huge jump in time. If you prefer, OpenBSD’s openntpd is available through Ports.

  1. echo 'ntpd_enable="YES"' >> $DESTDIR/etc/rc.conf
  2. echo 'ntpd_sync_on_start="YES"' >> $DESTDIR/etc/rc.conf

Set a better motd ( :3 ) and tell Ports not to enable some ports’ X11 dependencies.

  1. echo 'Heya cutie <3' > $DESTDIR/etc/motd
  2. echo 'WITHOUT_X11=yes' >> $DESTDIR/etc/make.conf

Set some mount options for our root filesystem. Disabling clustered reads and writes is reccommended on ARM.

  1. echo '# Device Mountpoint FStype Options Dump Pass#' > $DESTDIR/etc/fstab
  2. echo '/dev/ufs/kirkwoodroot / ufs rw,noclusterr,noclusterw 0 0' >> $DESTDIR/etc/fstab

Add your device’s hostname to the IPv4 and IPv6 loopback addresses in /etc/hosts. This example uses “pochan”.

/etc/hosts
  1. ::1 localhost localhost.my.domain pochan
  2. 127.0.0.1 localhost localhost.my.domain pochan

Finally, edit $DESTDIR/etc/ssh/sshd_config and change PermitRootLogin to yes, since there will be no user accounts on first boot.