feat: Xhci BIOS-to-OS handoff

This commit is contained in:
2026-05-24 10:23:16 +02:00
parent cd159235ca
commit 6b45c59a9a
+97
View File
@@ -230,6 +230,93 @@ namespace Drivers::USB::Xhci {
static void HandleInterrupt(uint8_t irq); static void HandleInterrupt(uint8_t irq);
// -------------------------------------------------------------------------
// BIOS-to-OS handoff (USB Legacy Support)
//
// Per xHCI spec section 7.1: walk the extended capability list starting at
// xECP (HCCPARAMS1[31:16]) to find Cap ID 0x01 (USB Legacy Support). Set
// the OS-Owned semaphore, wait for BIOS to clear its semaphore, and then
// disable all USB-Legacy SMI sources.
//
// Without this, BIOS SMI handlers that emulate PS/2 from USB devices stay
// active and steal i8042 events, so the built-in keyboard/trackpad input
// does not reach the OS until USB activity wakes the SMI handler.
// -------------------------------------------------------------------------
static constexpr uint8_t XHCI_EXTCAP_LEGACY = 0x01;
static constexpr uint32_t USBLEGSUP_BIOS_OWNED = (1u << 16);
static constexpr uint32_t USBLEGSUP_OS_OWNED = (1u << 24);
static constexpr uint32_t USBLEGCTLSTS_SMI_ENABLES =
(1u << 0) // USB SMI Enable
| (1u << 4) // SMI on Host System Error Enable
| (1u << 13) // SMI on OS Ownership Enable
| (1u << 14) // SMI on PCI Command Enable
| (1u << 15); // SMI on BAR Enable
static constexpr uint32_t USBLEGCTLSTS_W1C_STATUS =
(1u << 20) // SMI on OS Ownership Change
| (1u << 21) // SMI on PCI Command
| (1u << 22); // SMI on BAR
static void PerformBiosHandoff() {
uint32_t hccparams1 = ReadCap(CAP_HCCPARAMS1);
uint32_t xecp = (hccparams1 >> 16) & 0xFFFF;
if (xecp == 0) {
KernelLogStream(INFO, "xHCI") << "No extended capabilities (xECP=0)";
return;
}
volatile uint32_t* extCap = (volatile uint32_t*)(g_mmioBase + xecp * 4);
for (int i = 0; i < 64; i++) {
uint32_t capReg = *extCap;
uint8_t capId = capReg & 0xFF;
uint8_t nextOffset = (capReg >> 8) & 0xFF;
if (capId == XHCI_EXTCAP_LEGACY) {
KernelLogStream(INFO, "xHCI") << "USB Legacy Support found, requesting BIOS handoff";
// Assert OS-Owned. Preserve the BIOS-Owned bit so BIOS sees the
// request and can finish cleanly before clearing its own bit.
*extCap = capReg | USBLEGSUP_OS_OWNED;
uint64_t deadline = Timekeeping::GetMilliseconds() + 1000;
bool released = false;
while (Timekeeping::GetMilliseconds() < deadline) {
if (!(*extCap & USBLEGSUP_BIOS_OWNED)) {
released = true;
break;
}
BusyWaitMs(10);
}
if (!released) {
KernelLogStream(WARNING, "xHCI")
<< "BIOS did not release controller in 1s, forcing handoff";
uint32_t v = *extCap;
v &= ~USBLEGSUP_BIOS_OWNED;
v |= USBLEGSUP_OS_OWNED;
*extCap = v;
} else {
KernelLogStream(OK, "xHCI") << "BIOS released xHCI ownership";
}
// Disable all USB-Legacy SMI sources and clear any pending
// W1C status bits. Preserves RsvdP bits via read-modify-write.
volatile uint32_t* ctlsts = extCap + 1;
uint32_t v = *ctlsts;
v &= ~USBLEGCTLSTS_SMI_ENABLES;
v |= USBLEGCTLSTS_W1C_STATUS;
*ctlsts = v;
return;
}
if (nextOffset == 0) return;
extCap += nextOffset;
}
}
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// MSI setup (same pattern as E1000E) // MSI setup (same pattern as E1000E)
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
@@ -1011,6 +1098,11 @@ namespace Drivers::USB::Xhci {
if (g_maxSlots > MAX_SLOTS) g_maxSlots = MAX_SLOTS; if (g_maxSlots > MAX_SLOTS) g_maxSlots = MAX_SLOTS;
if (g_maxPorts > MAX_PORTS) g_maxPorts = MAX_PORTS; if (g_maxPorts > MAX_PORTS) g_maxPorts = MAX_PORTS;
// Tell BIOS to release the controller and disable USB-Legacy SMIs.
// Must run before we halt/reset so BIOS gets a chance to shut down
// its own use of the controller cleanly.
PerformBiosHandoff();
// Halt controller // Halt controller
uint32_t usbcmd = ReadOp(OP_USBCMD); uint32_t usbcmd = ReadOp(OP_USBCMD);
usbcmd &= ~USBCMD_RS; usbcmd &= ~USBCMD_RS;
@@ -1259,6 +1351,11 @@ namespace Drivers::USB::Xhci {
g_maxPorts = MAX_PORTS; g_maxPorts = MAX_PORTS;
} }
// -----------------------------------------------------------------
// Step 4.5: BIOS-to-OS handoff (USB Legacy Support)
// -----------------------------------------------------------------
PerformBiosHandoff();
// ----------------------------------------------------------------- // -----------------------------------------------------------------
// Step 5: Halt controller // Step 5: Halt controller
// ----------------------------------------------------------------- // -----------------------------------------------------------------