From cc17035e675ed2f371f3e8a19ac0dba03c087a89 Mon Sep 17 00:00:00 2001 From: Maxim Poliakovski Date: Sat, 4 Feb 2023 17:57:46 +0100 Subject: [PATCH] pcidevice: improve BAR configuration. --- devices/common/pci/pcidevice.cpp | 97 ++++++++++++++++++-------------- devices/common/pci/pcidevice.h | 28 +++++---- devices/ioctrl/grandcentral.cpp | 4 +- devices/ioctrl/heathrow.cpp | 7 +-- devices/ioctrl/ohare.cpp | 4 +- devices/video/atimach64gx.cpp | 4 +- devices/video/atirage.cpp | 10 ++-- devices/video/control.cpp | 10 ++-- 8 files changed, 92 insertions(+), 72 deletions(-) diff --git a/devices/common/pci/pcidevice.cpp b/devices/common/pci/pcidevice.cpp index 016f891..32fa0f0 100644 --- a/devices/common/pci/pcidevice.cpp +++ b/devices/common/pci/pcidevice.cpp @@ -1,6 +1,6 @@ /* DingusPPC - The Experimental PowerPC Macintosh emulator -Copyright (C) 2018-22 divingkatae and maximum +Copyright (C) 2018-23 divingkatae and maximum (theweirdo) spatium (Contact divingkatae#1017 or powermax#2286 on Discord for more info) @@ -123,6 +123,18 @@ void PCIDevice::pci_cfg_write(uint32_t reg_offs, uint32_t value, AccessDetails & } } +void PCIDevice::setup_bars(std::vector cfg_data) +{ + for (auto cfg_entry : cfg_data) { + if (cfg_entry.bar_num > 5) { + ABORT_F("BAR number %d out of range", cfg_entry.bar_num); + } + this->bars_cfg[cfg_entry.bar_num] = cfg_entry.bar_cfg; + } + + this->finish_config_bars(); +} + int PCIDevice::attach_exp_rom_image(const std::string img_path) { std::ifstream img_file; @@ -201,74 +213,73 @@ int PCIDevice::attach_exp_rom_image(const std::string img_path) return result; } -void PCIDevice::do_bar_sizing(int bar_num) -{ -} - void PCIDevice::set_bar_value(int bar_num, uint32_t value) { uint32_t bar_cfg = this->bars_cfg[bar_num]; switch (bars_typ[bar_num]) { - case BAR_Unused: + case PCIBarType::Unused: return; - case BAR_IO_16Bit: - case BAR_IO_32Bit: + case PCIBarType::Io_16_Bit: + case PCIBarType::Io_32_Bit: this->bars[bar_num] = (value & bar_cfg & ~3) | (bar_cfg & 3); break; - case BAR_MEM_20Bit: - case BAR_MEM_32Bit: - case BAR_MEM_64Bit: + case PCIBarType::Mem_20_Bit: + case PCIBarType::Mem_32_Bit: + case PCIBarType::Mem_64_Bit_Lo: this->bars[bar_num] = (value & bar_cfg & ~0xF) | (bar_cfg & 0xF); break; - case BAR_MEM_64BitHi: - this->bars[bar_num] = (value & bar_cfg); + case PCIBarType::Mem_64_Bit_Hi: + this->bars[bar_num] = value & bar_cfg; break; } - if (value == 0xFFFFFFFFUL) { - do_bar_sizing(bar_num); - return; - } - - this->pci_notify_bar_change(bar_num); + if (value != 0xFFFFFFFFUL) // don't notify the device during BAR sizing + this->pci_notify_bar_change(bar_num); } void PCIDevice::finish_config_bars() { for (int bar_num = 0; bar_num < 6; bar_num++) { uint32_t bar_cfg = this->bars_cfg[bar_num]; + + if (!bar_cfg) // skip unimplemented BARs + continue; + if (bar_cfg & 1) { - bars_typ[bar_num] = (bar_cfg & 0xffff0000) ? BAR_IO_32Bit : BAR_IO_16Bit; + bars_typ[bar_num] = (bar_cfg & 0xffff0000) ? PCIBarType::Io_32_Bit : + PCIBarType::Io_16_Bit; } - else if (bar_cfg != 0) { + else { int pci_space_type = (bar_cfg >> 1) & 3; switch (pci_space_type) { - case 0: - bars_typ[bar_num] = BAR_MEM_32Bit; - break; - case 1: - bars_typ[bar_num] = BAR_MEM_20Bit; - break; - case 2: - if (bar_num > 4) { - ABORT_F("%s: BAR %d cannot be 64-bit", this->pci_name.c_str(), bar_num); - } - else if (this->bars_cfg[bar_num+1] == 0) { - ABORT_F("%s: 64-bit BAR %d has zero for upper 32 bits", this->pci_name.c_str(), bar_num); - } - else { - bars_typ[bar_num++] = BAR_MEM_64Bit; - bars_typ[bar_num] = BAR_MEM_64BitHi; - } - break; - case 3: - ABORT_F("%s: invalid or unsupported PCI space type %d for BAR %d", this->pci_name.c_str(), pci_space_type, bar_num); - break; + case 0: + bars_typ[bar_num] = PCIBarType::Mem_32_Bit; + break; + case 1: + bars_typ[bar_num] = PCIBarType::Mem_20_Bit; + break; + case 2: + if (bar_num >= 5) { + ABORT_F("%s: BAR %d cannot be 64-bit", + this->pci_name.c_str(), bar_num); + } + else if (this->bars_cfg[bar_num+1] == 0) { + ABORT_F("%s: 64-bit BAR %d has zero for upper 32 bits", + this->pci_name.c_str(), bar_num); + } + else { + bars_typ[bar_num] = PCIBarType::Mem_64_Bit_Hi; + bars_typ[bar_num++] = PCIBarType::Mem_64_Bit_Lo; + } + break; + default: + ABORT_F("%s: invalid or unsupported PCI space type %d for BAR %d", + this->pci_name.c_str(), pci_space_type, bar_num); } // switch pci_space_type - } // if BAR_MEM + } } // for bar_num } diff --git a/devices/common/pci/pcidevice.h b/devices/common/pci/pcidevice.h index c215ea2..d1e48e9 100644 --- a/devices/common/pci/pcidevice.h +++ b/devices/common/pci/pcidevice.h @@ -1,6 +1,6 @@ /* DingusPPC - The Experimental PowerPC Macintosh emulator -Copyright (C) 2018-22 divingkatae and maximum +Copyright (C) 2018-23 divingkatae and maximum (theweirdo) spatium (Contact divingkatae#1017 or powermax#2286 on Discord for more info) @@ -29,6 +29,7 @@ along with this program. If not, see . #include #include #include +#include /** PCI configuration space registers offsets */ enum { @@ -59,16 +60,21 @@ enum { }; /** PCI BAR types */ -enum PCIBarType { - BAR_Unused, - BAR_IO_16Bit, - BAR_IO_32Bit, - BAR_MEM_20Bit, // < 1M - BAR_MEM_32Bit, - BAR_MEM_64Bit, - BAR_MEM_64BitHi, +enum PCIBarType : uint32_t { + Unused = 0, + Io_16_Bit, + Io_32_Bit, + Mem_20_Bit, // legacy type for < 1MB memory + Mem_32_Bit, + Mem_64_Bit_Lo, + Mem_64_Bit_Hi }; +typedef struct { + uint32_t bar_num; + uint32_t bar_cfg; +} BarConfig; + class PCIDevice : public MMIODevice { public: PCIDevice(std::string name); @@ -116,8 +122,8 @@ public: virtual void write(uint32_t rgn_start, uint32_t offset, uint32_t value, int size) { } protected: - void do_bar_sizing(int bar_num); void set_bar_value(int bar_num, uint32_t value); + void setup_bars(std::vector cfg_data); void finish_config_bars(); void map_exp_rom_mem(); @@ -143,7 +149,7 @@ protected: uint32_t bars[6] = { 0 }; // base address registers uint32_t bars_cfg[6] = { 0 }; // configuration values for base address registers - PCIBarType bars_typ[6] = { BAR_Unused }; // types for base address registers + PCIBarType bars_typ[6] = { PCIBarType::Unused }; // types for base address registers uint32_t exp_bar_cfg = 0; // expansion ROM configuration uint32_t exp_rom_bar = 0; // expansion ROM base address register diff --git a/devices/ioctrl/grandcentral.cpp b/devices/ioctrl/grandcentral.cpp index 18fc5f2..a129d8a 100644 --- a/devices/ioctrl/grandcentral.cpp +++ b/devices/ioctrl/grandcentral.cpp @@ -42,8 +42,8 @@ GrandCentral::GrandCentral() : PCIDevice("mac-io/grandcentral"), InterruptCtrl() this->device_id = 0x0002; this->class_rev = 0xFF000002; this->cache_ln_sz = 8; - this->bars_cfg[0] = 0xFFFE0000UL; // declare 128Kb of memory-mapped I/O space - this->finish_config_bars(); + + this->setup_bars({{0, 0xFFFE0000UL}}); // declare 128Kb of memory-mapped I/O space this->pci_notify_bar_change = [this](int bar_num) { this->notify_bar_change(bar_num); diff --git a/devices/ioctrl/heathrow.cpp b/devices/ioctrl/heathrow.cpp index 9331fb0..22fe65f 100644 --- a/devices/ioctrl/heathrow.cpp +++ b/devices/ioctrl/heathrow.cpp @@ -1,6 +1,6 @@ /* DingusPPC - The Experimental PowerPC Macintosh emulator -Copyright (C) 2018-22 divingkatae and maximum +Copyright (C) 2018-23 divingkatae and maximum (theweirdo) spatium (Contact divingkatae#1017 or powermax#2286 on Discord for more info) @@ -34,7 +34,6 @@ along with this program. If not, see . #include #include -#include #include /** Heathrow Mac I/O device emulation. @@ -54,8 +53,8 @@ HeathrowIC::HeathrowIC() : PCIDevice("mac-io/heathrow"), InterruptCtrl() this->class_rev = 0xFF000001; this->cache_ln_sz = 8; this->lat_timer = 0x40; - this->bars_cfg[0] = 0xFFF80000UL; // declare 512Kb of memory-mapped I/O space - this->finish_config_bars(); + + this->setup_bars({{0, 0xFFF80000UL}}); // declare 512Kb of memory-mapped I/O space this->pci_notify_bar_change = [this](int bar_num) { this->notify_bar_change(bar_num); diff --git a/devices/ioctrl/ohare.cpp b/devices/ioctrl/ohare.cpp index 50b1d03..8433ef9 100644 --- a/devices/ioctrl/ohare.cpp +++ b/devices/ioctrl/ohare.cpp @@ -36,8 +36,8 @@ OHare::OHare() : PCIDevice("mac-io/ohare"), InterruptCtrl() this->device_id = 0x0007; this->class_rev = 0xFF000001; this->cache_ln_sz = 8; - this->bars_cfg[0] = 0xFFF80000UL; // declare 512Kb of memory-mapped I/O space - this->finish_config_bars(); + + this->setup_bars({{0, 0xFFF80000UL}}); // declare 512Kb of memory-mapped I/O space this->pci_notify_bar_change = [this](int bar_num) { this->notify_bar_change(bar_num); diff --git a/devices/video/atimach64gx.cpp b/devices/video/atimach64gx.cpp index fa975f2..b4c6719 100644 --- a/devices/video/atimach64gx.cpp +++ b/devices/video/atimach64gx.cpp @@ -44,8 +44,8 @@ AtiMach64Gx::AtiMach64Gx() this->vendor_id = PCI_VENDOR_ATI; this->device_id = ATI_MACH64_GX_DEV_ID; this->class_rev = (0x030000 << 8) | 3; - this->bars_cfg[0] = 0xFF000000UL; // declare main aperture (16MB) - this->finish_config_bars(); + + this->setup_bars({{0, 0xFF000000UL}}); // declare main aperture (16MB) this->pci_notify_bar_change = [this](int bar_num) { this->notify_bar_change(bar_num); diff --git a/devices/video/atirage.cpp b/devices/video/atirage.cpp index f24c2c9..935dca1 100644 --- a/devices/video/atirage.cpp +++ b/devices/video/atirage.cpp @@ -124,10 +124,12 @@ ATIRage::ATIRage(uint16_t dev_id) this->class_rev = (0x030000 << 8) | asic_id; this->min_gnt = 8; this->irq_pin = 1; - this->bars_cfg[0] = 0xFF000000UL; // declare main aperture (16MB) - this->bars_cfg[1] = 0xFFFFFF01UL; // declare I/O region (256 bytes) - this->bars_cfg[2] = 0xFFFFF000UL; // declare register aperture (4KB) - this->finish_config_bars(); + + this->setup_bars({ + {0, 0xFF000000UL}, // declare main aperture (16MB) + {1, 0xFFFFFF01UL}, // declare I/O region (256 bytes) + {2, 0xFFFFF000UL} // declare register aperture (4KB) + }); this->pci_notify_bar_change = [this](int bar_num) { this->notify_bar_change(bar_num); diff --git a/devices/video/control.cpp b/devices/video/control.cpp index 30d26cd..123edf0 100644 --- a/devices/video/control.cpp +++ b/devices/video/control.cpp @@ -59,10 +59,12 @@ ControlVideo::ControlVideo() this->vendor_id = PCI_VENDOR_APPLE; this->device_id = 3; this->class_rev = 0; - this->bars_cfg[0] = 0xFFFFFFFFUL; // I/O region (4 bytes but it's weird because bit 1 is set) - this->bars_cfg[1] = 0xFFFFF000UL; // base address for the HW registers (4KB) - this->bars_cfg[2] = 0xFC000000UL; // base address for the VRAM (64MB) - this->finish_config_bars(); + + this->setup_bars({ + {0, 0xFFFFFFFFUL}, // I/O region (4 bytes but it's weird because bit 1 is set) + {1, 0xFFFFF000UL}, // base address for the HW registers (4KB) + {2, 0xFC000000UL} // base address for the VRAM (64MB) + }); this->pci_notify_bar_change = [this](int bar_num) { this->notify_bar_change(bar_num);