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 awhile 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:
1
2
3
4
5
6
7
| 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:
1
2
| 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:
1
2
3
4
5
6
7
8
| 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:
1
2
| 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
:
1
2
3
4
5
| 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
host# 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:
1
2
3
4
| 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):
1
2
3
| 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 its own native binaries! :-)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| 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!
|