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
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
5970c54912
commit
c2f1d94c97
@@ -1,5 +1,5 @@
|
||||
# Capsule Block Manifest — Auto-generated
|
||||
<!-- Generated by mkcapsule --manifest 2026-08-22T11:56:55Z -->
|
||||
<!-- Generated by mkcapsule --manifest 2026-08-22T12:20:25Z -->
|
||||
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
||||
<!-- Hand-written justifications and immutability notes live -->
|
||||
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -55,6 +55,13 @@ typedef struct {
|
||||
#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))
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Operational Registers (BAR0 + cap_length)
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
@@ -24,6 +24,16 @@ typedef struct {
|
||||
uint32_t max_slots;
|
||||
uint32_t max_ports;
|
||||
uint32_t max_intrs;
|
||||
uint32_t max_scratchpad_bufs;
|
||||
|
||||
/* Set up by xhci_bringup(); NULL/0 until then. */
|
||||
void *dcbaa; /* Device Context Base Address Array */
|
||||
void *scratchpad_arr; /* array of scratchpad buffer pointers, if any */
|
||||
xhci_trb_t *cmd_ring; /* Command Ring, XHCI_RING_TRB_COUNT TRBs */
|
||||
uint32_t cmd_ring_cycle; /* current Command Ring Cycle State (RCS) */
|
||||
xhci_trb_t *evt_ring; /* Event Ring, XHCI_RING_TRB_COUNT TRBs */
|
||||
void *evt_ring_seg_table; /* Event Ring Segment Table (1 entry) */
|
||||
uint32_t evt_ring_cycle; /* current Event Ring Cycle State */
|
||||
} xhci_dev_t;
|
||||
|
||||
/*
|
||||
@@ -39,4 +49,21 @@ typedef struct {
|
||||
*/
|
||||
int xhci_find_and_map(xhci_dev_t *dev);
|
||||
|
||||
/*
|
||||
* xhci_bringup — reset the controller, allocate and program the DCBAA,
|
||||
* Command Ring, and Event Ring (Interrupter 0), then start
|
||||
* the controller (RUN/STOP=1) and confirm it left the
|
||||
* halted state.
|
||||
*
|
||||
* Must be called after a successful xhci_find_and_map(). Does not enable
|
||||
* interrupts (USBCMD.INTE / IMAN.IE) — that's wired in a later increment
|
||||
* alongside the actual interrupt handler.
|
||||
*
|
||||
* Returns 0 on success.
|
||||
* Returns -1 on reset timeout.
|
||||
* Returns -2 on allocation failure.
|
||||
* Returns -3 if the controller failed to leave the halted state after RUN.
|
||||
*/
|
||||
int xhci_bringup(xhci_dev_t *dev);
|
||||
|
||||
#endif /* STARKERNEL_XHCI_DRIVER_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -59,7 +59,7 @@
|
||||
#include "freestanding/stdio.h"
|
||||
#include "word_registry.h"
|
||||
|
||||
int g_doe_log_enabled = 1;
|
||||
int g_doe_log_enabled = 0; /* off by default -- HB-ON to enable, per instruction */
|
||||
|
||||
#define DOE_PREFIX "\x1b[36m[HADES][DOE ]\x1b[0m "
|
||||
#define DOE_BUF_SIZE 512
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include "starkernel/pci.h"
|
||||
#include "starkernel/xhci.h"
|
||||
#include "starkernel/xhci_driver.h"
|
||||
#include "starkernel/kmalloc.h"
|
||||
#include "starkernel/timer.h"
|
||||
#include "console.h"
|
||||
|
||||
/* Conservative fixed BAR0 mapping size. xHCI has no self-describing
|
||||
@@ -64,7 +66,162 @@ int xhci_find_and_map(xhci_dev_t *dev)
|
||||
dev->max_slots = XHCI_HCSPARAMS1_MAX_SLOTS(hcs1);
|
||||
dev->max_intrs = XHCI_HCSPARAMS1_MAX_INTRS(hcs1);
|
||||
dev->max_ports = XHCI_HCSPARAMS1_MAX_PORTS(hcs1);
|
||||
dev->max_scratchpad_bufs = XHCI_HCSPARAMS2_MAX_SCRATCHPAD_BUFS(dev->cap->hcs_params2);
|
||||
|
||||
console_println("xhci: controller found, BAR0 mapped");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Spin-count-bounded busy-wait, matching kernel_main.c's established
|
||||
* pattern (heartbeat_ticks() elapsed + a hard spin-count safety cap, not
|
||||
* just one or the other). Polls *reg for (val & mask) to equal want_set
|
||||
* (0 or 1), re-reading the register itself each iteration. */
|
||||
static int xhci_wait_bit(volatile uint32_t *reg, uint32_t mask, int want_set,
|
||||
uint64_t max_ticks)
|
||||
{
|
||||
uint64_t start = heartbeat_ticks();
|
||||
uint64_t spins = 0;
|
||||
for (;;) {
|
||||
uint32_t val = *reg;
|
||||
int is_set = (val & mask) != 0;
|
||||
if (is_set == want_set) return 0;
|
||||
spins++;
|
||||
if (heartbeat_ticks() - start >= max_ticks || spins >= 100000000ULL) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int xhci_bringup(xhci_dev_t *dev)
|
||||
{
|
||||
if (!dev || !dev->op) return -2;
|
||||
|
||||
/* 1. If running, stop first (Run/Stop must be cleared before HCRST is
|
||||
* guaranteed to behave per spec on some implementations). */
|
||||
if (dev->op->usb_cmd & XHCI_USBCMD_RUN) {
|
||||
dev->op->usb_cmd &= ~XHCI_USBCMD_RUN;
|
||||
if (xhci_wait_bit(&dev->op->usb_sts, XHCI_USBSTS_HCH, 1, 10000) != 0) {
|
||||
console_println("xhci: timeout waiting for halt before reset");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 2. Host Controller Reset. HCRST self-clears; CNR (Controller Not
|
||||
* Ready) must also clear before touching any other operational
|
||||
* register. */
|
||||
dev->op->usb_cmd |= XHCI_USBCMD_HCRST;
|
||||
if (xhci_wait_bit(&dev->op->usb_cmd, XHCI_USBCMD_HCRST, 0, 10000) != 0) {
|
||||
console_println("xhci: timeout waiting for HCRST to self-clear");
|
||||
return -1;
|
||||
}
|
||||
if (xhci_wait_bit(&dev->op->usb_sts, XHCI_USBSTS_CNR, 0, 10000) != 0) {
|
||||
console_println("xhci: timeout waiting for CNR to clear");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 3. Device Context Base Address Array — (max_slots+1) x 8-byte
|
||||
* pointers, 64-byte aligned, zeroed (DCBAAP requires 64-byte
|
||||
* alignment per spec; kmalloc_aligned enforces it). */
|
||||
size_t dcbaa_bytes = (size_t)(dev->max_slots + 1) * sizeof(uint64_t);
|
||||
dev->dcbaa = kmalloc_aligned(dcbaa_bytes, 64);
|
||||
if (!dev->dcbaa) {
|
||||
console_println("xhci: DCBAA allocation failed");
|
||||
return -2;
|
||||
}
|
||||
for (size_t i = 0; i < dcbaa_bytes / sizeof(uint64_t); i++) {
|
||||
((uint64_t *)dev->dcbaa)[i] = 0;
|
||||
}
|
||||
|
||||
/* 3b. Scratchpad buffers, only if the controller asks for them (slot 0
|
||||
* of the DCBAA points at the scratchpad buffer array, not a device
|
||||
* context, when max_scratchpad_bufs > 0). PAGESIZE register: bit N
|
||||
* set means 2^(N+12)-byte pages; use the lowest set bit found. */
|
||||
if (dev->max_scratchpad_bufs > 0) {
|
||||
uint32_t pagesize_bits = dev->op->page_size;
|
||||
uint32_t page_bytes = 4096u;
|
||||
for (uint32_t b = 0; b < 16; b++) {
|
||||
if (pagesize_bits & (1u << b)) { page_bytes = 1u << (b + 12); break; }
|
||||
}
|
||||
size_t arr_bytes = (size_t)dev->max_scratchpad_bufs * sizeof(uint64_t);
|
||||
dev->scratchpad_arr = kmalloc_aligned(arr_bytes, 64);
|
||||
if (!dev->scratchpad_arr) {
|
||||
console_println("xhci: scratchpad array allocation failed");
|
||||
return -2;
|
||||
}
|
||||
for (uint32_t i = 0; i < dev->max_scratchpad_bufs; i++) {
|
||||
void *buf = kmalloc_aligned(page_bytes, page_bytes);
|
||||
if (!buf) {
|
||||
console_println("xhci: scratchpad buffer allocation failed");
|
||||
return -2;
|
||||
}
|
||||
((uint64_t *)dev->scratchpad_arr)[i] = (uint64_t)(uintptr_t)buf;
|
||||
}
|
||||
((uint64_t *)dev->dcbaa)[0] = (uint64_t)(uintptr_t)dev->scratchpad_arr;
|
||||
}
|
||||
|
||||
dev->op->dcbaap = (uint64_t)(uintptr_t)dev->dcbaa;
|
||||
|
||||
/* 4. Command Ring — XHCI_RING_TRB_COUNT TRBs, 64-byte aligned, zeroed.
|
||||
* Initial Ring Cycle State = 1 (software convention; the ring is
|
||||
* "owned" by software until the first TRB with a matching cycle bit
|
||||
* is consumed). CRCR low bits carry RCS, not the TRBs themselves. */
|
||||
dev->cmd_ring = (xhci_trb_t *)kmalloc_aligned(XHCI_RING_BYTES, 64);
|
||||
if (!dev->cmd_ring) {
|
||||
console_println("xhci: command ring allocation failed");
|
||||
return -2;
|
||||
}
|
||||
for (uint32_t i = 0; i < XHCI_RING_TRB_COUNT; i++) {
|
||||
dev->cmd_ring[i].parameter = 0;
|
||||
dev->cmd_ring[i].status = 0;
|
||||
dev->cmd_ring[i].control = 0;
|
||||
}
|
||||
dev->cmd_ring_cycle = 1;
|
||||
dev->op->crcr = ((uint64_t)(uintptr_t)dev->cmd_ring & XHCI_CRCR_PTR_MASK) |
|
||||
XHCI_CRCR_RCS;
|
||||
|
||||
/* 5. Event Ring — one segment (Event Ring Segment Table with a single
|
||||
* 16-byte entry: base address + size), wired to Interrupter 0.
|
||||
* Interrupter Register Sets start at runtime_base + 0x20; each is
|
||||
* sizeof(xhci_intr_regs_t) apart, but only Interrupter 0 is used
|
||||
* (single-interrupter design decided in 2a). */
|
||||
dev->evt_ring = (xhci_trb_t *)kmalloc_aligned(XHCI_RING_BYTES, 64);
|
||||
if (!dev->evt_ring) {
|
||||
console_println("xhci: event ring allocation failed");
|
||||
return -2;
|
||||
}
|
||||
for (uint32_t i = 0; i < XHCI_RING_TRB_COUNT; i++) {
|
||||
dev->evt_ring[i].parameter = 0;
|
||||
dev->evt_ring[i].status = 0;
|
||||
dev->evt_ring[i].control = 0;
|
||||
}
|
||||
dev->evt_ring_cycle = 1;
|
||||
|
||||
/* Event Ring Segment Table entry layout: u64 base + u32 size + u32
|
||||
* reserved = 16 bytes. One segment is enough (ERST Max >= 1 always). */
|
||||
dev->evt_ring_seg_table = kmalloc_aligned(16, 64);
|
||||
if (!dev->evt_ring_seg_table) {
|
||||
console_println("xhci: event ring segment table allocation failed");
|
||||
return -2;
|
||||
}
|
||||
uint64_t *erst = (uint64_t *)dev->evt_ring_seg_table;
|
||||
erst[0] = (uint64_t)(uintptr_t)dev->evt_ring; /* base address */
|
||||
erst[1] = (uint64_t)XHCI_RING_TRB_COUNT; /* size, low 32 bits used */
|
||||
|
||||
xhci_intr_regs_t *intr0 = (xhci_intr_regs_t *)((uint8_t *)dev->runtime + 0x20);
|
||||
intr0->erstsz = 1;
|
||||
intr0->erstba = (uint64_t)(uintptr_t)dev->evt_ring_seg_table;
|
||||
intr0->erdp = ((uint64_t)(uintptr_t)dev->evt_ring & XHCI_ERDP_PTR_MASK);
|
||||
|
||||
/* 6. Enable device slots (all of them — no reason to restrict for a
|
||||
* single-drive-at-a-time driver) and start the controller. */
|
||||
dev->op->config = XHCI_CONFIG_MAX_SLOTS_EN(dev->max_slots);
|
||||
dev->op->usb_cmd |= XHCI_USBCMD_RUN;
|
||||
|
||||
if (xhci_wait_bit(&dev->op->usb_sts, XHCI_USBSTS_HCH, 0, 10000) != 0) {
|
||||
console_println("xhci: controller did not leave halted state after RUN");
|
||||
return -3;
|
||||
}
|
||||
|
||||
console_println("xhci: controller running");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user