Experiments with the BeagleBone Black and U-Boot

This is a somewhat unstructured (and work in progress) protocol of me messing around with an embedded linux tutorial in the middle of 2024. These notes are mainly intended for my own potential future benefit. YMMV.

I’ve been working my way through bootlin’s excellent (freely available) course material for their (paid) trainings on embedded Linux. I’m using a BeagleBone Black (BBB) as my hardware testbed of choice.

Bus Pirate Woes

The BBB comes with a serial debug header (J1), where you can attach a serial interface to pins 1 (ground), 4 (receive) and 5 (transmit). I don’t own the required FTDI cable but the Bus Pirate v4 that had been gathering dust in a drawer should do the trick. Or so I thought. An old blog article contained a walk through how to set the Bus Pirate into UART mode to talk to the BBB. However, it turns out that the firmware on my board was so old that it did not include UART support yet. Then, even after reflashing the Bus Pirate to the latest firmware binaries that I could find , I could not get the BBB’s serial to work. This was extremely hard to debug. To make sure that the BBB wasn’t at fault, I downloaded a Debian image that I copied onto an SD card. Once I had inserted that, the BBB happily flashed its LED’s, indicating that it could indeed boot, but nothing that I did changed the fact that the Bus Pirate didn’t receive anything when configured to UART. In my desperation, I then went back and had a second look through my collection of odd USB dongles. I found a likely candidate with a likely-looking PCB. Indeed, searching for the code on the chip (SILABS CP2102) revealed that it was indeed a USB to UART chip. I could have simply plugged it in, where dmesg would have revealed

[129653.912133] usb 1-5.1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[129653.912137] usb 1-5.1.1: Product: CP2102 USB to UART Bridge Controller
[129653.912140] usb 1-5.1.1: Manufacturer: Silicon Labs
[129653.918658] cp210x 1-5.1.1:1.0: cp210x converter detected
[129653.921474] usb 1-5.1.1: cp210x converter now attached to ttyUSB0

And what is more, after attaching RX and TX cables in the right (crossed-over) order to the J1 header on the BBB, I finally could watch the thing boot, although not yet with my self-compiled version.

So, the Bus Pirate was at fault all along. Not sure if I messed it up or simply failed to properly enable UART.

Snagboot Woes

I could not get my self-compiled U-Boot bootloader reliably deployed to the BBB’s internal EMMC. While the Snagboot tool claims to support (re)flashing the bootloader of the BBB via the BOOTP-based recovery mechanism, my board refused to cooperate. It retrieves the SPL via TFTP just fine but then simply does not fetch the main u-boot.img payload in a second TFTP request.

After many retries, booting via USB (in ethernet gadget mode) finally started to work and I could load my own cross-compiled U-Boot and play around in the U-Boot shell. After playing around with further compile flags in an effort to get fastboot mode to work in U-Boot, I at one point ended up with broken SPL that could no longer load the main u-boot.img via USB. I didn’t think it would be an issue, but no matter what I tried, even with a complete vanilla build of U-Boot for the BBB, booting via USB simply stopped working beyond this point, I couldn’t get back to a working snagboot state.

Flashing U-Boot to SD Card

After giving up on snagboot, I followed this howto to copy my version of U-Boot to the raw SD card.

export DISK=/dev/sda
sudo dd if=/dev/zero of=${DISK} bs=1M count=10
sudo dd if=MLO of=${DISK} count=2 seek=1 bs=128k
sudo dd if=u-boot-dtb.img of=${DISK} count=4 seek=1 bs=384k
sync

Cross-compiling a Linux kernel

git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux
cd linux
git remote add stable https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux
git fetch stable
git checkout stable/linux-6.9.y
export PATH=/home/thorben/x-tools/arm-training-linux-musleabihf/bin:$PATH
make ARCH=arm CROSS_COMPILE=arm-linux- help
make ARCH=arm CROSS_COMPILE=arm-linux- omap2plus_defconfig 
make ARCH=arm CROSS_COMPILE=arm-linux- nconfig

Finally getting everything lined up

Boot into the u-boot shell. In the serial console, you’ll see u-boot startup messages. For me, it looks like this:

U-Boot SPL 2024.07-rc3-benthor (May 30 2024 - 12:57:11 +0200)
Trying to boot from MMC1


U-Boot 2024.07-rc3-benthor (May 30 2024 - 12:57:11 +0200)

CPU  : AM335X-GP rev 2.0
Model: TI AM335x BeagleBone Black
DRAM:  512 MiB
Core:  161 devices, 18 uclasses, devicetree: separate
WDT:   Started wdt@44e35000 with servicing every 1000ms (60s timeout)
NAND:  0 MiB
MMC:   OMAP SD/MMC: 0, OMAP SD/MMC: 1
Loading Environment from FAT... Unable to read "uboot.env" from mmc0:1... 
<ethaddr> not set. Validating first E-fuse MAC
Net:   eth2: ethernet@4a100000using musb-hdrc, OUT ep1out IN ep1in STATUS ep2in
MAC de:ad:be:ef:00:01
HOST MAC de:ad:be:ef:00:00
RNDIS ready
, eth3: usb_ether
Hit any key to stop autoboot:  0 

Not sure how to look at the FAT filesystem. help fatls has a slightly intimidating signature:

=> fatls
fatls - list files in a directory (default /)

Usage:
fatls <interface> [<dev[:part]>] [directory]
    - list files from 'dev' on 'interface' in a 'directory'

Not sure what to put in for interface, device and partition, but the line Loading Environment from FAT... Unable to read "uboot.env" from mmc0:1... that u-boot gives while loading gives us some clues. Indeed, just randomly trying fatls mmc 0:1 works!

   103708   MLO
  1544324   u-boot.img
  5590096   zImage
    70308   am335x-boneblack.dtb

These are exactly the files on our SD card.

So let’s try booting this zImage. The bootlin lab document gives useful hints how we might do this. First, let’s use the console to set an environment variable and save it, creating uboot.env:

=> setenv bootargs console=ttyS0,115200n8
=> saveenv
Saving Environment to FAT... OK
=> fatls mmc 0:1
   103708   MLO
  1544324   u-boot.img
  5590096   zImage
    70308   am335x-boneblack.dtb
   131072   uboot.env

5 file(s), 0 dir(s)

Now we need to load the kernel and the device tree into memory so that we can boot. fatload can load files from FAT into memory addresses. Here, I simply copied the addresses from the bootlin tutorial without quite understanding why those exact numbers.

=> fatload mmc 0:1 0x81000000 zImage 
5590096 bytes read in 369 ms (14.4 MiB/s)
=> fatload mmc 0:1 0x82000000 am335x-boneblack.dtb
70308 bytes read in 8 ms (8.4 MiB/s)

Then we can try booting the kernel. bootz takes three addresses but we’ll leave out the middle one for now, as we don’t have an initrd just yet:

bootz 0x81000000 - 0x82000000

This is how it looks in my case:


Kernel image @ 0x81000000 [ 0x000000 - 0x554c50 ]
## Flattened Device Tree blob at 82000000
   Booting using the fdt blob at 0x82000000
Working FDT set to 82000000
   Loading Device Tree to 8ffeb000, end 8ffff2a3 ... OK
Working FDT set to 8ffeb000

Starting kernel ...

[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 6.9.3 (thorben@Vetinari) (arm-linux-gcc (crosstool-NG 1.26.0) 13.2.0, GNU ld (crosstool-NG 1.26.0) 2.40) #2 SMP Fri May 31 13:49:57 CEST 2024
[    0.000000] CPU: ARMv7 Processor [413fc082] revision 2 (ARMv7), cr=10c5387d
[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[    0.000000] OF: fdt: Machine model: TI AM335x BeagleBone Black
[    0.000000] Memory policy: Data cache writeback
[    0.000000] cma: Reserved 16 MiB at 0x9e800000 on node -1
[    0.000000] Zone ranges:
[    0.000000]   Normal   [mem 0x0000000080000000-0x000000009fdfffff]
[    0.000000]   HighMem  empty
[    0.000000] Movable zone start for each node
[    0.000000] Early memory node ranges
[    0.000000]   node   0: [mem 0x0000000080000000-0x000000009fdfffff]
[    0.000000] Initmem setup node 0 [mem 0x0000000080000000-0x000000009fdfffff]
[    0.000000] CPU: All CPU(s) started in SVC mode.
[    0.000000] AM335X ES2.0 (sgx neon)
[    0.000000] percpu: Embedded 17 pages/cpu s40084 r8192 d21356 u69632
[    0.000000] Kernel command line: console=ttyS0,115200n8
[    0.000000] Dentry cache hash table entries: 65536 (order: 6, 262144 bytes, linear)
[    0.000000] Inode-cache hash table entries: 32768 (order: 5, 131072 bytes, linear)
[    0.000000] Built 1 zonelists, mobility grouping on.  Total pages: 129412
[    0.000000] mem auto-init: stack:all(zero), heap alloc:off, heap free:off
[    0.000000] Memory: 483620K/522240K available (11264K kernel code, 1174K rwdata, 2752K rodata, 1024K init, 294K bss, 22236K reserved, 16384K cma-reserved, 0K highmem)
[    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
[    0.000000] trace event string verifier disabled
[    0.000000] rcu: Hierarchical RCU implementation.
[    0.000000] rcu: 	RCU event tracing is enabled.
[    0.000000] rcu: 	RCU restricting CPUs from NR_CPUS=2 to nr_cpu_ids=1.
[    0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 10 jiffies.
[    0.000000] rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=1
[    0.000000] NR_IRQS: 16, nr_irqs: 16, preallocated irqs: 16
[    0.000000] IRQ: Found an INTC at 0x(ptrval) (revision 5.0) with 128 interrupts
[    0.000000] rcu: srcu_init: Setting srcu_struct sizes based on contention.
[    0.000000] TI gptimer clocksource: always-on /ocp/interconnect@44c00000/segment@200000/target-module@31000
[    0.000003] sched_clock: 32 bits at 24MHz, resolution 41ns, wraps every 89478484971ns
[    0.000029] clocksource: dmtimer: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 79635851949 ns
[    0.000486] TI gptimer clockevent: 24000000 Hz at /ocp/interconnect@48000000/segment@0/target-module@40000
[    0.001958] Console: colour dummy device 80x30
[    0.002044] Calibrating delay loop... 996.14 BogoMIPS (lpj=4980736)
[    0.090538] CPU: Testing write buffer coherency: ok
[    0.090636] CPU0: Spectre v2: using BPIALL workaround
[    0.090647] pid_max: default: 32768 minimum: 301
[    0.090773] LSM: initializing lsm=capability
[    0.090938] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[    0.090959] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[    0.092515] CPU0: thread -1, cpu 0, socket -1, mpidr 0
[    0.093993] Setting up static identity map for 0x80100000 - 0x80100078
[    0.094286] rcu: Hierarchical SRCU implementation.
[    0.094299] rcu: 	Max phase no-delay instances is 1000.
[    0.095284] smp: Bringing up secondary CPUs ...
[    0.095334] smp: Brought up 1 node, 1 CPU
[    0.095347] SMP: Total of 1 processors activated (996.14 BogoMIPS).
[    0.095359] CPU: All CPU(s) started in SVC mode.
[    0.096251] devtmpfs: initialized
[    0.111071] VFP support v0.3: implementor 41 architecture 3 part 30 variant c rev 3
[    0.111445] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
[    0.111481] futex hash table entries: 256 (order: 2, 16384 bytes, linear)
[    0.112696] pinctrl core: initialized pinctrl subsystem
[    0.115143] NET: Registered PF_NETLINK/PF_ROUTE protocol family
[    0.117838] DMA: preallocated 256 KiB pool for atomic coherent allocations
[    0.118409] audit: initializing netlink subsys (disabled)
[    0.119957] thermal_sys: Registered thermal governor 'fair_share'
[    0.119977] thermal_sys: Registered thermal governor 'step_wise'
[    0.119988] thermal_sys: Registered thermal governor 'user_space'
[    0.120106] audit: type=2000 audit(0.110:1): state=initialized audit_enabled=0 res=1
[    0.120175] cpuidle: using governor menu
[    0.141039] No ATAGs?
[    0.141073] hw-breakpoint: debug architecture 0x4 unsupported.
[    0.143899] kprobes: kprobe jump-optimization is enabled. All kprobes are optimized if possible.
[    0.163535] iommu: Default domain type: Translated
[    0.163558] iommu: DMA domain TLB invalidation policy: strict mode
[    0.171489] SCSI subsystem initialized
[    0.172199] usbcore: registered new interface driver usbfs
[    0.172248] usbcore: registered new interface driver hub
[    0.172310] usbcore: registered new device driver usb
[    0.172637] pps_core: LinuxPPS API ver. 1 registered
[    0.172649] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[    0.172675] PTP clock support registered
[    0.180858] vgaarb: loaded
[    0.181217] clocksource: Switched to clocksource dmtimer
[    0.181801] VFS: Disk quotas dquot_6.6.0
[    0.181866] VFS: Dquot-cache hash table entries: 1024 (order 0, 4096 bytes)
[    0.206098] NET: Registered PF_INET protocol family
[    0.206446] IP idents hash table entries: 8192 (order: 4, 65536 bytes, linear)
[    0.207816] tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 4096 bytes, linear)
[    0.207856] Table-perturb hash table entries: 65536 (order: 6, 262144 bytes, linear)
[    0.207874] TCP established hash table entries: 4096 (order: 2, 16384 bytes, linear)
[    0.207918] TCP bind hash table entries: 4096 (order: 4, 65536 bytes, linear)
[    0.208019] TCP: Hash tables configured (established 4096 bind 4096)
[    0.208143] UDP hash table entries: 256 (order: 1, 8192 bytes, linear)
[    0.208171] UDP-Lite hash table entries: 256 (order: 1, 8192 bytes, linear)
[    0.208351] NET: Registered PF_UNIX/PF_LOCAL protocol family
[    0.222302] RPC: Registered named UNIX socket transport module.
[    0.222330] RPC: Registered udp transport module.
[    0.222337] RPC: Registered tcp transport module.
[    0.222343] RPC: Registered tcp-with-tls transport module.
[    0.222349] RPC: Registered tcp NFSv4.1 backchannel transport module.
[    0.222376] PCI: CLS 0 bytes, default 64
[    0.223934] Initialise system trusted keyrings
[    0.225089] workingset: timestamp_bits=14 max_order=17 bucket_order=3
[    0.226355] NFS: Registering the id_resolver key type
[    0.226449] Key type id_resolver registered
[    0.226459] Key type id_legacy registered
[    0.226510] jffs2: version 2.2. (NAND) (SUMMARY)  © 2001-2006 Red Hat, Inc.
[    0.226964] Key type asymmetric registered
[    0.226982] Asymmetric key parser 'x509' registered
[    0.227052] io scheduler mq-deadline registered
[    0.227064] io scheduler kyber registered
[    0.227133] io scheduler bfq registered
[    0.241360] Serial: 8250/16550 driver, 6 ports, IRQ sharing enabled
[    0.302421] brd: module loaded
[    0.310451] loop: module loaded
[    0.311569] mtdoops: mtd device (mtddev=name/number) must be supplied
[    0.315659] usbcore: registered new interface driver cdc_acm
[    0.315683] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
[    0.315724] usbcore: registered new interface driver cdc_wdm
[    0.315765] usbcore: registered new interface driver usb-storage
[    0.316079] UDC core: g_ether: couldn't find an available UDC
[    0.316089] i2c_dev: i2c /dev entries driver
[    0.316955] cpuidle: enable-method property 'ti,am3352' found operations
[    0.317387] sdhci: Secure Digital Host Controller Interface driver
[    0.317402] sdhci: Copyright(c) Pierre Ossman
[    0.317572] sdhci-pltfm: SDHCI platform and OF driver helper
[    0.335059] ledtrig-cpu: registered to indicate activity on CPUs
[    0.335913] Initializing XFRM netlink socket
[    0.336053] NET: Registered PF_INET6 protocol family
[    0.337883] Segment Routing with IPv6
[    0.337980] In-situ OAM (IOAM) with IPv6
[    0.338086] sit: IPv6, IPv4 and MPLS over IPv4 tunneling driver
[    0.339011] NET: Registered PF_PACKET protocol family
[    0.339044] NET: Registered PF_KEY protocol family
[    0.339248] Key type dns_resolver registered
[    0.339449] ThumbEE CPU extension supported.
[    0.339471] Registering SWP/SWPB emulation handler
[    0.339923] omap_voltage_late_init: Voltage driver support not added
[    0.340294] SmartReflex Class3 initialized
[    0.369714] Loading compiled-in X.509 certificates
[    0.428477] platform 44e10800.pinmux: Fixed dependency cycle(s) with /ocp/interconnect@44c00000/segment@200000/target-module@10000/scm@0/pinmux@800/clkout2-pins
[    0.429111] pinctrl-single 44e10800.pinmux: 142 pins, size 568
[    0.434266] ti-sysc 44e31000.target-module: probe with driver ti-sysc failed with error -16
[    0.459425] ti-sysc 48040000.target-module: probe with driver ti-sysc failed with error -16
[    0.483611] OMAP GPIO hardware version 0.1
[    0.524159] omap_i2c 4819c000.i2c: bus 2 rev0.11 at 100 kHz
[    0.554330] platform 4830e000.lcdc: Fixed dependency cycle(s) with /ocp/interconnect@44c00000/segment@200000/target-module@b000/i2c@0/tda19988@70
[    0.566230] sdhci-omap 481d8000.mmc: supply pbias not found, using dummy regulator
[    0.566713] sdhci-omap 481d8000.mmc: supply vqmmc not found, using dummy regulator
[    0.644840] davinci_mdio 4a101000.mdio: davinci mdio revision 1.6, bus freq 1000000
[    0.762726] davinci_mdio 4a101000.mdio: phy[0]: device 4a101000.mdio:00, driver SMSC LAN8710/LAN8720
[    0.763201] cpsw-switch 4a100000.switch: initialized cpsw ale version 1.4
[    0.763223] cpsw-switch 4a100000.switch: ALE Table size 1024
[    0.763368] cpsw-switch 4a100000.switch: cpts: overflow check period 500 (jiffies)
[    0.763386] cpsw-switch 4a100000.switch: CPTS: ref_clk_freq:250000000 calc_mult:2147483648 calc_shift:29 error:0 nsec/sec
[    0.763499] cpsw-switch 4a100000.switch: Detected MACID = c8:a0:30:ac:3a:74
[    0.765258] cpsw-switch 4a100000.switch: initialized (regs 0x4a100000, pool size 256) hw_ver:0019010C 1.12 (0)
[    0.775946] debugfs: Directory '49000000.dma' with parent 'dmaengine' already present!
[    0.775996] edma 49000000.dma: TI EDMA DMA engine driver
[    0.782680] am335x-phy-driver 47401300.usb-phy: dummy supplies not allowed for exclusive requests
[    0.787611] am335x-phy-driver 47401b00.usb-phy: dummy supplies not allowed for exclusive requests
[    0.859946] hw perfevents: enabled with armv7_cortex_a8 PMU driver, 5 counters available
[    0.867714] l3-aon-clkctrl:0000:0: failed to disable
[    0.894194] printk: legacy console [ttyS0] disabled
[    0.895049] 44e09000.serial: ttyS0 at MMIO 0x44e09000 (irq = 36, base_baud = 3000000) is a 8250
[    0.895131] printk: legacy console [ttyS0] enabled
[    2.122833] tps65217-pmic: Failed to locate of_node [id: -1]
[    2.128881] tps65217-bl: Failed to locate of_node [id: -1]
[    2.156521] tps65217 0-0024: TPS65217 ID 0xe version 1.2
[    2.162694] platform 4830e000.lcdc: Fixed dependency cycle(s) with /ocp/interconnect@44c00000/segment@200000/target-module@b000/i2c@0/tda19988@70
[    2.176093] i2c 0-0070: Fixed dependency cycle(s) with /ocp/interconnect@48000000/segment@300000/target-module@e000/lcdc@0
[    2.187493] omap_i2c 44e0b000.i2c: bus 0 rev0.11 at 400 kHz
[    2.200072] g_ether gadget.0: HOST MAC ee:02:0b:2f:95:5d
[    2.205594] g_ether gadget.0: MAC ba:a3:40:9f:75:3e
[    2.210909] g_ether gadget.0: Ethernet Gadget, version: Memorial Day 2008
[    2.217792] g_ether gadget.0: g_ether ready
[    2.224633] omap_gpio 44e07000.gpio: Could not set line 6 debounce to 200000 microseconds (-22)
[    2.233554] sdhci-omap 48060000.mmc: Got CD GPIO
[    2.238545] sdhci-omap 48060000.mmc: supply pbias not found, using dummy regulator
[    2.278696] sdhci-omap 48060000.mmc: supply vqmmc not found, using dummy regulator
[    2.293653] clk: Disabling unused clocks
[    2.297829] PM: genpd: Disabling unused power domains
[    2.303972] sdhci-omap 481d8000.mmc: supply pbias not found, using dummy regulator
[    2.312790] sdhci-omap 481d8000.mmc: supply vqmmc not found, using dummy regulator
[    2.351693] mmc1: SDHCI controller on 481d8000.mmc [481d8000.mmc] using External DMA
[    2.359970] mmc0: SDHCI controller on 48060000.mmc [48060000.mmc] using External DMA
[    2.369730] /dev/root: Can't open blockdev
[    2.374044] VFS: Cannot open root device "" or unknown-block(0,0): error -6
[    2.381047] Please append a correct "root=" boot option; here are the available partitions:
[    2.389496] 0100           16384 ram0 
[    2.389508]  (driver?)
[    2.395696] 0101           16384 ram1 
[    2.395705]  (driver?)
[    2.401867] 0102           16384 ram2 
[    2.401875]  (driver?)
[    2.408007] 0103           16384 ram3 
[    2.408015]  (driver?)
[    2.414168] 0104           16384 ram4 
[    2.414176]  (driver?)
[    2.420305] 0105           16384 ram5 
[    2.420313]  (driver?)
[    2.426468] 0106           16384 ram6 
[    2.426477]  (driver?)
[    2.432627] 0107           16384 ram7 
[    2.432635]  (driver?)
[    2.438764] 0108           16384 ram8 
[    2.438772]  (driver?)
[    2.444937] 0109           16384 ram9 
[    2.444945]  (driver?)
[    2.451075] 010a           16384 ram10 
[    2.451082]  (driver?)
[    2.457323] 010b           16384 ram11 
[    2.457332]  (driver?)
[    2.463570] 010c           16384 ram12 
[    2.463578]  (driver?)
[    2.469795] 010d           16384 ram13 
[    2.469802]  (driver?)
[    2.476039] 010e           16384 ram14 
[    2.476048]  (driver?)
[    2.482284] 010f           16384 ram15 
[    2.482292]  (driver?)
[    2.488517] List of all bdev filesystems:
[    2.492563]  ext3
[    2.492570]  ext4
[    2.494504]  ext2
[    2.496436]  cramfs
[    2.498368]  vfat
[    2.500474]  msdos
[    2.502425] 
[    2.505940] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
[    2.514255] ---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0) ]---

Heureka!

Having seen that loading the kernel from FAT like this works, we can store the necessary commands in the bootcmd environment variable. Reset the board into u-boot console and:

=> setenv bootcmd 'fatload mmc 0:1 0x81000000 zImage; fatload mmc 0:1 0x82000000 am335x-boneblack.dtb; bootz 0x81000000 - 0x82000000'
=> saveenv

Booting into busybox

[    2.883263] Run /bin/busybox as init process
BusyBox v1.36.1 (2024-06-03 18:32:19 CEST)[    2.910874] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000
[    2.921061] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000 ]---
 multi-call binary.
BusyBox is copyrighted by many authors between 1998-2015.
Licensed under GPLv2. See source distribution for detailed
copyright notices.

Usage: busybox [function [arguments]...]
   or: busybox --list
   or: function [arguments]...

	BusyBox is a multi-call binary that combines many common Unix
	utilities into a single executable.  Most people will create a
	link to busybox for each function they wish to use and BusyBox
	will act like whatever it was invoked as.

Currently defined functions:
	ash, cat, chmod, cp, df, dmesg, echo, find, grep, halt, httpd,
	i2cdetect, ifconfig, init, insmod, kill, ln, ls, lsmod, lsusb, mkdir,
	mknod, modinfo, modprobe, more, mount, mv, od, ping, poweroff, ps, pwd,
	reboot, rm, rmdir, rmmod, seedrng, sh, sleep, swapoff, sync, top,
	touch, tree, tsort, umount, uname, uptime, vi, which

Resources

Online sites that helped me along: