Repository navigation
Internal USB driver binding, hot-plug and unplug - #3262
Closed
valentinbreiz wants to merge 4 commits into
Closed
valentinbreiz wants to merge 4 commits into
valentinbreiz wants to merge 4 commits into
Conversation
A device published by a USB driver leaves when it is pulled out, so the managers gain the paths that let it go: - MouseManager keeps its mice in a copy-on-write array; UnregisterMouse disables the mouse, clears its handler and releases held buttons. - NetworkManager.UnregisterDevice compacts the table with interrupts masked, moves the primary to the first remaining device, and purges the device's address map, MAC map and IPConfig entries. - IPConfig publishes an array it replaces whole, so a thread walking it while a device leaves never sees the collection change under it. - NetworkAdapter carries a generation stamp instead of the index, so a handle never names a device that later takes its slot.
…em on unplug The internal UsbDriver becomes UsbClassDriver, and UsbEndpointType and UsbTransferStatus move unchanged into Cosmos.Kernel.HAL.Drivers.Usb, next to the seam: UsbDriver, UsbDriverRegistration, UsbMatch and UsbDeviceContext (control transfers, interrupt IN and bulk pipes). DriverCore registers USB drivers in the same name space as PCI ones. The pass offers every interface no built-in bound, most specific match first; KitUsbDriver, last in UsbManager's list, does the same for devices plugged in later, so built-ins keep the first pick. - Reports reach a driver only after Bound, through an armed trampoline. - An attempt that opened a pipe ends the offering of its interface: xHCI cannot close a pipe. - On unplug, before the controller frees the device: the handlers are disarmed, the published mouse and link withdrawn through sinks System installs, work items and events cancelled, then Remove runs. The device list gains one record per USB interface, rebuilt after every enumeration and disconnect. xHCI reports how many bytes a control transfer moved. Every type stays internal in its final shape until the seam opens.
The test runner can now unplug and replug one device of a profile's "usb" list (usb-device-unplug/usb-device-plug n) and move a USB mouse (usb-pointer-move n dx dy [buttons]). Each such device gets the QEMU id usbdev<n>; mouse_set routes the input, because input-send-event with a USB device id aborts QEMU 10.2.2. The usb-mouse profile becomes usb-hid (mouse, tablet, keyboard). Per cell, the suite checks: - USB registration rules, ranking and fall-through after a decline; - the boot-mouse bind, ControlIn, reports only after Bound, and a real pointer move through the driver; - no fall-through once a failed attempt opened the tablet's endpoint; - unplug: Remove after withdrawal, the mouse and a published link leaving their managers, Disconnected transfers, cancelled work; - replug: a new driver instance binds on the hot-plug thread; - the built-in keyboard keeping its interface, and the device list. System grants the suite temporary internals access, as HAL does.
🧪 Drivers Tests
Skipped
📎 Artifacts
|
🧪 Graphic Tests
Skipped
📎 Artifacts
|
🧪 Storage Tests
Skipped
📎 Artifacts
|
🧪 Interrupts Tests
Skipped
📎 Artifacts
|
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #3260 (base
feature/driver-kit-engine), which sits on #3259, #3258 and #3257. Retarget it togen3once those merge.This is the fifth step towards letting a user kernel register its own PCI and USB drivers. It adds USB binding to the driver engine from #3260: a registered USB class driver is offered every interface the built-in drivers left, both at boot and when a device is plugged in later. When the device is pulled out, its binding is torn down.
Everything stays internal. Each type already has its final name, namespace and signature, so the PR that opens the seam only needs to make them public and mark them experimental (COSMOS0003). There is no public API change and no
PublicAPI.*.txtchange.Problem
UsbManageroffers each interface to a hard-coded list (hub, keyboard, mass storage). A kernel has no registration point, and nothing hands a driver a USB interface, its endpoints or its control pipe.UsbDriver,UsbEndpointTypeandUsbTransferStatushave the names the seam needs, so both sets could not coexist in HAL without CS0104 errors.Disconnect. Nothing withdraws a mouse or a network link from System's managers:MouseManagerandNetworkManageronly ever register.NetworkAdaptercarried the registration index. Once a device leaves and another takes its slot, an old handle names the new device.Fix
Renames (no behaviour change):
UsbDriverbecomesUsbClassDriver.UsbEndpointTypeandUsbTransferStatusmove unchanged intoCosmos.Kernel.HAL.Drivers.Usb.Seam (
Cosmos.Kernel.HAL.Drivers.Usb, internal):UsbDriver(Probe, andRemovefor unplug),UsbDriverRegistrationandUsbMatch.UsbDeviceContext:ControlInandControlOut, in thread context;OpenInterruptInandTryOpenBulk;UsbTransferResult.Lengthreports the bytes the transfer actually moved.UsbDeviceInfo,UsbInterfaceInfo,UsbEndpointInfo,UsbBulkPipe,UsbReportHandler,UsbDirection,UsbRequestKindandUsbRecipient.Registration and binding (
DriverCore,KitUsbDriver):DriverCore.Register(UsbDriverRegistration)follows the PCI rules.Device(v,p)>Interface(c,s,p)>(c,s)>(c); ties go to the earlier registration.[Drivers] usb/1-5:1.0 -> usb-boot-mouse (interface match).usb/<bus>-<root port>[.<hub port>...]:<config>.<interface>.KitUsbDriveris the last class driver inUsbManager's list, after the hub, keyboard and mass-storage built-ins, so built-ins keep first pick of every device, at boot and on hot-plug.UsbManager's log names the registration that bound an interface.OpenInterruptInwraps the handler in a trampoline that stays disarmed untilBound. A report that arrives beforeBound, after a failed attempt, or after unplug is dropped, never buffered. The report path does not allocate or take locks.Unplug (
DriverCore.RemoveUsbBinding). This runs on the hot-plug thread, beforeReleaseDevicefrees the pipes:IsPresentturns false, and the report trampolines are disarmed.DriverWorkQueue.IsRunningItemOf), and logs an overrun.Removeruns insidetry, with the re-entrancy guard set.Removed.After unplug, transfers return
Disconnected.System:
MouseManagerkeeps its mice in a copy-on-write array.UnregisterMousedisables the mouse, clears its handler and releases the buttons it may have held.NetworkManager.UnregisterDevice:IPConfigentries.IPConfignow publishes an array it replaces whole, so a thread walking it while a device leaves no longer throws "Collection was modified".PublishedNetworkDevicechecks for withdrawal again with interrupts masked. A send or delivery that was preempted just before the unplug then never reaches the driver or the stack afterwards.NetworkAdaptercarries a generation stamp instead of the index. A handle names only the device it was taken for, andIsValidturns false once that device leaves. The public signatures are unchanged;EqualsandGetHashCodenow use the stamp.Device list.
DriverCore.Devicesnow lists every USB interface after the PCI functions: path, owner (a built-in's name, a registration's name, or none), vendor and product IDs, and class triple. The hot-plug thread rebuilds it after every enumeration and every disconnect.Host controller. One generic change: xHCI now reports how many bytes a device-to-host control transfer moved (Interrupt-on-Short-Packet on the data stage, the way Linux does it). Built-in callers are unchanged.
Test runner:
"usb"list gets the QEMU idusbdev<n>. The USB stick, drive and controller ids are unchanged.TR:usb-device-unplug nandusb-device-plug n;usb-pointer-move n dx dy [buttons], which moves one USB mouse.input-send-eventnames a USB device (Property 'qemu-fixed-text-console.device' not found). The runner therefore selects the mouse withmouse_setand sends the events without a device."usb"device now also gets a QMP monitor.usb-tabletjoins the"usb"allow-list.usb-mouseprofile becomesusb-hid, withusb-mouse,usb-tabletandusb-kbd.Verification
Build.
make setupgives 0 errors, and no warning falls on a line this PR adds or changes.Host tests.
Cosmos.Tests.Patcher188 / 0 failed. This includes 50 new tests: the request parsing, the exact QMP JSON against a fake QEMU monitor, and the ids.Cosmos.Tests.Tools37 / 0.Cosmos.Kernel.Tests.System208 / 0.QEMU arguments. I compared old and new argument lines for all 166 combinations of suite, arch, profile and modifier. The 158 that don't use a
"usb"list are byte-identical, including every Storage USB-stick cell. The 8 Driversusb-hidlines differ only by the added device ids and the QMP monitor.Drivers suite. 80 tests per cell (47 before), final run:
The new
usb-hidcells check:Registerafter the pass or from a USB driver's callback.ControlInreads the 18-byte device descriptor (0627:0001); members that are Probe-only throw after Probe; endpoints of another interface are refused; the published mouse reachesMouseManager.Bound: the test driver requests 4 ms idle reports during Probe, and none reaches its handler beforeBound.[Drivers] usb/1-6:1.0 -> no driver: usb-tablet-fails opened an endpoint, which cannot be closed, so no other driver is offered the interface.usb-pointer-move 0 12 7 1moves the pointer by exactly (12, 7) with the left button held. The driver's own running sums show the movement came through it, not through x64's PS/2 mouse.Removeruns once, after the withdrawal;MouseManagerwith its button released;Disconnected;NetworkManagerand the primary is fixed (the link is primary on arm64 bare and gicv2);NetworkAdapterdoes not name the next link that takes its slot.Each rule was checked by breaking it. The implementers and the fixer removed or changed, one at a time:
IsPresent;Remove;UnregisterMouse;IPConfigarray, the button release.Each time, the cells written for it failed, and no unrelated cell did.
Other suites, QEMU. Same totals as #3260, test by test:
GC_InteriorPointerRootas it does on Internal driver engine and PCI driver binding #3260. Fix the GC freeing objects rooted only by an interior pointer #3261 fixed it ongen3, and this stack picks the fix up when it is rebased.USB off. A HelloWorld kernel with Keyboard and Storage off, so USB is off by the SDK's cascade, still passes 3/3 on x64 and arm64. Its image holds no symbol of
KitUsbDriver, the USB seam, the trampoline,UsbManageror the engine's USB paths; with USB on, the same kernel holds about 60.Real hardware. The runs above are QEMU only. A USB mouse on a real xHCI still needs checking.
Known gaps.
IPConfigcleanup are checked.NetworkManagerstill has 8 fixed slots, and a 9th device is dropped silently. This predates this PR; hot-plug reuses the freed slots.InternalsVisibleTogrants from HAL, Core and System. The PR that opens the seam removes them.QemuLauncher.UsbDeviceIdnow returns the"usb"list id (usbdev<n>). The stick id moved toUsbStickId, and every in-tree caller is updated.Found here but not changed:
UsbBulkOnlyTransport.Openleaves bulk IN open when opening bulk OUT fails, and the interface then goes to the next driver. It is harmless today only because xHCI accepts reopening an endpoint.ProfileCatalogTests.DriversSuiteCoversTheGicVersionsItsCellsNeedwas missing Internal driver engine and PCI driver binding #3260'snvmecell, which is why Internal driver engine and PCI driver binding #3260's host tests are red. This PR's version of that line includes it.