Artemis Milestone 2b complete: xHCI PCI discovery and BAR0 mapping

New src/starkernel/usb/ subsystem directory (added to both
LOADER_SRCS_BASE and KERNEL_SRCS_BASE wildcards in Makefile.starkernel,
matching the existing virtio/*.c pattern). xhci_find_and_map() locates
the controller via the already-generic pci_find_first(), enables it,
maps BAR0 via the already-generic pci_map_bar(), and fills in all four
register-region pointers (cap/op/runtime/doorbell) plus max_slots/
max_ports/max_intrs from HCSPARAMS1 -- ready for controller bring-up
(2c) to consume directly.

No pci.c extension needed, per 2a's finding that PCI discovery here is
ID-based lookup (already generic), not class-code scanning. Verified:
clean standalone syntax check, full amd64 kernel build with zero
warnings, live boot still reaches POST 1012/0/0 unaffected (nothing
calls xhci_find_and_map() yet, so this is purely additive).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-08-22 07:58:27 -04:00
co-authored by Claude Sonnet 5
parent 94345c24b7
commit 5970c54912
7 changed files with 10901 additions and 11 deletions
+70
View File
@@ -0,0 +1,70 @@
/*
* xhci.c — xHCI USB host controller driver for StarKernel: discovery and
* register-region mapping (Milestone 2b). Controller bring-up (2c) and
* beyond follow in later increments.
*
* Memory model: BAR0 is mapped identity (virtual address == physical
* address), matching virtio_blk.c's precedent and pci_map_bar()'s own
* documented behavior (amd64: vmm_map_range(phys, phys, ...); other
* arches: no-op, UEFI identity map already covers it).
*/
#ifndef __STARKERNEL__
#error "xhci.c is kernel-only"
#endif
#include <stddef.h>
#include <stdint.h>
#include "starkernel/pci.h"
#include "starkernel/xhci.h"
#include "starkernel/xhci_driver.h"
#include "console.h"
/* Conservative fixed BAR0 mapping size. xHCI has no self-describing
* capability-region length the way virtio PCI capabilities do (that's
* virtio_blk.c's approach, not available here) — 64 KiB comfortably
* covers Capability + Operational + Port registers + Runtime + Doorbell
* Array + typical extended-capability space for QEMU's qemu-xhci and for
* real hardware controllers with modest port counts. Revisit if a real
* device's actual BAR size (via PCI BAR-sizing probe, not yet
* implemented in pci.c) proves this insufficient. */
#define XHCI_BAR0_MAP_SIZE 0x10000ull
int xhci_find_and_map(xhci_dev_t *dev)
{
if (!dev) return -1;
if (pci_find_first(XHCI_PCI_VENDOR_ID, XHCI_PCI_DEVICE_ID, &dev->pci) != 0) {
console_println("xhci: no controller found on PCI bus 0");
return -1;
}
pci_enable(&dev->pci);
dev->bar0_phys = pci_bar(&dev->pci, 0);
if (!dev->bar0_phys) {
console_println("xhci: BAR0 read failed (zero or I/O BAR)");
return -1;
}
if (pci_map_bar(dev->bar0_phys, XHCI_BAR0_MAP_SIZE) != 0) {
console_println("xhci: BAR0 mapping failed");
return -2;
}
dev->cap = (xhci_cap_regs_t *)(uintptr_t)dev->bar0_phys;
dev->op = (xhci_op_regs_t *)((uint8_t *)dev->cap + dev->cap->cap_length);
dev->runtime = (xhci_runtime_regs_t *)((uint8_t *)dev->cap +
(dev->cap->rts_off & ~0x1Fu));
dev->doorbell = (xhci_doorbell_t *)((uint8_t *)dev->cap +
(dev->cap->db_off & ~0x3u));
uint32_t hcs1 = dev->cap->hcs_params1;
dev->max_slots = XHCI_HCSPARAMS1_MAX_SLOTS(hcs1);
dev->max_intrs = XHCI_HCSPARAMS1_MAX_INTRS(hcs1);
dev->max_ports = XHCI_HCSPARAMS1_MAX_PORTS(hcs1);
console_println("xhci: controller found, BAR0 mapped");
return 0;
}