Installing TAIL OS on Raspberry Pi 3
You build the SD card image yourself, from two downloads: the TAIL OS SDK, which holds the toolchain and the prebuilt operating system, and the Raspberry Pi 3 board support package (BSP), which holds the board's startup code and drivers as source plus the script that builds the image. To try TAIL OS without hardware, see Running TAIL OS in QEMU.
Hardware Required
| Item | Notes |
|---|---|
| Raspberry Pi 3B or 3B+ | |
| MicroSD card (8 GB+) | |
| USB-to-TTL serial adapter (3.3V) | For serial console (FTDI, CP2102, etc.) |
| 5V / 2.5A power supply | Official RPi PSU recommended |
| Host Linux machine | For building and flashing |
1. Install the SDK
Follow Installation. It installs the toolchain and the SDK and
writes tail-sdk-env.sh, which the BSP uses to find the SDK.
2. Download the BSP and build the image
curl -fsSLO https://tail-os.com/downloads/bsp-rpi3.zip
curl -fsSLO https://tail-os.com/downloads/SHA256SUMS
sha256sum -c --ignore-missing SHA256SUMS
unzip bsp-rpi3.zip
cd bsp-rpi3
source <install dir>/tail-sdk-env.sh
./make-disk.sh
<install dir> is the directory you gave the SDK installer. make-disk.sh checks that
the BSP matches the installed SDK, builds the board crates against it, and writes
tailos_sd.img. A BSP and an SDK are published as a pair: if the check rejects your SDK,
install the SDK from the same day's downloads.
The first run downloads the Raspberry Pi boot firmware, about 3 MB, from the official
raspberrypi/firmware repository and caches it in tools/.firmware_cache. On a machine
without network access, pass --firmware-dir <dir> pointing at one directory that
already holds bootcode.bin, start.elf, fixup.dat, bcm2710-rpi-3-b.dtb,
bcm2710-rpi-3-b-plus.dtb and miniuart-bt.dtbo, all side by side. They come from
https://github.com/raspberrypi/firmware/tree/master/boot, where miniuart-bt.dtbo is
under overlays/.
3. Flash the SD card
Replace /dev/sdX with your SD card's device:
sudo dd if=tailos_sd.img of=/dev/sdX bs=4M status=progress
sync
4. Wire the serial console
Connect the USB-to-TTL serial adapter to the RPi3 GPIO header:
USB-TTL Adapter RPi3 GPIO Header
+-----------+ +----------------+
| | | |
| TX o----+----------->| Pin 10 (RXD) | GPIO 15
| | | |
| RX o<---+-----------o| Pin 8 (TXD) | GPIO 14
| | | |
| GND o----+----------->| Pin 6 (GND) |
| | | |
+-----------+ +----------------+
Important: Do NOT connect the VCC/5V pin from the serial adapter to the RPi. Power the RPi from its own power supply.
Open the serial terminal on your host:
screen /dev/ttyUSB0 115200
# or
minicom -D /dev/ttyUSB0 -b 115200
5. Boot
Insert the SD card and power on. The boot log appears on the serial console, and the
shell prompt /$ follows it.
Try the image in QEMU first
The same image boots in QEMU. QEMU does not emulate the Pi's firmware boot chain, so it
loads the operating system from images/tail.rfs and takes the SD card image only for
its data partition:
qemu-system-aarch64 -M raspi3b -kernel images/tail.rfs -serial mon:stdio \
-display none -drive file=tailos_sd.img,format=raw,if=sd
Under QEMU the boot log shows four messages that are not faults. QEMU has no Bluetooth controller, and the command attaches no USB device, so there is no USB network adapter to route through:
route: the stack refused 10.0.2.2 on netdev_usb0: InvalidInput
[FAIL] usb no device on the root port
[FAIL] bluetoot bt: opcode 0x0c03 — 0 bytes from controller (unpowered / not routed / wrong baud?)
[FAIL] bt startup failed: TimedOut
Each [FAIL] line starts with a timestamp. Their order varies from run to run, and one
can print just after the /$ prompt; press Enter for a fresh prompt. This image needs a
machine with at least 2 CPUs under QEMU: with one, the boot stops at
boot waitfor timeout: prefix '/rfs'.
Exit with Ctrl-A, then lowercase x.
Add your own programs
Put a program in app/<name>/src/main.rs and add a line /usr/bin/<name>=<name> to the
[disk] section of tail.build. ./make-disk.sh builds it against the SDK and puts it
in /usr/bin on the image. This is also how a program uses the
Periodic Framework.
What's in the BSP
bsp-rpi3/
├── make-disk.sh Builds tailos_sd.img (runs the two scripts below)
├── verify-sdk.sh Checks that the installed SDK matches this BSP
├── build-os.sh Builds the operating system image, images/tail.rfs
├── bsp.toml Board manifest: board paths and the SDK this BSP pairs with
├── tail.build Image manifest: what boots, what starts, what goes on the disk
├── app/build.sh Builds your programs under app/
├── tools/ SD card image tools (Python 3 standard library only)
├── startup/ Board startup (EL3 to EL1, MMU, jump to the kernel)
├── library/hardware/ Board memory map, power and mailbox crates
└── driver/hardware/ GPIO, SD card (SDHOST and EMMC) and Bluetooth drivers
The source is TAIL OS software under licence; see the License Guide. The Bluetooth driver includes Broadcom's firmware for the Pi 3B+ controller, under Broadcom's own licence beside it.
SD Card Image Structure
make-disk.sh produces tailos_sd.img with the following layout:
+===========================================================================+
| tailos_sd.img (256 MiB) |
+===========================================================================+
| |
| Sector 0: MBR (Master Boot Record) |
| Partition 1: Boot | FAT32 | 64 MiB, starting at 1 MiB |
| Partition 2: Data | FAT32 | 128 MiB |
| The rest is padding: QEMU's SD emulation needs a power-of-two size. |
| |
| Partition 1: BOOT |
| +-----------------------------------------------------------------------+|
| | bootcode.bin .... RPi GPU 1st-stage bootloader ||
| | start.elf ....... RPi GPU firmware ||
| | fixup.dat ....... RPi GPU memory fixup ||
| | bcm2710-rpi-3-b.dtb, bcm2710-rpi-3-b-plus.dtb .. device trees ||
| | overlays/miniuart-bt.dtbo ... routes Bluetooth to the mini-UART ||
| | config.txt ...... Boot configuration (see below) ||
| | kernel8.img .... TAIL OS (startup + kernel + drivers + servers + tsh)||
| +-----------------------------------------------------------------------+|
| |
| Partition 2: DATA (mounted as /) |
| +-----------------------------------------------------------------------+|
| | /etc/hosts, /etc/resolv.conf .. name lookup ||
| | /usr/bin/ ...... 26 programs (ls, ps, top, vi, ping, wifi, ...) (*) ||
| +-----------------------------------------------------------------------+|
| |
+===========================================================================+
(*) Plus list-root-long, a copy of ls under a long file name that shows the FAT
server's long-name support, so ls /usr/bin lists 27 names.
Python is not on this image. It comes only with the QEMU download, tail_disk.img.
Boot Sequence
Power On
|
v
GPU ROM -> loads bootcode.bin from boot partition
|
v
bootcode.bin -> loads start.elf
|
v
start.elf -> reads config.txt, loads kernel8.img at 0x80000
|
v
TAIL OS startup (aarch64-startup)
|-- Switch EL3 -> EL1
|-- Initialize MMU and caches
|-- Jump to kernel
v
TAIL OS kernel
|-- Initialize process/thread/IPC subsystem
|-- Load drivers and servers from the image (UART, GPIO, SD, Bluetooth, network)
|-- Mount the data partition via the SD driver + FAT server
|-- Start tsh shell
v
/$ _ (serial console ready)
config.txt Reference
make-disk.sh writes this config.txt:
| Setting | Value | Purpose |
|---|---|---|
arm_64bit |
1 |
Boot in AArch64 mode |
kernel |
kernel8.img |
Kernel filename to load |
disable_commandline_tags |
1 |
Don't pass ATAGS (TAIL OS doesn't use them) |
gpu_mem |
64 |
The firmware default. 16 would make the firmware look for a cut-down start_cd.elf that is not on the card, and the Pi would not boot |
enable_uart |
1 |
Enable serial console |
uart_2ndstage |
1 |
Print the firmware's own boot messages on the serial console |
dtoverlay |
miniuart-bt |
Route the onboard Bluetooth controller to the mini-UART and keep it powered |
core_freq |
250 |
Pin the core clock so the mini-UART's baud rate stays stable |
TAIL OS's console is the PL011 UART at address 0x3F201000. TAIL OS's startup code
connects GPIO 14/15 to the PL011 itself, so the console reaches the header pins while
Bluetooth uses the mini-UART.
Troubleshooting
No serial output:
- Verify TX/RX wiring (they must be crossed: adapter TX -> RPi RX)
- Ensure baud rate is 115200
- Check that the SD card's
config.txthasenable_uart=1
RPi power LED on but no activity LED blinking:
- The SD card may not be readable. Re-flash with
ddand verify the boot partition containsbootcode.bin,start.elf, andkernel8.img
make-disk.sh rejects the SDK:
- The BSP was packaged against a different SDK. Install the SDK published with this
BSP, then run
./make-disk.shagain.
Kernel panic or hang after startup:
- Boot the same image in QEMU first (see above) to see whether the fault depends on the hardware, and compare with Running TAIL OS in QEMU