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>
281 lines
12 KiB
C
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 */
|