G.1: xHCI bulk-endpoint stall recovery (per F.14), built + verified
Full BOT-spec stall recovery per FABRIC-3.md F.14: new STALL_ERROR handling, Reset Endpoint + Set TR Dequeue Pointer commands, CLEAR_FEATURE(ENDPOINT_HALT), escalating to Bulk-Only Mass Storage Reset, capped retries (XHCI_BOT_STALL_MAX_RECOVERIES=2) mirroring bot_tur_retries, clean terminal failure via xhci_stall_fail(). Purely additive recovery path off the non-success transfer-event branch; the normal path is unchanged. Builds clean on amd64/aarch64/riscv64. QEMU amd64 boot regression passes: zero stalls, BOT attach (READ CAPACITY10 -> READ10 -> home-blocks) completes, normal-path xHCI trace identical to baseline. Live stall injection is not provable under qemu-xhci; deferred to v2.5.0 hardware. FABRIC-3.md G.1 documented; ROADMAP release-versioning policy folded in.
This commit is contained in:
+162
@@ -3264,3 +3264,165 @@ of the pump's own cadence), `USE bob` and `WELCOME` both still work correctly. F
|
|||||||
three-architecture regression clean (amd64 fresh Zuse reload + the fix compiled in; aarch64/
|
three-architecture regression clean (amd64 fresh Zuse reload + the fix compiled in; aarch64/
|
||||||
riscv64 clean Zuse reload, unaffected — the fix only touches content written at `MINT` time, no
|
riscv64 clean Zuse reload, unaffected — the fix only touches content written at `MINT` time, no
|
||||||
change to the boot path itself).
|
change to the boot path itself).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## G. v2.0.0 / v2.5.0 RELEASE plan — recommendation and punch lists (2026-08-28)
|
||||||
|
|
||||||
|
**Context.** This is the continuation section of record for the release decision. Opening it
|
||||||
|
as its own lettered section (§G) so it stands apart from the carried-forward item review
|
||||||
|
(§A), the design-scope sections (§B–§E), and the built-and-verified backlog (§F). Everything
|
||||||
|
before this section describes work already committed to `origin/master` (`5689c39` and
|
||||||
|
earlier). This section records the **versioning split** (v2.0.0 = QEMU, v2.5.0 = real
|
||||||
|
hardware), the **release-gate recommendation**, and the **punch lists to completion** for
|
||||||
|
each.
|
||||||
|
|
||||||
|
**The versioning split, decided 2026-08-28 — now standing policy, see
|
||||||
|
`docs/lithosananke/ROADMAP.md` "Release Versioning Policy" for the authoritative form.**
|
||||||
|
v2.0.0 is the **QEMU release** — the point
|
||||||
|
where the QEMU-only story is complete and defensible on its own terms. v2.5.0 is the
|
||||||
|
**real-hardware release** — the point where the same story transfers to bare metal on a real
|
||||||
|
board. This is one instance of a general policy: **`X.0.0` = QEMU release, `X.5.0` =
|
||||||
|
hardware bare-metal release, even major numbers are LTS.** The rationale for the split is
|
||||||
|
practical, not arbitrary: v2.0.0
|
||||||
|
is the natural, honest cut for what exists *today and is fully verifiable today* (three-arch
|
||||||
|
QEMU), and v2.5.0 bundles the real-hardware-only work (per-arch RNG drivers, real-board boot
|
||||||
|
validation) that cannot be green-lit or verified until the boards physically exist (the
|
||||||
|
author expects to have money for the SBCs — RasPi 6, Milk-V — within about a month of the
|
||||||
|
v2.0.0 cut). Nothing
|
||||||
|
is deferred that QEMU alone could already prove out; only what genuinely needs real silicon.
|
||||||
|
|
||||||
|
Everything about the state being shipped by v2.0.0 is unchanged by this versioning: the
|
||||||
|
current tree is a complete, deterministic, three-architecture OS that boots UEFI under QEMU
|
||||||
|
(M0–M9 core milestones complete, M7.1 Capsules live, M9 Block I/O live, terminal/REPL I/O
|
||||||
|
wired, real virtio-blk persistence proven, a working first-boot Zuse mint via the block
|
||||||
|
fence).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### v2.0.0 (QEMU) — release gates
|
||||||
|
|
||||||
|
The v2.0.0 punch list is the set of items that must be green on QEMU (all three of
|
||||||
|
amd64/aarch64/riscv64) before the QEMU story is complete. Each item states its own exit
|
||||||
|
criterion so closure is unambiguous and independently verifiable, per this project's
|
||||||
|
standing discipline.
|
||||||
|
|
||||||
|
#### G.1 [v2.0.0] Stall/short-packet recovery for xHCI (scoped §F.14 — **BUILT 2026-08-29**)
|
||||||
|
|
||||||
|
Implemented per §F.14 exactly as designed: new `STALL_ERROR` completion code handling, xHCI
|
||||||
|
Reset Endpoint + Set TR Dequeue Pointer commands, `CLEAR_FEATURE(ENDPOINT_HALT)`, escalating
|
||||||
|
to a full Bulk-Only Mass Storage Reset, and a recovery counter (`XHCI_BOT_STALL_MAX_RECOVERIES
|
||||||
|
= 2`) mirroring `bot_tur_retries`.
|
||||||
|
|
||||||
|
The code is a purely additive recovery path gated off the *non-success* transfer-event branch
|
||||||
|
(`xhci.c` transfer-event gate + `xhci_handle_bulk_stall()`, the two new command-completion
|
||||||
|
states `XHCI_CONN_AWAIT_RESET_ENDPOINT`/`AWAIT_SET_TR_DEQUEUE`, the two new transfer purposes
|
||||||
|
`XHCI_XFER_CLEAR_HALT`/`XHCI_XFER_BOT_RESET`, and the two new deferred `next_action` values
|
||||||
|
`XHCI_NEXT_ACTION_CLEAR_HALT`/`XHCI_NEXT_ACTION_BOT_RESET`). The normal (non-stall) path is
|
||||||
|
byte-for-byte unchanged — the only touched shared line was the single `"control transfer
|
||||||
|
failed"` gate, now with an else-branch for the recoverable-STALL case.
|
||||||
|
|
||||||
|
- **Built clean on all three archs** — `make -f Makefile.starkernel ARCH={amd64,aarch64,riscv64} all`.
|
||||||
|
- **QEMU amd64 boot regression:** clean enumeration + BOT attach (READ CAPACITY10 → READ10 →
|
||||||
|
home-blocks) completing with **zero stalls and zero failures**; normal-path xHCI trace
|
||||||
|
identical to the pre-change baseline. Repeated across fresh boots (all attach=SUCCESS).
|
||||||
|
- **Exit criterion — partial, honest:** the recovery path itself is not exercised live because
|
||||||
|
QEMU's `qemu-xhci` model does not produce a `STALL_ERROR` for the injected bad transfers this
|
||||||
|
driver can stage (no real hardware stall behavior). The design (§F.14) is reviewed and the
|
||||||
|
code paths are structured and reviewed; **live `STALL_ERROR` → recover → retry verification
|
||||||
|
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.
|
||||||
|
|
||||||
|
#### G.2 [v2.0.0] Real-hardware RNG driver plumbing, QEMU-verifiable slice (rest of it lands at v2.5.0)
|
||||||
|
|
||||||
|
The full real per-arch RNG driver (`rng_get_bytes()` backing off virtio-rng to RDRAND /
|
||||||
|
Zkr / peripheral-RNG) is a v2.5.0 item because it cannot be verified on hardware that does
|
||||||
|
not exist yet. What *is* a v2.0.0 gate is the *shape* of the driver — the unified
|
||||||
|
`rng_get_bytes()` entry point, the probe-and-refuse-loudly contract (never silently
|
||||||
|
degrading to a deterministic seed — the exact failure Phase A existed to avoid), and the
|
||||||
|
QEMU path staying on virtio-rng unchanged — all taken up **before** v2.0.0 so the
|
||||||
|
single entropy entry point is stable and the v2.5.0 work is purely per-arch backends, not a
|
||||||
|
redesign of the call path.
|
||||||
|
|
||||||
|
- **Exit criterion (v2.0.0 slice):** `rng_get_bytes()` exists as the single entropy entry
|
||||||
|
point, virtio-rng is its sole active backend on all three QEMU arches, the code refuses
|
||||||
|
loudly (boot-time message, safe fallback to this-boot-only cert) if no backend is present,
|
||||||
|
and the pre-existing Zuse mint/cert behavior is unchanged on all three arches. The
|
||||||
|
per-arch backends themselves are parked, explicitly, for v2.5.0.
|
||||||
|
- **Exit criterion (v2.5.0 completion, for reference):** on each real board `rng_get_bytes()`
|
||||||
|
returns genuinely non-deterministic bytes (two boots differ) and the Zuse mint path seeded
|
||||||
|
from it produces a valid distinct cert per boot when bleached.
|
||||||
|
|
||||||
|
#### G.3 [v2.0.0] NVRAM persistence decision — **DECIDED 2026-08-28: permanently de-scoped**
|
||||||
|
|
||||||
|
The NVRAM `SetVariable` crash is root-caused (this kernel's VMM never maps the flash-window
|
||||||
|
region OVMF's variable service needs; also the exposed-seed design defect) and, since the
|
||||||
|
Zuse cert now lives on the block fence on Artemis, functionally superseded. **DECIDED
|
||||||
|
(Captain Bob, 2026-08-28): de-scope NVRAM-backed identity permanently.** The block fence on
|
||||||
|
Artemis is the substrate of record for Zuse's cert. The alternative — scoping the real VMM
|
||||||
|
memory-map work to make OVMF's flash window writable — is not being scheduled: it is large,
|
||||||
|
unscoped VMM work with no live consumer now that the fence carries the cert, and the NVRAM
|
||||||
|
approach carried a real exposed-seed security defect regardless of the crash.
|
||||||
|
|
||||||
|
- **Exit criterion (MET):** a dated decision recorded in this section (de-scope), and the
|
||||||
|
ROADMAP/backlog updated to match. Decision required, not necessarily work — **closed,
|
||||||
|
no work required beyond this record.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### v2.5.0 (real hardware) — release gates
|
||||||
|
|
||||||
|
These are the real-hardware-only items. None can be verified until the boards exist (RasPi 6,
|
||||||
|
Milk-V; SER5 either in hand or not — see G.5). They are the entire v2.5.0 gate and are listed
|
||||||
|
together so the v2.5.0 scope is explicit and closed.
|
||||||
|
|
||||||
|
#### G.4 [v2.5.0] Per-arch RNG backends behind `rng_get_bytes()` (the G.2 body)
|
||||||
|
|
||||||
|
The real RNG driver backends, completed behind the v2.0.0-formed entry point. The existing
|
||||||
|
VM-UUID finding already maps the primitives: amd64/SER5 RDRAND, riscv64/Milk-V Zkr (RNDR),
|
||||||
|
aarch64/RasPi peripheral RNG. On QEMU all three arches stay on virtio-rng; nothing changes
|
||||||
|
there.
|
||||||
|
|
||||||
|
- **Exit criterion:** on each real board (`rng_get_bytes()` falling back through the real
|
||||||
|
primitive) returns genuinely non-deterministic bytes (two boots differ), the Zuse mint
|
||||||
|
path seeded from it produces a valid distinct cert per boot when bleached, and QEMU
|
||||||
|
behavior is unchanged.
|
||||||
|
|
||||||
|
#### G.5 [v2.5.0] Real-machine boot validation (SER5 / RasPi 6 / Milk-V)
|
||||||
|
|
||||||
|
Flash `starkernel.iso` to real media and boot each real board in hand, confirming the same
|
||||||
|
acceptance story QEMU keeps green: POST `1012/0/0` + `ok>`, block-fence Zuse load true to the
|
||||||
|
already-minted Artemis image, and the G.4 RNG backend working live. The board pool is
|
||||||
|
SER5 (if still in hand), RasPi 6 (aarch64), Milk-V (riscv64) — the goal is at least one
|
||||||
|
board per architecture, but each board that boots is a separate, recorded data point.
|
||||||
|
This is the genuine transfer proof that the zero-degradation QEMU claim holds on real
|
||||||
|
silicon — the thing v2.0.0 cannot honestly claim.
|
||||||
|
|
||||||
|
- **Exit criterion:** each board in hand cold-boots to `ok>` with Arena conservation
|
||||||
|
(43691/21845/65536), Zuse cert loads from the fence (or mints fresh on bleached media),
|
||||||
|
and its G.4 RNG backend returns non-deterministic bytes live. v2.5.0 does not close on any
|
||||||
|
board's G.4/G.x item being build-only.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Post-release tracking (not gating either milestone)
|
||||||
|
|
||||||
|
Beyond the v2.0.0/v2.5.0 gates, the carried-forward open items (§A) and open design questions
|
||||||
|
(§D) remain genuinely open. Not release-gating; tracked here so nothing silently ages and so
|
||||||
|
the punch lists above explicitly delimit what is excluded from each milestone:
|
||||||
|
|
||||||
|
- Block-map on-drive format field edit (scoped §F.4) and associated §F.6/§F.11 allocation.
|
||||||
|
- CA-signed-cert verification path + DER signature extraction (scoped §F.7) and
|
||||||
|
`CERTVERIFY`/`BINDSTEP` consumers (§F.8/§F.9).
|
||||||
|
- Migration state machine design (§A item, §B Stadium unification reframe).
|
||||||
|
- Console umbrella closure (§A 4.3) and `(user)` prompt segment (§A 4.4s) once 4.3's blocker
|
||||||
|
clears.
|
||||||
|
- `DETACH`/unclean-removal wiring into `sk_repl_idle()` (scoped §F.10).
|
||||||
|
- Dirty-event granularity (1.11, blocked on 4.3) and the §17.4 framebuffer heat/decay design.
|
||||||
|
- Re-run the DoE on the new substrate (§A 5.1).
|
||||||
|
- First-touch allocation first-call-free.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Capsule Block Manifest — Auto-generated
|
# Capsule Block Manifest — Auto-generated
|
||||||
<!-- Generated by mkcapsule --manifest 2026-08-29T02:41:11Z -->
|
<!-- Generated by mkcapsule --manifest 2026-08-29T04:57:27Z -->
|
||||||
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
||||||
<!-- Hand-written justifications and immutability notes live -->
|
<!-- Hand-written justifications and immutability notes live -->
|
||||||
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
||||||
|
|||||||
Binary file not shown.
@@ -7,6 +7,31 @@ longer exists here — see `.claude/CLAUDE.md`'s "On the branch topology" note)
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Release Versioning Policy (decided 2026-08-28)
|
||||||
|
|
||||||
|
This is the standing release-versioning policy for LithosAnanke. It is authoritative; the
|
||||||
|
FABRIC documents track implementation against it, and any permanent change to the policy
|
||||||
|
belongs here.
|
||||||
|
|
||||||
|
- **`X.0.0` — QEMU release.** A whole-number minor in the `X.0` position is the QEMU-only
|
||||||
|
release: the point where the three-architecture (amd64/aarch64/riscv64) story under QEMU
|
||||||
|
is complete and defensible on its own terms. Nothing real-hardware-only is required to cut
|
||||||
|
an `X.0.0`.
|
||||||
|
- **`X.5.0` — Hardware bare-metal release.** A `X.5` release is the real-hardware release:
|
||||||
|
the point where the same story transfers to bare metal on real boards (SER5, RasPi 6,
|
||||||
|
Milk-V, Zynq FPGA). Real-hardware-only work — the per-arch RNG drivers behind the unified
|
||||||
|
entropy entry point, and real-board boot validation — gates `X.5.0`, not `X.0.0`.
|
||||||
|
- **Even major numbers are LTS.** A release whose major number (`X`) is even is a
|
||||||
|
Long-Term-Support release — maintained and supported long-term (bug fixes, security,
|
||||||
|
backports) rather than a point-in-time cut. Odd major numbers are non-LTS development
|
||||||
|
lines.
|
||||||
|
|
||||||
|
Applied to the two planned releases: the **v2.0.0** cut (even major, so LTS) is the QEMU
|
||||||
|
release; **v2.5.0** is the hardware bare-metal release that transfers v2.0.0's QEMU story to
|
||||||
|
real boards. See `FABRIC-3.md` §G for the release-gate punch lists.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Milestone Overview
|
## Milestone Overview
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -196,6 +196,8 @@ typedef struct {
|
|||||||
#define XHCI_TRB_TYPE_DISABLE_SLOT_CMD 10
|
#define XHCI_TRB_TYPE_DISABLE_SLOT_CMD 10
|
||||||
#define XHCI_TRB_TYPE_ADDRESS_DEVICE_CMD 11
|
#define XHCI_TRB_TYPE_ADDRESS_DEVICE_CMD 11
|
||||||
#define XHCI_TRB_TYPE_CONFIGURE_ENDPOINT_CMD 12
|
#define XHCI_TRB_TYPE_CONFIGURE_ENDPOINT_CMD 12
|
||||||
|
#define XHCI_TRB_TYPE_RESET_ENDPOINT_CMD 14
|
||||||
|
#define XHCI_TRB_TYPE_SET_TR_DEQUEUE_POINTER_CMD 16
|
||||||
#define XHCI_TRB_TYPE_SETUP_STAGE 2 /* Transfer Ring, control transfers only */
|
#define XHCI_TRB_TYPE_SETUP_STAGE 2 /* Transfer Ring, control transfers only */
|
||||||
#define XHCI_TRB_TYPE_DATA_STAGE 3
|
#define XHCI_TRB_TYPE_DATA_STAGE 3
|
||||||
#define XHCI_TRB_TYPE_STATUS_STAGE 4
|
#define XHCI_TRB_TYPE_STATUS_STAGE 4
|
||||||
@@ -234,11 +236,32 @@ typedef struct {
|
|||||||
|
|
||||||
#define USB_REQ_GET_DESCRIPTOR 6u
|
#define USB_REQ_GET_DESCRIPTOR 6u
|
||||||
#define USB_REQ_SET_CONFIGURATION 9u
|
#define USB_REQ_SET_CONFIGURATION 9u
|
||||||
|
#define USB_REQ_CLEAR_FEATURE 1u
|
||||||
#define USB_DESC_TYPE_DEVICE 1u
|
#define USB_DESC_TYPE_DEVICE 1u
|
||||||
#define USB_DESC_TYPE_CONFIG 2u
|
#define USB_DESC_TYPE_CONFIG 2u
|
||||||
#define USB_DIR_DEVICE_TO_HOST 0x80u
|
#define USB_DIR_DEVICE_TO_HOST 0x80u
|
||||||
#define USB_DIR_HOST_TO_DEVICE 0x00u
|
#define USB_DIR_HOST_TO_DEVICE 0x00u
|
||||||
|
|
||||||
|
/* Standard USB Device/Endpoint feature selectors (USB 2.0 spec table 9-6) --
|
||||||
|
* ENDPOINT_HALT (0) is the halt condition on a specific endpoint, cleared
|
||||||
|
* (and the endpoint's data toggle reset) by a CLEAR_FEATURE request whose
|
||||||
|
* wValue is this selector and whose wIndex is the endpoint's own address --
|
||||||
|
* the USB-level half of G.1's stall recovery (xHCI Reset Endpoint +
|
||||||
|
* SET_TR_DEQUEUE_POINTER clear the xHC-side state; this clears the device-
|
||||||
|
* side halt so the endpoint will actually drive new transfers again).
|
||||||
|
* bmRequestType type field (bits 6:5 of the request type) -- 0 = standard,
|
||||||
|
* 1 = class, and the recipient field (bits 4:0) -- 0 = device, 2 = endpoint.
|
||||||
|
* BOT Mass Storage Reset (USB Mass Storage Class Bulk-Only Transport spec
|
||||||
|
* section 3.1) is a class, interface-recipient (recipient 1) request, the
|
||||||
|
* BOT-spec-mandated full teardown + restart of a stalled command sequence. */
|
||||||
|
#define USB_REQ_TYPE_STANDARD 0u
|
||||||
|
#define USB_REQ_TYPE_CLASS 1u
|
||||||
|
#define USB_RECIP_DEVICE 0u
|
||||||
|
#define USB_RECIP_INTERFACE 1u
|
||||||
|
#define USB_RECIP_ENDPOINT 2u
|
||||||
|
#define USB_FEATURE_ENDPOINT_HALT 0u
|
||||||
|
#define USB_BOT_MASS_STORAGE_RESET 0xFFu
|
||||||
|
|
||||||
/* Standard USB Interface descriptor field offsets (9 bytes, USB 2.0 spec
|
/* Standard USB Interface descriptor field offsets (9 bytes, USB 2.0 spec
|
||||||
* table 9-12) -- Mass Storage class detection reads these three fields.
|
* table 9-12) -- Mass Storage class detection reads these three fields.
|
||||||
* Not decoded via a struct like usb_setup_packet_t: the Interface
|
* Not decoded via a struct like usb_setup_packet_t: the Interface
|
||||||
@@ -328,6 +351,20 @@ typedef struct {
|
|||||||
* xhci_dev_t's bot_tur_retries doc comment. */
|
* xhci_dev_t's bot_tur_retries doc comment. */
|
||||||
#define XHCI_BOT_TUR_MAX_RETRIES 3u
|
#define XHCI_BOT_TUR_MAX_RETRIES 3u
|
||||||
|
|
||||||
|
/* Bounded recovery count for a stalled bulk endpoint before giving up on
|
||||||
|
* it -- see xhci_dev_t's bot_stall_recoveries doc comment (G.1 / §F.14).
|
||||||
|
* Mirrors the shape of XHCI_BOT_TUR_MAX_RETRIES: a small fixed budget of
|
||||||
|
* full recoveries, each of which is itself the multi-step xHCI Reset
|
||||||
|
* Endpoint -> Set TR Dequeue Pointer -> CLEAR_FEATURE(ENDPOINT_HALT)
|
||||||
|
* sequence (escalating to a BOT Mass Storage Reset on the last try),
|
||||||
|
* after which the original SCSI command is retried from scratch. Two
|
||||||
|
* full recoveries, then escalation and terminal failure, is a deliberately
|
||||||
|
* tight bound chosen to match this driver's "recover or fail clean, never
|
||||||
|
* wedge the controller, never loop forever" contract -- a genuinely
|
||||||
|
* wedged device gets two chances to clear, then the block layer sees a
|
||||||
|
* clean BOT_STATUS_FAILED. */
|
||||||
|
#define XHCI_BOT_STALL_MAX_RECOVERIES 2u
|
||||||
|
|
||||||
/* SCSI READ CAPACITY(10) (SBC-3 section 5.14) -- 10-byte CDB, opcode 0x25,
|
/* SCSI READ CAPACITY(10) (SBC-3 section 5.14) -- 10-byte CDB, opcode 0x25,
|
||||||
* every other CDB byte reserved/zero for the standard "report capacity"
|
* every other CDB byte reserved/zero for the standard "report capacity"
|
||||||
* form (LBA field left 0, PMI bit left clear). 8-byte Data-In reply:
|
* form (LBA field left 0, PMI bit left clear). 8-byte Data-In reply:
|
||||||
@@ -368,6 +405,7 @@ typedef struct {
|
|||||||
#define XHCI_EVT_COMPLETION_CODE(status) (((uint32_t)(status) >> 24) & 0xFFu)
|
#define XHCI_EVT_COMPLETION_CODE(status) (((uint32_t)(status) >> 24) & 0xFFu)
|
||||||
#define XHCI_EVT_SLOT_ID(control) (((uint32_t)(control) >> 24) & 0xFFu)
|
#define XHCI_EVT_SLOT_ID(control) (((uint32_t)(control) >> 24) & 0xFFu)
|
||||||
#define XHCI_COMPLETION_CODE_SUCCESS 1u
|
#define XHCI_COMPLETION_CODE_SUCCESS 1u
|
||||||
|
#define XHCI_COMPLETION_CODE_STALL_ERROR 6u
|
||||||
|
|
||||||
/* Port Status Change Event TRB layout (xHCI 1.2 spec table 6-34):
|
/* Port Status Change Event TRB layout (xHCI 1.2 spec table 6-34):
|
||||||
* parameter[31:24] = Port ID (1-based, matches PORTSC array indexing
|
* parameter[31:24] = Port ID (1-based, matches PORTSC array indexing
|
||||||
|
|||||||
@@ -72,7 +72,9 @@ typedef struct {
|
|||||||
XHCI_CONN_AWAIT_ENABLE_SLOT,
|
XHCI_CONN_AWAIT_ENABLE_SLOT,
|
||||||
XHCI_CONN_AWAIT_ADDRESS_DEVICE,
|
XHCI_CONN_AWAIT_ADDRESS_DEVICE,
|
||||||
XHCI_CONN_AWAIT_DISABLE_SLOT,
|
XHCI_CONN_AWAIT_DISABLE_SLOT,
|
||||||
XHCI_CONN_AWAIT_CONFIGURE_ENDPOINT
|
XHCI_CONN_AWAIT_CONFIGURE_ENDPOINT,
|
||||||
|
XHCI_CONN_AWAIT_RESET_ENDPOINT,
|
||||||
|
XHCI_CONN_AWAIT_SET_TR_DEQUEUE
|
||||||
} connect_state;
|
} connect_state;
|
||||||
uint32_t pending_connect_slot_id;
|
uint32_t pending_connect_slot_id;
|
||||||
/* Milestone 2e/2g: disconnect teardown. Same single-outstanding-
|
/* Milestone 2e/2g: disconnect teardown. Same single-outstanding-
|
||||||
@@ -117,7 +119,9 @@ typedef struct {
|
|||||||
XHCI_XFER_CBW_SENT,
|
XHCI_XFER_CBW_SENT,
|
||||||
XHCI_XFER_BOT_DATA_IN,
|
XHCI_XFER_BOT_DATA_IN,
|
||||||
XHCI_XFER_BOT_DATA_OUT,
|
XHCI_XFER_BOT_DATA_OUT,
|
||||||
XHCI_XFER_CSW_RECEIVED
|
XHCI_XFER_CSW_RECEIVED,
|
||||||
|
XHCI_XFER_CLEAR_HALT,
|
||||||
|
XHCI_XFER_BOT_RESET
|
||||||
} transfer_purpose;
|
} transfer_purpose;
|
||||||
uint32_t pending_transfer_slot_id;
|
uint32_t pending_transfer_slot_id;
|
||||||
uint8_t device_descriptor[18];
|
uint8_t device_descriptor[18];
|
||||||
@@ -241,6 +245,34 @@ typedef struct {
|
|||||||
uint32_t bot_cap_last_lba;
|
uint32_t bot_cap_last_lba;
|
||||||
uint32_t bot_cap_block_size;
|
uint32_t bot_cap_block_size;
|
||||||
|
|
||||||
|
/* Milestone 2 / G.1 / §F.14: bulk-endpoint stall recovery. A bulk
|
||||||
|
* transfer that completes with XHCI_COMPLETION_CODE_STALL_ERROR leaves
|
||||||
|
* the xHC endpoint in the Halted state and the device endpoint in its
|
||||||
|
* own halt; neither can drive new transfers until explicitly cleared.
|
||||||
|
* This driver runs exactly one bulk transfer at a time, so a single
|
||||||
|
* recovery thread driven by bot_stall_recoveries + the stall_* fields
|
||||||
|
* below fully describes the recovery — there is no concurrency to
|
||||||
|
* serialize. The recovery itself is the BOT-spec standard sequence:
|
||||||
|
* xHCI Reset Endpoint -> Set TR Dequeue Pointer -> USB
|
||||||
|
* CLEAR_FEATURE(ENDPOINT_HALT), escalating to a Bulk-Only Mass Storage
|
||||||
|
* Reset + CLEAR_FEATURE on both bulk endpoints on a repeated stall,
|
||||||
|
* then the original command stage is retried from scratch. The two
|
||||||
|
* xHCI command steps are correlated via connect_state's two new
|
||||||
|
* AWAIT_ values; the CLEAR_FEATURE / BOT-reset control transfers are
|
||||||
|
* correlated via transfer_purpose's two new XHCI_XFER_* values; the
|
||||||
|
* deferred issue + final re-issue ride next_action's two new
|
||||||
|
* XHCI_NEXT_ACTION_* values — see xhci_poll_events()'s completion
|
||||||
|
* handlers for the state machine that consumes these. */
|
||||||
|
uint32_t bot_stall_recoveries; /* full recoveries performed for the
|
||||||
|
current command chain, capped at
|
||||||
|
XHCI_BOT_STALL_MAX_RECOVERIES */
|
||||||
|
uint32_t stall_dci; /* Device Context Index of the stalled bulk ep */
|
||||||
|
uint8_t stall_ep_addr; /* bEndpointAddress (bit7=dir) of the stalled bulk ep */
|
||||||
|
uint8_t bot_reset_clear_remaining; /* CLEAR_FEATUREs still owed in a
|
||||||
|
BOT-reset escalation (2 = both eps) */
|
||||||
|
uint32_t stall_retry_action; /* XHCI_NEXT_ACTION_* stage to re-issue once
|
||||||
|
recovery completes */
|
||||||
|
|
||||||
/* Milestone 2h: set by the SET_CONFIGURATION completion handler
|
/* Milestone 2h: set by the SET_CONFIGURATION completion handler
|
||||||
* (inside xhci_poll_events()'s own call frame, so it only sets a flag
|
* (inside xhci_poll_events()'s own call frame, so it only sets a flag
|
||||||
* -- no doorbell ring, no xhci_bot_wait_for_idle() call, both unsafe
|
* -- no doorbell ring, no xhci_bot_wait_for_idle() call, both unsafe
|
||||||
@@ -296,7 +328,9 @@ typedef struct {
|
|||||||
XHCI_NEXT_ACTION_BOT_SEND_TUR,
|
XHCI_NEXT_ACTION_BOT_SEND_TUR,
|
||||||
XHCI_NEXT_ACTION_BOT_SEND_READ10,
|
XHCI_NEXT_ACTION_BOT_SEND_READ10,
|
||||||
XHCI_NEXT_ACTION_BOT_SEND_READ_CAPACITY10,
|
XHCI_NEXT_ACTION_BOT_SEND_READ_CAPACITY10,
|
||||||
XHCI_NEXT_ACTION_BOT_SEND_WRITE10
|
XHCI_NEXT_ACTION_BOT_SEND_WRITE10,
|
||||||
|
XHCI_NEXT_ACTION_CLEAR_HALT,
|
||||||
|
XHCI_NEXT_ACTION_BOT_RESET
|
||||||
} next_action;
|
} next_action;
|
||||||
uint32_t next_action_slot_id;
|
uint32_t next_action_slot_id;
|
||||||
uint16_t next_action_length;
|
uint16_t next_action_length;
|
||||||
@@ -468,6 +502,52 @@ int xhci_cmd_address_device(xhci_dev_t *dev, uint32_t slot_id,
|
|||||||
*/
|
*/
|
||||||
int xhci_cmd_configure_endpoint(xhci_dev_t *dev, uint32_t slot_id);
|
int xhci_cmd_configure_endpoint(xhci_dev_t *dev, uint32_t slot_id);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* xhci_cmd_reset_endpoint — submit a Reset Endpoint command TRB for
|
||||||
|
* slot_id's endpoint `ep_id` (a bEndpointAddress,
|
||||||
|
* bit 7 = direction). Transitions that endpoint
|
||||||
|
* from the Halted state back to Stopped in the
|
||||||
|
* xHC's internal context — the xHCI-level first
|
||||||
|
* step of G.1 / §F.14 stall recovery, mirroring
|
||||||
|
* xhci_cmd_disable_slot()'s shape exactly (submit,
|
||||||
|
* ring doorbell 0, don't wait). The device-side
|
||||||
|
* halt is cleared separately by
|
||||||
|
* xhci_ep0_clear_endpoint_halt() once the two
|
||||||
|
* xHCI command steps (Reset Endpoint, then Set TR
|
||||||
|
* Dequeue Pointer) have completed.
|
||||||
|
*
|
||||||
|
* Called from xhci_poll_events()'s transfer-event STALL handler -- not
|
||||||
|
* called directly by other code.
|
||||||
|
*
|
||||||
|
* Returns 0 if the command was posted, -1 if dev/dev->cmd_ring is not set
|
||||||
|
* up.
|
||||||
|
*/
|
||||||
|
int xhci_cmd_reset_endpoint(xhci_dev_t *dev, uint32_t slot_id, uint32_t ep_id);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* xhci_cmd_set_tr_dequeue_pointer — submit a Set TR Dequeue Pointer command
|
||||||
|
* TRB for slot_id's endpoint ep_id,
|
||||||
|
* repositioning its Transfer Ring's
|
||||||
|
* dequeue pointer to `new_dequeue` (a
|
||||||
|
* pointer into the ring, e.g. the ring's
|
||||||
|
* current producer slot) with cycle state
|
||||||
|
* `dcs`. The xHCI-level second step of
|
||||||
|
* G.1 / §F.14 stall recovery: after Reset
|
||||||
|
* Endpoint has un-halted the ring, this
|
||||||
|
* tells the controller where to resume /
|
||||||
|
* discard from so a freshly enqueued TRB
|
||||||
|
* is consumed cleanly.
|
||||||
|
*
|
||||||
|
* Called from xhci_poll_events()'s command-completion handler once Reset
|
||||||
|
* Endpoint succeeds -- not called directly by other code.
|
||||||
|
*
|
||||||
|
* Returns 0 if the command was posted, -1 if dev/dev->cmd_ring is not set
|
||||||
|
* up.
|
||||||
|
*/
|
||||||
|
int xhci_cmd_set_tr_dequeue_pointer(xhci_dev_t *dev, uint32_t slot_id,
|
||||||
|
uint32_t ep_id, uint64_t new_dequeue,
|
||||||
|
uint32_t dcs);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* xhci_bot_send_read10 — build a Command Block Wrapper for a SCSI
|
* xhci_bot_send_read10 — build a Command Block Wrapper for a SCSI
|
||||||
* READ(10) and submit it on the bulk OUT Transfer
|
* READ(10) and submit it on the bulk OUT Transfer
|
||||||
@@ -816,4 +896,54 @@ int xhci_ep0_get_config_descriptor(xhci_dev_t *dev, uint32_t slot_id, uint16_t l
|
|||||||
*/
|
*/
|
||||||
int xhci_ep0_set_configuration(xhci_dev_t *dev, uint32_t slot_id, uint8_t config_value);
|
int xhci_ep0_set_configuration(xhci_dev_t *dev, uint32_t slot_id, uint8_t config_value);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* xhci_ep0_clear_endpoint_halt — issue a CLEAR_FEATURE(ENDPOINT_HALT)
|
||||||
|
* standard control request (Setup + Status
|
||||||
|
* only, no Data stage, via the existing
|
||||||
|
* xhci_ep0_control_write_nodata() machinery)
|
||||||
|
* with wValue = ENDPOINT_HALT and wIndex =
|
||||||
|
* ep_addr. This is the USB-level step of
|
||||||
|
* G.1 / §F.14 stall recovery that clears
|
||||||
|
* the *device's* own halt condition (and
|
||||||
|
* resets its data toggle), so the endpoint
|
||||||
|
* will actually drive new transfers after
|
||||||
|
* the xHC-side Reset Endpoint + Set TR
|
||||||
|
* Dequeue Pointer commands have run.
|
||||||
|
* Sets transfer_purpose = XHCI_XFER_CLEAR_HALT
|
||||||
|
* so xhci_poll_events() can complete the
|
||||||
|
* recovery and re-issue the stalled command.
|
||||||
|
*
|
||||||
|
* Called from xhci_poll_events()'s deferred next_action dispatch (the
|
||||||
|
* XHCI_NEXT_ACTION_CLEAR_HALT branch, which may run it more than once in a
|
||||||
|
* BOT-Reset escalation to clear both bulk endpoints) -- not called directly
|
||||||
|
* by other code.
|
||||||
|
*
|
||||||
|
* Returns 0 if the transfer was posted, -1 if dev/dev->ep0_ring is not set
|
||||||
|
* up.
|
||||||
|
*/
|
||||||
|
int xhci_ep0_clear_endpoint_halt(xhci_dev_t *dev, uint32_t slot_id, uint8_t ep_addr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* xhci_ep0_bot_mass_storage_reset — issue the Bulk-Only Transport class
|
||||||
|
* request Mass Storage Reset
|
||||||
|
* (bmRequestType = 0x21 class/interface,
|
||||||
|
* bRequest = 0xFF, no Data stage, again via
|
||||||
|
* the existing xhci_ep0_control_write_nodata()
|
||||||
|
* machinery). The escalation step of G.1 /
|
||||||
|
* §F.14 stall recovery: BOT spec section
|
||||||
|
* 5.3.4's full reset of a wedged command
|
||||||
|
* sequence, followed by
|
||||||
|
* xhci_ep0_clear_endpoint_halt() on *both*
|
||||||
|
* bulk endpoints before the original
|
||||||
|
* command is retried from scratch. Sets
|
||||||
|
* transfer_purpose = XHCI_XFER_BOT_RESET.
|
||||||
|
*
|
||||||
|
* Called from xhci_poll_events()'s deferred next_action dispatch (the
|
||||||
|
* XHCI_NEXT_ACTION_BOT_RESET branch) -- not called directly by other code.
|
||||||
|
*
|
||||||
|
* Returns 0 if the transfer was posted, -1 if dev/dev->ep0_ring is not set
|
||||||
|
* up.
|
||||||
|
*/
|
||||||
|
int xhci_ep0_bot_mass_storage_reset(xhci_dev_t *dev, uint32_t slot_id);
|
||||||
|
|
||||||
#endif /* STARKERNEL_XHCI_DRIVER_H */
|
#endif /* STARKERNEL_XHCI_DRIVER_H */
|
||||||
|
|||||||
+371
-1
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user