Update boot order configuration for eMMC first, then network

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.
This commit is contained in:
nearxos
2026-02-21 15:05:17 +02:00
parent ff6258c2af
commit 5238d457e8
13 changed files with 348 additions and 247 deletions

View File

@@ -1,33 +1,36 @@
# Provisioning initramfs for network boot
Minimal 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.
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
1. Mounts `/proc`, `/sys`, `/dev`, `/dev/pts`.
2. Ensures an IP (reuses kernel DHCP or runs `udhcpc` on eth0).
2. Brings up eth0 and obtains a DHCP lease via `udhcpc`.
3. Runs the provisioning client with `PROVISIONING_SERVER` (default `http://10.20.50.1:5000`, overridable via kernel cmdline).
4. The client registers with the dashboard and polls for **Deploy** or **Backup**; on action it performs the dd + curl and exits.
4. The client registers with the dashboard and polls for **Deploy** or **Backup**; on action it performs the dd + curl and reboots.
## Build
**On x86_64 (e.g. your laptop):** the script uses **Podman** or **Docker** with `--platform linux/arm64` to run an arm64 container and copy busybox + curl into the initramfs. Your host must be able to *run* arm64 containers (via QEMU emulation).
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.
- **Fedora:** one-time setup to enable arm64 containers:
### Prerequisites
- **Docker** or **Podman** installed
- **arm64 emulation** (QEMU user-static):
```bash
# Fedora
sudo dnf install -y qemu-user-static
```
Then run the build (Podman will use QEMU automatically):
```bash
cd emmc-provisioning/network-boot-initramfs
./build.sh
```
- If you dont install `qemu-user-static`, the script will fail with an error and print the same instructions and an alternative (build on a Pi).
**On a Raspberry Pi 4 or other aarch64 host:** no Docker. Install deps and run:
# Debian/Ubuntu
sudo apt install -y qemu-user-static
```
### Build the initramfs
```bash
sudo apt install -y busybox curl
cd emmc-provisioning/network-boot-initramfs
./build.sh
```
@@ -37,6 +40,8 @@ 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
1. Copy **initrd.img** to the LXC TFTP root (e.g. `/srv/tftpboot`):
@@ -51,7 +56,7 @@ Optional: pass an output path:
initramfs initrd.img followkernel
```
So the firmware loads the kernel and then the initrd that follows it. The Pi will boot the kernel and run `/init` from the initrd.
So the firmware loads the kernel and then the initrd that "follows" it. The Pi will boot the kernel and run `/init` from the initrd.
3. 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.
@@ -67,15 +72,43 @@ The init script reads `provisioning_server=` from `/proc/cmdline` and exports `P
### Rescue mode (stuck in network-only boot)
If the device has **BOOT_ORDER=0x2** (network only), it never boots from eMMC. To get a shell and change boot order using the eMMCs **rpi-eeprom-config**, add **provisioning_rescue=1** to the kernel cmdline (e.g. in the TFTP-served `cmdline.txt` for that device). The initramfs will then start an interactive shell instead of the provisioning client. Run **/rescue-eeprom.sh** to mount eMMC and chroot to run `rpi-eeprom-config --edit`; set `BOOT_ORDER=0x1` or `0x21`, save, then `reboot`. See **docs/NETWORK-BOOT-TROUBLESHOOTING.md** (“Stuck in network-only boot”) for full steps.
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:
1. Reads the current EEPROM config using `rpi-eeprom-config` (included in the initramfs)
2. Creates a modified config with `BOOT_ORDER=0xf21` and tuned network timeouts
3. Embeds the config into a new EEPROM image using the bundled `pieeprom.bin` firmware
4. 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
1. Pi does DHCP gets IP and TFTP server (e.g. 10.20.50.1).
1. Pi does DHCP -> gets IP and TFTP server (e.g. 10.20.50.1).
2. Pi loads via TFTP: start4cd.elf, fixup4cd.dat, config.txt, cmdline.txt, kernel8.img, **initrd.img**.
3. Kernel boots with initrd as root; runs `/init`.
4. Init mounts minimal fs, ensures network, runs `/provisioning-client.sh`.
5. Client registers and polls; you choose Deploy or Backup in the dashboard; client runs dd + curl and exits.
6. After deploy, power cycle the Pi so it boots from eMMC.
5. Client registers and polls; you choose Deploy or Backup in the dashboard; client runs dd + curl and reboots.
6. After deploy, device boots from eMMC.
See **docs/NETWORK-BOOT-DEPLOYMENT-FLOW.md** for the full deployment flow.