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
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
b9c540a78b
commit
b4bbd043d0
+25
-2
@@ -3334,8 +3334,8 @@ command, DCBAA entry clear), and the callback surface into Section U's higher-le
|
||||
to, Section U item 7's foreign-drive/home-blocks-signature check, which happens one
|
||||
layer up, after the drive is already known to be USB mass storage) — **done
|
||||
2026-08-25**, see writeup below
|
||||
- [ ] Set the device configuration (SET_CONFIGURATION control transfer) — still open, last
|
||||
item before 2g's bulk transfers are possible
|
||||
- [x] Set the device configuration (SET_CONFIGURATION control transfer) — **done 2026-08-25**,
|
||||
see writeup below. **2f is now fully complete** — 2g (Bulk-Only Transport) can start.
|
||||
|
||||
**Device descriptor request, done 2026-08-22.** Extends the EP0 Transfer Ring built in 2e's
|
||||
Address Device work with real control-transfer submission: a new `xhci_ep0_enqueue_trb()`
|
||||
@@ -3391,6 +3391,29 @@ Verified live via QMP hotplug, all three architectures, byte-identical results e
|
||||
also confirmed clean on every arch — no wedge, matches 2e's existing disconnect discipline.
|
||||
`logs/20260825-071717/amd64/`, `logs/20260825-072116/aarch64/`, `logs/20260825-072329/riscv64/`.
|
||||
|
||||
**SET_CONFIGURATION, done 2026-08-25 — 2f complete.** Chains directly off a confirmed Mass
|
||||
Storage/SCSI/BOT interface match in the `XHCI_XFER_CONFIG_DESC_FULL` handler, via the same
|
||||
`next_action` deferral mechanism as the earlier chains (device descriptor → config descriptor
|
||||
→ set configuration is now a single automatic sequence with no manual steps in between).
|
||||
`bConfigurationValue` (offset 5 in the Configuration descriptor, `USB_CONFIG_OFF_CONFIG_VALUE`)
|
||||
is read directly out of the already-fetched `dev->config_descriptor` — no extra transfer
|
||||
needed to learn it.
|
||||
|
||||
Structurally this is the first *write* control transfer this driver has issued — every prior
|
||||
one (device descriptor, config descriptor) was a read. SET_CONFIGURATION has no Data Stage at
|
||||
all (`wLength=0`), so it needed its own submission helper, `xhci_ep0_control_write_nodata()`,
|
||||
alongside the existing `xhci_ep0_control_read()`: Setup Stage TRT = `XHCI_SETUP_TRT_NO_DATA`
|
||||
(the constant already existed in `xhci.h`, unused until now), and — per USB 2.0 spec §8.5.3,
|
||||
"if there is no Data stage, the Status stage is always an IN transaction" — the Status Stage
|
||||
TRB gets `DIR_IN` set, the reverse of what a normal OUT-data request's status stage would use.
|
||||
That's a real, spec-mandated asymmetry, not a copy-paste of the read helper's status stage.
|
||||
|
||||
Verified live via QMP hotplug, all three architectures, worked first try, byte-identical
|
||||
results: `xhci: set configuration submitted` → `xhci: device configured`, guest stays
|
||||
`running` (checked via QMP `query-status`) throughout. Disconnect confirmed clean on every
|
||||
arch afterward, no wedge. `logs/20260825-073235/amd64/`, `logs/20260825-073417/aarch64/`,
|
||||
`logs/20260825-073728/riscv64/`.
|
||||
|
||||
**2g. Bulk-Only Transport (BOT) — the actual read/write path**
|
||||
- [ ] Identify and configure the device's bulk IN and bulk OUT endpoints
|
||||
- [ ] Implement CBW (Command Block Wrapper) construction and send, for a SCSI READ(10)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Capsule Block Manifest — Auto-generated
|
||||
<!-- Generated by mkcapsule --manifest 2026-08-25T11:23:25Z -->
|
||||
<!-- Generated by mkcapsule --manifest 2026-08-25T11:37:26Z -->
|
||||
<!-- 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.
@@ -229,10 +229,12 @@ typedef struct {
|
||||
uint16_t wLength;
|
||||
} usb_setup_packet_t;
|
||||
|
||||
#define USB_REQ_GET_DESCRIPTOR 6u
|
||||
#define USB_DESC_TYPE_DEVICE 1u
|
||||
#define USB_DESC_TYPE_CONFIG 2u
|
||||
#define USB_DIR_DEVICE_TO_HOST 0x80u
|
||||
#define USB_REQ_GET_DESCRIPTOR 6u
|
||||
#define USB_REQ_SET_CONFIGURATION 9u
|
||||
#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 Interface descriptor field offsets (9 bytes, USB 2.0 spec
|
||||
* table 9-12) -- Mass Storage class detection reads these three fields.
|
||||
@@ -249,6 +251,7 @@ typedef struct {
|
||||
#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
|
||||
|
||||
@@ -99,7 +99,8 @@ typedef struct {
|
||||
XHCI_XFER_NONE = 0,
|
||||
XHCI_XFER_DEVICE_DESC,
|
||||
XHCI_XFER_CONFIG_DESC_SHORT,
|
||||
XHCI_XFER_CONFIG_DESC_FULL
|
||||
XHCI_XFER_CONFIG_DESC_FULL,
|
||||
XHCI_XFER_SET_CONFIG
|
||||
} transfer_purpose;
|
||||
uint32_t pending_transfer_slot_id;
|
||||
uint8_t device_descriptor[18];
|
||||
@@ -120,10 +121,14 @@ typedef struct {
|
||||
enum {
|
||||
XHCI_NEXT_ACTION_NONE = 0,
|
||||
XHCI_NEXT_ACTION_GET_DEVICE_DESC,
|
||||
XHCI_NEXT_ACTION_GET_CONFIG_DESC
|
||||
XHCI_NEXT_ACTION_GET_CONFIG_DESC,
|
||||
XHCI_NEXT_ACTION_SET_CONFIG
|
||||
} next_action;
|
||||
uint32_t next_action_slot_id;
|
||||
uint16_t next_action_length;
|
||||
uint8_t next_action_config_value; /* SET_CONFIGURATION's wValue, staged by
|
||||
* the CONFIG_DESC_FULL handler once
|
||||
* bConfigurationValue is known */
|
||||
} xhci_dev_t;
|
||||
|
||||
/*
|
||||
@@ -267,4 +272,22 @@ 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);
|
||||
|
||||
/*
|
||||
* xhci_ep0_set_configuration — issue a SET_CONFIGURATION control transfer
|
||||
* (Setup + Status stage only, no Data stage)
|
||||
* with wValue = config_value. Moves the
|
||||
* device from Addressed into Configured
|
||||
* state -- required before any endpoint
|
||||
* other than EP0 (i.e. the bulk IN/OUT
|
||||
* endpoints 2g needs) can be used.
|
||||
*
|
||||
* Called once the Configuration descriptor read confirms a Mass Storage/
|
||||
* SCSI/BOT device, with config_value = that descriptor's own
|
||||
* bConfigurationValue field -- 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_set_configuration(xhci_dev_t *dev, uint32_t slot_id, uint8_t config_value);
|
||||
|
||||
#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
@@ -130,6 +130,7 @@ int xhci_cmd_address_device(xhci_dev_t *dev, uint32_t slot_id,
|
||||
uint32_t port_id, uint32_t speed);
|
||||
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);
|
||||
|
||||
int xhci_bringup(xhci_dev_t *dev)
|
||||
{
|
||||
@@ -295,6 +296,7 @@ int xhci_bringup(xhci_dev_t *dev)
|
||||
dev->next_action = XHCI_NEXT_ACTION_NONE;
|
||||
dev->next_action_slot_id = 0;
|
||||
dev->next_action_length = 0;
|
||||
dev->next_action_config_value = 0;
|
||||
|
||||
console_println("xhci: controller running");
|
||||
/* Milestone 2e prep: HCCPARAMS1.CSZ decides 32- vs 64-byte Slot/
|
||||
@@ -572,6 +574,49 @@ int xhci_ep0_get_config_descriptor(xhci_dev_t *dev, uint32_t slot_id, uint16_t l
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Shared submission for a "no Data Stage" control transfer -- Setup Stage
|
||||
* only (TRT = XHCI_SETUP_TRT_NO_DATA), then Status Stage. Per USB 2.0
|
||||
* spec section 8.5.3, a control transfer with no Data Stage always uses
|
||||
* an IN Status Stage (the reverse of a normal OUT request's OUT status),
|
||||
* so DIR_IN is set unconditionally here -- this helper isn't generic
|
||||
* across OUT-data and no-data requests, only the latter. */
|
||||
static void xhci_ep0_control_write_nodata(xhci_dev_t *dev, uint8_t bRequest,
|
||||
uint16_t wValue, uint16_t wIndex)
|
||||
{
|
||||
usb_setup_packet_t setup = {
|
||||
.bmRequestType = USB_DIR_HOST_TO_DEVICE,
|
||||
.bRequest = bRequest,
|
||||
.wValue = wValue,
|
||||
.wIndex = wIndex,
|
||||
.wLength = 0
|
||||
};
|
||||
uint64_t setup_bits;
|
||||
memcpy(&setup_bits, &setup, sizeof(setup_bits));
|
||||
|
||||
xhci_ep0_enqueue_trb(dev, setup_bits, 8u,
|
||||
(XHCI_TRB_TYPE_SETUP_STAGE << XHCI_TRB_CONTROL_TYPE_SHIFT) |
|
||||
XHCI_TRB_CONTROL_IDT |
|
||||
(XHCI_SETUP_TRT_NO_DATA << XHCI_TRB_CONTROL_TRT_SHIFT));
|
||||
|
||||
xhci_ep0_enqueue_trb(dev, 0, 0,
|
||||
(XHCI_TRB_TYPE_STATUS_STAGE << XHCI_TRB_CONTROL_TYPE_SHIFT) |
|
||||
XHCI_TRB_CONTROL_IOC |
|
||||
XHCI_TRB_CONTROL_DIR_IN);
|
||||
}
|
||||
|
||||
int xhci_ep0_set_configuration(xhci_dev_t *dev, uint32_t slot_id, uint8_t config_value)
|
||||
{
|
||||
if (!dev || !dev->ep0_ring) return -1;
|
||||
|
||||
dev->transfer_purpose = XHCI_XFER_SET_CONFIG;
|
||||
xhci_ep0_control_write_nodata(dev, USB_REQ_SET_CONFIGURATION, config_value, 0);
|
||||
|
||||
dev->pending_transfer_slot_id = slot_id;
|
||||
dev->doorbell[slot_id] = XHCI_DB_TARGET(1);
|
||||
console_println("xhci: set configuration submitted");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* Milestone 2d: Event Ring servicing, polled from sk_repl_idle().
|
||||
*
|
||||
@@ -799,6 +844,16 @@ void xhci_poll_events(void)
|
||||
iface_subclass == USB_SUBCLASS_SCSI &&
|
||||
iface_protocol == USB_PROTOCOL_BOT) {
|
||||
console_println("xhci: confirmed Mass Storage / SCSI / BOT device");
|
||||
/* Deferred (see xhci_dev_t's
|
||||
* next_action doc comment) rather
|
||||
* than called directly here --
|
||||
* same doorbell-ordering hazard
|
||||
* as the device/config descriptor
|
||||
* chaining above. */
|
||||
dev->next_action = XHCI_NEXT_ACTION_SET_CONFIG;
|
||||
dev->next_action_slot_id = xfer_slot_id;
|
||||
dev->next_action_config_value =
|
||||
dev->config_descriptor[USB_CONFIG_OFF_CONFIG_VALUE];
|
||||
} else {
|
||||
console_println("xhci: not a Mass Storage/SCSI/BOT device -- not usable as a drive");
|
||||
}
|
||||
@@ -812,6 +867,10 @@ void xhci_poll_events(void)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case XHCI_XFER_SET_CONFIG: {
|
||||
console_println("xhci: device configured");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
console_println("xhci: transfer event");
|
||||
break;
|
||||
@@ -861,5 +920,12 @@ void xhci_poll_events(void)
|
||||
if (xhci_ep0_get_config_descriptor(dev, next_slot_id, next_length) != 0) {
|
||||
console_println("xhci: deferred config descriptor request setup failed");
|
||||
}
|
||||
} else if (dev->next_action == XHCI_NEXT_ACTION_SET_CONFIG) {
|
||||
uint32_t next_slot_id = dev->next_action_slot_id;
|
||||
uint8_t next_config_value = dev->next_action_config_value;
|
||||
dev->next_action = XHCI_NEXT_ACTION_NONE;
|
||||
if (xhci_ep0_set_configuration(dev, next_slot_id, next_config_value) != 0) {
|
||||
console_println("xhci: deferred set configuration request setup failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user