HGSMIHost.cpp revision 32b1164f35483be483177be7b5235002a4a5afbe
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * VBox Host Guest Shared Memory Interface (HGSMI).
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * Host part:
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * - virtual hardware IO handlers;
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * - channel management;
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * - low level interface for buffer transfer.
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * Copyright (C) 2006-2012 Oracle Corporation
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * This file is part of VirtualBox Open Source Edition (OSE), as
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * available from http://www.virtualbox.org. This file is free software;
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * you can redistribute it and/or modify it under the terms of the GNU
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * General Public License (GPL) as published by the Free Software
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * Foundation, in version 2 as it comes in the "COPYING" file of the
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * Async host->guest calls. Completion by an IO write from the guest or a timer timeout.
d1b57e78cf72f41c7c6a52bd7c2a6d6aa4da6ba4Craig McDonnell * Sync guest->host calls. Initiated by an IO write from the guest.
6909255a1970175507277a0f2f105979625f76b2Jaco Jooste * Guest->Host
6909255a1970175507277a0f2f105979625f76b2Jaco Jooste * ___________
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * Synchronous for the guest, an async result can be also reported later by a host->guest call:
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * G: Alloc shared memory, fill the structure, issue an IO write (HGSMI_IO_GUEST) with the memory offset.
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * H: Verify the shared memory and call the handler.
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * G: Continue after the IO completion.
8f8f8324cd7eb3d7d1d6b446be35096b9eff5f58Andrew Forrest * Host->Guest
8f8f8324cd7eb3d7d1d6b446be35096b9eff5f58Andrew Forrest * H: Alloc shared memory, fill in the info.
8f8f8324cd7eb3d7d1d6b446be35096b9eff5f58Andrew Forrest * Register in the FIFO with a callback, issue IRQ (on EMT).
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * Wait on a sem with timeout if necessary.
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * G: Read FIFO from HGSMI_IO_HOST_COMMAND.
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * H(EMT): Get the shared memory offset from FIFO to return to the guest.
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * G: Get offset, process command, issue IO write to HGSMI_IO_HOST_COMMAND.
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * H(EMT): Find registered shared mem, run callback, which could post the sem.
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * H: Get results and free shared mem (could be freed automatically on EMT too).
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * Implementation notes:
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * Host->Guest
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * * Shared memory allocation using a critsect.
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * * FIFO manipulation with a critsect.
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster#endif /* !DEBUG_sunlover */
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster//# define VBOXHGSMI_STATE_DEBUG
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster#define VBOXHGSMI_STATE_FIFOSTART_MAGIC 0x9abcdef1
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster#define VBOXHGSMI_STATE_FIFOSTOP_MAGIC 0x1fedcba9
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster#define VBOXHGSMI_SAVE_START(_pSSM) do{ int rc2 = SSMR3PutU32(_pSSM, VBOXHGSMI_STATE_START_MAGIC); AssertRC(rc2);}while(0)
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster#define VBOXHGSMI_SAVE_STOP(_pSSM) do{ int rc2 = SSMR3PutU32(_pSSM, VBOXHGSMI_STATE_STOP_MAGIC); AssertRC(rc2);}while(0)
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster#define VBOXHGSMI_SAVE_FIFOSTART(_pSSM) do{ int rc2 = SSMR3PutU32(_pSSM, VBOXHGSMI_STATE_FIFOSTART_MAGIC); AssertRC(rc2);}while(0)
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster#define VBOXHGSMI_SAVE_FIFOSTOP(_pSSM) do{ int rc2 = SSMR3PutU32(_pSSM, VBOXHGSMI_STATE_FIFOSTOP_MAGIC); AssertRC(rc2);}while(0)
74dca04245920444925c2544c591c3da5dad607eAndrew Forrest int rc2 = SSMR3GetU32(_pSSM, &u32); AssertRC(rc2); \
74dca04245920444925c2544c591c3da5dad607eAndrew Forrest#define VBOXHGSMI_LOAD_START(_pSSM) VBOXHGSMI_LOAD_CHECK(_pSSM, VBOXHGSMI_STATE_START_MAGIC)
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster#define VBOXHGSMI_LOAD_FIFOSTART(_pSSM) VBOXHGSMI_LOAD_CHECK(_pSSM, VBOXHGSMI_STATE_FIFOSTART_MAGIC)
ba3008548cd047b233fcd32bb3c5d69926eed22fAndrew Forrest#define VBOXHGSMI_LOAD_FIFOSTOP(_pSSM) VBOXHGSMI_LOAD_CHECK(_pSSM, VBOXHGSMI_STATE_FIFOSTOP_MAGIC)
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster#define VBOXHGSMI_LOAD_STOP(_pSSM) VBOXHGSMI_LOAD_CHECK(_pSSM, VBOXHGSMI_STATE_STOP_MAGIC)
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster#define VBOXHGSMI_SAVE_START(_pSSM) do{ }while(0)
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster#define VBOXHGSMI_SAVE_STOP(_pSSM) do{ }while(0)
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster#define VBOXHGSMI_SAVE_FIFOSTART(_pSSM) do{ }while(0)
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster#define VBOXHGSMI_SAVE_FIFOSTOP(_pSSM) do{ }while(0)
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster#define VBOXHGSMI_LOAD_START(_pSSM) do{ }while(0)
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster#define VBOXHGSMI_LOAD_FIFOSTART(_pSSM) do{ }while(0)
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster#define VBOXHGSMI_LOAD_FIFOSTOP(_pSSM) do{ }while(0)
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster/* Assertions for situations which could happen and normally must be processed properly
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * but must be investigated during development: guest misbehaving, etc.
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster#define HGSMI_STRICT_ASSERT_FAILED() AssertFailed()
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster#define HGSMI_STRICT_ASSERT_FAILED() do {} while (0)
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster#define HGSMI_STRICT_ASSERT(expr) do {} while (0)
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster#endif /* !HGSMI_STRICT */
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster const char *pszName; /* A name for the instance. Mostyl used in the log. */
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster RTCRITSECT instanceCritSect; /* For updating the instance data: FIFO's, channels. */
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster HGSMIAREA area; /* The shared memory description. */
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster RTCRITSECT hostHeapCritSect; /* Heap serialization lock. */
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster HGSMILIST hostFIFO; /* Pending host buffers. */
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster HGSMILIST hostFIFORead; /* Host buffers read by the guest. */
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster HGSMILIST hostFIFOProcessed; /* Processed by the guest. */
ba3008548cd047b233fcd32bb3c5d69926eed22fAndrew Forrest HGSMILIST hostFIFOFree; /* Buffers for reuse. */
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster HGSMILIST guestCmdCompleted; /* list of completed guest commands to be returned to the guest*/
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster RTCRITSECT hostFIFOCritSect; /* FIFO serialization lock. */
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster PFNHGSMINOTIFYGUEST pfnNotifyGuest; /* Guest notification callback. */
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster void *pvNotifyGuest; /* Guest notification callback context. */
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster HGSMICHANNELINFO channelInfo; /* Channel handlers indexed by the channel id.
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster * The array is accessed under the instance lock.
869a36e2649ae064c98063cf1e55198488d78d12Allan Fostertypedef DECLCALLBACK(void) FNHGSMIHOSTFIFOCALLBACK(void *pvCallback);
869a36e2649ae064c98063cf1e55198488d78d12Allan Fostertypedef FNHGSMIHOSTFIFOCALLBACK *PFNHGSMIHOSTFIFOCALLBACK;
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster /* The list field. Must be the first field. */
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster /* Backlink to the HGSMI instance. */
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster /* removed to allow saved state handling */
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster /* The event which is signalled when the command has been processed by the host. */
869a36e2649ae064c98063cf1e55198488d78d12Allan Foster /* Status flags of the entry. */
ba3008548cd047b233fcd32bb3c5d69926eed22fAndrew Forrest /* Offset in the memory region of the entry data. */
void *pvCallback;
#ifdef VBOX_WITH_WDDM
typedef struct _HGSMIGUESTCOMPLENTRY
if (pEntry)
return rc;
return rc;
return rc;
LogFlowFunc(("buffer 0x%x, area %p %x [0x%x;0x%x]\n", offBuffer, pArea->pu8Base, pArea->cbArea, pArea->offBase, pArea->offLast));
LogFunc(("offset 0x%x is outside the area [0x%x;0x%x]!!!\n", offBuffer, pArea->offBase, pArea->offLast));
return NULL;
LogFlowFunc(("datasize check: pHeader->u32DataSize = 0x%x pArea->offLast - offBuffer = 0x%x\n", pHeader->u32DataSize, pArea->offLast - offBuffer));
LogFlowFunc(("checksum check: u32Checksum = 0x%x pTail->u32Checksum = 0x%x\n", u32Checksum, pTail->u32Checksum));
return pHeader;
LogFunc(("invalid data size 0x%x, maximum is 0x%x!!!\n", pHeader->u32DataSize, pArea->offLast - offBuffer));
return NULL;
pHeader);
return rc;
#ifdef VBOX_WITH_WDDM
if(pHead)
if (pHead)
return offCmd;
#ifndef VBOX_WITH_WDDM
return HGSMIOFFSET_VOID;
return offCmd;
bool bCompleteFirst)
while (pEntry)
#ifdef DEBUGVHWASTRICT
AssertFailed();
if (pEntry)
if(!bCompleteFirst)
LogRel(("HGSMI[%s]: ignored invalid write to the host FIFO: 0x%08X!!!\n", pIns->pszName, offBuffer));
return HGSMIOFFSET_VOID;
return rc;
return rc;
if (pv)
return rc;
return rc;
return rc;
return rc;
if (pEntry)
return rc;
return rc;
void *pvMem)
while (pEntry)
if (pEntry)
AssertFailed ();
if(pEntry)
AssertFailed ();
return rc;
return rc;
* i.e. in case the command is not urgent(e.g. some guest command completion notification that does not require post-processing)
bool bDoIrq)
if(bDoIrq)
return rc;
void **ppvMem,
if (pvMem)
return rc;
* i.e. in case the command is not urgent(e.g. some guest command completion notification that does not require post-processing)
void *pvMem,
bool bDoIrq)
bDoIrq);
return rc;
void *pvMem)
return rc;
void *pvMem)
NULL,
AssertFailed();
&g_hgsmiEnv);
return rc;
++size;
return rc;
static int hgsmiHostSaveGuestCmdCompletedFifoEntryLocked (HGSMIGUESTCOMPLENTRY *pEntry, PSSMHANDLE pSSM)
++size;
return rc;
static int hgsmiHostLoadFifoEntryLocked (PHGSMIINSTANCE pIns, HGSMIHOSTFIFOENTRY **ppEntry, PSSMHANDLE pSSM)
return rc;
return rc;
static int hgsmiHostLoadGuestCmdCompletedFifoEntryLocked (PHGSMIINSTANCE pIns, HGSMIGUESTCOMPLENTRY **ppEntry, PSSMHANDLE pSSM)
return rc;
static int hgsmiHostLoadGuestCmdCompletedFifoLocked (PHGSMIINSTANCE pIns, HGSMILIST * pFifo, PSSMHANDLE pSSM, uint32_t u32Version)
return rc;
int rc;
HGSMIOFFSET off = pIns->pHGFlags ? HGSMIPointerToOffset(&pIns->area, (const HGSMIBUFFERHEADER *)pIns->pHGFlags) : HGSMIOFFSET_VOID;
#ifdef VBOX_WITH_WDDM
return rc;
return VINF_SUCCESS;
int rc;
pIns->pHGFlags = (off != HGSMIOFFSET_VOID) ? (HGSMIHOSTFLAGS*)HGSMIOffsetToPointer (&pIns->area, off) : NULL;
off,
&g_hgsmiEnv);
#ifdef VBOX_WITH_WDDM
return rc;
const char *pszChannel,
return VERR_NOT_SUPPORTED;
void *pvChannelHandler,
rc = HGSMIChannelRegister (&pIns->channelInfo, u8Channel, NULL, pfnChannelHandler, pvChannelHandler, pOldHandler);
return rc;
const char *pszChannel,
void *pvChannelHandler,
LogFlowFunc(("pIns %p, pszChannel %s, pfnChannelHandler %p, pvChannelHandler %p, pu8Channel %p, pOldHandler %p\n",
int rc;
if (pszName)
rc = HGSMIChannelRegister (&pIns->channelInfo, *pu8Channel, pszName, pfnChannelHandler, pvChannelHandler, pOldHandler);
return rc;
int rc;
if ( pHandler
return rc;
LogFunc(("offset 0x%x is outside the area [0x%x;0x%x]!!!\n", offBuffer, pArea->offBase, pArea->offLast));
return NULL;
const void *pv)
if ( p < pBegin
|| p > pEnd)
return HGSMIOFFSET_VOID;
return p + sizeof (HGSMIINSTANCE);
static DECLCALLBACK(int) hgsmiChannelHandler (void *pvHandler, uint16_t u16ChannelInfo, void *pvBuffer, HGSMISIZE cbBuffer)
switch (u16ChannelInfo)
return rc;
const char *pszName,
void *pvNotifyGuest,
LogFlowFunc(("ppIns = %p, pVM = %p, pszName = [%s], pu8MemBase = %p, cbMem = 0x%08X, offMemBase = 0x%08X, "
pVM,
if (!pIns)
pIns,
return rc;
#ifdef VBOX_WITH_WDDM
return flags;
if (pIns)
#ifdef VBOX_WITH_WDDM
return rc;
bool bDoIrq)
if(bDoIrq)
#ifdef DEBUG_misha
Assert(0);
return rc;
void *pvMem,
bool bDoIrq)
return rc;