PineBook Pro: How to install Manjaro on a LUKS-encrypted NVMe SSD

06.08.2021 yahe administration linux security

Last year I got myself a PineBook Pro to have a look into ARM-based devices and ARM development in general. Thanks to the optional NVMe adapter board I was able to add an SSD to the device as well. One of the first things I always do after receiving new hardware is to fully re-install the operating system, because you should never trust a default installation. I used the manjaro-arm-installer as Manjaro currently seems to provide the best support for the Rockchip hardware.

Unfortunately, the installer did not provide the type of installation that I wanted to have. The PineBook Pro currently is only able to boot from the internal eMMC card or from an microSD card and the installer is only able to install the whole system to one of those. What I wanted to have instead is that only the boot partition is located on the eMMC card, but the root partition should be located on the NVMe SSD and be fully encrypted.

In order to get what I wanted, I took the steps from the installer and modified them where necessary. The following blog post is meant to document the steps that I took to create an installation as described above. It is best to have a Manjaro installation already running on the PineBook Pro via a separate microSD card. This reduces the hassle a lot. I hope that this feature will someday make it into the official installer but until then we will have to do it by hand. So, let's begin!

1. Switch to the root account

To make things easier, everything will be executed as root.

sudo su -

2. Configure the installation

We will pre-define pretty much everything. This way we don't have to tinker with identifiers later on. You should only modify identifiers if you know what they are for (like USERNAME, FULLNAME, HOSTNAME, etc.). Unfortunately, I cannot guarantee, that EMMC_DEVICE and NVME_NAME will be the same on your device.

USERNAME="kenny"
FULLNAME="Kenny"
USERGROUPS="wheel,sys,audio,input,video,storage,lp,network,users,power"

HOSTNAME="pinebookpro.localzone.xyz"

LOCALE="de_DE.UTF-8"
TIMEZONE="Europe/Berlin"
CLIKEYMAP="us"
X11KEYMAP="us"

ARCH="aarch64"
DEVICE="pbpro"
EDITION="xfce"

EMMC_DEVICE="mmcblk2"
EMMC_PARTITION_DEVICE="${EMMC_DEVICE}p1"
EMMC_PARTITION_LABEL="BOOT"
EMMC_PARTITION_START="32MiB"
EMMC_PARTITION_END="544MiB"

NVME_NAME="nvme0"
NVME_DEVICE="${NVME_NAME}n1"
NVME_PARTITION_DEVICE="${NVME_DEVICE}p1"
NVME_PARTITION_NAME="${NVME_PARTITION_DEVICE}_luks"
NVME_PARTITION_START="0%"
NVME_PARTITION_END="100%"
NVME_VOLUMEGROUP_NAME="${NVME_PARTITION_NAME}_lvm"

#ROOT_VOLUME_LABEL="ROOT"
ROOT_VOLUME_NAME="${NVME_VOLUMEGROUP_NAME}_root"
ROOT_VOLUME_SIZE="100%FREE"

SWAP_VOLUME_LABEL="SWAP"
SWAP_VOLUME_NAME="${NVME_VOLUMEGROUP_NAME}_swap"
SWAP_VOLUME_SIZE="8GiB"

NSPAWN="systemd-nspawn -q --resolv-conf=copy-host --timezone=off -D"

3. Install the required packages

There are some tools that we will need later on, so install them now.

pacman -Syu bash wget git systemd parted libarchive openssl gawk dosfstools polkit haveged nvme-cli

4. Clone the Manjaro ARM profiles

The manjaro-arm-installer uses so-called "profiles" to decide which packages and services need to be installed for a specific ARM-based platform. If you want to install Manjaro on a different DEVICE or use a different Manjaro EDITION you have to look what the corresponding Git repository has to offer.

git clone https://gitlab.manjaro.org/manjaro-arm/applications/arm-profiles.git /tmp/arm-profiles/

5. Grep the required packages

Based on the selected DEVICE and EDITION we have to read the corresponding lists of packages to install and services to enable. These lists will be used later on.

PKG_DEVICE=$(grep "^[^#;]" "/tmp/arm-profiles/devices/${DEVICE}" | awk '{print $1}')
PKG_EDITION=$(grep "^[^#;]" "/tmp/arm-profiles/editions/${EDITION}" | awk '{print $1}')
SRV_EDITION=$(grep "^[^#;]" "/tmp/arm-profiles/services/${EDITION}" | awk '{print $1}')

6. Unmount all relevant partitions

The upcoming installation steps will destroy all data stored on the disks. But before that we have to unmount the devices. The unmounting of all relevant devices is a bit hacky, but it does the job just fine. Feel free to improve this or do it manually instead.

ls -1 /dev/* | grep "/dev/${EMMC_DEVICE}" | xargs umount
ls -1 /dev/* | grep "/dev/${NVME_DEVICE}" | xargs umount

7. Clear the bootloader section on the eMMC card

The eMMC card contains a specific bootloader section. It will be rewritten later on.

dd if=/dev/zero "of=/dev/${EMMC_DEVICE}" bs=1MiB count=32

8. Create the boot partition on the eMMC card

Now we will create the boot partition. It will be offset by 32MiB to leave room for the bootloader section. We won't put anything more on the eMMC card right now. If you don't want to waste the space, then you are free to add another data partition yourself.

parted -s "/dev/${EMMC_DEVICE}" mklabel msdos
parted -s "/dev/${EMMC_DEVICE}" mkpart primary fat32 "$EMMC_PARTITION_START" "$EMMC_PARTITION_END"
partprobe "/dev/${EMMC_DEVICE}"

mkfs.vfat "/dev/${EMMC_PARTITION_DEVICE}" -n "$EMMC_PARTITION_LABEL"

9. Optional: Reduce the power consumption of the NVMe disk

I am using a Samsung 970 EVO Plus 250GB as my NVMe SSD. According to the compatibility list it should not work, but it does. The only caveat is that I have to reduce the power level of the disk. If you use a less-power-hungry SSD you might come around this step. I will also introduce a boot-up service to automatically set the power level every time the PineBook Pro is powered on.

nvme set-feature "/dev/${NVME_NAME}" -f 2 -v 2

10. Create the LUKS partition on the NVMe disk

Now we come to the juicy part and create one big LUKS partition on the NVMe disk.

parted -s "/dev/${NVME_DEVICE}" mklabel msdos
parted -s "/dev/${NVME_DEVICE}" mkpart primary ext4 "$NVME_PARTITION_START" "$NVME_PARTITION_END"
partprobe "/dev/${NVME_DEVICE}"

cryptsetup --use-urandom luksFormat "/dev/${NVME_PARTITION_DEVICE}"

11. Open the LUKS partition on the NVMe disk

To proceed, we need to open the LUKS-encrypted partition that we just created.

cryptsetup open "/dev/${NVME_PARTITION_DEVICE}" "$NVME_PARTITION_NAME"

12. Create the LVM volumes within the LUKS partition

Within the LUKS partition we create LVM volumes. As I am lazy, I will only create a single root partition for everything and a swap partition. Feel free to introduce a more sophisticated partition layout if you feel like it.

pvcreate "/dev/mapper/${NVME_PARTITION_NAME}"

vgcreate "$NVME_VOLUMEGROUP_NAME" "/dev/mapper/${NVME_PARTITION_NAME}"

lvcreate -L "$SWAP_VOLUME_SIZE" "$NVME_VOLUMEGROUP_NAME" -n "$SWAP_VOLUME_NAME"
lvcreate -l "$ROOT_VOLUME_SIZE" "$NVME_VOLUMEGROUP_NAME" -n "$ROOT_VOLUME_NAME"

mkswap "/dev/${NVME_VOLUMEGROUP_NAME}/${SWAP_VOLUME_NAME}"
swaplabel -L "$SWAP_VOLUME_LABEL" "/dev/${NVME_VOLUMEGROUP_NAME}/${SWAP_VOLUME_NAME}"

mkfs.ext4 -O ^metadata_csum,^64bit "/dev/${NVME_VOLUMEGROUP_NAME}/${ROOT_VOLUME_NAME}"

13. Mount the boot and root partition

Now that we have created the relevant partitions, we can mount them.

mkdir -p /tmp/boot
mkdir -p /tmp/root

mount "/dev/${EMMC_PARTITION_DEVICE}" /tmp/boot
mount "/dev/${NVME_VOLUMEGROUP_NAME}/${ROOT_VOLUME_NAME}" /tmp/root

14. Install the root image

We can finally install the basic root image to our root partition.

wget -O "/tmp/Manjaro-ARM-${ARCH}-latest.tar.gz" "https://github.com/manjaro-arm/rootfs/releases/latest/download/Manjaro-ARM-${ARCH}-latest.tar.gz"

bsdtar -xpf "/tmp/Manjaro-ARM-${ARCH}-latest.tar.gz" -C /tmp/root

15. Prepare the package manager

Before we can install additional packages, we need to prepare the package manager pacman. This is the first time we will use the command stored in NSPAWN which will execute commands in the context of our newly installed operating system.

$NSPAWN /tmp/root pacman-key --init
$NSPAWN /tmp/root pacman-key --populate archlinux archlinuxarm manjaro manjaro-arm

mkdir -p /tmp/pkg-cache
mount -o bind /tmp/pkg-cache /tmp/root/var/cache/pacman/pkg

16. Install the device and edition specific packages

After preparing the package manager, we can install additional packages into our new system. There are some basic packages as well as the DEVICE-specific and EDITION-specific packages. Feel free to add other packages that are relevant to you. This process will take a while.

$NSPAWN /tmp/root pacman -Syyu base manjaro-system manjaro-release systemd systemd-libs haveged nvme-cli $PKG_EDITION $PKG_DEVICE

17. Enable the services

There are some services that got installed and that need to be enabled so that they start automatically. Should you have installed additional services then don't forget to enable them as well.

$NSPAWN /tmp/root systemctl enable getty.target haveged.service
$NSPAWN /tmp/root systemctl enable $SRV_EDITION

if [ -f /tmp/root/usr/bin/xdg-user-dirs-update ]; then
$NSPAWN /tmp/root systemctl --global enable xdg-user-dirs-update.service
fi

18. Disable the zswap service

Thanks to our NVMe SSD we have a real swap partition and don't have to rely on zswap.

$NSPAWN /tmp/root systemctl disable zswap-arm.service

19. Optional: Install the NVMe power state service

If you need to set the power level of your SSD then you can use this startup service to do this for you on every boot. If you don't need to do this, then just skip this step.

cat << EOF > /tmp/root/etc/systemd/system/nvme-state.service
[Unit]
Description=Reduce the NVMe power consumption.

[Service]
Type=oneshot
ExecStart=/usr/bin/nvme set-feature /dev/nvme0 -f 2 -v 2

[Install]
WantedBy=sysinit.target
EOF

sed -i "s/nvme0/${NVME_NAME}/" /tmp/root/etc/systemd/system/nvme-state.service

$NSPAWN /tmp/root systemctl enable nvme-state.service

20. Apply the overlay for the selected edition

The overlays are basically just a bunch of files that will overwrite default files with EDITION-specific versions. Therefore, we just copy them around.

cp -ap /tmp/arm-profiles/overlays/${EDITION}/* /tmp/root/

21. Create a new user

We will only create one user in addition to the root user for now.

$NSPAWN /tmp/root useradd -m -G "$USERGROUPS" -s /bin/bash "$USERNAME"
$NSPAWN /tmp/root chfn -f "$FULLNAME" "$USERNAME"

22. Set the root and user password

After we have created the new user, we can set the root and user password.

$NSPAWN /tmp/root passwd root
$NSPAWN /tmp/root passwd "$USERNAME"

23. Enable the user services

PulseAudio is a user-specific service. So we can enable it now.

if [[ "$EDITION" != "minimal" ]] && [[ "$EDITION" != "server" ]]; then
$NSPAWN /tmp/root --user "$USERNAME" systemctl --user enable pulseaudio.service
fi

24. Set up the system

Now it is time to setup the system, including keyboard layouts, timezones, etc.

$NSPAWN /tmp/root chmod u+s /usr/bin/ping

rm -f /tmp/root/etc/ssl/certs/ca-certificates.crt
rm -f /tmp/root/etc/ca-certificates/extracted/tls-ca-bundle.pem
cp -a /etc/ssl/certs/ca-certificates.crt /tmp/root/etc/ssl/certs/
cp -a /etc/ca-certificates/extracted/tls-ca-bundle.pem /tmp/root/etc/ca-certificates/extracted/

$NSPAWN /tmp/root ln -sf "/usr/share/zoneinfo/${TIMEZONE}" /etc/localtime

$NSPAWN /tmp/root sed -i "s/"#${LOCALE}"/${LOCALE}/g" /etc/locale.gen

echo "LANG=${LOCALE}" >> /tmp/root/etc/locale.conf

$NSPAWN /tmp/root locale-gen

echo "KEYMAP=${CLIKEYMAP}" >> /tmp/root/etc/vconsole.conf

if [[ "$EDITION" != "minimal" ]]; then
cat << EOF > /tmp/root/etc/X11/xorg.conf.d/00-keyboard.conf
Section "InputClass"
Identifier "system-keyboard"
Option "XkbLayout" "us"
EndSection
EOF
sed -i "s/us/${X11KEYMAP}"/ /tmp/root/etc/X11/xorg.conf.d/00-keyboard.conf
fi

if [[ "$EDITION" = "sway" ]]; then
sed -i "s/us/${X11KEYMAP}"/ /tmp/root/etc/sway/inputs/default-keyboard
fi

echo "$HOSTNAME" >> /tmp/root/etc/hostname

sed -i "s/enable systemd-resolved.service/#enable systemd-resolved.service/" /tmp/root/usr/lib/systemd/system-preset/90-systemd.preset

chown -R root:root /tmp/root/etc

if [[ "$EDITION" != "minimal" && "$EDITION" != "server" ]]; then
chown root:polkitd /tmp/root/etc/polkit-1/rules.d
elif [[ "$EDITION" = "cubocore" ]]; then
cp /tmp/root/usr/share/applications/corestuff.desktop /tmp/root/etc/xdg/autostart/
fi

25. Tweak initrd

We are pretty close to the finishing line. Let's prepare the initial ramdisk for our device. Installing the required lvm2 package afterwards will automatically trigger a rebuild.

cat << EOF > /tmp/root/etc/mkinitcpio.conf
MODULES=(panfrost rockchipdrm drm_kms_helper hantro_vpu analogix_dp rockchip_rga panel_simple arc_uart cw2015_battery i2c-hid iscsi_boot_sysfs jsm pwm_bl uhid)
BINARIES=()
FILES=()
HOOKS=(base udev keyboard autodetect keymap modconf block encrypt lvm2 filesystems fsck)
COMPRESSION="cat"
EOF

$NSPAWN /tmp/root pacman -Syyu lvm2

26. Add the partitions to fstab

Let's create the fstab file so that our partitions can be mounted automatically.

BOOT_UUID=$(blkid -s UUID -o value "/dev/${EMMC_PARTITION_DEVICE}")
ROOT_UUID=$(blkid -s UUID -o value "/dev/${NVME_VOLUMEGROUP_NAME}/${ROOT_VOLUME_NAME}")
SWAP_UUID=$(blkid -s UUID -o value "/dev/${NVME_VOLUMEGROUP_NAME}/${SWAP_VOLUME_NAME}")

cat << EOF > /tmp/root/etc/fstab
UUID=BOOT_UUID /boot vfat defaults 0 0
UUID=ROOT_UUID /     ext4 defaults 0 1
UUID=SWAP_UUID none  swap sw       0 0
EOF

sed -i "s/BOOT_UUID/${BOOT_UUID}/" /tmp/root/etc/fstab
sed -i "s/ROOT_UUID/${ROOT_UUID}/" /tmp/root/etc/fstab
sed -i "s/SWAP_UUID/${SWAP_UUID}/" /tmp/root/etc/fstab

27. Add the partitions to crypttab

The same is necessary for the crypttab file so that our encrypted partitions are mounted automatically as well.

NVME_UUID=$(blkid -s UUID -o value "/dev/${NVME_PARTITION_DEVICE}")

cat << EOF > /tmp/root/etc/crypttab
NVME_PARTITION_NAME UUID=NVME_UUID none luks,discard
EOF

sed -i "s/NVME_PARTITION_NAME/${NVME_PARTITION_NAME}/" /tmp/root/etc/crypttab
sed -i "s/NVME_UUID/${NVME_UUID}/" /tmp/root/etc/crypttab

28. Move the boot partition files

During the installation all files for the boot partition have been installed to the root partition instead. We just move them over to our boot partition.

mv /tmp/root/boot/* /tmp/boot

29. Flash the bootloader

Now it is finally time to write the bootloader to the specific bootloader section.

dd if=/tmp/boot/idbloader.img "of=/dev/${EMMC_DEVICE}" seek=64 conv=notrunc
dd if=/tmp/boot/u-boot.itb "of=/dev/${EMMC_DEVICE}" seek=16384 conv=notrunc

30. Update the boot configuration

We finalize the boot configuration now by setting the correct boot parameters. This way the boot process will know where to find the root partition and it will know that it is encrypted.

head -n -1 /tmp/boot/extlinux/extlinux.conf >/tmp/boot/extlinux/extlinux.conf.new

cp /tmp/boot/extlinux/extlinux.conf.new /tmp/boot/extlinux/extlinux.conf

echo "APPEND initrd=/initramfs-linux.img console=tty1 cryptdevice=UUID=${NVME_UUID}:${NVME_PARTITION_NAME} root=UUID=${ROOT_UUID} rw rootwait video=eDP-1:1920x1080@60 video=HDMI-A-1:1920x1080@60" >>/tmp/boot/extlinux/extlinux.conf

31. Clean up files

We are already in the clean-up part of the installation. At first we get rid of temporary files.

umount /tmp/root/var/cache/pacman/pkg
rm -rf /tmp/root/usr/bin/qemu-aarch64-static
rm -rf /tmp/root/var/cache/pacman/pkg/*
rm -rf /tmp/root/var/log/*
rm -rf /tmp/root/etc/*.pacnew
rm -rf /tmp/root/usr/lib/systemd/system/systemd-firstboot.service
rm -rf /tmp/root/etc/machine-id

rm "/tmp/Manjaro-ARM-${ARCH}-latest.tar.gz"

rm -rf /tmp/arm-profiles

32. Unmount the partitions

Unmount the newly written partitions and you are nearly done.

umount /tmp/boot
umount /tmp/root

vgchange -a n

cryptsetup close "/dev/mapper/${NVME_PARTITION_NAME}"

partprobe "/dev/${EMMC_DEVICE}"
partprobe "/dev/${NVME_DEVICE}"

33. Shutdown and boot

If you have come to this point then you have done it. You have installed Manjaro by-hand on a PineBook Pro, including an encrypted root partition that is stored on the separate NVMe SSD. Currently, you are running Manjaro from an microSD card which needs to be removed before booting from the internal eMMC card. So shut the device done, remove the microSD card and then boot normally. During the boot process you should be asked for your LUKS password and then the boot process should continue until it reaches the login screen.

Go ahead, try it out and have a lot of fun with your shiny new Manjaro installation! 😃

shutdown -h now

Search

Categories

administration (44)
arduino (12)
calcpw (2)
code (37)
hardware (16)
java (2)
legacy (113)
linux (30)
publicity (7)
review (2)
security (63)
thoughts (22)
update (9)
windows (17)
wordpress (19)