summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostDrivers/VBoxPci
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/HostDrivers/VBoxPci')
-rw-r--r--src/VBox/HostDrivers/VBoxPci/Makefile.kmk93
-rw-r--r--src/VBox/HostDrivers/VBoxPci/VBoxPci.c800
-rw-r--r--src/VBox/HostDrivers/VBoxPci/VBoxPciInternal.h213
-rw-r--r--src/VBox/HostDrivers/VBoxPci/linux/Makefile81
-rw-r--r--src/VBox/HostDrivers/VBoxPci/linux/Makefile.kup0
-rw-r--r--src/VBox/HostDrivers/VBoxPci/linux/VBoxPci-linux.c1186
-rwxr-xr-xsrc/VBox/HostDrivers/VBoxPci/linux/files_vboxpci111
7 files changed, 2484 insertions, 0 deletions
diff --git a/src/VBox/HostDrivers/VBoxPci/Makefile.kmk b/src/VBox/HostDrivers/VBoxPci/Makefile.kmk
new file mode 100644
index 00000000..736824d3
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxPci/Makefile.kmk
@@ -0,0 +1,93 @@
+# $Id: Makefile.kmk $
+## @file
+# Sub-Makefile for the PCI passthru driver (VBoxPci).
+#
+
+#
+# Copyright (C) 2011-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>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+SUB_DEPTH = ../../../..
+include $(KBUILD_PATH)/subheader.kmk
+if1of ($(KBUILD_TARGET), linux)
+
+ ifdef VBOX_WITH_VBOXDRV
+ #
+ # The driver.
+ #
+ SYSMODS += VBoxPci
+ VBoxPci_TEMPLATE = VBoxR0Drv
+ VBoxPci_INST = $(INST_VBOXPCI)$(if $(eq $(KBUILD_TARGET),darwin),Contents/MacOS/)
+ VBoxPci_NAME.linux = vboxpci
+ VBoxPci_DEFS = IN_RT_R0 VBOX_SVN_REV=$(VBOX_SVN_REV) IN_SUP_STATIC
+ VBoxPci_INCS = \
+ .
+ VBoxPci_SOURCES = \
+ VBoxPci.c
+ VBoxPci_LIBS += \
+ $(PATH_STAGE_LIB)/SUPR0IdcClient$(VBOX_SUFF_LIB)
+ endif
+
+ #
+ # Install the sources.
+ #
+ include $(PATH_SUB_CURRENT)/linux/files_vboxpci
+ INSTALLS += VBoxPci-src
+ VBoxPci-src_INST = bin/src/vboxpci/
+ VBoxPci-src_SOURCES = \
+ $(subst $(DQUOTE),,$(VBOX_VBOXPCI_SOURCES)) \
+ $(VBoxPci-src_0_OUTDIR)/Makefile
+ VBoxPci-src_CLEAN = \
+ $(VBoxPci-src_0_OUTDIR)/Makefile \
+ $(PATH_TARGET)/VBoxPciSrc-src-1.dep
+
+ # Generate the scripts needed for building the kernel module.
+
+ includedep $(PATH_TARGET)/VBoxPci-src-1.dep
+ $$(VBoxPci-src_0_OUTDIR)/Makefile: \
+ $(PATH_SUB_CURRENT)/linux/Makefile \
+ $$(if $$(eq $$(VBoxPci/linux/Makefile_VBOX_HARDENED),$$(VBOX_WITH_HARDENING)),,FORCE) \
+ | $$(dir $$@)
+ $(QUIET)$(RM) -f -- $@
+ ifndef VBOX_WITH_HARDENING
+ $(QUIET)$(SED) -e "s;VBOX_WITH_HARDENING;;g" --output $@ $<
+ else
+ $(QUIET)$(CP) -f $< $@
+ endif
+ %$(QUIET2)$(APPEND) -t '$(PATH_TARGET)/VBoxPci-src-1.dep' 'VBoxPci/linux/Makefile_VBOX_HARDENED=$(VBOX_WITH_HARDENING)'
+
+ #
+ # Build test for the linux host kernel modules.
+ #
+ $(evalcall2 VBOX_LINUX_KMOD_TEST_BUILD_RULE_FN,VBoxPci-src,vboxdrv-src,)
+
+endif # Supported platform.
+include $(FILE_KBUILD_SUB_FOOTER)
+
diff --git a/src/VBox/HostDrivers/VBoxPci/VBoxPci.c b/src/VBox/HostDrivers/VBoxPci/VBoxPci.c
new file mode 100644
index 00000000..d4e756a4
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxPci/VBoxPci.c
@@ -0,0 +1,800 @@
+/* $Id: VBoxPci.c $ */
+/** @file
+ * VBoxPci - PCI card passthrough support (Host), Common Code.
+ */
+
+/*
+ * Copyright (C) 2011-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/** @page pg_rawpci VBoxPci - host PCI support
+ *
+ * This is a kernel module that works as host proxy between guest and
+ * PCI hardware.
+ *
+ */
+
+#define LOG_GROUP LOG_GROUP_DEV_PCI_RAW
+#include <VBox/log.h>
+#include <VBox/err.h>
+#include <VBox/sup.h>
+#include <VBox/version.h>
+
+#include <iprt/string.h>
+#include <iprt/assert.h>
+#include <iprt/spinlock.h>
+#include <iprt/uuid.h>
+#include <iprt/asm.h>
+#include <iprt/mem.h>
+
+#include "VBoxPciInternal.h"
+
+
+#define DEVPORT_2_VBOXRAWPCIINS(pPort) \
+ ( (PVBOXRAWPCIINS)((uint8_t *)pPort - RT_OFFSETOF(VBOXRAWPCIINS, DevPort)) )
+
+
+/**
+ * Implements the SUPDRV component factor interface query method.
+ *
+ * @returns Pointer to an interface. NULL if not supported.
+ *
+ * @param pSupDrvFactory Pointer to the component factory registration structure.
+ * @param pSession The session - unused.
+ * @param pszInterfaceUuid The factory interface id.
+ */
+static DECLCALLBACK(void *) vboxPciQueryFactoryInterface(PCSUPDRVFACTORY pSupDrvFactory, PSUPDRVSESSION pSession, const char *pszInterfaceUuid)
+{
+ PVBOXRAWPCIGLOBALS pGlobals = (PVBOXRAWPCIGLOBALS)((uint8_t *)pSupDrvFactory - RT_OFFSETOF(VBOXRAWPCIGLOBALS, SupDrvFactory));
+
+ /*
+ * Convert the UUID strings and compare them.
+ */
+ RTUUID UuidReq;
+ int rc = RTUuidFromStr(&UuidReq, pszInterfaceUuid);
+ if (RT_SUCCESS(rc))
+ {
+ if (!RTUuidCompareStr(&UuidReq, RAWPCIFACTORY_UUID_STR))
+ {
+ ASMAtomicIncS32(&pGlobals->cFactoryRefs);
+ return &pGlobals->RawPciFactory;
+ }
+ }
+ else
+ Log(("VBoxRawPci: rc=%Rrc, uuid=%s\n", rc, pszInterfaceUuid));
+
+ return NULL;
+}
+DECLINLINE(int) vboxPciDevLock(PVBOXRAWPCIINS pThis)
+{
+#ifdef VBOX_WITH_SHARED_PCI_INTERRUPTS
+ RTSpinlockAcquire(pThis->hSpinlock);
+ return VINF_SUCCESS;
+#else
+ int rc = RTSemFastMutexRequest(pThis->hFastMtx);
+
+ AssertRC(rc);
+ return rc;
+#endif
+}
+
+DECLINLINE(void) vboxPciDevUnlock(PVBOXRAWPCIINS pThis)
+{
+#ifdef VBOX_WITH_SHARED_PCI_INTERRUPTS
+ RTSpinlockRelease(pThis->hSpinlock);
+#else
+ RTSemFastMutexRelease(pThis->hFastMtx);
+#endif
+}
+
+DECLINLINE(int) vboxPciVmLock(PVBOXRAWPCIDRVVM pThis)
+{
+ int rc = RTSemFastMutexRequest(pThis->hFastMtx);
+ AssertRC(rc);
+ return rc;
+}
+
+DECLINLINE(void) vboxPciVmUnlock(PVBOXRAWPCIDRVVM pThis)
+{
+ RTSemFastMutexRelease(pThis->hFastMtx);
+}
+
+DECLINLINE(int) vboxPciGlobalsLock(PVBOXRAWPCIGLOBALS pGlobals)
+{
+ int rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
+ AssertRC(rc);
+ return rc;
+}
+
+DECLINLINE(void) vboxPciGlobalsUnlock(PVBOXRAWPCIGLOBALS pGlobals)
+{
+ RTSemFastMutexRelease(pGlobals->hFastMtx);
+}
+
+static PVBOXRAWPCIINS vboxPciFindInstanceLocked(PVBOXRAWPCIGLOBALS pGlobals, uint32_t iHostAddress)
+{
+ PVBOXRAWPCIINS pCur;
+ for (pCur = pGlobals->pInstanceHead; pCur != NULL; pCur = pCur->pNext)
+ {
+ if (iHostAddress == pCur->HostPciAddress)
+ return pCur;
+ }
+ return NULL;
+}
+
+static void vboxPciUnlinkInstanceLocked(PVBOXRAWPCIGLOBALS pGlobals, PVBOXRAWPCIINS pToUnlink)
+{
+ if (pGlobals->pInstanceHead == pToUnlink)
+ pGlobals->pInstanceHead = pToUnlink->pNext;
+ else
+ {
+ PVBOXRAWPCIINS pCur;
+ for (pCur = pGlobals->pInstanceHead; pCur != NULL; pCur = pCur->pNext)
+ {
+ if (pCur->pNext == pToUnlink)
+ {
+ pCur->pNext = pToUnlink->pNext;
+ break;
+ }
+ }
+ }
+ pToUnlink->pNext = NULL;
+}
+
+
+#if 0 /** @todo r=bird: Who the heck is supposed to call this?!? */
+DECLHIDDEN(void) vboxPciDevCleanup(PVBOXRAWPCIINS pThis)
+{
+ pThis->DevPort.pfnDeinit(&pThis->DevPort, 0);
+
+ if (pThis->hFastMtx)
+ {
+ RTSemFastMutexDestroy(pThis->hFastMtx);
+ pThis->hFastMtx = NIL_RTSEMFASTMUTEX;
+ }
+
+ if (pThis->hSpinlock)
+ {
+ RTSpinlockDestroy(pThis->hSpinlock);
+ pThis->hSpinlock = NIL_RTSPINLOCK;
+ }
+
+ vboxPciGlobalsLock(pThis->pGlobals);
+ vboxPciUnlinkInstanceLocked(pThis->pGlobals, pThis);
+ vboxPciGlobalsUnlock(pThis->pGlobals);
+}
+#endif
+
+
+/**
+ * @interface_method_impl{RAWPCIDEVPORT,pfnInit}
+ */
+static DECLCALLBACK(int) vboxPciDevInit(PRAWPCIDEVPORT pPort, uint32_t fFlags)
+{
+ PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
+ int rc;
+
+ vboxPciDevLock(pThis);
+
+ rc = vboxPciOsDevInit(pThis, fFlags);
+
+ vboxPciDevUnlock(pThis);
+
+ return rc;
+}
+
+/**
+ * @interface_method_impl{RAWPCIDEVPORT,pfnDeinit}
+ */
+static DECLCALLBACK(int) vboxPciDevDeinit(PRAWPCIDEVPORT pPort, uint32_t fFlags)
+{
+ PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
+ int rc;
+
+ vboxPciDevLock(pThis);
+
+ if (pThis->IrqHandler.pfnIrqHandler)
+ {
+ vboxPciOsDevUnregisterIrqHandler(pThis, pThis->IrqHandler.iHostIrq);
+ pThis->IrqHandler.iHostIrq = 0;
+ pThis->IrqHandler.pfnIrqHandler = NULL;
+ }
+
+ rc = vboxPciOsDevDeinit(pThis, fFlags);
+
+ vboxPciDevUnlock(pThis);
+
+ return rc;
+}
+
+
+/**
+ * @interface_method_impl{RAWPCIDEVPORT,pfnDestroy}
+ */
+static DECLCALLBACK(int) vboxPciDevDestroy(PRAWPCIDEVPORT pPort)
+{
+ PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
+ int rc;
+
+ rc = vboxPciOsDevDestroy(pThis);
+ if (rc == VINF_SUCCESS)
+ {
+ if (pThis->hFastMtx)
+ {
+ RTSemFastMutexDestroy(pThis->hFastMtx);
+ pThis->hFastMtx = NIL_RTSEMFASTMUTEX;
+ }
+
+ if (pThis->hSpinlock)
+ {
+ RTSpinlockDestroy(pThis->hSpinlock);
+ pThis->hSpinlock = NIL_RTSPINLOCK;
+ }
+
+ vboxPciGlobalsLock(pThis->pGlobals);
+ vboxPciUnlinkInstanceLocked(pThis->pGlobals, pThis);
+ vboxPciGlobalsUnlock(pThis->pGlobals);
+
+ RTMemFree(pThis);
+ }
+
+ return rc;
+}
+/**
+ * @interface_method_impl{RAWPCIDEVPORT,pfnGetRegionInfo}
+ */
+static DECLCALLBACK(int) vboxPciDevGetRegionInfo(PRAWPCIDEVPORT pPort,
+ int32_t iRegion,
+ RTHCPHYS *pRegionStart,
+ uint64_t *pu64RegionSize,
+ bool *pfPresent,
+ uint32_t *pfFlags)
+{
+ PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
+ int rc;
+
+ vboxPciDevLock(pThis);
+
+ rc = vboxPciOsDevGetRegionInfo(pThis, iRegion,
+ pRegionStart, pu64RegionSize,
+ pfPresent, pfFlags);
+ vboxPciDevUnlock(pThis);
+
+ return rc;
+}
+
+/**
+ * @interface_method_impl{RAWPCIDEVPORT,pfnMapRegion}
+ */
+static DECLCALLBACK(int) vboxPciDevMapRegion(PRAWPCIDEVPORT pPort,
+ int32_t iRegion,
+ RTHCPHYS RegionStart,
+ uint64_t u64RegionSize,
+ int32_t fFlags,
+ RTR0PTR *pRegionBaseR0)
+{
+ PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
+ int rc;
+
+ vboxPciDevLock(pThis);
+
+ rc = vboxPciOsDevMapRegion(pThis, iRegion, RegionStart, u64RegionSize, fFlags, pRegionBaseR0);
+
+ vboxPciDevUnlock(pThis);
+
+ return rc;
+}
+
+/**
+ * @interface_method_impl{RAWPCIDEVPORT,pfnUnmapRegion}
+ */
+static DECLCALLBACK(int) vboxPciDevUnmapRegion(PRAWPCIDEVPORT pPort,
+ int32_t iRegion,
+ RTHCPHYS RegionStart,
+ uint64_t u64RegionSize,
+ RTR0PTR RegionBase)
+{
+ PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
+ int rc;
+
+ vboxPciDevLock(pThis);
+
+ rc = vboxPciOsDevUnmapRegion(pThis, iRegion, RegionStart, u64RegionSize, RegionBase);
+
+ vboxPciDevUnlock(pThis);
+
+ return rc;
+}
+
+/**
+ * @interface_method_impl{RAWPCIDEVPORT,pfnPciCfgRead}
+ */
+static DECLCALLBACK(int) vboxPciDevPciCfgRead(PRAWPCIDEVPORT pPort,
+ uint32_t Register,
+ PCIRAWMEMLOC *pValue)
+{
+ PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
+ int rc;
+
+ vboxPciDevLock(pThis);
+
+ rc = vboxPciOsDevPciCfgRead(pThis, Register, pValue);
+
+ vboxPciDevUnlock(pThis);
+
+ return rc;
+}
+
+/**
+ * @interface_method_impl{RAWPCIDEVPORT,pfnPciCfgWrite}
+ */
+static DECLCALLBACK(int) vboxPciDevPciCfgWrite(PRAWPCIDEVPORT pPort,
+ uint32_t Register,
+ PCIRAWMEMLOC *pValue)
+{
+ PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
+ int rc;
+
+ vboxPciDevLock(pThis);
+
+ rc = vboxPciOsDevPciCfgWrite(pThis, Register, pValue);
+
+ vboxPciDevUnlock(pThis);
+
+ return rc;
+}
+
+static DECLCALLBACK(int) vboxPciDevRegisterIrqHandler(PRAWPCIDEVPORT pPort,
+ PFNRAWPCIISR pfnHandler,
+ void* pIrqContext,
+ PCIRAWISRHANDLE *phIsr)
+{
+ PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
+ int rc;
+ int32_t iHostIrq = 0;
+
+ if (pfnHandler == NULL)
+ return VERR_INVALID_PARAMETER;
+
+ vboxPciDevLock(pThis);
+
+ if (pThis->IrqHandler.pfnIrqHandler)
+ {
+ rc = VERR_ALREADY_EXISTS;
+ }
+ else
+ {
+ rc = vboxPciOsDevRegisterIrqHandler(pThis, pfnHandler, pIrqContext, &iHostIrq);
+ if (RT_SUCCESS(rc))
+ {
+ *phIsr = 0xcafe0000;
+ pThis->IrqHandler.iHostIrq = iHostIrq;
+ pThis->IrqHandler.pfnIrqHandler = pfnHandler;
+ pThis->IrqHandler.pIrqContext = pIrqContext;
+ }
+ }
+
+ vboxPciDevUnlock(pThis);
+
+ return rc;
+}
+
+static DECLCALLBACK(int) vboxPciDevUnregisterIrqHandler(PRAWPCIDEVPORT pPort,
+ PCIRAWISRHANDLE hIsr)
+{
+ PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
+ int rc;
+
+ if (hIsr != 0xcafe0000)
+ return VERR_INVALID_PARAMETER;
+
+ vboxPciDevLock(pThis);
+
+ rc = vboxPciOsDevUnregisterIrqHandler(pThis, pThis->IrqHandler.iHostIrq);
+ if (RT_SUCCESS(rc))
+ {
+ pThis->IrqHandler.pfnIrqHandler = NULL;
+ pThis->IrqHandler.pIrqContext = NULL;
+ pThis->IrqHandler.iHostIrq = 0;
+ }
+ vboxPciDevUnlock(pThis);
+
+ return rc;
+}
+
+static DECLCALLBACK(int) vboxPciDevPowerStateChange(PRAWPCIDEVPORT pPort,
+ PCIRAWPOWERSTATE aState,
+ uint64_t *pu64Param)
+{
+ PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
+ int rc;
+
+ vboxPciDevLock(pThis);
+
+ rc = vboxPciOsDevPowerStateChange(pThis, aState);
+
+ switch (aState)
+ {
+ case PCIRAW_POWER_ON:
+ /*
+ * Let virtual device know about VM caps.
+ */
+ *pu64Param = VBOX_DRV_VMDATA(pThis)->pPerVmData->fVmCaps;
+ break;
+ default:
+ pu64Param = 0;
+ break;
+ }
+
+
+ vboxPciDevUnlock(pThis);
+
+ return rc;
+}
+
+/**
+ * Creates a new instance.
+ *
+ * @returns VBox status code.
+ * @param pGlobals The globals.
+ * @param u32HostAddress Host address.
+ * @param fFlags Flags.
+ * @param pVmCtx VM context.
+ * @param ppDevPort Where to store the pointer to our port interface.
+ * @param pfDevFlags The device flags.
+ */
+static int vboxPciNewInstance(PVBOXRAWPCIGLOBALS pGlobals,
+ uint32_t u32HostAddress,
+ uint32_t fFlags,
+ PRAWPCIPERVM pVmCtx,
+ PRAWPCIDEVPORT *ppDevPort,
+ uint32_t *pfDevFlags)
+{
+ int rc;
+ PVBOXRAWPCIINS pNew = (PVBOXRAWPCIINS)RTMemAllocZ(sizeof(*pNew));
+ if (!pNew)
+ return VERR_NO_MEMORY;
+
+ pNew->pGlobals = pGlobals;
+ pNew->hSpinlock = NIL_RTSPINLOCK;
+ pNew->cRefs = 1;
+ pNew->pNext = NULL;
+ pNew->HostPciAddress = u32HostAddress;
+ pNew->pVmCtx = pVmCtx;
+
+ pNew->DevPort.u32Version = RAWPCIDEVPORT_VERSION;
+
+ pNew->DevPort.pfnInit = vboxPciDevInit;
+ pNew->DevPort.pfnDeinit = vboxPciDevDeinit;
+ pNew->DevPort.pfnDestroy = vboxPciDevDestroy;
+ pNew->DevPort.pfnGetRegionInfo = vboxPciDevGetRegionInfo;
+ pNew->DevPort.pfnMapRegion = vboxPciDevMapRegion;
+ pNew->DevPort.pfnUnmapRegion = vboxPciDevUnmapRegion;
+ pNew->DevPort.pfnPciCfgRead = vboxPciDevPciCfgRead;
+ pNew->DevPort.pfnPciCfgWrite = vboxPciDevPciCfgWrite;
+ pNew->DevPort.pfnPciCfgRead = vboxPciDevPciCfgRead;
+ pNew->DevPort.pfnPciCfgWrite = vboxPciDevPciCfgWrite;
+ pNew->DevPort.pfnRegisterIrqHandler = vboxPciDevRegisterIrqHandler;
+ pNew->DevPort.pfnUnregisterIrqHandler = vboxPciDevUnregisterIrqHandler;
+ pNew->DevPort.pfnPowerStateChange = vboxPciDevPowerStateChange;
+ pNew->DevPort.u32VersionEnd = RAWPCIDEVPORT_VERSION;
+
+ rc = RTSpinlockCreate(&pNew->hSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "VBoxPCI");
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSemFastMutexCreate(&pNew->hFastMtx);
+ if (RT_SUCCESS(rc))
+ {
+ rc = pNew->DevPort.pfnInit(&pNew->DevPort, fFlags);
+ if (RT_SUCCESS(rc))
+ {
+ *ppDevPort = &pNew->DevPort;
+
+ pNew->pNext = pGlobals->pInstanceHead;
+ pGlobals->pInstanceHead = pNew;
+ }
+ else
+ {
+ RTSemFastMutexDestroy(pNew->hFastMtx);
+ RTSpinlockDestroy(pNew->hSpinlock);
+ RTMemFree(pNew);
+ }
+ }
+ }
+
+ return rc;
+}
+
+/**
+ * @interface_method_impl{RAWPCIFACTORY,pfnCreateAndConnect}
+ */
+static DECLCALLBACK(int) vboxPciFactoryCreateAndConnect(PRAWPCIFACTORY pFactory,
+ uint32_t u32HostAddress,
+ uint32_t fFlags,
+ PRAWPCIPERVM pVmCtx,
+ PRAWPCIDEVPORT *ppDevPort,
+ uint32_t *pfDevFlags)
+{
+ PVBOXRAWPCIGLOBALS pGlobals = (PVBOXRAWPCIGLOBALS)((uint8_t *)pFactory - RT_OFFSETOF(VBOXRAWPCIGLOBALS, RawPciFactory));
+ int rc;
+
+ LogFlow(("vboxPciFactoryCreateAndConnect: PCI=%x fFlags=%#x\n", u32HostAddress, fFlags));
+ Assert(pGlobals->cFactoryRefs > 0);
+ rc = vboxPciGlobalsLock(pGlobals);
+ AssertRCReturn(rc, rc);
+
+ /* First search if there's no existing instance with same host device
+ * address - if so - we cannot continue.
+ */
+ if (vboxPciFindInstanceLocked(pGlobals, u32HostAddress) != NULL)
+ {
+ rc = VERR_RESOURCE_BUSY;
+ goto unlock;
+ }
+
+ rc = vboxPciNewInstance(pGlobals, u32HostAddress, fFlags, pVmCtx, ppDevPort, pfDevFlags);
+
+unlock:
+ vboxPciGlobalsUnlock(pGlobals);
+
+ return rc;
+}
+
+/**
+ * @interface_method_impl{RAWPCIFACTORY,pfnRelease}
+ */
+static DECLCALLBACK(void) vboxPciFactoryRelease(PRAWPCIFACTORY pFactory)
+{
+ PVBOXRAWPCIGLOBALS pGlobals = (PVBOXRAWPCIGLOBALS)((uint8_t *)pFactory - RT_OFFSETOF(VBOXRAWPCIGLOBALS, RawPciFactory));
+
+ int32_t cRefs = ASMAtomicDecS32(&pGlobals->cFactoryRefs);
+ Assert(cRefs >= 0); NOREF(cRefs);
+ LogFlow(("vboxPciFactoryRelease: cRefs=%d (new)\n", cRefs));
+}
+
+/**
+ * @interface_method_impl{RAWPCIFACTORY,pfnInitVm}
+ */
+static DECLCALLBACK(int) vboxPciFactoryInitVm(PRAWPCIFACTORY pFactory,
+ PVM pVM,
+ PRAWPCIPERVM pVmData)
+{
+ PVBOXRAWPCIDRVVM pThis = (PVBOXRAWPCIDRVVM)RTMemAllocZ(sizeof(VBOXRAWPCIDRVVM));
+ int rc;
+
+ if (!pThis)
+ return VERR_NO_MEMORY;
+
+ rc = RTSemFastMutexCreate(&pThis->hFastMtx);
+ if (RT_SUCCESS(rc))
+ {
+ rc = vboxPciOsInitVm(pThis, pVM, pVmData);
+
+ if (RT_SUCCESS(rc))
+ {
+#ifdef VBOX_WITH_IOMMU
+ /* If IOMMU notification routine in pVmData->pfnContigMemInfo
+ is set - we have functional IOMMU hardware. */
+ if (pVmData->pfnContigMemInfo)
+ pVmData->fVmCaps |= PCIRAW_VMFLAGS_HAS_IOMMU;
+#endif
+ pThis->pPerVmData = pVmData;
+ pVmData->pDriverData = pThis;
+ return VINF_SUCCESS;
+ }
+
+ RTSemFastMutexDestroy(pThis->hFastMtx);
+ pThis->hFastMtx = NIL_RTSEMFASTMUTEX;
+ RTMemFree(pThis);
+ }
+
+ return rc;
+}
+
+/**
+ * @interface_method_impl{RAWPCIFACTORY,pfnDeinitVm}
+ */
+static DECLCALLBACK(void) vboxPciFactoryDeinitVm(PRAWPCIFACTORY pFactory,
+ PVM pVM,
+ PRAWPCIPERVM pVmData)
+{
+ if (pVmData->pDriverData)
+ {
+ PVBOXRAWPCIDRVVM pThis = (PVBOXRAWPCIDRVVM)pVmData->pDriverData;
+
+#ifdef VBOX_WITH_IOMMU
+ /* If we have IOMMU, need to unmap all guest's physical pages from IOMMU on VM termination. */
+#endif
+
+ vboxPciOsDeinitVm(pThis, pVM);
+
+ if (pThis->hFastMtx)
+ {
+ RTSemFastMutexDestroy(pThis->hFastMtx);
+ pThis->hFastMtx = NIL_RTSEMFASTMUTEX;
+ }
+
+ RTMemFree(pThis);
+ pVmData->pDriverData = NULL;
+ }
+}
+
+
+static bool vboxPciCanUnload(PVBOXRAWPCIGLOBALS pGlobals)
+{
+ int rc = vboxPciGlobalsLock(pGlobals);
+ bool fRc = !pGlobals->pInstanceHead
+ && pGlobals->cFactoryRefs <= 0;
+ vboxPciGlobalsUnlock(pGlobals);
+ AssertRC(rc);
+ return fRc;
+}
+
+
+static int vboxPciInitIdc(PVBOXRAWPCIGLOBALS pGlobals)
+{
+ int rc;
+ Assert(!pGlobals->fIDCOpen);
+
+ /*
+ * Establish a connection to SUPDRV and register our component factory.
+ */
+ rc = SUPR0IdcOpen(&pGlobals->SupDrvIDC, 0 /* iReqVersion = default */, 0 /* iMinVersion = default */, NULL, NULL, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
+ if (RT_SUCCESS(rc))
+ {
+ pGlobals->fIDCOpen = true;
+ Log(("VBoxRawPci: pSession=%p\n", SUPR0IdcGetSession(&pGlobals->SupDrvIDC)));
+ return rc;
+ }
+
+ /* bail out. */
+ LogRel(("VBoxRawPci: Failed to register component factory, rc=%Rrc\n", rc));
+ SUPR0IdcClose(&pGlobals->SupDrvIDC);
+ }
+
+ return rc;
+}
+
+
+/**
+ * Try to close the IDC connection to SUPDRV if established.
+ *
+ * @returns VBox status code.
+ * @retval VINF_SUCCESS on success.
+ * @retval VERR_WRONG_ORDER if we're busy.
+ *
+ * @param pGlobals Pointer to the globals.
+ */
+static int vboxPciDeleteIdc(PVBOXRAWPCIGLOBALS pGlobals)
+{
+ int rc;
+
+ Assert(pGlobals->hFastMtx != NIL_RTSEMFASTMUTEX);
+
+ /*
+ * Check before trying to deregister the factory.
+ */
+ if (!vboxPciCanUnload(pGlobals))
+ return VERR_WRONG_ORDER;
+
+ if (!pGlobals->fIDCOpen)
+ rc = VINF_SUCCESS;
+ else
+ {
+ /*
+ * Disconnect from SUPDRV.
+ */
+ rc = SUPR0IdcComponentDeregisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
+ AssertRC(rc);
+ SUPR0IdcClose(&pGlobals->SupDrvIDC);
+ pGlobals->fIDCOpen = false;
+ }
+
+ return rc;
+}
+
+
+/**
+ * Initializes the globals.
+ *
+ * @returns VBox status code.
+ * @param pGlobals Pointer to the globals.
+ */
+static int vboxPciInitGlobals(PVBOXRAWPCIGLOBALS pGlobals)
+{
+ /*
+ * Initialize the common portions of the structure.
+ */
+ int rc = RTSemFastMutexCreate(&pGlobals->hFastMtx);
+ if (RT_SUCCESS(rc))
+ {
+ pGlobals->pInstanceHead = NULL;
+ pGlobals->RawPciFactory.pfnRelease = vboxPciFactoryRelease;
+ pGlobals->RawPciFactory.pfnCreateAndConnect = vboxPciFactoryCreateAndConnect;
+ pGlobals->RawPciFactory.pfnInitVm = vboxPciFactoryInitVm;
+ pGlobals->RawPciFactory.pfnDeinitVm = vboxPciFactoryDeinitVm;
+ memcpy(pGlobals->SupDrvFactory.szName, "VBoxRawPci", sizeof("VBoxRawPci"));
+ pGlobals->SupDrvFactory.pfnQueryFactoryInterface = vboxPciQueryFactoryInterface;
+ pGlobals->fIDCOpen = false;
+ }
+ return rc;
+}
+
+
+/**
+ * Deletes the globals.
+ *
+ * @param pGlobals Pointer to the globals.
+ */
+static void vboxPciDeleteGlobals(PVBOXRAWPCIGLOBALS pGlobals)
+{
+ Assert(!pGlobals->fIDCOpen);
+
+ /*
+ * Release resources.
+ */
+ if (pGlobals->hFastMtx)
+ {
+ RTSemFastMutexDestroy(pGlobals->hFastMtx);
+ pGlobals->hFastMtx = NIL_RTSEMFASTMUTEX;
+ }
+}
+
+
+int vboxPciInit(PVBOXRAWPCIGLOBALS pGlobals)
+{
+
+ /*
+ * Initialize the common portions of the structure.
+ */
+ int rc = vboxPciInitGlobals(pGlobals);
+ if (RT_SUCCESS(rc))
+ {
+ rc = vboxPciInitIdc(pGlobals);
+ if (RT_SUCCESS(rc))
+ return rc;
+
+ /* bail out. */
+ vboxPciDeleteGlobals(pGlobals);
+ }
+
+ return rc;
+}
+
+void vboxPciShutdown(PVBOXRAWPCIGLOBALS pGlobals)
+{
+ int rc = vboxPciDeleteIdc(pGlobals);
+ if (RT_SUCCESS(rc))
+ vboxPciDeleteGlobals(pGlobals);
+}
+
diff --git a/src/VBox/HostDrivers/VBoxPci/VBoxPciInternal.h b/src/VBox/HostDrivers/VBoxPci/VBoxPciInternal.h
new file mode 100644
index 00000000..c82cd18d
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxPci/VBoxPciInternal.h
@@ -0,0 +1,213 @@
+/* $Id: VBoxPciInternal.h $ */
+/** @file
+ * VBoxPci - PCI driver (Host), Internal Header.
+ */
+
+/*
+ * Copyright (C) 2011-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#ifndef VBOX_INCLUDED_SRC_VBoxPci_VBoxPciInternal_h
+#define VBOX_INCLUDED_SRC_VBoxPci_VBoxPciInternal_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <VBox/sup.h>
+#include <VBox/rawpci.h>
+#include <iprt/semaphore.h>
+#include <iprt/assert.h>
+
+#ifdef RT_OS_LINUX
+
+#if RTLNX_VER_MIN(2,6,35) && defined(CONFIG_IOMMU_API)
+# define VBOX_WITH_IOMMU
+#endif
+
+#ifdef VBOX_WITH_IOMMU
+#include <linux/errno.h>
+#include <linux/iommu.h>
+#endif
+
+#endif
+
+RT_C_DECLS_BEGIN
+
+/* Forward declaration. */
+typedef struct VBOXRAWPCIGLOBALS *PVBOXRAWPCIGLOBALS;
+typedef struct VBOXRAWPCIDRVVM *PVBOXRAWPCIDRVVM;
+typedef struct VBOXRAWPCIINS *PVBOXRAWPCIINS;
+
+typedef struct VBOXRAWPCIISRDESC
+{
+ /** Handler function. */
+ PFNRAWPCIISR pfnIrqHandler;
+ /** Handler context. */
+ void *pIrqContext;
+ /** Host IRQ. */
+ int32_t iHostIrq;
+} VBOXRAWPCIISRDESC;
+typedef struct VBOXRAWPCIISRDESC *PVBOXRAWPCIISRDESC;
+
+/**
+ * The per-instance data of the VBox raw PCI interface.
+ *
+ * This is data associated with a host PCI card attached to the VM.
+ *
+ */
+typedef struct VBOXRAWPCIINS
+{
+ /** Pointer to the globals. */
+ PVBOXRAWPCIGLOBALS pGlobals;
+
+ /** Mutex protecting device access. */
+ RTSEMFASTMUTEX hFastMtx;
+ /** The spinlock protecting the state variables and device access. */
+ RTSPINLOCK hSpinlock;
+ /** Pointer to the next device in the list. */
+ PVBOXRAWPCIINS pNext;
+ /** Reference count. */
+ uint32_t volatile cRefs;
+
+ /* Host PCI address of this device. */
+ uint32_t HostPciAddress;
+
+#ifdef RT_OS_LINUX
+ struct pci_dev * pPciDev;
+ char szPrevDriver[64];
+#endif
+ bool fMsiUsed;
+ bool fMsixUsed;
+ bool fIommuUsed;
+ bool fPad0;
+
+ /** Port, given to the outside world. */
+ RAWPCIDEVPORT DevPort;
+
+ /** IRQ handler. */
+ VBOXRAWPCIISRDESC IrqHandler;
+
+ /** Pointer to per-VM context in hypervisor data. */
+ PRAWPCIPERVM pVmCtx;
+
+ RTR0PTR aRegionR0Mapping[/* XXX: magic */ 7];
+} VBOXRAWPCIINS;
+
+/**
+ * Per-VM data of the VBox PCI driver. Pointed to by pGVM->rawpci.s.pDriverData.
+ *
+ */
+typedef struct VBOXRAWPCIDRVVM
+{
+ /** Mutex protecting state changes. */
+ RTSEMFASTMUTEX hFastMtx;
+
+#ifdef RT_OS_LINUX
+# ifdef VBOX_WITH_IOMMU
+ /* IOMMU domain. */
+ struct iommu_domain* pIommuDomain;
+# endif
+#endif
+ /* Back pointer to pGVM->rawpci.s. */
+ PRAWPCIPERVM pPerVmData;
+} VBOXRAWPCIDRVVM;
+
+/**
+ * The global data of the VBox PCI driver.
+ *
+ * This contains the bit required for communicating with support driver, VBoxDrv
+ * (start out as SupDrv).
+ */
+typedef struct VBOXRAWPCIGLOBALS
+{
+ /** Mutex protecting the list of instances and state changes. */
+ RTSEMFASTMUTEX hFastMtx;
+
+ /** Pointer to a list of instance data. */
+ PVBOXRAWPCIINS pInstanceHead;
+
+ /** The raw PCI interface factory. */
+ RAWPCIFACTORY RawPciFactory;
+ /** The SUPDRV component factory registration. */
+ SUPDRVFACTORY SupDrvFactory;
+ /** The number of current factory references. */
+ int32_t volatile cFactoryRefs;
+ /** Whether the IDC connection is open or not.
+ * This is only for cleaning up correctly after the separate IDC init on Windows. */
+ bool fIDCOpen;
+ /** The SUPDRV IDC handle (opaque struct). */
+ SUPDRVIDCHANDLE SupDrvIDC;
+#ifdef RT_OS_LINUX
+ bool fPciStubModuleAvail;
+ struct module * pciStubModule;
+#endif
+} VBOXRAWPCIGLOBALS;
+
+DECLHIDDEN(int) vboxPciInit(PVBOXRAWPCIGLOBALS pGlobals);
+DECLHIDDEN(void) vboxPciShutdown(PVBOXRAWPCIGLOBALS pGlobals);
+
+DECLHIDDEN(int) vboxPciOsInitVm(PVBOXRAWPCIDRVVM pThis, PVM pVM, PRAWPCIPERVM pVmData);
+DECLHIDDEN(void) vboxPciOsDeinitVm(PVBOXRAWPCIDRVVM pThis, PVM pVM);
+
+DECLHIDDEN(int) vboxPciOsDevInit (PVBOXRAWPCIINS pIns, uint32_t fFlags);
+DECLHIDDEN(int) vboxPciOsDevDeinit(PVBOXRAWPCIINS pIns, uint32_t fFlags);
+DECLHIDDEN(int) vboxPciOsDevDestroy(PVBOXRAWPCIINS pIns);
+
+DECLHIDDEN(int) vboxPciOsDevGetRegionInfo(PVBOXRAWPCIINS pIns,
+ int32_t iRegion,
+ RTHCPHYS *pRegionStart,
+ uint64_t *pu64RegionSize,
+ bool *pfPresent,
+ uint32_t *pfFlags);
+DECLHIDDEN(int) vboxPciOsDevMapRegion(PVBOXRAWPCIINS pIns,
+ int32_t iRegion,
+ RTHCPHYS pRegionStart,
+ uint64_t u64RegionSize,
+ uint32_t fFlags,
+ RTR0PTR *pRegionBase);
+DECLHIDDEN(int) vboxPciOsDevUnmapRegion(PVBOXRAWPCIINS pIns,
+ int32_t iRegion,
+ RTHCPHYS RegionStart,
+ uint64_t u64RegionSize,
+ RTR0PTR RegionBase);
+
+DECLHIDDEN(int) vboxPciOsDevPciCfgWrite(PVBOXRAWPCIINS pIns, uint32_t Register, PCIRAWMEMLOC *pValue);
+DECLHIDDEN(int) vboxPciOsDevPciCfgRead (PVBOXRAWPCIINS pIns, uint32_t Register, PCIRAWMEMLOC *pValue);
+
+DECLHIDDEN(int) vboxPciOsDevRegisterIrqHandler (PVBOXRAWPCIINS pIns, PFNRAWPCIISR pfnHandler, void* pIrqContext, int32_t *piHostIrq);
+DECLHIDDEN(int) vboxPciOsDevUnregisterIrqHandler(PVBOXRAWPCIINS pIns, int32_t iHostIrq);
+
+DECLHIDDEN(int) vboxPciOsDevPowerStateChange(PVBOXRAWPCIINS pIns, PCIRAWPOWERSTATE aState);
+
+#define VBOX_DRV_VMDATA(pIns) ((PVBOXRAWPCIDRVVM)(pIns->pVmCtx ? pIns->pVmCtx->pDriverData : NULL))
+
+RT_C_DECLS_END
+
+#endif /* !VBOX_INCLUDED_SRC_VBoxPci_VBoxPciInternal_h */
diff --git a/src/VBox/HostDrivers/VBoxPci/linux/Makefile b/src/VBox/HostDrivers/VBoxPci/linux/Makefile
new file mode 100644
index 00000000..bbcefe76
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxPci/linux/Makefile
@@ -0,0 +1,81 @@
+# $Id: Makefile $
+## @file
+# Makefile for the VirtualBox Linux Host PCI Driver.
+#
+
+#
+# Copyright (C) 2011-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>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+
+# Linux kbuild sets this to our source directory if we are called from there
+obj ?= $(CURDIR)
+include $(obj)/Makefile-header.gmk
+VBOXPCI_DIR := $(VBOX_MODULE_SRC_DIR)
+
+# Allow building directly from the subdirectory without assuming the toplevel
+# makefile has done the copying. Not the default use case, but can be handy.
+ifndef KBUILD_EXTRA_SYMBOLS
+KBUILD_EXTRA_SYMBOLS=$(abspath $(VBOXPCI_DIR)/../vboxdrv/Module.symvers)
+endif
+
+# override is required by the Debian guys
+VBOXMOD_NAME = vboxpci
+VBOXMOD_OBJS = \
+ linux/VBoxPci-linux.o \
+ VBoxPci.o \
+ SUPR0IdcClient.o \
+ SUPR0IdcClientComponent.o \
+ linux/SUPR0IdcClient-linux.o
+ifeq ($(VBOX_KBUILD_TARGET_ARCH),x86)
+VBOXMOD_OBJS += \
+ math/gcc/divdi3.o \
+ math/gcc/moddi3.o \
+ math/gcc/qdivrem.o \
+ math/gcc/udivdi3.o \
+ math/gcc/udivmoddi4.o \
+ math/gcc/divdi3.o \
+ math/gcc/umoddi3.o
+endif
+VBOXMOD_INCL = \
+ $(VBOXPCI_DIR) \
+ $(VBOXPCI_DIR)include \
+ $(VBOXPCI_DIR)r0drv/linux
+VBOXMOD_DEFS = \
+ RT_OS_LINUX \
+ IN_RING0 \
+ IN_RT_R0 \
+ IN_SUP_R0 \
+ VBOX \
+ RT_WITH_VBOX \
+ VBOX_WITH_HARDENING
+VBOXMOD_CFLAGS = -include $(VBOXPCI_DIR)include/VBox/SUPDrvMangling.h -fno-pie
+
+include $(obj)/Makefile-footer.gmk
diff --git a/src/VBox/HostDrivers/VBoxPci/linux/Makefile.kup b/src/VBox/HostDrivers/VBoxPci/linux/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxPci/linux/Makefile.kup
diff --git a/src/VBox/HostDrivers/VBoxPci/linux/VBoxPci-linux.c b/src/VBox/HostDrivers/VBoxPci/linux/VBoxPci-linux.c
new file mode 100644
index 00000000..36685dd9
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxPci/linux/VBoxPci-linux.c
@@ -0,0 +1,1186 @@
+/* $Id: VBoxPci-linux.c $ */
+/** @file
+ * VBoxPci - PCI Driver (Host), Linux Specific Code.
+ */
+
+/*
+ * Copyright (C) 2011-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>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-linux-kernel.h"
+#include "version-generated.h"
+#include "revision-generated.h"
+#include "product-generated.h"
+
+#define LOG_GROUP LOG_GROUP_DEV_PCI_RAW
+#include <VBox/log.h>
+#include <VBox/err.h>
+#include <iprt/process.h>
+#include <iprt/initterm.h>
+#include <iprt/string.h>
+#include <iprt/mem.h>
+
+#include "../VBoxPciInternal.h"
+
+#ifdef VBOX_WITH_IOMMU
+# include <linux/dmar.h>
+# include <linux/intel-iommu.h>
+# include <linux/pci.h>
+# if RTLNX_VER_MAX(3,1,0) && \
+ (RTLNX_VER_MAX(2,6,41) || RTLNX_VER_MIN(3,0,0))
+# include <asm/amd_iommu.h>
+# else
+# include <linux/amd-iommu.h>
+# endif
+# if RTLNX_VER_MAX(3,2,0)
+# define IOMMU_PRESENT() iommu_found()
+# define IOMMU_DOMAIN_ALLOC() iommu_domain_alloc()
+# else
+# define IOMMU_PRESENT() iommu_present(&pci_bus_type)
+# define IOMMU_DOMAIN_ALLOC() iommu_domain_alloc(&pci_bus_type)
+# endif
+#endif /* VBOX_WITH_IOMMU */
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static int __init VBoxPciLinuxInit(void);
+static void __exit VBoxPciLinuxUnload(void);
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+static VBOXRAWPCIGLOBALS g_VBoxPciGlobals;
+
+module_init(VBoxPciLinuxInit);
+module_exit(VBoxPciLinuxUnload);
+
+MODULE_AUTHOR(VBOX_VENDOR);
+MODULE_DESCRIPTION(VBOX_PRODUCT " PCI access Driver");
+MODULE_LICENSE("GPL");
+#ifdef MODULE_VERSION
+MODULE_VERSION(VBOX_VERSION_STRING " r" RT_XSTR(VBOX_SVN_REV));
+#endif
+
+
+#if RTLNX_VER_MIN(2,6,20)
+# define PCI_DEV_GET(v,d,p) pci_get_device(v,d,p)
+# define PCI_DEV_PUT(x) pci_dev_put(x)
+#if RTLNX_VER_MIN(4,17,0)
+/* assume the domain number to be zero - exactly the same assumption of
+ * pci_get_bus_and_slot()
+ */
+# define PCI_DEV_GET_SLOT(bus, devfn) pci_get_domain_bus_and_slot(0, bus, devfn)
+#else
+# define PCI_DEV_GET_SLOT(bus, devfn) pci_get_bus_and_slot(bus, devfn)
+#endif
+#else
+# define PCI_DEV_GET(v,d,p) pci_find_device(v,d,p)
+# define PCI_DEV_PUT(x) do { } while (0)
+# define PCI_DEV_GET_SLOT(bus, devfn) pci_find_slot(bus, devfn)
+#endif
+
+/**
+ * Name of module used to attach to the host PCI device, when
+ * PCI device passthrough is used.
+ */
+#define PCI_STUB_MODULE "pci-stub"
+/* For some reasons my kernel names module for find_module() this way,
+ * while device name seems to be above one.
+ */
+#define PCI_STUB_MODULE_NAME "pci_stub"
+
+/**
+ * Our driver name.
+ */
+#define DRIVER_NAME "vboxpci"
+
+/*
+ * Currently we keep the device bound to pci stub driver, so
+ * dev_printk() &co would report that instead of our name. They also
+ * expect non-NULL dev pointer in older kernels.
+ */
+#define vbpci_printk(level, pdev, format, arg...) \
+ printk(level DRIVER_NAME "%s%s: " format, \
+ pdev ? " " : "", pdev ? pci_name(pdev) : "", \
+ ## arg)
+
+
+/**
+ * Initialize module.
+ *
+ * @returns appropriate status code.
+ */
+static int __init VBoxPciLinuxInit(void)
+{
+ int rc;
+ /*
+ * Initialize IPRT.
+ */
+ rc = RTR0Init(0);
+
+ if (RT_FAILURE(rc))
+ goto error;
+
+
+ LogRel(("VBoxPciLinuxInit\n"));
+
+ RT_ZERO(g_VBoxPciGlobals);
+
+ rc = vboxPciInit(&g_VBoxPciGlobals);
+ if (RT_FAILURE(rc))
+ {
+ LogRel(("cannot do VBoxPciInit: %Rc\n", rc));
+ goto error;
+ }
+
+#if defined(CONFIG_PCI_STUB)
+ /* nothing to do, pci_stub module part of the kernel */
+ g_VBoxPciGlobals.fPciStubModuleAvail = true;
+
+#elif defined(CONFIG_PCI_STUB_MODULE)
+ if (request_module(PCI_STUB_MODULE) == 0)
+ {
+# if RTLNX_VER_MIN(2,6,30)
+ /* find_module() is static before Linux 2.6.30 */
+ mutex_lock(&module_mutex);
+ g_VBoxPciGlobals.pciStubModule = find_module(PCI_STUB_MODULE_NAME);
+ mutex_unlock(&module_mutex);
+ if (g_VBoxPciGlobals.pciStubModule)
+ {
+ if (try_module_get(g_VBoxPciGlobals.pciStubModule))
+ g_VBoxPciGlobals.fPciStubModuleAvail = true;
+ }
+ else
+ printk(KERN_INFO "vboxpci: find_module %s failed\n", PCI_STUB_MODULE);
+# endif
+ }
+ else
+ printk(KERN_INFO "vboxpci: cannot load %s\n", PCI_STUB_MODULE);
+
+#else
+ printk(KERN_INFO "vboxpci: %s module not available, cannot detach PCI devices\n",
+ PCI_STUB_MODULE);
+#endif
+
+#ifdef VBOX_WITH_IOMMU
+ if (IOMMU_PRESENT())
+ printk(KERN_INFO "vboxpci: IOMMU found\n");
+ else
+ printk(KERN_INFO "vboxpci: IOMMU not found (not registered)\n");
+#else
+ printk(KERN_INFO "vboxpci: IOMMU not found (not compiled)\n");
+#endif
+
+ return 0;
+
+ error:
+ return -RTErrConvertToErrno(rc);
+}
+
+/**
+ * Unload the module.
+ */
+static void __exit VBoxPciLinuxUnload(void)
+{
+ LogRel(("VBoxPciLinuxLinuxUnload\n"));
+
+ /*
+ * Undo the work done during start (in reverse order).
+ */
+ vboxPciShutdown(&g_VBoxPciGlobals);
+
+ RTR0Term();
+
+ if (g_VBoxPciGlobals.pciStubModule)
+ {
+ module_put(g_VBoxPciGlobals.pciStubModule);
+ g_VBoxPciGlobals.pciStubModule = NULL;
+ }
+
+ Log(("VBoxPciLinuxUnload - done\n"));
+}
+
+static int vboxPciLinuxDevRegisterWithIommu(PVBOXRAWPCIINS pIns)
+{
+#ifdef VBOX_WITH_IOMMU
+ int rc = VINF_SUCCESS;
+ struct pci_dev *pPciDev = pIns->pPciDev;
+ PVBOXRAWPCIDRVVM pData = VBOX_DRV_VMDATA(pIns);
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ if (RT_LIKELY(pData))
+ {
+ if (RT_LIKELY(pData->pIommuDomain))
+ {
+ /** @todo KVM checks IOMMU_CAP_CACHE_COHERENCY and sets
+ * flag IOMMU_CACHE later used when mapping physical
+ * addresses, which could improve performance.
+ */
+ int rcLnx = iommu_attach_device(pData->pIommuDomain, &pPciDev->dev);
+ if (!rcLnx)
+ {
+ vbpci_printk(KERN_DEBUG, pPciDev, "attached to IOMMU\n");
+ pIns->fIommuUsed = true;
+ rc = VINF_SUCCESS;
+ }
+ else
+ {
+ vbpci_printk(KERN_DEBUG, pPciDev, "failed to attach to IOMMU, error %d\n", rcLnx);
+ rc = VERR_INTERNAL_ERROR;
+ }
+ }
+ else
+ {
+ vbpci_printk(KERN_DEBUG, pIns->pPciDev, "cannot attach to IOMMU, no domain\n");
+ rc = VERR_NOT_FOUND;
+ }
+ }
+ else
+ {
+ vbpci_printk(KERN_DEBUG, pPciDev, "cannot attach to IOMMU, no VM data\n");
+ rc = VERR_INVALID_PARAMETER;
+ }
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+#else
+ return VERR_NOT_SUPPORTED;
+#endif
+}
+
+static int vboxPciLinuxDevUnregisterWithIommu(PVBOXRAWPCIINS pIns)
+{
+#ifdef VBOX_WITH_IOMMU
+ int rc = VINF_SUCCESS;
+ struct pci_dev *pPciDev = pIns->pPciDev;
+ PVBOXRAWPCIDRVVM pData = VBOX_DRV_VMDATA(pIns);
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ if (RT_LIKELY(pData))
+ {
+ if (RT_LIKELY(pData->pIommuDomain))
+ {
+ if (pIns->fIommuUsed)
+ {
+ iommu_detach_device(pData->pIommuDomain, &pIns->pPciDev->dev);
+ vbpci_printk(KERN_DEBUG, pPciDev, "detached from IOMMU\n");
+ pIns->fIommuUsed = false;
+ }
+ }
+ else
+ {
+ vbpci_printk(KERN_DEBUG, pPciDev,
+ "cannot detach from IOMMU, no domain\n");
+ rc = VERR_NOT_FOUND;
+ }
+ }
+ else
+ {
+ vbpci_printk(KERN_DEBUG, pPciDev,
+ "cannot detach from IOMMU, no VM data\n");
+ rc = VERR_INVALID_PARAMETER;
+ }
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+#else
+ return VERR_NOT_SUPPORTED;
+#endif
+}
+
+static int vboxPciLinuxDevReset(PVBOXRAWPCIINS pIns)
+{
+ int rc = VINF_SUCCESS;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ if (RT_LIKELY(pIns->pPciDev))
+ {
+#if RTLNX_VER_MIN(2,6,28)
+ if (pci_reset_function(pIns->pPciDev))
+ {
+ vbpci_printk(KERN_DEBUG, pIns->pPciDev,
+ "pci_reset_function() failed\n");
+ rc = VERR_INTERNAL_ERROR;
+ }
+#else
+ rc = VERR_NOT_SUPPORTED;
+#endif
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+}
+
+static struct file* vboxPciFileOpen(const char* path, int flags)
+{
+ struct file* filp = NULL;
+ int err = 0;
+
+ filp = filp_open(path, flags, 0);
+
+ if (IS_ERR(filp))
+ {
+ err = PTR_ERR(filp);
+ printk(KERN_DEBUG "vboxPciFileOpen: error %d\n", err);
+ return NULL;
+ }
+
+ if (!filp->f_op || !filp->f_op->write)
+ {
+ printk(KERN_DEBUG "Not writable FS\n");
+ filp_close(filp, NULL);
+ return NULL;
+ }
+
+ return filp;
+}
+
+static void vboxPciFileClose(struct file* file)
+{
+ filp_close(file, NULL);
+}
+
+static int vboxPciFileWrite(struct file* file, unsigned long long offset, unsigned char* data, unsigned int size)
+{
+ int ret;
+ mm_segment_t fs_save;
+
+ fs_save = get_fs();
+ set_fs(KERNEL_DS);
+#if RTLNX_VER_MIN(4,14,0)
+ ret = kernel_write(file, data, size, &offset);
+#else
+ ret = vfs_write(file, data, size, &offset);
+#endif
+ set_fs(fs_save);
+ if (ret < 0)
+ printk(KERN_DEBUG "vboxPciFileWrite: error %d\n", ret);
+
+ return ret;
+}
+
+static int vboxPciLinuxDevDetachHostDriver(PVBOXRAWPCIINS pIns)
+{
+ struct pci_dev *pPciDev = NULL;
+ uint8_t uBus = (pIns->HostPciAddress) >> 8;
+ uint8_t uDevFn = (pIns->HostPciAddress) & 0xff;
+ const char* currentDriver;
+ uint16_t uVendor, uDevice;
+ bool fDetach = 0;
+
+ if (!g_VBoxPciGlobals.fPciStubModuleAvail)
+ {
+ printk(KERN_INFO "vboxpci: stub module %s not detected: cannot detach\n",
+ PCI_STUB_MODULE);
+ return VERR_ACCESS_DENIED;
+ }
+
+ pPciDev = PCI_DEV_GET_SLOT(uBus, uDevFn);
+
+ if (!pPciDev)
+ {
+ printk(KERN_INFO "vboxpci: device at %02x:%02x.%d not found\n",
+ uBus, uDevFn>>3, uDevFn&7);
+ return VERR_NOT_FOUND;
+ }
+
+ uVendor = pPciDev->vendor;
+ uDevice = pPciDev->device;
+
+ currentDriver = pPciDev->driver ? pPciDev->driver->name : NULL;
+
+ printk(KERN_DEBUG "vboxpci: detected device: %04x:%04x at %02x:%02x.%d, driver %s\n",
+ uVendor, uDevice, uBus, uDevFn>>3, uDevFn&7,
+ currentDriver ? currentDriver : "<none>");
+
+ fDetach = (currentDriver == NULL || (strcmp(currentDriver, PCI_STUB_MODULE) != 0));
+
+ /* Init previous driver data. */
+ pIns->szPrevDriver[0] = '\0';
+
+ if (fDetach && currentDriver)
+ {
+ /* Dangerous: if device name for some reasons contains slashes - arbitrary file could be written to. */
+ if (strchr(currentDriver, '/') != 0)
+ {
+ printk(KERN_DEBUG "vboxpci: ERROR: %s contains invalid symbols\n", currentDriver);
+ return VERR_ACCESS_DENIED;
+ }
+ /** @todo RTStrCopy not exported. */
+ strncpy(pIns->szPrevDriver, currentDriver, sizeof(pIns->szPrevDriver) - 1);
+ pIns->szPrevDriver[sizeof(pIns->szPrevDriver) - 1] = '\0';
+ }
+
+ PCI_DEV_PUT(pPciDev);
+ pPciDev = NULL;
+
+ if (fDetach)
+ {
+ char* szCmdBuf;
+ char* szFileBuf;
+ struct file* pFile;
+ int iCmdLen;
+ const int cMaxBuf = 128;
+#if RTLNX_VER_MIN(2,6,29)
+ const struct cred *pOldCreds;
+ struct cred *pNewCreds;
+#endif
+
+ /*
+ * Now perform kernel analog of:
+ *
+ * echo -n "10de 040a" > /sys/bus/pci/drivers/pci-stub/new_id
+ * echo -n 0000:03:00.0 > /sys/bus/pci/drivers/nvidia/unbind
+ * echo -n 0000:03:00.0 > /sys/bus/pci/drivers/pci-stub/bind
+ *
+ * We do this way, as this interface is presumingly more stable than
+ * in-kernel ones.
+ */
+ szCmdBuf = kmalloc(cMaxBuf, GFP_KERNEL);
+ szFileBuf = kmalloc(cMaxBuf, GFP_KERNEL);
+ if (!szCmdBuf || !szFileBuf)
+ goto done;
+
+ /* Somewhat ugly hack - override current credentials */
+#if RTLNX_VER_MIN(2,6,29)
+ pNewCreds = prepare_creds();
+ if (!pNewCreds)
+ goto done;
+
+# if RTLNX_VER_MIN(3,5,0)
+ pNewCreds->fsuid = GLOBAL_ROOT_UID;
+# else
+ pNewCreds->fsuid = 0;
+# endif
+ pOldCreds = override_creds(pNewCreds);
+#endif
+
+ RTStrPrintf(szFileBuf, cMaxBuf,
+ "/sys/bus/pci/drivers/%s/new_id",
+ PCI_STUB_MODULE);
+ pFile = vboxPciFileOpen(szFileBuf, O_WRONLY);
+ if (pFile)
+ {
+ iCmdLen = RTStrPrintf(szCmdBuf, cMaxBuf,
+ "%04x %04x",
+ uVendor, uDevice);
+ /* Don't write trailing \0 */
+ vboxPciFileWrite(pFile, 0, szCmdBuf, iCmdLen);
+ vboxPciFileClose(pFile);
+ }
+ else
+ printk(KERN_DEBUG "vboxpci: cannot open %s\n", szFileBuf);
+
+ iCmdLen = RTStrPrintf(szCmdBuf, cMaxBuf,
+ "0000:%02x:%02x.%d",
+ uBus, uDevFn>>3, uDevFn&7);
+
+ /* Unbind if bound to smth */
+ if (pIns->szPrevDriver[0])
+ {
+ RTStrPrintf(szFileBuf, cMaxBuf,
+ "/sys/bus/pci/drivers/%s/unbind",
+ pIns->szPrevDriver);
+ pFile = vboxPciFileOpen(szFileBuf, O_WRONLY);
+ if (pFile)
+ {
+
+ /* Don't write trailing \0 */
+ vboxPciFileWrite(pFile, 0, szCmdBuf, iCmdLen);
+ vboxPciFileClose(pFile);
+ }
+ else
+ printk(KERN_DEBUG "vboxpci: cannot open %s\n", szFileBuf);
+ }
+
+ RTStrPrintf(szFileBuf, cMaxBuf,
+ "/sys/bus/pci/drivers/%s/bind",
+ PCI_STUB_MODULE);
+ pFile = vboxPciFileOpen(szFileBuf, O_WRONLY);
+ if (pFile)
+ {
+ /* Don't write trailing \0 */
+ vboxPciFileWrite(pFile, 0, szCmdBuf, iCmdLen);
+ vboxPciFileClose(pFile);
+ }
+ else
+ printk(KERN_DEBUG "vboxpci: cannot open %s\n", szFileBuf);
+
+#if RTLNX_VER_MIN(2,6,29)
+ revert_creds(pOldCreds);
+ put_cred(pNewCreds);
+#endif
+
+ done:
+ kfree(szCmdBuf);
+ kfree(szFileBuf);
+ }
+
+ return 0;
+}
+
+static int vboxPciLinuxDevReattachHostDriver(PVBOXRAWPCIINS pIns)
+{
+ struct pci_dev *pPciDev = pIns->pPciDev;
+
+ if (!pPciDev)
+ return VINF_SUCCESS;
+
+ if (pIns->szPrevDriver[0])
+ {
+ char* szCmdBuf;
+ char* szFileBuf;
+ struct file* pFile;
+ int iCmdLen;
+ const int cMaxBuf = 128;
+#if RTLNX_VER_MIN(2,6,29)
+ const struct cred *pOldCreds;
+ struct cred *pNewCreds;
+#endif
+ uint8_t uBus = (pIns->HostPciAddress) >> 8;
+ uint8_t uDevFn = (pIns->HostPciAddress) & 0xff;
+
+ vbpci_printk(KERN_DEBUG, pPciDev,
+ "reattaching old host driver %s\n", pIns->szPrevDriver);
+ /*
+ * Now perform kernel analog of:
+ *
+ * echo -n 0000:03:00.0 > /sys/bus/pci/drivers/pci-stub/unbind
+ * echo -n 0000:03:00.0 > /sys/bus/pci/drivers/nvidia/bind
+ */
+ szCmdBuf = kmalloc(cMaxBuf, GFP_KERNEL);
+ szFileBuf = kmalloc(cMaxBuf, GFP_KERNEL);
+
+ if (!szCmdBuf || !szFileBuf)
+ goto done;
+
+ iCmdLen = RTStrPrintf(szCmdBuf, cMaxBuf,
+ "0000:%02x:%02x.%d",
+ uBus, uDevFn>>3, uDevFn&7);
+
+ /* Somewhat ugly hack - override current credentials */
+#if RTLNX_VER_MIN(2,6,29)
+ pNewCreds = prepare_creds();
+ if (!pNewCreds)
+ goto done;
+
+# if RTLNX_VER_MIN(3,5,0)
+ pNewCreds->fsuid = GLOBAL_ROOT_UID;
+# else
+ pNewCreds->fsuid = 0;
+# endif
+ pOldCreds = override_creds(pNewCreds);
+#endif
+ RTStrPrintf(szFileBuf, cMaxBuf,
+ "/sys/bus/pci/drivers/%s/unbind",
+ PCI_STUB_MODULE);
+ pFile = vboxPciFileOpen(szFileBuf, O_WRONLY);
+ if (pFile)
+ {
+
+ /* Don't write trailing \0 */
+ vboxPciFileWrite(pFile, 0, szCmdBuf, iCmdLen);
+ vboxPciFileClose(pFile);
+ }
+ else
+ printk(KERN_DEBUG "vboxpci: cannot open %s\n", szFileBuf);
+
+ RTStrPrintf(szFileBuf, cMaxBuf,
+ "/sys/bus/pci/drivers/%s/bind",
+ pIns->szPrevDriver);
+ pFile = vboxPciFileOpen(szFileBuf, O_WRONLY);
+ if (pFile)
+ {
+
+ /* Don't write trailing \0 */
+ vboxPciFileWrite(pFile, 0, szCmdBuf, iCmdLen);
+ vboxPciFileClose(pFile);
+ pIns->szPrevDriver[0] = '\0';
+ }
+ else
+ printk(KERN_DEBUG "vboxpci: cannot open %s\n", szFileBuf);
+
+#if RTLNX_VER_MIN(2,6,29)
+ revert_creds(pOldCreds);
+ put_cred(pNewCreds);
+#endif
+
+ done:
+ kfree(szCmdBuf);
+ kfree(szFileBuf);
+ }
+
+ return VINF_SUCCESS;
+}
+
+DECLHIDDEN(int) vboxPciOsDevInit(PVBOXRAWPCIINS pIns, uint32_t fFlags)
+{
+ struct pci_dev *pPciDev = NULL;
+ int rc = VINF_SUCCESS;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ if (fFlags & PCIRAWDRIVERRFLAG_DETACH_HOST_DRIVER)
+ {
+ rc = vboxPciLinuxDevDetachHostDriver(pIns);
+ if (RT_FAILURE(rc))
+ {
+ printk(KERN_DEBUG "Cannot detach host driver for device %x: %d\n",
+ pIns->HostPciAddress, rc);
+ }
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ pPciDev = PCI_DEV_GET_SLOT((pIns->HostPciAddress) >> 8,
+ (pIns->HostPciAddress) & 0xff);
+
+ if (RT_LIKELY(pPciDev))
+ {
+ int rcLnx = pci_enable_device(pPciDev);
+
+ if (!rcLnx)
+ {
+ pIns->pPciDev = pPciDev;
+ vbpci_printk(KERN_DEBUG, pPciDev, "%s\n", __func__);
+
+#if RTLNX_VER_MIN(2,6,1)
+ if (pci_enable_msi(pPciDev) == 0)
+ pIns->fMsiUsed = true;
+#endif
+
+ /** @todo
+ * pci_enable_msix(pPciDev, entries, nvec)
+ *
+ * In fact, if device uses interrupts, and cannot be forced to use MSI or MSI-X
+ * we have to refuse using it, as we cannot work with shared PCI interrupts (unless we're lucky
+ * to grab unshared PCI interrupt).
+ */
+ }
+ else
+ rc = RTErrConvertFromErrno(RT_ABS(rcLnx));
+ }
+ else
+ rc = VERR_NOT_FOUND;
+ }
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+}
+
+DECLHIDDEN(int) vboxPciOsDevDeinit(PVBOXRAWPCIINS pIns, uint32_t fFlags)
+{
+ int rc = VINF_SUCCESS;
+ struct pci_dev *pPciDev = pIns->pPciDev;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ vbpci_printk(KERN_DEBUG, pPciDev, "%s\n", __func__);
+
+ if (RT_LIKELY(pPciDev))
+ {
+ int iRegion;
+ for (iRegion = 0; iRegion < 7; ++iRegion)
+ {
+ if (pIns->aRegionR0Mapping[iRegion])
+ {
+ iounmap(pIns->aRegionR0Mapping[iRegion]);
+ pIns->aRegionR0Mapping[iRegion] = 0;
+ pci_release_region(pPciDev, iRegion);
+ }
+ }
+
+ vboxPciLinuxDevUnregisterWithIommu(pIns);
+
+#if RTLNX_VER_MIN(2,6,1)
+ if (pIns->fMsiUsed)
+ pci_disable_msi(pPciDev);
+#endif
+ // pci_disable_msix(pPciDev);
+ pci_disable_device(pPciDev);
+ vboxPciLinuxDevReattachHostDriver(pIns);
+
+ PCI_DEV_PUT(pPciDev);
+ pIns->pPciDev = NULL;
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+}
+
+DECLHIDDEN(int) vboxPciOsDevDestroy(PVBOXRAWPCIINS pIns)
+{
+ return VINF_SUCCESS;
+}
+
+DECLHIDDEN(int) vboxPciOsDevGetRegionInfo(PVBOXRAWPCIINS pIns,
+ int32_t iRegion,
+ RTHCPHYS *pRegionStart,
+ uint64_t *pu64RegionSize,
+ bool *pfPresent,
+ uint32_t *pfFlags)
+{
+ int rc = VINF_SUCCESS;
+ struct pci_dev *pPciDev = pIns->pPciDev;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ if (RT_LIKELY(pPciDev))
+ {
+ int fFlags = pci_resource_flags(pPciDev, iRegion);
+
+ if ( ((fFlags & (IORESOURCE_MEM | IORESOURCE_IO)) == 0)
+ || ((fFlags & IORESOURCE_DISABLED) != 0))
+ {
+ *pfPresent = false;
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ uint32_t fResFlags = 0;
+ *pfPresent = true;
+
+ if (fFlags & IORESOURCE_MEM)
+ fResFlags |= PCIRAW_ADDRESS_SPACE_MEM;
+
+ if (fFlags & IORESOURCE_IO)
+ fResFlags |= PCIRAW_ADDRESS_SPACE_IO;
+
+#ifdef IORESOURCE_MEM_64
+ if (fFlags & IORESOURCE_MEM_64)
+ fResFlags |= PCIRAW_ADDRESS_SPACE_BAR64;
+#endif
+
+ if (fFlags & IORESOURCE_PREFETCH)
+ fResFlags |= PCIRAW_ADDRESS_SPACE_MEM_PREFETCH;
+
+ *pfFlags = fResFlags;
+ *pRegionStart = pci_resource_start(pPciDev, iRegion);
+ *pu64RegionSize = pci_resource_len (pPciDev, iRegion);
+
+ vbpci_printk(KERN_DEBUG, pPciDev,
+ "region %d: %s %llx+%lld\n",
+ iRegion, (fFlags & IORESOURCE_MEM) ? "mmio" : "pio",
+ *pRegionStart, *pu64RegionSize);
+ }
+ }
+ else
+ {
+ *pfPresent = false;
+ rc = VERR_INVALID_PARAMETER;
+ }
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+}
+
+DECLHIDDEN(int) vboxPciOsDevMapRegion(PVBOXRAWPCIINS pIns,
+ int32_t iRegion,
+ RTHCPHYS RegionStart,
+ uint64_t u64RegionSize,
+ uint32_t fFlags,
+ RTR0PTR *pRegionBase)
+{
+ int rc = VINF_SUCCESS;
+ struct pci_dev *pPciDev = pIns->pPciDev;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ if (!pPciDev || iRegion < 0 || iRegion > 0)
+ {
+ if (pPciDev)
+ vbpci_printk(KERN_DEBUG, pPciDev, "invalid region %d\n", iRegion);
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VERR_INVALID_PARAMETER;
+ }
+
+ vbpci_printk(KERN_DEBUG, pPciDev, "reg=%d start=%llx size=%lld\n",
+ iRegion, RegionStart, u64RegionSize);
+
+ if ( (pci_resource_flags(pPciDev, iRegion) & IORESOURCE_IO)
+ || RegionStart != pci_resource_start(pPciDev, iRegion)
+ || u64RegionSize != pci_resource_len(pPciDev, iRegion))
+ {
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VERR_INVALID_PARAMETER;
+ }
+
+ /*
+ * XXX: Current code never calls unmap. To avoid leaking mappings
+ * only request and map resources once.
+ */
+ if (!pIns->aRegionR0Mapping[iRegion])
+ {
+ int rcLnx;
+ *pRegionBase = pIns->aRegionR0Mapping[iRegion];
+
+ rcLnx = pci_request_region(pPciDev, iRegion, "vboxpci");
+ if (!rcLnx)
+ {
+#if RTLNX_VER_MIN(2,6,25)
+ /*
+ * ioremap() defaults to no caching since the 2.6 kernels.
+ * ioremap_nocache() has been removed finally in 5.6-rc1.
+ */
+ RTR0PTR R0PtrMapping = ioremap(pci_resource_start(pPciDev, iRegion),
+ pci_resource_len(pPciDev, iRegion));
+#else /* KERNEL_VERSION < 2.6.25 */
+ /* For now no caching, try to optimize later. */
+ RTR0PTR R0PtrMapping = ioremap_nocache(pci_resource_start(pPciDev, iRegion),
+ pci_resource_len(pPciDev, iRegion));
+#endif /* KERNEL_VERSION < 2.6.25 */
+ if (R0PtrMapping != NIL_RTR0PTR)
+ pIns->aRegionR0Mapping[iRegion] = R0PtrMapping;
+ else
+ {
+#if RTLNX_VER_MIN(2,6,25)
+ vbpci_printk(KERN_DEBUG, pPciDev, "ioremap() failed\n");
+#else
+ vbpci_printk(KERN_DEBUG, pPciDev, "ioremap_nocache() failed\n");
+#endif
+ pci_release_region(pPciDev, iRegion);
+ rc = VERR_MAP_FAILED;
+ }
+ }
+ else
+ rc = VERR_RESOURCE_BUSY;
+ }
+
+ if (RT_SUCCESS(rc))
+ *pRegionBase = pIns->aRegionR0Mapping[iRegion];
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+}
+
+DECLHIDDEN(int) vboxPciOsDevUnmapRegion(PVBOXRAWPCIINS pIns,
+ int32_t iRegion,
+ RTHCPHYS RegionStart,
+ uint64_t u64RegionSize,
+ RTR0PTR RegionBase)
+{
+ /* XXX: Current code never calls unmap. */
+ return VERR_NOT_IMPLEMENTED;
+}
+
+DECLHIDDEN(int) vboxPciOsDevPciCfgWrite(PVBOXRAWPCIINS pIns, uint32_t Register, PCIRAWMEMLOC *pValue)
+{
+ struct pci_dev *pPciDev = pIns->pPciDev;
+ int rc = VINF_SUCCESS;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ if (RT_LIKELY(pPciDev))
+ {
+ switch (pValue->cb)
+ {
+ case 1:
+ pci_write_config_byte(pPciDev, Register, pValue->u.u8);
+ break;
+ case 2:
+ pci_write_config_word(pPciDev, Register, pValue->u.u16);
+ break;
+ case 4:
+ pci_write_config_dword(pPciDev, Register, pValue->u.u32);
+ break;
+ }
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+}
+
+DECLHIDDEN(int) vboxPciOsDevPciCfgRead(PVBOXRAWPCIINS pIns, uint32_t Register, PCIRAWMEMLOC *pValue)
+{
+ struct pci_dev *pPciDev = pIns->pPciDev;
+ int rc = VINF_SUCCESS;
+
+ if (RT_LIKELY(pPciDev))
+ {
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ switch (pValue->cb)
+ {
+ case 1:
+ pci_read_config_byte(pPciDev, Register, &pValue->u.u8);
+ break;
+ case 2:
+ pci_read_config_word(pPciDev, Register, &pValue->u.u16);
+ break;
+ case 4:
+ pci_read_config_dword(pPciDev, Register, &pValue->u.u32);
+ break;
+ }
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+
+ return rc;
+}
+
+/**
+ * Interrupt service routine.
+ *
+ * @returns In 2.6 we indicate whether we've handled the IRQ or not.
+ *
+ * @param iIrq The IRQ number.
+ * @param pvDevId The device ID, a pointer to PVBOXRAWPCIINS.
+ * @param pRegs Register set. Removed in 2.6.19.
+ */
+#if RTLNX_VER_MIN(2,6,19) && !defined(DOXYGEN_RUNNING)
+static irqreturn_t vboxPciOsIrqHandler(int iIrq, void *pvDevId)
+#else
+static irqreturn_t vboxPciOsIrqHandler(int iIrq, void *pvDevId, struct pt_regs *pRegs)
+#endif
+{
+ PVBOXRAWPCIINS pIns = (PVBOXRAWPCIINS)pvDevId;
+ bool fTaken = true;
+
+ if (pIns && pIns->IrqHandler.pfnIrqHandler)
+ fTaken = pIns->IrqHandler.pfnIrqHandler(pIns->IrqHandler.pIrqContext, iIrq);
+#ifndef VBOX_WITH_SHARED_PCI_INTERRUPTS
+ /* If we don't allow interrupts sharing, we consider all interrupts as non-shared, thus targetted to us. */
+ fTaken = true;
+#endif
+
+ return fTaken;
+}
+
+DECLHIDDEN(int) vboxPciOsDevRegisterIrqHandler(PVBOXRAWPCIINS pIns, PFNRAWPCIISR pfnHandler, void* pIrqContext, int32_t *piHostIrq)
+{
+ int rc;
+ int32_t iIrq = pIns->pPciDev->irq;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ if (iIrq == 0)
+ {
+ vbpci_printk(KERN_NOTICE, pIns->pPciDev, "no irq assigned\n");
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VERR_INVALID_PARAMETER;
+ }
+
+ rc = request_irq(iIrq,
+ vboxPciOsIrqHandler,
+#ifdef VBOX_WITH_SHARED_PCI_INTERRUPTS
+ /* Allow interrupts sharing. */
+# if RTLNX_VER_MIN(2,6,20)
+ IRQF_SHARED,
+# else
+ SA_SHIRQ,
+# endif
+
+#else
+
+ /* We don't allow interrupts sharing */
+ /* XXX overhaul */
+# if RTLNX_VER_MIN(2,6,20) && RTLNX_VER_MAX(4,1,0)
+ IRQF_DISABLED, /* keep irqs disabled when calling the action handler */
+# else
+ 0,
+# endif
+#endif
+ DRIVER_NAME,
+ pIns);
+ if (rc)
+ {
+ vbpci_printk(KERN_DEBUG, pIns->pPciDev,
+ "could not request irq %d, error %d\n", iIrq, rc);
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VERR_RESOURCE_BUSY;
+ }
+
+ vbpci_printk(KERN_DEBUG, pIns->pPciDev, "got irq %d\n", iIrq);
+ *piHostIrq = iIrq;
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+}
+
+DECLHIDDEN(int) vboxPciOsDevUnregisterIrqHandler(PVBOXRAWPCIINS pIns, int32_t iHostIrq)
+{
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ vbpci_printk(KERN_DEBUG, pIns->pPciDev, "freeing irq %d\n", iHostIrq);
+ free_irq(iHostIrq, pIns);
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return VINF_SUCCESS;
+}
+
+DECLHIDDEN(int) vboxPciOsDevPowerStateChange(PVBOXRAWPCIINS pIns, PCIRAWPOWERSTATE aState)
+{
+ int rc;
+
+ switch (aState)
+ {
+ case PCIRAW_POWER_ON:
+ vbpci_printk(KERN_DEBUG, pIns->pPciDev, "PCIRAW_POWER_ON\n");
+ /* Reset device, just in case. */
+ vboxPciLinuxDevReset(pIns);
+ /* register us with IOMMU */
+ rc = vboxPciLinuxDevRegisterWithIommu(pIns);
+ break;
+ case PCIRAW_POWER_RESET:
+ vbpci_printk(KERN_DEBUG, pIns->pPciDev, "PCIRAW_POWER_RESET\n");
+ rc = vboxPciLinuxDevReset(pIns);
+ break;
+ case PCIRAW_POWER_OFF:
+ vbpci_printk(KERN_DEBUG, pIns->pPciDev, "PCIRAW_POWER_OFF\n");
+ /* unregister us from IOMMU */
+ rc = vboxPciLinuxDevUnregisterWithIommu(pIns);
+ break;
+ case PCIRAW_POWER_SUSPEND:
+ vbpci_printk(KERN_DEBUG, pIns->pPciDev, "PCIRAW_POWER_SUSPEND\n");
+ rc = VINF_SUCCESS;
+ /// @todo what do we do here?
+ break;
+ case PCIRAW_POWER_RESUME:
+ vbpci_printk(KERN_DEBUG, pIns->pPciDev, "PCIRAW_POWER_RESUME\n");
+ rc = VINF_SUCCESS;
+ /// @todo what do we do here?
+ break;
+ default:
+ vbpci_printk(KERN_DEBUG, pIns->pPciDev, "unknown power state %u\n", aState);
+ /* to make compiler happy */
+ rc = VERR_NOT_SUPPORTED;
+ break;
+ }
+
+ return rc;
+}
+
+
+#ifdef VBOX_WITH_IOMMU
+/** Callback for FNRAWPCICONTIGPHYSMEMINFO. */
+static DECLCALLBACK(int) vboxPciOsContigMemInfo(PRAWPCIPERVM pVmCtx, RTHCPHYS HostStart, RTGCPHYS GuestStart,
+ uint64_t cMemSize, PCIRAWMEMINFOACTION Action)
+{
+ struct iommu_domain* domain = ((PVBOXRAWPCIDRVVM)(pVmCtx->pDriverData))->pIommuDomain;
+ int rc = VINF_SUCCESS;
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ switch (Action)
+ {
+ case PCIRAW_MEMINFO_MAP:
+ {
+ int flags, r;
+
+ if (iommu_iova_to_phys(domain, GuestStart))
+ break;
+
+ flags = IOMMU_READ | IOMMU_WRITE;
+ /** @todo flags |= IOMMU_CACHE; */
+
+ r = iommu_map(domain, GuestStart, HostStart, get_order(cMemSize), flags);
+ if (r)
+ {
+ printk(KERN_ERR "vboxPciOsContigMemInfo:"
+ "iommu failed to map pfn=%llx\n", HostStart);
+ rc = VERR_GENERAL_FAILURE;
+ break;
+ }
+ rc = VINF_SUCCESS;
+ break;
+ }
+ case PCIRAW_MEMINFO_UNMAP:
+ {
+ int order;
+ order = iommu_unmap(domain, GuestStart, get_order(cMemSize));
+ NOREF(order);
+ break;
+ }
+
+ default:
+ printk(KERN_DEBUG "Unsupported action: %d\n", (int)Action);
+ rc = VERR_NOT_SUPPORTED;
+ break;
+ }
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+ return rc;
+}
+#endif
+
+DECLHIDDEN(int) vboxPciOsInitVm(PVBOXRAWPCIDRVVM pThis, PVM pVM, PRAWPCIPERVM pVmData)
+{
+ int rc = VINF_SUCCESS;
+
+#ifdef VBOX_WITH_IOMMU
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ if (IOMMU_PRESENT())
+ {
+ pThis->pIommuDomain = IOMMU_DOMAIN_ALLOC();
+ if (!pThis->pIommuDomain)
+ {
+ vbpci_printk(KERN_DEBUG, NULL, "cannot allocate IOMMU domain\n");
+ rc = VERR_NO_MEMORY;
+ }
+ else
+ {
+ pVmData->pfnContigMemInfo = vboxPciOsContigMemInfo;
+
+ vbpci_printk(KERN_DEBUG, NULL, "created IOMMU domain %p\n",
+ pThis->pIommuDomain);
+ }
+ }
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+#endif
+ return rc;
+}
+
+DECLHIDDEN(void) vboxPciOsDeinitVm(PVBOXRAWPCIDRVVM pThis, PVM pVM)
+{
+#ifdef VBOX_WITH_IOMMU
+ IPRT_LINUX_SAVE_EFL_AC();
+
+ if (pThis->pIommuDomain)
+ {
+ vbpci_printk(KERN_DEBUG, NULL, "freeing IOMMU domain %p\n",
+ pThis->pIommuDomain);
+ iommu_domain_free(pThis->pIommuDomain);
+ pThis->pIommuDomain = NULL;
+ }
+
+ IPRT_LINUX_RESTORE_EFL_AC();
+#endif
+}
diff --git a/src/VBox/HostDrivers/VBoxPci/linux/files_vboxpci b/src/VBox/HostDrivers/VBoxPci/linux/files_vboxpci
new file mode 100755
index 00000000..70e15ed2
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxPci/linux/files_vboxpci
@@ -0,0 +1,111 @@
+#!/bin/sh
+# $Id: files_vboxpci $
+## @file
+# Shared file between Makefile.kmk and export_modules.sh.
+#
+
+#
+# Copyright (C) 2011-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>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+VBOX_VBOXPCI_SOURCES=" \
+ ${PATH_ROOT}/include/iprt/alloc.h=>include/iprt/alloc.h \
+ ${PATH_ROOT}/include/iprt/alloca.h=>include/iprt/alloca.h \
+ ${PATH_ROOT}/include/iprt/asm.h=>include/iprt/asm.h \
+ ${PATH_ROOT}/include/iprt/asm-amd64-x86.h=>include/iprt/asm-amd64-x86.h \
+ ${PATH_ROOT}/include/iprt/asm-math.h=>include/iprt/asm-math.h \
+ ${PATH_ROOT}/include/iprt/assert.h=>include/iprt/assert.h \
+ ${PATH_ROOT}/include/iprt/assertcompile.h=>include/iprt/assertcompile.h \
+ ${PATH_ROOT}/include/iprt/avl.h=>include/iprt/avl.h \
+ ${PATH_ROOT}/include/iprt/cdefs.h=>include/iprt/cdefs.h \
+ ${PATH_ROOT}/include/iprt/cpuset.h=>include/iprt/cpuset.h \
+ ${PATH_ROOT}/include/iprt/ctype.h=>include/iprt/ctype.h \
+ ${PATH_ROOT}/include/iprt/err.h=>include/iprt/err.h \
+ ${PATH_ROOT}/include/iprt/errcore.h=>include/iprt/errcore.h \
+ ${PATH_ROOT}/include/iprt/heap.h=>include/iprt/heap.h \
+ ${PATH_ROOT}/include/iprt/initterm.h=>include/iprt/initterm.h \
+ ${PATH_ROOT}/include/iprt/latin1.h=>include/iprt/latin1.h \
+ ${PATH_ROOT}/include/iprt/log.h=>include/iprt/log.h \
+ ${PATH_ROOT}/include/iprt/mangling.h=>include/iprt/mangling.h \
+ ${PATH_ROOT}/include/iprt/mem.h=>include/iprt/mem.h \
+ ${PATH_ROOT}/include/iprt/memobj.h=>include/iprt/memobj.h \
+ ${PATH_ROOT}/include/iprt/mp.h=>include/iprt/mp.h \
+ ${PATH_ROOT}/include/iprt/param.h=>include/iprt/param.h \
+ ${PATH_ROOT}/include/iprt/power.h=>include/iprt/power.h \
+ ${PATH_ROOT}/include/iprt/process.h=>include/iprt/process.h \
+ ${PATH_ROOT}/include/iprt/semaphore.h=>include/iprt/semaphore.h \
+ ${PATH_ROOT}/include/iprt/spinlock.h=>include/iprt/spinlock.h \
+ ${PATH_ROOT}/include/iprt/stdarg.h=>include/iprt/stdarg.h \
+ ${PATH_ROOT}/include/iprt/stdint.h=>include/iprt/stdint.h \
+ ${PATH_ROOT}/include/iprt/string.h=>include/iprt/string.h \
+ ${PATH_ROOT}/include/iprt/thread.h=>include/iprt/thread.h \
+ ${PATH_ROOT}/include/iprt/time.h=>include/iprt/time.h \
+ ${PATH_ROOT}/include/iprt/timer.h=>include/iprt/timer.h \
+ ${PATH_ROOT}/include/iprt/types.h=>include/iprt/types.h \
+ ${PATH_ROOT}/include/iprt/uint64.h=>include/iprt/uint64.h \
+ ${PATH_ROOT}/include/iprt/uni.h=>include/iprt/uni.h \
+ ${PATH_ROOT}/include/iprt/utf16.h=>include/iprt/utf16.h \
+ ${PATH_ROOT}/include/iprt/uuid.h=>include/iprt/uuid.h \
+ ${PATH_ROOT}/include/iprt/x86-helpers.h=>include/iprt/x86-helpers.h \
+ ${PATH_ROOT}/include/iprt/linux/version.h=>include/iprt/linux/version.h \
+ ${PATH_ROOT}/include/iprt/nocrt/limits.h=>include/iprt/nocrt/limits.h \
+ ${PATH_ROOT}/include/VBox/cdefs.h=>include/VBox/cdefs.h \
+ ${PATH_ROOT}/include/VBox/err.h=>include/VBox/err.h \
+ ${PATH_ROOT}/include/VBox/log.h=>include/VBox/log.h \
+ ${PATH_ROOT}/include/VBox/rawpci.h=>include/VBox/rawpci.h \
+ ${PATH_ROOT}/include/VBox/vmm/stam.h=>include/VBox/vmm/stam.h \
+ ${PATH_ROOT}/include/VBox/param.h=>include/VBox/param.h \
+ ${PATH_ROOT}/include/VBox/sup.h=>include/VBox/sup.h \
+ ${PATH_ROOT}/include/VBox/types.h=>include/VBox/types.h \
+ ${PATH_ROOT}/include/VBox/version.h=>include/VBox/version.h \
+ ${PATH_ROOT}/include/VBox/SUPDrvMangling.h=>include/VBox/SUPDrvMangling.h \
+ ${PATH_ROOT}/src/VBox/HostDrivers/VBoxPci/linux/VBoxPci-linux.c=>linux/VBoxPci-linux.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/VBoxPci/VBoxPci.c=>VBoxPci.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/VBoxPci/VBoxPciInternal.h=>VBoxPciInternal.h \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/SUPDrvIDC.h=>SUPDrvIDC.h \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/SUPR0IdcClient.c=>SUPR0IdcClient.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/SUPR0IdcClientComponent.c=>SUPR0IdcClientComponent.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/SUPR0IdcClientInternal.h=>SUPR0IdcClientInternal.h \
+ ${PATH_ROOT}/src/VBox/HostDrivers/Support/linux/SUPR0IdcClient-linux.c=>linux/SUPR0IdcClient-linux.c \
+ ${PATH_ROOT}/src/VBox/Installer/linux/Makefile-footer.gmk=>Makefile-footer.gmk \
+ ${PATH_ROOT}/src/VBox/Installer/linux/Makefile-header.gmk=>Makefile-header.gmk \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/divdi3.c=>math/gcc/divdi3.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/moddi3.c=>math/gcc/moddi3.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/qdivrem.c=>math/gcc/qdivrem.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/quad.h=>math/gcc/quad.h \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/udivdi3.c=>math/gcc/udivdi3.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/udivmoddi4.c=>math/gcc/udivmoddi4.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/umoddi3.c=>math/gcc/umoddi3.c \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h=>r0drv/linux/the-linux-kernel.h \
+ ${PATH_OUT}/version-generated.h=>version-generated.h \
+ ${PATH_OUT}/revision-generated.h=>revision-generated.h \
+ ${PATH_OUT}/product-generated.h=>product-generated.h \
+"
+