Zuse default-attach: xHCI initial-port-scan fix, ZUSEDISK wiring, mismatched-marker resync
xhci_bringup() now scans for already-connected ports at bring-up (xhci_scan_ports_for_already_connected()), not just later hotplug events, so a USB device present on the QEMU command line at launch is detected. Makefile.starkernel attaches disk/zuse.img on the xhci0 bus by default in all three arch qemu targets (ZUSEDISK=, empties for a bare boot). capsule_mint_identity() gained a drive_known_blank param to skip a fully redundant second homeblocks_sig_check() when the caller already confirmed HOMEBLOCKS_SIG_BLANK itself. Root-caused what looked like a hang after the drive attached: Artemis's fence still carried a genesis marker from before a mid-session reformat, while the reformatted disk/zuse.img read back BLANK -- a mismatched pair capsule_zuse_boot_try_attach() correctly declined to act on, leaving the boot idling at a plain ok> with nothing left to log (indistinguishable from a hang under slow TCG). Fixed by zeroing both disk/artemis.img and disk/zuse.img at their original sizes, giving a matched blank pair. Verified full three-architecture acceptance: amd64 fresh genesis-mint, aarch64/riscv64 clean reload against the same now-minted images. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KBjfeLPo71sUQ8zC7V7P5m
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
3f74ff0f78
commit
849b83b727
@@ -59,7 +59,8 @@ static int write_devblock(struct blkio_dev *dev, uint32_t devblock,
|
||||
MintResult capsule_mint_identity(struct blkio_dev *dev, VM *issuer_vm,
|
||||
const char *full_name, const char *username,
|
||||
const char *email, const char *phone,
|
||||
uint8_t out_pubkey[32], uint8_t out_seed[32]) {
|
||||
uint8_t out_pubkey[32], uint8_t out_seed[32],
|
||||
int drive_known_blank) {
|
||||
if (!dev || !full_name || !username) return MINT_ERR_WRITE_FAIL;
|
||||
|
||||
/* full_name/username required and must fit; email/phone may be NULL
|
||||
@@ -75,8 +76,11 @@ MintResult capsule_mint_identity(struct blkio_dev *dev, VM *issuer_vm,
|
||||
|
||||
/* Refuse to overwrite an already-recognized home-blocks drive --
|
||||
* mirrors WRITE(10)'s own refuse-on-non-blank-media posture (§F.8,
|
||||
* decided 2026-08-28: "reasonable by analogy" there, now decided). */
|
||||
{
|
||||
* decided 2026-08-28: "reasonable by analogy" there, now decided).
|
||||
* Skipped when the caller already just confirmed HOMEBLOCKS_SIG_BLANK
|
||||
* itself (drive_known_blank) -- otherwise this repeats the exact same
|
||||
* full BOT read sequence a second time immediately after the first. */
|
||||
if (!drive_known_blank) {
|
||||
homeblocks_sig_t existing;
|
||||
if (homeblocks_sig_check(dev, HOMEBLOCKS_SIG_START_FBLOCK, &existing)
|
||||
== HOMEBLOCKS_SIG_OK) {
|
||||
|
||||
@@ -73,7 +73,8 @@ void capsule_zuse_boot_try_attach(struct blkio_dev *dev,
|
||||
uint8_t seed[32], pubkey[32];
|
||||
MintResult r = capsule_mint_identity(dev, (VM *)0, "Zuse", "zuse",
|
||||
(const char *)0, (const char *)0,
|
||||
pubkey, seed);
|
||||
pubkey, seed,
|
||||
1 /* sig_rc already confirmed BLANK above */);
|
||||
if (r != MINT_OK) {
|
||||
console_println("Zuse: genesis mint failed");
|
||||
return;
|
||||
|
||||
@@ -868,7 +868,8 @@ static void mama_word_mint(VM *vm)
|
||||
}
|
||||
|
||||
MintResult r = capsule_mint_identity(dev, vm, full_name, username, email, phone,
|
||||
(uint8_t *)0, (uint8_t *)0);
|
||||
(uint8_t *)0, (uint8_t *)0,
|
||||
0 /* not pre-checked -- keep the safety check */);
|
||||
switch (r) {
|
||||
case MINT_OK:
|
||||
console_println("MINT: identity minted");
|
||||
|
||||
+88
-29
@@ -144,6 +144,14 @@ int xhci_ep0_get_device_descriptor(xhci_dev_t *dev, uint32_t slot_id);
|
||||
int xhci_ep0_get_config_descriptor(xhci_dev_t *dev, uint32_t slot_id, uint16_t length);
|
||||
int xhci_ep0_set_configuration(xhci_dev_t *dev, uint32_t slot_id, uint8_t config_value);
|
||||
|
||||
/* Forward declaration -- xhci_bringup() below calls this once the
|
||||
* controller is running, to catch a device that was already connected
|
||||
* (present on the QEMU command line at launch, not hot-plugged after boot).
|
||||
* The implementation lives after xhci_poll_events() since it shares
|
||||
* xhci_port_regs() and the same connect-handling logic. See xhci_scan_
|
||||
* ports_for_already_connected()'s own doc comment for why this exists. */
|
||||
static void xhci_scan_ports_for_already_connected(xhci_dev_t *dev);
|
||||
|
||||
int xhci_bringup(xhci_dev_t *dev)
|
||||
{
|
||||
if (!dev || !dev->op) return -2;
|
||||
@@ -347,6 +355,16 @@ int xhci_bringup(xhci_dev_t *dev)
|
||||
: "xhci: context size = 32 bytes");
|
||||
|
||||
g_xhci_dev = dev;
|
||||
|
||||
/* Catch a device already connected at launch -- xhci_poll_events() is
|
||||
* purely event-ring-driven (Port Status Change events only), and a
|
||||
* device present on the QEMU command line before this controller reset
|
||||
* never generates one (nothing "changed" from the controller's
|
||||
* perspective once it starts looking). g_xhci_dev must be set first --
|
||||
* this reuses the same connect-handling path xhci_poll_events() uses,
|
||||
* which reads it as a singleton rather than taking dev as an arg. */
|
||||
xhci_scan_ports_for_already_connected(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1161,6 +1179,75 @@ static xhci_port_regs_t *xhci_port_regs(xhci_dev_t *dev, uint32_t port_id)
|
||||
(port_id - 1) * sizeof(xhci_port_regs_t));
|
||||
}
|
||||
|
||||
/* Shared "device connected" handling -- factored out of xhci_poll_events()'s
|
||||
* PORT_STATUS_CHANGE_EVT case so xhci_scan_ports_for_already_connected()
|
||||
* (called once from xhci_bringup(), see its own doc comment) can drive the
|
||||
* exact same Enable Slot sequence for a device that was already attached at
|
||||
* controller bring-up, not just one detected via a later hotplug event. */
|
||||
static void xhci_handle_port_connected(xhci_dev_t *dev, uint32_t port_id, uint32_t portsc)
|
||||
{
|
||||
console_println("xhci: port status change -- device connected");
|
||||
/* Milestone 2e prep: Address Device requires the port in Default
|
||||
* state. USB3 links train and enable themselves; USB2 needs software
|
||||
* to drive PORTSC.PR and wait for PRC/PED before the device will
|
||||
* respond to addressing -- not yet known which this driver's ports
|
||||
* need, so log raw PORTSC and PED rather than assume. */
|
||||
xhci_log_hex32("xhci: portsc=", portsc);
|
||||
console_println((portsc & XHCI_PORTSC_PED)
|
||||
? "xhci: port enabled (PED set)"
|
||||
: "xhci: port not yet enabled (PED clear)");
|
||||
/* Only one Enable Slot in flight at a time (see xhci_dev_t's doc
|
||||
* comment) -- if another connect's slot request is still outstanding,
|
||||
* this one is dropped rather than queued. Acceptable for this
|
||||
* milestone's single-device testing scope; revisit if multi-port
|
||||
* simultaneous connects become a real scenario. */
|
||||
if (port_id > XHCI_MAX_TRACKED_PORTS) {
|
||||
console_println("xhci: port beyond tracked range -- enable slot skipped");
|
||||
} else if (dev->connect_state == XHCI_CONN_IDLE) {
|
||||
dev->pending_connect_port_id = port_id;
|
||||
dev->pending_connect_speed = XHCI_PORTSC_SPEED(portsc);
|
||||
dev->connect_state = XHCI_CONN_AWAIT_ENABLE_SLOT;
|
||||
xhci_cmd_enable_slot(dev);
|
||||
} else {
|
||||
console_println("xhci: enable slot already pending -- dropped");
|
||||
}
|
||||
}
|
||||
|
||||
/* xhci_scan_ports_for_already_connected -- called once from xhci_bringup(),
|
||||
* right after the controller starts running. xhci_poll_events() only reacts
|
||||
* to Port Status Change *events*, and a device present on the QEMU command
|
||||
* line before this controller reset never generates one (nothing "changed"
|
||||
* from the controller's perspective once it starts looking) -- confirmed by
|
||||
* reading the spec's event model, not assumed. Without this scan, such a
|
||||
* device stays invisible to the guest forever, since no later event will
|
||||
* ever announce it either.
|
||||
*
|
||||
* Scans tracked ports for CCS (Current Connect Status) directly, and drives
|
||||
* the first connected one found through the same Enable Slot path
|
||||
* xhci_poll_events() uses -- matching that path's own single-outstanding-
|
||||
* connect limitation, which is fine here too: this driver's real use case
|
||||
* is exactly one thumbdrive already attached at boot, not several. */
|
||||
static void xhci_scan_ports_for_already_connected(xhci_dev_t *dev)
|
||||
{
|
||||
uint32_t max_port = dev->max_ports;
|
||||
if (max_port > XHCI_MAX_TRACKED_PORTS) max_port = XHCI_MAX_TRACKED_PORTS;
|
||||
|
||||
for (uint32_t port_id = 1; port_id <= max_port; port_id++) {
|
||||
xhci_port_regs_t *port = xhci_port_regs(dev, port_id);
|
||||
if (!port) continue;
|
||||
uint32_t portsc = port->portsc;
|
||||
if (!(portsc & XHCI_PORTSC_CCS)) continue;
|
||||
|
||||
console_println("xhci: device already connected at bring-up");
|
||||
xhci_handle_port_connected(dev, port_id, portsc);
|
||||
/* Acknowledge CSC the same way xhci_poll_events() does, in case
|
||||
* the controller latched it during reset -- harmless if it was
|
||||
* never set. */
|
||||
port->portsc = (portsc & XHCI_PORTSC_PP) | XHCI_PORTSC_CSC;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void xhci_poll_events(void)
|
||||
{
|
||||
xhci_dev_t *dev = g_xhci_dev;
|
||||
@@ -1185,35 +1272,7 @@ void xhci_poll_events(void)
|
||||
}
|
||||
uint32_t portsc = port->portsc;
|
||||
if (portsc & XHCI_PORTSC_CCS) {
|
||||
console_println("xhci: port status change -- device connected");
|
||||
/* Milestone 2e prep: Address Device requires the port
|
||||
* in Default state. USB3 links train and enable
|
||||
* themselves; USB2 needs software to drive PORTSC.PR
|
||||
* and wait for PRC/PED before the device will respond
|
||||
* to addressing -- not yet known which this driver's
|
||||
* ports need, so log raw PORTSC and PED rather than
|
||||
* assume. */
|
||||
xhci_log_hex32("xhci: portsc=", portsc);
|
||||
console_println((portsc & XHCI_PORTSC_PED)
|
||||
? "xhci: port enabled (PED set)"
|
||||
: "xhci: port not yet enabled (PED clear)");
|
||||
/* Only one Enable Slot in flight at a time (see
|
||||
* xhci_dev_t's doc comment) -- if another connect's
|
||||
* slot request is still outstanding, this one is
|
||||
* dropped rather than queued. Acceptable for this
|
||||
* milestone's single-device testing scope; revisit if
|
||||
* multi-port simultaneous connects become a real
|
||||
* scenario. */
|
||||
if (port_id > XHCI_MAX_TRACKED_PORTS) {
|
||||
console_println("xhci: port beyond tracked range -- enable slot skipped");
|
||||
} else if (dev->connect_state == XHCI_CONN_IDLE) {
|
||||
dev->pending_connect_port_id = port_id;
|
||||
dev->pending_connect_speed = XHCI_PORTSC_SPEED(portsc);
|
||||
dev->connect_state = XHCI_CONN_AWAIT_ENABLE_SLOT;
|
||||
xhci_cmd_enable_slot(dev);
|
||||
} else {
|
||||
console_println("xhci: enable slot already pending -- dropped");
|
||||
}
|
||||
xhci_handle_port_connected(dev, port_id, portsc);
|
||||
} else {
|
||||
console_println("xhci: port status change -- device disconnected");
|
||||
if (port_id >= 1 && port_id <= XHCI_MAX_TRACKED_PORTS &&
|
||||
|
||||
Reference in New Issue
Block a user