Repository navigation
usb: fix SuperSpeedPlus passthrough - #7928
Conversation
|
If you don't have the entitlement you can still test with sudo (QEMU command line only) or with SIP off (get entitlement without needing a profile). Either way we do not accept untested PR as per CONTRIBUTING.md. |
|
As requested, I ran the tests physically with the hardware from the report. Setup: MacBook Air M4, macOS 27.0.1, the ASM2362 USB 3.2 Gen 2 enclosure (
Both attaching and detaching were confirmed on the physical device. The detach behaviour depends on the libusb fix ( |
|
Hello @osy, is this proposal alright? Should I fix anything about it? |
a768d7a to
6ee9f03
Compare
|
@osy the hardware test is done (details in the comment above): with the ASM2362 enclosure the guest enumerates it at SuperSpeed, |
|
@giovariot |
Disconnecting a USB drive that the guest uses through USB Attached SCSI (most USB 3 drives and SSD enclosures) froze UTM: the USB menu and every other part of the app stopped answering, and after UTM was ended the drive did not come back to macOS until it was replugged. When a device is released, usbredirhost cancels its transfers and waits for them to complete. libusb on macOS refused to cancel bulk stream transfers (LIBUSB_ERROR_INVALID_PARAM), and USB Attached SCSI always has one pending on its status pipe, so the wait never ended while it held the lock the main thread needs. Pick up c1c01e6593 from the UTM libusb fork (utmapp/libusb#1), which cancels bulk stream transfers the way plain bulk transfers are. The change is by giovariot, who included it in utmapp#7928. Assisted-by: Claude:claude-fable-5-2
6ee9f03 to
a2a098c
Compare
USB 3.2 Gen 2 (10 Gbps) devices were reported by libusb at a speed the usb-redir protocol cannot express, so QEMU attached them at full speed while forwarding their SuperSpeed descriptors. Guests rejected them with "Invalid ep0 maxpacket: 9" and "unable to enumerate USB device". - attach a device announced with an unknown speed at SuperSpeed when its endpoints show it is one (8ab298bc52 from the UTM QEMU fork) - apply QEMU's bMaxPacketSize0 fix-up whenever the device is not attached at SuperSpeed (e37b2e515d from the UTM QEMU fork) The two QEMU commits (utmapp/qemu#30) are a rework of the QEMU change first proposed here. They take the place of the usbredir patch that presented SuperSpeedPlus devices as SuperSpeed: QEMU now works that out itself, so usbredir stays unpatched. Resolves utmapp#7530 Assisted-by: OpenCode:deepseek-v4.1-flash Assisted-by: Claude:claude-fable-5-2
a2a098c to
5f951c8
Compare
|
@giovariot this PR was split up, so here is where each part went. The description above has the details, with the outdated parts struck out.
Why it was split: each PR is meant to be one change, and dependency patches go through UTM's forks of those projects first. You are the author of the commit here, of the commits in #8134 and #8133, and of the libusb commit. What changed in your code, in short:
Tested with a Seagate 500 GB and a Seagate 4 TB drive on a 5 Gb/s link; the results are in each PR. A real 10 Gbps device was not available, so the unknown-speed case was forced on a 5 Gb/s drive. If you can run this PR's branch with your ASM2362 enclosure, that would close the gap. |
A USB device set to "Auto connect on start" was only connected when the virtual machine started. When it was unplugged and plugged in again while the virtual machine ran, or restarted itself as a device does after a firmware update, UTM asked whether to connect it, or did nothing when the prompt is turned off or the window is not in front. Connect such a device when it appears, without asking. A device that another virtual machine has, or that this one has no room for, is left alone without an alert. The idea and a first version are from giovariot in #7928. Assisted-by: OpenCode:deepseek-v4.1-flash Assisted-by: Claude:claude-fable-5-2
Summary
QEMU USB passthrough fails for USB 3.2 Gen 2 (10 Gbps) devices — the external SSDs and NVMe enclosures that most users hit in #7530 — with the guest rejecting the device as
Invalid ep0 maxpacket: 9. This change fixes the speed negotiation that causes it~~, unmounts the host volumes of a mass storage device before it is redirected so macOS never loses a mounted disk, and reconnects a saved device automatically when it appears again (for example after a firmware update restarts it)~~.Resolves #7530, #2728, #3975, #3995, #5154, #6291, #6721 and #6764.
Root cause
UTM's QEMU passthrough does not hand the device to QEMU directly: it uses SPICE usb-redir with libusb running in the app process (CocoaSpice/usbredirhost). The entitlements are already in place (
com.apple.security.device.usb,com.apple.vm.device-access), so macOS can release the device from its kernel drivers; the failure is in the speed negotiation:LIBUSB_SPEED_SUPER_PLUS(kUSBDeviceSpeedSuperPlus).usbredirhost_send_device_connect(), so it sendsusb_redir_speed_unknown.hw/usb/redirect.c) while still forwarding the device's SuperSpeed descriptor, whosebMaxPacketSize0is 9 (the SuperSpeed encoding, 512 bytes).Invalid ep0 maxpacket: 9, thenunable to enumerate USB device.This matches the reports: USB 2.0 and USB 3.0 (5 Gbps) devices keep working, 10 Gbps SSDs and NVMe enclosures fail, and a USB 2.0 hub "fixes" it by forcing the host device to enumerate at high speed. The usb-redir protocol has no speed above SuperSpeed, so these devices are presented at 5 Gbps instead of 10 Gbps.
Changes
patches/usbredir-0.14.0.patch(new): presentLIBUSB_SPEED_SUPER_PLUSdevices as SuperSpeed, so the guest gets a link and descriptors that match.patches/qemu-10.0.12-utm.patch: the existingbMaxPacketSize0fix-up only ran when QEMU had marked the device as SuperSpeed. Run it whenever the device is presented at a non-SuperSpeed link, which also covers speeds libusb cannot report (for example 20 GbpskUSBDeviceSpeedSuperPlusBy2devices are reported as unknown speed).Services/UTMUSBDeviceUnmount.swift(new, macOS): before redirecting a device, unmount its mounted volumes with DiskArbitration so the capture does not tear the storage driver away from macOS with volumes still in use. If a volume is busy the connection is refused with a clear message instead of risking data loss. The helper also maps the "device still in use" errors from libusb to a message that tells the user what to do.Reconnect a saved device automatically (VMDisplayQemuDisplayController): a device in the saved auto-connect list is connected again without prompting when it is attached while the virtual machine is running. This covers devices that reset themselves, for example during a firmware update, and come back a few seconds later.Related issues
These issues are less specific or describe a different problem and are only possibly related: #3322, #3375, #4167, #5664, #7288.
Testing
I confirmed the report with a synthetic test: without access to the
com.apple.vm.device-accessentitlement a local build cannot capture the physical device (on macOS 27 the device is markedNeedsDeviceAccessEntitlement = Yes, so even root cannot), which makes a hardware test impossible. The tests were run on macOS 27.0, MacBook Air M4 (Apple Silicon).The reporter's ASM2362 enclosure (
174c:2362) was used to confirm the reported values:speed=5 (LIBUSB_SPEED_SUPER_PLUS),bcdUSB=0x0320,bMaxPacketSize0=9USBSpeed=5,UsbLinkSpeed=10000000000binary comparison of the pinned usbredirhost: the current one handles only speeds below 5 (soSUPER_PLUSfalls through to "unknown"); the patched one handles speeds below 6 and mapsSUPER_PLUStosuper.End-to-end in QEMU, with a synthetic usb-redir device that mirrors the SSD descriptors (
bcdUSB 0x0320,bMaxPacketSize0 = 9, mass storage interface) and an Alpine Linux guest on the serial console:unknownspeed)new high-speed USB device,Invalid ep0 maxpacket: 9,unable to enumerate USB devicepatched (superspeed)currentenumerates:new SuperSpeed USB device number 2,New USB device found, idVendor=174c, idProduct=2362current (unknownspeed)patchedenumerates:new high-speed USB device, descriptor accepted (the fix-up rewritesbMaxPacketSize0to 64)The physical device itself could not be captured on this machine (see above), and the automatic reconnection path also needs a device that resets while a virtual machine is running, which was not exercised here.
Testing: Tested by the author on macOS 27.0, MacBook Air M4 (Apple Silicon), assisted by the AI agent (DeepSeek V4.1 Flash via OpenCode) which set up and ran the diagnostics and the QEMU tests under the author's supervision. The author acknowledges that this change has been tested and/or reviewed by a human in accordance with UTM's AI contribution guidelines.
Update (by a maintainer's AI agent)
This PR now carries one commit, still authored by @giovariot, and only the QEMU part:
usb: fix SuperSpeedPlus passthrough. The rest was moved out so that each PR is one change (the parts struck out above):patches/usbredir-0.14.0.patch): removed. With the second QEMU commit below, QEMU works out by itself that a device of unknown speed is a SuperSpeed one, so usbredir stays unpatched.QEMU (
patches/qemu-10.0.12-utm.patch): e37b2e515d and 8ab298bc52 from the UTM QEMU fork (utmapp/qemu#30), a rework of the QEMU patch first proposed here.bMaxPacketSize0fix-up did not "only run when QEMU had marked the device as SuperSpeed" (struck out above): sinceusb_pick_speed()(2014) it never ran at all, because the speed of an attached device is the one it runs at on its port. A SuperSpeed device on a USB 2.0 controller failed the same way as a SuperSpeedPlus device. The fix-up now runs whenever the device is not attached at SuperSpeed.uas_eh_abort_handler,Device offlined - not ready after error recovery). The row "current usbredir, patched QEMU" of the table above showed enumeration only.Tests of the versions that are now in the branch, by an AI agent on a MacBook Pro M2 Max, macOS 27.2, with a Seagate Backup Plus 500 GB drive (0bc2:ab24, USB Attached SCSI) on a 5 Gb/s link and an Ubuntu 26.04 arm64 guest. Only reads were done. The UTM builds used carry the QEMU patches of this PR and the libusb patch of #8131:
Invalid ep0 maxpacket: 9,unable to enumerate USB deviceDriver=uas, 480M); the disk does not appear, for the reason aboveDriver=uas, 480M, no disknew SuperSpeed USB device,Driver=uas, 5000M, the disk appears, 1000 MiB read at 105 MB/sWith the libusb patch, disconnecting the drive returns within a second, also during a read, and the drive comes back to macOS when the VM stops. Without it (UTM 5.0.8), disconnecting freezes UTM.
Not tested: a real SuperSpeedPlus (10 Gbps) device; the unknown speed was forced on a 5 Gb/s drive. The tests in the Testing section and in the comments were made with the first versions of the patches.