From f8fe689a81f906d1b91bb3220acde2a4ecb14c5b Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 6 May 2024 05:01:46 +0200 Subject: Adding upstream version 6.0.4-dfsg. Signed-off-by: Daniel Baumann --- src/VBox/Devices/Bus/DevPciMerge1.cpp.h | 240 ++++++++++++++++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 src/VBox/Devices/Bus/DevPciMerge1.cpp.h (limited to 'src/VBox/Devices/Bus/DevPciMerge1.cpp.h') diff --git a/src/VBox/Devices/Bus/DevPciMerge1.cpp.h b/src/VBox/Devices/Bus/DevPciMerge1.cpp.h new file mode 100644 index 00000000..ace0ab5c --- /dev/null +++ b/src/VBox/Devices/Bus/DevPciMerge1.cpp.h @@ -0,0 +1,240 @@ +/* $Id: DevPciMerge1.cpp.h $ */ +/** @file + * DevPci - Early attempt at common code for DevPci and DevPciIch9. + * + * @note Don't add more, add code to DevPciIch9.cpp instead. + * @note We'll keep this file like this for a little while longer + * because of 5.1. + */ + +/* + * Copyright (C) 2004-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + + +/** + * Search for a completely unused device entry (all 8 functions are unused). + * + * @returns VBox status code. + * @param pBus The bus to register with. + * @remarks Caller enters the PDM critical section. + */ +static uint8_t pciR3MergedFindUnusedDeviceNo(PDEVPCIBUS pBus) +{ + for (uint8_t uPciDevNo = pBus->iDevSearch >> VBOX_PCI_DEVFN_DEV_SHIFT; uPciDevNo < VBOX_PCI_MAX_DEVICES; uPciDevNo++) + if ( !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 0)] + && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 1)] + && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 2)] + && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 3)] + && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 4)] + && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 5)] + && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 6)] + && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 7)]) + return uPciDevNo; + return UINT8_MAX; +} + + + +/** + * Registers the device with the specified PCI bus. + * + * This is shared between the pci bus and pci bridge code. + * + * @returns VBox status code. + * @param pBus The bus to register with. + * @param pPciDev The PCI device structure. + * @param fFlags Reserved for future use, PDMPCIDEVREG_F_MBZ. + * @param uPciDevNo PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, or a specific + * device number (0-31). + * @param uPciFunNo PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, or a specific + * function number (0-7). + * @param pszName Device name (static but not unique). + * @param pfnConfigRead The default config read method. + * @param pfnConfigWrite The default config read method. + * + * @remarks Caller enters the PDM critical section. + */ +static int pciR3MergedRegisterDeviceOnBus(PDEVPCIBUS pBus, PPDMPCIDEV pPciDev, uint32_t fFlags, + uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName, + PFNPCICONFIGREAD pfnConfigRead, PFNPCICONFIGWRITE pfnConfigWrite) +{ + /* + * Validate input. + */ + AssertPtrReturn(pszName, VERR_INVALID_POINTER); + AssertPtrReturn(pPciDev, VERR_INVALID_POINTER); + AssertReturn(!(fFlags & ~PDMPCIDEVREG_F_VALID_MASK), VERR_INVALID_FLAGS); + AssertReturn(uPciDevNo < VBOX_PCI_MAX_DEVICES || uPciDevNo == PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, VERR_INVALID_PARAMETER); + AssertReturn(uPciFunNo < VBOX_PCI_MAX_FUNCTIONS || uPciFunNo == PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, VERR_INVALID_PARAMETER); + + /* + * Assign device & function numbers. + */ + + /* Work the optional assignment flag. */ + if (fFlags & PDMPCIDEVREG_F_NOT_MANDATORY_NO) + { + AssertLogRelMsgReturn(uPciDevNo < VBOX_PCI_MAX_DEVICES && uPciFunNo < VBOX_PCI_MAX_FUNCTIONS, + ("PDMPCIDEVREG_F_NOT_MANDATORY_NO not implemented for #Dev=%#x / #Fun=%#x\n", uPciDevNo, uPciFunNo), + VERR_NOT_IMPLEMENTED); + if (pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)]) + { + uPciDevNo = PDMPCIDEVREG_DEV_NO_FIRST_UNUSED; + uPciFunNo = PDMPCIDEVREG_FUN_NO_FIRST_UNUSED; + } + } + + if (uPciDevNo == PDMPCIDEVREG_DEV_NO_FIRST_UNUSED) + { + /* Just find the next unused device number and we're good. */ + uPciDevNo = pciR3MergedFindUnusedDeviceNo(pBus); + AssertLogRelMsgReturn(uPciDevNo < VBOX_PCI_MAX_DEVICES, ("Couldn't find a free spot!\n"), VERR_PDM_TOO_PCI_MANY_DEVICES); + if (uPciFunNo == PDMPCIDEVREG_FUN_NO_FIRST_UNUSED) + uPciFunNo = 0; + } + else + { + /* + * Direct assignment of device number can be more complicated. + */ + PPDMPCIDEV pClash; + if (uPciFunNo != PDMPCIDEVREG_FUN_NO_FIRST_UNUSED) + { + /* In the case of a specified function, we only relocate an existing + device if it belongs to a different device instance. Reasoning is + that the device should figure out it's own function assignments. + Note! We could make this more flexible by relocating functions assigned + via PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, but it can wait till it's needed. */ + pClash = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)]; + if (!pClash) + { /* likely */ } + else if (pClash->Int.s.pDevInsR3 == pPciDev->Int.s.pDevInsR3) + AssertLogRelMsgFailedReturn(("PCI Configuration conflict at %u.%u: %s vs %s (same pDevIns)!\n", + uPciDevNo, uPciFunNo, pClash->pszNameR3, pszName), + VERR_PDM_TOO_PCI_MANY_DEVICES); + else if (!pClash->Int.s.fReassignableDevNo) + AssertLogRelMsgFailedReturn(("PCI Configuration conflict at %u.%u: %s vs %s (different pDevIns)!\n", + uPciDevNo, uPciFunNo, pClash->pszNameR3, pszName), + VERR_PDM_TOO_PCI_MANY_DEVICES); + } + else + { + /* First unused function slot. Again, we only relocate the whole + thing if all the device instance differs, because we otherwise + reason that a device should manage its own functions correctly. */ + unsigned cSameDevInses = 0; + for (uPciFunNo = 0, pClash = NULL; uPciFunNo < VBOX_PCI_MAX_FUNCTIONS; uPciFunNo++) + { + pClash = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)]; + if (!pClash) + break; + cSameDevInses += pClash->Int.s.pDevInsR3 == pPciDev->Int.s.pDevInsR3; + } + if (!pClash) + Assert(uPciFunNo < VBOX_PCI_MAX_FUNCTIONS); + else + AssertLogRelMsgReturn(cSameDevInses == 0, + ("PCI Configuration conflict at %u.* appending %s (%u of %u pDevIns matches)!\n", + uPciDevNo, pszName, cSameDevInses, VBOX_PCI_MAX_FUNCTIONS), + VERR_PDM_TOO_PCI_MANY_DEVICES); + } + if (pClash) + { + /* + * Try relocate the existing device. + */ + /* Check that all functions can be moved. */ + for (uint8_t uMoveFun = 0; uMoveFun < VBOX_PCI_MAX_FUNCTIONS; uMoveFun++) + { + PPDMPCIDEV pMovePciDev = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uMoveFun)]; + AssertLogRelMsgReturn(!pMovePciDev || pMovePciDev->Int.s.fReassignableDevNo, + ("PCI Configuration conflict at %u.%u: %s vs %s\n", + uPciDevNo, uMoveFun, pMovePciDev->pszNameR3, pszName), + VERR_PDM_TOO_PCI_MANY_DEVICES); + } + + /* Find a free device number to move it to. */ + uint8_t uMoveToDevNo = pciR3MergedFindUnusedDeviceNo(pBus); + Assert(uMoveToDevNo != uPciFunNo); + AssertLogRelMsgReturn(uMoveToDevNo < VBOX_PCI_MAX_DEVICES, + ("No space to relocate device at %u so '%s' can be placed there instead!\n", uPciFunNo, pszName), + VERR_PDM_TOO_PCI_MANY_DEVICES); + + /* Execute the move. */ + for (uint8_t uMoveFun = 0; uMoveFun < VBOX_PCI_MAX_FUNCTIONS; uMoveFun++) + { + PPDMPCIDEV pMovePciDev = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uMoveFun)]; + if (pMovePciDev) + { + Log(("PCI: Relocating '%s' from %u.%u to %u.%u.\n", pMovePciDev->pszNameR3, uPciDevNo, uMoveFun, uMoveToDevNo, uMoveFun)); + pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uMoveFun)] = NULL; + pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uMoveToDevNo, uMoveFun)] = pMovePciDev; + pMovePciDev->uDevFn = VBOX_PCI_DEVFN_MAKE(uMoveToDevNo, uMoveFun); + } + } + } + } + + /* + * Now, initialize the rest of the PCI device structure. + */ + Assert(!pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)]); + pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)] = pPciDev; + + pPciDev->uDevFn = VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo); + pPciDev->Int.s.pBusR3 = pBus; + pPciDev->Int.s.pBusR0 = MMHyperR3ToR0(PDMDevHlpGetVM(pBus->CTX_SUFF(pDevIns)), pBus); + pPciDev->Int.s.pBusRC = MMHyperR3ToRC(PDMDevHlpGetVM(pBus->CTX_SUFF(pDevIns)), pBus); + pPciDev->Int.s.pfnConfigRead = pfnConfigRead; + pPciDev->Int.s.pfnConfigWrite = pfnConfigWrite; + + /* Remember and mark bridges. */ + if (fFlags & PDMPCIDEVREG_F_PCI_BRIDGE) + { + AssertLogRelMsgReturn(pBus->cBridges < RT_ELEMENTS(pBus->apDevices), + ("Number of bridges exceeds the number of possible devices on the bus\n"), + VERR_INTERNAL_ERROR_3); + pBus->papBridgesR3[pBus->cBridges++] = pPciDev; + pciDevSetPci2PciBridge(pPciDev); + } + + Log(("PCI: Registered device %d function %d (%#x) '%s'.\n", + uPciDevNo, uPciFunNo, UINT32_C(0x80000000) | (pPciDev->uDevFn << 8), pszName)); + + return VINF_SUCCESS; +} + + +/** + * @interface_method_impl{PDMPCIBUSREG,pfnRegisterR3} + */ +static DECLCALLBACK(int) pciR3MergedRegister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags, + uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName) +{ + PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS); + AssertCompileMemberOffset(DEVPCIROOT, PciBus, 0); + return pciR3MergedRegisterDeviceOnBus(pBus, pPciDev, fFlags, uPciDevNo, uPciFunNo, pszName, + devpciR3CommonDefaultConfigRead, devpciR3CommonDefaultConfigWrite); +} + + +/** + * @interface_method_impl{PDMPCIBUSREG,pfnRegisterR3} + */ +static DECLCALLBACK(int) pcibridgeR3MergedRegisterDevice(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags, + uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName) +{ + PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS); + return pciR3MergedRegisterDeviceOnBus(pBus, pPciDev, fFlags, uPciDevNo, uPciFunNo, pszName, + devpciR3CommonDefaultConfigRead, devpciR3CommonDefaultConfigWrite); +} + -- cgit v1.2.3