universalisos/kernel/drivers/pci.h
Fábio Coutada 9540b0528c feat(universalisos): PikeOS-style Phase B/C device drivers + Phase D microkernel
Phase B (Core Device Support) — all drivers verified in QEMU:
- Network: virtio-net cleanup, RTL8139, E1000, clause-22 MDIO PHY management,
  CAN bus, industrial protocols (Modbus/Profibus/EtherCAT), controller probe+dispatch
- Block storage: RAM disk backend (write->read->verify PASSED), virtio-blk transport,
  backend dispatch, real MBR+GPT partition parsers, SD/eMMC command framework
- GPIO: PL061 (verified), I2C: DesignWare (verified), SPI: PL022 (verified)

Phase C (Advanced Features):
- PCI: FULL PikeOS ARMv7 replica — transport-agnostic uos_pci_ops, config-address
  encoding, BAR sizing, capability walk, enumeration+bridge recursion, MSI/MSI-X
- USB: PikeOS-style layered stack — usb.h contract, usb_core.cpp (enumeration
  state machine), usb_ehci.cpp (EHCI transport)
- Display: FULL 1:1 PikeOS fbcon replica + copied font_8x16

Build foundation fixes:
- Freestanding aeabi_runtime.cpp (__aeabi_uidiv/__aeabi_uldivmod)
- PikeOS-style flat 4GB MMU section map + proper enable (unblocked device MMIO)
- guest.h MAX_GUEST_IMAGE_SIZE 256MB->16MB (BSS was 259MB)
- C/C++ linkage fixes, duplicate-virtio_net_init, MMIO access-size handling

Phase D (PikeOS ARMv7 Microkernel Port):
- D-1: Per-VM address spaces — cloned pgdirs, ASID-tagged TLB, 4K page walker,
  isolation PASSED (two guests, same VA->different PAs), guest fault recovery
- D-2: IRQ dispatch backbone — 1024-slot dispatch table, real GICv2 hardware
  (GICD_CTLR/GICC_CTLR/GICC_PMR/GICC_IAR/GICC_EOIR), arm_irq_handler wired
- D-3: Time subsystem — CNTVCT ns-since-boot, CNTP periodic ticker via D-2
- D-4: KDEV framework — linker-section driver registration, uos_kdev_init_all,
  name lookup
- D-5: VFP/NEON — lazy enable (undef trap->CPACR+FPEXC.EN), FPEXC=0x40000000
- D-6: SMP — per-CPU state, MPIDR, IPI/SGI framework (reschedule+TLB flush)

All uos_ naming (PikeOS p4_ convention adapted). Compiles -Werror freestanding C++17.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-09 09:10:53 +01:00

281 lines
12 KiB
C

/*
* Universalisos PCI/PCIe Stack — full PikeOS-architecture replica
*
* Faithful adaptation of the PikeOS ARMv7 PCI driver
* (src/target/arm/v7hf: p4pci.h, p4pci_types.h, p4pcidev.h, pci_common.c,
* pci_enum.c, pci_msi.c, pci_msix.c) into the Universalisos freestanding kernel,
* using the `uos_` naming convention instead of PikeOS's `p4_`.
*
* PikeOS philosophy: the PCI core is TRANSPORT-AGNOSTIC. All hardware-specific
* config-space access goes through a pluggable `uos_pci_ops_t` callback table.
* One transport variant (e.g. ECAM, Layerscape DBI+ATU) registers its ops at
* boot; the shared core then enumerates, sizes BARs, walks capabilities, and
* programs MSI/MSI-X for every device, independent of how config cycles are
* produced. This file is the public contract.
*
* Author: PortugalFuturista Hypervisor Development Team
*/
#ifndef UNIVERSALISOS_DRIVERS_PCI_H
#define UNIVERSALISOS_DRIVERS_PCI_H
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/* ==========================================================================
* Config-address encoding (PikeOS P4_pci_config_addr_t)
*
* A single 32-bit word packing domain/bus/dev/func; the low 8 bits hold the
* register offset when the word is used as a transaction address.
* domain [31:24] bus [23:16] dev [15:11] func [10:8] regoff [7:0]
* ========================================================================== */
typedef uint32_t uos_pci_config_addr_t;
#define UOS_PCI_DOM_MAX 16u
#define UOS_PCI_BUS_MAX 256u
#define UOS_PCI_DEV_MAX 32u
#define UOS_PCI_FN_MAX 8u
#define UOS_PCI_REG_MAX 4096u
#define UOS_PCI_CONFIG_ADDR(dom, bus, dev, fn) \
((((uint32_t)(dom) << 24) & 0x0F000000u) | \
(((uint32_t)(bus) << 16) & 0x00FF0000u) | \
(((uint32_t)(dev) << 11) & 0x0000F800u) | \
(((uint32_t)(fn) << 8) & 0x00000700u))
#define UOS_PCI_CONFIG_DOM(a) (((a) & 0x0F000000u) >> 24)
#define UOS_PCI_CONFIG_BUS(a) (((a) & 0x00FF0000u) >> 16)
#define UOS_PCI_CONFIG_DEV(a) (((a) & 0x0000F800u) >> 11)
#define UOS_PCI_CONFIG_FN(a) (((a) & 0x00000700u) >> 8)
/* ==========================================================================
* Config register offsets (Type-0 endpoint header)
* ========================================================================== */
#define UOS_PCI_R_VENDOR_ID 0x00u
#define UOS_PCI_R_DEVICE_ID 0x02u
#define UOS_PCI_R_COMMAND 0x04u
#define UOS_PCI_R_STATUS 0x06u
#define UOS_PCI_R_CLASS_REV 0x08u
#define UOS_PCI_R_CACHE_LN_SZ 0x0cu
#define UOS_PCI_R_PRM_LAT_TMR 0x0du
#define UOS_PCI_R_HDR_TYPE 0x0eu
#define UOS_PCI_R_BIST 0x0fu
#define UOS_PCI_R_BAR_0 0x10u
#define UOS_PCI_R_BAR_1 0x14u
#define UOS_PCI_R_BAR_2 0x18u
#define UOS_PCI_R_BAR_3 0x1cu
#define UOS_PCI_R_BAR_4 0x20u
#define UOS_PCI_R_BAR_5 0x24u
#define UOS_PCI_R_CARDBUS_CIS_PTR 0x28u
#define UOS_PCI_R_SUBSYS_VENDOR_ID 0x2cu
#define UOS_PCI_R_SUBSYS_ID 0x2eu
#define UOS_PCI_R_ROM_BAR_HDR0 0x30u
#define UOS_PCI_R_CAP_PTR 0x34u
#define UOS_PCI_R_ROM_BAR_HDR1 0x38u
#define UOS_PCI_R_INT_LINE 0x3cu
#define UOS_PCI_R_INT_PIN 0x3du
/* Type-1 (bridge) header offsets */
#define UOS_PCI_R_PRIMARY_BUS 0x18u
#define UOS_PCI_R_SECONDARY_BUS 0x19u
#define UOS_PCI_R_SUBORDINATE_BUS 0x1au
#define UOS_PCI_R_SEC_LAT_TMR 0x1bu
#define UOS_PCI_R_IO_BASE 0x1cu
#define UOS_PCI_R_IO_LIMIT 0x1du
#define UOS_PCI_R_SEC_STATUS 0x1eu
#define UOS_PCI_R_MEM_BASE 0x20u
#define UOS_PCI_R_MEM_LIMIT 0x22u
#define UOS_PCI_R_PREF_MEM_BASE 0x24u
#define UOS_PCI_R_PREF_MEM_LIMIT 0x26u
#define UOS_PCI_R_PREF_BASE_UPPER32 0x28u
#define UOS_PCI_R_PREF_LIMIT_UPPER32 0x2cu
#define UOS_PCI_R_IO_BASE_UPPER16 0x30u
#define UOS_PCI_R_IO_LIMIT_UPPER16 0x32u
#define UOS_PCI_R_BRIDGE_CNTRL 0x3eu
/* Header type values */
#define UOS_PCI_HDR_TYPE_MASK 0x7Fu
#define UOS_PCI_HDR_TYPE_NORMAL 0u
#define UOS_PCI_HDR_TYPE_BRIDGE 1u
#define UOS_PCI_HDR_TYPE_CARDBUS 2u
#define UOS_PCI_HDR_TYPE_MULTIFUNC 0x80u
/* BAR decoding masks */
#define UOS_PCI_BAR_SPACE_MASK 0x01u
#define UOS_PCI_BAR_SPACE_IO 0x01u
#define UOS_PCI_BAR_SPACE_MEM 0x00u
#define UOS_PCI_BAR_MEM_TYPE_MASK 0x06u
#define UOS_PCI_BAR_MEM_TYPE_32 0x00u
#define UOS_PCI_BAR_MEM_TYPE_64 0x04u
#define UOS_PCI_BAR_MEM_PREF 0x08u
#define UOS_PCI_BAR_MEM_MASK (~0x0fu)
#define UOS_PCI_BAR_IO_MASK (~0x03u)
#define UOS_PCI_ROM_ADDR_MASK (~0x7ffu)
/* COMMAND bits */
#define UOS_PCI_CMD_IO 0x0001u
#define UOS_PCI_CMD_MEM 0x0002u
#define UOS_PCI_CMD_MASTER 0x0004u
#define UOS_PCI_CMD_SERR 0x0100u
#define UOS_PCI_CMD_INT_DIS 0x0400u
/* STATUS bits */
#define UOS_PCI_STATUS_CAP 0x0010u
/* Capability IDs */
#define UOS_PCI_CAP_ID_PM 0x01u
#define UOS_PCI_CAP_ID_AGP 0x02u
#define UOS_PCI_CAP_ID_MSI 0x05u
#define UOS_PCI_CAP_ID_PCIX 0x07u
#define UOS_PCI_CAP_ID_EXP 0x10u /* PCI Express */
#define UOS_PCI_CAP_ID_MSIX 0x11u
#define UOS_PCI_CAP_LIST_ID 0x00u /* cap entry: ID byte */
#define UOS_PCI_CAP_LIST_NEXT 0x01u /* cap entry: next-ptr byte */
/* MSI capability register field bits (Message Control) */
#define UOS_PCI_MSI_CNTL_ENABLE 0x0001u
#define UOS_PCI_MSI_CNTL_MULTICA 0x000eu /* [3:1] multiple message capable */
#define UOS_PCI_MSI_CNTL_MULTIEN 0x0070u /* [6:4] multiple message enable */
#define UOS_PCI_MSI_CNTL_64BIT 0x0080u /* 64-bit address capable */
#define UOS_PCI_MSI_CNTL_VECMASK 0x0100u /* per-vector mask capable */
/* MSI-X capability Message Control bits */
#define UOS_PCI_MSIX_CNTL_ENABLE 0x8000u
#define UOS_PCI_MSIX_CNTL_FNMASK 0x4000u
#define UOS_PCI_MSIX_CNTL_TABLESZ 0x07ffu /* table size field (N-1) */
/* MSI-X table entry layout (16 bytes each) */
#define UOS_PCI_MSIX_ENTRY_SIZE 16u
#define UOS_PCI_MSIX_ADDRLO_OFFSET 0x00u
#define UOS_PCI_MSIX_ADDRHI_OFFSET 0x04u
#define UOS_PCI_MSIX_DATA_OFFSET 0x08u
#define UOS_PCI_MSIX_MASK_OFFSET 0x0cu /* bit 0 = per-entry Mask */
/* ==========================================================================
* Data structures (PikeOS P4_pci_res_t / P4_pci_dev_t)
* ========================================================================== */
#define UOS_PCI_NUM_RES 7u /* 6 standard BARs + expansion ROM */
/* Resource flags */
#define UOS_PCI_RES_MEM_32 0x00000001u
#define UOS_PCI_RES_MEM_64 0x00000002u
#define UOS_PCI_RES_IO 0x00000004u
#define UOS_PCI_RES_PREF 0x00000008u
/* Device open state (simple lock, no refcount, as in PikeOS) */
#define UOS_PCI_DEV_CLOSED 0u
#define UOS_PCI_DEV_OPEN 1u
typedef struct {
uint64_t bus_addr; /* address as seen on the PCI bus */
uint64_t cpu_addr; /* address as seen by the CPU (after ATU) */
uint32_t size; /* size in bytes */
uint32_t flags; /* UOS_PCI_RES_* OR'd */
uint32_t r_normal; /* original BAR value (for BAR-size virtualization) */
uint32_t r_sized; /* all-1s-probe readback */
} uos_pci_res_t;
typedef struct {
uos_pci_res_t res[UOS_PCI_NUM_RES];
bool force_intx_dis;
bool ext_pci_cfg;
int32_t irq; /* INTID, -1 = invalid */
uos_pci_config_addr_t config_addr; /* packed domain/bus/dev/func */
uint32_t class_code; /* class<<8 (no rev in low byte) */
uint16_t vendor;
uint16_t device;
uint16_t subsysvendor;
uint16_t subsys;
uint8_t hdr_type; /* low 7 bits */
uint8_t state; /* UOS_PCI_DEV_* */
/* MSI/MSI-X probe results */
uint8_t msi_cap; /* MSI cap offset, 0 if none */
uint8_t msix_cap; /* MSI-X cap offset, 0 if none */
uint16_t msi_control; /* cached Message Control */
uint16_t msix_control; /* cached MSI-X Message Control */
uint8_t msi_is64;
uint8_t msi_max_irqs;
uint8_t msix_table_bar; /* which res[] holds the MSI-X table */
uint32_t msix_table_offset;
} uos_pci_dev_t;
/* ==========================================================================
* Transport contract — the pluggable `pci_ops` (PikeOS philosophy)
*
* A board port implements these and registers them via uos_pci_register_ops().
* The core never touches config space directly except through these callbacks.
* ========================================================================== */
typedef struct {
void (*read_config8) (uos_pci_config_addr_t addr, uint32_t offset, uint8_t *val);
void (*read_config16)(uos_pci_config_addr_t addr, uint32_t offset, uint16_t *val);
void (*read_config32)(uos_pci_config_addr_t addr, uint32_t offset, uint32_t *val);
void (*write_config8) (uos_pci_config_addr_t addr, uint32_t offset, uint8_t val);
void (*write_config16)(uos_pci_config_addr_t addr, uint32_t offset, uint16_t val);
void (*write_config32)(uos_pci_config_addr_t addr, uint32_t offset, uint32_t val);
void (*find_irq) (uos_pci_dev_t *dev, uint8_t pin); /* sets dev->irq */
void (*arch_quirk_post)(uos_pci_dev_t *dev); /* per-device hook */
void (*set_cpu_addr) (uos_pci_dev_t *dev); /* map bus->cpu addr */
unsigned int (*num_domains)(void);
} uos_pci_ops_t;
/* ==========================================================================
* Public core API
* ========================================================================== */
#define UOS_PCI_MAX_DEVICES 128u
/** Register a transport. The core uses the last registered ops. */
void uos_pci_register_ops(const uos_pci_ops_t *ops);
/** Convenience config accessors that dispatch through the registered ops. */
uint8_t uos_pci_read8 (uos_pci_config_addr_t a, uint32_t off);
uint16_t uos_pci_read16(uos_pci_config_addr_t a, uint32_t off);
uint32_t uos_pci_read32(uos_pci_config_addr_t a, uint32_t off);
void uos_pci_write8 (uos_pci_config_addr_t a, uint32_t off, uint8_t v);
void uos_pci_write16(uos_pci_config_addr_t a, uint32_t off, uint16_t v);
void uos_pci_write32(uos_pci_config_addr_t a, uint32_t off, uint32_t v);
/** Walk the capability list, return the cap offset for `id`, or 0 if absent. */
uint8_t uos_pci_find_cap(uos_pci_dev_t *dev, uint8_t id);
/** Canonical BAR-sizing probe (PikeOS pci_read_bases). Sizes all BARs + ROM. */
void uos_pci_read_bases(uos_pci_dev_t *dev, uint32_t num_bars, uint32_t rom_off);
/** Enumerate the whole hierarchy from bus 0 (bridge recursion, BAR sizing). */
int uos_pci_enumerate(void);
/** Device table access. */
uos_pci_dev_t *uos_pci_get_device(unsigned int index);
unsigned int uos_pci_get_device_count(void);
/** Enable a device: set I/O + memory + bus-master in COMMAND. */
void uos_pci_enable_device(uos_pci_dev_t *dev);
/** MSI / MSI-X programming (no-op if the device lacks the capability). */
void uos_pci_msi_enable (uos_pci_dev_t *dev, uint32_t msg_addr, uint16_t msg_data);
void uos_pci_msi_disable(uos_pci_dev_t *dev);
void uos_pci_msix_enable (uos_pci_dev_t *dev); /* enables + unmasks all entries */
void uos_pci_msix_disable(uos_pci_dev_t *dev);
/** Init + demonstration. */
void uos_pci_driver_init(void);
void uos_pci_driver_demo(void);
/* Legacy simple API (kept for the existing kernel boot wiring). */
#define MAX_PCI_DEVICES UOS_PCI_MAX_DEVICES
#define QEMU_VIRT_PCI_ECAM_BASE 0x3F000000u
int pci_init(uint32_t ecam_base);
void pci_driver_init(void);
void pci_driver_demo(void);
#ifdef __cplusplus
}
#endif
#endif /* UNIVERSALISOS_DRIVERS_PCI_H */