diff --git a/FABRIC-3.md b/FABRIC-3.md index 0686ffb..2d4eb21 100644 --- a/FABRIC-3.md +++ b/FABRIC-3.md @@ -3333,10 +3333,11 @@ failed"` gate, now with an else-branch for the recoverable-STALL case. is deferred to hardware (v2.5.0/Artemis bare-metal)**, where a real bad transfer can be staged. This is the last QEMU-verifiable storage-integrity gap and the recovery logic is in place; the one thing QEMU cannot prove is the live stall injection itself. -- **Note (pre-existing, NOT G.1):** during verification an intermittent boot-time attach race - was observed (the `sk_repl_idle()` `bot_msc_attach_pending` handoff occasionally does not - progress on a cold QEMU boot, independent of source, with baseline `HEAD` exhibiting it too). - Unrelated to G.1; tracked for a separate follow-up. +- **Follow-up (pre-existing, NOT G.1): ROOT-CAUSED and FIXED 2026-08-29 — see §G.4 below.** + During G.1 verification an intermittent boot-time attach race was observed (the + `sk_repl_idle()` `bot_msc_attach_pending` handoff occasionally does not progress on a cold + QEMU boot, independent of source, with baseline `HEAD` exhibiting it too). Unrelated to G.1; + root cause and fix are documented in §G.4, verified across six consecutive fresh boots. #### G.2 [v2.0.0] Real-hardware RNG driver plumbing, QEMU-verifiable slice (rest of it lands at v2.5.0) diff --git a/capsules/BLOCK_MAP.md b/capsules/BLOCK_MAP.md index 5d56475..c7b2736 100644 --- a/capsules/BLOCK_MAP.md +++ b/capsules/BLOCK_MAP.md @@ -1,5 +1,5 @@ # Capsule Block Manifest — Auto-generated - + diff --git a/disk/artemis.img b/disk/artemis.img index 142cc9d..8af565f 100644 Binary files a/disk/artemis.img and b/disk/artemis.img differ diff --git a/include/starkernel/xhci.h b/include/starkernel/xhci.h index 13e2e89..76da344 100644 --- a/include/starkernel/xhci.h +++ b/include/starkernel/xhci.h @@ -486,6 +486,26 @@ typedef struct { #define XHCI_RING_TRB_COUNT 256u #define XHCI_RING_BYTES (XHCI_RING_TRB_COUNT * sizeof(xhci_trb_t)) +/* Bounded per-call event-ring drain (Milestone 2h boot-attach hardening). + * xhci_poll_events()'s drain loop is otherwise terminated only by the + * ring's cycle-bit match, which is a fine early-exit on the normal, + * quiescent path (each beat drains the one-or-few events the controller + * posts per chained command) but has no hard ceiling. If the controller + * keeps producing events across the whole drain -- ERDP is not written + * back until the loop exits, so the controller cannot reclaim event TRBs + * mid-drain, and on pathological controller behavior the head can chase + * the software dequeue pointer indefinitely -- the loop can livelock: + * xhci_poll_events() never returns, sk_repl_idle() never reaches its + * bot_msc_attach_pending check, and a fresh USB BOT device that finished + * SET_CONFIGURATION is left flagged-but-never-attached while the guest, + * though alive, appears hung. Bounding the drain makes xhci_poll_events() + * always terminate and always write ERDP each call; any events not yet + * processed keep their cycle bit and are simply re-read on the next poll, + * so nothing is dropped. Equal to a full ring: on the healthy path one + * drain never processes anywhere near this many events, so this bound + * only ever triggers in the pathological case it exists to break. */ +#define XHCI_EVT_RING_MAX_DRAIN XHCI_RING_TRB_COUNT + /* Milestone 2e: upper bound on ports tracked for connect/disconnect -> * Enable Slot correlation (xhci_dev_t.port_slot_id). PORTSC's own field * width allows up to 255 ports (XHCI_HCSPARAMS1_MAX_PORTS is 8 bits), but diff --git a/src/starkernel/usb/xhci.c b/src/starkernel/usb/xhci.c index 3386278..6238e30 100644 --- a/src/starkernel/usb/xhci.c +++ b/src/starkernel/usb/xhci.c @@ -1480,8 +1480,10 @@ void xhci_poll_events(void) xhci_dev_t *dev = g_xhci_dev; if (!dev) return; - while (((dev->evt_ring[dev->evt_ring_deq].control & XHCI_TRB_CONTROL_CYCLE) != 0) - == (dev->evt_ring_cycle != 0)) { + uint32_t evt_processed = 0; + while (evt_processed < XHCI_EVT_RING_MAX_DRAIN && + ((dev->evt_ring[dev->evt_ring_deq].control & XHCI_TRB_CONTROL_CYCLE) != 0) + == (dev->evt_ring_cycle != 0)) { xhci_trb_t *trb = &dev->evt_ring[dev->evt_ring_deq]; uint32_t type = XHCI_TRB_TYPE(trb->control); @@ -2060,6 +2062,7 @@ void xhci_poll_events(void) dev->evt_ring_deq = 0; dev->evt_ring_cycle ^= 1u; } + evt_processed++; } /* Event Ring dequeue-pointer update (xHCI 1.2 spec §4.9.4): write the