-
Notifications
You must be signed in to change notification settings - Fork 265
Mounted images fail to boot #633
Copy link
Copy link
Open
Description
On NanoKVM PCIe version (img: 1.4.0/app 2.2.9), I've noticed that my .iso images are failing to boot - the boot sector seems to be fine but the rest of .iso is missing.
My BIOS reported all .iso I've used to be 162 MB in size which after some research with LLMs pointed me to this:
Why your ISO mounted as only 162 MB
- Wrong backing device was used
- The original code set imageNone = /dev/mmcblk0p3.
- When no file was passed (or logic didn’t flip correctly), the gadget exposed your real eMMC partition (~162 MB) as the storage device, not the ISO.
- BIOS therefore reported the partition’s true size = 162 MB.
I've built a workaround via AI:
kvm-mass-storage.sh
# kvm-mass-storage.sh — Recreate & mount USB gadget mass_storage properly
# Works with BusyBox ash (no bashisms).
set -eu
# Defaults
ISO_OR_IMG=""
MODE="iso" # iso | img
GADGET="g0"
LUN="0"
CFG="c.1"
UDC="" # auto-detect if empty
RO="" # auto by MODE: iso->1, img->0 (overridable)
REMOVABLE="" # empty = skip; set 0/1 to force
NOFUA="" # empty = skip; set 0/1 to force
UNMOUNT=0
usage() {
cat <<EOF
Usage:
$0 -i /data/image.iso [-m iso|img] [-g g0] [-l 0] [-c c.1] [-u <udc>] [--ro 0|1] [--removable 0|1] [--nofua 0|1]
$0 --unmount [-g g0] [-l 0] [-c c.1] [-u <udc>]
Options:
-i PATH Path to ISO/IMG file (required except with --unmount)
-m MODE iso (CD-ROM, 2048B sectors, RO) or img (disk). Default: iso
-g NAME Gadget name. Default: g0
-l N LUN index. Default: 0 (path: lun.N)
-c NAME Config name. Default: c.1
-u UDC UDC controller to bind. Default: auto-detect first in /sys/class/udc
--ro X Force ro flag (0/1). Overrides mode default.
--removable X Set lun.N/removable (0/1)
--nofua X Set lun.N/nofua (0/1)
--unmount Detach backing file and unbind/bind to signal media change
Examples:
# Mount ISO as CD-ROM (RO):
$0 -i /data/my.iso
# Mount IMG as writable disk:
$0 -i /data/disk.img -m img
# Unmount / detach:
$0 --unmount
EOF
}
# --- Parse args (POSIX) ---
while [ $# -gt 0 ]; do
case "$1" in
-i) ISO_OR_IMG="$2"; shift 2 ;;
-m) MODE="$2"; shift 2 ;;
-g) GADGET="$2"; shift 2 ;;
-l) LUN="$2"; shift 2 ;;
-c) CFG="$2"; shift 2 ;;
-u) UDC="$2"; shift 2 ;;
--ro) RO="$2"; shift 2 ;;
--removable) REMOVABLE="$2"; shift 2 ;;
--nofua) NOFUA="$2"; shift 2 ;;
--unmount) UNMOUNT=1; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown option: $1" >&2; usage; exit 1 ;;
esac
done
G="/sys/kernel/config/usb_gadget/$GADGET"
L="$G/functions/mass_storage.disk0/lun.$LUN"
C="$G/configs/$CFG"
die() { echo "ERR: $*" >&2; exit 1; }
exists_dir() { [ -d "$1" ] || die "Missing dir: $1"; }
exists_file() { [ -f "$1" ] || die "Missing file: $1"; }
# Auto RO by mode if not forced
if [ -z "${RO:-}" ]; then
if [ "$MODE" = "iso" ]; then RO=1; else RO=0; fi
fi
# Resolve UDC if empty
if [ -z "${UDC:-}" ]; then
# shellcheck disable=SC2012
UDC=$(ls -1 /sys/class/udc 2>/dev/null | head -n1 || true)
fi
# Sanity checks
exists_dir "$G" || true
[ "$UNMOUNT" -eq 1 ] || exists_file "$ISO_OR_IMG"
[ -n "$UDC" ] || [ "$UNMOUNT" -eq 1 ] || die "No UDC found; specify with -u"
# Helpers to write sysfs without newline
w() { echo -n "$2" > "$1"; }
unbind() { w "$G/UDC" ""; }
bind() { w "$G/UDC" "$UDC"; }
unlink_func() {
if [ -L "$C/mass_storage.disk0" ]; then rm -f "$C/mass_storage.disk0" || true; fi
}
detach_file() {
if [ -e "$L/file" ]; then w "$L/file" ""; fi
}
remove_func() {
if [ -d "$G/functions/mass_storage.disk0" ]; then
rmdir "$G/functions/mass_storage.disk0" 2>/dev/null || true
fi
}
create_func() {
mkdir -p "$G/functions/mass_storage.disk0"
}
ensure_config() {
mkdir -p "$C"
mkdir -p "$C/strings/0x409"
[ -f "$C/strings/0x409/configuration" ] || w "$C/strings/0x409/configuration" "Config 1"
}
link_func() {
ln -s "$G/functions/mass_storage.disk0" "$C/mass_storage.disk0"
}
set_flags() {
# MODE determines cdrom; RO already chosen
if [ "$MODE" = "iso" ]; then
w "$L/cdrom" "1"
else
w "$L/cdrom" "0"
fi
w "$L/ro" "$RO"
# Optional flags if requested and nodes exist
if [ -n "${REMOVABLE:-}" ] && [ -e "$L/removable" ]; then w "$L/removable" "$REMOVABLE"; fi
if [ -n "${NOFUA:-}" ] && [ -e "$L/nofua" ]; then w "$L/nofua" "$NOFUA"; fi
}
attach_file() {
w "$L/file" "$ISO_OR_IMG"
}
verify() {
echo "UDC: $(cat "$G/UDC" 2>/dev/null || echo)"
[ -e "$L/file" ] && echo "file: $(cat "$L/file")" || true
[ -e "$L/cdrom" ] && echo "cdrom: $(cat "$L/cdrom")" || true
[ -e "$L/ro" ] && echo "ro: $(cat "$L/ro")" || true
}
# --- Actions ---
if [ "$UNMOUNT" -eq 1 ]; then
# Cleanly detach whatever is mounted and unbind/bind to signal media change
exists_dir "$G"
exists_dir "$C" || true
echo "[*] Unmounting from $G (LUN $LUN) ..."
unbind || true
detach_file || true
unlink_func || true
remove_func || true
# Recreate empty function so host sees 'no media'
create_func
ensure_config
link_func
# Bind back (still no file attached)
if [ -n "$UDC" ]; then bind || true; fi
verify
exit 0
fi
# Mount flow
echo "[*] Mounting '$ISO_OR_IMG' as $MODE on gadget '$GADGET', LUN $LUN, cfg $CFG, UDC=${UDC:-auto-none}"
exists_dir "$G" || die "Gadget $GADGET not found in configfs"
ensure_config
# 1) Unbind to avoid host probing mid-change
unbind || true
# 2) Unlink & remove any existing mass_storage function
unlink_func || true
detach_file || true
# small settle helps some controllers
sleep 0.2
remove_func || true
# 3) Recreate function fresh
create_func
# 4) Set flags BEFORE attaching file
set_flags
# 5) Attach file (no newline)
attach_file
# 6) Link function into the config
link_func
# 7) Bind to UDC
[ -n "$UDC" ] && bind
# 8) Verify
verify
echo "[*] Done."
chmod +x kvm-mass-storage.sh
./kvm-mass-storage.sh -i /data/my.iso - this properly mounts it, BIOS recognizes the proper ISO size and it is booting properly
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels