58c59e87e5816d7e23252d9fba69d3a29ea5f819
20
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
49a3faa331 |
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. |
||
|
|
5e9802845a |
Implement SCSI WRITE(10), closing the graph's highest-leverage blocker
Direct mirror of the existing READ(10) implementation (FABRIC-3.md §F.1), data direction flipped: new XHCI_XFER_BOT_DATA_OUT/XHCI_NEXT_ACTION_BOT_DATA_OUT states, xhci_bot_send_write10()/xhci_bot_write_block()/xhci_bot_write_data_out() in xhci.c, new SCSI_CMD_WRITE10 opcode and BOT_CMD_WRITE10/BOT_TUR_CHAIN_WRITE10 enum values. usb_blk_write() in blkio_usb.c is real now, no longer the BLKIO_ENOSUP stub. read_only flips to 0 in blkio_info() now that it's proven. Verified live end-to-end on all three architectures with a genuine cold-reboot round-trip (not just a same-session read): BLK-CONFIRM-FORMAT's BAM/reloc writes and an explicit block content write both completed via clean WRITE10 cycles (CSW PASS), and the written byte read back correctly after a full kernel rebuild + fresh boot -- amd64=65, aarch64=170, riscv64=201, each at LBN 32734 on a disposable usbwrite-test.img attached via QEMU usb-storage. Added Makefile.starkernel's QEMU_EXTRA (empty by default, no behavior change) to attach the disposable test image for this validation; the drive must be hotplugged via QMP after boot reaches ok>, not attached at QEMU launch -- attaching before xhci_bringup()'s controller reset means no fresh Port Status Change event fires (see project_xhci_milestone_2d_polling memory). Found and reported, not fixed, during testing: EMPTY-BUFFERS (empty_all_buffers(), block_words.c) does not implement standard Forth-79 semantics -- it force-writes zero to every block on every attached device instead of discarding cache assignments. This corrupted disk/artemis.img during an earlier test run; restored from git, confirmed byte-identical. Avoided in the final validation runs (detach/reattach used instead to force a fresh read). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019ZGkimpfyh63EZyRkNbkPD |
||
|
|
af267a52a6 |
Artemis Milestone 2h: hot-detach -- 2h complete
blk_subsys_detach_device() (block_subsystem.c) walks the device chain, refuses removal of anything but the current tail (a mid-chain removal would corrupt every later slot's start_lbn -- this architecture's own doc already argues USB stays last specifically to avoid that), unlinks, shrinks total_user_lbn, closes and frees the slot. Discards rather than flushes dirty state -- the device is physically gone by the time this runs (PORTSC disconnect only). Trigger wiring mirrors the attach path: bot_msc_attached (set only once attach actually succeeds) gates a new bot_msc_detach_pending flag set at PORTSC disconnect (not Disable Slot completion, which is conditionally skipped and would miss concurrent connect/disconnect pairs), consumed in sk_repl_idle(). Advisor flagged the real hazard ahead of time: block_words.c's VM block window (blk_vm_lbn[]/blk_vm_cbuf[]) can go stale across a detach then a same-LBN re-attach, and suggested a pointer-identity re-check in blk_vm_load() as a minimal fix. That fix was implemented, then directly falsified by its own designed-for-this test: attach a blank device, read a block (populating the cache), detach, re-attach a device with distinct content at the identical LBN, read again -- served stale content from the first device. Root cause, confirmed live: glibc's allocator hands free(slot) straight back to the very next same-size calloc(), so the "fresh" and stale pointers were bitwise identical despite being two different devices. Fixed properly with a monotonic blk_subsys_epoch() counter (bumped on every attach/detach) checked by a new blk_vm_check_epoch() helper at the one choke point (blk_vm_find(), plus blk_vm_flush_all() which reads the same arrays directly) that covers every path touching the window cache -- unfooled by address reuse. Verified live with a new disk/usb-thumbdrive-test2.img fixture (distinct content from the existing blank test image): attach A, read (cache hit populated), detach, re-attach B at the same LBN, read again -- correctly ran a fresh device read and returned B's real content, not A's stale cached zeros. The failing pointer-comparison attempt's own capture log kept as evidence, not deleted. All three architectures re-verified clean. FABRIC-2.md Section X 2h marked complete -- enumeration through hot-detach all live and verified; only WRITE(10) (2g's own still-open item) remains unimplemented in the driver, not blocking anything here. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn |
||
|
|
3b085dd875 |
Artemis Milestone 2h: blkio_usb.c backend -- USB thumb drive is now a real block device
Wires a hot-plugged USB Mass Storage device into the block subsystem's unified LBN chain. blkio_usb.c/blkio_usb.h mirror virtio_blk.c/ virtio_blk.h's established shape exactly (singleton state, blkio_vtable_t, a blkio_usb_open_msc() "find" function playing virtio_blk_find_artemis()'s role): read() translates a Forth block into a SCSI LBA/count pair and calls xhci_bot_read_block() + xhci_bot_wait_for_idle(); write() returns BLKIO_ENOSUP (no SCSI WRITE(10) exists yet, and blk_format_or_load_disk() never writes at attach time, so read-only is sufficient -- confirmed by reading that function first, not assumed). Refuses (-2) if the reported SCSI block size doesn't evenly divide the 1024-byte Forth block size. Connect-time wiring reuses the bot_msc_attach_pending/consume-in- sk_repl_idle() shape the prior increment's temp probe already validated, now made permanent: SET_CONFIGURATION sets the flag, sk_repl_idle() (strictly after its own xhci_poll_events() call returns) calls blkio_usb_open_msc() then blk_subsys_attach_device(). Verified live via hot-attach: full chain from USB connect through 'blkio_usb: MSC device ready' to 'blk: disk 'StarForth Volume' v2 LBN 26074..75184 (49111 user blocks)' -- real attachment, disk image confirmed byte-for-byte untouched after. Chased a real debugging detour along the way: the attach initially appeared silent (no blk: log line) -- traced to LOG_INFO filtering at the default LOG_WARN boot level, not a functional bug (settled via a temporary log-level bump, reverted after capture; also found and reported, but did not fix, a pre-existing unrelated Makefile.starkernel bug where --log-level=info via KERNEL_ARGS breaks printf parsing). All three architectures re-verified clean. FABRIC-2.md Section X 2h updated -- only hot-detach remains for 2h. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn |
||
|
|
d686f28853 |
Artemis Milestone 2h (foundational): sync wait bridge + SCSI READ CAPACITY(10)
Closes the gap block_subsystem.c needs before any of 2h's real work (blkio_usb.c, attach wiring, hot-detach) can start: this driver is fully async/polled with no way for a synchronous caller (blkio_read()/ blkio_info() etc.) to get a result back. xhci_bot_wait_for_idle() is a bounded busy-wait over xhci_poll_events() -- MUST be called only from outside xhci_poll_events()'s own call frame, never from within it or a next_action dispatch (recursion into live Event Ring/ERDP processing, same class of hazard already documented for doorbell rings in this driver). xhci_get_dev() exposes the module-static device handle to outside callers that didn't observe the original hotplug event. SCSI READ CAPACITY(10) (opcode 0x25) is the other half -- nothing could learn a device's block size/capacity before this. First attempt sent it bare and hit the classic first-command UNIT ATTENTION (CSW FAILED); fixed with the same TUR-guard pattern READ(10) already used, generalized via a new bot_tur_chain_target field so TEST UNIT READY's PASS handling can chain into either command. bot_data_buf grown 512->1024 bytes (one Forth block = two 512-byte SCSI blocks, per block_subsystem.c's own 1KiB-unit convention). Verified live via a temporary probe (hot-attached disk/usb-thumbdrive- test.img via QMP, reverted after capture): TUR-guarded READ CAPACITY10 correctly reported last LBA=0x1ffff, block size=0x200 -- exactly 64MiB, matching the test image byte for byte -- followed by a TUR-guarded 1024-byte/2-block READ10, both PASS. All three architectures re-verified clean, probe-free boot to ok> on the reverted tree. FABRIC-2.md Section X 2h updated with the writeup; the blkio_usb.c backend itself is next. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn |
||
|
|
65effbd1ba |
Artemis Milestone 2g: TEST UNIT READY unit-init sequence -- READ(10) now PASSes
Roots out the CSW status FAILED left unexplained in the prior increment: a freshly attached SCSI target's standing UNIT ATTENTION condition, which a bare READ(10) with no retry can never clear. xhci_bot_send_test_unit_ready() sends SCSI TEST UNIT READY (SPC-4 6.33) ahead of the real command; the CSW handler now tags command kind (bot_cmd_kind) to distinguish a TUR completion from a READ10 completion, chains TUR PASS into the real READ(10), and bounded-retries TUR on FAILED/PHASE ERROR (bot_tur_retries, capped at XHCI_BOT_TUR_MAX_RETRIES). xhci_bot_read_block() is the new intended entry point tying lba/num_blocks/block_size + the TUR-first sequencing together. Verified live via a temporary probe (hot-attached disk/usb-thumbdrive-test.img through the running instance's QMP socket), captured on amd64: full chain CBW(TUR) -> FAILED -> retry -> PASS -> CBW(READ10) -> Data-In -> CSW PASS. Probe reverted after capture; all three architectures re-verified clean, probe-free boot to ok>. FABRIC-2.md Section X 2g updated with the writeup. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn |
||
|
|
c54ea24aaf |
Artemis Milestone 2g: Data-In stage read and CSW receive/validation
Completes the CBW -> Data-In -> CSW chain for READ(10) started last commit. xhci_bot_read_data_in() and xhci_bot_receive_csw(), each a single Normal TRB on the bulk IN Transfer Ring via a new xhci_bulk_in_enqueue_and_ring() helper (mirrors the OUT-side helper from CBW send). All three stages now chain automatically via the existing deferred next_action pattern: CBW completion defers into Data-In, Data-In completion defers into CSW receive, CSW completion is where signature/tag/status validation happens. Data-In reads into a new fixed 512-byte bot_data_buf -- single-block scope for this increment, matches QEMU's usb-storage reported block size; xhci_bot_send_read10() now refuses rather than overflow/truncate if a request exceeds it. CSW validation (BOT spec section 5.2) checks dCSWSignature and dCSWTag (a new bot_last_tag field, latched from the CBW) before trusting bCSWStatus at all, so a garbled/misaligned CSW read can't be misread as a clean pass. usb_bot_csw_t follows the same struct-with-explicit-length-not-sizeof discipline as usb_bot_cbw_t. Verified live via a temporary probe (written, run once, log captured, reverted per this project's own probe convention), all three architectures, byte-identical: the full CBW -> Data-In -> CSW exchange completes cleanly, well-formed CSW with correct signature and echoed tag, no wedge, clean disconnect immediately after. The SCSI command itself reports CSW status FAILED against the current test fixture -- expected at this stage (no TEST UNIT READY / UNIT ATTENTION handling implemented yet, consistent with a fresh-attach unit-attention condition, not a transport-layer defect) and not root-caused further here; the BOT mechanism itself is confirmed correct end to end. Probe-free re-verification afterward on all three architectures. FABRIC-2.md Section X Milestone 2g's CSW checklist item marked done; "get one real READ(10) working end to end" stays explicitly open, distinguishing "the mechanism works" from "the SCSI command succeeds." Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R4VMX6VSKCten8nGgaMkq4 |
||
|
|
a88c004ecb |
Artemis Milestone 2g: CBW construction and send for SCSI READ(10)
First real use of the bulk Transfer Rings Configure Endpoint wired up. xhci_bot_send_read10() builds a 31-byte Command Block Wrapper (USB Mass Storage Class Bulk-Only Transport spec section 5.1) and submits it as a single Normal TRB on the bulk OUT ring via a new xhci_bulk_out_enqueue_and_ring() helper -- a CBW is always exactly one TRB, so unlike the EP0 helper this one rings its own doorbell rather than leaving that to a caller assembling a group. usb_bot_cbw_t is a real struct (every field up to the CDB array is naturally aligned, and this driver's targets are all little-endian already assumed everywhere else), but its DMA length is the explicit USB_BOT_CBW_LENGTH (31) constant, never sizeof(*cbw), since the compiler may pad the struct to 32 bytes. The SCSI READ(10) CDB itself is written byte-by-byte since its LBA/Transfer Length fields are big-endian on the wire, unlike everything else in this driver -- the one place two byte orders are both live in the same function. Completion is correlated via the existing pending_transfer_slot_id/ transfer_purpose gate (new XHCI_XFER_CBW_SENT purpose) -- no ring-specific dispatch needed, since this driver's single-outstanding- transfer scope already implies which ring produced an event. This covers construction and send only (one third of a full READ(10): CBW -> Data-In stage -> CSW) -- reading the Data-In stage and CSW receive/validation are separate, explicitly not-yet-implemented items. Verified live via a temporary probe (written, run once, log captured, reverted per this project's own probe convention) -- all three architectures, byte-identical: CBW submitted -> CBW send completed, then a clean disconnect even with the Data-In stage never drained (confirms no wedge on a dangling BOT transaction). Probe-free re-verification afterward on all three architectures. FABRIC-2.md Section X Milestone 2g's CBW checklist item marked done. Also records a monitoring gotcha hit three times this session: `ls -t` over the logs/ tree can return a stale leftover log from an earlier run in the same session -- fixed going forward by reading the log path off the actual running QEMU process's own command line instead, and a memory note added so it doesn't recur next session. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R4VMX6VSKCten8nGgaMkq4 |
||
|
|
92ce1f85dd |
Artemis Milestone 2g: Configure Endpoint command
Adds the xHCI Configure Endpoint command for the two bulk endpoints identified by the previous increment, and fixes control-transfer sequencing to match the spec: xHCI 1.2 section 4.3.5 requires Configure Endpoint before SET_CONFIGURATION is sent to the device, the reverse of the order this driver used through 2f (which happened to work against QEMU's lenient qemu-xhci emulation but wasn't spec-correct). New XHCI_TRB_TYPE_CONFIGURE_ENDPOINT_CMD, EP Context type constants for Bulk IN/OUT, and an XHCI_EP_ADDR_TO_DCI() macro (DCI = 2*EndpointNumber + Direction) in xhci.h. xhci_cmd_configure_endpoint() builds the Input Context (Slot + one EP Context per DCI up to the highest bulk endpoint in use) and submits the command via the existing next_action deferral mechanism, correlated on completion via a new XHCI_CONN_AWAIT_CONFIGURE_ENDPOINT connect_state, then chains into the existing SET_CONFIGURATION path. Two allocations had to grow beyond what Address Device sized them for: the Input Context (previously room for one EP Context only) and, less obviously, the Device Context that DCBAA[slot_id] itself points at -- the controller only touches DCIs named in a command's own Add/Drop flags, so growing that buffer required copying its existing Slot+EP0 content forward rather than zeroing it, to avoid handing the controller a blank EP0 out from under an endpoint this command isn't touching. Bulk Transfer Rings (bulk_in_ring/bulk_out_ring) are allocated and wired into the new EP Contexts but not yet exercised by an actual transfer -- CBW/CSW submission is next. Verified live via QMP hotplug, all three architectures, byte-identical: bulk endpoint identification -> configure endpoint command submitted -> configure endpoint succeeded -> the existing set configuration -> device configured chain, then a clean disconnect/disable-slot teardown afterward with the larger Device Context installed. FABRIC-2.md Section X Milestone 2g's endpoint identify+configure checklist item marked fully done. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R4VMX6VSKCten8nGgaMkq4 |
||
|
|
96d55fcd87 |
Artemis Milestone 2g (partial): bulk endpoint discovery + 2e disconnect teardown
Picked up from a crashed session: xhci_driver.h/xhci.h already had the bulk_in/out_ep_addr/max_packet fields and Endpoint-descriptor offset macros scaffolded, but the actual walk that populates them was never written. Added it: after 2f confirms a Mass Storage/SCSI/BOT interface, a nested walk continues through the Endpoint descriptors that follow it (bDescriptorType==5, stopping at the next Interface descriptor or end of stream), keeping only Bulk-type endpoints and splitting IN/OUT by bEndpointAddress bit 7. Also reset the four new fields in xhci_bringup(), which the scaffolding had missed. Also completed 2e's disconnect teardown, which was fully implemented this session (not scaffolded): a Disable Slot command is now submitted on a real disconnect, with the port's tracked slot ID captured and cleared from port_slot_id[] immediately (before the command completes) so a fresh connect on the same port isn't confused for one already in progress, and DCBAA[slot_id] cleared only on a successful completion. Verified live via QMP hotplug (deliberate device_add/device_del against freshly launched, individually-tracked instances -- not whatever happened to be attached at boot), all three architectures, byte-identical: bulk IN endpoint=0x81, bulk OUT endpoint=0x02, then a clean disconnect -> disable slot succeeded, no wedge. Caught and fixed a documentation near-miss in the same pass: an initial draft cited the probe-free three-arch acceptance boots as this feature's verification evidence, but a stale leftover log directory from a pre-crash orphaned QEMU process had been picked up by an `ls -dt | head -1` glob during monitoring and mistaken for this session's own result -- the real acceptance logs never had a device attached at all. Re-verified against real PIDs and real log paths before writing FABRIC-2.md's final writeup. FABRIC-2.md Section X Milestone 2 updated: 2e's disconnect-teardown checklist item marked done, 2g's endpoint-identification item marked partially done (identification only -- Configure Endpoint / EP Context wiring is still open). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R4VMX6VSKCten8nGgaMkq4 |
||
|
|
b4bbd043d0 |
Artemis Milestone 2f: SET_CONFIGURATION -- 2f complete
Chains off a confirmed Mass Storage/SCSI/BOT interface match via the existing next_action deferral mechanism: device descriptor -> config descriptor -> SET_CONFIGURATION is now a single automatic sequence. bConfigurationValue is read directly out of the already-fetched config_descriptor buffer, no extra transfer needed. First write control transfer this driver has issued (every prior one was a read), so it needed its own submission helper, xhci_ep0_control_write_nodata() -- SET_CONFIGURATION has no Data Stage (wLength=0), and per USB 2.0 spec 8.5.3 a no-data control transfer's Status Stage is always IN, the reverse of an OUT-data request's status stage. XHCI_SETUP_TRT_NO_DATA already existed in xhci.h, unused until now. Verified live via QMP hotplug, all three architectures, worked first try, byte-identical: "set configuration submitted" -> "device configured", guest stays running throughout (checked via QMP query-status). Disconnect confirmed clean on every arch afterward, no wedge. FABRIC-2.md Section X Milestone 2f updated -- 2f is now fully complete, 2g (Bulk-Only Transport) can start. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QPfdtaXs9ay1nbwuMnrscu |
||
|
|
b9c540a78b |
Artemis Milestone 2f: Configuration descriptor read + Mass Storage/BOT class confirmation
Chains off the device descriptor request via a new deferred-action mechanism on xhci_dev_t (next_action/next_action_slot_id/next_action_length): a short 9-byte Configuration descriptor read learns wTotalLength, then a full read retrieves Config+Interface+Endpoint descriptors, walked for the Interface descriptor to confirm bInterfaceClass/SubClass/Protocol == Mass Storage/ SCSI/Bulk-Only Transport. The deferral exists because ringing the next doorbell synchronously inside xhci_poll_events()'s event-processing loop -- before the current event's ERDP write -- hung the guest outright (confirmed live via checkpoint logging, amd64). Fixed by moving the actual control-transfer submission to a small dispatch at the end of xhci_poll_events(), after ERDP is updated. A debug hack that shipped mid-session (forcing a repeated 9-byte read instead of chaining into the real 44-byte length, to isolate whether the hang was doorbell-ordering or length-specific) has been reverted: restored the real length and re-verified live. The doorbell-ordering fix was the whole story -- the 44-byte read completes cleanly. Verified live via QMP hotplug, all three architectures, byte-identical results: wTotalLength=0x2c, bInterfaceClass=0x08, bInterfaceSubClass=0x06, bInterfaceProtocol=0x50 -- confirmed Mass Storage/SCSI/BOT. Disconnect confirmed clean on every arch, no wedge. FABRIC-2.md Section X Milestone 2f updated with the full writeup. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QPfdtaXs9ay1nbwuMnrscu |
||
|
|
2c34e45d05 |
Artemis Milestone 2f: EP0 control transfer, device descriptor request
Adds Setup/Data/Status stage TRB types and control bits (IDT, TRT, DIR) to xhci.h, and xhci_ep0_enqueue_trb()/xhci_ep0_get_device_descriptor() to xhci.c -- the first real control transfer this driver has issued. Follows the same enqueue-then-doorbell-once pattern as the Command Ring, operating on the EP0 Transfer Ring built during 2e's Address Device work. Setup Stage uses Immediate Data (parameter IS the 8-byte setup packet); Data Stage reads into a reused 18-byte device_descriptor buffer; Status Stage alone carries IOC, so exactly one Transfer Event signals transfer completion, correlated via a new pending_transfer_slot_id (same single-outstanding-operation pattern as connect/Enable Slot/Address Device). Automatically triggered once Address Device succeeds. Verified live via QMP hotplug, all three architectures, worked first try with identical results everywhere: idVendor=0x46f4, idProduct=0x0001, bDeviceClass=0x00 -- the class=0 confirms Mass Storage class detection needs the Configuration/Interface descriptor (2f's next item), not the device descriptor. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HZ8kNoTuP63pbQtro4qvrm |
||
|
|
2b7743027c |
Artemis Milestone 2e: Address Device implemented, worked first try, 3-arch
Adds Slot/Endpoint/Input Control Context structs (32-byte layout only -- HCCPARAMS1.CSZ checked live and confirmed 0 against this driver's QEMU target; 64-byte contexts refuse rather than silently mis-laying-out), xhci_cmd_address_device(), and a new dev->connect_state (idle/await-enable-slot/await-address-device) sequencing Enable Slot and Address Device per connect. Input Context (what the command TRB's parameter points at) and Device Context (what DCBAA[slot_id] points at) are separate 64-byte-aligned allocations, lazily created once and reused across every connect -- single-device driver scope, no free path needed. A new EP0 Transfer Ring uses the same fixed-ring-plus-Link-TRB pattern as the Command Ring. Two facts checked live before writing any context code, not assumed: HCCPARAMS1.CSZ (32-byte, confirmed) and PORTSC.PED at connect time (already set -- PORTSC=0x00021203, SuperSpeed -- the test device self-enables via USB3 link training, so no port-reset state machine was needed this increment; USB2 would need one, untested). Both diagnostics also added console_puts/println-based hex logging (xhci_log_hex32()) -- console_println() only takes string literals, no formatted print existed on this driver's console path before now. Verified live via QMP hotplug, all three architectures, succeeded on the first attempt with no debugging needed: "enable slot succeeded" -> "address device command submitted" -> "address device succeeded" on every boot. Also fixes a FABRIC-2.md dependency-direction error from the previous commit (Address Device is 2f's prerequisite, not the reverse). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HZ8kNoTuP63pbQtro4qvrm |
||
|
|
6d330efdd8 |
Artemis Milestone 2e: real connect drives Enable Slot, slot ID correlated
xhci_poll_events()'s Port Status Change connect branch now calls xhci_cmd_enable_slot() directly (the earlier boot-time smoke test call is gone), tracked via a new dev->pending_connect_port_id -- since this driver only ever has one command outstanding at a time, that alone identifies which port a later Command Completion Event answers, without needing to match the Command TRB Pointer yet. On success the returned Slot ID is recorded in a new dev->port_slot_id[], a fixed uint32_t[XHCI_MAX_TRACKED_PORTS] (32) indexed by port. Disconnect clears the port's tracked slot (real teardown -- Disable Slot, DCBAA clear, Section U callback -- is still a later increment). Fixed array, not heap-allocated: a first attempt sized port_slot_id dynamically via kmalloc_aligned(dev->max_ports * sizeof(uint32_t), 64) inside xhci_bringup() and it crashed amd64 with a page fault (IFETCH at RIP=CR2=0xA0000, the legacy VGA hole) during the unrelated Mama-VM-birth phase afterward -- a heap-corruption signature, not chased to root cause. Switching to a fixed array (matching this driver's existing preference for fixed over dynamic allocation) made the crash go away; the crashing boot's log is kept (logs/20260822-102516/) as the evidence trail. Verified live via QMP hotplug, all three architectures: connect -> "enable slot command submitted" -> "enable slot succeeded", with a disconnect/reconnect cycle repeating cleanly and no port wedge. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HZ8kNoTuP63pbQtro4qvrm |
||
|
|
dd043bbfeb |
Artemis Milestone 2e: PORTSC connect/disconnect detection, verified live
xhci_poll_events()'s Port Status Change branch now decodes the Port ID from the event TRB (XHCI_PSC_EVT_PORT_ID, new in xhci.h), reads that port's PORTSC.CCS via a new xhci_port_regs() helper, and logs connect vs. disconnect. Acknowledges by writing back only PP (preserved) and CSC (the bit being cleared) -- PED/PR/other _C bits written 0 so nothing is accidentally disabled, reset, or silently cleared, matching the RW1C discipline already used for ERDP.EHB in 2d. Verified with the real target scenario via QMP hotplug on all three architectures: boot with the xHCI controller present but no USB device attached (confirmed zero port activity at ok>), then live attach/detach/re-attach of a virtual USB thumb drive (disk/usb-thumbdrive-test.img via usb-storage on xhci0.0). Full connect->disconnect->connect cycle confirmed clean (no port wedge) on amd64; single connect confirmed on aarch64 and riscv64. Still open: correlating Command Completion Events back to their issuing command, driving Enable Slot/Address Device from this connect path (currently only a boot-time smoke test), and the callback surface into Section U's higher-level code. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HZ8kNoTuP63pbQtro4qvrm |
||
|
|
9c8ad8f6ff |
Artemis Milestone 2e (in progress): xHCI Command Ring write path proven live
Enable Slot command TRB submitted via a new xhci_submit_command()/ xhci_cmd_enable_slot(), ring doorbell 0, confirmed by a real Command Completion Event on all three architectures -- the first time this driver has written a TRB rather than only reading the Event Ring (2d). Added the Command Ring's previously-missing Link TRB (xHCI 1.2 spec sec 4.9.2) for wraparound correctness. Port Register connect/disconnect handling, slot-ID/context bookkeeping, Address Device, and the callback surface into Section U's code are still open -- this is the discriminating first step, not full 2e. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HZ8kNoTuP63pbQtro4qvrm |
||
|
|
2b16daba16 |
Artemis Milestone 2d: xHCI Event Ring servicing, polled not interrupt-driven
Implements Event Ring TRB parsing and ERDP dequeue-pointer update
(xhci_poll_events(), src/starkernel/usb/xhci.c), called from
sk_repl_idle()'s existing ~1s idle cadence rather than a per-arch
interrupt handler.
A first attempt wired real interrupt delivery (PCI->IOAPIC GSI routing,
a dedicated isr_stub34/vector 0x22, GIC/PLIC routing mirroring
virtio_input.c). Checked live via QMP query-pci before trusting it: the
amd64 PIRQ swizzle formula predicted GSI 16 for the xHCI controller at
PCI slot 4; the real QEMU-assigned IRQ was 10, and embedded ICH9
functions contradicted the same formula too. Reverted all of it back to
the exact committed baseline rather than chasing chipset PIRQ routing
further, and reframed around Section U item 6's own design intent
("interrupt-driven, coarse cadence, cheap early-exit... quick check
blocks... done") via sk_repl_idle() instead -- USB insertion is a
human-timescale event, not a hot path.
Added -device qemu-xhci to all three QEMU launch targets (required for
any of this to be testable). Verified end to end via genuine post-boot
hotplug (QMP device_add/device_del usb-storage): all three architectures
detect a live attach within seconds. A false-alarm heartbeat "freeze"
found mid-verification traced to querying the wrong counter
(vm->heartbeat.tick_count, which only advances during word execution,
not the kernel's real ISR-driven heartbeat_ticks()) -- confirmed via a
temporary diagnostic word, captured and reverted.
Full writeup, including the discarded interrupt-routing attempt and the
false-alarm investigation, in FABRIC-2.md's Milestone 2c/2d entries.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HZ8kNoTuP63pbQtro4qvrm
|
||
|
|
c2f1d94c97 |
Artemis Milestone 2c: xHCI controller bring-up wired, DoE CSV export off by default
xhci_bringup() (HC reset, DCBAA, Command/Event rings, RUN/STOP) was uncommitted and referenced an XHCI_WAIT_FOR macro that was never defined, breaking the build. Wired all four wait sites to the existing xhci_wait_bit() helper instead, matching each register/bit/polarity needed (halt-before-reset waits for HCH set; HCRST, CNR, and post-RUN HCH waits all wait for their bit to clear). Also flipped g_doe_log_enabled's default from 1 to 0 -- the per-tick [HADES][DOE] CSV export was flooding every boot log and slowing interactive verification for no reason during ordinary acceptance runs; HB-ON still re-enables it at the REPL for anyone running an actual DoE campaign. Three-arch acceptance: amd64/aarch64/riscv64 all boot clean to ok>, zero DoE rows in any log. aarch64 and riscv64 both exited cleanly via BYE with no exception, confirming the earlier SMC->HVC PSCI fix still holds. Logs and DoE CSV artifacts from this run included. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HZ8kNoTuP63pbQtro4qvrm |
||
|
|
5970c54912 |
Artemis Milestone 2b complete: xHCI PCI discovery and BAR0 mapping
New src/starkernel/usb/ subsystem directory (added to both LOADER_SRCS_BASE and KERNEL_SRCS_BASE wildcards in Makefile.starkernel, matching the existing virtio/*.c pattern). xhci_find_and_map() locates the controller via the already-generic pci_find_first(), enables it, maps BAR0 via the already-generic pci_map_bar(), and fills in all four register-region pointers (cap/op/runtime/doorbell) plus max_slots/ max_ports/max_intrs from HCSPARAMS1 -- ready for controller bring-up (2c) to consume directly. No pci.c extension needed, per 2a's finding that PCI discovery here is ID-based lookup (already generic), not class-code scanning. Verified: clean standalone syntax check, full amd64 kernel build with zero warnings, live boot still reaches POST 1012/0/0 unaffected (nothing calls xhci_find_and_map() yet, so this is purely additive). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |