Hello all,
recently I've been playing with booting BBB via USB to ease and automate flashing process. Through the fiddling, I found some peculiar things that are worth mentioning. First of all, through the net, there are some scattered informations regarding this procedure, from which I relied mostly on these two:
https://github.com/ungureanuvladvictor/BBBlfs
https://octavosystems.com/app_notes/programming-emmc-with-usb/#_Toc382081427
BBBlfs will probably work on its own as it incorporates bootp and tftp in itself, but I was looking for more general mechanism and simply digged in... Therefore I only used precompiled binary blobs from BBBlfs github page.
So lets recapitulate the boot process:
1) Eject external SD if any, hold S2 on BBB and connect your PC and P4 port on BBB via mini-USB cable
2) Internal AM335x ROM bootloader boots and exposes RNDIS network interface and asks for DHCP/BOOTP configuration
3) DHCP server on your PC then assigns IP to ROM bootloader and as a part of the same DHCP/BOOTP reply, sends name of U-boot SPL (secondary program loader) binary that it should boot, this is then requested and transferred via TFTP from your PC.
4) Once transferred, SPL boots in the same manner and again requests for DHCP/BOOTP, this time our server has to send other filename as part of its reply, that is u-boot booloader binary filename.
5) U-boot transfers, boots and here comes last booting step, TFTP is again in work, but your DHCP is not responsible anymore. U-boot simply asks for specific binary on its own using specific server IP (configured in U-boot at compile time), this binary is now flattened image tree (FIT) that includes kernel + DTB + ramdisk.
6) Uploaded kernel starts and exposes onboard eMMC as USB mass storage that simply attaches as SCSI disk to your PC, now you can simply "dd" your image to/from BBB eMMC.
As my system, I am using regular archlinux on my desktop PC, the most peculiar thing was setting up DHCP/BOOTP and TFTP servers. On the first try, I experimented with systemd-networkd to set up DHCP server of its own to send BOOTP options along. But I failed no manner what I tried, so the only thing I made systemd-networkd for me was to bring up the RNDIS interface and assign IP to it. Then I chose regular dhcp server for which some examples were available, configured subnets and to send corresponding binary filenames in DHCP/BOOTP responses, strange enough this failed too. Digged in tcpdump and in both previous cases, after DHCP/BOOTP responses there was no TFTP request for binary blob name which was sent, as if there was something wrong/incompatible (maybe because BOOTP is an older subset of DHCP and does not support dynamic addresses?). This helplessness led me to try dnsmasq - surprisingly this way worked quite easily! Also have to mention that at first I tried to use xinetd with tftpd as TFTP server, but tftpd accepts only absolute filenames, this proved critical in step 5, where U-boot asks for relative file named "itb" (which is hardcoded and wont change without recompilation of u-boot). As dnsmasq has its own tftp implementation which is sufficient and supports relative file names, my problem reduced only to configuring dnsmasq correctly, lets look on the results:
1) systemd-networkd profile:
$this->bbcode_second_pass_code('', '[Match]
Name=enp2s*
[Network]
Address=192.168.1.9/24
DHCP=no')
I have to comment here, that interface naming scheme in systemd-networkd causes a bit of head-ache. In the process, RNDIS restarts several times (between each boot stage), mac addresses of BBB change too and interface names on PC side too. For example MAC 88:c2:55:84:1f:ab and "enp2s0f0u13" for AM335x ROM, MAC 92:af:b8:15:db:77 and "enp2s0f0u13c2" for U-boot SPL and FIT. Sure, you can change interface name via udev rule like this:
$this->bbcode_second_pass_code('', 'UBSYSTEM=="net" ACTION=="add", DEVPATH=="/devices/pci*/*XX.X/*/usb1/*", NAME="usb0"')
but it is not necessary and you would have to use same USB port on your PC all the time. Good thing is, that systemd-networkd profile could contain wildcards and dnsmasq could be configured to listen on specific interfaces (or all except for...). Also local IP 192.168.1.9 is a must for last U-boot stage when loading FIT image via TFTP.
2) dnsmasq config important options:
$this->bbcode_second_pass_code('', '#Enable only DHCP and TFTP
port=0
#Listen only on RNDIS interfaces (my case)
interface=enp2s0f0u13
interface=enp2s0f0u13c2
#Set range of dhcp addresses (192.168.1.9 should be your PC address)
dhcp-range=192.168.1.10,192.168.1.100,12h
#switch between binary blobs in each stage based on vendor class string
dhcp-vendorclass=set:am335x,AM335x ROM
dhcp-vendorclass=set:ubootspl,AM335x U-Boot SPL
#fork, send spl for AM335x ROM, uboot for SPL
dhcp-boot=tag:am335x,spl
dhcp-boot=tag:ubootspl,uboot
# Enable dnsmasq's built-in TFTP server
enable-tftp
#Set tftp root to directory where your binary blobs are located
tftp-root=/XXX/tftpboot')
Basically this is all you need to have in your /etc/dnsmasq.conf. One more important thing to mention, dnsmasq must be run with "--bootp-dynamic" parameter, otherwise you must allocate IP based on MAC in your dnsmasq.conf like this:
$this->bbcode_second_pass_code('', 'dhcp-host=88:c2:55:84:1f:ab,92:af:b8:15:db:77,192.168.1.3')
also "--leasefile-ro" parameter is probably essential because --bootp-dynamic causes leases to last/stay forever. Also you should not bind interfaces as they go up and down trough the process (dnsmasq wont start if they are down).
3) Last thing I should comment is relative to binary blobs from BBBlfs:
https://github.com/ungureanuvladvictor/BBBlfs/blob/master/bin/spl
https://github.com/ungureanuvladvictor/BBBlfs/blob/master/bin/uboot
https://github.com/ungureanuvladvictor/BBBlfs/blob/master/bin/fit
Download these three files in your tftp root directory (based on dnsmasq config, /XXX/tftpboot). Binary blob "fit" must be renamed to "itb". You can see in this patch (in CONFIG_BOOTCOMMAND changes)
https://github.com/ungureanuvladvictor/BBBlfs/blob/master/tools/USB_FLash.patch
that U-boot tries to TFPT blob named itb, also you can see that its IP is hardcoded to 192.168.1.3 and it expects TFTP server on 192.168.1.9, hence systemd-networkd profile address.
4) Summary:
- Configure systemd network profile to set up RNDIS interface properly with IP 192.168.1.9, no DHCP (reload daemons, restart).
- Download binary blobs into designated TFTP root folder and rename "fit" to "itb".
- Configure dnsmasq as BOOTP/TFTP server according to provided config and start with "dnsmasq --bootp-dynamic --leasefile-ro"
- Hold S2 on BBB and plug into USB, after ~30s block device of exposed internal eMMC attaches to your PC.
- Clone/flash using for example:
$this->bbcode_second_pass_code('', 'dd if=/dev/sdX | gzip -c > ./image.img.gz
gunzip -c ./image.img.gz | dd of=/dev/sdX')
Hope this helps and have a nice day.
Zeno