DevPciRaw.cpp revision 11923fc977be1686f5428c3e790c04d0701a074c
/* $Id$ */
/** @file
* PCI passthrough device emulation.
*/
/*
* Copyright (C) 2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* 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.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_DEV_PCI
#define PCI_INCLUDE_PRIVATE
#include "VBoxDD.h"
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** The version of the saved state. */
#define PCIRAW_SAVED_STATE_VERSION 1
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
typedef struct PciRawState
{
/** Pointer to the device instance. - R3 ptr. */
/** The PCI raw helpers - R3 Ptr. */
/** Pointer to the device instance. - R0 ptr. */
/** The PCI raw helpers - R0 Ptr. */
/** Pointer to the device instance. - RC ptr. */
/** The PCI raw helpers - RC Ptr. */
/* Virtual PCI device */
/* Device name, as provided by Main */
char szDeviceName[64];
/* Address of device on the host */
/* Address of device in the guest */
/* Global device lock */
/**
* Device port - LUN#0.
*
* @implements PDMIBASE
* @implements PDMIPCIRAW
*/
struct
{
/** The base interface for the PCI device port. */
/** The device port base interface. */
/** The base interface of the attached raw PCI driver. */
/** The device interface of the attached raw PCI driver. */
} Lun0;
} PciRawState;
/** Pointer to the raw PCI instance data. */
typedef PciRawState *PPciRawState;
#ifndef VBOX_DEVICE_STRUCT_TESTCASE
PDMBOTHCBDECL(int) pcirawMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
PDMBOTHCBDECL(int) pcirawMMIORead (PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
{
}
{
}
void * pvUser,
void * pv,
unsigned cb)
{
int rc = VINF_SUCCESS;
return rc;
switch (cb)
{
case 1:
case 2:
case 4:
case 8:
{
break;
}
default:
rc = VINF_SUCCESS;
}
return rc;
}
void * pvUser,
void * pv,
unsigned cb)
{
int rc = VINF_SUCCESS;
LogFlow(("pcirawMMIOWrite: %llx (%d) <- %x\n",
return rc;
switch (cb)
{
case 1:
case 2:
case 4:
case 8:
{
break;
}
default:
}
return rc;
}
{
return VINF_SUCCESS;
}
{
return VINF_SUCCESS;
}
#ifdef IN_RING3
/**
* @copydoc FNSSMDEVLIVEEXEC
*/
{
return VINF_SSM_DONT_CALL_AGAIN;
}
/**
* Saves a state of the raw PCI device. Do nothing yet.
*
* @returns VBox status code.
* @param pDevIns The device instance.
* @param pSSMHandle The handle to save the state to.
*/
{
/* The config. */
return VINF_SUCCESS;
}
/**
* Loads a state of the raw PCI device state.
*
* @returns VBox status code.
* @param pDevIns The device instance.
* @param pSSMHandle The handle to the saved state.
* @param uVersion The data unit version number.
* @param uPass The data pass.
*/
{
int rc;
if (uVersion != PCIRAW_SAVED_STATE_VERSION)
return VINF_SUCCESS;
}
/**
* Relocation notification.
*
* @returns VBox status.
* @param pDevIns The device instance data.
* @param offDelta The delta relative to the old address.
*/
{
unsigned i;
LogFlow(("pcirawRelocate:\n"));
}
/**
* Reset notification.
*
* @returns VBox status.
* @param pDevIns The device instance data.
*/
{
unsigned i;
LogFlow(("pcirawReset:\n"));
}
{
/* Not yet used */
return 0;
}
{
/* Not yet used */
}
/**
* Initialization routine.
*
* @returns VBox status.
* @param pDevIns The device instance data.
*/
{
unsigned i;
int rc;
return VINF_SUCCESS;
}
{
return 0;
}
{
}
/**
* @interface_method_impl{PDMIBASE,pfnQueryInterface}
*/
{
return NULL;
}
{
return 0;
}
/**
* @interface_method_impl{PDMDEVREG,pfnConstruct}
*/
{
int rc;
bool fRCEnabled = false;
bool fR0Enabled = false;
/*
* Validate configuration.
*/
if (!CFGMR3AreValuesValid(pCfg,
"GCEnabled\0"
"R0Enabled\0"
"DeviceName\0"
"GuestPCIBusNo\0"
"GuestPCIDeviceNo\0"
"GuestPCIFunctionNo\0"
"HostPCIBusNo\0"
"HostPCIDeviceNo\0"
"HostPCIFunctionNo\0"
))
/* Query configuration. */
if (RT_FAILURE(rc))
N_("Configuration error: Querying \"GCEnabled\" as a bool failed"));
if (RT_FAILURE(rc))
N_("Configuration error: failed to read R0Enabled as boolean"));
if (RT_FAILURE(rc))
N_("Configuration error: failed to read DeviceName as string"));
/* Obtain device address info */
do {
if (RT_FAILURE(rc))
{
N_("Configuration error: Querying \"HostPCIBusNo\" as a int failed"));
break;
}
if (RT_FAILURE(rc))
{
N_("Configuration error: Querying \"HostPCIDeviceNo\" as a int failed"));
break;
}
if (RT_FAILURE(rc))
{
N_("Configuration error: Querying \"HostPCIFunctionNo\" as a int failed"));
break;
}
if (RT_FAILURE(rc))
{
N_("Configuration error: Querying \"GuestPCIBusNo\" as a int failed"));
break;
}
if (RT_FAILURE(rc))
{
N_("Configuration error: Querying \"GuestPCIDeviceNo\" as a int failed"));
break;
}
if (RT_FAILURE(rc))
{
N_("Configuration error: Querying \"GuestPCIFunctionNo\" as a int failed"));
break;
}
/* Initialize the device state */
if (RT_FAILURE(rc))
break;
/*
* Register the raw device and get helpers.
*/
if (RT_FAILURE(rc))
{
break;
}
/*
* Initialize critical section.
*/
if (RT_FAILURE(rc))
{
break;
}
/* Mark device as passthrough */
/* IBase */
/*
* Attach to the Main driver.
*/
rc = pDevIns->pHlpR3->pfnDriverAttach(pDevIns, 0/*iLun*/, &pThis->Lun0.IBase, &pThis->Lun0.pDrvBase, "Device Port");
if (RT_FAILURE(rc))
{
break;
}
{
rc = PDMDevHlpVMSetError(pDevIns, VERR_PDM_MISSING_INTERFACE, RT_SRC_POS, N_("Raw PCI failed to query interface"));
break;
}
/* Just a safety measure, this data shall never be reached */
if (RT_FAILURE(rc))
break;
/*
*/
{
bool fMmio;
{
/* If region is present, register callbacks in guest.
@todo: replace it with direct region access with remap */
// @todo: check if host's PA make sense for the guest
if (fMmio)
{
"Raw PCI MMIO regions");
if (RT_FAILURE(rc))
{
break;
}
}
else
{
"Raw PCI IO regions");
if (RT_FAILURE(rc))
{
break;
}
}
}
}
if (RT_FAILURE(rc))
break;
if (fRCEnabled)
{
if (!pThis->pPciRawHlpRC)
{
AssertReleaseMsgFailed(("cannot get RC helper\n"));
break;
}
}
if (fR0Enabled)
{
if (!pThis->pPciRawHlpR0)
{
AssertReleaseMsgFailed(("cannot get R0 helper\n"));
break;
}
}
/* Register SSM callbacks */
rc = PDMDevHlpSSMRegister3(pDevIns, PCIRAW_SAVED_STATE_VERSION, sizeof(*pThis), pcirawLiveExec, pcirawSaveExec, pcirawLoadExec);
if (RT_FAILURE(rc))
break;
} while (0);
/* Notify Main about result of PCI device attach attempt */
pThis->Lun0.pDrv->pfnPciDeviceConstructComplete(pThis->Lun0.pDrv, hostAddress.asLong(), guestAddress.asLong(),
return rc;
}
/**
* The device registration structure.
*/
const PDMDEVREG g_DevicePciRaw =
{
/* u32Version */
/* szName */
"pciraw",
/* szRCMod */
"VBoxDDGC.gc",
/* szR0Mod */
"VBoxDDR0.r0",
/* pszDescription */
"Raw PCI wrapper Device",
/* fFlags */
PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36 | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
/* fClass */
/* cMaxInstances */
~0,
/* cbInstance */
sizeof(PciRawState),
/* pfnConstruct */
/* pfnDestruct */
NULL,
/* pfnRelocate */
/* pfnIOCtl */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
/* pfnSuspend */
NULL,
/* pfnResume */
NULL,
/* pfnAttach */
NULL,
/* pfnDetach */
NULL,
/* pfnQueryInterface. */
NULL,
/* pfnInitComplete */
NULL,
/* pfnPowerOff */
NULL,
/* pfnSoftReset */
NULL,
/* u32VersionEnd */
};
#endif /* IN_RING3 */
#endif /* VBOX_DEVICE_STRUCT_TESTCASE */