Skip to main content

RKways tech blog

When old meets new

Photo by Paola Ocaranza on Unsplash

While working on PXE booting Raspberry Pi cluster I realised I would need to extract kernel, initial ram-disk and firmware data from the official Raspberry Pi OS.

Possible solutions:

  • /dev/loop
  • kpartx (Device Mapper)
  • FUSE

All of those would need special privileges in the Docker container and might impact the container cleanup action.

Enter the Old

GNU mtools package, while being the solution for an old 💾-era problem, is still widely available in popular Linux distributions.

  • Alpine Linux

      apk add mtools
    
  • Debian/Ubuntu

      apt install mtools
    

To work with the disk image file just use the -i <file.img> option:

mcopy -s -i rpi-firmware.img ::. rpi-boot/

The rpi-firmware.img is a single partition from Raspberry Pi OS Zip file, to extract it you can use following shell code snippet:

CACHEDIR=.

# Download Raspberry Pi OS
curl -sSLf https://downloads.raspberrypi.org/raspios_lite_armhf_latest \
  -o $CACHEDIR/raspios_lite_armhf_latest.zip \
  -z $CACHEDIR/raspios_lite_armhf_latest.zip

# Only do this time-consuming operation if timestamp changes...
if [ ! -f $CACHEDIR/raspios_lite_armhf_latest.tstamp  ] || \
   [ $CACHEDIR/raspios_lite_armhf_latest.zip -nt $CACHEDIR/raspios_lite_armhf_latest.tstamp ]
then
    # extract information about the 0x0c partition (with firmware)
    unzip -p $CACHEDIR/raspios_lite_armhf_latest.zip | \
      dd bs=512 count=1 of=$CACHEDIR/raspios_lite_armhf_latest.mbr
    eval $(sfdisk -J $CACHEDIR/raspios_lite_armhf_latest.mbr | jq -er '
        .partitiontable.partitions[] | select(.type=="c") |
        "TYPE_C_START=\(.start | @sh)\nTYPE_C_SIZE=\(.size | @sh)"
    ')
    unzip -p $CACHEDIR/raspios_lite_armhf_latest.zip | \
      dd of=$CACHEDIR/rpi-firmware.img skip="$TYPE_C_START" count="$TYPE_C_SIZE"
    touch -r $CACHEDIR/raspios_lite_armhf_latest.zip \
      $CACHEDIR/raspios_lite_armhf_latest.tstamp
fi

First it extracts the MBR sector and looks inside it to find where the firmware partition starts and ends, then dd this area into the separate file.