Add support for PCI I/O space.

This commit is contained in:
Maxim Poliakovski 2020-03-31 21:12:06 +02:00
parent cc5261cfa9
commit a243c79d0f
4 changed files with 66 additions and 15 deletions

View File

@ -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);

View File

@ -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;
}

View File

@ -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<int, PCIDevice*> pci_0_bus;
std::vector<PCIDevice*> io_space_devs;
};
#endif

View File

@ -30,8 +30,16 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
/* 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