SrvPciRawR0.cpp revision 7790c8b32f534f1d0939c1d2231c38dc54ca4423
/* $Id$ */
/** @file
* PCI passthrough - The ring 0 service.
*/
/*
* Copyright (C) 2011 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_RAW
#include <iprt/handletable.h>
#include <iprt/semaphore.h>
#include <iprt/spinlock.h>
#include <iprt/asm-amd64-x86.h>
typedef struct PCIRAWSRVSTATE
{
/** Structure lock. */
/** Handle table for devices. */
typedef PCIRAWSRVSTATE *PPCIRAWSRVSTATE;
typedef struct PCIRAWDEV
{
/* Port pointer. */
/* Handle used by everybody else. */
/** The session this device is associated with. */
/** Structure lock. */
/** Event for IRQ updates. */
/** Current pending IRQ for the device. */
/** ISR handle. */
/* If object is being destroyed. */
bool fTerminate;
/** The SUPR0 object. */
void *pvObj;
} PCIRAWDEV;
typedef PCIRAWDEV *PPCIRAWDEV;
static PCIRAWSRVSTATE g_State;
/* Interrupt handler. Could be called in the interrupt context,
* depending on host OS implmenetation. */
{
int rc;
/* Cannot read, assume non-shared. */
if (RT_FAILURE(rc))
return false;
/* Check interrupt status bit. */
return false;
#endif
/**
* @todo: RTSemEventSignal() docs claims that it's platform-dependent
* if RTSemEventSignal() could be called from the ISR, but it seems IPRT
* doesn't provide primitives that guaranteed to work this way.
*/
return true;
}
static DECLCALLBACK(int) pcirawr0DevRetainHandle(RTHANDLETABLE hHandleTable, void *pvObj, void *pvCtx, void *pvUser)
{
return VINF_SUCCESS;
}
/**
* Initializes the raw PCI ring-0 service.
*
* @returns VBox status code.
*/
PCIRAWR0DECL(int) PciRawR0Init(void)
{
LogFlow(("PciRawR0Init:\n"));
int rc = VINF_SUCCESS;
rc = RTHandleTableCreateEx(&g_State.hHtDevs, RTHANDLETABLE_FLAGS_LOCKED | RTHANDLETABLE_FLAGS_CONTEXT,
return rc;
}
/**
* Destroys raw PCI ring-0 service.
*/
PCIRAWR0DECL(void) PciRawR0Term(void)
{
LogFlow(("PciRawR0Term:\n"));
}
/**
* Per-VM R0 module init.
*/
{
int rc;
rc = SUPR0ComponentQueryFactory(pVM->pSession, "VBoxRawPci", RAWPCIFACTORY_UUID_STR, (void **)&pFactory);
if (RT_SUCCESS(rc))
{
if (pFactory)
{
if (RT_SUCCESS(rc))
}
}
return VINF_SUCCESS;
}
/**
* Per-VM R0 module termination routine.
*/
{
int rc;
rc = SUPR0ComponentQueryFactory(pVM->pSession, "VBoxRawPci", RAWPCIFACTORY_UUID_STR, (void **)&pFactory);
if (RT_SUCCESS(rc))
{
if (pFactory)
{
if (RT_SUCCESS(rc))
}
}
}
{
/* Enable that, once figure our how to make sure
IRQ getter thread notified and woke up. */
#if 0
{
}
#endif
{
}
/* Forcefully deinit. */
}
if (!pDev) \
return VERR_INVALID_HANDLE; \
#ifdef DEBUG_nike
/* Code to perform debugging without host driver. */
typedef struct DUMMYRAWPCIINS
{
/* Host PCI address of this device. */
/* Padding */
/** Port, given to the outside world. */
typedef struct DUMMYRAWPCIINS *PDUMMYRAWPCIINS;
#define DEVPORT_2_DUMMYRAWPCIINS(pPort) \
{
}
{
}
{
return RT_H2LE_U16(u16Value);
}
{
}
{
return RT_H2LE_U32(u32Value);
}
{
}
/**
* @copydoc RAWPCIDEVPORT:: pfnInit
*/
{
dummyPciSetWord(pThis, VBOX_PCI_COMMAND, PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS | PCI_COMMAND_BUSMASTER);
return VINF_SUCCESS;
}
/**
* @copydoc RAWPCIDEVPORT:: pfnDeinit
*/
{
return VINF_SUCCESS;
}
/**
* @copydoc RAWPCIDEVPORT:: pfnDestroy
*/
{
return VINF_SUCCESS;
}
/**
* @copydoc RAWPCIDEVPORT:: pfnGetRegionInfo
*/
bool *pfPresent,
{
if (iRegion == 0)
{
*pfPresent = true;
*pRegionStart = 0xfef0;
*pu64RegionSize = 0x10;
}
else if (iRegion == 2)
{
*pfPresent = true;
*pRegionStart = 0xffff0000;
*pu64RegionSize = 0x1000;
}
else
*pfPresent = false;
return VINF_SUCCESS;
}
/**
* @copydoc RAWPCIDEVPORT:: pfnMapRegion
*/
{
return VINF_SUCCESS;
}
/**
* @copydoc RAWPCIDEVPORT:: pfnUnapRegion
*/
{
return VINF_SUCCESS;
}
/**
* @copydoc RAWPCIDEVPORT:: pfnPciCfgRead
*/
{
{
case 1:
break;
case 2:
break;
case 4:
break;
}
return VINF_SUCCESS;
}
/**
* @copydoc RAWPCIDEVPORT:: pfnPciCfgWrite
*/
{
{
case 1:
break;
case 2:
break;
case 4:
break;
}
return VINF_SUCCESS;
}
void* pIrqContext,
{
return VINF_SUCCESS;
}
{
return VINF_SUCCESS;
}
{
return VINF_SUCCESS;
}
{
if (!pNew)
return NULL;
}
#endif
{
/* Forcefully deinit. */
pcirawr0DevTerm(pThis, 0);
/* And destroy. */
}
{
/*
* Query the factory we want, then use it create and connect the host device.
*/
int rc;
if (!pNew)
return VERR_NO_MEMORY;
rc = SUPR0ComponentQueryFactory(pSession, "VBoxRawPci", RAWPCIFACTORY_UUID_STR, (void **)&pFactory);
/* No host driver registered, provide some fake implementation
for debugging purposes. */
#ifdef DEBUG_nike
if (rc == VERR_SUPDRV_COMPONENT_NOT_FOUND)
{
if (pDevPort)
{
rc = VINF_SUCCESS;
}
else
rc = VERR_NO_MEMORY;
}
#endif
if (RT_SUCCESS(rc))
{
if (pFactory)
{
if (RT_SUCCESS(rc))
&pDevPort,
}
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
}
else
{
}
}
}
if (RT_FAILURE(rc))
return rc;
}
{
int rc;
PUT_PORT();
return rc;
}
/* We may want to call many functions here directly, so no static */
bool *pfPresent,
{
int rc = pDevPort->pfnGetRegionInfo(pDevPort, iRegion, pRegionStart, pu64RegionSize, pfPresent, pfFlags);
PUT_PORT();
return rc;
}
{
LogFlow(("pcirawr0MapRegion\n"));
int rc;
if (RT_SUCCESS(rc))
{
/* Do we need to do something to help with R3 mapping, if ((fFlags & PCIRAWRFLAG_ALLOW_R3MAP) != 0) */
}
*ppvAddressR3 = 0;
PUT_PORT();
return rc;
}
{
LogFlow(("pcirawr0UnmapRegion\n"));
int rc;
PUT_PORT();
return rc;
}
unsigned cb)
{
/// @todo: add check that port fits into device range
switch (cb)
{
case 1:
break;
case 2:
break;
case 4:
break;
default:
}
return VINF_SUCCESS;
}
unsigned cb)
{
/// @todo: add check that port fits into device range
switch (cb)
{
case 1:
break;
case 2:
break;
case 4:
break;
default:
}
return VINF_SUCCESS;
}
{
/// @todo: add check that address fits into device range
#if 1
{
case 1:
break;
case 2:
break;
case 4:
break;
case 8:
break;
}
#else
#endif
return VINF_SUCCESS;
}
{
/// @todo: add check that address fits into device range
#if 1
{
case 1:
break;
case 2:
break;
case 4:
break;
case 8:
break;
}
#endif
return VINF_SUCCESS;
}
{
}
{
int rc;
PUT_PORT();
return rc;
}
{
int rc = VINF_SUCCESS;
PUT_PORT();
return rc;
}
{
int rc = VINF_SUCCESS;
PUT_PORT();
return rc;
}
{
int rc = VINF_SUCCESS;
bool fTerminate = false;
int32_t iPendingIrq = 0;
LogFlow(("pcirawr0GetIrq\n"));
pDev->iPendingIrq = 0;
/* Block until new IRQs arrives */
if (!fTerminate)
{
if (iPendingIrq == 0)
{
if (RT_SUCCESS(rc))
{
/** @todo: racy */
{
pDev->iPendingIrq = 0;
}
else
}
}
if (RT_SUCCESS(rc))
*piIrq = iPendingIrq;
}
else
PUT_PORT();
return rc;
}
{
LogFlow(("pcirawr0PowerStateChange\n"));
PUT_PORT();
return rc;
}
/**
* Process PCI raw request
*
* @returns VBox status code.
*/
{
int rc = VINF_SUCCESS;
/* Route request to the host driver */
{
case PCIRAWR0_DO_OPEN_DEVICE:
break;
case PCIRAWR0_DO_CLOSE_DEVICE:
break;
break;
case PCIRAWR0_DO_MAP_REGION:
break;
case PCIRAWR0_DO_UNMAP_REGION:
break;
case PCIRAWR0_DO_PIO_WRITE:
break;
case PCIRAWR0_DO_PIO_READ:
break;
case PCIRAWR0_DO_MMIO_WRITE:
break;
case PCIRAWR0_DO_MMIO_READ:
break;
case PCIRAWR0_DO_PCICFG_WRITE:
break;
case PCIRAWR0_DO_PCICFG_READ:
break;
case PCIRAWR0_DO_ENABLE_IRQ:
pReq->TargetDevice);
break;
case PCIRAWR0_DO_DISABLE_IRQ:
pReq->TargetDevice);
break;
case PCIRAWR0_DO_GET_IRQ:
break;
break;
default:
}
return rc;
}