2020–09–04: Pinebook Pro
and Levinboot
Pinebook Pro is a very nice laptop. Software support just has a few annoying
quirks:
- system suspend doesn't work due to lack of support for LPDDR4 in TF-A
- U-Boot is dog slow to boot it (about 6s or more to run the kernel, load
speeds of 10 MiB/s, etc.)
- Kernel takes quite a bit of time too (about 1.5s to run init)
Thankfully, a discord user CrystalGamma took to creating Levinboot, which is a
specialized bootloader for Pinebook Pro and other similar RK3399 based
computers. Its goals are almost identical to my p-boot project: boot the kernel as fast as
possible from local storage and get out of the way. Its limitations are similar
too. No or very limited support for partition schemes, no support for
traditional filesystems, etc.
Version 0.7.1 was released a few days ago, so I decided to give it a try on
my Pinebook Pro, and I'm happy to report that it works quite nicely, and it
looks like it's going to have a bright future. :)
Boot process now shows a feedback. At first, red LED turns on for 1 sec,
then green LED turns on for another sec, then red LED turns off and in another
2–3 seconds the tty shows up, and the system is interactive. That's with a
small 7MiB gzip compressed kernel payload. I also tried a large 20MiB zstd
compressed payload from eMMC, but that doesn't yet work as expected. I get load
speeds of about 5MiB/s with that.
With lack of support for system suspend, fast boot times help make the laptop
more useable.
My Levinboot setup
I use eMMC to load the payload, and SD card to load Levinboot itself. This
way I can easily upgrade and test new Levinboot versions, and not worry about
it breaking, because I just pop out a SD card, and update the bootloader from
my PC, in case something fails.
To get Levinboot, I compile it from source code:
CROSS=aarch64-linux-gnu
export CC=$CROSS-gcc
export OBJCOPY=$CROSS-objcopy
export LD=$CROSS-gcc
git clone https://gitlab.com/DeltaGem/levinboot.git
cd levinboot
# currently contains fixes for reading GPT partition table
git checkout dev
./configure.py --payload-emmc --payload-zstd --payload-initcpio --with-tf-a-headers $ATF_DIR/include/export
ninja
# Copy levinboot-sd.img to my Pinebook Pro
scp levinboot-sd.img root@pbp:/boot/levinboot-emmc.img
Then I install it to SD card from Pinebook Pro itself, along with flashing
payload to eMMC:
#!/bin/bash
set -e -x
ROOT_UUID=6795bcbb-fba8-4d22-81ef-dc628324b021
BOOTOPTS=(
console=tty1
video=eDP-1:1920x1080@60
rd.luks.uuid=$ROOT_UUID
rd.luks.name=$ROOT_UUID=root
rd.luks.options=timeout=0,discard
root=/dev/mapper/root
rootfstype=f2fs
rootflags=x-systemd.device-timeout=0
rootwait
rw
mitigations=off
quiet
loglevel=2
)
BOOTOPTS="${BOOTOPTS[@]}"
cp -f board.dtb board-lv.dtb
fdtput -pt s board-lv.dtb /chosen bootargs "$BOOTOPTS"
truncate -s 0 payload-lv.img
zstd -zc bl31.elf >> payload-lv.img
zstd -zc board-lv.dtb >> payload-lv.img
zstd -zc Image >> payload-lv.img
zstd -zc initramfs.img >> payload-lv.img
dd if=payload-lv.img of=/dev/mmcblk2p1
dd if=levinboot-emmc.img of=/dev/mmcblk1 seek=64
#dd if=levinboot-sd.img of=/dev/mmcblk1 seek=64
sync
When booting from eMMC, Levinboot expects to find payload in a special GPT
partition. I just use a single partition with GUID
e5ab07a0-8e5e-46f6-9ce8-41a518929b7c
.
This is all documented in detail in the Levinboot README
file.