mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-12-24 12:30:05 +00:00
pcidevice: loading of expansion ROMs from files.
This commit is contained in:
parent
4bba61a920
commit
b78f17c161
@ -26,6 +26,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
#include <memaccess.h>
|
#include <memaccess.h>
|
||||||
|
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
PCIDevice::PCIDevice(std::string name)
|
PCIDevice::PCIDevice(std::string name)
|
||||||
{
|
{
|
||||||
@ -132,7 +134,13 @@ void PCIDevice::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size)
|
|||||||
if (data == 0xFFFFF800UL) {
|
if (data == 0xFFFFF800UL) {
|
||||||
this->exp_rom_bar = this->exp_bar_cfg;
|
this->exp_rom_bar = this->exp_bar_cfg;
|
||||||
} else {
|
} else {
|
||||||
this->exp_rom_bar = (data & 0xFFFFF800UL) | (this->exp_bar_cfg & 1);
|
this->exp_rom_bar = (data & 0xFFFFF801UL);
|
||||||
|
if (this->exp_rom_bar & 1) {
|
||||||
|
this->map_exp_rom_mem(this->exp_rom_bar & 0xFFFFF800UL);
|
||||||
|
} else {
|
||||||
|
LOG_F(WARNING, "%s: unmapping of expansion ROM not implemented yet",
|
||||||
|
this->pci_name.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PCI_CFG_DWORD_15:
|
case PCI_CFG_DWORD_15:
|
||||||
@ -144,6 +152,70 @@ void PCIDevice::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int PCIDevice::attach_exp_rom_image(const std::string img_path)
|
||||||
|
{
|
||||||
|
std::ifstream img_file;
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
this->exp_bar_cfg = 0; // tell the world we got no ROM for now
|
||||||
|
|
||||||
|
try {
|
||||||
|
img_file.open(img_path, std::ios::in | std::ios::binary);
|
||||||
|
if (img_file.fail()) {
|
||||||
|
throw std::runtime_error("could not open specified ROM dump image");
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate image file
|
||||||
|
uint8_t buf[4] = { 0 };
|
||||||
|
|
||||||
|
img_file.seekg(0, std::ios::beg);
|
||||||
|
img_file.read((char *)buf, sizeof(buf));
|
||||||
|
|
||||||
|
if (buf[0] != 0x55 || buf[1] != 0xAA) {
|
||||||
|
throw std::runtime_error("invalid expansion ROM signature");
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine image size
|
||||||
|
img_file.seekg(0, std::ios::end);
|
||||||
|
this->exp_rom_size = img_file.tellg();
|
||||||
|
|
||||||
|
// verify PCI struct offset
|
||||||
|
uint32_t pci_struct_offset = 0;
|
||||||
|
img_file.seekg(0x18, std::ios::beg);
|
||||||
|
img_file.read((char *)&pci_struct_offset, sizeof(pci_struct_offset));
|
||||||
|
|
||||||
|
if (pci_struct_offset > this->exp_rom_size) {
|
||||||
|
throw std::runtime_error("invalid PCI structure offset");
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify PCI struct signature
|
||||||
|
img_file.seekg(pci_struct_offset, std::ios::beg);
|
||||||
|
img_file.read((char *)buf, sizeof(buf));
|
||||||
|
|
||||||
|
if (buf[0] != 'P' || buf[1] != 'C' || buf[2] != 'I' || buf[3] != 'R') {
|
||||||
|
throw std::runtime_error("unexpected PCI struct signature");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ROM image ok - go ahead and load it
|
||||||
|
this->exp_rom_data = std::unique_ptr<uint8_t[]> (new uint8_t[this->exp_rom_size]);
|
||||||
|
img_file.seekg(0, std::ios::beg);
|
||||||
|
img_file.read((char *)this->exp_rom_data.get(), this->exp_rom_size);
|
||||||
|
|
||||||
|
// align ROM image size on a 2KB boundary and initialize ROM config
|
||||||
|
this->exp_rom_size = (this->exp_rom_size + 0x7FFU) & 0xFFFFF800UL;
|
||||||
|
this->exp_bar_cfg = ~(this->exp_rom_size - 1);
|
||||||
|
}
|
||||||
|
catch (const std::exception& exc) {
|
||||||
|
LOG_F(ERROR, "PCIDevice: %s", exc.what());
|
||||||
|
result = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
img_file.close();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void PCIDevice::do_bar_sizing(int bar_num)
|
void PCIDevice::do_bar_sizing(int bar_num)
|
||||||
{
|
{
|
||||||
this->bars[bar_num] = this->bars_cfg[bar_num];
|
this->bars[bar_num] = this->bars_cfg[bar_num];
|
||||||
@ -162,3 +234,10 @@ void PCIDevice::set_bar_value(int bar_num, uint32_t value)
|
|||||||
}
|
}
|
||||||
this->pci_notify_bar_change(bar_num);
|
this->pci_notify_bar_change(bar_num);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PCIDevice::map_exp_rom_mem(uint32_t rom_addr)
|
||||||
|
{
|
||||||
|
if (!this->exp_rom_addr || this->exp_rom_addr != rom_addr) {
|
||||||
|
this->host_instance->pci_register_mmio_region(rom_addr, 0x10000, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -27,6 +27,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
/** PCI configuration space registers offsets */
|
/** PCI configuration space registers offsets */
|
||||||
@ -91,6 +92,8 @@ public:
|
|||||||
|
|
||||||
std::function<void(int)> pci_notify_bar_change;
|
std::function<void(int)> pci_notify_bar_change;
|
||||||
|
|
||||||
|
int attach_exp_rom_image(const std::string img_path);
|
||||||
|
|
||||||
virtual void set_host(PCIHost* host_instance) {
|
virtual void set_host(PCIHost* host_instance) {
|
||||||
this->host_instance = host_instance;
|
this->host_instance = host_instance;
|
||||||
};
|
};
|
||||||
@ -98,6 +101,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
void do_bar_sizing(int bar_num);
|
void do_bar_sizing(int bar_num);
|
||||||
void set_bar_value(int bar_num, uint32_t value);
|
void set_bar_value(int bar_num, uint32_t value);
|
||||||
|
void map_exp_rom_mem(uint32_t rom_addr);
|
||||||
|
|
||||||
std::string pci_name; // human-readable device name
|
std::string pci_name; // human-readable device name
|
||||||
PCIHost* host_instance; // host bridge instance to call back
|
PCIHost* host_instance; // host bridge instance to call back
|
||||||
@ -120,8 +124,13 @@ protected:
|
|||||||
|
|
||||||
uint32_t bars[6] = { 0 }; // base address registers
|
uint32_t bars[6] = { 0 }; // base address registers
|
||||||
uint32_t bars_cfg[6] = { 0 }; // configuration values for base address registers
|
uint32_t bars_cfg[6] = { 0 }; // configuration values for base address registers
|
||||||
uint32_t exp_rom_bar = 0; // expansion ROM base address
|
|
||||||
uint32_t exp_bar_cfg = 0;
|
uint32_t exp_bar_cfg = 0; // expansion ROM configuration
|
||||||
|
uint32_t exp_rom_bar = 0; // expansion ROM base address register
|
||||||
|
uint32_t exp_rom_addr = 0; // expansion ROM base address
|
||||||
|
uint32_t exp_rom_size = 0; // expansion ROM size in bytes
|
||||||
|
|
||||||
|
std::unique_ptr<uint8_t[]> exp_rom_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* PCI_DEVICE_H */
|
#endif /* PCI_DEVICE_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user