On Friday, 14th October, Oleksandr Tymoshenko committed an initial support for RPI3 into FreeBSD. The system is able to boot in multiuser mode with single processor. SMP is being actively worked on. For now, only the on-board Ethernet chip is supported and we will need to wait a while for a WiFi and Bluetooth support. The port is quite usable, and what’s more interesting – it’s full 64bit!
You can find the steps to prepare image for your RPI3 on the wiki. I made my on a late Saturday evening and my RPI3 if now happily running FreeBSD 12.0-CURRENT. Yet, I found myself with a kind of chicken and egg problem. The version of binutils
included in base doesn’t have support for aarch64, and to compile anything, you need to install binutils
from ports. We’re still waiting for a lld
from LLVM to become usable on arm64. Therefore, the install world will not include ld
, meaning that you’ll not be able to produce binaries on your RPI3.
Here are the steps to build a native, aarch64, version of pkg
, binutils
, and possibly a whole package repository at your will.
To run FreeBSD/arm64 binaries on a amd64 system, we can use qemu-user along with binmiscctl(8)
. Install qemu-user-static
from pkg
or ports
, and setup image activation for aarch64:
host# binmiscctl add arm64 \ --interpreter "/usr/local/bin/qemu-aarch64-static" \ --magic "\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\ \x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00" \ --mask "\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\ \xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff" \ --size 20 --set-enabled
Create a directory and install the same version of world you used to build your RPI3 image:
host# mkdir /arm64 host# make -C /usr/src -s installworld distribution TARGET=arm64 DESTDIR=/arm64
Now we have to build binutils
that can produce aarch64 code and put the in the chroot. I chose to build statically linked version of binutils
for amd64 host, but aarch64 target. You have to link them statically because /libexec/ld-elf.so.1
in the chroot will not be able to run amd64 dynamically linked binaries. That’s the same reason why the qemu emulator is linked statically.
Let’s use binutils
and some patches for them from ports:
host# tar cxf /usr/ports/distfiles/binutils-2.27.tar.bz2 host# cd binutils-2.27/ host# for p in /usr/ports/devel/binutils/files/patch-*; do > patch < $p > done […] host# ./configure --disable-shared --target=aarch64-freebsd --disable-werror --enable-deterministic-archives --with-sysroot=/ --disable-nls --prefix=$HOME/binutils-static --build=x86_64-freebsd12.0 host# gmake LDFLAGS=-all-static all install
Then, you need to copy qemu-aarch64-static
and statically linked binutils
into your chroot environment:
host# cp /usr/local/bin/qemu-aarch64-static /arm64/usr/local/bin/qemu-aarch64-static host# cp -r ~/binutils-static /arm64/usr/local/binutils-static
Mount devfs
, ports
, src
and copy resolv.conf
:
host# mount -t devfs devfs /arm64/dev host# mkdir /arm64/usr/ports host# mount_nullfs /usr/ports /arm64/usr/ports host# mount_nullfs /usr/src /arm64/usr/src hist# cp /etc/resolv.conf /arm64/etc/resolv.conf
Now you can chroot to the arm64 environment, set prompt for aarch64, add path to static binutils
and regenerate libraries cache:
host# chroot /arm64 /bin/sh # export PS1="aarch64# " aarch64# export PATH=$PATH:/usr/local/binutils-static/bin aarch64# ldconfig
That’s it! You’re now in emulated environment that can build native aarch64 binaries! Let’s check it out and build pkg
. Be warned that because whole qemu emulation is done in userspace it’ll be painfully slow. Like really, really slow. 10, 100 or maybe even 1000 times slower than executing native amd64 code (depending on your CPU speed):
aarch64# uname -srp FreeBSD 12.0-CURRENT aarch64 aarch64# make -C /usr/ports/ports-mgmt/pkg install clean
It works for many ports, but sometimes qemu will segfault 🙁 usually because of internal problems with emulation of certain aarch64 instructions.
However, I’ve been able to built pkg
and binutils
, and now have a 64bit RIP3 that can produce it’s own native binaries! 🙂
rpi3# cc -v -ohello hello.c FreeBSD clang version 3.8.0 (tags/RELEASE_380/final 262564) (based on LLVM 3.8.0) Target: aarch64-unknown-freebsd12.0 Thread model: posix InstalledDir: /usr/bin "/usr/bin/cc" -cc1 -triple aarch64-unknown-freebsd12.0 -emit-obj -mrelax-all -disable-free -main-file-name hello.c -mrelocation-model static -mthread-model posix -mdisable-fp-elim -masm-verbose -mconstructor-aliases -fuse-init-array -target-cpu generic -target-feature +neon -target-abi aapcs -v -dwarf-column-info -debugger-tuning=gdb -resource-dir /usr/bin/../lib/clang/3.8.0 -fdebug-compilation-dir /root -ferror-limit 19 -fmessage-length 158 -fallow-half-arguments-and-returns -fno-signed-char -fobjc-runtime=gnustep -fdiagnostics-show-option -fcolor-diagnostics -o /tmp/hello-057377.o -x c hello.c clang -cc1 version 3.8.0 based upon LLVM 3.8.0 default target aarch64-unknown-freebsd12.0 #include "..." search starts here: #include <...> search starts here: /usr/bin/../lib/clang/3.8.0/include /usr/include End of search list. "/usr/local/bin/ld" --eh-frame-hdr -dynamic-linker /libexec/ld-elf.so.1 --enable-new-dtags -o hello /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/crtbegin.o -L/usr/lib /tmp/hello-057377.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/crtend.o /usr/lib/crtn.o rip3# file hello hello: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /libexec/ld-elf.so.1, for FreeBSD 12.0 (1200013), FreeBSD-style, not stripped rip3# ./hello hello aarch64!
Remember, you can always use our RSS feed to keep up to date, follow us on Twitter or sign up to our newsletter below (no spam, promise):
Leave a comment