VBoxPci.c revision 1fff175c9a0fea173ee52a209224dc6ecbd39572
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync/* $Id $ */
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync/** @file
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * VBoxPci - PCI card passthrough support (Host), Common Code.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync */
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync
c7814cf6e1240a519cbec0441e033d0e2470ed00vboxsync/*
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * Copyright (C) 2011 Oracle Corporation
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync *
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * available from http://www.virtualbox.org. This file is free software;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * you can redistribute it and/or modify it under the terms of the GNU
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * General Public License (GPL) as published by the Free Software
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync */
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync/** @page pg_rawpci VBoxPci - host PCI support
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync *
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * This is a kernel module that works as host proxy between guest and
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * PCI hardware.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync *
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync */
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync#define LOG_GROUP LOG_GROUP_DEV_PCI_RAW
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync#include <VBox/log.h>
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync#include <VBox/err.h>
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync#include <VBox/sup.h>
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync#include <VBox/version.h>
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync#include <iprt/string.h>
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync#include <iprt/assert.h>
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsync#include <iprt/spinlock.h>
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync#include <iprt/uuid.h>
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync#include <iprt/asm.h>
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync#include <iprt/mem.h>
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync#include "VBoxPciInternal.h"
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync#define DEVPORT_2_VBOXRAWPCIINS(pPort) \
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync ( (PVBOXRAWPCIINS)((uint8_t *)pPort - RT_OFFSETOF(VBOXRAWPCIINS, DevPort)) )
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync/**
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * Implements the SUPDRV component factor interface query method.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync *
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * @returns Pointer to an interface. NULL if not supported.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync *
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * @param pSupDrvFactory Pointer to the component factory registration structure.
5c1381fc884d30a749517579368ff6cb4b43e809vboxsync * @param pSession The session - unused.
5c1381fc884d30a749517579368ff6cb4b43e809vboxsync * @param pszInterfaceUuid The factory interface id.
5c1381fc884d30a749517579368ff6cb4b43e809vboxsync */
1df297ea8319f3f3afddb73e6ea2fd9c7f0e5eb4vboxsyncstatic DECLCALLBACK(void *) vboxPciQueryFactoryInterface(PCSUPDRVFACTORY pSupDrvFactory, PSUPDRVSESSION pSession, const char *pszInterfaceUuid)
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsync{
5c1381fc884d30a749517579368ff6cb4b43e809vboxsync PVBOXRAWPCIGLOBALS pGlobals = (PVBOXRAWPCIGLOBALS)((uint8_t *)pSupDrvFactory - RT_OFFSETOF(VBOXRAWPCIGLOBALS, SupDrvFactory));
5c1381fc884d30a749517579368ff6cb4b43e809vboxsync
5c1381fc884d30a749517579368ff6cb4b43e809vboxsync /*
5c1381fc884d30a749517579368ff6cb4b43e809vboxsync * Convert the UUID strings and compare them.
5c1381fc884d30a749517579368ff6cb4b43e809vboxsync */
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsync RTUUID UuidReq;
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsync int rc = RTUuidFromStr(&UuidReq, pszInterfaceUuid);
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsync if (RT_SUCCESS(rc))
1df297ea8319f3f3afddb73e6ea2fd9c7f0e5eb4vboxsync {
2a560b28131ee7efa5b73a9e9cbfdb08eae28624vboxsync if (!RTUuidCompareStr(&UuidReq, RAWPCIFACTORY_UUID_STR))
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsync {
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsync ASMAtomicIncS32(&pGlobals->cFactoryRefs);
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsync return &pGlobals->RawPciFactory;
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsync }
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsync }
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsync else
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsync Log(("VBoxRawPci: rc=%Rrc, uuid=%s\n", rc, pszInterfaceUuid));
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsync
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsync return NULL;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync}
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsync
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsync/**
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsync * @copydoc RAWPCIDEVPORT:: pfnRetain
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsync */
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsyncDECLHIDDEN(void) vboxPciDevRetain(PRAWPCIDEVPORT pPort)
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsync{
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync}
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync/**
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync * @copydoc RAWPCIDEVPORT:: pfnRelease
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync */
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsyncDECLHIDDEN(void) vboxPciDevRelease(PRAWPCIDEVPORT pPort)
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync{
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync}
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync/**
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync * @copydoc RAWPCIDEVPORT:: pfnInit
5e5603ae40c7a0a884fe91e269b7d6d6c0ba56f5vboxsync */
2a560b28131ee7efa5b73a9e9cbfdb08eae28624vboxsyncDECLHIDDEN(int) vboxPciDevInit(PRAWPCIDEVPORT pPort, uint32_t fFlags)
5e5603ae40c7a0a884fe91e269b7d6d6c0ba56f5vboxsync{
5e5603ae40c7a0a884fe91e269b7d6d6c0ba56f5vboxsync PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
5e5603ae40c7a0a884fe91e269b7d6d6c0ba56f5vboxsync
5e5603ae40c7a0a884fe91e269b7d6d6c0ba56f5vboxsync int rc = vboxPciOsDevInit(pThis, fFlags);
2a560b28131ee7efa5b73a9e9cbfdb08eae28624vboxsync
5e5603ae40c7a0a884fe91e269b7d6d6c0ba56f5vboxsync return rc;
5e5603ae40c7a0a884fe91e269b7d6d6c0ba56f5vboxsync}
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync
2a560b28131ee7efa5b73a9e9cbfdb08eae28624vboxsync/**
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * @copydoc RAWPCIDEVPORT:: pfnDeinit
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync */
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsyncDECLHIDDEN(int) vboxPciDevDeinit(PRAWPCIDEVPORT pPort, uint32_t fFlags)
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync{
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync int rc = vboxPciOsDevDeinit(pThis, fFlags);
2a560b28131ee7efa5b73a9e9cbfdb08eae28624vboxsync
2a560b28131ee7efa5b73a9e9cbfdb08eae28624vboxsync return rc;
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync}
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync/**
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * @copydoc RAWPCIDEVPORT:: pfnGetRegionInfo
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync */
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsyncDECLHIDDEN(int) vboxPciDevGetRegionInfo(PRAWPCIDEVPORT pPort,
6a5bc4dc98789eb202e249b189f036e5ff9129ccvboxsync int32_t iRegion,
2235e7604f29ce0edc7a1d9aa829668563f86867vboxsync RTHCPHYS *pRegionStart,
2235e7604f29ce0edc7a1d9aa829668563f86867vboxsync uint64_t *pu64RegionSize,
2235e7604f29ce0edc7a1d9aa829668563f86867vboxsync bool *pfPresent,
2235e7604f29ce0edc7a1d9aa829668563f86867vboxsync uint32_t *pfFlags)
6a5bc4dc98789eb202e249b189f036e5ff9129ccvboxsync{
6a5bc4dc98789eb202e249b189f036e5ff9129ccvboxsync PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync int rc = vboxPciOsDevGetRegionInfo(pThis, iRegion,
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync pRegionStart, pu64RegionSize,
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync pfPresent, pfFlags);
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync return rc;
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync}
3c1c973ceaac2fdf7f3b0305f57ae30531acb9ccvboxsync
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync/**
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * @copydoc RAWPCIDEVPORT:: pfnMapRegion
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync */
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsyncDECLHIDDEN(int) vboxPciDevMapRegion(PRAWPCIDEVPORT pPort,
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync int32_t iRegion,
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync RTHCPHYS RegionStart,
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync uint64_t u64RegionSize,
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync int32_t fFlags,
04bce18d27791abed8346aba0de41c53a2acd81avboxsync RTR0PTR *pRegionBase)
04bce18d27791abed8346aba0de41c53a2acd81avboxsync{
04bce18d27791abed8346aba0de41c53a2acd81avboxsync PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
04bce18d27791abed8346aba0de41c53a2acd81avboxsync
04bce18d27791abed8346aba0de41c53a2acd81avboxsync int rc = vboxPciOsDevMapRegion(pThis, iRegion, RegionStart, u64RegionSize, fFlags, pRegionBase);
04bce18d27791abed8346aba0de41c53a2acd81avboxsync
04bce18d27791abed8346aba0de41c53a2acd81avboxsync return rc;
04bce18d27791abed8346aba0de41c53a2acd81avboxsync}
2a560b28131ee7efa5b73a9e9cbfdb08eae28624vboxsync
2a560b28131ee7efa5b73a9e9cbfdb08eae28624vboxsync/**
2a560b28131ee7efa5b73a9e9cbfdb08eae28624vboxsync * @copydoc RAWPCIDEVPORT:: pfnUnapRegion
2a560b28131ee7efa5b73a9e9cbfdb08eae28624vboxsync */
2a560b28131ee7efa5b73a9e9cbfdb08eae28624vboxsyncDECLHIDDEN(int) vboxPciDevUnmapRegion(PRAWPCIDEVPORT pPort,
2a560b28131ee7efa5b73a9e9cbfdb08eae28624vboxsync int32_t iRegion,
2a560b28131ee7efa5b73a9e9cbfdb08eae28624vboxsync RTHCPHYS RegionStart,
2a560b28131ee7efa5b73a9e9cbfdb08eae28624vboxsync uint64_t u64RegionSize,
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync RTR0PTR RegionBase)
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync{
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync int rc = vboxPciOsDevUnmapRegion(pThis, iRegion, RegionStart, u64RegionSize, RegionBase);
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync return rc;
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync}
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync/**
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync * @copydoc RAWPCIDEVPORT:: pfnPciCfgRead
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync */
e3e8bde164b5715114ebf596187b5512fa9b75advboxsyncDECLHIDDEN(int) vboxPciDevPciCfgRead(PRAWPCIDEVPORT pPort, uint32_t Register, PCIRAWMEMLOC *pValue)
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync{
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync
04bce18d27791abed8346aba0de41c53a2acd81avboxsync int rc;
04bce18d27791abed8346aba0de41c53a2acd81avboxsync
04bce18d27791abed8346aba0de41c53a2acd81avboxsync rc = vboxPciOsDevPciCfgRead(pThis, Register, pValue);
04bce18d27791abed8346aba0de41c53a2acd81avboxsync
04bce18d27791abed8346aba0de41c53a2acd81avboxsync return rc;
04bce18d27791abed8346aba0de41c53a2acd81avboxsync}
04bce18d27791abed8346aba0de41c53a2acd81avboxsync
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync/**
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync * @copydoc RAWPCIDEVPORT:: pfnPciCfgWrite
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync */
e3e8bde164b5715114ebf596187b5512fa9b75advboxsyncDECLHIDDEN(int) vboxPciDevPciCfgWrite(PRAWPCIDEVPORT pPort, uint32_t Register, PCIRAWMEMLOC *pValue)
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync{
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync int rc = vboxPciOsDevPciCfgWrite(pThis, Register, pValue);
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync
1df297ea8319f3f3afddb73e6ea2fd9c7f0e5eb4vboxsync return rc;
5a7d67754026bd3654a2464799f0db1790ecf183vboxsync}
1df297ea8319f3f3afddb73e6ea2fd9c7f0e5eb4vboxsync
5a7d67754026bd3654a2464799f0db1790ecf183vboxsyncDECLHIDDEN(int) vboxPciDevRegisterIrqHandler(PRAWPCIDEVPORT pPort, PFNRAWPCIISR pfnHandler, void* pIrqContext, int32_t *piHostIrq)
5a7d67754026bd3654a2464799f0db1790ecf183vboxsync{
5a7d67754026bd3654a2464799f0db1790ecf183vboxsync PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
5a7d67754026bd3654a2464799f0db1790ecf183vboxsync int rc;
5a7d67754026bd3654a2464799f0db1790ecf183vboxsync
1df297ea8319f3f3afddb73e6ea2fd9c7f0e5eb4vboxsync pThis->pfnIrqHandler = pfnHandler;
1df297ea8319f3f3afddb73e6ea2fd9c7f0e5eb4vboxsync pThis->pIrqContext = pIrqContext;
1df297ea8319f3f3afddb73e6ea2fd9c7f0e5eb4vboxsync rc = vboxPciOsDevRegisterIrqHandler(pThis, pfnHandler, pIrqContext, piHostIrq);
1df297ea8319f3f3afddb73e6ea2fd9c7f0e5eb4vboxsync if (RT_FAILURE(rc))
5a7d67754026bd3654a2464799f0db1790ecf183vboxsync {
1df297ea8319f3f3afddb73e6ea2fd9c7f0e5eb4vboxsync pThis->pfnIrqHandler = NULL;
5a7d67754026bd3654a2464799f0db1790ecf183vboxsync pThis->pIrqContext = NULL;
5a7d67754026bd3654a2464799f0db1790ecf183vboxsync *piHostIrq = -1;
5a7d67754026bd3654a2464799f0db1790ecf183vboxsync }
5a7d67754026bd3654a2464799f0db1790ecf183vboxsync
5a7d67754026bd3654a2464799f0db1790ecf183vboxsync return rc;
1df297ea8319f3f3afddb73e6ea2fd9c7f0e5eb4vboxsync}
1df297ea8319f3f3afddb73e6ea2fd9c7f0e5eb4vboxsync
1df297ea8319f3f3afddb73e6ea2fd9c7f0e5eb4vboxsyncDECLHIDDEN(int) vboxPciDevUnregisterIrqHandler(PRAWPCIDEVPORT pPort, int32_t iHostIrq)
c00fd08041e14ed8ad7733165f855bfbbc818a0evboxsync{
c00fd08041e14ed8ad7733165f855bfbbc818a0evboxsync PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
c00fd08041e14ed8ad7733165f855bfbbc818a0evboxsync
c00fd08041e14ed8ad7733165f855bfbbc818a0evboxsync int rc = vboxPciOsDevUnregisterIrqHandler(pThis, iHostIrq);
c00fd08041e14ed8ad7733165f855bfbbc818a0evboxsync
c00fd08041e14ed8ad7733165f855bfbbc818a0evboxsync return rc;
c00fd08041e14ed8ad7733165f855bfbbc818a0evboxsync}
c00fd08041e14ed8ad7733165f855bfbbc818a0evboxsync
c00fd08041e14ed8ad7733165f855bfbbc818a0evboxsync/**
c00fd08041e14ed8ad7733165f855bfbbc818a0evboxsync * Creates a new instance.
c00fd08041e14ed8ad7733165f855bfbbc818a0evboxsync *
c00fd08041e14ed8ad7733165f855bfbbc818a0evboxsync * @returns VBox status code.
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * @param pGlobals The globals.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * @param pszName The instance name.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * @param ppDevPort Where to store the pointer to our port interface.
d9658602103599d13b5449fc1ea49d765a23e6f1vboxsync */
d9658602103599d13b5449fc1ea49d765a23e6f1vboxsyncstatic int vboxPciNewInstance(PVBOXRAWPCIGLOBALS pGlobals,
d9658602103599d13b5449fc1ea49d765a23e6f1vboxsync uint32_t u32HostAddress,
d9658602103599d13b5449fc1ea49d765a23e6f1vboxsync uint32_t fFlags,
d9658602103599d13b5449fc1ea49d765a23e6f1vboxsync PRAWPCIDEVPORT *ppDevPort)
d9658602103599d13b5449fc1ea49d765a23e6f1vboxsync{
d9658602103599d13b5449fc1ea49d765a23e6f1vboxsync int rc;
d9658602103599d13b5449fc1ea49d765a23e6f1vboxsync PVBOXRAWPCIINS pNew = (PVBOXRAWPCIINS)RTMemAllocZ(sizeof(*pNew));
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync if (!pNew)
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync return VERR_NO_MEMORY;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync pNew->pGlobals = pGlobals;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync pNew->hSpinlock = NIL_RTSPINLOCK;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync pNew->cRefs = 1;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync pNew->pNext = NULL;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync pNew->HostPciAddress = u32HostAddress;
e0dec59adb362e8486c0622785420ad10e720972vboxsync
e0dec59adb362e8486c0622785420ad10e720972vboxsync pNew->DevPort.u32Version = RAWPCIDEVPORT_VERSION;
e0dec59adb362e8486c0622785420ad10e720972vboxsync
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync pNew->DevPort.pfnRetain = vboxPciDevRetain;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync pNew->DevPort.pfnRelease = vboxPciDevRelease;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync pNew->DevPort.pfnInit = vboxPciDevInit;
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync pNew->DevPort.pfnDeinit = vboxPciDevDeinit;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync pNew->DevPort.pfnGetRegionInfo = vboxPciDevGetRegionInfo;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync pNew->DevPort.pfnMapRegion = vboxPciDevMapRegion;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync pNew->DevPort.pfnUnmapRegion = vboxPciDevUnmapRegion;
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync pNew->DevPort.pfnPciCfgRead = vboxPciDevPciCfgRead;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync pNew->DevPort.pfnPciCfgWrite = vboxPciDevPciCfgWrite;
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync pNew->DevPort.pfnPciCfgRead = vboxPciDevPciCfgRead;
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync pNew->DevPort.pfnPciCfgWrite = vboxPciDevPciCfgWrite;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync pNew->DevPort.pfnRegisterIrqHandler = vboxPciDevRegisterIrqHandler;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync pNew->DevPort.pfnUnregisterIrqHandler = vboxPciDevUnregisterIrqHandler;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync pNew->DevPort.u32VersionEnd = RAWPCIDEVPORT_VERSION;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync
e0dec59adb362e8486c0622785420ad10e720972vboxsync rc = RTSpinlockCreate(&pNew->hSpinlock);
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync if (RT_SUCCESS(rc))
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync {
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync rc = pNew->DevPort.pfnInit(&pNew->DevPort, fFlags);
fa86ccda70bc5dd1ae28597340f252b212dcf36dvboxsync if (RT_SUCCESS(rc))
fa86ccda70bc5dd1ae28597340f252b212dcf36dvboxsync {
fa86ccda70bc5dd1ae28597340f252b212dcf36dvboxsync *ppDevPort = &pNew->DevPort;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync }
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync else
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync {
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync RTSpinlockDestroy(pNew->hSpinlock);
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync RTMemFree(pNew);
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync }
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync return rc;
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync }
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync return rc;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync}
e0dec59adb362e8486c0622785420ad10e720972vboxsync
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync/**
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * @copydoc RAWPCIFACTORY::pfnCreateAndConnect
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync */
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsyncstatic DECLCALLBACK(int) vboxPciFactoryCreateAndConnect(PRAWPCIFACTORY pFactory,
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync uint32_t u32HostAddress,
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync uint32_t fFlags,
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync PRAWPCIDEVPORT *ppDevPort)
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync{
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync PVBOXRAWPCIGLOBALS pGlobals = (PVBOXRAWPCIGLOBALS)((uint8_t *)pFactory - RT_OFFSETOF(VBOXRAWPCIGLOBALS, RawPciFactory));
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync int rc;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync LogFlow(("vboxPciFactoryCreateAndConnect: PCI=%x fFlags=%#x\n", u32HostAddress, fFlags));
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync Assert(pGlobals->cFactoryRefs > 0);
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync AssertRCReturn(rc, rc);
e0dec59adb362e8486c0622785420ad10e720972vboxsync
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync rc = vboxPciNewInstance(pGlobals, u32HostAddress, fFlags, ppDevPort);
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync RTSemFastMutexRelease(pGlobals->hFastMtx);
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync return rc;
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync}
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync/**
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync * @copydoc RAWPCIFACTORY::pfnRelease
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync */
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsyncstatic DECLCALLBACK(void) vboxPciFactoryRelease(PRAWPCIFACTORY pFactory)
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync{
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync PVBOXRAWPCIGLOBALS pGlobals = (PVBOXRAWPCIGLOBALS)((uint8_t *)pFactory - RT_OFFSETOF(VBOXRAWPCIGLOBALS, RawPciFactory));
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync int32_t cRefs = ASMAtomicDecS32(&pGlobals->cFactoryRefs);
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync Assert(cRefs >= 0); NOREF(cRefs);
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync LogFlow(("vboxPciFactoryRelease: cRefs=%d (new)\n", cRefs));
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync}
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsyncstatic DECLHIDDEN(bool) vboxPciCanUnload(PVBOXRAWPCIGLOBALS pGlobals)
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync{
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync int rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync bool fRc = !pGlobals->pInstanceHead
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync && pGlobals->cFactoryRefs <= 0;
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync RTSemFastMutexRelease(pGlobals->hFastMtx);
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync AssertRC(rc);
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync return fRc;
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync}
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync
0aaf889969ebdaba8a310db13adcec8c10174796vboxsyncstatic DECLHIDDEN(int) vboxPciInitIdc(PVBOXRAWPCIGLOBALS pGlobals)
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync{
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync int rc;
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync Assert(!pGlobals->fIDCOpen);
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync /*
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * Establish a connection to SUPDRV and register our component factory.
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync */
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync rc = SUPR0IdcOpen(&pGlobals->SupDrvIDC, 0 /* iReqVersion = default */, 0 /* iMinVersion = default */, NULL, NULL, NULL);
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync if (RT_SUCCESS(rc))
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync {
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync if (RT_SUCCESS(rc))
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync {
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync pGlobals->fIDCOpen = true;
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync Log(("VBoxRawPci: pSession=%p\n", SUPR0IdcGetSession(&pGlobals->SupDrvIDC)));
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync return rc;
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync }
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync /* bail out. */
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync LogRel(("VBoxRawPci: Failed to register component factory, rc=%Rrc\n", rc));
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync SUPR0IdcClose(&pGlobals->SupDrvIDC);
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync }
34bfec0bd844700e3b769dcfad1a869ca6b8a0d8vboxsync
34bfec0bd844700e3b769dcfad1a869ca6b8a0d8vboxsync return rc;
34bfec0bd844700e3b769dcfad1a869ca6b8a0d8vboxsync}
34bfec0bd844700e3b769dcfad1a869ca6b8a0d8vboxsync
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync/**
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * Try to close the IDC connection to SUPDRV if established.
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync *
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * @returns VBox status code.
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * @retval VINF_SUCCESS on success.
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * @retval VERR_WRONG_ORDER if we're busy.
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync *
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * @param pGlobals Pointer to the globals.
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync */
0aaf889969ebdaba8a310db13adcec8c10174796vboxsyncDECLHIDDEN(int) vboxPciDeleteIdc(PVBOXRAWPCIGLOBALS pGlobals)
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync{
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync int rc;
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync Assert(pGlobals->hFastMtx != NIL_RTSEMFASTMUTEX);
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync /*
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * Check before trying to deregister the factory.
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync */
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync if (!vboxPciCanUnload(pGlobals))
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync return VERR_WRONG_ORDER;
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync if (!pGlobals->fIDCOpen)
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync rc = VINF_SUCCESS;
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync else
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync {
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync /*
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * Disconnect from SUPDRV.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync */
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync rc = SUPR0IdcComponentDeregisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync AssertRC(rc);
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsync SUPR0IdcClose(&pGlobals->SupDrvIDC);
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync pGlobals->fIDCOpen = false;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync }
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync
return rc;
}
/**
* Initializes the globals.
*
* @returns VBox status code.
* @param pGlobals Pointer to the globals.
*/
DECLHIDDEN(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;
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.
*/
DECLHIDDEN(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);
}