summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f>2023-05-11 13:37:24 +0000
committervboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f>2023-05-11 13:37:24 +0000
commite2e3ce67b9bf47174b045e0523a806b323d9e4eb (patch)
tree72032bd7da3033c23c6bd6695f2acb68f0bab068
parent8445b2628a04f528dd24e6042fd85e344bef23fa (diff)
downloadVirtualBox-svn-e2e3ce67b9bf47174b045e0523a806b323d9e4eb.tar.gz
Devices/Bus: Started a basic PCI bus implementation suitable for ARMv8, devices are detected by a Linux guest but interrupts don't work right now. The implementation shares most code with ICH9 PCI device, bugref:10445
git-svn-id: https://www.virtualbox.org/svn/vbox/trunk@99750 cfe28804-0f27-0410-a406-dd0f0b0b656f
-rw-r--r--src/VBox/Devices/Bus/DevPCI.cpp8
-rw-r--r--src/VBox/Devices/Bus/DevPciGenericEcam.cpp457
-rw-r--r--src/VBox/Devices/Bus/DevPciIch9.cpp81
-rw-r--r--src/VBox/Devices/Bus/DevPciInternal.h75
-rw-r--r--src/VBox/Devices/Makefile.kmk1
-rw-r--r--src/VBox/Devices/build/VBoxDD.cpp4
-rw-r--r--src/VBox/Devices/build/VBoxDD.h1
7 files changed, 569 insertions, 58 deletions
diff --git a/src/VBox/Devices/Bus/DevPCI.cpp b/src/VBox/Devices/Bus/DevPCI.cpp
index 4d77c83185f..860f40fd59c 100644
--- a/src/VBox/Devices/Bus/DevPCI.cpp
+++ b/src/VBox/Devices/Bus/DevPCI.cpp
@@ -1304,8 +1304,7 @@ static DECLCALLBACK(int) pciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCF
pGlobals->fUseIoApic = fUseIoApic;
memset((void *)&pGlobals->auPciApicIrqLevels, 0, sizeof(pGlobals->auPciApicIrqLevels));
- pGlobals->PciBus.fTypePiix3 = true;
- pGlobals->PciBus.fTypeIch9 = false;
+ pGlobals->PciBus.enmType = DEVPCIBUSTYPE_PIIX3;
pGlobals->PciBus.fPureBridge = false;
pGlobals->PciBus.papBridgesR3 = (PPDMPCIDEV *)PDMDevHlpMMHeapAllocZ(pDevIns,
sizeof(PPDMPCIDEV)
@@ -1695,9 +1694,8 @@ static DECLCALLBACK(int) pcibridgeR3Construct(PPDMDEVINS pDevIns, int iInstanc
/*
* Init data and register the PCI bus.
*/
- pBus->fTypePiix3 = true;
- pBus->fTypeIch9 = false;
- pBus->fPureBridge = true;
+ pBus->enmType = DEVPCIBUSTYPE_PIIX3;
+ pBus->fPureBridge = true;
pBus->papBridgesR3 = (PPDMPCIDEV *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPDMPCIDEV) * RT_ELEMENTS(pBus->apDevices));
AssertLogRelReturn(pBus->papBridgesR3, VERR_NO_MEMORY);
diff --git a/src/VBox/Devices/Bus/DevPciGenericEcam.cpp b/src/VBox/Devices/Bus/DevPciGenericEcam.cpp
new file mode 100644
index 00000000000..49ef9d54fba
--- /dev/null
+++ b/src/VBox/Devices/Bus/DevPciGenericEcam.cpp
@@ -0,0 +1,457 @@
+/* $Id$ */
+/** @file
+ * DevPciGeneric - Generic host to PCIe bridge emulation.
+ */
+
+/*
+ * Copyright (C) 2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_DEV_PCI
+#define PDMPCIDEV_INCLUDE_PRIVATE /* Hack to get pdmpcidevint.h included at the right point. */
+#include <VBox/vmm/pdmpcidev.h>
+
+#include <VBox/AssertGuest.h>
+#include <VBox/msi.h>
+#include <VBox/vmm/pdmdev.h>
+#include <VBox/vmm/mm.h>
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/string.h>
+#ifdef IN_RING3
+# include <iprt/mem.h>
+# include <iprt/uuid.h>
+#endif
+
+#include "PciInline.h"
+#include "VBoxDD.h"
+#include "MsiCommon.h"
+#include "DevPciInternal.h"
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** Saved state version of the generic ECAM PCI bus device. */
+#define VBOX_PCIGENECAM_SAVED_STATE_VERSION 1
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+
+static DECLCALLBACK(void) pciGenEcamSetIrq(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
+{
+ PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
+ PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
+ uint8_t uDevFn = pPciDev->uDevFn;
+
+ LogFlowFunc(("invoked by %p/%d: iIrq=%d iLevel=%d uTagSrc=%#x\n", pDevIns, pDevIns->iInstance, iIrq, iLevel, uTagSrc));
+
+ /* If MSI or MSI-X is enabled, PCI INTx# signals are disabled regardless of the PCI command
+ * register interrupt bit state.
+ * PCI 3.0 (section 6.8) forbids MSI and MSI-X to be enabled at the same time and makes
+ * that undefined behavior. We check for MSI first, then MSI-X.
+ */
+ if (MsiIsEnabled(pPciDev))
+ {
+ Assert(!MsixIsEnabled(pPciDev)); /* Not allowed -- see note above. */
+ LogFlowFunc(("PCI Dev %p : MSI\n", pPciDev));
+ MsiNotify(pDevIns, pBusCC->CTX_SUFF(pPciHlp), pPciDev, iIrq, iLevel, uTagSrc);
+ return;
+ }
+
+ if (MsixIsEnabled(pPciDev))
+ {
+ LogFlowFunc(("PCI Dev %p : MSI-X\n", pPciDev));
+ MsixNotify(pDevIns, pBusCC->CTX_SUFF(pPciHlp), pPciDev, iIrq, iLevel, uTagSrc);
+ return;
+ }
+
+ PDEVPCIBUS pBus = &pPciRoot->PciBus;
+ LogFlowFunc(("PCI Dev %p : IRQ\n", pPciDev));
+
+ /* Check if the state changed. */
+ if (pPciDev->Int.s.uIrqPinState != iLevel)
+ {
+ pPciDev->Int.s.uIrqPinState = (iLevel & PDM_IRQ_LEVEL_HIGH);
+
+ /** @todo */
+ }
+}
+
+
+/**
+ * @callback_method_impl{FNIOMMMIONEWWRITE,
+ * Emulates writes to configuration space.}
+ */
+static DECLCALLBACK(VBOXSTRICTRC) pciHostR3MmioPioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
+{
+ Log2Func(("%RGp LB %d\n", off, cb));
+ RT_NOREF(pvUser);
+
+ AssertReturn(off < _64K, VERR_INVALID_PARAMETER);
+ AssertReturn(cb <= 4, VERR_INVALID_PARAMETER);
+
+ /* Get the value. */
+ uint32_t u32;
+ switch (cb)
+ {
+ case 1:
+ u32 = *(uint8_t const *)pv;
+ break;
+ case 2:
+ u32 = *(uint16_t const *)pv;
+ break;
+ case 4:
+ u32 = *(uint32_t const *)pv;
+ break;
+ default:
+ ASSERT_GUEST_MSG_FAILED(("cb=%u off=%RGp\n", cb, off)); /** @todo how the heck should this work? Split it, right? */
+ u32 = 0;
+ break;
+ }
+
+ return PDMDevHlpIoPortWrite(pDevIns, (RTIOPORT)off, u32, cb);
+}
+
+
+/**
+ * @callback_method_impl{FNIOMMMIONEWWRITE,
+ * Emulates reads from configuration space.}
+ */
+static DECLCALLBACK(VBOXSTRICTRC) pciHostR3MmioPioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
+{
+ LogFlowFunc(("%RGp LB %u\n", off, cb));
+ RT_NOREF(pvUser);
+
+ AssertReturn(off < _64K, VERR_INVALID_PARAMETER);
+ AssertReturn(cb <= 4, VERR_INVALID_PARAMETER);
+
+ /* Perform configuration space read */
+ uint32_t u32Value = 0;
+ VBOXSTRICTRC rcStrict = PDMDevHlpIoPortRead(pDevIns, (RTIOPORT)off, &u32Value, cb);
+
+ if (RT_SUCCESS(rcStrict))
+ {
+ switch (cb)
+ {
+ case 1:
+ *(uint8_t *)pv = (uint8_t)u32Value;
+ break;
+ case 2:
+ *(uint16_t *)pv = (uint16_t)u32Value;
+ break;
+ case 4:
+ *(uint32_t *)pv = u32Value;
+ break;
+ default:
+ ASSERT_GUEST_MSG_FAILED(("cb=%u off=%RGp\n", cb, off)); /** @todo how the heck should this work? Split it, right? */
+ break;
+ }
+ }
+
+ return rcStrict;
+}
+
+
+#ifdef IN_RING3
+
+/* -=-=-=-=-=- PCI Config Space -=-=-=-=-=- */
+
+
+/**
+ * @interface_method_impl{PDMDEVREG,pfnConstruct}
+ */
+static DECLCALLBACK(int) pciGenEcamR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
+{
+ RT_NOREF1(iInstance);
+ Assert(iInstance == 0);
+ PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
+
+ PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
+ PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
+ PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
+ PDEVPCIBUS pBus = &pPciRoot->PciBus;
+
+ /*
+ * Validate and read configuration.
+ */
+ PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "MmioEcamBase|MmioEcamLength|MmioPioBase|MmioPioSize", "");
+
+ int rc = pHlp->pfnCFGMQueryU64Def(pCfg, "MmioEcamBase", &pPciRoot->u64PciConfigMMioAddress, 0);
+ AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"McfgBase\"")));
+
+ rc = pHlp->pfnCFGMQueryU64Def(pCfg, "MmioEcamLength", &pPciRoot->u64PciConfigMMioLength, 0);
+ AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"McfgLength\"")));
+
+ rc = pHlp->pfnCFGMQueryU64Def(pCfg, "MmioPioBase", &pPciRoot->GCPhysMmioPioEmuBase, 0);
+ AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"MmioPioBase\"")));
+
+ rc = pHlp->pfnCFGMQueryU64Def(pCfg, "MmioPioSize", &pPciRoot->GCPhysMmioPioEmuSize, 0);
+ AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"MmioPioSize\"")));
+
+ Log(("PCI: fUseIoApic=%RTbool McfgBase=%#RX64 McfgLength=%#RX64 fR0Enabled=%RTbool fRCEnabled=%RTbool\n", pPciRoot->fUseIoApic,
+ pPciRoot->u64PciConfigMMioAddress, pPciRoot->u64PciConfigMMioLength, pDevIns->fR0Enabled, pDevIns->fRCEnabled));
+
+ /*
+ * Init data.
+ */
+ /* And fill values */
+ pBusCC->pDevInsR3 = pDevIns;
+ pPciRoot->hIoPortAddress = NIL_IOMIOPORTHANDLE;
+ pPciRoot->hIoPortData = NIL_IOMIOPORTHANDLE;
+ pPciRoot->hIoPortMagic = NIL_IOMIOPORTHANDLE;
+ pPciRoot->hMmioMcfg = NIL_IOMMMIOHANDLE;
+ pPciRoot->hMmioPioEmu = NIL_IOMMMIOHANDLE;
+ pPciRoot->PciBus.enmType = DEVPCIBUSTYPE_GENERIC_ECAM;
+ pPciRoot->PciBus.fPureBridge = false;
+ pPciRoot->PciBus.papBridgesR3 = (PPDMPCIDEV *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPDMPCIDEV) * RT_ELEMENTS(pPciRoot->PciBus.apDevices));
+ AssertLogRelReturn(pPciRoot->PciBus.papBridgesR3, VERR_NO_MEMORY);
+
+ /*
+ * Disable default device locking.
+ */
+ rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
+ AssertRCReturn(rc, rc);
+
+ /*
+ * Register bus
+ */
+ PDMPCIBUSREGCC PciBusReg;
+ PciBusReg.u32Version = PDM_PCIBUSREGCC_VERSION;
+ PciBusReg.pfnRegisterR3 = devpciR3CommonRegisterDevice;
+ PciBusReg.pfnRegisterMsiR3 = NULL;
+ PciBusReg.pfnIORegionRegisterR3 = devpciR3CommonIORegionRegister;
+ PciBusReg.pfnInterceptConfigAccesses = devpciR3CommonInterceptConfigAccesses;
+ PciBusReg.pfnConfigRead = devpciR3CommonConfigRead;
+ PciBusReg.pfnConfigWrite = devpciR3CommonConfigWrite;
+ PciBusReg.pfnSetIrqR3 = pciGenEcamSetIrq;
+ PciBusReg.u32EndVersion = PDM_PCIBUSREGCC_VERSION;
+ rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBusCC->pPciHlpR3, &pBus->iBus);
+ if (RT_FAILURE(rc))
+ return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to register ourselves as a PCI Bus"));
+ Assert(pBus->iBus == 0);
+ if (pBusCC->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
+ return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
+ N_("PCI helper version mismatch; got %#x expected %#x"),
+ pBusCC->pPciHlpR3->u32Version, PDM_PCIHLPR3_VERSION);
+
+ /*
+ * Fill in PCI configs and add them to the bus.
+ */
+#if 0
+ /* Host bridge device */
+ PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
+ AssertPtr(pPciDev);
+ PDMPciDevSetVendorId( pPciDev, 0x8086); /** @todo Intel */
+ PDMPciDevSetDeviceId( pPciDev, 0x29e0); /** @todo Desktop */
+ PDMPciDevSetRevisionId(pPciDev, 0x01); /* rev. 01 */
+ PDMPciDevSetClassBase( pPciDev, 0x06); /* bridge */
+ PDMPciDevSetClassSub( pPciDev, 0x00); /* Host/PCI bridge */
+ PDMPciDevSetClassProg( pPciDev, 0x00); /* Host/PCI bridge */
+ PDMPciDevSetHeaderType(pPciDev, 0x00); /* bridge */
+ PDMPciDevSetWord(pPciDev, VBOX_PCI_SEC_STATUS, 0x0280); /* secondary status */
+
+ rc = PDMDevHlpPCIRegisterEx(pDevIns, pPciDev, 0 /*fFlags*/, 0 /*uPciDevNo*/, 0 /*uPciFunNo*/, "Host");
+ AssertLogRelRCReturn(rc, rc);
+#endif
+
+ /*
+ * MMIO handlers.
+ */
+ if (pPciRoot->u64PciConfigMMioAddress != 0)
+ {
+ rc = PDMDevHlpMmioCreateAndMap(pDevIns, pPciRoot->u64PciConfigMMioAddress, pPciRoot->u64PciConfigMMioLength,
+ devpciCommonMcfgMmioWrite, devpciCommonMcfgMmioRead,
+ IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
+ "ECAM window", &pPciRoot->hMmioMcfg);
+ AssertMsgRCReturn(rc, ("rc=%Rrc %#RX64/%#RX64\n", rc, pPciRoot->u64PciConfigMMioAddress, pPciRoot->u64PciConfigMMioLength), rc);
+ }
+
+ if (pPciRoot->GCPhysMmioPioEmuBase != 0)
+ {
+ rc = PDMDevHlpMmioCreateAndMap(pDevIns, pPciRoot->GCPhysMmioPioEmuBase, pPciRoot->GCPhysMmioPioEmuSize,
+ pciHostR3MmioPioWrite, pciHostR3MmioPioRead,
+ IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
+ "PIO range", &pPciRoot->hMmioPioEmu);
+ AssertMsgRCReturn(rc, ("rc=%Rrc %#RGp/%#RGp\n", rc, pPciRoot->GCPhysMmioPioEmuBase, pPciRoot->GCPhysMmioPioEmuSize), rc);
+ }
+
+ /*
+ * Saved state and info handlers.
+ */
+ rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_PCIGENECAM_SAVED_STATE_VERSION,
+ sizeof(*pBus) + 16*128, "pgm",
+ NULL, NULL, NULL,
+ NULL, devpciR3CommonSaveExec, NULL,
+ NULL, devpciR3CommonLoadExec, NULL);
+ AssertRCReturn(rc, rc);
+
+ PDMDevHlpDBGFInfoRegister(pDevIns, "pci",
+ "Display PCI bus status. Recognizes 'basic' or 'verbose' as arguments, defaults to 'basic'.",
+ devpciR3InfoPci);
+ PDMDevHlpDBGFInfoRegister(pDevIns, "pciirq", "Display PCI IRQ state. (no arguments)", devpciR3InfoPciIrq);
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{PDMDEVREG,pfnDestruct}
+ */
+static DECLCALLBACK(int) pciGenEcamR3Destruct(PPDMDEVINS pDevIns)
+{
+ PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
+ if (pPciRoot->PciBus.papBridgesR3)
+ {
+ PDMDevHlpMMHeapFree(pDevIns, pPciRoot->PciBus.papBridgesR3);
+ pPciRoot->PciBus.papBridgesR3 = NULL;
+ }
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{PDMDEVREG,pfnReset}
+ */
+static DECLCALLBACK(void) pciGenEcamR3Reset(PPDMDEVINS pDevIns)
+{
+ /* Reset everything under the root bridge. */
+ devpciR3CommonResetBridge(pDevIns);
+}
+
+#else /* !IN_RING3 */
+
+/**
+ * @interface_method_impl{PDMDEVREGR0,pfnConstruct}
+ */
+DECLCALLBACK(int) pciGenEcamRZConstruct(PPDMDEVINS pDevIns)
+{
+ PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
+ PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
+ PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
+
+ /* Mirror the ring-3 device lock disabling: */
+ int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
+ AssertRCReturn(rc, rc);
+
+ /* Set up the RZ PCI bus callbacks: */
+ PDMPCIBUSREGCC PciBusReg;
+ PciBusReg.u32Version = PDM_PCIBUSREGCC_VERSION;
+ PciBusReg.iBus = pPciRoot->PciBus.iBus;
+ PciBusReg.pfnSetIrq = pciGenEcamSetIrq;
+ PciBusReg.u32EndVersion = PDM_PCIBUSREGCC_VERSION;
+ rc = PDMDevHlpPCIBusSetUpContext(pDevIns, &PciBusReg, &pBusCC->CTX_SUFF(pPciHlp));
+ AssertRCReturn(rc, rc);
+
+ /* Set up MMIO callbacks: */
+ if (pPciRoot->hMmioMcfg != NIL_IOMMMIOHANDLE)
+ {
+ rc = PDMDevHlpMmioSetUpContext(pDevIns, pPciRoot->hMmioMcfg, devpciCommonMcfgMmioWrite, devpciCommonMcfgMmioRead, NULL /*pvUser*/);
+ AssertLogRelRCReturn(rc, rc);
+ }
+
+ return rc;
+}
+
+#endif /* !IN_RING3 */
+
+/**
+ * The PCI bus device registration structure.
+ */
+const PDMDEVREG g_DevicePciGenericEcam =
+{
+ /* .u32Version = */ PDM_DEVREG_VERSION,
+ /* .uReserved0 = */ 0,
+ /* .szName = */ "pci-generic-ecam",
+ /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
+ /* .fClass = */ PDM_DEVREG_CLASS_BUS_PCI,
+ /* .cMaxInstances = */ 1,
+ /* .uSharedVersion = */ 42,
+ /* .cbInstanceShared = */ sizeof(DEVPCIROOT),
+ /* .cbInstanceCC = */ sizeof(CTX_SUFF(DEVPCIBUS)),
+ /* .cbInstanceRC = */ sizeof(DEVPCIBUSRC),
+ /* .cMaxPciDevices = */ 1,
+ /* .cMaxMsixVectors = */ 0,
+ /* .pszDescription = */ "Generic PCI host bridge (working with pci-host-ecam-generic driver)",
+#if defined(IN_RING3)
+ /* .pszRCMod = */ "VBoxDDRC.rc",
+ /* .pszR0Mod = */ "VBoxDDR0.r0",
+ /* .pfnConstruct = */ pciGenEcamR3Construct,
+ /* .pfnDestruct = */ pciGenEcamR3Destruct,
+ /* .pfnRelocate = */ NULL,
+ /* .pfnMemSetup = */ NULL,
+ /* .pfnPowerOn = */ NULL,
+ /* .pfnReset = */ pciGenEcamR3Reset,
+ /* .pfnSuspend = */ NULL,
+ /* .pfnResume = */ NULL,
+ /* .pfnAttach = */ NULL,
+ /* .pfnDetach = */ NULL,
+ /* .pfnQueryInterface = */ NULL,
+ /* .pfnInitComplete = */ NULL,
+ /* .pfnPowerOff = */ NULL,
+ /* .pfnSoftReset = */ NULL,
+ /* .pfnReserved0 = */ NULL,
+ /* .pfnReserved1 = */ NULL,
+ /* .pfnReserved2 = */ NULL,
+ /* .pfnReserved3 = */ NULL,
+ /* .pfnReserved4 = */ NULL,
+ /* .pfnReserved5 = */ NULL,
+ /* .pfnReserved6 = */ NULL,
+ /* .pfnReserved7 = */ NULL,
+#elif defined(IN_RING0)
+ /* .pfnEarlyConstruct = */ NULL,
+ /* .pfnConstruct = */ pciGenEcamRZConstruct,
+ /* .pfnDestruct = */ NULL,
+ /* .pfnFinalDestruct = */ NULL,
+ /* .pfnRequest = */ NULL,
+ /* .pfnReserved0 = */ NULL,
+ /* .pfnReserved1 = */ NULL,
+ /* .pfnReserved2 = */ NULL,
+ /* .pfnReserved3 = */ NULL,
+ /* .pfnReserved4 = */ NULL,
+ /* .pfnReserved5 = */ NULL,
+ /* .pfnReserved6 = */ NULL,
+ /* .pfnReserved7 = */ NULL,
+#elif defined(IN_RC)
+ /* .pfnConstruct = */ pciGenEcamRZConstruct,
+ /* .pfnReserved0 = */ NULL,
+ /* .pfnReserved1 = */ NULL,
+ /* .pfnReserved2 = */ NULL,
+ /* .pfnReserved3 = */ NULL,
+ /* .pfnReserved4 = */ NULL,
+ /* .pfnReserved5 = */ NULL,
+ /* .pfnReserved6 = */ NULL,
+ /* .pfnReserved7 = */ NULL,
+#else
+# error "Not in IN_RING3, IN_RING0 or IN_RC!"
+#endif
+ /* .u32VersionEnd = */ PDM_DEVREG_VERSION
+};
diff --git a/src/VBox/Devices/Bus/DevPciIch9.cpp b/src/VBox/Devices/Bus/DevPciIch9.cpp
index f749ee34c7b..e969fb095d6 100644
--- a/src/VBox/Devices/Bus/DevPciIch9.cpp
+++ b/src/VBox/Devices/Bus/DevPciIch9.cpp
@@ -115,7 +115,6 @@ static void ich9pciSetIrqInternal(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEV
uint8_t uDevFn, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc);
#ifdef IN_RING3
static int ich9pciFakePCIBIOS(PPDMDEVINS pDevIns);
-DECLINLINE(PPDMPCIDEV) ich9pciFindBridge(PDEVPCIBUS pBus, uint8_t uBus);
static void ich9pciBiosInitAllDevicesOnBus(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUS pBus);
static bool ich9pciBiosInitAllDevicesPrefetchableOnBus(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUS pBus, bool fUse64Bit, bool fDryrun);
#endif
@@ -341,7 +340,7 @@ static VBOXSTRICTRC ich9pciConfigWrite(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot,
if (pPciRoot->PciBus.cBridges)
{
#ifdef IN_RING3 /** @todo do lookup in R0/RC too! r=klaus don't think that it can work, since the config space access callback only works in R3 */
- PPDMPCIDEV pBridgeDevice = ich9pciFindBridge(&pPciRoot->PciBus, pPciAddr->iBus);
+ PPDMPCIDEV pBridgeDevice = devpciR3FindBridge(&pPciRoot->PciBus, pPciAddr->iBus);
if (pBridgeDevice)
{
AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigWrite);
@@ -436,7 +435,7 @@ static VBOXSTRICTRC ich9pciConfigRead(PDEVPCIROOT pPciRoot, PciAddress* pPciAddr
if (pPciRoot->PciBus.cBridges)
{
#ifdef IN_RING3 /** @todo do lookup in R0/RC too! r=klaus don't think that it can work, since the config space access callback only works in R3 */
- PPDMPCIDEV pBridgeDevice = ich9pciFindBridge(&pPciRoot->PciBus, pPciAddr->iBus);
+ PPDMPCIDEV pBridgeDevice = devpciR3FindBridge(&pPciRoot->PciBus, pPciAddr->iBus);
if (pBridgeDevice)
{
AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigRead);
@@ -657,7 +656,7 @@ static void ich9pciSetIrqInternal(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEV
* @callback_method_impl{FNIOMMMIONEWWRITE,
* Emulates writes to configuration space.}
*/
-static DECLCALLBACK(VBOXSTRICTRC) ich9pciMcfgMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
+DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) devpciCommonMcfgMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
{
PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
Log2Func(("%RGp LB %d\n", off, cb));
@@ -699,7 +698,7 @@ static DECLCALLBACK(VBOXSTRICTRC) ich9pciMcfgMMIOWrite(PPDMDEVINS pDevIns, void
* @callback_method_impl{FNIOMMMIONEWWRITE,
* Emulates reads from configuration space.}
*/
-static DECLCALLBACK(VBOXSTRICTRC) ich9pciMcfgMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
+DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) devpciCommonMcfgMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
{
PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
LogFlowFunc(("%RGp LB %u\n", off, cb));
@@ -739,31 +738,6 @@ static DECLCALLBACK(VBOXSTRICTRC) ich9pciMcfgMMIORead(PPDMDEVINS pDevIns, void *
#ifdef IN_RING3
-DECLINLINE(PPDMPCIDEV) ich9pciFindBridge(PDEVPCIBUS pBus, uint8_t uBus)
-{
- /* Search for a fitting bridge. */
- for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
- {
- /*
- * Examine secondary and subordinate bus number.
- * If the target bus is in the range we pass the request on to the bridge.
- */
- PPDMPCIDEV pBridge = pBus->papBridgesR3[iBridge];
- AssertMsg(pBridge && pciDevIsPci2PciBridge(pBridge),
- ("Device is not a PCI bridge but on the list of PCI bridges\n"));
- /* safe, only needs to go to the config space array */
- uint32_t uSecondary = PDMPciDevGetByte(pBridge, VBOX_PCI_SECONDARY_BUS);
- /* safe, only needs to go to the config space array */
- uint32_t uSubordinate = PDMPciDevGetByte(pBridge, VBOX_PCI_SUBORDINATE_BUS);
- Log3Func(("bus %p, bridge %d: %d in %d..%d\n", pBus, iBridge, uBus, uSecondary, uSubordinate));
- if (uBus >= uSecondary && uBus <= uSubordinate)
- return pBridge;
- }
-
- /* Nothing found. */
- return NULL;
-}
-
uint32_t devpciR3GetCfg(PPDMPCIDEV pPciDev, int32_t iRegister, int cb)
{
uint32_t u32Value = UINT32_MAX;
@@ -977,7 +951,7 @@ static int devpciR3CommonRegisterDeviceOnBus(PPDMDEVINS pDevIns, PDEVPCIBUS pBus
pPciDev->Int.s.pfnConfigRead = NULL;
pPciDev->Int.s.pfnConfigWrite = NULL;
pPciDev->Int.s.hMmioMsix = NIL_IOMMMIOHANDLE;
- if (pBus->fTypePiix3 && pPciDev->cbConfig > 256)
+ if (pBus->enmType == DEVPCIBUSTYPE_PIIX3 && pPciDev->cbConfig > 256)
pPciDev->cbConfig = 256;
/* Remember and mark bridges. */
@@ -1175,7 +1149,7 @@ static int ich9pciR3CommonSaveExec(PCPDMDEVHLPR3 pHlp, PDEVPCIBUS pBus, PSSMHAND
return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX); /* terminator */
}
-static DECLCALLBACK(int) ich9pciR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
+DECL_HIDDEN_CALLBACK(int) devpciR3CommonSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
{
PDEVPCIROOT pThis = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
@@ -1220,7 +1194,7 @@ static DECLCALLBACK(VBOXSTRICTRC) ich9pcibridgeConfigWrite(PPDMDEVINSR3 pDevIns,
/* safe, only needs to go to the config space array */
if (iBus != PDMPciDevGetByte(pDevIns->apPciDevs[0], VBOX_PCI_SECONDARY_BUS))
{
- PPDMPCIDEV pBridgeDevice = ich9pciFindBridge(pBus, iBus);
+ PPDMPCIDEV pBridgeDevice = devpciR3FindBridge(pBus, iBus);
if (pBridgeDevice)
{
AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigWrite);
@@ -1260,7 +1234,7 @@ static DECLCALLBACK(VBOXSTRICTRC) ich9pcibridgeConfigRead(PPDMDEVINSR3 pDevIns,
/* safe, only needs to go to the config space array */
if (iBus != PDMPciDevGetByte(pDevIns->apPciDevs[0], VBOX_PCI_SECONDARY_BUS))
{
- PPDMPCIDEV pBridgeDevice = ich9pciFindBridge(pBus, iBus);
+ PPDMPCIDEV pBridgeDevice = devpciR3FindBridge(pBus, iBus);
if (pBridgeDevice)
{
AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigRead);
@@ -1748,7 +1722,7 @@ static int ich9pciR3CommonLoadExec(PPDMDEVINS pDevIns, PDEVPCIBUS pBus, PSSMHAND
return rc;
}
-static DECLCALLBACK(int) ich9pciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
+DECL_HIDDEN_CALLBACK(int) devpciR3CommonLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
{
PDEVPCIROOT pThis = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
@@ -3078,6 +3052,21 @@ static const char *devpciR3InInfoPciBusClassName(uint8_t iBaseClass)
return "device does not fit in any defined classes";
}
+static const char *devpciR3InInfoPciBusType(DEVPCIBUSTYPE enmType)
+{
+ static const char *s_szBusType[] =
+ {
+ /* 00h */ "INVALID",
+ /* 01h */ "PIIX3",
+ /* 02h */ "ICH9",
+ /* 03h */ "GenericEcam",
+ /* 04h */ "?32-bit hack?",
+ };
+
+ if (enmType < RT_ELEMENTS(s_szBusType))
+ return s_szBusType[enmType];
+ return "?type?";
+}
/**
* Recursive worker for devpciR3InfoPci.
@@ -3112,7 +3101,7 @@ static void devpciR3InfoPciBus(PDEVPCIBUS pBus, PCDBGFINFOHLP pHlp, unsigned iIn
pPciDev->pszNameR3,
pciDevIsPassthrough(pPciDev) ? " (PASSTHROUGH)" : "",
devpciR3GetWord(pPciDev, VBOX_PCI_VENDOR_ID), devpciR3GetWord(pPciDev, VBOX_PCI_DEVICE_ID),
- pBus->fTypeIch9 ? "ICH9" : pBus->fTypePiix3 ? "PIIX3" : "?type?",
+ devpciR3InInfoPciBusType(pBus->enmType),
pciDevIsMsiCapable(pPciDev) ? " MSI" : "",
pciDevIsMsixCapable(pPciDev) ? " MSI-X" : ""
);
@@ -3358,8 +3347,7 @@ static DECLCALLBACK(int) ich9pciR3Construct(PPDMDEVINS pDevIns, int iInstance, P
pPciRoot->hIoPortData = NIL_IOMIOPORTHANDLE;
pPciRoot->hIoPortMagic = NIL_IOMIOPORTHANDLE;
pPciRoot->hMmioMcfg = NIL_IOMMMIOHANDLE;
- pPciRoot->PciBus.fTypePiix3 = false;
- pPciRoot->PciBus.fTypeIch9 = true;
+ pPciRoot->PciBus.enmType = DEVPCIBUSTYPE_GENERIC_ECAM;
pPciRoot->PciBus.fPureBridge = false;
pPciRoot->PciBus.papBridgesR3 = (PPDMPCIDEV *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPDMPCIDEV) * RT_ELEMENTS(pPciRoot->PciBus.apDevices));
AssertLogRelReturn(pPciRoot->PciBus.papBridgesR3, VERR_NO_MEMORY);
@@ -3440,7 +3428,7 @@ static DECLCALLBACK(int) ich9pciR3Construct(PPDMDEVINS pDevIns, int iInstance, P
if (pPciRoot->u64PciConfigMMioAddress != 0)
{
rc = PDMDevHlpMmioCreateAndMap(pDevIns, pPciRoot->u64PciConfigMMioAddress, pPciRoot->u64PciConfigMMioLength,
- ich9pciMcfgMMIOWrite, ich9pciMcfgMMIORead,
+ devpciCommonMcfgMmioWrite, devpciCommonMcfgMmioRead,
IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
"MCFG ranges", &pPciRoot->hMmioMcfg);
AssertMsgRCReturn(rc, ("rc=%Rrc %#RX64/%#RX64\n", rc, pPciRoot->u64PciConfigMMioAddress, pPciRoot->u64PciConfigMMioLength), rc);
@@ -3452,8 +3440,8 @@ static DECLCALLBACK(int) ich9pciR3Construct(PPDMDEVINS pDevIns, int iInstance, P
rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_ICH9PCI_SAVED_STATE_VERSION,
sizeof(*pBus) + 16*128, "pgm",
NULL, NULL, NULL,
- NULL, ich9pciR3SaveExec, NULL,
- NULL, ich9pciR3LoadExec, NULL);
+ NULL, devpciR3CommonSaveExec, NULL,
+ NULL, devpciR3CommonLoadExec, NULL);
AssertRCReturn(rc, rc);
/** @todo other chipset devices shall be registered too */
@@ -3571,7 +3559,7 @@ static uint8_t ich9pcibridgeR3GetExpressPortTypeFromString(const char *pszExpres
*
* @param pDevIns ICH9 bridge (root or PCI-to-PCI) instance.
*/
-static void ich9pciResetBridge(PPDMDEVINS pDevIns)
+DECLHIDDEN(void) devpciR3CommonResetBridge(PPDMDEVINS pDevIns)
{
PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
@@ -3585,7 +3573,7 @@ static void ich9pciResetBridge(PPDMDEVINS pDevIns)
for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
{
if (pBus->papBridgesR3[iBridge])
- ich9pciResetBridge(pBus->papBridgesR3[iBridge]->Int.s.CTX_SUFF(pDevIns));
+ devpciR3CommonResetBridge(pBus->papBridgesR3[iBridge]->Int.s.CTX_SUFF(pDevIns));
}
/* Reset topology config for non-root bridge. Last thing to do, otherwise
@@ -3609,7 +3597,7 @@ static void ich9pciResetBridge(PPDMDEVINS pDevIns)
static DECLCALLBACK(void) ich9pciReset(PPDMDEVINS pDevIns)
{
/* Reset everything under the root bridge. */
- ich9pciResetBridge(pDevIns);
+ devpciR3CommonResetBridge(pDevIns);
}
@@ -3677,8 +3665,7 @@ static DECLCALLBACK(int) ich9pcibridgeR3Construct(PPDMDEVINS pDevIns, int iInsta
PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
- pBus->fTypePiix3 = false;
- pBus->fTypeIch9 = true;
+ pBus->enmType = DEVPCIBUSTYPE_ICH9;
pBus->fPureBridge = true;
pBusCC->pDevInsR3 = pDevIns;
pBus->papBridgesR3 = (PPDMPCIDEV *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPDMPCIDEV) * RT_ELEMENTS(pBus->apDevices));
@@ -3858,7 +3845,7 @@ DECLCALLBACK(int) ich9pciRZConstruct(PPDMDEVINS pDevIns)
/* Set up MMIO callbacks: */
if (pPciRoot->hMmioMcfg != NIL_IOMMMIOHANDLE)
{
- rc = PDMDevHlpMmioSetUpContext(pDevIns, pPciRoot->hMmioMcfg, ich9pciMcfgMMIOWrite, ich9pciMcfgMMIORead, NULL /*pvUser*/);
+ rc = PDMDevHlpMmioSetUpContext(pDevIns, pPciRoot->hMmioMcfg, devpciCommonMcfgMmioWrite, devpciCommonMcfgMmioRead, NULL /*pvUser*/);
AssertLogRelRCReturn(rc, rc);
}
diff --git a/src/VBox/Devices/Bus/DevPciInternal.h b/src/VBox/Devices/Bus/DevPciInternal.h
index bfeb30463f5..bb9a8f59b2b 100644
--- a/src/VBox/Devices/Bus/DevPciInternal.h
+++ b/src/VBox/Devices/Bus/DevPciInternal.h
@@ -36,6 +36,26 @@
#endif
#include <VBox/vmm/pdmdev.h>
+#include "PciInline.h"
+
+
+/**
+ * Supported PCI bus types.
+ */
+typedef enum DEVPCIBUSTYPE
+{
+ /** The usual invalid type. */
+ DEVPCIBUSTYPE_INVALID = 0,
+ /** PIIX3 PCI bus type. */
+ DEVPCIBUSTYPE_PIIX3,
+ /** ICH9 PCI bus type. */
+ DEVPCIBUSTYPE_ICH9,
+ /** Generic ECAM PCI bus type. */
+ DEVPCIBUSTYPE_GENERIC_ECAM,
+ /** 32bit blowup. */
+ DEVPCIBUSTYPE_32BIT_HACK = 0x7fffffff
+} DEVPCIBUSTYPE;
+
/**
* PCI bus shared instance data (common to both PCI buses).
@@ -50,24 +70,24 @@ typedef struct DEVPCIBUS
uint32_t cBridges;
/** Start device number - always zero (only for DevPCI source compat). */
uint32_t iDevSearch;
- /** Set if PIIX3 type. */
- uint32_t fTypePiix3 : 1;
- /** Set if ICH9 type. */
- uint32_t fTypeIch9 : 1;
+ /** PCI Bus type. */
+ DEVPCIBUSTYPE enmType;
/** Set if this is a pure bridge, i.e. not part of DEVPCIGLOBALS struct. */
uint32_t fPureBridge : 1;
/** Reserved for future config flags. */
- uint32_t uReservedConfigFlags : 29;
+ uint32_t uReservedConfigFlags : 31;
/** Array of bridges attached to the bus. */
R3PTRTYPE(PPDMPCIDEV *) papBridgesR3;
/** Cache line align apDevices. */
- uint32_t au32Alignment1[HC_ARCH_BITS == 32 ? 3 + 8 : 2 + 8];
+ uint32_t au32Alignment1[HC_ARCH_BITS == 32 ? 2 + 8 : 8];
/** Array of PCI devices. We assume 32 slots, each with 8 functions. */
R3PTRTYPE(PPDMPCIDEV) apDevices[256];
} DEVPCIBUS;
/** Pointer to PCI bus shared instance data. */
typedef DEVPCIBUS *PDEVPCIBUS;
+AssertCompileMemberAlignment(DEVPCIBUS, apDevices, 64);
+
/**
* PCI bus ring-3 instance data (common to both PCI buses).
@@ -144,6 +164,11 @@ typedef struct DEVPCIROOT
uint64_t u64PciConfigMMioAddress;
/** Length of PCI config space MMIO region. */
uint64_t u64PciConfigMMioLength;
+ /** Physical address of PCI PIO emulation MMIO region. */
+ RTGCPHYS GCPhysMmioPioEmuBase;
+ /** Length of PCI PIO emulation MMIO region. */
+ RTGCPHYS GCPhysMmioPioEmuSize;
+
/** I/O APIC irq levels */
volatile uint32_t auPciApicIrqLevels[DEVPCI_APIC_IRQ_PINS];
@@ -175,6 +200,8 @@ typedef struct DEVPCIROOT
IOMIOPORTHANDLE hIoPortMagic;
/** The MCFG MMIO region. */
IOMMMIOHANDLE hMmioMcfg;
+ /** The PIO emulation MMIO region. */
+ IOMMMIOHANDLE hMmioPioEmu;
#if 1 /* Will be moved into the BIOS "soon". */
/** Current bus number - obsolete (still used by DevPCI, but merge will fix that). */
@@ -216,8 +243,13 @@ typedef DEVPCIROOT *PDEVPCIROOT;
DECLHIDDEN(PPDMDEVINS) devpcibridgeCommonSetIrqRootWalk(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq,
PDEVPCIBUS *ppBus, uint8_t *puDevFnBridge, int *piIrqPinBridge);
+DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) devpciCommonMcfgMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb);
+DECL_HIDDEN_CALLBACK(VBOXSTRICTRC) devpciCommonMcfgMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb);
+
+
#ifdef IN_RING3
+# ifndef VBOX_DEVICE_STRUCT_TESTCASE
DECLCALLBACK(void) devpciR3InfoPci(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs);
DECLCALLBACK(void) devpciR3InfoPciIrq(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs);
DECLCALLBACK(int) devpciR3CommonRegisterDevice(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags,
@@ -242,6 +274,10 @@ void devpciR3ResetDevice(PPDMDEVINS pDevIns, PPDMPCIDEV pDev);
void devpciR3BiosInitSetRegionAddress(PPDMDEVINS pDevIns, PDEVPCIBUS pBus, PPDMPCIDEV pPciDev, int iRegion, uint64_t addr);
uint32_t devpciR3GetCfg(PPDMPCIDEV pPciDev, int32_t iRegister, int cb);
void devpciR3SetCfg(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int32_t iRegister, uint32_t u32, int cb);
+DECLHIDDEN(void) devpciR3CommonResetBridge(PPDMDEVINS pDevIns);
+DECL_HIDDEN_CALLBACK(int) devpciR3CommonSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM);
+DECL_HIDDEN_CALLBACK(int) devpciR3CommonLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
+
DECLINLINE(uint8_t) devpciR3GetByte(PPDMPCIDEV pPciDev, int32_t iRegister)
{
@@ -273,6 +309,33 @@ DECLINLINE(void) devpciR3SetDWord(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int32_
devpciR3SetCfg(pDevIns, pPciDev, iRegister, u32, 4);
}
+
+DECLINLINE(PPDMPCIDEV) devpciR3FindBridge(PDEVPCIBUS pBus, uint8_t uBus)
+{
+ /* Search for a fitting bridge. */
+ for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
+ {
+ /*
+ * Examine secondary and subordinate bus number.
+ * If the target bus is in the range we pass the request on to the bridge.
+ */
+ PPDMPCIDEV pBridge = pBus->papBridgesR3[iBridge];
+ AssertMsg(pBridge && pciDevIsPci2PciBridge(pBridge),
+ ("Device is not a PCI bridge but on the list of PCI bridges\n"));
+ /* safe, only needs to go to the config space array */
+ uint32_t uSecondary = PDMPciDevGetByte(pBridge, VBOX_PCI_SECONDARY_BUS);
+ /* safe, only needs to go to the config space array */
+ uint32_t uSubordinate = PDMPciDevGetByte(pBridge, VBOX_PCI_SUBORDINATE_BUS);
+ Log3Func(("bus %p, bridge %d: %d in %d..%d\n", pBus, iBridge, uBus, uSecondary, uSubordinate));
+ if (uBus >= uSecondary && uBus <= uSubordinate)
+ return pBridge;
+ }
+
+ /* Nothing found. */
+ return NULL;
+}
+# endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
+
#endif /* IN_RING3 */
#endif /* !VBOX_INCLUDED_SRC_Bus_DevPciInternal_h */
diff --git a/src/VBox/Devices/Makefile.kmk b/src/VBox/Devices/Makefile.kmk
index 38a5e0ea5c1..78c7b527591 100644
--- a/src/VBox/Devices/Makefile.kmk
+++ b/src/VBox/Devices/Makefile.kmk
@@ -920,6 +920,7 @@ if !defined(VBOX_ONLY_EXTPACKS) && "$(intersects $(KBUILD_TARGET_ARCH),$(VBOX_SU
if defined(VBOX_WITH_VIRT_ARMV8)
VBoxDD_DEFS += VBOX_VMM_TARGET_ARMV8
VBoxDD_SOURCES += \
+ Bus/DevPciGenericEcam.cpp \
Misc/DevFlashCFI.cpp \
Misc/DevPL031.cpp \
Serial/DevPL011.cpp
diff --git a/src/VBox/Devices/build/VBoxDD.cpp b/src/VBox/Devices/build/VBoxDD.cpp
index 3aaa372fe46..1c272e92a3e 100644
--- a/src/VBox/Devices/build/VBoxDD.cpp
+++ b/src/VBox/Devices/build/VBoxDD.cpp
@@ -259,6 +259,10 @@ extern "C" DECLEXPORT(int) VBoxDevicesRegister(PPDMDEVREGCB pCallbacks, uint32_t
rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceFlashCFI);
if (RT_FAILURE(rc))
return rc;
+
+ rc = pCallbacks->pfnRegister(pCallbacks, &g_DevicePciGenericEcam);
+ if (RT_FAILURE(rc))
+ return rc;
#endif
return VINF_SUCCESS;
diff --git a/src/VBox/Devices/build/VBoxDD.h b/src/VBox/Devices/build/VBoxDD.h
index 273d9d55a14..759e1ead107 100644
--- a/src/VBox/Devices/build/VBoxDD.h
+++ b/src/VBox/Devices/build/VBoxDD.h
@@ -232,6 +232,7 @@ extern const PDMDEVREG g_DeviceIommuIntel;
extern const PDMDEVREG g_DevicePl011;
extern const PDMDEVREG g_DevicePl031Rtc;
extern const PDMDEVREG g_DeviceFlashCFI;
+extern const PDMDEVREG g_DevicePciGenericEcam;
#endif
/* VBoxAcpi.cpp */