DevPCI.cpp revision c79685b34475bd901e9bf729f068e621b0ddbbac
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * DevPCI - PCI BUS Device.
c58f1213e628a545081c70e26c6b67a841cff880vboxsync * Copyright (C) 2006-2007 Oracle Corporation
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * available from http://www.virtualbox.org. This file is free software;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * you can redistribute it and/or modify it under the terms of the GNU
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * General Public License (GPL) as published by the Free Software
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * --------------------------------------------------------------------
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * This code is based on:
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * QEMU PCI bus manager
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * Copyright (c) 2004 Fabrice Bellard
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * Permission is hereby granted, free of charge, to any person obtaining a copy
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * of this software and associated documentation files (the "Software"), to deal
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * in the Software without restriction, including without limitation the rights
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * copies of the Software, and to permit persons to whom the Software is
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * furnished to do so, subject to the following conditions:
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * The above copyright notice and this permission notice shall be included in
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * all copies or substantial portions of the Software.
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
230bd8589bba39933ac5ec21482d6186d675e604vboxsync * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync * THE SOFTWARE.
b72d3233df38e3122eda39b39a27b35c27209615vboxsync/*******************************************************************************
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync* Header Files *
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync*******************************************************************************/
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync/* Hack to get PCIDEVICEINT declare at the right point - include "PCIInternal.h". */
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync/*******************************************************************************
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync* Structures and Typedefs *
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync*******************************************************************************/
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync * PIIX3 ISA Bridge state.
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsynctypedef struct PIIX3State
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync /** The PCI device of the bridge. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * PCI Bus instance.
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsynctypedef struct PCIBus
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /** Bus number. */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /** Start device number. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** Number of bridges attached to the bus. */
230bd8589bba39933ac5ec21482d6186d675e604vboxsync /** Array of PCI devices. */
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync /** Array of bridges attached to the bus. */
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync /** R3 pointer to the device instance. */
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync /** Pointer to the PCI R3 helpers. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** R0 pointer to the device instance. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** Pointer to the PCI R0 helpers. */
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync /** RC pointer to the device instance. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** Pointer to the PCI RC helpers. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** The PCI device for the PCI bridge. */
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync/** Pointer to a PCIBUS instance. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync/** @def PCI_IRQ_PINS
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * Number of pins for interrupts (PIRQ#0...PIRQ#3)
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync/** @def PCI_APIC_IRQ_PINS
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync * Number of pins for interrupts if the APIC is used.
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * PCI Globals - This is the host-to-pci bridge and the root bus.
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsynctypedef struct PCIGLOBALS
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync /** Irq levels for the four PCI Irqs.
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync * These count how many devices asserted
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync * the IRQ line. If greater 0 an IRQ is sent to the guest.
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync * If it drops to 0 the IRQ is deasserted.
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** The next I/O port address which the PCI BIOS will use. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** The next MMIO address which the PCI BIOS will use. */
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync /** Actual bus number. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** I/O APIC usage flag */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** I/O APIC irq levels */
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync volatile uint32_t pci_apic_irq_levels[PCI_APIC_IRQ_PINS];
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** ACPI IRQ level */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** ACPI PIC IRQ */
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync /** Config register. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** R3 pointer to the device instance. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** R0 pointer to the device instance. */
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync /** RC pointer to the device instance. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** ISA bridge state. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /** PCI bus which is attached to the host-to-PCI bridge. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync/** Pointer to per VM data. */
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync/*******************************************************************************
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync* Defined Constants And Macros *
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync*******************************************************************************/
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync/** Converts a bus instance pointer to a device instance pointer. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync#define PCIBUS_2_DEVINS(pPciBus) ((pPciBus)->CTX_SUFF(pDevIns))
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync/** Converts a device instance pointer to a PCIGLOBALS pointer. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync#define DEVINS_2_PCIGLOBALS(pDevIns) ((PPCIGLOBALS)(PDMINS_2_DATA(pDevIns, PPCIGLOBALS)))
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync/** Converts a device instance pointer to a PCIBUS pointer. */
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync#define DEVINS_2_PCIBUS(pDevIns) ((PPCIBUS)(&PDMINS_2_DATA(pDevIns, PPCIGLOBALS)->PciBus))
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync/** Converts a pointer to a PCI bus instance to a PCIGLOBALS pointer.
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync * @note This works only if the bus number is 0!!!
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync#define PCIBUS_2_PCIGLOBALS(pPciBus) ( (PPCIGLOBALS)((uintptr_t)(pPciBus) - RT_OFFSETOF(PCIGLOBALS, PciBus)) )
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync/** @def PCI_LOCK
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync * Acquires the PDM lock. This is a NOP if locking is disabled. */
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync/** @def PCI_UNLOCK
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync * Releases the PDM lock. This is a NOP if locking is disabled. */
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync int rc2 = DEVINS_2_PCIBUS(pDevIns)->CTX_SUFF(pPciHlp)->pfnLock((pDevIns), rc); \
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync } while (0)
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync DEVINS_2_PCIBUS(pDevIns)->CTX_SUFF(pPciHlp)->pfnUnlock(pDevIns)
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync/** @def VBOX_PCI_SAVED_STATE_VERSION
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync * Saved state version of the PCI bus device.
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync/*******************************************************************************
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync* Internal Functions *
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync*******************************************************************************/
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsyncPDMBOTHCBDECL(void) pciSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTag);
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsyncPDMBOTHCBDECL(void) pcibridgeSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTag);
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsyncPDMBOTHCBDECL(int) pciIOPortAddressWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsyncPDMBOTHCBDECL(int) pciIOPortAddressRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsyncPDMBOTHCBDECL(int) pciIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsyncPDMBOTHCBDECL(int) pciIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsyncDECLINLINE(PPCIDEVICE) pciFindBridge(PPCIBUS pBus, uint8_t iBus);
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync#define PCI_COMMAND_IO 0x01 /* Enable response in I/O space */
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync#define PCI_COMMAND_MEMORY 0x02 /* Enable response in Memory space */
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync cmd = RT_LE2H_U16(*(uint16_t *)(d->config + PCI_COMMAND));
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync for(i = 0; i < PCI_NUM_REGIONS; i++) {
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync if (r->size != 0) {
b35e3948f1287430503b6b432945b8cf4bfd3a23vboxsync /* NOTE: we have only 64K ioports on PC */
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync /* the ROM slot has a specific enable bit */
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync /* NOTE: we do not support wrapping */
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync /* XXX: as we cannot support really dynamic
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync mappings, we handle specific values as invalid
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync mappings. */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /* now do the real mapping */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (r->addr != ~0U) {
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /* NOTE: specific hack for IDE in PC case:
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync only one byte must be mapped. */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync devclass = d->config[0x0a] | (d->config[0x0b] << 8);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync int rc = PDMDevHlpIOPortDeregister(d->pDevIns, r->addr + 2, 1);
aace59ca7fd1b66174593c5a564878cfac89e11evboxsync int rc = PDMDevHlpIOPortDeregister(d->pDevIns, r->addr, r->size);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (pBus->pPciHlpR3->pfnIsMMIO2Base(pBus->pDevInsR3, d->pDevIns, GCPhysBase))
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /* unmap it. */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync rc = r->map_func(d, i, NIL_RTGCPHYS, r->size, (PCIADDRESSSPACE)(r->type));
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync rc = PDMDevHlpMMIO2Unmap(d->pDevIns, i, GCPhysBase);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync rc = PDMDevHlpMMIODeregister(d->pDevIns, GCPhysBase, r->size);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync AssertMsgRC(rc, ("rc=%Rrc d=%s i=%d GCPhysBase=%RGp size=%#x\n", rc, d->name, i, GCPhysBase, r->size));
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (r->addr != ~0U) {
683eff3070b1b86fe71b71af7fda82766ea19d17vboxsync r->addr + (r->type & PCI_ADDRESS_SPACE_IO ? 0 : 0),
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsyncstatic DECLCALLBACK(uint32_t) pci_default_read_config(PCIDevice *d, uint32_t address, unsigned len)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync val = RT_LE2H_U16(*(uint16_t *)(d->config + address));
aace59ca7fd1b66174593c5a564878cfac89e11evboxsync val = RT_LE2H_U32(*(uint32_t *)(d->config + address));
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsyncstatic DECLCALLBACK(void) pci_default_write_config(PCIDevice *d, uint32_t address, uint32_t val, unsigned len)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync unsigned i;
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) ||
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (r->size == 0)
683eff3070b1b86fe71b71af7fda82766ea19d17vboxsync /* compute the stored value */
b72d3233df38e3122eda39b39a27b35c27209615vboxsync /* keep ROM enable bit */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync *(uint32_t *)(d->config + address) = RT_H2LE_U32(val);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /* not efficient, but simple */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync for(i = 0; i < len; i++) {
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /* default read/write accesses */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: /* base */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync case 0x30: case 0x31: case 0x32: case 0x33: /* rom */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync case 0x38: case 0x39: case 0x3a: case 0x3b: /* rom */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (addr == 0x05) /* Command register, bits 8-15. */
aace59ca7fd1b66174593c5a564878cfac89e11evboxsync /* don't change reserved bits (11-15) */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync else if (addr == 0x06) /* Status register, bits 0-7. */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /* don't change read-only bits => actually all lower bits are read-only */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /* status register, low part: clear bits by writing a '1' to the corresponding bit */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync else if (addr == 0x07) /* Status register, bits 8-15. */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /* don't change read-only bits */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /* status register, high part: clear bits by writing a '1' to the corresponding bit */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync if (end > PCI_COMMAND && address < (PCI_COMMAND + 2)) {
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync /* if the command register is modified, we must modify the mappings */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync#endif /* IN_RING3 */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsyncstatic int pci_data_write(PPCIGLOBALS pGlobals, uint32_t addr, uint32_t val, int len)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync Log(("pci_data_write: addr=%08x val=%08x len=%d\n", pGlobals->uConfigReg, val, len));
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync config_addr = (pGlobals->uConfigReg & 0xfc) | (addr & 3);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync#ifdef IN_RING3 /** @todo do lookup in R0/RC too! */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync PPCIDEVICE pBridgeDevice = pciFindBridge(&pGlobals->PciBus, iBus);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigWrite);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->pDevIns, iBus, iDevice, config_addr, val, len);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync R3PTRTYPE(PCIDevice *) pci_dev = pGlobals->PciBus.devices[iDevice];
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync Log(("pci_config_write: %s: addr=%02x val=%08x len=%d\n", pci_dev->name, config_addr, val, len));
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync pci_dev->Int.s.pfnConfigWrite(pci_dev, config_addr, val, len);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsyncstatic int pci_data_read(PPCIGLOBALS pGlobals, uint32_t addr, int len, uint32_t *pu32)
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync config_addr = (pGlobals->uConfigReg & 0xfc) | (addr & 3);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync#ifdef IN_RING3 /** @todo do lookup in R0/RC too! */
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync PPCIDEVICE pBridgeDevice = pciFindBridge(&pGlobals->PciBus, iBus);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigRead);
9b456547aefb8a2e8f5600eba9ec377dbc9b4475vboxsync *pu32 = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->pDevIns, iBus, iDevice, config_addr, len);
b72d3233df38e3122eda39b39a27b35c27209615vboxsync R3PTRTYPE(PCIDevice *) pci_dev = pGlobals->PciBus.devices[iDevice];
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync *pu32 = pci_dev->Int.s.pfnConfigRead(pci_dev, config_addr, len);
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync Log(("pci_config_read: %s: addr=%02x val=%08x len=%d\n", pci_dev->name, config_addr, *pu32, len));
return VINF_SUCCESS;
int slot_addend;
static void apic_set_irq(PPCIBUS pBus, uint8_t uDevFn, PCIDevice *pPciDev, int irq_num1, int iLevel, int acpi_irq, uint32_t uTagSrc)
static void pciSetIrqInternal(PPCIGLOBALS pGlobals, uint8_t uDevFn, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
if (fIsApicEnabled)
if (fIsAcpiDevice)
if (fIsAcpiDevice)
int irq_num;
pic_level = 0;
PDMBOTHCBDECL(void) pciSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
pciSetIrqInternal(PDMINS_2_DATA(pDevIns, PPCIGLOBALS), pPciDev->devfn, pPciDev, iIrq, iLevel, uTagSrc);
#ifdef IN_RING3
return pBridgeTemp;
return NULL;
pci_conf[0x82] = 0x02; /* Get rid of the Linux guest "Enabling Passive Release" PCI quirk warning. */
static void pci_config_writel(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint32_t addr, uint32_t val)
static void pci_config_writew(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint32_t addr, uint32_t val)
static void pci_config_writeb(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint32_t addr, uint32_t val)
return u32Val;
return u32Val;
return u32Val;
static void pci_set_io_region_addr(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, int region_num, uint32_t addr)
static void pci_bios_init_device(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint8_t cBridgeDepth, uint8_t *paBridgePositions)
switch(devclass)
goto default_map;
goto default_map;
pci_config_writeb(pGlobals, uBus, uDevFn, VBOX_PCI_SUBORDINATE_BUS, 0xff); /* Temporary until we know how many other bridges are behind this one. */
Log(("%s: Aligned I/O start address. New address %#x\n", __FUNCTION__, pGlobals->pci_bios_io_addr));
pci_config_writeb(pGlobals, uBus, uDevFn, VBOX_PCI_IO_BASE, (pGlobals->pci_bios_io_addr >> 8) & 0xf0);
Log(("%s: Aligned MMIO start address. New address %#x\n", __FUNCTION__, pGlobals->pci_bios_mem_addr));
pci_config_writew(pGlobals, uBus, uDevFn, VBOX_PCI_MEMORY_BASE, (pGlobals->pci_bios_mem_addr >> 16) & UINT32_C(0xffff0));
pci_config_writeb(pGlobals, uBus, uDevFn, VBOX_PCI_IO_LIMIT, ((pGlobals->pci_bios_io_addr >> 8) & 0xf0) - 1);
if ((u32MMIOAddressBase != pGlobals->pci_bios_mem_addr) && ((pGlobals->pci_bios_mem_addr % (1024 * 1024)) != 0))
pci_config_writew(pGlobals, uBus, uDevFn, VBOX_PCI_MEMORY_LIMIT, ((pGlobals->pci_bios_mem_addr >> 16) & UINT32_C(0xfff0)) - 1);
* which may be behind a bridge. That's why it is unconditionally disabled here atm by writing a higher value into
* PCI_NUM_REGIONS is 7 because of the rom region but there are only 6 base address register defined by the PCI spec.
* Leaving only PCI_NUM_REGIONS would cause reading another and enabling a memory region which does not exist.
Log(("%s: Size of region %u for device %d on bus %d is %u\n", __FUNCTION__, i, uDevFn, uBus, u32Size));
if (u32Size)
Log(("%s: Start address of %s region %u is %#x\n", __FUNCTION__, ((u8RessourceType & 0x01) == 1 ? "I/O" : "MMIO"), i, *paddr));
if (pin != 0)
pin--;
while (cBridgeDepth != 0)
cBridgeDepth--;
PDMBOTHCBDECL(int) pciIOPortAddressWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
return VINF_SUCCESS;
PDMBOTHCBDECL(int) pciIOPortAddressRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
return VINF_SUCCESS;
return VERR_IOM_IOPORT_UNUSED;
PDMBOTHCBDECL(int) pciIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
return rc;
PDMBOTHCBDECL(int) pciIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
return rc;
return VERR_IOM_IOPORT_UNUSED;
#ifdef IN_RING3
static DECLCALLBACK(int) pciGenericSaveExec(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PSSMHANDLE pSSM)
static DECLCALLBACK(int) pciGenericLoadExec(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PSSMHANDLE pSSM)
if (pDev)
return rc;
uint32_t i;
for (i = 0; i < PCI_IRQ_PINS; i++)
for (i = 0; i < PCI_APIC_IRQ_PINS; i++)
static const struct PciField
const char *pszName;
} s_aFields[] =
#ifdef RT_STRICT
while (cb-- > 0)
off++;
switch (cb)
AssertFailed();
pDev->name, pDev->pDevIns->iInstance, off, pbDstConfig[off], pbSrcConfig[off])); /** @todo make this Log() later. */
static DECLCALLBACK(int) pciR3CommonLoadExec(PPCIBUS pBus, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
uint32_t i;
int rc;
if (pDev)
return rc;
|| u32 < i)
return rc;
for (; i < u32; i++)
return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("New device in slot %#x, %s (vendor=%#06x device=%#06x)"),
i, pBus->devices[i]->name, PCIDevGetVendorId(pBus->devices[i]), PCIDevGetDeviceId(pBus->devices[i]));
DevTmp.Int.s.uIrqPinState = ~0; /* Invalid value in case we have an older saved state to force a state change in pciSetIrq. */
return rc;
return rc;
if (!pDev)
return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device in slot %#x has been removed! vendor=%#06x device=%#06x"),
return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device in slot %#x (%s) vendor id mismatch! saved=%.4Rhxs current=%.4Rhxs"),
return VINF_SUCCESS;
static DECLCALLBACK(int) pciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
int rc;
return rc;
if (iDev < 0)
return VERR_PDM_TOO_PCI_MANY_DEVICES;
int iDevRel;
return VERR_INTERNAL_ERROR;
Log(("PCI: relocating '%s' from slot %#x to %#x\n", pBus->devices[iDev + i]->name, iDev + i, iDevRel + i));
return VERR_PDM_TOO_PCI_MANY_DEVICES;
AssertMsg(pBus->cBridges < RT_ELEMENTS(pBus->devices), ("Number of bridges exceeds the number of possible devices on the bus\n"));
return VINF_SUCCESS;
static DECLCALLBACK(int) pciRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, const char *pszName, int iDev)
if ( !pszName
|| !pPciDev
return VERR_INVALID_PARAMETER;
static DECLCALLBACK(int) pciIORegionRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iRegion, uint32_t cbRegion, PCIADDRESSSPACE enmType, PFNPCIIOREGIONMAP pfnCallback)
return VINF_SUCCESS;
static DECLCALLBACK(void) pciSetConfigCallbacks(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld,
if (ppfnReadOld)
if (ppfnWriteOld)
return VINF_SUCCESS;
for (int i = 0; i < iIndent; i++)
if (iRegionSize == 0)
const char * pszDesc;
if (f64Bit)
iRegion++;
if (fRegisters)
while (iPerLine-- > 0)
bool fUseIoApic;
bool fGCEnabled;
bool fR0Enabled;
Log(("PCI: fUseIoApic=%RTbool fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fUseIoApic, fGCEnabled, fR0Enabled));
pGlobals->PciBus.papBridgesR3 = (PPCIDEVICE *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPCIDEVICE) * RT_ELEMENTS(pGlobals->PciBus.devices));
PCIDevSetDeviceId( &pGlobals->PIIX3State.dev, 0x7000); /* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */
rc = PDMDevHlpIOPortRegister(pDevIns, 0x0cf8, 1, NULL, pciIOPortAddressWrite, pciIOPortAddressRead, NULL, NULL, "i440FX (PCI)");
return rc;
rc = PDMDevHlpIOPortRegister(pDevIns, 0x0cfc, 4, NULL, pciIOPortDataWrite, pciIOPortDataRead, NULL, NULL, "i440FX (PCI)");
return rc;
if (fGCEnabled)
rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x0cf8, 1, NIL_RTGCPTR, "pciIOPortAddressWrite", "pciIOPortAddressRead", NULL, NULL, "i440FX (PCI)");
return rc;
rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x0cfc, 4, NIL_RTGCPTR, "pciIOPortDataWrite", "pciIOPortDataRead", NULL, NULL, "i440FX (PCI)");
return rc;
if (fR0Enabled)
rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x0cf8, 1, NIL_RTR0PTR, "pciIOPortAddressWrite", "pciIOPortAddressRead", NULL, NULL, "i440FX (PCI)");
return rc;
rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x0cfc, 4, NIL_RTR0PTR, "pciIOPortDataWrite", "pciIOPortDataRead", NULL, NULL, "i440FX (PCI)");
return rc;
return rc;
PDMDevHlpDBGFInfoRegister(pDevIns, "pci", "Display PCI bus status. Recognizes 'basic' or 'verbose' "
PDMDevHlpDBGFInfoRegister(pDevIns, "pciirq", "Display PCI IRQ routing state. (no arguments)", pciIrqInfo);
return VINF_SUCCESS;
sizeof(PCIGLOBALS),
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
PDMBOTHCBDECL(void) pcibridgeSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
* of our parent passing the device which asserted the interrupt instead of the device of the bridge.
pciSetIrqInternal(PCIBUS_2_PCIGLOBALS(pBus), uDevFnBridge, pPciDev, iIrqPinBridge, iLevel, uTagSrc);
#ifdef IN_RING3
static void pcibridgeConfigWrite(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice, uint32_t u32Address, uint32_t u32Value, unsigned cb)
LogFlowFunc((": pDevIns=%p iBus=%d iDevice=%d u32Address=%u u32Value=%u cb=%d\n", pDevIns, iBus, iDevice, u32Address, u32Value, cb));
if (pBridgeDevice)
pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->pDevIns, iBus, iDevice, u32Address, u32Value, cb);
if (pPciDev)
Log(("%s: %s: addr=%02x val=%08x len=%d\n", __FUNCTION__, pPciDev->name, u32Address, u32Value, cb));
static uint32_t pcibridgeConfigRead(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice, uint32_t u32Address, unsigned cb)
LogFlowFunc((": pDevIns=%p iBus=%d iDevice=%d u32Address=%u cb=%d\n", pDevIns, iBus, iDevice, u32Address, cb));
if (pBridgeDevice)
u32Value = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->pDevIns, iBus, iDevice, u32Address, cb);
if (pPciDev)
Log(("%s: %s: u32Address=%02x u32Value=%08x cb=%d\n", __FUNCTION__, pPciDev->name, u32Address, u32Value, cb));
return u32Value;
static DECLCALLBACK(int) pcibridgeR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
static DECLCALLBACK(int) pcibridgeRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, const char *pszName, int iDev)
if ( !pszName
|| !pPciDev
return VERR_INVALID_PARAMETER;
bool fGCEnabled;
bool fR0Enabled;
pBus->papBridgesR3 = (PPCIDEVICE *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPCIDEVICE) * RT_ELEMENTS(pBus->devices));
PCIDevSetHeaderType(&pBus->PciDev, 0x01); /* Single function device which adheres to the PCI-to-PCI bridge spec. */
return rc;
return rc;
return VINF_SUCCESS;
sizeof(PCIBUS),
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,