diff --git a/board/myna-player-odyssey/rootfs_overlay/loader/entries/myna-player.conf b/board/myna-player-odyssey/rootfs_overlay/loader/entries/myna-player.conf index 91c752b..639a08c 100644 --- a/board/myna-player-odyssey/rootfs_overlay/loader/entries/myna-player.conf +++ b/board/myna-player-odyssey/rootfs_overlay/loader/entries/myna-player.conf @@ -2,5 +2,5 @@ version 5.8rc7 linux boot/zImage devicetree boot/stm32mp157c-odyssey.dtb -options rootfstype=ext4 rw rootwait quiet systemd.log_color=off +options rootfstype=ext4 ro rootwait quiet systemd.log_color=off init=/sbin/pre-init linux-appendroot true diff --git a/board/myna-player-odyssey/rootfs_overlay/usr/sbin/pre-init b/board/myna-player-odyssey/rootfs_overlay/usr/sbin/pre-init new file mode 100755 index 0000000..7cfaf9b --- /dev/null +++ b/board/myna-player-odyssey/rootfs_overlay/usr/sbin/pre-init @@ -0,0 +1,85 @@ +#!/bin/bash +# Copyright 2020 Jookia +# SPDX-License-Identifier: GPL-3.0-or-later +# This scripts sets up an OverlayFS using a read-only rootfs mounted by Linux. +# Example usage: Save as /preinit and pass init=/preinit to your kernel. + +set -e # Safety feature: Error out if we hit any errors + +# Step 0: Check that this is running in the proper environment +# We don't want to run a bunch of complicated system-altering code accidentally +if [[ "$$" != "1" ]]; then + echo 'Usage: Run as PID 1 before booting your system!' 1>&2 + exit 1 +fi + +# Step 1: Set up a temporary root on a tmpfs on /run +# Since root is read-only, we'll use /run for our tmpfs mount +# This tmpfs will store all our temporary files used for OverlayFS operation +mount -t tmpfs tmpfs /run + +# Step 2: Mount and initialize the data partition at /run/data +# For OverlayFS we need a partition (/dev/mmcblk2p6 in our case) and two +# directories: overlay_root (contains the changes to the read-only root filesystem) +# as well as overlay_work which is used as a temporary store when writing files +# So mount and create these directories. + +mkdir /run/data +mount /dev/mmcblk2p6 /run/data +for i in overlay_root overlay_work; do + mkdir -p /run/data/$i; +done + +# Step 3: Prepare for chrooting +# In a moment we're going to move the current root to /run/old_root and +# temporarily chroot to /run for reasons explained in the next step. But this +# is going to break running applications since we don't have bin, sbin or +# lib directories in /run. So create links to them now that will correctly +# resolve once we chroot. + +for i in lib bin sbin; do + ln -s /old_root/$i /run/$i +done + +# Step 4: Move current root +# When using OverlayFS we have to make sure both the lower directory (in our +# case the read-only root) and upper directory (in our case the data +# partition's overlay root) don't contain each other. +# In our case the lower does: It's the root directory / which contains +# /run/data/overlay_root. +# The solution to this is to move the current root mount to /run/old_root. +# The util-linux provides a tool for this: pivot_root. +# In our case the pivot_root utility will move our read-only root filesystem +# from / to /run/old_root. +# The current version of Linux (5.8 as of writing) will automatically chroot +# all running applications to the /run directory, but this is explicitly not +# guaranteed behaviour. So we will have to chroot to /run ourselves next. + +mkdir /run/old_root && pivot_root /run/ /run/old_root + +# Note: Bash doesn't natively support chrooting and continuing execution, so we +# have to do the previous steps in one long invocation. Apologies. + +# Step 5: Chroot to /run so we have a proper root after pivoting +# In order for this step to work we need to have /bin, /sbin and /lib in /run +# with working programs so we can continue execution by calling a shell. +# In step 3 we set up links to the now pivoted old_root's bin, sbin and lib +# directories so everything will work fine. + +# Step 6: Mount OverlayFS on /new_root (previously /run/new_root) +# At this point we have the following directories of interest: +# - /old_root containing our read-only root filesystem +# - /data/overlay_root containing our writeable root filesystem +# - /data/overlay_work containing the work directory for OverlayFS root +# - /new_root which we just created to place the OverlayFS root +# When making the OverlayFS root, we use the /old_root as the lowerdir, +# /data/overlay_root as the upperdir, and /data/overlay_work as the workdir. + +# Step 7: Chroot to /new_root and run /sbin/init within the root +# This finally boots the system from the overlay root. Yay! +# Since we chroot instead of pivoting root, we leave our /run tmpfs in memory +# but no longer accessible. This shouldn't take up much memory given it's just +# a few mounts and symbolic links. + +# Okay, finally do steps 5 to 7. +exec chroot . sh -c "mkdir new_root && mount -t overlay overlay -o lowerdir=/old_root,upperdir=/data/overlay_root,workdir=/data/overlay_work /new_root && exec chroot /new_root /sbin/init"