The Batocera image is a compressed disk image (.img) file with gzip (.gz). The
file is mounted to /dev/loop0
with losetup -P --show -f $image
and
sfdisk -d /dev/loop0
shows the following:
label: gpt
label-id: CBECB451-5B87-4EA1-851B-D727826652F4
device: /dev/loop0
unit: sectors
first-lba: 32768
last-lba: 8945670
sector-size: 512
/dev/loop0p1 : start= 32768, size= 8388608, type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7, uuid=B849C18A-E422-4875-9B09-3B908F82C469, name="vfat"
/dev/loop0p2 : start= 8421376, size= 524288, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=73E5369E-E0FA-45BE-B88F-72721ED91658, name="userdata"
The first 32768 sectors are reserved for the bootloader, including ATF and U-boot.
Partition 1 (vfat) contains the following files:
Filename | File Type |
---|---|
/boot/batocera | Squashfs filesystem, little endian, v4.0, zstd |
/boot/rk3588-rock-5b.dtb | Device Tree Blob version 17 |
/boot/linux | Linux kernel ARM64 boot Image, little endian, 4K pages |
/boot/batocera.board | Board identifier string |
/boot/initrd.lz4 | LZ4 compressed initramfs image |
/extlinux/extlinux.conf | Configuration file for extlinux |
/tools/btrfs_on_windows | Contains btrfs tools for Windows users (directory) |
/batocera-boot.conf | Userland boot configuration parameters for Batocera |
Parition 2 (ext4) is an empty ext4 partition.
The initrd.lz4 archive, when uncompressed unlz4
and using cpio -idv < initrd
yields the initramfs.
The initramfs is Busybox and contains ash shell in the file init
to bootstrap
the system.
do_root()
is the main function of the init script and does the following:
- mounts
/proc
and/sys
. - reads kernel commandline for
dev
andlabel
parameters - mounts
/dev
. - By calling
do_mount()
in a loop, which attempts to mount the root partition to/boot_root
, the script waits for the root device to be available and mounted.¹ - Checks
/boot_root/boot/batocera.update
and goes through an update process if the file present. The batocera.update file is a replacement squashfs file. - Populates and manages the file system overlay
- Mounts the squashfs at
/new_root
. - Moves existing mounts (
/sys
,/proc
,/dev
,/boot
, and/overlay
into/new_root
mount point, preparing it for boot. - Executes
switch_root /new_root /sbin/init
, launching regular init.
¹ The mount script looks for dev
and label
options in the kernel
commandline to find a mount point.
The script follows:
#!/bin/ash
do_mount() {
if mount -o ro "${1}" /boot_root; then return 0; fi
return 1
}
do_root() {
mkdir -p /boot_root /new_root /overlay_root /sys /proc || return 1
mount -t proc -o nodev,noexec,nosuid proc /proc || return 1
mount -t sysfs -o nodev,noexec,nosuid sysfs /sys || return 1
# read the parameters
read -r cmdline < /proc/cmdline
for param in ${cmdline} ; do
case ${param} in
dev=*) dev=${param#dev=};;
label=*) label=${param#label=};;
esac
done
# look for devices
mount -t devtmpfs none /dev
MOUNTARG=none
test -n "${dev}" && MOUNTARG=${dev}
test -n "${label}" && MOUNTARG=LABEL=${label}
while ! do_mount "${MOUNTARG}"
do
echo "Waiting for the root device"
sleep 1
done
# update the squashfs
if test -e /boot_root/boot/batocera.update
then
mount -o remount,rw /boot_root || return 1
mv /boot_root/boot/batocera.update /boot_root/boot/batocera || return 1
# remove the overlay when updating
if test -e /boot_root/boot/overlay
then
mv /boot_root/boot/overlay /boot_root/boot/overlay.old || return 1
fi
mount -o remount,ro /boot_root || return 1
fi
# create an overlay on memory
mount -t tmpfs -o size=256M tmpfs /overlay_root || return 1
mkdir /overlay_root/base /overlay_root/overlay /overlay_root/work /overlay_root/saved || return 1
# fill the overlay with the stored one
if test -f /boot_root/boot/overlay
then
# the mount can fail if the fs was open in write and not correctly closed
if mount -o ro /boot_root/boot/overlay /overlay_root/saved
then
cp -pr /overlay_root/saved/* /overlay_root/overlay || return 1
umount /overlay_root/saved || return 1
fi
fi
# mount the squashfs
mount /boot_root/boot/batocera /overlay_root/base || return 1
# mount the future root in read write
if ! mount -t overlay overlay -o rw,lowerdir=/overlay_root/base,upperdir=/overlay_root/overlay,workdir=/overlay_root/work /new_root
then
# mount only as squashfs, no overlay (xu4 doesn't support overlayfs)
mount /boot_root/boot/batocera /new_root || return 1
fi
# moving current mounts
mount --move /boot_root /new_root/boot || return 1
mount --move /overlay_root /new_root/overlay || return 1
mount --move /sys /new_root/sys || return 1
mount --move /proc /new_root/proc || return 1
mount --move /dev /new_root/dev || return 1
# switch to the new root
exec switch_root /new_root /sbin/init || return 1
}
if ! do_root
then
echo "oooutch !"
/bin/ash
fi
To create a squashfs with the same settings, use the following:
squashfs -noappend -processors 12 -b 128k -comp zstd