3
* HGCM (Host-Guest Communication Manager)
7
* Copyright (C) 2006-2007 Oracle Corporation
9
* This file is part of VirtualBox Open Source Edition (OSE), as
10
* available from http://www.virtualbox.org. This file is free software;
11
* you can redistribute it and/or modify it under the terms of the GNU
12
* General Public License (GPL) as published by the Free Software
13
* Foundation, in version 2 as it comes in the "COPYING" file of the
14
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18
#define LOG_GROUP_MAIN_OVERRIDE LOG_GROUP_HGCM
21
#include "hgcm/HGCM.h"
22
#include "hgcm/HGCMThread.h"
25
#include <VBox/hgcmsvc.h>
27
#include <iprt/alloc.h>
28
#include <iprt/alloca.h>
30
#include <iprt/critsect.h>
33
#include <iprt/param.h>
34
#include <iprt/path.h>
35
#include <iprt/string.h>
36
#include <iprt/semaphore.h>
37
#include <iprt/thread.h>
39
#include <VBox/VMMDev.h>
42
* A service gets one thread, which synchronously delivers messages to
43
* the service. This is good for serialization.
45
* Some services may want to process messages asynchronously, and will want
46
* a next message to be delivered, while a previous message is still being
49
* The dedicated service thread delivers a next message when service
50
* returns after fetching a previous one. The service will call a message
51
* completion callback when message is actually processed. So returning
52
* from the service call means only that the service is processing message.
54
* 'Message processed' condition is indicated by service, which call the
55
* callback, even if the callback is called synchronously in the dedicated
58
* This message completion callback is only valid for Call requests.
59
* Connect and Disconnect are processed synchronously by the service.
63
/* The maximum allowed size of a service name in bytes. */
64
#define VBOX_HGCM_SVC_NAME_MAX_BYTES 1024
66
struct _HGCMSVCEXTHANDLEDATA
69
/* The service name follows. */
72
/** Internal helper service object. HGCM code would use it to
73
* hold information about services and communicate with services.
74
* The HGCMService is an (in future) abstract class that implements
75
* common functionality. There will be derived classes for specific
82
VBOXHGCMSVCHELPERS m_svcHelpers;
84
static HGCMService *sm_pSvcListHead;
85
static HGCMService *sm_pSvcListTail;
87
static int sm_cServices;
89
HGCMTHREADHANDLE m_thread;
90
friend DECLCALLBACK(void) hgcmServiceThread (HGCMTHREADHANDLE ThreadHandle, void *pvUser);
92
uint32_t volatile m_u32RefCnt;
94
HGCMService *m_pSvcNext;
95
HGCMService *m_pSvcPrev;
98
char *m_pszSvcLibrary;
101
PFNVBOXHGCMSVCLOAD m_pfnLoad;
103
VBOXHGCMSVCFNTABLE m_fntable;
106
int m_cClientsAllocated;
108
uint32_t *m_paClientIds;
110
HGCMSVCEXTHANDLE m_hExtension;
112
int loadServiceDLL (void);
113
void unloadServiceDLL (void);
116
* Main HGCM thread methods.
118
int instanceCreate (const char *pszServiceLibrary, const char *pszServiceName);
119
void instanceDestroy (void);
121
int saveClientState(uint32_t u32ClientId, PSSMHANDLE pSSM);
122
int loadClientState(uint32_t u32ClientId, PSSMHANDLE pSSM);
127
static DECLCALLBACK(void) svcHlpCallComplete (VBOXHGCMCALLHANDLE callHandle, int32_t rc);
128
static DECLCALLBACK(void) svcHlpDisconnectClient (void *pvInstance, uint32_t u32ClientId);
133
* Main HGCM thread methods.
135
static int LoadService (const char *pszServiceLibrary, const char *pszServiceName);
136
void UnloadService (void);
138
static void UnloadAll (void);
140
static int ResolveService (HGCMService **ppsvc, const char *pszServiceName);
141
void ReferenceService (void);
142
void ReleaseService (void);
144
static void Reset (void);
146
static int SaveState (PSSMHANDLE pSSM);
147
static int LoadState (PSSMHANDLE pSSM);
149
int CreateAndConnectClient (uint32_t *pu32ClientIdOut, uint32_t u32ClientIdIn);
150
int DisconnectClient (uint32_t u32ClientId, bool fFromService);
152
int HostCall (uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM *paParms);
154
uint32_t SizeOfClient (void) { return m_fntable.cbClient; };
156
int RegisterExtension (HGCMSVCEXTHANDLE handle, PFNHGCMSVCEXT pfnExtension, void *pvExtension);
157
void UnregisterExtension (HGCMSVCEXTHANDLE handle);
160
* The service thread methods.
163
int GuestCall (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM aParms[]);
167
class HGCMClient: public HGCMObject
170
HGCMClient () : HGCMObject(HGCMOBJ_CLIENT), pService(NULL),
174
int Init (HGCMService *pSvc);
176
/** Service that the client is connected to. */
177
HGCMService *pService;
179
/** Client specific data. */
183
HGCMClient::~HGCMClient ()
185
if (pService->SizeOfClient () > 0)
189
int HGCMClient::Init (HGCMService *pSvc)
193
if (pService->SizeOfClient () > 0)
195
pvData = RTMemAllocZ (pService->SizeOfClient ());
199
return VERR_NO_MEMORY;
207
#define HGCM_CLIENT_DATA(pService, pClient) (pClient->pvData)
211
HGCMService *HGCMService::sm_pSvcListHead = NULL;
212
HGCMService *HGCMService::sm_pSvcListTail = NULL;
213
int HGCMService::sm_cServices = 0;
215
HGCMService::HGCMService ()
222
m_pszSvcLibrary (NULL),
223
m_hLdrMod (NIL_RTLDRMOD),
226
m_cClientsAllocated (0),
227
m_paClientIds (NULL),
230
memset (&m_fntable, 0, sizeof (m_fntable));
234
static bool g_fResetting = false;
235
static bool g_fSaveState = false;
238
/** Helper function to load a local service DLL.
242
int HGCMService::loadServiceDLL (void)
244
LogFlowFunc(("m_pszSvcLibrary = %s\n", m_pszSvcLibrary));
246
if (m_pszSvcLibrary == NULL)
248
return VERR_INVALID_PARAMETER;
251
int rc = SUPR3HardenedLdrLoadAppPriv (m_pszSvcLibrary, &m_hLdrMod);
255
LogFlowFunc(("successfully loaded the library.\n"));
259
rc = RTLdrGetSymbol (m_hLdrMod, VBOX_HGCM_SVCLOAD_NAME, (void**)&m_pfnLoad);
261
if (RT_FAILURE(rc) || !m_pfnLoad)
263
Log(("HGCMService::loadServiceDLL: Error resolving the service entry point %s, rc = %d, m_pfnLoad = %p\n", VBOX_HGCM_SVCLOAD_NAME, rc, m_pfnLoad));
267
/* m_pfnLoad was NULL */
268
rc = VERR_SYMBOL_NOT_FOUND;
274
memset (&m_fntable, 0, sizeof (m_fntable));
276
m_fntable.cbSize = sizeof (m_fntable);
277
m_fntable.u32Version = VBOX_HGCM_SVC_VERSION;
278
m_fntable.pHelpers = &m_svcHelpers;
280
rc = m_pfnLoad (&m_fntable);
282
LogFlowFunc(("m_pfnLoad rc = %Rrc\n", rc));
286
if ( m_fntable.pfnUnload == NULL
287
|| m_fntable.pfnConnect == NULL
288
|| m_fntable.pfnDisconnect == NULL
289
|| m_fntable.pfnCall == NULL
292
Log(("HGCMService::loadServiceDLL: at least one of function pointers is NULL\n"));
294
rc = VERR_INVALID_PARAMETER;
296
if (m_fntable.pfnUnload)
298
m_fntable.pfnUnload (m_fntable.pvService);
306
LogRel(("HGCM: Failed to load the service library: [%s], rc = %Rrc. The service will be not available.\n", m_pszSvcLibrary, rc));
307
m_hLdrMod = NIL_RTLDRMOD;
318
/** Helper function to free a local service DLL.
322
void HGCMService::unloadServiceDLL (void)
326
RTLdrClose (m_hLdrMod);
329
memset (&m_fntable, 0, sizeof (m_fntable));
331
m_hLdrMod = NIL_RTLDRMOD;
335
* Messages processed by service threads. These threads only call the service entry points.
338
#define SVC_MSG_LOAD (0) /* Load the service library and call VBOX_HGCM_SVCLOAD_NAME entry point. */
339
#define SVC_MSG_UNLOAD (1) /* call pfnUnload and unload the service library. */
340
#define SVC_MSG_CONNECT (2) /* pfnConnect */
341
#define SVC_MSG_DISCONNECT (3) /* pfnDisconnect */
342
#define SVC_MSG_GUESTCALL (4) /* pfnGuestCall */
343
#define SVC_MSG_HOSTCALL (5) /* pfnHostCall */
344
#define SVC_MSG_LOADSTATE (6) /* pfnLoadState. */
345
#define SVC_MSG_SAVESTATE (7) /* pfnSaveState. */
346
#define SVC_MSG_QUIT (8) /* Terminate the thread. */
347
#define SVC_MSG_REGEXT (9) /* pfnRegisterExtension */
348
#define SVC_MSG_UNREGEXT (10) /* pfnRegisterExtension */
350
class HGCMMsgSvcLoad: public HGCMMsgCore
354
class HGCMMsgSvcUnload: public HGCMMsgCore
358
class HGCMMsgSvcConnect: public HGCMMsgCore
361
/* client identifier */
362
uint32_t u32ClientId;
365
class HGCMMsgSvcDisconnect: public HGCMMsgCore
368
/* client identifier */
369
uint32_t u32ClientId;
372
class HGCMMsgHeader: public HGCMMsgCore
375
HGCMMsgHeader () : pCmd (NULL), pHGCMPort (NULL) {};
377
/* Command pointer/identifier. */
380
/* Port to be informed on message completion. */
381
PPDMIHGCMPORT pHGCMPort;
385
class HGCMMsgCall: public HGCMMsgHeader
388
/* client identifier */
389
uint32_t u32ClientId;
391
/* function number */
392
uint32_t u32Function;
394
/* number of parameters */
397
VBOXHGCMSVCPARM *paParms;
400
class HGCMMsgLoadSaveStateClient: public HGCMMsgCore
403
uint32_t u32ClientId;
407
class HGCMMsgHostCallSvc: public HGCMMsgCore
410
/* function number */
411
uint32_t u32Function;
413
/* number of parameters */
416
VBOXHGCMSVCPARM *paParms;
419
class HGCMMsgSvcRegisterExtension: public HGCMMsgCore
422
/* Handle of the extension to be registered. */
423
HGCMSVCEXTHANDLE handle;
424
/* The extension entry point. */
425
PFNHGCMSVCEXT pfnExtension;
426
/* The extension pointer. */
430
class HGCMMsgSvcUnregisterExtension: public HGCMMsgCore
433
/* Handle of the registered extension. */
434
HGCMSVCEXTHANDLE handle;
437
static HGCMMsgCore *hgcmMessageAllocSvc (uint32_t u32MsgId)
441
case SVC_MSG_LOAD: return new HGCMMsgSvcLoad ();
442
case SVC_MSG_UNLOAD: return new HGCMMsgSvcUnload ();
443
case SVC_MSG_CONNECT: return new HGCMMsgSvcConnect ();
444
case SVC_MSG_DISCONNECT: return new HGCMMsgSvcDisconnect ();
445
case SVC_MSG_HOSTCALL: return new HGCMMsgHostCallSvc ();
446
case SVC_MSG_GUESTCALL: return new HGCMMsgCall ();
447
case SVC_MSG_LOADSTATE:
448
case SVC_MSG_SAVESTATE: return new HGCMMsgLoadSaveStateClient ();
449
case SVC_MSG_REGEXT: return new HGCMMsgSvcRegisterExtension ();
450
case SVC_MSG_UNREGEXT: return new HGCMMsgSvcUnregisterExtension ();
452
AssertReleaseMsgFailed(("Msg id = %08X\n", u32MsgId));
459
* The service thread. Loads the service library and calls the service entry points.
461
DECLCALLBACK(void) hgcmServiceThread (HGCMTHREADHANDLE ThreadHandle, void *pvUser)
463
HGCMService *pSvc = (HGCMService *)pvUser;
464
AssertRelease(pSvc != NULL);
470
HGCMMsgCore *pMsgCore;
471
int rc = hgcmMsgGet (ThreadHandle, &pMsgCore);
475
/* The error means some serious unrecoverable problem in the hgcmMsg/hgcmThread layer. */
476
AssertMsgFailed (("%Rrc\n", rc));
480
/* Cache required information to avoid unnecessary pMsgCore access. */
481
uint32_t u32MsgId = pMsgCore->MsgId ();
487
LogFlowFunc(("SVC_MSG_LOAD\n"));
488
rc = pSvc->loadServiceDLL ();
493
LogFlowFunc(("SVC_MSG_UNLOAD\n"));
494
if (pSvc->m_fntable.pfnUnload)
496
pSvc->m_fntable.pfnUnload (pSvc->m_fntable.pvService);
499
pSvc->unloadServiceDLL ();
503
case SVC_MSG_CONNECT:
505
HGCMMsgSvcConnect *pMsg = (HGCMMsgSvcConnect *)pMsgCore;
507
LogFlowFunc(("SVC_MSG_CONNECT u32ClientId = %d\n", pMsg->u32ClientId));
509
HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
513
rc = pSvc->m_fntable.pfnConnect (pSvc->m_fntable.pvService, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient));
515
hgcmObjDereference (pClient);
519
rc = VERR_HGCM_INVALID_CLIENT_ID;
523
case SVC_MSG_DISCONNECT:
525
HGCMMsgSvcDisconnect *pMsg = (HGCMMsgSvcDisconnect *)pMsgCore;
527
LogFlowFunc(("SVC_MSG_DISCONNECT u32ClientId = %d\n", pMsg->u32ClientId));
529
HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
533
rc = pSvc->m_fntable.pfnDisconnect (pSvc->m_fntable.pvService, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient));
535
hgcmObjDereference (pClient);
539
rc = VERR_HGCM_INVALID_CLIENT_ID;
543
case SVC_MSG_GUESTCALL:
545
HGCMMsgCall *pMsg = (HGCMMsgCall *)pMsgCore;
547
LogFlowFunc(("SVC_MSG_GUESTCALL u32ClientId = %d, u32Function = %d, cParms = %d, paParms = %p\n",
548
pMsg->u32ClientId, pMsg->u32Function, pMsg->cParms, pMsg->paParms));
550
HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
554
pSvc->m_fntable.pfnCall (pSvc->m_fntable.pvService, (VBOXHGCMCALLHANDLE)pMsg, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient), pMsg->u32Function, pMsg->cParms, pMsg->paParms);
556
hgcmObjDereference (pClient);
560
rc = VERR_HGCM_INVALID_CLIENT_ID;
564
case SVC_MSG_HOSTCALL:
566
HGCMMsgHostCallSvc *pMsg = (HGCMMsgHostCallSvc *)pMsgCore;
568
LogFlowFunc(("SVC_MSG_HOSTCALL u32Function = %d, cParms = %d, paParms = %p\n", pMsg->u32Function, pMsg->cParms, pMsg->paParms));
570
rc = pSvc->m_fntable.pfnHostCall (pSvc->m_fntable.pvService, pMsg->u32Function, pMsg->cParms, pMsg->paParms);
573
case SVC_MSG_LOADSTATE:
575
HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)pMsgCore;
577
LogFlowFunc(("SVC_MSG_LOADSTATE\n"));
579
HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
583
if (pSvc->m_fntable.pfnLoadState)
585
rc = pSvc->m_fntable.pfnLoadState (pSvc->m_fntable.pvService, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient), pMsg->pSSM);
588
hgcmObjDereference (pClient);
592
rc = VERR_HGCM_INVALID_CLIENT_ID;
596
case SVC_MSG_SAVESTATE:
598
HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)pMsgCore;
600
LogFlowFunc(("SVC_MSG_SAVESTATE\n"));
602
HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
608
if (pSvc->m_fntable.pfnSaveState)
611
rc = pSvc->m_fntable.pfnSaveState (pSvc->m_fntable.pvService, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient), pMsg->pSSM);
612
g_fSaveState = false;
615
hgcmObjDereference (pClient);
619
rc = VERR_HGCM_INVALID_CLIENT_ID;
625
HGCMMsgSvcRegisterExtension *pMsg = (HGCMMsgSvcRegisterExtension *)pMsgCore;
627
LogFlowFunc(("SVC_MSG_REGEXT handle = %p, pfn = %p\n", pMsg->handle, pMsg->pfnExtension));
629
if (pSvc->m_hExtension)
631
rc = VERR_NOT_SUPPORTED;
635
if (pSvc->m_fntable.pfnRegisterExtension)
637
rc = pSvc->m_fntable.pfnRegisterExtension (pSvc->m_fntable.pvService, pMsg->pfnExtension, pMsg->pvExtension);
641
rc = VERR_NOT_SUPPORTED;
646
pSvc->m_hExtension = pMsg->handle;
651
case SVC_MSG_UNREGEXT:
653
HGCMMsgSvcUnregisterExtension *pMsg = (HGCMMsgSvcUnregisterExtension *)pMsgCore;
655
LogFlowFunc(("SVC_MSG_UNREGEXT handle = %p\n", pMsg->handle));
657
if (pSvc->m_hExtension != pMsg->handle)
659
rc = VERR_NOT_SUPPORTED;
663
if (pSvc->m_fntable.pfnRegisterExtension)
665
rc = pSvc->m_fntable.pfnRegisterExtension (pSvc->m_fntable.pvService, NULL, NULL);
669
rc = VERR_NOT_SUPPORTED;
672
pSvc->m_hExtension = NULL;
678
AssertMsgFailed(("hgcmServiceThread::Unsupported message number %08X\n", u32MsgId));
679
rc = VERR_NOT_SUPPORTED;
683
if (u32MsgId != SVC_MSG_GUESTCALL)
685
/* For SVC_MSG_GUESTCALL the service calls the completion helper.
686
* Other messages have to be completed here.
688
hgcmMsgComplete (pMsgCore, rc);
693
/* static */ DECLCALLBACK(void) HGCMService::svcHlpCallComplete (VBOXHGCMCALLHANDLE callHandle, int32_t rc)
695
HGCMMsgCore *pMsgCore = (HGCMMsgCore *)callHandle;
697
if (pMsgCore->MsgId () == SVC_MSG_GUESTCALL)
699
/* Only call the completion for these messages. The helper
700
* is called by the service, and the service does not get
701
* any other messages.
703
hgcmMsgComplete (pMsgCore, rc);
711
/* static */ DECLCALLBACK(void) HGCMService::svcHlpDisconnectClient (void *pvInstance, uint32_t u32ClientId)
713
HGCMService *pService = static_cast <HGCMService *> (pvInstance);
717
pService->DisconnectClient (u32ClientId, true);
721
static DECLCALLBACK(void) hgcmMsgCompletionCallback (int32_t result, HGCMMsgCore *pMsgCore)
723
/* Call the VMMDev port interface to issue IRQ notification. */
724
HGCMMsgHeader *pMsgHdr = (HGCMMsgHeader *)pMsgCore;
726
LogFlow(("MAIN::hgcmMsgCompletionCallback: message %p\n", pMsgCore));
728
if (pMsgHdr->pHGCMPort && !g_fResetting)
730
pMsgHdr->pHGCMPort->pfnCompleted (pMsgHdr->pHGCMPort, g_fSaveState? VINF_HGCM_SAVE_STATE: result, pMsgHdr->pCmd);
735
* The main HGCM methods of the service.
738
int HGCMService::instanceCreate (const char *pszServiceLibrary, const char *pszServiceName)
740
LogFlowFunc(("name %s, lib %s\n", pszServiceName, pszServiceLibrary));
742
/* The maximum length of the thread name, allowed by the RT is 15. */
743
char achThreadName[16];
745
strncpy (achThreadName, pszServiceName, 15);
746
achThreadName[15] = 0;
748
int rc = hgcmThreadCreate (&m_thread, achThreadName, hgcmServiceThread, this);
752
m_pszSvcName = RTStrDup (pszServiceName);
753
m_pszSvcLibrary = RTStrDup (pszServiceLibrary);
755
if (!m_pszSvcName || !m_pszSvcLibrary)
757
RTStrFree (m_pszSvcLibrary);
758
m_pszSvcLibrary = NULL;
760
RTStrFree (m_pszSvcName);
767
/* Initialize service helpers table. */
768
m_svcHelpers.pfnCallComplete = svcHlpCallComplete;
769
m_svcHelpers.pvInstance = this;
770
m_svcHelpers.pfnDisconnectClient = svcHlpDisconnectClient;
772
/* Execute the load request on the service thread. */
774
rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_LOAD, hgcmMessageAllocSvc);
778
rc = hgcmMsgSend (hMsg);
788
LogFlowFunc(("rc = %Rrc\n", rc));
792
void HGCMService::instanceDestroy (void)
794
LogFlowFunc(("%s\n", m_pszSvcName));
797
int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_UNLOAD, hgcmMessageAllocSvc);
801
rc = hgcmMsgSend (hMsg);
805
hgcmThreadWait (m_thread);
809
RTStrFree (m_pszSvcLibrary);
810
m_pszSvcLibrary = NULL;
812
RTStrFree (m_pszSvcName);
816
int HGCMService::saveClientState(uint32_t u32ClientId, PSSMHANDLE pSSM)
818
LogFlowFunc(("%s\n", m_pszSvcName));
821
int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_SAVESTATE, hgcmMessageAllocSvc);
825
HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
828
pMsg->u32ClientId = u32ClientId;
831
hgcmObjDereference (pMsg);
833
rc = hgcmMsgSend (hMsg);
836
LogFlowFunc(("rc = %Rrc\n", rc));
840
int HGCMService::loadClientState (uint32_t u32ClientId, PSSMHANDLE pSSM)
842
LogFlowFunc(("%s\n", m_pszSvcName));
845
int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_LOADSTATE, hgcmMessageAllocSvc);
849
HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
853
pMsg->u32ClientId = u32ClientId;
856
hgcmObjDereference (pMsg);
858
rc = hgcmMsgSend (hMsg);
861
LogFlowFunc(("rc = %Rrc\n", rc));
866
/** The method creates a service and references it.
868
* @param pszServcieLibrary The library to be loaded.
869
* @param pszServiceName The name of the service.
873
/* static */ int HGCMService::LoadService (const char *pszServiceLibrary, const char *pszServiceName)
875
LogFlowFunc(("lib %s, name = %s\n", pszServiceLibrary, pszServiceName));
877
/* Look at already loaded services to avoid double loading. */
880
int rc = HGCMService::ResolveService (&pSvc, pszServiceName);
884
/* The service is already loaded. */
885
pSvc->ReleaseService ();
886
rc = VERR_HGCM_SERVICE_EXISTS;
890
/* Create the new service. */
891
pSvc = new HGCMService ();
899
/* Load the library and call the initialization entry point. */
900
rc = pSvc->instanceCreate (pszServiceLibrary, pszServiceName);
904
/* Insert the just created service to list for future references. */
905
pSvc->m_pSvcNext = sm_pSvcListHead;
906
pSvc->m_pSvcPrev = NULL;
910
sm_pSvcListHead->m_pSvcPrev = pSvc;
914
sm_pSvcListTail = pSvc;
917
sm_pSvcListHead = pSvc;
921
/* Reference the service (for first time) until it is unloaded on HGCM termination. */
922
AssertRelease (pSvc->m_u32RefCnt == 0);
923
pSvc->ReferenceService ();
925
LogFlowFunc(("service %p\n", pSvc));
930
LogFlowFunc(("rc = %Rrc\n", rc));
934
/** The method unloads a service.
938
void HGCMService::UnloadService (void)
940
LogFlowFunc(("name = %s\n", m_pszSvcName));
942
/* Remove the service from the list. */
945
m_pSvcNext->m_pSvcPrev = m_pSvcPrev;
949
sm_pSvcListTail = m_pSvcPrev;
954
m_pSvcPrev->m_pSvcNext = m_pSvcNext;
958
sm_pSvcListHead = m_pSvcNext;
963
/* The service must be unloaded only if all clients were disconnected. */
964
LogFlowFunc(("m_u32RefCnt = %d\n", m_u32RefCnt));
965
AssertRelease (m_u32RefCnt == 1);
967
/* Now the service can be released. */
971
/** The method unloads all services.
975
/* static */ void HGCMService::UnloadAll (void)
977
while (sm_pSvcListHead)
979
sm_pSvcListHead->UnloadService ();
983
/** The method obtains a referenced pointer to the service with
984
* specified name. The caller must call ReleaseService when
985
* the pointer is no longer needed.
987
* @param ppSvc Where to store the pointer to the service.
988
* @param pszServiceName The name of the service.
992
/* static */ int HGCMService::ResolveService (HGCMService **ppSvc, const char *pszServiceName)
994
LogFlowFunc(("ppSvc = %p name = %s\n",
995
ppSvc, pszServiceName));
997
if (!ppSvc || !pszServiceName)
999
return VERR_INVALID_PARAMETER;
1002
HGCMService *pSvc = sm_pSvcListHead;
1006
if (strcmp (pSvc->m_pszSvcName, pszServiceName) == 0)
1011
pSvc = pSvc->m_pSvcNext;
1014
LogFlowFunc(("lookup in the list is %p\n", pSvc));
1019
return VERR_HGCM_SERVICE_NOT_FOUND;
1022
pSvc->ReferenceService ();
1026
return VINF_SUCCESS;
1029
/** The method increases reference counter.
1033
void HGCMService::ReferenceService (void)
1035
ASMAtomicIncU32 (&m_u32RefCnt);
1036
LogFlowFunc(("[%s] m_u32RefCnt = %d\n", m_pszSvcName, m_u32RefCnt));
1039
/** The method dereferences a service and deletes it when no more refs.
1043
void HGCMService::ReleaseService (void)
1045
LogFlowFunc(("m_u32RefCnt = %d\n", m_u32RefCnt));
1046
uint32_t u32RefCnt = ASMAtomicDecU32 (&m_u32RefCnt);
1047
AssertRelease(u32RefCnt != ~0U);
1049
LogFlowFunc(("u32RefCnt = %d, name %s\n", u32RefCnt, m_pszSvcName));
1058
/** The method is called when the VM is being reset or terminated
1059
* and disconnects all clients from all services.
1063
/* static */ void HGCMService::Reset (void)
1065
g_fResetting = true;
1067
HGCMService *pSvc = sm_pSvcListHead;
1071
while (pSvc->m_cClients && pSvc->m_paClientIds)
1073
LogFlowFunc(("handle %d\n", pSvc->m_paClientIds[0]));
1074
pSvc->DisconnectClient (pSvc->m_paClientIds[0], false);
1077
pSvc = pSvc->m_pSvcNext;
1080
g_fResetting = false;
1083
/** The method saves the HGCM state.
1085
* @param pSSM The saved state context.
1089
/* static */ int HGCMService::SaveState (PSSMHANDLE pSSM)
1091
/* Save the current handle count and restore afterwards to avoid client id conflicts. */
1092
int rc = SSMR3PutU32(pSSM, hgcmObjQueryHandleCount());
1093
AssertRCReturn(rc, rc);
1095
LogFlowFunc(("%d services to be saved:\n", sm_cServices));
1097
/* Save number of services. */
1098
rc = SSMR3PutU32(pSSM, sm_cServices);
1099
AssertRCReturn(rc, rc);
1101
/* Save every service. */
1102
HGCMService *pSvc = sm_pSvcListHead;
1106
LogFlowFunc(("Saving service [%s]\n", pSvc->m_pszSvcName));
1108
/* Save the length of the service name. */
1109
rc = SSMR3PutU32(pSSM, (uint32_t) strlen(pSvc->m_pszSvcName) + 1);
1110
AssertRCReturn(rc, rc);
1112
/* Save the name of the service. */
1113
rc = SSMR3PutStrZ(pSSM, pSvc->m_pszSvcName);
1114
AssertRCReturn(rc, rc);
1116
/* Save the number of clients. */
1117
rc = SSMR3PutU32(pSSM, pSvc->m_cClients);
1118
AssertRCReturn(rc, rc);
1120
/* Call the service for every client. Normally a service must not have
1121
* a global state to be saved: only per client info is relevant.
1122
* The global state of a service is configured during VM startup.
1126
for (i = 0; i < pSvc->m_cClients; i++)
1128
uint32_t u32ClientId = pSvc->m_paClientIds[i];
1130
Log(("client id 0x%08X\n", u32ClientId));
1132
/* Save the client id. */
1133
rc = SSMR3PutU32(pSSM, u32ClientId);
1134
AssertRCReturn(rc, rc);
1136
/* Call the service, so the operation is executed by the service thread. */
1137
rc = pSvc->saveClientState (u32ClientId, pSSM);
1138
AssertRCReturn(rc, rc);
1141
pSvc = pSvc->m_pSvcNext;
1144
return VINF_SUCCESS;
1147
/** The method loads saved HGCM state.
1149
* @param pSSM The saved state context.
1153
/* static */ int HGCMService::LoadState (PSSMHANDLE pSSM)
1155
/* Restore handle count to avoid client id conflicts. */
1158
int rc = SSMR3GetU32(pSSM, &u32);
1159
AssertRCReturn(rc, rc);
1161
hgcmObjSetHandleCount(u32);
1163
/* Get the number of services. */
1166
rc = SSMR3GetU32(pSSM, &cServices);
1167
AssertRCReturn(rc, rc);
1169
LogFlowFunc(("%d services to be restored:\n", cServices));
1173
/* Get the length of the service name. */
1174
rc = SSMR3GetU32(pSSM, &u32);
1175
AssertRCReturn(rc, rc);
1176
AssertReturn(u32 <= VBOX_HGCM_SVC_NAME_MAX_BYTES, VERR_SSM_UNEXPECTED_DATA);
1178
char *pszServiceName = (char *)alloca (u32);
1180
/* Get the service name. */
1181
rc = SSMR3GetStrZ(pSSM, pszServiceName, u32);
1182
AssertRCReturn(rc, rc);
1184
LogRel(("HGCM: restoring [%s]\n", pszServiceName));
1186
/* Resolve the service instance. */
1188
rc = ResolveService (&pSvc, pszServiceName);
1189
AssertLogRelMsgReturn(pSvc, ("rc=%Rrc, %s\n", rc, pszServiceName), VERR_SSM_UNEXPECTED_DATA);
1191
/* Get the number of clients. */
1193
rc = SSMR3GetU32(pSSM, &cClients);
1196
pSvc->ReleaseService ();
1203
/* Get the client id. */
1204
uint32_t u32ClientId;
1205
rc = SSMR3GetU32(pSSM, &u32ClientId);
1208
pSvc->ReleaseService ();
1213
/* Connect the client. */
1214
rc = pSvc->CreateAndConnectClient (NULL, u32ClientId);
1217
pSvc->ReleaseService ();
1218
AssertLogRelMsgFailed(("rc=%Rrc %s\n", rc, pszServiceName));
1222
/* Call the service, so the operation is executed by the service thread. */
1223
rc = pSvc->loadClientState (u32ClientId, pSSM);
1226
pSvc->ReleaseService ();
1227
AssertLogRelMsgFailed(("rc=%Rrc %s\n", rc, pszServiceName));
1232
pSvc->ReleaseService ();
1235
return VINF_SUCCESS;
1238
/* Create a new client instance and connect it to the service.
1240
* @param pu32ClientIdOut If not NULL, then the method must generate a new handle for the client.
1241
* If NULL, use the given 'u32ClientIdIn' handle.
1242
* @param u32ClientIdIn The handle for the client, when 'pu32ClientIdOut' is NULL.
1245
int HGCMService::CreateAndConnectClient (uint32_t *pu32ClientIdOut, uint32_t u32ClientIdIn)
1247
LogFlowFunc(("pu32ClientIdOut = %p, u32ClientIdIn = %d\n", pu32ClientIdOut, u32ClientIdIn));
1249
/* Allocate a client information structure. */
1250
HGCMClient *pClient = new HGCMClient ();
1254
LogWarningFunc(("Could not allocate HGCMClient!!!\n"));
1255
return VERR_NO_MEMORY;
1260
if (pu32ClientIdOut != NULL)
1262
handle = hgcmObjGenerateHandle (pClient);
1266
handle = hgcmObjAssignHandle (pClient, u32ClientIdIn);
1269
LogFlowFunc(("client id = %d\n", handle));
1271
AssertRelease(handle);
1273
/* Initialize the HGCM part of the client. */
1274
int rc = pClient->Init (this);
1278
/* Call the service. */
1281
rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_CONNECT, hgcmMessageAllocSvc);
1285
HGCMMsgSvcConnect *pMsg = (HGCMMsgSvcConnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1286
AssertRelease(pMsg);
1288
pMsg->u32ClientId = handle;
1290
hgcmObjDereference (pMsg);
1292
rc = hgcmMsgSend (hMsg);
1296
/* Add the client Id to the array. */
1297
if (m_cClients == m_cClientsAllocated)
1299
m_paClientIds = (uint32_t *)RTMemRealloc (m_paClientIds, (m_cClientsAllocated + 64) * sizeof (m_paClientIds[0]));
1300
Assert(m_paClientIds);
1301
m_cClientsAllocated += 64;
1304
m_paClientIds[m_cClients] = handle;
1312
hgcmObjDeleteHandle (handle);
1316
if (pu32ClientIdOut != NULL)
1318
*pu32ClientIdOut = handle;
1321
ReferenceService ();
1324
LogFlowFunc(("rc = %Rrc\n", rc));
1328
/* Disconnect the client from the service and delete the client handle.
1330
* @param u32ClientId The handle of the client.
1333
int HGCMService::DisconnectClient (uint32_t u32ClientId, bool fFromService)
1335
int rc = VINF_SUCCESS;
1337
LogFlowFunc(("client id = %d, fFromService = %d\n", u32ClientId, fFromService));
1341
/* Call the service. */
1344
rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_DISCONNECT, hgcmMessageAllocSvc);
1348
HGCMMsgSvcDisconnect *pMsg = (HGCMMsgSvcDisconnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1349
AssertRelease(pMsg);
1351
pMsg->u32ClientId = u32ClientId;
1353
hgcmObjDereference (pMsg);
1355
rc = hgcmMsgSend (hMsg);
1359
LogRel(("(%d, %d) [%s] hgcmMsgAlloc(%p, SVC_MSG_DISCONNECT) failed %Rrc\n",
1360
u32ClientId, fFromService, RT_VALID_PTR(m_pszSvcName)? m_pszSvcName: "", m_thread, rc));
1364
/* Remove the client id from the array in any case, rc does not matter. */
1367
for (i = 0; i < m_cClients; i++)
1369
if (m_paClientIds[i] == u32ClientId)
1375
memmove (&m_paClientIds[i], &m_paClientIds[i + 1], sizeof (m_paClientIds[0]) * (m_cClients - i));
1378
/* Delete the client handle. */
1379
hgcmObjDeleteHandle (u32ClientId);
1381
/* The service must be released. */
1388
LogFlowFunc(("rc = %Rrc\n", rc));
1392
int HGCMService::RegisterExtension (HGCMSVCEXTHANDLE handle,
1393
PFNHGCMSVCEXT pfnExtension,
1396
LogFlowFunc(("%s\n", handle->pszServiceName));
1398
/* Forward the message to the service thread. */
1399
HGCMMSGHANDLE hMsg = 0;
1400
int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_REGEXT, hgcmMessageAllocSvc);
1404
HGCMMsgSvcRegisterExtension *pMsg = (HGCMMsgSvcRegisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1405
AssertRelease(pMsg);
1407
pMsg->handle = handle;
1408
pMsg->pfnExtension = pfnExtension;
1409
pMsg->pvExtension = pvExtension;
1411
hgcmObjDereference (pMsg);
1413
rc = hgcmMsgSend (hMsg);
1416
LogFlowFunc(("rc = %Rrc\n", rc));
1420
void HGCMService::UnregisterExtension (HGCMSVCEXTHANDLE handle)
1422
/* Forward the message to the service thread. */
1423
HGCMMSGHANDLE hMsg = 0;
1424
int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_UNREGEXT, hgcmMessageAllocSvc);
1428
HGCMMsgSvcUnregisterExtension *pMsg = (HGCMMsgSvcUnregisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1429
AssertRelease(pMsg);
1431
pMsg->handle = handle;
1433
hgcmObjDereference (pMsg);
1435
rc = hgcmMsgSend (hMsg);
1438
LogFlowFunc(("rc = %Rrc\n", rc));
1441
/* Perform a guest call to the service.
1443
* @param pHGCMPort The port to be used for completion confirmation.
1444
* @param pCmd The VBox HGCM context.
1445
* @param u32ClientId The client handle to be disconnected and deleted.
1446
* @param u32Function The function number.
1447
* @param cParms Number of parameters.
1448
* @param paParms Pointer to array of parameters.
1451
int HGCMService::GuestCall (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1453
HGCMMSGHANDLE hMsg = 0;
1455
LogFlow(("MAIN::HGCMService::Call\n"));
1457
int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_GUESTCALL, hgcmMessageAllocSvc);
1461
HGCMMsgCall *pMsg = (HGCMMsgCall *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1463
AssertRelease(pMsg);
1466
pMsg->pHGCMPort = pHGCMPort;
1468
pMsg->u32ClientId = u32ClientId;
1469
pMsg->u32Function = u32Function;
1470
pMsg->cParms = cParms;
1471
pMsg->paParms = paParms;
1473
hgcmObjDereference (pMsg);
1475
rc = hgcmMsgPost (hMsg, hgcmMsgCompletionCallback);
1479
Log(("MAIN::HGCMService::Call: Message allocation failed: %Rrc\n", rc));
1482
LogFlowFunc(("rc = %Rrc\n", rc));
1486
/* Perform a host call the service.
1488
* @param u32Function The function number.
1489
* @param cParms Number of parameters.
1490
* @param paParms Pointer to array of parameters.
1493
int HGCMService::HostCall (uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM *paParms)
1495
LogFlowFunc(("%s u32Function = %d, cParms = %d, paParms = %p\n",
1496
m_pszSvcName, u32Function, cParms, paParms));
1498
HGCMMSGHANDLE hMsg = 0;
1499
int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_HOSTCALL, hgcmMessageAllocSvc);
1503
HGCMMsgHostCallSvc *pMsg = (HGCMMsgHostCallSvc *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1504
AssertRelease(pMsg);
1506
pMsg->u32Function = u32Function;
1507
pMsg->cParms = cParms;
1508
pMsg->paParms = paParms;
1510
hgcmObjDereference (pMsg);
1512
rc = hgcmMsgSend (hMsg);
1515
LogFlowFunc(("rc = %Rrc\n", rc));
1521
* Main HGCM thread that manages services.
1524
/* Messages processed by the main HGCM thread. */
1525
#define HGCM_MSG_CONNECT (10) /* Connect a client to a service. */
1526
#define HGCM_MSG_DISCONNECT (11) /* Disconnect the specified client id. */
1527
#define HGCM_MSG_LOAD (12) /* Load the service. */
1528
#define HGCM_MSG_HOSTCALL (13) /* Call the service. */
1529
#define HGCM_MSG_LOADSTATE (14) /* Load saved state for the specified service. */
1530
#define HGCM_MSG_SAVESTATE (15) /* Save state for the specified service. */
1531
#define HGCM_MSG_RESET (16) /* Disconnect all clients from the specified service. */
1532
#define HGCM_MSG_QUIT (17) /* Unload all services and terminate the thread. */
1533
#define HGCM_MSG_REGEXT (18) /* Register a service extension. */
1534
#define HGCM_MSG_UNREGEXT (19) /* Unregister a service extension. */
1536
class HGCMMsgMainConnect: public HGCMMsgHeader
1540
const char *pszServiceName;
1541
/* Where to store the client handle. */
1542
uint32_t *pu32ClientId;
1545
class HGCMMsgMainDisconnect: public HGCMMsgHeader
1548
/* Handle of the client to be disconnected. */
1549
uint32_t u32ClientId;
1552
class HGCMMsgMainLoad: public HGCMMsgCore
1555
/* Name of the library to be loaded. */
1556
const char *pszServiceLibrary;
1557
/* Name to be assigned to the service. */
1558
const char *pszServiceName;
1561
class HGCMMsgMainHostCall: public HGCMMsgCore
1564
/* Which service to call. */
1565
const char *pszServiceName;
1566
/* Function number. */
1567
uint32_t u32Function;
1568
/* Number of the function parameters. */
1570
/* Pointer to array of the function parameters. */
1571
VBOXHGCMSVCPARM *paParms;
1574
class HGCMMsgMainLoadSaveState: public HGCMMsgCore
1581
class HGCMMsgMainReset: public HGCMMsgCore
1585
class HGCMMsgMainQuit: public HGCMMsgCore
1589
class HGCMMsgMainRegisterExtension: public HGCMMsgCore
1592
/* Returned handle to be used in HGCMMsgMainUnregisterExtension. */
1593
HGCMSVCEXTHANDLE *pHandle;
1594
/* Name of the service. */
1595
const char *pszServiceName;
1596
/* The extension entry point. */
1597
PFNHGCMSVCEXT pfnExtension;
1598
/* The extension pointer. */
1602
class HGCMMsgMainUnregisterExtension: public HGCMMsgCore
1605
/* Handle of the registered extension. */
1606
HGCMSVCEXTHANDLE handle;
1609
static HGCMMsgCore *hgcmMainMessageAlloc (uint32_t u32MsgId)
1613
case HGCM_MSG_CONNECT: return new HGCMMsgMainConnect ();
1614
case HGCM_MSG_DISCONNECT: return new HGCMMsgMainDisconnect ();
1615
case HGCM_MSG_LOAD: return new HGCMMsgMainLoad ();
1616
case HGCM_MSG_HOSTCALL: return new HGCMMsgMainHostCall ();
1617
case HGCM_MSG_LOADSTATE:
1618
case HGCM_MSG_SAVESTATE: return new HGCMMsgMainLoadSaveState ();
1619
case HGCM_MSG_RESET: return new HGCMMsgMainReset ();
1620
case HGCM_MSG_QUIT: return new HGCMMsgMainQuit ();
1621
case HGCM_MSG_REGEXT: return new HGCMMsgMainRegisterExtension ();
1622
case HGCM_MSG_UNREGEXT: return new HGCMMsgMainUnregisterExtension ();
1624
AssertReleaseMsgFailed(("Msg id = %08X\n", u32MsgId));
1631
/* The main HGCM thread handler. */
1632
static DECLCALLBACK(void) hgcmThread (HGCMTHREADHANDLE ThreadHandle, void *pvUser)
1634
LogFlowFunc(("ThreadHandle = %p, pvUser = %p\n",
1635
ThreadHandle, pvUser));
1643
HGCMMsgCore *pMsgCore;
1644
int rc = hgcmMsgGet (ThreadHandle, &pMsgCore);
1648
/* The error means some serious unrecoverable problem in the hgcmMsg/hgcmThread layer. */
1649
AssertMsgFailed (("%Rrc\n", rc));
1653
uint32_t u32MsgId = pMsgCore->MsgId ();
1657
case HGCM_MSG_CONNECT:
1659
HGCMMsgMainConnect *pMsg = (HGCMMsgMainConnect *)pMsgCore;
1661
LogFlowFunc(("HGCM_MSG_CONNECT pszServiceName %s, pu32ClientId %p\n",
1662
pMsg->pszServiceName, pMsg->pu32ClientId));
1664
/* Resolve the service name to the pointer to service instance.
1666
HGCMService *pService;
1667
rc = HGCMService::ResolveService (&pService, pMsg->pszServiceName);
1671
/* Call the service instance method. */
1672
rc = pService->CreateAndConnectClient (pMsg->pu32ClientId, 0);
1674
/* Release the service after resolve. */
1675
pService->ReleaseService ();
1679
case HGCM_MSG_DISCONNECT:
1681
HGCMMsgMainDisconnect *pMsg = (HGCMMsgMainDisconnect *)pMsgCore;
1683
LogFlowFunc(("HGCM_MSG_DISCONNECT u32ClientId = %d\n",
1684
pMsg->u32ClientId));
1686
HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
1690
rc = VERR_HGCM_INVALID_CLIENT_ID;
1694
/* The service the client belongs to. */
1695
HGCMService *pService = pClient->pService;
1697
/* Call the service instance to disconnect the client. */
1698
rc = pService->DisconnectClient (pMsg->u32ClientId, false);
1700
hgcmObjDereference (pClient);
1705
HGCMMsgMainLoad *pMsg = (HGCMMsgMainLoad *)pMsgCore;
1707
LogFlowFunc(("HGCM_MSG_LOAD pszServiceName = %s, pMsg->pszServiceLibrary = %s\n",
1708
pMsg->pszServiceName, pMsg->pszServiceLibrary));
1710
rc = HGCMService::LoadService (pMsg->pszServiceLibrary, pMsg->pszServiceName);
1713
case HGCM_MSG_HOSTCALL:
1715
HGCMMsgMainHostCall *pMsg = (HGCMMsgMainHostCall *)pMsgCore;
1717
LogFlowFunc(("HGCM_MSG_HOSTCALL pszServiceName %s, u32Function %d, cParms %d, paParms %p\n",
1718
pMsg->pszServiceName, pMsg->u32Function, pMsg->cParms, pMsg->paParms));
1720
/* Resolve the service name to the pointer to service instance. */
1721
HGCMService *pService;
1722
rc = HGCMService::ResolveService (&pService, pMsg->pszServiceName);
1726
rc = pService->HostCall (pMsg->u32Function, pMsg->cParms, pMsg->paParms);
1728
pService->ReleaseService ();
1732
case HGCM_MSG_RESET:
1734
LogFlowFunc(("HGCM_MSG_RESET\n"));
1736
HGCMService::Reset ();
1739
case HGCM_MSG_LOADSTATE:
1741
HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pMsgCore;
1743
LogFlowFunc(("HGCM_MSG_LOADSTATE\n"));
1745
rc = HGCMService::LoadState (pMsg->pSSM);
1748
case HGCM_MSG_SAVESTATE:
1750
HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pMsgCore;
1752
LogFlowFunc(("HGCM_MSG_SAVESTATE\n"));
1754
rc = HGCMService::SaveState (pMsg->pSSM);
1759
LogFlowFunc(("HGCM_MSG_QUIT\n"));
1761
HGCMService::UnloadAll ();
1766
case HGCM_MSG_REGEXT:
1768
HGCMMsgMainRegisterExtension *pMsg = (HGCMMsgMainRegisterExtension *)pMsgCore;
1770
LogFlowFunc(("HGCM_MSG_REGEXT\n"));
1772
/* Allocate the handle data. */
1773
HGCMSVCEXTHANDLE handle = (HGCMSVCEXTHANDLE)RTMemAllocZ (sizeof (struct _HGCMSVCEXTHANDLEDATA)
1774
+ strlen (pMsg->pszServiceName)
1779
rc = VERR_NO_MEMORY;
1783
handle->pszServiceName = (char *)((uint8_t *)handle + sizeof (struct _HGCMSVCEXTHANDLEDATA));
1784
strcpy (handle->pszServiceName, pMsg->pszServiceName);
1786
HGCMService *pService;
1787
rc = HGCMService::ResolveService (&pService, handle->pszServiceName);
1791
pService->RegisterExtension (handle, pMsg->pfnExtension, pMsg->pvExtension);
1793
pService->ReleaseService ();
1802
*pMsg->pHandle = handle;
1807
case HGCM_MSG_UNREGEXT:
1809
HGCMMsgMainUnregisterExtension *pMsg = (HGCMMsgMainUnregisterExtension *)pMsgCore;
1811
LogFlowFunc(("HGCM_MSG_UNREGEXT\n"));
1813
HGCMService *pService;
1814
rc = HGCMService::ResolveService (&pService, pMsg->handle->pszServiceName);
1818
pService->UnregisterExtension (pMsg->handle);
1820
pService->ReleaseService ();
1823
RTMemFree (pMsg->handle);
1828
AssertMsgFailed(("hgcmThread: Unsupported message number %08X!!!\n", u32MsgId));
1829
rc = VERR_NOT_SUPPORTED;
1833
/* Complete the message processing. */
1834
hgcmMsgComplete (pMsgCore, rc);
1836
LogFlowFunc(("message processed %Rrc\n", rc));
1845
/* The main hgcm thread. */
1846
static HGCMTHREADHANDLE g_hgcmThread = 0;
1849
* Public HGCM functions.
1851
* hgcmGuest* - called as a result of the guest HGCM requests.
1852
* hgcmHost* - called by the host.
1855
/* Load a HGCM service from the specified library.
1856
* Assign the specified name to the service.
1858
* @param pszServiceLibrary The library to be loaded.
1859
* @param pszServiceName The name to be assigned to the service.
1862
int HGCMHostLoad (const char *pszServiceLibrary,
1863
const char *pszServiceName)
1865
LogFlowFunc(("lib = %s, name = %s\n", pszServiceLibrary, pszServiceName));
1867
if (!pszServiceLibrary || !pszServiceName)
1869
return VERR_INVALID_PARAMETER;
1872
/* Forward the request to the main hgcm thread. */
1873
HGCMMSGHANDLE hMsg = 0;
1875
int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_LOAD, hgcmMainMessageAlloc);
1879
/* Initialize the message. Since the message is synchronous, use the supplied pointers. */
1880
HGCMMsgMainLoad *pMsg = (HGCMMsgMainLoad *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1881
AssertRelease(pMsg);
1883
pMsg->pszServiceLibrary = pszServiceLibrary;
1884
pMsg->pszServiceName = pszServiceName;
1886
hgcmObjDereference (pMsg);
1888
rc = hgcmMsgSend (hMsg);
1891
LogFlowFunc(("rc = %Rrc\n", rc));
1895
/* Register a HGCM service extension.
1897
* @param pHandle Returned handle for the registered extension.
1898
* @param pszServiceName The name of the service.
1899
* @param pfnExtension The extension entry point (callback).
1900
* @param pvExtension The extension pointer.
1903
int HGCMHostRegisterServiceExtension (HGCMSVCEXTHANDLE *pHandle,
1904
const char *pszServiceName,
1905
PFNHGCMSVCEXT pfnExtension,
1908
LogFlowFunc(("pHandle = %p, name = %s, pfn = %p, rv = %p\n", pHandle, pszServiceName, pfnExtension, pvExtension));
1910
if (!pHandle || !pszServiceName || !pfnExtension)
1912
return VERR_INVALID_PARAMETER;
1915
/* Forward the request to the main hgcm thread. */
1916
HGCMMSGHANDLE hMsg = 0;
1918
int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_REGEXT, hgcmMainMessageAlloc);
1922
/* Initialize the message. Since the message is synchronous, use the supplied pointers. */
1923
HGCMMsgMainRegisterExtension *pMsg = (HGCMMsgMainRegisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1924
AssertRelease(pMsg);
1926
pMsg->pHandle = pHandle;
1927
pMsg->pszServiceName = pszServiceName;
1928
pMsg->pfnExtension = pfnExtension;
1929
pMsg->pvExtension = pvExtension;
1931
hgcmObjDereference (pMsg);
1933
rc = hgcmMsgSend (hMsg);
1936
LogFlowFunc(("*pHandle = %p, rc = %Rrc\n", *pHandle, rc));
1940
void HGCMHostUnregisterServiceExtension (HGCMSVCEXTHANDLE handle)
1942
LogFlowFunc(("handle = %p\n", handle));
1944
/* Forward the request to the main hgcm thread. */
1945
HGCMMSGHANDLE hMsg = 0;
1947
int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_UNREGEXT, hgcmMainMessageAlloc);
1951
/* Initialize the message. */
1952
HGCMMsgMainUnregisterExtension *pMsg = (HGCMMsgMainUnregisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1953
AssertRelease(pMsg);
1955
pMsg->handle = handle;
1957
hgcmObjDereference (pMsg);
1959
rc = hgcmMsgSend (hMsg);
1962
LogFlowFunc(("rc = %Rrc\n", rc));
1966
/* Find a service and inform it about a client connection, create a client handle.
1968
* @param pHGCMPort The port to be used for completion confirmation.
1969
* @param pCmd The VBox HGCM context.
1970
* @param pszServiceName The name of the service to be connected to.
1971
* @param pu32ClientId Where the store the created client handle.
1974
int HGCMGuestConnect (PPDMIHGCMPORT pHGCMPort,
1976
const char *pszServiceName,
1977
uint32_t *pu32ClientId)
1979
LogFlowFunc(("pHGCMPort = %p, pCmd = %p, name = %s, pu32ClientId = %p\n",
1980
pHGCMPort, pCmd, pszServiceName, pu32ClientId));
1982
if (pHGCMPort == NULL || pCmd == NULL || pszServiceName == NULL || pu32ClientId == NULL)
1984
return VERR_INVALID_PARAMETER;
1987
/* Forward the request to the main hgcm thread. */
1988
HGCMMSGHANDLE hMsg = 0;
1990
int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_CONNECT, hgcmMainMessageAlloc);
1994
/* Initialize the message. Since 'pszServiceName' and 'pu32ClientId'
1995
* will not be deallocated by the caller until the message is completed,
1996
* use the supplied pointers.
1998
HGCMMsgMainConnect *pMsg = (HGCMMsgMainConnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1999
AssertRelease(pMsg);
2001
pMsg->pHGCMPort = pHGCMPort;
2003
pMsg->pszServiceName = pszServiceName;
2004
pMsg->pu32ClientId = pu32ClientId;
2006
hgcmObjDereference (pMsg);
2008
rc = hgcmMsgPost (hMsg, hgcmMsgCompletionCallback);
2011
LogFlowFunc(("rc = %Rrc\n", rc));
2015
/* Tell a service that the client is disconnecting, destroy the client handle.
2017
* @param pHGCMPort The port to be used for completion confirmation.
2018
* @param pCmd The VBox HGCM context.
2019
* @param u32ClientId The client handle to be disconnected and deleted.
2022
int HGCMGuestDisconnect (PPDMIHGCMPORT pHGCMPort,
2024
uint32_t u32ClientId)
2026
LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d\n",
2027
pHGCMPort, pCmd, u32ClientId));
2029
if (!pHGCMPort || !pCmd || !u32ClientId)
2031
return VERR_INVALID_PARAMETER;
2034
/* Forward the request to the main hgcm thread. */
2035
HGCMMSGHANDLE hMsg = 0;
2037
int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_DISCONNECT, hgcmMainMessageAlloc);
2041
/* Initialize the message. */
2042
HGCMMsgMainDisconnect *pMsg = (HGCMMsgMainDisconnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2043
AssertRelease(pMsg);
2046
pMsg->pHGCMPort = pHGCMPort;
2047
pMsg->u32ClientId = u32ClientId;
2049
hgcmObjDereference (pMsg);
2051
rc = hgcmMsgPost (hMsg, hgcmMsgCompletionCallback);
2054
LogFlowFunc(("rc = %Rrc\n", rc));
2058
/* Helper to send either HGCM_MSG_SAVESTATE or HGCM_MSG_LOADSTATE messages to the main HGCM thread.
2060
* @param pSSM The SSM handle.
2061
* @param u32MsgId The message to be sent: HGCM_MSG_SAVESTATE or HGCM_MSG_LOADSTATE.
2064
static int hgcmHostLoadSaveState (PSSMHANDLE pSSM,
2067
LogFlowFunc(("pSSM = %p, u32MsgId = %d\n", pSSM, u32MsgId));
2069
HGCMMSGHANDLE hMsg = 0;
2071
int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, u32MsgId, hgcmMainMessageAlloc);
2075
HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2076
AssertRelease(pMsg);
2080
hgcmObjDereference (pMsg);
2082
rc = hgcmMsgSend (hMsg);
2085
LogFlowFunc(("rc = %Rrc\n", rc));
2089
/* Save the state of services.
2091
* @param pSSM The SSM handle.
2094
int HGCMHostSaveState (PSSMHANDLE pSSM)
2096
return hgcmHostLoadSaveState (pSSM, HGCM_MSG_SAVESTATE);
2099
/* Load the state of services.
2101
* @param pSSM The SSM handle.
2104
int HGCMHostLoadState (PSSMHANDLE pSSM)
2106
return hgcmHostLoadSaveState (pSSM, HGCM_MSG_LOADSTATE);
2109
/* The guest calls the service.
2111
* @param pHGCMPort The port to be used for completion confirmation.
2112
* @param pCmd The VBox HGCM context.
2113
* @param u32ClientId The client handle to be disconnected and deleted.
2114
* @param u32Function The function number.
2115
* @param cParms Number of parameters.
2116
* @param paParms Pointer to array of parameters.
2119
int HGCMGuestCall (PPDMIHGCMPORT pHGCMPort,
2121
uint32_t u32ClientId,
2122
uint32_t u32Function,
2124
VBOXHGCMSVCPARM *paParms)
2126
LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d, u32Function = %d, cParms = %d, paParms = %p\n",
2127
pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms));
2129
if (!pHGCMPort || !pCmd || u32ClientId == 0)
2131
return VERR_INVALID_PARAMETER;
2134
int rc = VERR_HGCM_INVALID_CLIENT_ID;
2136
/* Resolve the client handle to the client instance pointer. */
2137
HGCMClient *pClient = (HGCMClient *)hgcmObjReference (u32ClientId, HGCMOBJ_CLIENT);
2141
AssertRelease(pClient->pService);
2143
/* Forward the message to the service thread. */
2144
rc = pClient->pService->GuestCall (pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms);
2146
hgcmObjDereference (pClient);
2149
LogFlowFunc(("rc = %Rrc\n", rc));
2153
/* The host calls the service.
2155
* @param pszServiceName The service name to be called.
2156
* @param u32Function The function number.
2157
* @param cParms Number of parameters.
2158
* @param paParms Pointer to array of parameters.
2161
int HGCMHostCall (const char *pszServiceName,
2162
uint32_t u32Function,
2164
VBOXHGCMSVCPARM *paParms)
2166
LogFlowFunc(("name = %s, u32Function = %d, cParms = %d, paParms = %p\n",
2167
pszServiceName, u32Function, cParms, paParms));
2169
if (!pszServiceName)
2171
return VERR_INVALID_PARAMETER;
2174
HGCMMSGHANDLE hMsg = 0;
2176
/* Host calls go to main HGCM thread that resolves the service name to the
2177
* service instance pointer and then, using the service pointer, forwards
2178
* the message to the service thread.
2179
* So it is slow but host calls are intended mostly for configuration and
2180
* other non-time-critical functions.
2182
int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_HOSTCALL, hgcmMainMessageAlloc);
2186
HGCMMsgMainHostCall *pMsg = (HGCMMsgMainHostCall *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2187
AssertRelease(pMsg);
2189
pMsg->pszServiceName = (char *)pszServiceName;
2190
pMsg->u32Function = u32Function;
2191
pMsg->cParms = cParms;
2192
pMsg->paParms = paParms;
2194
hgcmObjDereference (pMsg);
2196
rc = hgcmMsgSend (hMsg);
2199
LogFlowFunc(("rc = %Rrc\n", rc));
2203
int HGCMHostReset (void)
2205
LogFlowFunc(("\n"));
2207
/* Disconnect all clients.
2210
HGCMMSGHANDLE hMsg = 0;
2212
int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_RESET, hgcmMainMessageAlloc);
2216
rc = hgcmMsgSend (hMsg);
2219
LogFlowFunc(("rc = %Rrc\n", rc));
2223
int HGCMHostInit (void)
2225
LogFlowFunc(("\n"));
2227
int rc = hgcmThreadInit ();
2232
* Start main HGCM thread.
2235
rc = hgcmThreadCreate (&g_hgcmThread, "MainHGCMthread", hgcmThread, NULL);
2239
LogRel(("Failed to start HGCM thread. HGCM services will be unavailable!!! rc = %Rrc\n", rc));
2243
LogFlowFunc(("rc = %Rrc\n", rc));
2247
int HGCMHostShutdown (void)
2249
LogFlowFunc(("\n"));
2252
* Do HGCMReset and then unload all services.
2255
int rc = HGCMHostReset ();
2259
/* Send the quit message to the main hgcmThread. */
2260
HGCMMSGHANDLE hMsg = 0;
2262
rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_QUIT, hgcmMainMessageAlloc);
2266
rc = hgcmMsgSend (hMsg);
2270
/* Wait for the thread termination. */
2271
hgcmThreadWait (g_hgcmThread);
2274
hgcmThreadUninit ();
2279
LogFlowFunc(("rc = %Rrc\n", rc));