forked from armbian/build
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
extensions:
initramfs-usb-gadget-ums
: kernel cmdline enables initra…
…mfs UMS of all block devices - this optional extension adds an initramfs script that: - enumerates and filters all block devices - exposes each device as an UMS (USB Mass Storage) in an USB Gadget - loops forever with info (board never boots) - the idea here is to compensate for UEFI's lack of "ums" or "rockusb" mode that's present in u-boot - it also allows to expose USB/NVMe devices that might or not be detected by bootloader, if the kernel works
- Loading branch information
1 parent
205dd11
commit 055d871
Showing
2 changed files
with
204 additions
and
0 deletions.
There are no files selected for viewing
173 changes: 173 additions & 0 deletions
173
extensions/initramfs-usb-gadget-ums/init-premount/usb-gadget-ums.sh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
#!/bin/sh | ||
|
||
# SPDX-License-Identifier: GPL-2.0 | ||
# Copyright (c) 2023 Ricardo Pardini <[email protected]> | ||
# This file is a part of the Armbian Build Framework https://github.com/armbian/build/ | ||
|
||
echo "" | ||
echo "Armbian initramfs USB Gadget UMS: ums-initramfs.sh starting..." | ||
|
||
# First, check if /proc/cmdline contains "ums=yes", otherwise exit | ||
if ! grep -q "ums=yes" /proc/cmdline; then | ||
echo "Armbian initramfs USB Gadget UMS: ums=yes not found in /proc/cmdline, exiting normally." | ||
exit 0 | ||
fi | ||
|
||
echo "Armbian initramfs USB Gadget UMS: ums=yes found in /proc/cmdline, continuing..." | ||
sleep 1 | ||
|
||
deviceinfo_name="Armbian on %%BOARD%%" | ||
deviceinfo_manufacturer="Armbian on %%BOARD%%" | ||
usb_idVendor="0x1d6b" # Linux Foundation | ||
usb_idProduct="0x104" # Multifunction Composite Gadget. | ||
usb_serialnumber="Armbian %%BOARD%%" | ||
|
||
echo "Armbian initramfs USB Gadget UMS: found UDC: $(ls /sys/class/udc) for %%BOARD%%" | ||
|
||
modprobe g_ffs || echo "Armbian initramfs USB Gadget UMS: Failed to modprobe g_ffs" | ||
|
||
mkdir -p /config | ||
mount -t configfs -o nodev,noexec,nosuid configfs /config | ||
|
||
CONFIGFS=/config/usb_gadget | ||
GADGET=${CONFIGFS}/g1 | ||
CONFIG=${GADGET}/configs/c.1 | ||
FUNCTIONS=${GADGET}/functions | ||
|
||
if [ -d "${GADGET}" ]; then | ||
echo "Armbian initramfs USB Gadget UMS: Found existing gadget, removing" | ||
echo "" > ${GADGET}/UDC | ||
|
||
rm -v ${CONFIG}/mass_storage.usb* | ||
|
||
rmdir -v ${CONFIG}/strings/0x409 | ||
rmdir -v ${CONFIG} | ||
|
||
rmdir -v ${FUNCTIONS}/mass_storage.usb* | ||
|
||
rmdir -v ${GADGET}/strings/0x409 | ||
|
||
rmdir -v "${GADGET}" | ||
|
||
echo "Done removing gadget" | ||
|
||
if [ -d "${GADGET}" ]; then | ||
echo "Gadget still exists... ${GADGET}" | ||
fi | ||
exit 0 | ||
fi | ||
|
||
echo " Setting up an USB gadget through configfs" | ||
mkdir ${GADGET} || echo " Couldn't create ${GADGET}" | ||
echo "$usb_idVendor" > "${GADGET}/idVendor" | ||
echo "$usb_idProduct" > "${GADGET}/idProduct" | ||
|
||
# Create english (0x409) strings | ||
mkdir ${GADGET}/strings/0x409 || echo " Couldn't create ${GADGET}/strings/0x409" | ||
|
||
echo "$deviceinfo_manufacturer" > "${GADGET}/strings/0x409/manufacturer" | ||
echo "$usb_serialnumber" > "${GADGET}/strings/0x409/serialnumber" | ||
echo "$deviceinfo_name" > "${GADGET}/strings/0x409/product" | ||
|
||
# Create configuration instance | ||
mkdir ${CONFIG} || echo " Couldn't create ${CONFIG}" | ||
|
||
counter=0 | ||
all_devices="" | ||
|
||
for one_block in /sys/class/block/*; do | ||
partition="${one_block}/partition" | ||
if [ -f "$partition" ]; then | ||
continue # we don't wanna expose partitions | ||
fi | ||
size_file="${one_block}/size" | ||
if [ ! -f "$size_file" ]; then | ||
continue # we don't wanna expose non-block devices | ||
fi | ||
size=$(cat "$size_file") | ||
if [ "$size" -eq 0 ]; then | ||
continue # we don't wanna expose zero-sized devices | ||
fi | ||
# we don't wanna expose devices that smaller than 1Gb (avoids mmcblk0boot0 etc) | ||
if [ "$size" -lt 1953125 ]; then | ||
continue | ||
fi | ||
|
||
ro_file="${one_block}/ro" | ||
if [ ! -f "$ro_file" ]; then | ||
continue # we don't wanna expose devices that can't tell if they're read-only | ||
fi | ||
ro=$(cat -v "$ro_file") | ||
if [ "$ro" -ne 0 ]; then | ||
continue # we don't wanna expose read-only devices | ||
fi | ||
phys_block_size_file="${one_block}/queue/physical_block_size" | ||
if [ ! -f "$phys_block_size_file" ]; then | ||
continue # we don't wanna expose devices that can't tell us their physical block size | ||
fi | ||
phys_block_size=$(cat "$phys_block_size_file") | ||
if [ "$phys_block_size" -ne 512 ]; then | ||
continue # we don't wanna expose devices that don't have a 512-byte physical block size | ||
fi | ||
|
||
# lets guess the real device name... | ||
basename_device=$(basename "$one_block") | ||
device_in_dash_dev="/dev/${basename_device}" | ||
if [ ! -b "$device_in_dash_dev" ]; then | ||
continue # we don't wanna expose devices that don't have a /dev/ entry | ||
fi | ||
|
||
description="Armbian${counter} ${basename_device}" | ||
|
||
model_file="${one_block}/device/model" | ||
if [ -f "$model_file" ]; then | ||
model=$(cat "$model_file") | ||
model=$(echo "$model" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') | ||
description="${description} ${model}" | ||
fi | ||
|
||
# hack, skip this | ||
#if [ "$basename_device" = "mmcblk0" ]; then | ||
# continue | ||
#fi | ||
|
||
echo "one block [${counter}]: $one_block one_block: $one_block size: ${size} ro: ${ro} phys_block_size: ${phys_block_size} basename_device: ${basename_device} device_in_dash_dev: ${device_in_dash_dev} model: '${model}' description: '${description}'" | ||
|
||
# add to all_devices | ||
all_devices="${all_devices} '${counter}:${description}' " | ||
|
||
# increment counter | ||
counter=$((counter + 1)) | ||
|
||
echo "Create Mass Storage device ${counter} for ${device_in_dash_dev} desc '${description}'" | ||
MASS_STORAGE_FUNCTION="${FUNCTIONS}/mass_storage.usb${counter}" | ||
mkdir -p "${MASS_STORAGE_FUNCTION}" || echo " Couldn't create ${MASS_STORAGE_FUNCTION}" | ||
echo 1 > "${MASS_STORAGE_FUNCTION}"/stall # allow bulk EPs | ||
echo 0 > "${MASS_STORAGE_FUNCTION}"/lun.0/cdrom # don't emulate CD-ROm | ||
#echo 0 > "${MASS_STORAGE_FUNCTION}"/ro # write access - disabled for now | ||
echo 0 > "${MASS_STORAGE_FUNCTION}"/lun.0/nofua # enable Force Unit Access (FUA) | ||
echo 0 > "${MASS_STORAGE_FUNCTION}"/lun.0/removable | ||
echo "${description}" > "${MASS_STORAGE_FUNCTION}"/lun.0/inquiry_string | ||
echo "${device_in_dash_dev}" > "${MASS_STORAGE_FUNCTION}"/lun.0/file | ||
|
||
# Link the function to the config | ||
ln -s "${MASS_STORAGE_FUNCTION}" "${CONFIG}" || echo " Couldn't symlink mass_storage.usb${counter}" | ||
|
||
done | ||
|
||
echo "Done creating functions and configs, enabling UDC.." | ||
|
||
echo "$(ls /sys/class/udc)" > ${GADGET}/UDC || echo " Couldn't write UDC" | ||
|
||
#umount /config | ||
|
||
echo "Armbian initramfs USB Gadget UMS: done USB Gadget mode." | ||
|
||
while true; do | ||
echo "Armbian initramfs USB Gadget UMS: Board: %%BOARD%%" | ||
echo "Armbian initramfs USB Gadget UMS: Machine will hang here forever; connect your USB OTG cable and write to disks!" | ||
echo "Armbian initramfs USB Gadget UMS: UMS devices: ${all_devices}" | ||
echo "Armbian initramfs USB Gadget UMS: UMS UDC: $(ls /sys/class/udc)" | ||
echo "Armbian initramfs USB Gadget UMS: Now: $(date)" | ||
sleep 30 | ||
done |
31 changes: 31 additions & 0 deletions
31
extensions/initramfs-usb-gadget-ums/initramfs-usb-gadget-ums.sh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# | ||
# SPDX-License-Identifier: GPL-2.0 | ||
# Copyright (c) 2023 Ricardo Pardini <[email protected]> | ||
# This file is a part of the Armbian Build Framework https://github.com/armbian/build/ | ||
|
||
# This includes a very early script in the initramfs, which checks the kernel command line | ||
# for the presence of "ums=yes", and if found, sets up a USB gadget for UMS (USB Mass Storage) | ||
# exposing all the block devices found in the system. | ||
# After setting this up, it loops forever, so the initramfs doesn't proceed to boot the system. | ||
# This allows the user to connect the board to a host computer, and use it as a USB storage device, | ||
# to flash the eMMC/SD/NVMe/USB/whatever storage device simply using BalenaEtcher or similar tools. | ||
|
||
function extension_prepare_config__check_sanity_usb_gadget_ums() { | ||
display_alert "Checking sanity for" "${EXTENSION} in dir ${EXTENSION_DIR}" "info" | ||
local script_file_src="${EXTENSION_DIR}/init-premount/usb-gadget-ums.sh" | ||
if [[ ! -f "${script_file_src}" ]]; then | ||
exit_with_error "Could not find '${script_file_src}'" | ||
fi | ||
} | ||
|
||
|
||
# @TODO: maybe include this in the bsp-cli, so it can be updated later | ||
function pre_customize_image__inject_initramfs_usb_gadget_ums() { | ||
display_alert "Enabling" "usb-gadget-ums into initramfs" "info" | ||
local script_file_src="${EXTENSION_DIR}/init-premount/usb-gadget-ums.sh" | ||
local script_file_dst="${SDCARD}/etc/initramfs-tools/scripts/init-premount/usb-gadget-ums.sh" | ||
run_host_command_logged cat "${script_file_src}" "|" sed -e "'s|%%BOARD%%|${BOARD}|g'" ">" "${script_file_dst}" | ||
run_host_command_logged chmod -v +x "${script_file_dst}" | ||
return 0 | ||
} | ||
|