/* * xhci.h — xHCI (Extensible Host Controller Interface, USB 3.x) register * layout and shared constants for StarKernel's USB host controller driver. * * Register layout from the xHCI 1.2 specification. Four MMIO regions, each * reached via an offset from PCI BAR0: * Capability Registers — at BAR0 + 0, fixed layout, CAPLENGTH gives the * offset to Operational Registers * Operational Registers — at BAR0 + CAPLENGTH * Runtime Registers — at BAR0 + RTSOFF (read from Capability Registers) * Doorbell Array — at BAR0 + DBOFF (read from Capability Registers) * * Struct fields are `volatile`, naturally aligned, NOT __attribute__((packed)) * — matching virtio_blk.c's precedent and its documented riscv64 lesson: * packed structs force byte-wise loads/stores on strict-alignment targets, * and QEMU's MMIO handlers for exact-width registers can misbehave under * byte-wise access. The xHCI spec's register layout is naturally aligned at * every offset, so this translates directly without padding tricks. * * QEMU's `qemu-xhci` device identifies as PCI vendor 0x1B36 (Red Hat, Inc.), * device 0x000D — confirmed live via QMP `query-pci` against a real running * instance (not assumed from memory), 2026-08-22. */ #ifndef STARKERNEL_XHCI_H #define STARKERNEL_XHCI_H #include /* ------------------------------------------------------------------------- * PCI identification * ------------------------------------------------------------------------- */ #define XHCI_PCI_VENDOR_ID 0x1B36u /* Red Hat, Inc. (QEMU qemu-xhci) */ #define XHCI_PCI_DEVICE_ID 0x000Du /* ------------------------------------------------------------------------- * Capability Registers (BAR0 + 0) * ------------------------------------------------------------------------- */ typedef struct { volatile uint8_t cap_length; /* offset to Operational Registers */ volatile uint8_t reserved0; volatile uint16_t hci_version; /* BCD xHCI spec version */ volatile uint32_t hcs_params1; /* MaxSlots[7:0], MaxIntrs[18:8], MaxPorts[31:24] */ volatile uint32_t hcs_params2; /* IST, ERST Max, scratchpad buffer counts */ volatile uint32_t hcs_params3; /* U1/U2 device exit latencies */ volatile uint32_t hcc_params1; /* AC64, BNC, CSZ, xECP pointer[31:16], etc. */ volatile uint32_t db_off; /* Doorbell Array offset (low 2 bits reserved) */ volatile uint32_t rts_off; /* Runtime Register Space offset (low 5 bits reserved) */ volatile uint32_t hcc_params2; } xhci_cap_regs_t; #define XHCI_HCSPARAMS1_MAX_SLOTS(v) ((uint32_t)(v) & 0xFFu) #define XHCI_HCSPARAMS1_MAX_INTRS(v) (((uint32_t)(v) >> 8) & 0x7FFu) #define XHCI_HCSPARAMS1_MAX_PORTS(v) (((uint32_t)(v) >> 24) & 0xFFu) /* HCSPARAMS2: Max Scratchpad Buffers is a 10-bit field split across two * non-adjacent locations (xHCI 1.2 spec table 5-13) — Hi bits[25:21], * Lo bits[31:27]. Zero means the controller needs no scratchpad buffers * (common for simple emulated controllers, but verify live, not assumed). */ #define XHCI_HCSPARAMS2_MAX_SCRATCHPAD_BUFS(v) \ ((((uint32_t)(v) >> 21) & 0x1Fu) << 5 | (((uint32_t)(v) >> 27) & 0x1Fu)) /* HCCPARAMS1.CSZ (bit 2): 0 = 32-byte Slot/Endpoint/Input Contexts, * 1 = 64-byte. Every context field offset shifts with this bit -- must be * read live, never assumed, before laying out any context structure. */ #define XHCI_HCCPARAMS1_CSZ(v) (((uint32_t)(v) >> 2) & 0x1u) /* ------------------------------------------------------------------------- * Operational Registers (BAR0 + cap_length) * ------------------------------------------------------------------------- */ typedef struct { volatile uint32_t usb_cmd; /* Run/Stop, HC Reset, Interrupter Enable, ... */ volatile uint32_t usb_sts; /* HCHalted, HSE, EINT, PCD, CNR, HCE */ volatile uint32_t page_size; /* bit N set => 2^(N+12)-byte pages supported */ volatile uint32_t reserved0[2]; volatile uint32_t dn_ctrl; /* Device Notification Control */ volatile uint64_t crcr; /* Command Ring Control Register */ volatile uint32_t reserved1[4]; volatile uint64_t dcbaap; /* Device Context Base Address Array Pointer */ volatile uint32_t config; /* MaxSlotsEn[7:0] */ /* Port Register Sets follow at a fixed offset (0x400 from Operational * base), not contiguous with the fields above — accessed via * xhci_port_regs() below, not as a struct member. */ } xhci_op_regs_t; /* USBCMD bits */ #define XHCI_USBCMD_RUN (1u << 0) /* Run/Stop: 1 = run */ #define XHCI_USBCMD_HCRST (1u << 1) /* HC Reset */ #define XHCI_USBCMD_INTE (1u << 2) /* Interrupter Enable */ #define XHCI_USBCMD_HSEE (1u << 3) /* Host System Error Enable */ /* USBSTS bits */ #define XHCI_USBSTS_HCH (1u << 0) /* HC Halted */ #define XHCI_USBSTS_HSE (1u << 2) /* Host System Error */ #define XHCI_USBSTS_EINT (1u << 3) /* Event Interrupt */ #define XHCI_USBSTS_PCD (1u << 4) /* Port Change Detect */ #define XHCI_USBSTS_CNR (1u << 11) /* Controller Not Ready */ #define XHCI_USBSTS_HCE (1u << 12) /* Host Controller Error */ /* CRCR bits (low bits of the 64-bit register; pointer occupies bits[63:6]) */ #define XHCI_CRCR_RCS (1ull << 0) /* Ring Cycle State */ #define XHCI_CRCR_CS (1ull << 1) /* Command Stop */ #define XHCI_CRCR_CA (1ull << 2) /* Command Abort */ #define XHCI_CRCR_CRR (1ull << 3) /* Command Ring Running (read-only) */ #define XHCI_CRCR_PTR_MASK (~0x3Full) /* pointer must be 64-byte aligned */ /* CONFIG */ #define XHCI_CONFIG_MAX_SLOTS_EN(n) ((uint32_t)(n) & 0xFFu) /* Port Register Set — array at Operational base + 0x400, 0x10 bytes each, * indexed 0..(MaxPorts-1) for ports numbered 1..MaxPorts. */ typedef struct { volatile uint32_t portsc; /* Port Status and Control */ volatile uint32_t portpmsc; /* Port Power Management Status and Control */ volatile uint32_t portli; /* Port Link Info */ volatile uint32_t porthlpmc; /* Port Hardware LPM Control */ } xhci_port_regs_t; #define XHCI_PORT_REGS_OFFSET 0x400u /* PORTSC bits (subset needed for hotplug + reset) */ #define XHCI_PORTSC_CCS (1u << 0) /* Current Connect Status */ #define XHCI_PORTSC_PED (1u << 1) /* Port Enabled/Disabled */ #define XHCI_PORTSC_PR (1u << 4) /* Port Reset */ #define XHCI_PORTSC_PLS_MASK (0xFu << 5) /* Port Link State */ #define XHCI_PORTSC_PP (1u << 9) /* Port Power */ #define XHCI_PORTSC_SPEED_MASK (0xFu << 10) #define XHCI_PORTSC_SPEED(v) (((uint32_t)(v) >> 10) & 0xFu) /* xHCI 1.2 spec table 7-13 speed IDs */ #define XHCI_PORTSC_CSC (1u << 17) /* Connect Status Change */ #define XHCI_PORTSC_PEC (1u << 18) /* Port Enabled/Disabled Change */ #define XHCI_PORTSC_PRC (1u << 21) /* Port Reset Change */ /* Writing 1 to a _C (change) bit clears it (RW1CS) — writing 0 has no effect. * PORTSC also has RW1CS bits interleaved with RW bits; always read-modify- * write with the change bits masked to 0 unless intentionally clearing one, * to avoid accidentally acknowledging an event by a stray read-modify-write. */ /* ------------------------------------------------------------------------- * Runtime Registers (BAR0 + rts_off) * ------------------------------------------------------------------------- */ typedef struct { volatile uint32_t iman; /* Interrupt Management: bit0=IP, bit1=IE */ volatile uint32_t imod; /* Interrupt Moderation */ volatile uint32_t erstsz; /* Event Ring Segment Table Size */ volatile uint32_t reserved0; volatile uint64_t erstba; /* Event Ring Segment Table Base Address */ volatile uint64_t erdp; /* Event Ring Dequeue Pointer; bit3=EHB */ } xhci_intr_regs_t; typedef struct { volatile uint32_t mf_index; /* Microframe Index */ volatile uint32_t reserved0[7]; /* Interrupter Register Sets follow, one xhci_intr_regs_t per interrupter, * starting immediately after this 0x20-byte header. Interrupter 0 is * accessed via xhci_intr_regs_t at (runtime_base + 0x20). */ } xhci_runtime_regs_t; #define XHCI_IMAN_IP (1u << 0) /* Interrupt Pending */ #define XHCI_IMAN_IE (1u << 1) /* Interrupt Enable */ #define XHCI_ERDP_EHB (1ull << 3) /* Event Handler Busy */ #define XHCI_ERDP_PTR_MASK (~0xFull) /* pointer occupies bits[63:4] */ /* ------------------------------------------------------------------------- * Doorbell Array (BAR0 + db_off) — array of uint32_t, one per device slot * plus doorbell 0 for the Command Ring. Write-only. * ------------------------------------------------------------------------- */ typedef volatile uint32_t xhci_doorbell_t; #define XHCI_DB_TARGET(ep) ((uint32_t)(ep) & 0xFFu) /* 0 = command ring */ #define XHCI_DB_STREAM_ID(sid) (((uint32_t)(sid) & 0xFFFFu) << 16) /* ------------------------------------------------------------------------- * TRB (Transfer Request Block) — 16 bytes, the unit of both Command Ring * and Event Ring entries (and Transfer Rings, used later for BOT I/O). * ------------------------------------------------------------------------- */ typedef struct { volatile uint64_t parameter; volatile uint32_t status; volatile uint32_t control; } xhci_trb_t; #define XHCI_TRB_CONTROL_CYCLE (1u << 0) /* Cycle bit */ #define XHCI_TRB_CONTROL_TYPE_SHIFT 10 #define XHCI_TRB_CONTROL_TYPE_MASK (0x3Fu << XHCI_TRB_CONTROL_TYPE_SHIFT) #define XHCI_TRB_TYPE(ctrl) (((ctrl) & XHCI_TRB_CONTROL_TYPE_MASK) >> XHCI_TRB_CONTROL_TYPE_SHIFT) /* TRB types used by this driver (subset — xHCI defines many more) */ #define XHCI_TRB_TYPE_NORMAL 1 /* Transfer Ring, bulk/interrupt/isoch -- not EP0 */ #define XHCI_TRB_TYPE_LINK 6 /* ring-wraparound marker, Command/Transfer Rings only */ #define XHCI_TRB_TYPE_ENABLE_SLOT_CMD 9 #define XHCI_TRB_TYPE_DISABLE_SLOT_CMD 10 #define XHCI_TRB_TYPE_ADDRESS_DEVICE_CMD 11 #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_DATA_STAGE 3 #define XHCI_TRB_TYPE_STATUS_STAGE 4 #define XHCI_TRB_TYPE_TRANSFER_EVENT 32 #define XHCI_TRB_TYPE_COMMAND_COMPLETION_EVT 33 #define XHCI_TRB_TYPE_PORT_STATUS_CHANGE_EVT 34 /* Control bits used only by Link TRBs */ #define XHCI_TRB_CONTROL_TC (1u << 1) /* Toggle Cycle */ /* Control bits for control-transfer TRBs (xHCI 1.2 spec section 4.11.2.2 / * table 6-23..6-25). IDT (Immediate Data) tells the controller the Setup * Stage TRB's parameter field IS the 8-byte setup packet, not a pointer * to one -- required for every Setup Stage TRB. TRT/DIR select data * direction: TRT=3 (IN Data Stage) for the standard "read a descriptor" * case this driver needs first; DIR must match TRT's direction on the * Data Stage TRB, and the Status Stage TRB's DIR is the OPPOSITE * direction of the Data Stage (status is always the reverse handshake). */ #define XHCI_TRB_CONTROL_IDT (1u << 6) #define XHCI_TRB_CONTROL_IOC (1u << 5) /* Interrupt On Completion */ #define XHCI_TRB_CONTROL_DIR_IN (1u << 16) /* Data/Status Stage: 1=IN, 0=OUT */ #define XHCI_SETUP_TRT_NO_DATA 0u #define XHCI_SETUP_TRT_OUT_DATA 2u #define XHCI_SETUP_TRT_IN_DATA 3u #define XHCI_TRB_CONTROL_TRT_SHIFT 16 /* Setup Stage TRB only; Data/Status Stage overlays DIR at the same bit */ /* Standard USB Setup packet (8 bytes) -- the exact bytes placed in a * Setup Stage TRB's parameter field via IDT. */ typedef struct { uint8_t bmRequestType; uint8_t bRequest; uint16_t wValue; uint16_t wIndex; uint16_t wLength; } usb_setup_packet_t; #define USB_REQ_GET_DESCRIPTOR 6u #define USB_REQ_SET_CONFIGURATION 9u #define USB_REQ_CLEAR_FEATURE 1u #define USB_DESC_TYPE_DEVICE 1u #define USB_DESC_TYPE_CONFIG 2u #define USB_DIR_DEVICE_TO_HOST 0x80u #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 * table 9-12) -- Mass Storage class detection reads these three fields. * Not decoded via a struct like usb_setup_packet_t: the Interface * descriptor's exact position within a Configuration descriptor's byte * stream isn't fixed (depends on the device's actual interface/endpoint * layout), so it's found by walking the byte stream looking for * bDescriptorType == USB_DESC_TYPE_INTERFACE, not by a fixed struct * offset into the whole buffer. */ /* Every standard USB descriptor starts with these two bytes (bLength, * bDescriptorType) -- used to walk the concatenated descriptor stream a * full Configuration descriptor read returns (Config + Interface + * Endpoint descriptors back to back), not just the Interface one. */ #define USB_DESC_OFF_LENGTH 0u #define USB_DESC_OFF_TYPE 1u #define USB_CONFIG_OFF_TOTAL_LENGTH 2u /* wTotalLength, 2 bytes, Configuration descriptor only */ #define USB_CONFIG_OFF_CONFIG_VALUE 5u /* bConfigurationValue -- the value SET_CONFIGURATION needs in wValue */ #define USB_DESC_TYPE_INTERFACE 4u #define USB_IFACE_OFF_CLASS 5u #define USB_IFACE_OFF_SUBCLASS 6u #define USB_IFACE_OFF_PROTOCOL 7u #define USB_CLASS_MASS_STORAGE 0x08u #define USB_SUBCLASS_SCSI 0x06u /* SCSI transparent command set */ #define USB_PROTOCOL_BOT 0x50u /* Bulk-Only Transport */ /* Standard USB Endpoint descriptor field offsets (7 bytes, USB 2.0 spec * table 9-13) -- found the same way as the Interface descriptor: walked * by bDescriptorType within the concatenated stream, not a fixed offset, * since the number of endpoints on the interface isn't known up front. */ #define USB_DESC_TYPE_ENDPOINT 5u #define USB_EP_OFF_ADDRESS 2u /* bEndpointAddress: bit 7 = direction, bits 3:0 = number */ #define USB_EP_OFF_ATTRIBUTES 3u /* bmAttributes: bits 1:0 = transfer type */ #define USB_EP_OFF_MAX_PACKET_SIZE 4u /* wMaxPacketSize, 2 bytes */ #define USB_EP_ADDR_DIR_MASK 0x80u #define USB_EP_ADDR_NUM_MASK 0x0Fu #define USB_EP_ATTR_TYPE_MASK 0x03u #define USB_EP_TYPE_BULK 0x02u /* Bulk-Only Transport Command Block Wrapper (USB Mass Storage Class Bulk- * Only Transport spec, section 5.1) -- sent host-to-device on the bulk OUT * endpoint ahead of every SCSI command's data phase. Fixed 31-byte wire * layout; every multi-byte field is little-endian, which this driver's * targets (amd64/aarch64/riscv64, all little-endian) already assume * throughout (no htole32-style conversions anywhere in this codebase) -- * direct field assignment is wire-correct as-is. sizeof() is NOT used as * this struct's DMA length anywhere (may be padded to 32 by the compiler * to satisfy the uint32_t members' alignment) -- USB_BOT_CBW_LENGTH (31) * is the correct, explicit wire length, matching the same * offset-constant-not-sizeof discipline already used for the USB * descriptor field offsets above. */ typedef struct { uint32_t dCBWSignature; uint32_t dCBWTag; uint32_t dCBWDataTransferLength; uint8_t bmCBWFlags; uint8_t bCBWLUN; uint8_t bCBWCBLength; uint8_t CBWCB[16]; } usb_bot_cbw_t; #define USB_BOT_CBW_SIGNATURE 0x43425355u /* "USBC", wire byte order U,S,B,C as an LE dword */ #define USB_BOT_CBW_LENGTH 31u #define USB_BOT_CBW_FLAG_DATA_IN 0x80u /* bmCBWFlags: device-to-host data stage */ #define USB_BOT_CBW_LUN_DEFAULT 0u /* no multi-LUN support -- single-LUN devices only */ #define SCSI_CMD_READ10 0x28u #define SCSI_CDB_LEN_READ10 10u /* SCSI WRITE(10) (SBC-3 section 5.32) -- direct mirror of READ(10): same * 10-byte CDB layout (opcode, LBA, transfer length), opposite data * direction (host -> device). See xhci_bot_send_write10()'s own doc * comment for the CBW-level difference (bmCBWFlags clears the DATA_IN * bit instead of setting it). */ #define SCSI_CMD_WRITE10 0x2Au #define SCSI_CDB_LEN_WRITE10 10u /* SCSI TEST UNIT READY (SPC-4 section 6.33) -- 6-byte CDB, all-zero apart * from the opcode, no data stage. Convention (not spec-mandated, but * standard SCSI target behavior): the first command a target sees after * attach fails with CHECK CONDITION/UNIT ATTENTION (media/reset notice), * clearing on the next command -- issuing this ahead of a real data * command and retrying it a bounded number of times on failure is the * standard way to drain that condition before trusting a READ/WRITE. */ #define SCSI_CMD_TEST_UNIT_READY 0x00u #define SCSI_CDB_LEN_TEST_UNIT_READY 6u /* Bounded retry count for SCSI TEST UNIT READY before giving up -- see * xhci_dev_t's bot_tur_retries doc comment. */ #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, * 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: * bytes 0-3 = Returned Logical Block Address (the *last* valid LBA, not a * block count) big-endian, bytes 4-7 = Block Length in Bytes big-endian. * This is Milestone 2h's prerequisite for everything else -- there is no * other way for this driver to learn a device's block size or capacity, * and block_subsystem.c's blk_subsys_attach_device() needs exactly that * (via blkio_info()) before it can do anything with a device. */ #define SCSI_CMD_READ_CAPACITY10 0x25u #define SCSI_CDB_LEN_READ_CAPACITY10 10u #define SCSI_READ_CAPACITY10_DATA_LEN 8u /* Bulk-Only Transport Command Status Wrapper (same spec, section 5.2) -- * received device-to-host on the bulk IN endpoint after the Data-In * stage, closing out every SCSI command. Fixed 13-byte wire layout; same * little-endian-direct-assignment and explicit-length-not-sizeof * discipline as usb_bot_cbw_t above (this struct's natural size is * likely padded to 16 by the compiler for the same alignment reason -- * USB_BOT_CSW_LENGTH (13) is the real wire length). */ typedef struct { uint32_t dCSWSignature; uint32_t dCSWTag; uint32_t dCSWDataResidue; uint8_t bCSWStatus; } usb_bot_csw_t; #define USB_BOT_CSW_SIGNATURE 0x53425355u /* "USBS", wire byte order U,S,B,S as an LE dword */ #define USB_BOT_CSW_LENGTH 13u #define USB_BOT_CSW_STATUS_PASS 0u #define USB_BOT_CSW_STATUS_FAILED 1u #define USB_BOT_CSW_STATUS_PHASE_ERROR 2u /* Command Completion Event TRB layout (xHCI 1.2 spec table 6-32): * parameter[63:4] = Command TRB Pointer, status[31:24] = Completion Code, * status[23:0] = unused here, control[31:24] = Slot ID (Enable Slot's * result, also present on Address Device completions). */ #define XHCI_EVT_COMPLETION_CODE(status) (((uint32_t)(status) >> 24) & 0xFFu) #define XHCI_EVT_SLOT_ID(control) (((uint32_t)(control) >> 24) & 0xFFu) #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): * parameter[31:24] = Port ID (1-based, matches PORTSC array indexing * 1..MaxPorts); parameter[23:0] and the rest of the TRB are reserved. */ #define XHCI_PSC_EVT_PORT_ID(parameter) (((uint32_t)(parameter) >> 24) & 0xFFu) /* ------------------------------------------------------------------------- * Slot Context, Endpoint Context, Input Control Context — 32-byte layout * only (xHCI 1.2 spec tables 6-6, 6-9, 6-5). HCCPARAMS1.CSZ selects 32- vs * 64-byte contexts; confirmed live (CSZ=0) against this driver's target * QEMU qemu-xhci controller (2026-08-22) before writing these -- 64-byte * contexts (CSZ=1) are NOT implemented here. xhci_cmd_address_device() * checks CSZ itself and refuses rather than silently mis-laying-out a * 64-byte-context controller as 32-byte. * ------------------------------------------------------------------------- */ typedef struct { volatile uint32_t dword0; /* Route String[19:0] Speed[23:20] MTT[25] Hub[26] Context Entries[31:27] */ volatile uint32_t dword1; /* Max Exit Latency[15:0] Root Hub Port Number[23:16] Number of Ports[31:24] */ volatile uint32_t dword2; /* Parent Hub Slot ID[7:0] Parent Port Number[15:8] TTT[17:16] Interrupter Target[31:22] */ volatile uint32_t dword3; /* USB Device Address[7:0] Slot State[31:27] */ volatile uint32_t reserved[4]; } xhci_slot_ctx32_t; #define XHCI_SLOT_CTX_SPEED_SHIFT 20 #define XHCI_SLOT_CTX_CONTEXT_ENTRIES_SHIFT 27 #define XHCI_SLOT_CTX_ROOT_PORT_SHIFT 16 #define XHCI_SLOT_CTX_INTR_TARGET_SHIFT 22 typedef struct { volatile uint32_t dword0; /* EP State[2:0] Interval[23:16] */ volatile uint32_t dword1; /* CErr[2:1] EP Type[5:3] Max Packet Size[31:16] */ volatile uint64_t tr_dequeue_ptr; /* [0]=DCS (Dequeue Cycle State), [63:4]=pointer */ volatile uint32_t dword4; /* Average TRB Length[15:0] */ volatile uint32_t reserved[3]; } xhci_ep_ctx32_t; #define XHCI_EP_CTX_TYPE_SHIFT 3 #define XHCI_EP_CTX_TYPE_CONTROL_BIDI 4u /* EP0 */ #define XHCI_EP_CTX_TYPE_BULK_OUT 2u /* xHCI 1.2 spec table 6-9 */ #define XHCI_EP_CTX_TYPE_BULK_IN 6u #define XHCI_EP_CTX_CERR_SHIFT 1 #define XHCI_EP_CTX_MAX_PACKET_SHIFT 16 /* Device Context Index (DCI) for a given endpoint, xHCI 1.2 spec section * 4.5.1: DCI = 2*EndpointNumber + Direction (Direction=1 for IN, 0 for * OUT/control) -- EP0 is always DCI 1 regardless of direction, a special * case this macro does not need to handle since EP0's DCI is hardcoded * (XHCI_INPUT_CTRL_ADD_EP0's bit position) everywhere it's used. Takes a * full bEndpointAddress (bit 7 = direction, bits 3:0 = number), matching * how bulk_in_ep_addr/bulk_out_ep_addr are stored. */ #define XHCI_EP_ADDR_TO_DCI(addr) \ ((2u * ((uint32_t)(addr) & USB_EP_ADDR_NUM_MASK)) + \ (((uint32_t)(addr) & USB_EP_ADDR_DIR_MASK) ? 1u : 0u)) typedef struct { volatile uint32_t drop_flags; /* D0..D31 -- unused for Address Device (nothing to drop) */ volatile uint32_t add_flags; /* A0..A31 -- bit0=Slot, bit1=EP0 for Address Device */ volatile uint32_t reserved[5]; volatile uint32_t config_word; /* Configuration Value/Interface/AltSetting -- unused here */ } xhci_input_ctrl_ctx32_t; #define XHCI_INPUT_CTRL_ADD_SLOT (1u << 0) #define XHCI_INPUT_CTRL_ADD_EP0 (1u << 1) /* ------------------------------------------------------------------------- * Ring sizing — decided up front per Milestone 2's punch list (2a). * * Fixed, single-page rings: 256 TRBs x 16 bytes = 4096 bytes = one page. * This project's usage (MSC hotplug detection + read/write to one drive at * a time) does not need a high-throughput, dynamically-growable ring — * matches this codebase's existing preference for fixed, page-sized * allocations over dynamic growth (e.g. KRD_MAX_BLOCKS's fixed 1024-block * RAMDRIVE). One Command Ring, one Event Ring (Interrupter 0 only — this * driver does not use multiple interrupters). * ------------------------------------------------------------------------- */ #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 * no real or QEMU-emulated root hub this driver targets comes close to * that; 32 is comfortably generous and keeps this a fixed, not * heap-allocated, array. */ #define XHCI_MAX_TRACKED_PORTS 32u #endif /* STARKERNEL_XHCI_H */