FOG Project Image Capture on Raspberry Pi 4 (ARM64) via U-Boot
-
Hello, the goal of using FOG Project at the company where I work is to capture an image of a Raspberry Pi 4 that is already configured (with SSH, Wi-Fi, locale, and keyboard settings enabled).
I haven’t been able to find a topic to help me set this up; for now, I am relying on Gemini and Claude for assistance.
Project Overview:
I am trying to capture an image from a Raspberry Pi 4 (2 GB RAM) to a FOG Project server (v1.5.10). The Pi 4 uses an external 512 GB JMicron SSD/USB drive connected to an USB 3.0 port (/dev/sda).What has been done and validated so far:
PXE / TFTP Chainloading: The Raspberry Pi 4 successfully boots via native PXE, loads U-Boot, and downloads via TFTP the boot.scr script, the bzImageARM64 kernel, the uInitrd ramdisk, and the bcm2711-rpi-4-b.dtb DTB file
Network Driver Issue Resolved: The default FOG bzImageARM64 kernel lacked support for the Pi 4’s onboard Broadcom NIC. I replaced it with the official Raspberry Pi ARM64 kernel (kernel8.img / 6.18.46-v8+).
Hardware Detection:
The native Broadcom Ethernet controller (bcmgenet) initializes properly (eth0: Link is Up - 1Gbps/Full).
An IP address is assigned via DHCP (udhcpc: lease of 192.168.203.73 obtained).
The external storage drive is properly detected at /dev/sda (JMicron drive with sda1 and sda2 partitions).
Current boot.cmd Configuration (U-Boot):
setenv kernel_addr_r 0x00080000
setenv kernel_comp_addr_r 0x0a000000
setenv kernel_comp_size 0x02000000
setenv fdt_addr_r 0x02600000
setenv ramdisk_addr_r 0x03000000setenv bootargs console=tty1 root=/dev/ram0 rw ramdisk_size=275000 web=192.168.203.113/fog/ loglevel=7 mode=debug type=up mac=dc:a6:32:c8:b4:33 osid=50 img=ImagePi4 storage=192.168.203.113:/images/ storageip=192.168.203.113 imgType=mps imgPartitionType=all storagedev=/dev/sda
tftp ${kernel_addr_r} 7efcf632/bzImageARM64
tftp ${ramdisk_addr_r} 7efcf632/uInitrd
tftp ${fdt_addr_r} 7efcf632/bcm2711-rpi-4-b.dtbbooti ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}
Current Issue:
During the FOS Linux kernel boot, the process hangs right after displaying the network link line (bcmgenet fd580000.ethernet eth0: Link is Up - 1Gbps/Full - flow control rx/tx) and does not automatically proceed to the FOG init scripts / check-in process (/bin/fog.checkin).Has anyone successfully automated a full FOS capture workflow on ARM64 / Raspberry Pi 4 architecture?
-
@Jeremy FOS apparently hasn’t been great with Raspberry Pi.
I’m working on building in proper support and fixing a bug we found along the way (Yes I’m using AI to help with the coding and finding/implementing piece.)
I’ll need you, once this refactoring is done and an experimental build is built to test that kernel/init pair to be able to know if what we added/supposedly fixed is working.
Thank you for letting us know.
-
Thanks a lot for your feedback; I’ve been trying to get it working for a week without success, and your reply confirms that the issue isn’t on my end.
I’d be more than happy to help once you’ve found the solution.
-
@Jeremy The build is up, and it turned out there were two separate bugs, not one.
Bug 1: our arm64 kernel couldn’t unpack our own arm64 init. The kernel had gzip
initramfs support switched off while the init we publish isarm_init.cpio.gz. I
checked a releasedarm_Imagewithextract-ikconfigto be sure and it’s real. That
pair has been unable to boot since January 2021, when a cleanup commit pruned “unneeded
initrd compression algos” from all three kernel configs. Correct for x86, wrong for arm64,
and nobody caught it because almost nobody boots the arm64 build.Bug 2: our arm64 kernel didn’t describe an ARM platform at all. No
CONFIG_ARCH_BCM,
so no Broadcom SoC and no Raspberry Pi anything. That’s the missing NIC you found. It also
had no PL011 UART and no generic PCI host bridge, so it had no serial console and no PCI
bus on basically any arm64 machine. The config was added in 2018 by someone who said in
the commit message that they couldn’t test it, and eight years ofmake oldconfigcarried
it forward untouched.Both are fixed and merged. The kernel now has BCM2835/2711/2712 support, which covers Pi 3
through Pi 5: the VideoCore firmware and mailbox chain, the SD card controllers, bcmgenet,
lan78xx and smsc95xx for the older boards, macb for the Pi 5’s RP1, PCIE_BRCMSTB, and the
SoC watchdog (FOS reboots through that at the end of a task, so without it a client
finishes and just sits there).I’ve tested it under QEMU as far as QEMU can go: the new kernel unpacks the released init
and boots all the way into FOS userspace, and with a virtio NIC it gets an IP. The old
kernel produces no console output at all on the same machine. What QEMU can’t test is
any of the Broadcom code, because its Pi 4 model disables the PCIe, genet, RNG and thermal
blocks. That’s the part I need you for. None of us has a Pi.
Testing it
Good news: don’t change your setup. Keep the U-Boot chain you already have working. We’re
not asking you to switch to iPXE yet, I just want to know whether the kernel runs on real
Pi hardware.1. Get the files
# the new kernel wget https://github.com/FOGProject/fos/releases/download/EXP_20260825-141730/arm_Image # the init - unchanged, but grab this exact one, it's the pair I tested wget https://github.com/FOGProject/fos/releases/download/EXP_20260819-141018/arm_init.cpio.gz # device trees, if you'd rather use ours than the one you have wget https://github.com/FOGProject/fos/releases/download/EXP_20260825-141730/arm_dtbs.tar.gz tar xzf arm_dtbs.tar.gz # gives you broadcom/bcm2711-rpi-4-b.dtbDrop
arm_Imageandarm_init.cpio.gzinto your7efcf632/TFTP directory. Your existing
DTB is fine, ours is just there if you want it.2. Skip the uInitrd wrapper
You can hand the gzip file straight to
bootiand skipmkimageentirely:tftp ${ramdisk_addr_r} 7efcf632/arm_init.cpio.gz booti ${kernel_addr_r} ${ramdisk_addr_r}:${filesize} ${fdt_addr_r}I’d rather you did it this way for this test. If you wrap it with
mkimage -C gzip,
U-Boot may decompress it before the kernel sees it, and then we won’t have tested the
decompression fix at all. If you’d rather keepuInitrd, build it with-C noneso
the gzip bytes get passed through untouched.3. Move your load addresses
This one matters. Your current layout puts the DTB at
0x02600000, which is 38 MB in,
and the kernel at0x00080000. The newarm_Imageis 30 MB and its BSS runs past the end
of the file, so it can land on top of the DTB and you’d get a hang that looks exactly like
the one you’re already seeing. Give it room:setenv kernel_addr_r 0x00080000 setenv fdt_addr_r 0x08000000 setenv ramdisk_addr_r 0x09000000You can drop
kernel_comp_addr_randkernel_comp_size. Those are for a compressed
kernel andarm_Imageisn’t one.4. Fix the bootargs
There are four real mistakes in what you have, and one addition that will save you a lot of
time:storagedev=/dev/sdaisn’t a thing. FOS ignores it. The variable that picks a disk
isfdrive=. That’s the “Host Primary Disk” field in the web UI.storage=is pointing at the wrong share. A capture writes to
192.168.203.113:/images/dev/./imagesis exported read-only,/images/devis the
writable one, so as written the upload will fail on permissions after a long wait.web=needs the scheme:web=http://192.168.203.113/fog/. curl usually guesses,
don’t rely on it.mode=debugdoes nothing here. FOS only readsmode=whentype=is empty, so with
type=upit’s ignored. The one you want isisdebug=yes, which drops you to a shell
and pauses after every step. Use it for this first test, it’ll show you exactly where
things stop.
So:
setenv bootargs console=tty1 console=ttyS0,115200 loglevel=7 consoleblank=0 \ isdebug=yes \ web=http://192.168.203.113/fog/ \ mac=dc:a6:32:c8:b4:33 osid=50 type=up \ img=ImagePi4 imgType=mps imgPartitionType=all \ storage=192.168.203.113:/images/dev/ storageip=192.168.203.113 \ fdrive=/dev/sda(
console=ttyS0is the Pi’s mini-UART. That driver is new in this build too, so if you have
a serial adapter you’ll now get output on it. Harmless if you don’t.)5. What success looks like
Early on you should see, before anything FOG-specific:
Trying to unpack rootfs image as initramfs... Freeing initrd memory: 52576K Run /init as init processThose three lines alone tell me bug 1 is fixed on real hardware. Then the FOG banner with
Version / Init Version / Kernel Version, thenChecking Operating System ... Linux, then
Attempting to check in.If it sits on “Attempting to check in” repeating, that is a pass, not a failure. It means
everything booted and FOS is waiting for the server to hand it a job.
Then the actual capture
FOS won’t image anything until the server has a task queued for it. Hand-writing kernel
arguments doesn’t create one, which is the other reason you weren’t getting anywhere.- In the web UI, register the Pi as a host with MAC
dc:a6:32:c8:b4:33. - Set that host’s Host Primary Disk to
/dev/sda(that’s whatfdrive=above is
doing by hand). - Create an image called
ImagePi4, Linux, Multiple Partition Image - Single Disk. - On the host, Basic Tasks -> Capture.
- Boot the Pi again with the same bootargs. Check-in should return and it should start
uploading.
Fair warning on one thing I can’t predict: your Pi boots off that USB SSD, and FOS is going
to be capturing the same disk it isn’t running from, which is fine. But a Pi’s boot
partition and its partition layout aren’t like a PC’s, and I don’t know yet how our
partition code handles it. That’s the second thing I want to learn from you.
What to send back
Even a failure is useful, honestly more useful than a success.
- The console output from boot, as much as you can capture. Serial is easier than
photographing a screen if you have an adapter. - Specifically whether you see those three
initramfslines. - If it stops somewhere, whatever the last line on screen is. With
isdebug=yesit’ll be
paused at a named step rather than just hanging, which tells me exactly where to look.
Thanks for sticking with this. Two people have asked for Pi support on here over the last
couple of years and both threads died because none of the developers has the hardware, so
you finding this and being willing to test it is genuinely how it gets fixed.