pci: Change pci_conv_rd_data unaligned.

pci_conv_rd_data can be used to handle unaligned or 64-bit accesses in mmio regions if it's modified to include the next 32-bit value.
For pci config accesses, grackle repeats the 32-bit value. bandit uses a seemingly random number for the next 32-bit value, but we'll make it work like grackle.
This commit is contained in:
joevt 2023-06-14 21:55:43 -07:00 committed by dingusdev
parent 6d23e18c11
commit 54bda0ea95
3 changed files with 18 additions and 10 deletions

View File

@ -147,7 +147,10 @@ uint32_t BanditHost::read(uint32_t rgn_start, uint32_t offset, int size)
cfg_setup(offset, size, bus_num, dev_num, fun_num, reg_offs, details, device);
details.flags |= PCI_CONFIG_READ;
if (device) {
return pci_conv_rd_data(device->pci_cfg_read(reg_offs, details), details);
uint32_t value = device->pci_cfg_read(reg_offs, details);
// bytes 4 to 7 are random on bandit but
// we choose to repeat bytes 0 to 3 like grackle
return pci_conv_rd_data(value, value, details);
}
LOG_READ_NON_EXISTENT_PCI_DEVICE();
return 0xFFFFFFFFUL; // PCI spec §6.1

View File

@ -93,11 +93,11 @@ protected:
// Helpers for data conversion in the PCI Configuration space.
/**
Perform size dependent endian swapping for value that is dword from PCI config.
Perform size dependent endian swapping for value that is dword from PCI config or any other dword little endian register.
Unaligned data is handled properly by wrapping around if needed.
Unaligned data is handled properly by using bytes from the next dword.
*/
inline uint32_t pci_conv_rd_data(uint32_t value, AccessDetails &details) {
inline uint32_t pci_conv_rd_data(uint32_t value, uint32_t value2, AccessDetails &details) {
switch (details.size << 2 | details.offset) {
// Bytes
case 0x04:
@ -117,17 +117,20 @@ inline uint32_t pci_conv_rd_data(uint32_t value, AccessDetails &details) {
case 0x0A:
return BYTESWAP_16((value >> 16) & 0xFFFFU); // 2 3
case 0x0B:
return ((value >> 16) & 0xFF00) | (value & 0xFF); // 3 0
return ((value >> 16) & 0xFF00) | (value2 & 0xFF); // 3 4
// Dwords
case 0x10:
return BYTESWAP_32(value); // 0 1 2 3
return BYTESWAP_32(value); // 0 1 2 3
case 0x11:
return ROTL_32(BYTESWAP_32(value), 8); // 1 2 3 0
value = (uint32_t)((((uint64_t)value2 << 32) | value) >> 8);
return BYTESWAP_32(value); // 1 2 3 4
case 0x12:
return ROTL_32(BYTESWAP_32(value), 16); // 2 3 0 1
value = (uint32_t)((((uint64_t)value2 << 32) | value) >> 16);
return BYTESWAP_32(value); // 2 3 4 5
case 0x13:
return ROTR_32(BYTESWAP_32(value), 8); // 3 0 1 2
value = (uint32_t)((((uint64_t)value2 << 32) | value) >> 24);
return BYTESWAP_32(value); // 3 4 5 6
default:
return 0xFFFFFFFFUL;
}

View File

@ -86,7 +86,9 @@ uint32_t MPC106::read(uint32_t rgn_start, uint32_t offset, int size) {
cfg_setup(offset, size, bus_num, dev_num, fun_num, reg_offs, details, device);
details.flags |= PCI_CONFIG_READ;
if (device) {
return pci_conv_rd_data(device->pci_cfg_read(reg_offs, details), details);
uint32_t value = device->pci_cfg_read(reg_offs, details);
// bytes 0 to 3 repeat
return pci_conv_rd_data(value, value, details);
}
LOG_READ_NON_EXISTENT_PCI_DEVICE();
return 0xFFFFFFFFUL; // PCI spec §6.1