From e2e3ce67b9bf47174b045e0523a806b323d9e4eb Mon Sep 17 00:00:00 2001 From: vboxsync Date: Thu, 11 May 2023 13:37:24 +0000 Subject: 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 --- src/VBox/Devices/Bus/DevPCI.cpp | 8 +- src/VBox/Devices/Bus/DevPciGenericEcam.cpp | 457 +++++++++++++++++++++++++++++ src/VBox/Devices/Bus/DevPciIch9.cpp | 81 +++-- src/VBox/Devices/Bus/DevPciInternal.h | 75 ++++- src/VBox/Devices/Makefile.kmk | 1 + src/VBox/Devices/build/VBoxDD.cpp | 4 + src/VBox/Devices/build/VBoxDD.h | 1 + 7 files changed, 569 insertions(+), 58 deletions(-) create mode 100644 src/VBox/Devices/Bus/DevPciGenericEcam.cpp 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 . + * + * 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 + +#include +#include +#include +#include +#include +#include +#include +#ifdef IN_RING3 +# include +# include +#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 +#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 */ -- cgit v1.2.1