From a243c79d0f77637d3b6c63cb9fec7d42e6e2e136 Mon Sep 17 00:00:00 2001 From: Maxim Poliakovski Date: Tue, 31 Mar 2020 21:12:06 +0200 Subject: [PATCH] Add support for PCI I/O space. --- devices/macio.h | 4 ++-- devices/mpc106.cpp | 51 ++++++++++++++++++++++++++++++++++++++------- devices/mpc106.h | 5 ++--- devices/pcidevice.h | 21 +++++++++++++++++-- 4 files changed, 66 insertions(+), 15 deletions(-) diff --git a/devices/macio.h b/devices/macio.h index 0b77dab..b73df35 100644 --- a/devices/macio.h +++ b/devices/macio.h @@ -94,9 +94,9 @@ public: bool supports_type(HWCompType type) { return type == HWCompType::MMIO_DEV; }; - void set_host(PCIHost *host_instance) {this->host_instance = host_instance;}; - /* PCI device methods */ + bool supports_io_space(void) { return false; }; + uint32_t pci_cfg_read(uint32_t reg_offs, uint32_t size); void pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size); diff --git a/devices/mpc106.cpp b/devices/mpc106.cpp index 338dede..5c9fd75 100644 --- a/devices/mpc106.cpp +++ b/devices/mpc106.cpp @@ -40,10 +40,14 @@ MPC106::MPC106() : MemCtrlBase(), PCIDevice("Grackle PCI host bridge") { this->name = "Grackle"; + /* add PCI/ISA I/O space, 64K for now */ + add_mmio_region(0xFE000000, 0x10000, this); + /* add memory mapped I/O region for MPC106 registers */ add_mmio_region(0xFEC00000, 0x300000, this); this->pci_0_bus.clear(); + this->io_space_devs.clear(); } MPC106::~MPC106() @@ -63,9 +67,23 @@ bool MPC106::supports_type(HWCompType type) uint32_t MPC106::read(uint32_t reg_start, uint32_t offset, int size) { - if (offset >= 0x200000) { - if (this->config_addr & 0x80) // process only if bit E (enable) is set - return pci_read(size); + uint32_t result; + + if (reg_start == 0xFE000000) { + /* broadcast I/O request to devices that support I/O space + until a device returns true that means "request accepted" */ + for (auto& dev : this->io_space_devs) { + if (dev->pci_io_read(offset, size, &result)) { + return result; + } + } + LOG_F(ERROR, "Attempt to read from unmapped PCI I/O space, offset=0x%X", offset); + } + else { + if (offset >= 0x200000) { + if (this->config_addr & 0x80) // process only if bit E (enable) is set + return pci_read(size); + } } /* FIXME: reading from CONFIG_ADDR is ignored for now */ @@ -75,11 +93,24 @@ uint32_t MPC106::read(uint32_t reg_start, uint32_t offset, int size) void MPC106::write(uint32_t reg_start, uint32_t offset, uint32_t value, int size) { - if (offset < 0x200000) { - this->config_addr = value; - } else { - if (this->config_addr & 0x80) // process only if bit E (enable) is set - return pci_write(value, size); + if (reg_start == 0xFE000000) { + /* broadcast I/O request to devices that support I/O space + until a device returns true that means "request accepted" */ + for (auto& dev : this->io_space_devs) { + if (dev->pci_io_write(offset, value, size)) { + return; + } + } + LOG_F(ERROR, "Attempt to write to unmapped PCI I/O space, offset=0x%X", offset); + } + else { + if (offset < 0x200000) { + this->config_addr = value; + } + else { + if (this->config_addr & 0x80) // process only if bit E (enable) is set + return pci_write(value, size); + } } } @@ -204,6 +235,10 @@ bool MPC106::pci_register_device(int dev_num, PCIDevice *dev_instance) dev_instance->set_host(this); + if (dev_instance->supports_io_space()) { + this->io_space_devs.push_back(dev_instance); + } + return true; } diff --git a/devices/mpc106.h b/devices/mpc106.h index cdc74d0..bd4b947 100644 --- a/devices/mpc106.h +++ b/devices/mpc106.h @@ -67,10 +67,8 @@ protected: uint32_t pci_cfg_read(uint32_t reg_offs, uint32_t size); void pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size); - void set_host(PCIHost *host_instance) {}; // unimplemented for now + bool supports_io_space(void) { return true; }; - /* PCI host bridge API */ - //bool pci_register_device(int dev_num, PCIDevice *dev_instance); bool pci_register_mmio_region(uint32_t start_addr, uint32_t size, PCIDevice *obj); void setup_ram(void); @@ -175,6 +173,7 @@ private: //uint32_t config_data; std::unordered_map pci_0_bus; + std::vector io_space_devs; }; #endif diff --git a/devices/pcidevice.h b/devices/pcidevice.h index 2ee1851..972abd7 100644 --- a/devices/pcidevice.h +++ b/devices/pcidevice.h @@ -30,8 +30,16 @@ along with this program. If not, see . /* convert little-endian DWORD to big-endian DWORD */ #define LE2BE(x) (x >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | (x << 24) +/** PCI configuration space registers offsets */ enum { - CFG_REG_BAR0 = 0x10 // base address register 0 + CFG_REG_CMD = 0x04, // command/status register + CFG_REG_BAR0 = 0x10, // base address register 0 + CFG_REG_BAR1 = 0x14, // base address register 1 + CFG_REG_BAR2 = 0x18, // base address register 2 + CFG_REG_BAR3 = 0x1C, // base address register 3 + CFG_REG_BAR4 = 0x20, // base address register 4 + CFG_REG_BAR5 = 0x24, // base address register 5 + CFG_EXP_BASE = 0x30, // expansion ROM base }; @@ -40,11 +48,20 @@ public: PCIDevice(std::string name) { this->pci_name = name; }; virtual ~PCIDevice() = default; + virtual bool supports_io_space(void) = 0; + + /* I/O space access methods */ + virtual bool pci_io_read(uint32_t offset, uint32_t size, uint32_t* res) + { return false; }; + + virtual bool pci_io_write(uint32_t offset, uint32_t value, uint32_t size) + { return false; }; + /* configuration space access methods */ virtual uint32_t pci_cfg_read(uint32_t reg_offs, uint32_t size) = 0; virtual void pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size) = 0; - virtual void set_host(PCIHost *host_instance) = 0; + virtual void set_host(PCIHost* host_instance) { this->host_instance = host_instance; }; protected: std::string pci_name; // human-readable device name