DevPCI.cpp revision d91fdc7bce3c48308e9dfc26fc582f8ba5f60f06
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * DevPCI - PCI BUS Device.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * Copyright (C) 2006-2007 Oracle Corporation
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * available from http://www.virtualbox.org. This file is free software;
d63de4508a08b11f57c307a15eda3cd95485bf2cvboxsync * you can redistribute it and/or modify it under the terms of the GNU
d63de4508a08b11f57c307a15eda3cd95485bf2cvboxsync * General Public License (GPL) as published by the Free Software
d63de4508a08b11f57c307a15eda3cd95485bf2cvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
d63de4508a08b11f57c307a15eda3cd95485bf2cvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * --------------------------------------------------------------------
a3d06a524c4f1cde2f0eada83656543d5a24115dvboxsync * This code is based on:
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * QEMU PCI bus manager
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * Copyright (c) 2004 Fabrice Bellard
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * Permission is hereby granted, free of charge, to any person obtaining a copy
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * of this software and associated documentation files (the "Software"), to deal
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * in the Software without restriction, including without limitation the rights
88350256a6c78b8631aba5aa5ce249d90a8514a2vboxsync * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * copies of the Software, and to permit persons to whom the Software is
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * furnished to do so, subject to the following conditions:
943d182735b76ecae26ea011cb7b87e449aafea8vboxsync * The above copyright notice and this permission notice shall be included in
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * all copies or substantial portions of the Software.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * THE SOFTWARE.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync/*******************************************************************************
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync* Header Files *
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync*******************************************************************************/
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync/* Hack to get PCIDEVICEINT declare at the right point - include "PCIInternal.h". */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync/*******************************************************************************
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync* Structures and Typedefs *
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync*******************************************************************************/
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * PIIX3 ISA Bridge state.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsynctypedef struct PIIX3State
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** The PCI device of the bridge. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * PCI Bus instance.
58b7773f17a933ab8d53f450bed0afcf2f003508vboxsynctypedef struct PCIBus
c48c4d769ded37e2496f97dddbbd36dc62f244b1vboxsync /** Bus number. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** Start device number. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** Number of bridges attached to the bus. */
e7159a7ab092aaf8a7423d811c2b7a8286e2669bvboxsync /** Array of PCI devices. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** Array of bridges attached to the bus. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** R3 pointer to the device instance. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** Pointer to the PCI R3 helpers. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** R0 pointer to the device instance. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** Pointer to the PCI R0 helpers. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** RC pointer to the device instance. */
c6adb272ec43d5eaadb1493cb2bf45f2f8adf588vboxsync /** Pointer to the PCI RC helpers. */
c48c4d769ded37e2496f97dddbbd36dc62f244b1vboxsync /** The PCI device for the PCI bridge. */
257927abbaa6d9774427049fcbea552cda362281vboxsync/** Pointer to a PCIBUS instance. */
c48c4d769ded37e2496f97dddbbd36dc62f244b1vboxsync/** @def PCI_IRQ_PINS
c48c4d769ded37e2496f97dddbbd36dc62f244b1vboxsync * Number of pins for interrupts (PIRQ#0...PIRQ#3)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync/** @def PCI_APIC_IRQ_PINS
a3d06a524c4f1cde2f0eada83656543d5a24115dvboxsync * Number of pins for interrupts if the APIC is used.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * PCI Globals - This is the host-to-pci bridge and the root bus.
e7159a7ab092aaf8a7423d811c2b7a8286e2669bvboxsynctypedef struct PCIGLOBALS
4bc1bbf45f30ff3ca38c2ad006836e490972c7ccvboxsync /** Irq levels for the four PCI Irqs.
4bc1bbf45f30ff3ca38c2ad006836e490972c7ccvboxsync * These count how many devices asserted
4bc1bbf45f30ff3ca38c2ad006836e490972c7ccvboxsync * the IRQ line. If greater 0 an IRQ is sent to the guest.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * If it drops to 0 the IRQ is deasserted.
73e8df2e481cb3697372a3cf4acffd068a7f1296vboxsync /** The next I/O port address which the PCI BIOS will use. */
d293c8e7a1adaf427e7a361add878676749b7da6vboxsync /** The next MMIO address which the PCI BIOS will use. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** Actual bus number. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** I/O APIC usage flag */
73e8df2e481cb3697372a3cf4acffd068a7f1296vboxsync /** I/O APIC irq levels */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync volatile uint32_t pci_apic_irq_levels[PCI_APIC_IRQ_PINS];
d293c8e7a1adaf427e7a361add878676749b7da6vboxsync /** ACPI IRQ level */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** ACPI PIC IRQ */
9704f1d0180960069e2c4eb8fe2ddee350910e5dvboxsync /** Config register. */
9704f1d0180960069e2c4eb8fe2ddee350910e5dvboxsync /** R3 pointer to the device instance. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** R0 pointer to the device instance. */
a3d06a524c4f1cde2f0eada83656543d5a24115dvboxsync /** RC pointer to the device instance. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** ISA bridge state. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /** PCI bus which is attached to the host-to-PCI bridge. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync/** Pointer to per VM data. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync/*******************************************************************************
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync* Defined Constants And Macros *
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync*******************************************************************************/
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync/** Converts a bus instance pointer to a device instance pointer. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync#define PCIBUS_2_DEVINS(pPciBus) ((pPciBus)->CTX_SUFF(pDevIns))
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync/** Converts a device instance pointer to a PCIGLOBALS pointer. */
58b7773f17a933ab8d53f450bed0afcf2f003508vboxsync#define DEVINS_2_PCIGLOBALS(pDevIns) ((PPCIGLOBALS)(PDMINS_2_DATA(pDevIns, PPCIGLOBALS)))
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync/** Converts a device instance pointer to a PCIBUS pointer. */
58b7773f17a933ab8d53f450bed0afcf2f003508vboxsync#define DEVINS_2_PCIBUS(pDevIns) ((PPCIBUS)(&PDMINS_2_DATA(pDevIns, PPCIGLOBALS)->PciBus))
58b7773f17a933ab8d53f450bed0afcf2f003508vboxsync/** Converts a pointer to a PCI bus instance to a PCIGLOBALS pointer.
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * @note This works only if the bus number is 0!!!
58b7773f17a933ab8d53f450bed0afcf2f003508vboxsync#define PCIBUS_2_PCIGLOBALS(pPciBus) ( (PPCIGLOBALS)((uintptr_t)(pPciBus) - RT_OFFSETOF(PCIGLOBALS, PciBus)) )
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync/** @def PCI_LOCK
14dcfe007d2a64583946ed5e4cfdb458a7f7f03bvboxsync * Acquires the PDM lock. This is a NOP if locking is disabled. */
14dcfe007d2a64583946ed5e4cfdb458a7f7f03bvboxsync/** @def PCI_UNLOCK
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync * Releases the PDM lock. This is a NOP if locking is disabled. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync int rc2 = DEVINS_2_PCIBUS(pDevIns)->CTX_SUFF(pPciHlp)->pfnLock((pDevIns), rc); \
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync } while (0)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync DEVINS_2_PCIBUS(pDevIns)->CTX_SUFF(pPciHlp)->pfnUnlock(pDevIns)
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync/** @def VBOX_PCI_SAVED_STATE_VERSION
cf5af7fccfec4bef83f4ec21662d6a6e6cbe3835vboxsync * Saved state version of the PCI bus device.
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync/*******************************************************************************
87c50c527af59e43745475c4b8ac907c5f9bc204vboxsync* Internal Functions *
87c50c527af59e43745475c4b8ac907c5f9bc204vboxsync*******************************************************************************/
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsyncPDMBOTHCBDECL(void) pciSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel);
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsyncPDMBOTHCBDECL(void) pcibridgeSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel);
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsyncPDMBOTHCBDECL(int) pciIOPortAddressWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsyncPDMBOTHCBDECL(int) pciIOPortAddressRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsyncPDMBOTHCBDECL(int) pciIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsyncPDMBOTHCBDECL(int) pciIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsyncDECLINLINE(PPCIDEVICE) pciFindBridge(PPCIBUS pBus, uint8_t iBus);
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync#define PCI_COMMAND_IO 0x01 /* Enable response in I/O space */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync#define PCI_COMMAND_MEMORY 0x02 /* Enable response in Memory space */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync cmd = RT_LE2H_U16(*(uint16_t *)(d->config + PCI_COMMAND));
f1acc1e99894e016bd1a6ee65c56b3fc064fa4ebvboxsync for(i = 0; i < PCI_NUM_REGIONS; i++) {
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync if (r->size != 0) {
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /* NOTE: we have only 64K ioports on PC */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /* the ROM slot has a specific enable bit */
d15e1d56958bda40cd12a7c3a71c962b5a710be2vboxsync /* NOTE: we do not support wrapping */
d15e1d56958bda40cd12a7c3a71c962b5a710be2vboxsync /* XXX: as we cannot support really dynamic
d15e1d56958bda40cd12a7c3a71c962b5a710be2vboxsync mappings, we handle specific values as invalid
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync mappings. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /* now do the real mapping */
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync if (r->addr != ~0U) {
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /* NOTE: specific hack for IDE in PC case:
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync only one byte must be mapped. */
c48c4d769ded37e2496f97dddbbd36dc62f244b1vboxsync devclass = d->config[0x0a] | (d->config[0x0b] << 8);
c48c4d769ded37e2496f97dddbbd36dc62f244b1vboxsync int rc = PDMDevHlpIOPortDeregister(d->pDevIns, r->addr + 2, 1);
7eaaa8a4480370b82ef3735994f986f338fb4df2vboxsync int rc = PDMDevHlpIOPortDeregister(d->pDevIns, r->addr, r->size);
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsync if (pBus->pPciHlpR3->pfnIsMMIO2Base(pBus->pDevInsR3, d->pDevIns, GCPhysBase))
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /* unmap it. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync rc = r->map_func(d, i, NIL_RTGCPHYS, r->size, (PCIADDRESSSPACE)(r->type));
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync rc = PDMDevHlpMMIO2Unmap(d->pDevIns, i, GCPhysBase);
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync rc = PDMDevHlpMMIODeregister(d->pDevIns, GCPhysBase, r->size);
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync AssertMsgRC(rc, ("rc=%Rrc d=%s i=%d GCPhysBase=%RGp size=%#x\n", rc, d->name, i, GCPhysBase, r->size));
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync if (r->addr != ~0U) {
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync r->addr + (r->type & PCI_ADDRESS_SPACE_IO ? 0 : 0),
f5ab5688c35373443d953e2a9fa8a054defdece8vboxsyncstatic DECLCALLBACK(uint32_t) pci_default_read_config(PCIDevice *d, uint32_t address, unsigned len)
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync val = RT_LE2H_U16(*(uint16_t *)(d->config + address));
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync val = RT_LE2H_U32(*(uint32_t *)(d->config + address));
aca7a56d52c58d8b388343450503c22822fd6620vboxsyncstatic DECLCALLBACK(void) pci_default_write_config(PCIDevice *d, uint32_t address, uint32_t val, unsigned len)
87c50c527af59e43745475c4b8ac907c5f9bc204vboxsync unsigned i;
aca7a56d52c58d8b388343450503c22822fd6620vboxsync if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) ||
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync if (r->size == 0)
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync /* compute the stored value */
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync /* keep ROM enable bit */
0c587d7af645db20acefebcfc15b6f46c440ba4avboxsync *(uint32_t *)(d->config + address) = RT_H2LE_U32(val);
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /* not efficient, but simple */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync for(i = 0; i < len; i++) {
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /* default read/write accesses */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: /* base */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case 0x30: case 0x31: case 0x32: case 0x33: /* rom */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync case 0x38: case 0x39: case 0x3a: case 0x3b: /* rom */
17d67aeb3722c094c6493a3e9a9d0cdfb9453ecdvboxsync if (addr == 0x05) /* Command register, bits 8-15. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /* don't change reserved bits (11-15) */
ed970880a556512196471e9cdd0d793e68943ec6vboxsync else if (addr == 0x06) /* Status register, bits 0-7. */
5f9dfb422a6ed57822f9c0cb94fa7df8d24acc9bvboxsync /* don't change read-only bits => actually all lower bits are read-only */
dbfaafc0d352df8a264ef8a09cf56ea20c93cb2cvboxsync /* status register, low part: clear bits by writing a '1' to the corresponding bit */
dbfaafc0d352df8a264ef8a09cf56ea20c93cb2cvboxsync else if (addr == 0x07) /* Status register, bits 8-15. */
dbfaafc0d352df8a264ef8a09cf56ea20c93cb2cvboxsync /* don't change read-only bits */
dbfaafc0d352df8a264ef8a09cf56ea20c93cb2cvboxsync /* status register, high part: clear bits by writing a '1' to the corresponding bit */
if (can_write) {
addr++;
return VINF_SUCCESS;
return VINF_SUCCESS;
if (iBus != 0)
if (pBridgeDevice)
pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->pDevIns, iBus, iDevice, config_addr, val, len);
return VINF_IOM_HC_IOPORT_WRITE;
if (pci_dev)
#ifdef IN_RING3
return VINF_IOM_HC_IOPORT_WRITE;
return VINF_SUCCESS;
return VINF_SUCCESS;
return VINF_SUCCESS;
if (iBus != 0)
if (pBridgeDevice)
*pu32 = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->pDevIns, iBus, iDevice, config_addr, len);
return VINF_IOM_HC_IOPORT_READ;
if (pci_dev)
#ifdef IN_RING3
return VINF_IOM_HC_IOPORT_READ;
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)
static void pciSetIrqInternal(PPCIGLOBALS pGlobals, uint8_t uDevFn, PPCIDEVICE pPciDev, int iIrq, int iLevel)
if (fIsApicEnabled)
if (fIsAcpiDevice)
if (fIsAcpiDevice)
int irq_num;
pic_level = 0;
#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. Thatswhy 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;
int rc;
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;
return VINF_SUCCESS;
sizeof(PCIGLOBALS),
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
* of our parent passing the device which asserted the interrupt instead of the device of the bridge.
#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;
int rc;
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,