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
+22 -10
View File
@@ -3093,16 +3093,28 @@ match" not "class code match"), and `pci_bar()`/`pci_map_bar()`/`pci_enable()` a
generic, reusable as-is for the xHCI BAR0 mapping and bus-master enable. 2b is smaller than
originally scoped.
**2b. PCI discovery**
- [ ] Extend `src/starkernel/pci/pci.c`'s enumeration to recognize the xHCI PCI class code
(Serial Bus Controller / USB Controller / xHCI programming interface) the same way it
already recognizes whatever device classes it currently handles (need to read
`pci.c`'s current class-match logic before extending it, not written from scratch)
- [ ] Read and store the xHCI controller's BAR (memory-mapped I/O base address) from PCI
config space
- [ ] Map that MMIO region into kernel virtual address space (via `vmm.c`'s existing
page-table machinery — confirm the right mapping-request function to call, matching
how virtio-blk's MMIO region gets mapped today as the closest existing precedent)
**2b. PCI discovery ✅ DONE 2026-08-22**
- [x] No `pci.c` extension needed after all (per 2a's bonus finding — `pci_find_first()` is
already generic ID-based lookup). New files instead: `include/starkernel/xhci_driver.h`
(driver state struct `xhci_dev_t` + public API) and `src/starkernel/usb/xhci.c`
(`xhci_find_and_map()`) — new `usb/` subsystem directory, added to both
`LOADER_SRCS_BASE` and `KERNEL_SRCS_BASE` wildcards in `Makefile.starkernel`, matching
the existing `virtio/*.c` wildcard pattern exactly.
- [x] BAR0 read via the existing `pci_bar()` — no new code needed, direct reuse.
- [x] BAR0 mapped via the existing `pci_map_bar()` — no new code needed, direct reuse. Mapping
size is a documented, explicit fixed assumption (`XHCI_BAR0_MAP_SIZE`, 64 KiB) rather
than real PCI BAR-size probing, since xHCI has no self-describing capability-region
length the way virtio PCI capabilities do (that mechanism was `virtio_blk.c`'s approach,
not available here) — flagged in a comment as a revisit point if it proves insufficient,
not swept under the rug.
`xhci_find_and_map()` fills in all four register-region pointers (`cap`/`op`/`runtime`/
`doorbell`) plus `max_slots`/`max_ports`/`max_intrs` from `HCSPARAMS1`, ready for 2c's
controller bring-up to consume directly. Verified: standalone syntax check clean (`gcc -Wall
-Wextra -fsyntax-only`), full amd64 kernel build succeeds with zero warnings (both loader and
kernel compilation passes), and a live amd64 boot still reaches POST 1012/0/0 and `ok>`
unaffected (expected — nothing calls `xhci_find_and_map()` yet, so this is purely additive
until 2c wires it in).
**2c. Controller bring-up**
- [ ] Read Capability Registers to learn controller parameters (max device slots, max ports,
+2
View File
@@ -395,6 +395,7 @@ LOADER_SRCS_BASE := \
$(wildcard $(KERNEL_SRC)/capsule/*.c) \
$(wildcard $(KERNEL_SRC)/pci/*.c) \
$(wildcard $(KERNEL_SRC)/virtio/*.c) \
$(wildcard $(KERNEL_SRC)/usb/*.c) \
$(KERNEL_SRC)/repl.c \
$(KERNEL_SRC)/doe_log.c \
$(KERNEL_SRC)/heartbeat.c
@@ -444,6 +445,7 @@ KERNEL_SRCS_BASE := \
$(wildcard $(KERNEL_SRC)/capsule/*.c) \
$(wildcard $(KERNEL_SRC)/pci/*.c) \
$(wildcard $(KERNEL_SRC)/virtio/*.c) \
$(wildcard $(KERNEL_SRC)/usb/*.c) \
$(wildcard $(KERNEL_SRC)/arch/$(ARCH)/*.c) \
$(KERNEL_SRC)/repl.c \
$(KERNEL_SRC)/doe_log.c \
+1 -1
View File
@@ -1,5 +1,5 @@
# Capsule Block Manifest — Auto-generated
<!-- Generated by mkcapsule --manifest 2026-08-22T11:46:44Z -->
<!-- Generated by mkcapsule --manifest 2026-08-22T11:56:55Z -->
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
<!-- Hand-written justifications and immutability notes live -->
<!-- in MANIFEST.md alongside this auto-generated index. -->
BIN
View File
Binary file not shown.
+42
View File
@@ -0,0 +1,42 @@
/*
* xhci_driver.h xHCI USB host controller driver public API for StarKernel
*
* Register-layout definitions live in xhci.h; this header is the driver's
* own state and public entry points, matching virtio_blk.h's split.
*/
#ifndef STARKERNEL_XHCI_DRIVER_H
#define STARKERNEL_XHCI_DRIVER_H
#include <stdint.h>
#include "starkernel/pci.h"
#include "starkernel/xhci.h"
/* Driver state for one xHCI controller instance. Only one controller is
* supported (matches virtio_blk's single-device precedent). */
typedef struct {
PciDevice pci;
uint64_t bar0_phys; /* physical MMIO base, BAR0 */
xhci_cap_regs_t *cap; /* BAR0 + 0 */
xhci_op_regs_t *op; /* BAR0 + cap->cap_length */
xhci_runtime_regs_t *runtime; /* BAR0 + cap->rts_off */
xhci_doorbell_t *doorbell; /* BAR0 + cap->db_off */
uint32_t max_slots;
uint32_t max_ports;
uint32_t max_intrs;
} xhci_dev_t;
/*
* xhci_find_and_map locate the xHCI controller on PCI bus 0, enable it
* (I/O+MEM+bus-master), map its BAR0 MMIO region, and
* fill in the four register-region pointers in *dev.
*
* dev must point to a zero-initialised xhci_dev_t.
*
* Returns 0 on success.
* Returns -1 if no xHCI device was found on the PCI bus.
* Returns -2 if the BAR0 mapping failed.
*/
int xhci_find_and_map(xhci_dev_t *dev);
#endif /* STARKERNEL_XHCI_DRIVER_H */
File diff suppressed because it is too large Load Diff
+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;
}