Punch list §25 item 4.3.5c complete. Amended from a nonexistent MMIO transport to PCI (matching the board's actual virtio-blk-pci precedent). New virtio-input driver: eventq with pre-posted buffers, PLIC source computed at runtime from PCI slot/pin (derived live from this host's QEMU riscv64 DTB), mandatory ISR-status read, PCI interrupt-disable-bit check. New VKBD-EVENT/VKBD-DEBUG FORTH words. Verified with a real QEMU sendkey keypress: exact KEY_A/press match, two real interrupts serviced, zero exceptions. Three-arch acceptance boot clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
105 lines
3.6 KiB
C
105 lines
3.6 KiB
C
/*
|
|
* pci.h — Generic PCI/PCIe subsystem for StarKernel
|
|
*
|
|
* Config space access:
|
|
* amd64 — Type 1 port I/O (CF8/CFC); no memory mapping required.
|
|
* others — ECAM via ACPI MCFG; UEFI identity-maps the ECAM window.
|
|
*
|
|
* BAR MMIO:
|
|
* Call pci_map_bar() before the first MMIO access. On amd64 this
|
|
* adds a VMM page-table mapping (cache-disabled); on other arches
|
|
* the UEFI tables already cover the region and the call is a no-op.
|
|
*/
|
|
|
|
#ifndef STARKERNEL_PCI_H
|
|
#define STARKERNEL_PCI_H
|
|
|
|
#include <stdint.h>
|
|
|
|
/* PCI standard config-space offsets */
|
|
#define PCI_CFG_VENDOR_ID 0x00
|
|
#define PCI_CFG_DEVICE_ID 0x02
|
|
#define PCI_CFG_COMMAND 0x04
|
|
#define PCI_CFG_STATUS 0x06
|
|
#define PCI_CFG_CLASS_REV 0x08
|
|
#define PCI_CFG_HEADER_TYPE 0x0E
|
|
#define PCI_CFG_BAR0 0x10
|
|
#define PCI_CFG_BAR1 0x14
|
|
#define PCI_CFG_BAR2 0x18
|
|
#define PCI_CFG_BAR3 0x1C
|
|
#define PCI_CFG_BAR4 0x20
|
|
#define PCI_CFG_BAR5 0x24
|
|
#define PCI_CFG_CAP_PTR 0x34
|
|
#define PCI_CFG_INT_LINE 0x3C
|
|
#define PCI_CFG_INT_PIN 0x3D /* 0=none, 1=INTA .. 4=INTD (item 4.3.5c/4.3.5d) */
|
|
|
|
/* PCI command register bits */
|
|
#define PCI_CMD_IO_SPACE (1u << 0)
|
|
#define PCI_CMD_MEM_SPACE (1u << 1)
|
|
#define PCI_CMD_BUS_MASTER (1u << 2)
|
|
#define PCI_CMD_INTX_DISABLE (1u << 10) /* item 4.3.5c/4.3.5e: pci_enable() never
|
|
* clears this -- if firmware left it set,
|
|
* INTx never asserts. Check explicitly. */
|
|
|
|
/* BAR type flags */
|
|
#define PCI_BAR_TYPE_MASK 0x1u
|
|
#define PCI_BAR_IO 0x1u
|
|
#define PCI_BAR_MEM_64 0x4u /* bits [2:1] == 10 in memory BAR */
|
|
|
|
/* Identified PCI device */
|
|
typedef struct {
|
|
uint8_t bus;
|
|
uint8_t device;
|
|
uint8_t function;
|
|
uint16_t vendor_id;
|
|
uint16_t device_id;
|
|
} PciDevice;
|
|
|
|
/*
|
|
* pci_init — parse ACPI RSDP → XSDT → MCFG to find ECAM base.
|
|
* On amd64, also maps the ECAM window via the VMM.
|
|
* May be called with rsdp==NULL; port-I/O fallback still works
|
|
* on amd64. On aarch64/riscv64 ECAM is required.
|
|
* Returns 0 on success, -1 if no ECAM found (amd64 still functional via
|
|
* port I/O).
|
|
*/
|
|
int pci_init(void *rsdp);
|
|
|
|
/*
|
|
* pci_find_first — linear scan of bus 0 for the first device matching
|
|
* (vendor_id, device_id). Fill *out on match.
|
|
* Returns 0 on found, -1 if not found.
|
|
*/
|
|
int pci_find_first(uint16_t vendor_id, uint16_t device_id, PciDevice *out);
|
|
|
|
/* Config space accessors */
|
|
uint32_t pci_read32 (const PciDevice *d, uint16_t offset);
|
|
uint16_t pci_read16 (const PciDevice *d, uint16_t offset);
|
|
uint8_t pci_read8 (const PciDevice *d, uint16_t offset);
|
|
void pci_write32(const PciDevice *d, uint16_t offset, uint32_t val);
|
|
void pci_write16(const PciDevice *d, uint16_t offset, uint16_t val);
|
|
void pci_write8 (const PciDevice *d, uint16_t offset, uint8_t val);
|
|
|
|
/*
|
|
* pci_enable — set I/O space + memory space + bus-master bits in the
|
|
* PCI command register.
|
|
*/
|
|
void pci_enable(const PciDevice *d);
|
|
|
|
/*
|
|
* pci_bar — return the base address (physical) of BAR bar_idx.
|
|
* Handles 32-bit and 64-bit memory BARs; returns 0 for I/O BARs.
|
|
* Does NOT map the region — call pci_map_bar() separately.
|
|
*/
|
|
uint64_t pci_bar(const PciDevice *d, int bar_idx);
|
|
|
|
/*
|
|
* pci_map_bar — make the BAR MMIO region accessible.
|
|
* amd64: calls vmm_map_range(phys, phys, size, WR|CD).
|
|
* others: no-op (UEFI identity map covers it).
|
|
* Returns 0 on success, -1 on failure.
|
|
*/
|
|
int pci_map_bar(uint64_t phys_addr, uint64_t size);
|
|
|
|
#endif /* STARKERNEL_PCI_H */
|