Modify the first-boot script and documentation to set the EEPROM boot order to 0xf21, prioritizing eMMC boot followed by network boot. Adjust network boot settings for faster failure on DHCP timeouts and update related scripts and documentation to reflect these changes. Enhance the rescue script to directly modify EEPROM settings without requiring a chroot into eMMC, streamlining the recovery process for devices stuck in network-only boot. Update relevant documentation to ensure clarity on the new boot order and its implications.
Provisioning initramfs for network boot
Alpine Linux-based initramfs that runs provisioning-client.sh after bringing up the network. Used with Raspberry Pi 4 / CM4 (reTerminal) when booting via TFTP from the provisioning LXC.
Includes Python 3 and rpi-eeprom-config so EEPROM configuration can be modified directly from the initramfs without chrooting into eMMC.
What it does
- Mounts
/proc,/sys,/dev,/dev/pts. - Brings up eth0 and obtains a DHCP lease via
udhcpc. - Runs the provisioning client with
PROVISIONING_SERVER(defaulthttp://10.20.50.1:5000, overridable via kernel cmdline). - The client registers with the dashboard and polls for Deploy or Backup; on action it performs the dd + curl and reboots.
Build
The build script uses Docker or Podman with --platform linux/arm64 to create an Alpine aarch64 rootfs with Python 3, curl, and rpi-eeprom-config. Your host must support arm64 containers via QEMU emulation.
Prerequisites
- Docker or Podman installed
- arm64 emulation (QEMU user-static):
# Fedora sudo dnf install -y qemu-user-static # Debian/Ubuntu sudo apt install -y qemu-user-static
Build the initramfs
cd emmc-provisioning/network-boot-initramfs
./build.sh
Optional: pass an output path:
./build.sh /path/to/initrd.img
The resulting initrd.img is approximately 25-35 MB compressed (Alpine base + Python + EEPROM firmware).
Deploy to TFTP root
-
Copy initrd.img to the LXC TFTP root (e.g.
/srv/tftpboot):scp initrd.img root@10.130.60.141:/srv/tftpboot/ -
In the TFTP root, ensure config.txt (Raspberry Pi boot config) includes the initramfs line. If you use the stock
config.txtfrom the RPi firmware repo, add:initramfs initrd.img followkernelSo the firmware loads the kernel and then the initrd that "follows" it. The Pi will boot the kernel and run
/initfrom the initrd. -
If your DHCP already points the Pi to this TFTP server and
start4cd.elf, the Pi will load kernel + initrd from the same root. No NFS or extra server needed.
Kernel cmdline (optional)
To override the provisioning server URL (e.g. if the dashboard is on another IP), add to cmdline.txt in the TFTP root (or append to the kernel command line):
provisioning_server=http://10.20.50.1:5000
The init script reads provisioning_server= from /proc/cmdline and exports PROVISIONING_SERVER for the client.
Rescue mode (stuck in network-only boot)
If the device has BOOT_ORDER=0x2 (network only), it never boots from eMMC. To fix the EEPROM config, add provisioning_rescue=1 to the kernel cmdline (e.g. in the TFTP-served cmdline.txt for that device). The initramfs will start an interactive shell instead of the provisioning client.
Run /rescue-eeprom.sh to set BOOT_ORDER=0xf21 directly from the initramfs. The script:
- Reads the current EEPROM config using
rpi-eeprom-config(included in the initramfs) - Creates a modified config with
BOOT_ORDER=0xf21and tuned network timeouts - Embeds the config into a new EEPROM image using the bundled
pieeprom.binfirmware - Copies the update (
pieeprom.upd+pieeprom.sig) to the eMMC boot partition
No chroot, no EDITOR hack, no dependency on the eMMC OS.
After running the script, disable network boot on the LXC and reboot so the bootloader boots from eMMC and applies the update.
See docs/NETWORK-BOOT-TROUBLESHOOTING.md ("Stuck in network-only boot") for full steps.
What's included in the initramfs
| Component | Purpose |
|---|---|
| Alpine Linux base | Minimal rootfs with apk package manager |
| BusyBox | Core Unix utilities (sh, mount, ip, udhcpc, dd, etc.) |
| Python 3 | Required by rpi-eeprom-config |
| curl | HTTP client for provisioning dashboard API |
| rpi-eeprom-config | EEPROM configuration tool (from rpi-eeprom repo) |
| pieeprom.bin | EEPROM firmware image (for creating update files) |
| init | Boot script: mounts fs, DHCP, rescue or provision |
| provisioning-client.sh | Registers with dashboard, executes deploy/backup |
| rescue-eeprom.sh | Sets EEPROM boot order directly |
| udhcpc.script | Applies DHCP lease (IP, route, DNS) |
Flow summary
- Pi does DHCP -> gets IP and TFTP server (e.g. 10.20.50.1).
- Pi loads via TFTP: start4cd.elf, fixup4cd.dat, config.txt, cmdline.txt, kernel8.img, initrd.img.
- Kernel boots with initrd as root; runs
/init. - Init mounts minimal fs, ensures network, runs
/provisioning-client.sh. - Client registers and polls; you choose Deploy or Backup in the dashboard; client runs dd + curl and reboots.
- After deploy, device boots from eMMC.
See docs/NETWORK-BOOT-DEPLOYMENT-FLOW.md for the full deployment flow.