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:
co-authored by
Claude Sonnet 5
parent
94345c24b7
commit
5970c54912
+22
-10
@@ -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,
|
||||
|
||||
@@ -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,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. -->
|
||||
|
||||
Binary file not shown.
@@ -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
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user