From 1b9878ffcfc0c0dbc4a6e674827fe508ba77db4b Mon Sep 17 00:00:00 2001 From: Bart Trojanowski Date: Thu, 13 Mar 2008 17:42:16 -0400 Subject: [PATCH] Bug #14332: Fix PCI access cycles from x86emu. The address written to 0xcf8 contains the PCI slot address to send the config cycle to. However, we would ignore that and always send the cycle to the device whose BIOS we were running. This breaks some integrated graphics platforms that have explicit knowledge about the system's host bridge, for example. --- hw/xfree86/int10/helper_exec.c | 57 +++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/hw/xfree86/int10/helper_exec.c b/hw/xfree86/int10/helper_exec.c index de6fde5d8..9daff22dc 100644 --- a/hw/xfree86/int10/helper_exec.c +++ b/hw/xfree86/int10/helper_exec.c @@ -33,6 +33,7 @@ #ifdef _X86EMU #include "x86emu/x86emui.h" #endif +#include static int pciCfg1in(CARD16 addr, CARD32 *val); static int pciCfg1out(CARD16 addr, CARD32 val); @@ -459,7 +460,43 @@ Mem_wl(CARD32 addr, CARD32 val) static CARD32 PciCfg1Addr = 0; -#define OFFSET(Cfg1Addr) (Cfg1Addr & 0xff) +#define PCI_OFFSET(x) ((x) & 0x000000ff) +#define PCI_TAG(x) ((x) & 0xffffff00) + +static struct pci_device* +pci_device_for_cfg_address (CARD32 addr) +{ + struct pci_device *dev = NULL; + PCITAG tag = PCI_TAG(addr); + struct pci_slot_match slot_match = { + .domain = PCI_DOM_FROM_TAG(tag), + .bus = PCI_BUS_NO_DOMAIN(PCI_BUS_FROM_TAG(tag)), + .dev = PCI_DEV_FROM_TAG(tag), + .func = PCI_FUNC_FROM_TAG(tag), + .match_data = 0 + }; + + struct pci_device_iterator *iter = + pci_slot_match_iterator_create (&slot_match); + if (iter) + dev = pci_device_next(iter); + if (!dev) { + char buf[128]; /* enough to store "%u@%u" */ + xf86FormatPciBusNumber(tag >> 16, buf); + ErrorF("Failed to find device matching %s:%u:%u\n", + buf, slot_match.dev, slot_match.func); + return NULL; + } + + if (pci_device_next(iter)) { + char buf[128]; /* enough to store "%u@%u" */ + xf86FormatPciBusNumber(tag >> 16, buf); + ErrorF("Multiple devices matching %s:%u:%u\n", + buf, slot_match.dev, slot_match.func); + } + + return dev; +} static int pciCfg1in(CARD16 addr, CARD32 *val) @@ -469,7 +506,8 @@ pciCfg1in(CARD16 addr, CARD32 *val) return 1; } if (addr == 0xCFC) { - pci_device_cfg_read_u32(Int10Current->dev, val, OFFSET(PciCfg1Addr)); + pci_device_cfg_read_u32(pci_device_for_cfg_address(PciCfg1Addr), + val, PCI_OFFSET(PciCfg1Addr)); if (PRINT_PORT && DEBUG_IO_TRACE()) ErrorF(" cfg_inl(%#x) = %8.8x\n", PciCfg1Addr, *val); return 1; @@ -487,7 +525,8 @@ pciCfg1out(CARD16 addr, CARD32 val) if (addr == 0xCFC) { if (PRINT_PORT && DEBUG_IO_TRACE()) ErrorF(" cfg_outl(%#x, %8.8x)\n", PciCfg1Addr, val); - pci_device_cfg_write_u32(Int10Current->dev, val, OFFSET(PciCfg1Addr)); + pci_device_cfg_write_u32(pci_device_for_cfg_address(PciCfg1Addr), + val, PCI_OFFSET(PciCfg1Addr)); return 1; } return 0; @@ -506,7 +545,8 @@ pciCfg1inw(CARD16 addr, CARD16 *val) if ((addr >= 0xCFC) && (addr <= 0xCFF)) { const unsigned offset = addr - 0xCFC; - pci_device_cfg_read_u16(Int10Current->dev, val, OFFSET(PciCfg1Addr) + offset); + pci_device_cfg_read_u16(pci_device_for_cfg_address(PciCfg1Addr), + val, PCI_OFFSET(PciCfg1Addr) + offset); if (PRINT_PORT && DEBUG_IO_TRACE()) ErrorF(" cfg_inw(%#x) = %4.4x\n", PciCfg1Addr + offset, *val); return 1; @@ -530,7 +570,8 @@ pciCfg1outw(CARD16 addr, CARD16 val) if (PRINT_PORT && DEBUG_IO_TRACE()) ErrorF(" cfg_outw(%#x, %4.4x)\n", PciCfg1Addr + offset, val); - pci_device_cfg_write_u16(Int10Current->dev, val, OFFSET(PciCfg1Addr) + offset); + pci_device_cfg_write_u16(pci_device_for_cfg_address(PciCfg1Addr), + val, PCI_OFFSET(PciCfg1Addr) + offset); return 1; } return 0; @@ -549,7 +590,8 @@ pciCfg1inb(CARD16 addr, CARD8 *val) if ((addr >= 0xCFC) && (addr <= 0xCFF)) { const unsigned offset = addr - 0xCFC; - pci_device_cfg_read_u8(Int10Current->dev, val, OFFSET(PciCfg1Addr) + offset); + pci_device_cfg_read_u8(pci_device_for_cfg_address(PciCfg1Addr), + val, PCI_OFFSET(PciCfg1Addr) + offset); if (PRINT_PORT && DEBUG_IO_TRACE()) ErrorF(" cfg_inb(%#x) = %2.2x\n", PciCfg1Addr + offset, *val); return 1; @@ -573,7 +615,8 @@ pciCfg1outb(CARD16 addr, CARD8 val) if (PRINT_PORT && DEBUG_IO_TRACE()) ErrorF(" cfg_outb(%#x, %2.2x)\n", PciCfg1Addr + offset, val); - pci_device_cfg_write_u8(Int10Current->dev, val, OFFSET(PciCfg1Addr) + offset); + pci_device_cfg_write_u8(pci_device_for_cfg_address(PciCfg1Addr), + val, PCI_OFFSET(PciCfg1Addr) + offset); return 1; } return 0;