VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/HGCM.cpp@ 75541

Last change on this file since 75541 was 75541, checked in by vboxsync, 7 years ago

Main/HGCM: Skip the handle stuff for the HGCMMsgCore class, it just add overhead. bugref:9172

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 77.3 KB
Line 
1/* $Id: HGCM.cpp 75541 2018-11-17 03:50:40Z vboxsync $ */
2/** @file
3 * HGCM (Host-Guest Communication Manager)
4 */
5
6/*
7 * Copyright (C) 2006-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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.
16 */
17
18#define LOG_GROUP LOG_GROUP_HGCM
19#include "LoggingNew.h"
20
21#include "HGCM.h"
22#include "HGCMThread.h"
23
24#include <VBox/err.h>
25#include <VBox/hgcmsvc.h>
26#include <VBox/vmm/ssm.h>
27#include <VBox/vmm/stam.h>
28#include <VBox/sup.h>
29
30#include <iprt/alloc.h>
31#include <iprt/avl.h>
32#include <iprt/critsect.h>
33#include <iprt/asm.h>
34#include <iprt/ldr.h>
35#include <iprt/param.h>
36#include <iprt/path.h>
37#include <iprt/string.h>
38#include <iprt/semaphore.h>
39#include <iprt/thread.h>
40
41#include <VBox/VMMDev.h>
42#include <new>
43
44/**
45 * A service gets one thread, which synchronously delivers messages to
46 * the service. This is good for serialization.
47 *
48 * Some services may want to process messages asynchronously, and will want
49 * a next message to be delivered, while a previous message is still being
50 * processed.
51 *
52 * The dedicated service thread delivers a next message when service
53 * returns after fetching a previous one. The service will call a message
54 * completion callback when message is actually processed. So returning
55 * from the service call means only that the service is processing message.
56 *
57 * 'Message processed' condition is indicated by service, which call the
58 * callback, even if the callback is called synchronously in the dedicated
59 * thread.
60 *
61 * This message completion callback is only valid for Call requests.
62 * Connect and Disconnect are processed synchronously by the service.
63 */
64
65
66/* The maximum allowed size of a service name in bytes. */
67#define VBOX_HGCM_SVC_NAME_MAX_BYTES 1024
68
69struct _HGCMSVCEXTHANDLEDATA
70{
71 char *pszServiceName;
72 /* The service name follows. */
73};
74
75/** Internal helper service object. HGCM code would use it to
76 * hold information about services and communicate with services.
77 * The HGCMService is an (in future) abstract class that implements
78 * common functionality. There will be derived classes for specific
79 * service types.
80 */
81
82class HGCMService
83{
84 private:
85 VBOXHGCMSVCHELPERS m_svcHelpers;
86
87 static HGCMService *sm_pSvcListHead;
88 static HGCMService *sm_pSvcListTail;
89
90 static int sm_cServices;
91
92 HGCMThread *m_pThread;
93 friend DECLCALLBACK(void) hgcmServiceThread(HGCMThread *pThread, void *pvUser);
94
95 uint32_t volatile m_u32RefCnt;
96
97 HGCMService *m_pSvcNext;
98 HGCMService *m_pSvcPrev;
99
100 char *m_pszSvcName;
101 char *m_pszSvcLibrary;
102
103 RTLDRMOD m_hLdrMod;
104 PFNVBOXHGCMSVCLOAD m_pfnLoad;
105
106 VBOXHGCMSVCFNTABLE m_fntable;
107
108 uint32_t m_cClients;
109 uint32_t m_cClientsAllocated;
110
111 uint32_t *m_paClientIds;
112
113#ifdef VBOX_WITH_CRHGSMI
114 uint32_t m_cHandleAcquires;
115#endif
116
117 HGCMSVCEXTHANDLE m_hExtension;
118
119 PUVM m_pUVM;
120
121 /** @name Statistics
122 * @{ */
123 STAMPROFILE m_StatHandleMsg;
124 /** @} */
125
126 int loadServiceDLL(void);
127 void unloadServiceDLL(void);
128
129 /*
130 * Main HGCM thread methods.
131 */
132 int instanceCreate(const char *pszServiceLibrary, const char *pszServiceName, PUVM pUVM);
133 void instanceDestroy(void);
134
135 int saveClientState(uint32_t u32ClientId, PSSMHANDLE pSSM);
136 int loadClientState(uint32_t u32ClientId, PSSMHANDLE pSSM);
137
138 HGCMService();
139 ~HGCMService() {};
140
141 static DECLCALLBACK(void) svcHlpCallComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc);
142 static DECLCALLBACK(void) svcHlpDisconnectClient(void *pvInstance, uint32_t u32ClientId);
143 static DECLCALLBACK(bool) svcHlpIsCallRestored(VBOXHGCMCALLHANDLE callHandle);
144 static DECLCALLBACK(int) svcHlpStamRegisterV(void *pvInstance, void *pvSample, STAMTYPE enmType,
145 STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, const char *pszDesc,
146 const char *pszName, va_list va);
147 static DECLCALLBACK(int) svcHlpStamDeregisterV(void *pvInstance, const char *pszPatFmt, va_list va);
148 static DECLCALLBACK(int) svcHlpInfoRegister(void *pvInstance, const char *pszName, const char *pszDesc,
149 PFNDBGFHANDLEREXT pfnHandler, void *pvUser);
150 static DECLCALLBACK(int) svcHlpInfoDeregister(void *pvInstance, const char *pszName);
151
152 public:
153
154 /*
155 * Main HGCM thread methods.
156 */
157 static int LoadService(const char *pszServiceLibrary, const char *pszServiceName, PUVM pUVM);
158 void UnloadService(void);
159
160 static void UnloadAll(void);
161
162 static int ResolveService(HGCMService **ppsvc, const char *pszServiceName);
163 void ReferenceService(void);
164 void ReleaseService(void);
165
166 static void Reset(void);
167
168 static int SaveState(PSSMHANDLE pSSM);
169 static int LoadState(PSSMHANDLE pSSM);
170
171 int CreateAndConnectClient(uint32_t *pu32ClientIdOut, uint32_t u32ClientIdIn);
172 int DisconnectClient(uint32_t u32ClientId, bool fFromService);
173
174 int HostCall(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM *paParms);
175
176#ifdef VBOX_WITH_CRHGSMI
177 int HandleAcquired();
178 int HandleReleased();
179 int HostFastCallAsync(uint32_t u32Function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion,
180 void *pvCompletion);
181#endif
182
183 uint32_t SizeOfClient(void) { return m_fntable.cbClient; };
184
185 int RegisterExtension(HGCMSVCEXTHANDLE handle, PFNHGCMSVCEXT pfnExtension, void *pvExtension);
186 void UnregisterExtension(HGCMSVCEXTHANDLE handle);
187
188 /*
189 * The service thread methods.
190 */
191
192 int GuestCall(PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId,
193 uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM aParms[], uint64_t tsArrival);
194};
195
196
197class HGCMClient: public HGCMObject
198{
199 public:
200 HGCMClient() : HGCMObject(HGCMOBJ_CLIENT), pService(NULL),
201 pvData(NULL) {};
202 ~HGCMClient();
203
204 int Init(HGCMService *pSvc);
205
206 /** Service that the client is connected to. */
207 HGCMService *pService;
208
209 /** Client specific data. */
210 void *pvData;
211};
212
213HGCMClient::~HGCMClient()
214{
215 if (pService->SizeOfClient() > 0)
216 RTMemFree(pvData);
217}
218
219int HGCMClient::Init(HGCMService *pSvc)
220{
221 pService = pSvc;
222
223 if (pService->SizeOfClient() > 0)
224 {
225 pvData = RTMemAllocZ(pService->SizeOfClient());
226
227 if (!pvData)
228 {
229 return VERR_NO_MEMORY;
230 }
231 }
232
233 return VINF_SUCCESS;
234}
235
236
237#define HGCM_CLIENT_DATA(pService, pClient)(pClient->pvData)
238
239
240
241HGCMService *HGCMService::sm_pSvcListHead = NULL;
242HGCMService *HGCMService::sm_pSvcListTail = NULL;
243int HGCMService::sm_cServices = 0;
244
245HGCMService::HGCMService()
246 :
247 m_pThread (NULL),
248 m_u32RefCnt (0),
249 m_pSvcNext (NULL),
250 m_pSvcPrev (NULL),
251 m_pszSvcName (NULL),
252 m_pszSvcLibrary (NULL),
253 m_hLdrMod (NIL_RTLDRMOD),
254 m_pfnLoad (NULL),
255 m_cClients (0),
256 m_cClientsAllocated (0),
257 m_paClientIds (NULL),
258#ifdef VBOX_WITH_CRHGSMI
259 m_cHandleAcquires (0),
260#endif
261 m_hExtension (NULL),
262 m_pUVM (NULL)
263{
264 RT_ZERO(m_fntable);
265}
266
267
268static bool g_fResetting = false;
269static bool g_fSaveState = false;
270
271
272/** Helper function to load a local service DLL.
273 *
274 * @return VBox code
275 */
276int HGCMService::loadServiceDLL(void)
277{
278 LogFlowFunc(("m_pszSvcLibrary = %s\n", m_pszSvcLibrary));
279
280 if (m_pszSvcLibrary == NULL)
281 {
282 return VERR_INVALID_PARAMETER;
283 }
284
285 RTERRINFOSTATIC ErrInfo;
286 RTErrInfoInitStatic(&ErrInfo);
287
288 int rc;
289
290 if (RTPathHasPath(m_pszSvcLibrary))
291 rc = SUPR3HardenedLdrLoadPlugIn(m_pszSvcLibrary, &m_hLdrMod, &ErrInfo.Core);
292 else
293 rc = SUPR3HardenedLdrLoadAppPriv(m_pszSvcLibrary, &m_hLdrMod, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core);
294
295 if (RT_SUCCESS(rc))
296 {
297 LogFlowFunc(("successfully loaded the library.\n"));
298
299 m_pfnLoad = NULL;
300
301 rc = RTLdrGetSymbol(m_hLdrMod, VBOX_HGCM_SVCLOAD_NAME, (void**)&m_pfnLoad);
302
303 if (RT_FAILURE(rc) || !m_pfnLoad)
304 {
305 Log(("HGCMService::loadServiceDLL: Error resolving the service entry point %s, rc = %d, m_pfnLoad = %p\n",
306 VBOX_HGCM_SVCLOAD_NAME, rc, m_pfnLoad));
307
308 if (RT_SUCCESS(rc))
309 {
310 /* m_pfnLoad was NULL */
311 rc = VERR_SYMBOL_NOT_FOUND;
312 }
313 }
314
315 if (RT_SUCCESS(rc))
316 {
317 RT_ZERO(m_fntable);
318
319 m_fntable.cbSize = sizeof(m_fntable);
320 m_fntable.u32Version = VBOX_HGCM_SVC_VERSION;
321 m_fntable.pHelpers = &m_svcHelpers;
322
323 rc = m_pfnLoad(&m_fntable);
324
325 LogFlowFunc(("m_pfnLoad rc = %Rrc\n", rc));
326
327 if (RT_SUCCESS(rc))
328 {
329 if ( m_fntable.pfnUnload == NULL
330 || m_fntable.pfnConnect == NULL
331 || m_fntable.pfnDisconnect == NULL
332 || m_fntable.pfnCall == NULL
333 )
334 {
335 Log(("HGCMService::loadServiceDLL: at least one of function pointers is NULL\n"));
336
337 rc = VERR_INVALID_PARAMETER;
338
339 if (m_fntable.pfnUnload)
340 {
341 m_fntable.pfnUnload(m_fntable.pvService);
342 }
343 }
344 }
345 }
346 }
347 else
348 {
349 LogRel(("HGCM: Failed to load the service library: [%s], rc = %Rrc - %s. The service will be not available.\n",
350 m_pszSvcLibrary, rc, ErrInfo.Core.pszMsg));
351 m_hLdrMod = NIL_RTLDRMOD;
352 }
353
354 if (RT_FAILURE(rc))
355 {
356 unloadServiceDLL();
357 }
358
359 return rc;
360}
361
362/** Helper function to free a local service DLL.
363 *
364 * @return VBox code
365 */
366void HGCMService::unloadServiceDLL(void)
367{
368 if (m_hLdrMod)
369 {
370 RTLdrClose(m_hLdrMod);
371 }
372
373 RT_ZERO(m_fntable);
374 m_pfnLoad = NULL;
375 m_hLdrMod = NIL_RTLDRMOD;
376}
377
378/*
379 * Messages processed by service threads. These threads only call the service entry points.
380 */
381
382#define SVC_MSG_LOAD (0) /* Load the service library and call VBOX_HGCM_SVCLOAD_NAME entry point. */
383#define SVC_MSG_UNLOAD (1) /* call pfnUnload and unload the service library. */
384#define SVC_MSG_CONNECT (2) /* pfnConnect */
385#define SVC_MSG_DISCONNECT (3) /* pfnDisconnect */
386#define SVC_MSG_GUESTCALL (4) /* pfnGuestCall */
387#define SVC_MSG_HOSTCALL (5) /* pfnHostCall */
388#define SVC_MSG_LOADSTATE (6) /* pfnLoadState. */
389#define SVC_MSG_SAVESTATE (7) /* pfnSaveState. */
390#define SVC_MSG_QUIT (8) /* Terminate the thread. */
391#define SVC_MSG_REGEXT (9) /* pfnRegisterExtension */
392#define SVC_MSG_UNREGEXT (10) /* pfnRegisterExtension */
393#ifdef VBOX_WITH_CRHGSMI
394# define SVC_MSG_HOSTFASTCALLASYNC (21) /* pfnHostCall */
395#endif
396
397class HGCMMsgSvcLoad: public HGCMMsgCore
398{
399 public:
400 HGCMMsgSvcLoad() : HGCMMsgCore(), pUVM() {}
401
402 /** The user mode VM handle (for statistics and such). */
403 PUVM pUVM;
404};
405
406class HGCMMsgSvcUnload: public HGCMMsgCore
407{
408};
409
410class HGCMMsgSvcConnect: public HGCMMsgCore
411{
412 public:
413 /* client identifier */
414 uint32_t u32ClientId;
415};
416
417class HGCMMsgSvcDisconnect: public HGCMMsgCore
418{
419 public:
420 /* client identifier */
421 uint32_t u32ClientId;
422};
423
424class HGCMMsgHeader: public HGCMMsgCore
425{
426 public:
427 HGCMMsgHeader() : pCmd(NULL), pHGCMPort(NULL) {};
428
429 /* Command pointer/identifier. */
430 PVBOXHGCMCMD pCmd;
431
432 /* Port to be informed on message completion. */
433 PPDMIHGCMPORT pHGCMPort;
434};
435
436
437class HGCMMsgCall: public HGCMMsgHeader
438{
439 public:
440 HGCMMsgCall() {}
441
442 HGCMMsgCall(HGCMThread *pThread)
443 {
444 InitializeCore(SVC_MSG_GUESTCALL, pThread);
445 Initialize();
446 }
447 ~HGCMMsgCall() { Log(("~HGCMMsgCall %p\n", this)); }
448
449 /* client identifier */
450 uint32_t u32ClientId;
451
452 /* function number */
453 uint32_t u32Function;
454
455 /* number of parameters */
456 uint32_t cParms;
457
458 VBOXHGCMSVCPARM *paParms;
459
460 /** The STAM_GET_TS() value when the request arrived. */
461 uint64_t tsArrival;
462};
463
464class HGCMMsgLoadSaveStateClient: public HGCMMsgCore
465{
466 public:
467 uint32_t u32ClientId;
468 PSSMHANDLE pSSM;
469};
470
471class HGCMMsgHostCallSvc: public HGCMMsgCore
472{
473 public:
474 /* function number */
475 uint32_t u32Function;
476
477 /* number of parameters */
478 uint32_t cParms;
479
480 VBOXHGCMSVCPARM *paParms;
481};
482
483class HGCMMsgSvcRegisterExtension: public HGCMMsgCore
484{
485 public:
486 /* Handle of the extension to be registered. */
487 HGCMSVCEXTHANDLE handle;
488 /* The extension entry point. */
489 PFNHGCMSVCEXT pfnExtension;
490 /* The extension pointer. */
491 void *pvExtension;
492};
493
494class HGCMMsgSvcUnregisterExtension: public HGCMMsgCore
495{
496 public:
497 /* Handle of the registered extension. */
498 HGCMSVCEXTHANDLE handle;
499};
500
501#ifdef VBOX_WITH_CRHGSMI
502class HGCMMsgHostFastCallAsyncSvc: public HGCMMsgCore
503{
504 public:
505 /* function number */
506 uint32_t u32Function;
507 /* parameter */
508 VBOXHGCMSVCPARM Param;
509 /* completion info */
510 PHGCMHOSTFASTCALLCB pfnCompletion;
511 void *pvCompletion;
512};
513#endif
514
515static HGCMMsgCore *hgcmMessageAllocSvc(uint32_t u32MsgId)
516{
517 switch (u32MsgId)
518 {
519#ifdef VBOX_WITH_CRHGSMI
520 case SVC_MSG_HOSTFASTCALLASYNC: return new HGCMMsgHostFastCallAsyncSvc();
521#endif
522 case SVC_MSG_LOAD: return new HGCMMsgSvcLoad();
523 case SVC_MSG_UNLOAD: return new HGCMMsgSvcUnload();
524 case SVC_MSG_CONNECT: return new HGCMMsgSvcConnect();
525 case SVC_MSG_DISCONNECT: return new HGCMMsgSvcDisconnect();
526 case SVC_MSG_HOSTCALL: return new HGCMMsgHostCallSvc();
527 case SVC_MSG_GUESTCALL: return new HGCMMsgCall();
528 case SVC_MSG_LOADSTATE:
529 case SVC_MSG_SAVESTATE: return new HGCMMsgLoadSaveStateClient();
530 case SVC_MSG_REGEXT: return new HGCMMsgSvcRegisterExtension();
531 case SVC_MSG_UNREGEXT: return new HGCMMsgSvcUnregisterExtension();
532 default:
533 AssertReleaseMsgFailed(("Msg id = %08X\n", u32MsgId));
534 }
535
536 return NULL;
537}
538
539/*
540 * The service thread. Loads the service library and calls the service entry points.
541 */
542DECLCALLBACK(void) hgcmServiceThread(HGCMThread *pThread, void *pvUser)
543{
544 HGCMService *pSvc = (HGCMService *)pvUser;
545 AssertRelease(pSvc != NULL);
546
547 bool fQuit = false;
548
549 while (!fQuit)
550 {
551 HGCMMsgCore *pMsgCore;
552 int rc = hgcmMsgGet(pThread, &pMsgCore);
553
554 if (RT_FAILURE(rc))
555 {
556 /* The error means some serious unrecoverable problem in the hgcmMsg/hgcmThread layer. */
557 AssertMsgFailed(("%Rrc\n", rc));
558 break;
559 }
560
561 STAM_REL_PROFILE_START(&pSvc->m_StatHandleMsg, a);
562
563 /* Cache required information to avoid unnecessary pMsgCore access. */
564 uint32_t u32MsgId = pMsgCore->MsgId();
565
566 switch (u32MsgId)
567 {
568#ifdef VBOX_WITH_CRHGSMI
569 case SVC_MSG_HOSTFASTCALLASYNC:
570 {
571 HGCMMsgHostFastCallAsyncSvc *pMsg = (HGCMMsgHostFastCallAsyncSvc *)pMsgCore;
572
573 LogFlowFunc(("SVC_MSG_HOSTFASTCALLASYNC u32Function = %d, pParm = %p\n", pMsg->u32Function, &pMsg->Param));
574
575 rc = pSvc->m_fntable.pfnHostCall(pSvc->m_fntable.pvService, pMsg->u32Function, 1, &pMsg->Param);
576 } break;
577#endif
578 case SVC_MSG_LOAD:
579 {
580 LogFlowFunc(("SVC_MSG_LOAD\n"));
581 rc = pSvc->loadServiceDLL();
582 } break;
583
584 case SVC_MSG_UNLOAD:
585 {
586 LogFlowFunc(("SVC_MSG_UNLOAD\n"));
587 if (pSvc->m_fntable.pfnUnload)
588 {
589 pSvc->m_fntable.pfnUnload(pSvc->m_fntable.pvService);
590 }
591
592 pSvc->unloadServiceDLL();
593 fQuit = true;
594 } break;
595
596 case SVC_MSG_CONNECT:
597 {
598 HGCMMsgSvcConnect *pMsg = (HGCMMsgSvcConnect *)pMsgCore;
599
600 LogFlowFunc(("SVC_MSG_CONNECT u32ClientId = %d\n", pMsg->u32ClientId));
601
602 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(pMsg->u32ClientId, HGCMOBJ_CLIENT);
603
604 if (pClient)
605 {
606 rc = pSvc->m_fntable.pfnConnect(pSvc->m_fntable.pvService, pMsg->u32ClientId,
607 HGCM_CLIENT_DATA(pSvc, pClient));
608
609 hgcmObjDereference(pClient);
610 }
611 else
612 {
613 rc = VERR_HGCM_INVALID_CLIENT_ID;
614 }
615 } break;
616
617 case SVC_MSG_DISCONNECT:
618 {
619 HGCMMsgSvcDisconnect *pMsg = (HGCMMsgSvcDisconnect *)pMsgCore;
620
621 LogFlowFunc(("SVC_MSG_DISCONNECT u32ClientId = %d\n", pMsg->u32ClientId));
622
623 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(pMsg->u32ClientId, HGCMOBJ_CLIENT);
624
625 if (pClient)
626 {
627 rc = pSvc->m_fntable.pfnDisconnect(pSvc->m_fntable.pvService, pMsg->u32ClientId,
628 HGCM_CLIENT_DATA(pSvc, pClient));
629
630 hgcmObjDereference(pClient);
631 }
632 else
633 {
634 rc = VERR_HGCM_INVALID_CLIENT_ID;
635 }
636 } break;
637
638 case SVC_MSG_GUESTCALL:
639 {
640 HGCMMsgCall *pMsg = (HGCMMsgCall *)pMsgCore;
641
642 LogFlowFunc(("SVC_MSG_GUESTCALL u32ClientId = %d, u32Function = %d, cParms = %d, paParms = %p\n",
643 pMsg->u32ClientId, pMsg->u32Function, pMsg->cParms, pMsg->paParms));
644
645 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(pMsg->u32ClientId, HGCMOBJ_CLIENT);
646
647 if (pClient)
648 {
649 pSvc->m_fntable.pfnCall(pSvc->m_fntable.pvService, (VBOXHGCMCALLHANDLE)pMsg, pMsg->u32ClientId,
650 HGCM_CLIENT_DATA(pSvc, pClient), pMsg->u32Function,
651 pMsg->cParms, pMsg->paParms, pMsg->tsArrival);
652
653 hgcmObjDereference(pClient);
654 }
655 else
656 {
657 rc = VERR_HGCM_INVALID_CLIENT_ID;
658 }
659 } break;
660
661 case SVC_MSG_HOSTCALL:
662 {
663 HGCMMsgHostCallSvc *pMsg = (HGCMMsgHostCallSvc *)pMsgCore;
664
665 LogFlowFunc(("SVC_MSG_HOSTCALL u32Function = %d, cParms = %d, paParms = %p\n",
666 pMsg->u32Function, pMsg->cParms, pMsg->paParms));
667
668 rc = pSvc->m_fntable.pfnHostCall(pSvc->m_fntable.pvService, pMsg->u32Function, pMsg->cParms, pMsg->paParms);
669 } break;
670
671 case SVC_MSG_LOADSTATE:
672 {
673 HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)pMsgCore;
674
675 LogFlowFunc(("SVC_MSG_LOADSTATE\n"));
676
677 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(pMsg->u32ClientId, HGCMOBJ_CLIENT);
678
679 if (pClient)
680 {
681 if (pSvc->m_fntable.pfnLoadState)
682 {
683 rc = pSvc->m_fntable.pfnLoadState(pSvc->m_fntable.pvService, pMsg->u32ClientId,
684 HGCM_CLIENT_DATA(pSvc, pClient), pMsg->pSSM);
685 }
686
687 hgcmObjDereference(pClient);
688 }
689 else
690 {
691 rc = VERR_HGCM_INVALID_CLIENT_ID;
692 }
693 } break;
694
695 case SVC_MSG_SAVESTATE:
696 {
697 HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)pMsgCore;
698
699 LogFlowFunc(("SVC_MSG_SAVESTATE\n"));
700
701 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(pMsg->u32ClientId, HGCMOBJ_CLIENT);
702
703 rc = VINF_SUCCESS;
704
705 if (pClient)
706 {
707 if (pSvc->m_fntable.pfnSaveState)
708 {
709 g_fSaveState = true;
710 rc = pSvc->m_fntable.pfnSaveState(pSvc->m_fntable.pvService, pMsg->u32ClientId,
711 HGCM_CLIENT_DATA(pSvc, pClient), pMsg->pSSM);
712 g_fSaveState = false;
713 }
714
715 hgcmObjDereference(pClient);
716 }
717 else
718 {
719 rc = VERR_HGCM_INVALID_CLIENT_ID;
720 }
721 } break;
722
723 case SVC_MSG_REGEXT:
724 {
725 HGCMMsgSvcRegisterExtension *pMsg = (HGCMMsgSvcRegisterExtension *)pMsgCore;
726
727 LogFlowFunc(("SVC_MSG_REGEXT handle = %p, pfn = %p\n", pMsg->handle, pMsg->pfnExtension));
728
729 if (pSvc->m_hExtension)
730 {
731 rc = VERR_NOT_SUPPORTED;
732 }
733 else
734 {
735 if (pSvc->m_fntable.pfnRegisterExtension)
736 {
737 rc = pSvc->m_fntable.pfnRegisterExtension(pSvc->m_fntable.pvService, pMsg->pfnExtension,
738 pMsg->pvExtension);
739 }
740 else
741 {
742 rc = VERR_NOT_SUPPORTED;
743 }
744
745 if (RT_SUCCESS(rc))
746 {
747 pSvc->m_hExtension = pMsg->handle;
748 }
749 }
750 } break;
751
752 case SVC_MSG_UNREGEXT:
753 {
754 HGCMMsgSvcUnregisterExtension *pMsg = (HGCMMsgSvcUnregisterExtension *)pMsgCore;
755
756 LogFlowFunc(("SVC_MSG_UNREGEXT handle = %p\n", pMsg->handle));
757
758 if (pSvc->m_hExtension != pMsg->handle)
759 {
760 rc = VERR_NOT_SUPPORTED;
761 }
762 else
763 {
764 if (pSvc->m_fntable.pfnRegisterExtension)
765 {
766 rc = pSvc->m_fntable.pfnRegisterExtension(pSvc->m_fntable.pvService, NULL, NULL);
767 }
768 else
769 {
770 rc = VERR_NOT_SUPPORTED;
771 }
772
773 pSvc->m_hExtension = NULL;
774 }
775 } break;
776
777 default:
778 {
779 AssertMsgFailed(("hgcmServiceThread::Unsupported message number %08X\n", u32MsgId));
780 rc = VERR_NOT_SUPPORTED;
781 } break;
782 }
783
784 if (u32MsgId != SVC_MSG_GUESTCALL)
785 {
786 /* For SVC_MSG_GUESTCALL the service calls the completion helper.
787 * Other messages have to be completed here.
788 */
789 hgcmMsgComplete (pMsgCore, rc);
790 }
791 STAM_REL_PROFILE_STOP(&pSvc->m_StatHandleMsg, a);
792 }
793}
794
795/**
796 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnCallComplete}
797 */
798/* static */ DECLCALLBACK(void) HGCMService::svcHlpCallComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc)
799{
800 HGCMMsgCore *pMsgCore = (HGCMMsgCore *)callHandle;
801
802 if (pMsgCore->MsgId () == SVC_MSG_GUESTCALL)
803 {
804 /* Only call the completion for these messages. The helper
805 * is called by the service, and the service does not get
806 * any other messages.
807 */
808 hgcmMsgComplete(pMsgCore, rc);
809 }
810 else
811 {
812 AssertFailed();
813 }
814}
815
816/**
817 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnDisconnectClient}
818 */
819/* static */ DECLCALLBACK(void) HGCMService::svcHlpDisconnectClient(void *pvInstance, uint32_t u32ClientId)
820{
821 HGCMService *pService = static_cast <HGCMService *> (pvInstance);
822
823 if (pService)
824 {
825 pService->DisconnectClient(u32ClientId, true);
826 }
827}
828
829/**
830 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnIsCallRestored}
831 */
832/* static */ DECLCALLBACK(bool) HGCMService::svcHlpIsCallRestored(VBOXHGCMCALLHANDLE callHandle)
833{
834 HGCMMsgHeader *pMsgHdr = (HGCMMsgHeader *)(callHandle);
835 AssertPtrReturn(pMsgHdr, false);
836
837 PVBOXHGCMCMD pCmd = pMsgHdr->pCmd;
838 AssertPtrReturn(pCmd, false);
839
840 PPDMIHGCMPORT pHgcmPort = pMsgHdr->pHGCMPort;
841 AssertPtrReturn(pHgcmPort, false);
842
843 return pHgcmPort->pfnIsCmdRestored(pHgcmPort, pCmd);
844}
845
846/**
847 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnStamRegisterV}
848 */
849/* static */ DECLCALLBACK(int)
850HGCMService::svcHlpStamRegisterV(void *pvInstance, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
851 STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list va)
852{
853 HGCMService *pService = static_cast <HGCMService *>(pvInstance);
854 AssertPtrReturn(pService, VERR_INVALID_PARAMETER);
855
856 return STAMR3RegisterVU(pService->m_pUVM, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, va);
857}
858
859/**
860 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnStamDeregisterV}
861 */
862/* static */ DECLCALLBACK(int) HGCMService::svcHlpStamDeregisterV(void *pvInstance, const char *pszPatFmt, va_list va)
863{
864 HGCMService *pService = static_cast <HGCMService *>(pvInstance);
865 AssertPtrReturn(pService, VERR_INVALID_PARAMETER);
866
867 return STAMR3DeregisterV(pService->m_pUVM, pszPatFmt, va);
868}
869
870/**
871 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnInfoRegister}
872 */
873/* static */ DECLCALLBACK(int) HGCMService::svcHlpInfoRegister(void *pvInstance, const char *pszName, const char *pszDesc,
874 PFNDBGFHANDLEREXT pfnHandler, void *pvUser)
875{
876 HGCMService *pService = static_cast <HGCMService *>(pvInstance);
877 AssertPtrReturn(pService, VERR_INVALID_PARAMETER);
878
879 return DBGFR3InfoRegisterExternal(pService->m_pUVM, pszName, pszDesc, pfnHandler, pvUser);
880}
881
882/**
883 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnInfoDeregister}
884 */
885/* static */ DECLCALLBACK(int) HGCMService::svcHlpInfoDeregister(void *pvInstance, const char *pszName)
886{
887 HGCMService *pService = static_cast <HGCMService *>(pvInstance);
888 AssertPtrReturn(pService, VERR_INVALID_PARAMETER);
889
890 return DBGFR3InfoDeregisterExternal(pService->m_pUVM, pszName);
891}
892
893
894static DECLCALLBACK(void) hgcmMsgCompletionCallback(int32_t result, HGCMMsgCore *pMsgCore)
895{
896 /* Call the VMMDev port interface to issue IRQ notification. */
897 HGCMMsgHeader *pMsgHdr = (HGCMMsgHeader *)pMsgCore;
898
899 LogFlow(("MAIN::hgcmMsgCompletionCallback: message %p\n", pMsgCore));
900
901 if (pMsgHdr->pHGCMPort && !g_fResetting)
902 {
903 pMsgHdr->pHGCMPort->pfnCompleted(pMsgHdr->pHGCMPort, g_fSaveState? VINF_HGCM_SAVE_STATE: result, pMsgHdr->pCmd);
904 }
905}
906
907/*
908 * The main HGCM methods of the service.
909 */
910
911int HGCMService::instanceCreate(const char *pszServiceLibrary, const char *pszServiceName, PUVM pUVM)
912{
913 LogFlowFunc(("name %s, lib %s\n", pszServiceName, pszServiceLibrary));
914 /* The maximum length of the thread name, allowed by the RT is 15. */
915 char szThreadName[16];
916 if (!strncmp(pszServiceName, RT_STR_TUPLE("VBoxShared")))
917 RTStrPrintf(szThreadName, sizeof(szThreadName), "Sh%s", pszServiceName + 10);
918 else if (!strncmp(pszServiceName, RT_STR_TUPLE("VBox")))
919 RTStrCopy(szThreadName, sizeof(szThreadName), pszServiceName + 4);
920 else
921 RTStrCopy(szThreadName, sizeof(szThreadName), pszServiceName);
922
923 int rc = hgcmThreadCreate(&m_pThread, szThreadName, hgcmServiceThread, this, pszServiceName, pUVM);
924
925 if (RT_SUCCESS(rc))
926 {
927 m_pszSvcName = RTStrDup(pszServiceName);
928 m_pszSvcLibrary = RTStrDup(pszServiceLibrary);
929
930 if (!m_pszSvcName || !m_pszSvcLibrary)
931 {
932 RTStrFree(m_pszSvcLibrary);
933 m_pszSvcLibrary = NULL;
934
935 RTStrFree(m_pszSvcName);
936 m_pszSvcName = NULL;
937
938 rc = VERR_NO_MEMORY;
939 }
940 else
941 {
942 /* Register statistics: */
943 m_pUVM = pUVM;
944 STAMR3RegisterFU(pUVM, &m_StatHandleMsg, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
945 "Message handling", "/HGCM/%s/Msg", pszServiceName);
946
947 /* Initialize service helpers table. */
948 m_svcHelpers.pfnCallComplete = svcHlpCallComplete;
949 m_svcHelpers.pvInstance = this;
950 m_svcHelpers.pfnDisconnectClient = svcHlpDisconnectClient;
951 m_svcHelpers.pfnIsCallRestored = svcHlpIsCallRestored;
952 m_svcHelpers.pfnStamRegisterV = svcHlpStamRegisterV;
953 m_svcHelpers.pfnStamDeregisterV = svcHlpStamDeregisterV;
954 m_svcHelpers.pfnInfoRegister = svcHlpInfoRegister;
955 m_svcHelpers.pfnInfoDeregister = svcHlpInfoDeregister;
956
957 /* Execute the load request on the service thread. */
958 HGCMMsgCore *pCoreMsg;
959 rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_LOAD, hgcmMessageAllocSvc);
960
961 if (RT_SUCCESS(rc))
962 {
963 HGCMMsgSvcLoad *pMsg = (HGCMMsgSvcLoad *)pCoreMsg;
964
965 pMsg->pUVM = pUVM;
966
967 rc = hgcmMsgSend(pMsg);
968 }
969 }
970 }
971
972 if (RT_FAILURE(rc))
973 {
974 instanceDestroy();
975 }
976
977 LogFlowFunc(("rc = %Rrc\n", rc));
978 return rc;
979}
980
981void HGCMService::instanceDestroy(void)
982{
983 LogFlowFunc(("%s\n", m_pszSvcName));
984
985 HGCMMsgCore *pMsg;
986 int rc = hgcmMsgAlloc(m_pThread, &pMsg, SVC_MSG_UNLOAD, hgcmMessageAllocSvc);
987
988 if (RT_SUCCESS(rc))
989 {
990 rc = hgcmMsgSend(pMsg);
991
992 if (RT_SUCCESS(rc))
993 hgcmThreadWait(m_pThread);
994 }
995
996 if (m_pszSvcName)
997 STAMR3DeregisterF(m_pUVM, "/HGCM/%s/*", m_pszSvcName);
998 m_pUVM = NULL;
999
1000 RTStrFree(m_pszSvcLibrary);
1001 m_pszSvcLibrary = NULL;
1002
1003 RTStrFree(m_pszSvcName);
1004 m_pszSvcName = NULL;
1005}
1006
1007int HGCMService::saveClientState(uint32_t u32ClientId, PSSMHANDLE pSSM)
1008{
1009 LogFlowFunc(("%s\n", m_pszSvcName));
1010
1011 HGCMMsgCore *pCoreMsg;
1012 int rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_SAVESTATE, hgcmMessageAllocSvc);
1013
1014 if (RT_SUCCESS(rc))
1015 {
1016 HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)pCoreMsg;
1017
1018 pMsg->u32ClientId = u32ClientId;
1019 pMsg->pSSM = pSSM;
1020
1021 rc = hgcmMsgSend(pMsg);
1022 }
1023
1024 LogFlowFunc(("rc = %Rrc\n", rc));
1025 return rc;
1026}
1027
1028int HGCMService::loadClientState(uint32_t u32ClientId, PSSMHANDLE pSSM)
1029{
1030 LogFlowFunc(("%s\n", m_pszSvcName));
1031
1032 HGCMMsgCore *pCoreMsg;
1033 int rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_LOADSTATE, hgcmMessageAllocSvc);
1034
1035 if (RT_SUCCESS(rc))
1036 {
1037 HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)pCoreMsg;
1038
1039 pMsg->u32ClientId = u32ClientId;
1040 pMsg->pSSM = pSSM;
1041
1042 rc = hgcmMsgSend(pMsg);
1043 }
1044
1045 LogFlowFunc(("rc = %Rrc\n", rc));
1046 return rc;
1047}
1048
1049
1050/** The method creates a service and references it.
1051 *
1052 * @param pszServiceLibrary The library to be loaded.
1053 * @param pszServiceName The name of the service.
1054 * @param pUVM The user mode VM handle (for statistics and such).
1055 * @return VBox rc.
1056 * @thread main HGCM
1057 */
1058/* static */ int HGCMService::LoadService(const char *pszServiceLibrary, const char *pszServiceName, PUVM pUVM)
1059{
1060 LogFlowFunc(("lib %s, name = %s, pUVM = %p\n", pszServiceLibrary, pszServiceName, pUVM));
1061
1062 /* Look at already loaded services to avoid double loading. */
1063
1064 HGCMService *pSvc;
1065 int rc = HGCMService::ResolveService(&pSvc, pszServiceName);
1066
1067 if (RT_SUCCESS(rc))
1068 {
1069 /* The service is already loaded. */
1070 pSvc->ReleaseService();
1071 rc = VERR_HGCM_SERVICE_EXISTS;
1072 }
1073 else
1074 {
1075 /* Create the new service. */
1076 pSvc = new (std::nothrow) HGCMService();
1077
1078 if (!pSvc)
1079 {
1080 rc = VERR_NO_MEMORY;
1081 }
1082 else
1083 {
1084 /* Load the library and call the initialization entry point. */
1085 rc = pSvc->instanceCreate(pszServiceLibrary, pszServiceName, pUVM);
1086
1087 if (RT_SUCCESS(rc))
1088 {
1089 /* Insert the just created service to list for future references. */
1090 pSvc->m_pSvcNext = sm_pSvcListHead;
1091 pSvc->m_pSvcPrev = NULL;
1092
1093 if (sm_pSvcListHead)
1094 {
1095 sm_pSvcListHead->m_pSvcPrev = pSvc;
1096 }
1097 else
1098 {
1099 sm_pSvcListTail = pSvc;
1100 }
1101
1102 sm_pSvcListHead = pSvc;
1103
1104 sm_cServices++;
1105
1106 /* Reference the service (for first time) until it is unloaded on HGCM termination. */
1107 AssertRelease(pSvc->m_u32RefCnt == 0);
1108 pSvc->ReferenceService();
1109
1110 LogFlowFunc(("service %p\n", pSvc));
1111 }
1112 }
1113 }
1114
1115 LogFlowFunc(("rc = %Rrc\n", rc));
1116 return rc;
1117}
1118
1119/** The method unloads a service.
1120 *
1121 * @thread main HGCM
1122 */
1123void HGCMService::UnloadService(void)
1124{
1125 LogFlowFunc(("name = %s\n", m_pszSvcName));
1126
1127 /* Remove the service from the list. */
1128 if (m_pSvcNext)
1129 {
1130 m_pSvcNext->m_pSvcPrev = m_pSvcPrev;
1131 }
1132 else
1133 {
1134 sm_pSvcListTail = m_pSvcPrev;
1135 }
1136
1137 if (m_pSvcPrev)
1138 {
1139 m_pSvcPrev->m_pSvcNext = m_pSvcNext;
1140 }
1141 else
1142 {
1143 sm_pSvcListHead = m_pSvcNext;
1144 }
1145
1146 sm_cServices--;
1147
1148 /* The service must be unloaded only if all clients were disconnected. */
1149 LogFlowFunc(("m_u32RefCnt = %d\n", m_u32RefCnt));
1150 AssertRelease(m_u32RefCnt == 1);
1151
1152 /* Now the service can be released. */
1153 ReleaseService();
1154}
1155
1156/** The method unloads all services.
1157 *
1158 * @thread main HGCM
1159 */
1160/* static */ void HGCMService::UnloadAll(void)
1161{
1162 while (sm_pSvcListHead)
1163 {
1164 sm_pSvcListHead->UnloadService();
1165 }
1166}
1167
1168/** The method obtains a referenced pointer to the service with
1169 * specified name. The caller must call ReleaseService when
1170 * the pointer is no longer needed.
1171 *
1172 * @param ppSvc Where to store the pointer to the service.
1173 * @param pszServiceName The name of the service.
1174 * @return VBox rc.
1175 * @thread main HGCM
1176 */
1177/* static */ int HGCMService::ResolveService(HGCMService **ppSvc, const char *pszServiceName)
1178{
1179 LogFlowFunc(("ppSvc = %p name = %s\n",
1180 ppSvc, pszServiceName));
1181
1182 if (!ppSvc || !pszServiceName)
1183 {
1184 return VERR_INVALID_PARAMETER;
1185 }
1186
1187 HGCMService *pSvc = sm_pSvcListHead;
1188
1189 while (pSvc)
1190 {
1191 if (strcmp(pSvc->m_pszSvcName, pszServiceName) == 0)
1192 {
1193 break;
1194 }
1195
1196 pSvc = pSvc->m_pSvcNext;
1197 }
1198
1199 LogFlowFunc(("lookup in the list is %p\n", pSvc));
1200
1201 if (pSvc == NULL)
1202 {
1203 *ppSvc = NULL;
1204 return VERR_HGCM_SERVICE_NOT_FOUND;
1205 }
1206
1207 pSvc->ReferenceService();
1208
1209 *ppSvc = pSvc;
1210
1211 return VINF_SUCCESS;
1212}
1213
1214/** The method increases reference counter.
1215 *
1216 * @thread main HGCM
1217 */
1218void HGCMService::ReferenceService(void)
1219{
1220 ASMAtomicIncU32(&m_u32RefCnt);
1221 LogFlowFunc(("[%s] m_u32RefCnt = %d\n", m_pszSvcName, m_u32RefCnt));
1222}
1223
1224/** The method dereferences a service and deletes it when no more refs.
1225 *
1226 * @thread main HGCM
1227 */
1228void HGCMService::ReleaseService(void)
1229{
1230 LogFlowFunc(("m_u32RefCnt = %d\n", m_u32RefCnt));
1231 uint32_t u32RefCnt = ASMAtomicDecU32(&m_u32RefCnt);
1232 AssertRelease(u32RefCnt != ~0U);
1233
1234 LogFlowFunc(("u32RefCnt = %d, name %s\n", u32RefCnt, m_pszSvcName));
1235
1236 if (u32RefCnt == 0)
1237 {
1238 instanceDestroy();
1239 delete this;
1240 }
1241}
1242
1243/** The method is called when the VM is being reset or terminated
1244 * and disconnects all clients from all services.
1245 *
1246 * @thread main HGCM
1247 */
1248/* static */ void HGCMService::Reset(void)
1249{
1250 g_fResetting = true;
1251
1252 HGCMService *pSvc = sm_pSvcListHead;
1253
1254 while (pSvc)
1255 {
1256 while (pSvc->m_cClients && pSvc->m_paClientIds)
1257 {
1258 LogFlowFunc(("handle %d\n", pSvc->m_paClientIds[0]));
1259 pSvc->DisconnectClient(pSvc->m_paClientIds[0], false);
1260 }
1261
1262#ifdef VBOX_WITH_CRHGSMI
1263 /** @todo could this actually happen that the service is destroyed on ReleaseService? */
1264 HGCMService *pNextSvc = pSvc->m_pSvcNext;
1265 while (pSvc->m_cHandleAcquires)
1266 {
1267 pSvc->HandleReleased();
1268 pSvc->ReleaseService();
1269 }
1270 pSvc = pNextSvc;
1271#else
1272 pSvc = pSvc->m_pSvcNext;
1273#endif
1274 }
1275
1276 g_fResetting = false;
1277}
1278
1279/** The method saves the HGCM state.
1280 *
1281 * @param pSSM The saved state context.
1282 * @return VBox rc.
1283 * @thread main HGCM
1284 */
1285/* static */ int HGCMService::SaveState(PSSMHANDLE pSSM)
1286{
1287 /* Save the current handle count and restore afterwards to avoid client id conflicts. */
1288 int rc = SSMR3PutU32(pSSM, hgcmObjQueryHandleCount());
1289 AssertRCReturn(rc, rc);
1290
1291 LogFlowFunc(("%d services to be saved:\n", sm_cServices));
1292
1293 /* Save number of services. */
1294 rc = SSMR3PutU32(pSSM, sm_cServices);
1295 AssertRCReturn(rc, rc);
1296
1297 /* Save every service. */
1298 HGCMService *pSvc = sm_pSvcListHead;
1299
1300 while (pSvc)
1301 {
1302 LogFlowFunc(("Saving service [%s]\n", pSvc->m_pszSvcName));
1303
1304 /* Save the length of the service name. */
1305 rc = SSMR3PutU32(pSSM, (uint32_t) strlen(pSvc->m_pszSvcName) + 1);
1306 AssertRCReturn(rc, rc);
1307
1308 /* Save the name of the service. */
1309 rc = SSMR3PutStrZ(pSSM, pSvc->m_pszSvcName);
1310 AssertRCReturn(rc, rc);
1311
1312 /* Save the number of clients. */
1313 rc = SSMR3PutU32(pSSM, pSvc->m_cClients);
1314 AssertRCReturn(rc, rc);
1315
1316 /* Call the service for every client. Normally a service must not have
1317 * a global state to be saved: only per client info is relevant.
1318 * The global state of a service is configured during VM startup.
1319 */
1320 uint32_t i;
1321
1322 for (i = 0; i < pSvc->m_cClients; i++)
1323 {
1324 uint32_t u32ClientId = pSvc->m_paClientIds[i];
1325
1326 Log(("client id 0x%08X\n", u32ClientId));
1327
1328 /* Save the client id. */
1329 rc = SSMR3PutU32(pSSM, u32ClientId);
1330 AssertRCReturn(rc, rc);
1331
1332 /* Call the service, so the operation is executed by the service thread. */
1333 rc = pSvc->saveClientState(u32ClientId, pSSM);
1334 AssertRCReturn(rc, rc);
1335 }
1336
1337 pSvc = pSvc->m_pSvcNext;
1338 }
1339
1340 return VINF_SUCCESS;
1341}
1342
1343/** The method loads saved HGCM state.
1344 *
1345 * @param pSSM The saved state context.
1346 * @return VBox rc.
1347 * @thread main HGCM
1348 */
1349/* static */ int HGCMService::LoadState(PSSMHANDLE pSSM)
1350{
1351 /* Restore handle count to avoid client id conflicts. */
1352 uint32_t u32;
1353
1354 int rc = SSMR3GetU32(pSSM, &u32);
1355 AssertRCReturn(rc, rc);
1356
1357 hgcmObjSetHandleCount(u32);
1358
1359 /* Get the number of services. */
1360 uint32_t cServices;
1361
1362 rc = SSMR3GetU32(pSSM, &cServices);
1363 AssertRCReturn(rc, rc);
1364
1365 LogFlowFunc(("%d services to be restored:\n", cServices));
1366
1367 while (cServices--)
1368 {
1369 /* Get the length of the service name. */
1370 rc = SSMR3GetU32(pSSM, &u32);
1371 AssertRCReturn(rc, rc);
1372 AssertReturn(u32 <= VBOX_HGCM_SVC_NAME_MAX_BYTES, VERR_SSM_UNEXPECTED_DATA);
1373
1374 /* Get the service name. */
1375 char szServiceName[VBOX_HGCM_SVC_NAME_MAX_BYTES];
1376 rc = SSMR3GetStrZ(pSSM, szServiceName, u32);
1377 AssertRCReturn(rc, rc);
1378
1379 LogRel(("HGCM: Restoring [%s]\n", szServiceName));
1380
1381 /* Resolve the service instance. */
1382 HGCMService *pSvc;
1383 rc = ResolveService(&pSvc, szServiceName);
1384 AssertLogRelMsgReturn(pSvc, ("rc=%Rrc, %s\n", rc, szServiceName), VERR_SSM_UNEXPECTED_DATA);
1385
1386 /* Get the number of clients. */
1387 uint32_t cClients;
1388 rc = SSMR3GetU32(pSSM, &cClients);
1389 if (RT_FAILURE(rc))
1390 {
1391 pSvc->ReleaseService();
1392 AssertFailed();
1393 return rc;
1394 }
1395
1396 while (cClients--)
1397 {
1398 /* Get the client id. */
1399 uint32_t u32ClientId;
1400 rc = SSMR3GetU32(pSSM, &u32ClientId);
1401 if (RT_FAILURE(rc))
1402 {
1403 pSvc->ReleaseService();
1404 AssertFailed();
1405 return rc;
1406 }
1407
1408 /* Connect the client. */
1409 rc = pSvc->CreateAndConnectClient(NULL, u32ClientId);
1410 if (RT_FAILURE(rc))
1411 {
1412 pSvc->ReleaseService();
1413 AssertLogRelMsgFailed(("rc=%Rrc %s\n", rc, szServiceName));
1414 return rc;
1415 }
1416
1417 /* Call the service, so the operation is executed by the service thread. */
1418 rc = pSvc->loadClientState(u32ClientId, pSSM);
1419 if (RT_FAILURE(rc))
1420 {
1421 pSvc->ReleaseService();
1422 AssertLogRelMsgFailed(("rc=%Rrc %s\n", rc, szServiceName));
1423 return rc;
1424 }
1425 }
1426
1427 pSvc->ReleaseService();
1428 }
1429
1430 return VINF_SUCCESS;
1431}
1432
1433/* Create a new client instance and connect it to the service.
1434 *
1435 * @param pu32ClientIdOut If not NULL, then the method must generate a new handle for the client.
1436 * If NULL, use the given 'u32ClientIdIn' handle.
1437 * @param u32ClientIdIn The handle for the client, when 'pu32ClientIdOut' is NULL.
1438 * @return VBox rc.
1439 */
1440int HGCMService::CreateAndConnectClient(uint32_t *pu32ClientIdOut, uint32_t u32ClientIdIn)
1441{
1442 LogFlowFunc(("pu32ClientIdOut = %p, u32ClientIdIn = %d\n", pu32ClientIdOut, u32ClientIdIn));
1443
1444 /* Allocate a client information structure. */
1445 HGCMClient *pClient = new HGCMClient();
1446
1447 if (!pClient)
1448 {
1449 Log1WarningFunc(("Could not allocate HGCMClient!!!\n"));
1450 return VERR_NO_MEMORY;
1451 }
1452
1453 uint32_t handle;
1454
1455 if (pu32ClientIdOut != NULL)
1456 {
1457 handle = hgcmObjGenerateHandle(pClient);
1458 }
1459 else
1460 {
1461 handle = hgcmObjAssignHandle(pClient, u32ClientIdIn);
1462 }
1463
1464 LogFlowFunc(("client id = %d\n", handle));
1465
1466 AssertRelease(handle);
1467
1468 /* Initialize the HGCM part of the client. */
1469 int rc = pClient->Init(this);
1470
1471 if (RT_SUCCESS(rc))
1472 {
1473 /* Call the service. */
1474 HGCMMsgCore *pCoreMsg;
1475
1476 rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_CONNECT, hgcmMessageAllocSvc);
1477
1478 if (RT_SUCCESS(rc))
1479 {
1480 HGCMMsgSvcConnect *pMsg = (HGCMMsgSvcConnect *)pCoreMsg;
1481
1482 pMsg->u32ClientId = handle;
1483
1484 rc = hgcmMsgSend(pMsg);
1485
1486 if (RT_SUCCESS(rc))
1487 {
1488 /* Add the client Id to the array. */
1489 if (m_cClients == m_cClientsAllocated)
1490 {
1491 const uint32_t cDelta = 64;
1492
1493 /* Guards against integer overflow on 32bit arch and also limits size of m_paClientIds array to 4GB*/
1494 if (m_cClientsAllocated < UINT32_MAX / sizeof(m_paClientIds[0]) - cDelta)
1495 {
1496 uint32_t *paClientIdsNew;
1497
1498 paClientIdsNew = (uint32_t *)RTMemRealloc(m_paClientIds,
1499 (m_cClientsAllocated + cDelta) * sizeof(m_paClientIds[0]));
1500 Assert(paClientIdsNew);
1501
1502 if (paClientIdsNew)
1503 {
1504 m_paClientIds = paClientIdsNew;
1505 m_cClientsAllocated += cDelta;
1506 }
1507 else
1508 {
1509 rc = VERR_NO_MEMORY;
1510 }
1511 }
1512 else
1513 {
1514 rc = VERR_NO_MEMORY;
1515 }
1516 }
1517
1518 m_paClientIds[m_cClients] = handle;
1519 m_cClients++;
1520 }
1521 }
1522 }
1523
1524 if (RT_FAILURE(rc))
1525 {
1526 hgcmObjDeleteHandle(handle);
1527 }
1528 else
1529 {
1530 if (pu32ClientIdOut != NULL)
1531 {
1532 *pu32ClientIdOut = handle;
1533 }
1534
1535 ReferenceService();
1536 }
1537
1538 LogFlowFunc(("rc = %Rrc\n", rc));
1539 return rc;
1540}
1541
1542/* Disconnect the client from the service and delete the client handle.
1543 *
1544 * @param u32ClientId The handle of the client.
1545 * @return VBox rc.
1546 */
1547int HGCMService::DisconnectClient(uint32_t u32ClientId, bool fFromService)
1548{
1549 int rc = VINF_SUCCESS;
1550
1551 LogFlowFunc(("client id = %d, fFromService = %d\n", u32ClientId, fFromService));
1552
1553 if (!fFromService)
1554 {
1555 /* Call the service. */
1556 HGCMMsgCore *pCoreMsg;
1557
1558 rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_DISCONNECT, hgcmMessageAllocSvc);
1559
1560 if (RT_SUCCESS(rc))
1561 {
1562 HGCMMsgSvcDisconnect *pMsg = (HGCMMsgSvcDisconnect *)pCoreMsg;
1563
1564 pMsg->u32ClientId = u32ClientId;
1565
1566 rc = hgcmMsgSend(pMsg);
1567 }
1568 else
1569 {
1570 LogRel(("(%d, %d) [%s] hgcmMsgAlloc(%p, SVC_MSG_DISCONNECT) failed %Rrc\n",
1571 u32ClientId, fFromService, RT_VALID_PTR(m_pszSvcName)? m_pszSvcName: "", m_pThread, rc));
1572 }
1573 }
1574
1575 /* Remove the client id from the array in any case, rc does not matter. */
1576 uint32_t i;
1577
1578 for (i = 0; i < m_cClients; i++)
1579 {
1580 if (m_paClientIds[i] == u32ClientId)
1581 {
1582 m_cClients--;
1583
1584 if (m_cClients > i)
1585 memmove(&m_paClientIds[i], &m_paClientIds[i + 1], sizeof(m_paClientIds[0]) * (m_cClients - i));
1586
1587 /* Delete the client handle. */
1588 hgcmObjDeleteHandle(u32ClientId);
1589
1590 /* The service must be released. */
1591 ReleaseService();
1592
1593 break;
1594 }
1595 }
1596
1597 LogFlowFunc(("rc = %Rrc\n", rc));
1598 return rc;
1599}
1600
1601int HGCMService::RegisterExtension(HGCMSVCEXTHANDLE handle,
1602 PFNHGCMSVCEXT pfnExtension,
1603 void *pvExtension)
1604{
1605 LogFlowFunc(("%s\n", handle->pszServiceName));
1606
1607 /* Forward the message to the service thread. */
1608 HGCMMsgCore *pCoreMsg;
1609 int rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_REGEXT, hgcmMessageAllocSvc);
1610
1611 if (RT_SUCCESS(rc))
1612 {
1613 HGCMMsgSvcRegisterExtension *pMsg = (HGCMMsgSvcRegisterExtension *)pCoreMsg;
1614
1615 pMsg->handle = handle;
1616 pMsg->pfnExtension = pfnExtension;
1617 pMsg->pvExtension = pvExtension;
1618
1619 rc = hgcmMsgSend(pMsg);
1620 }
1621
1622 LogFlowFunc(("rc = %Rrc\n", rc));
1623 return rc;
1624}
1625
1626void HGCMService::UnregisterExtension(HGCMSVCEXTHANDLE handle)
1627{
1628 /* Forward the message to the service thread. */
1629 HGCMMsgCore *pCoreMsg;
1630 int rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_UNREGEXT, hgcmMessageAllocSvc);
1631
1632 if (RT_SUCCESS(rc))
1633 {
1634 HGCMMsgSvcUnregisterExtension *pMsg = (HGCMMsgSvcUnregisterExtension *)pCoreMsg;
1635
1636 pMsg->handle = handle;
1637
1638 rc = hgcmMsgSend(pMsg);
1639 }
1640
1641 LogFlowFunc(("rc = %Rrc\n", rc));
1642}
1643
1644/** Perform a guest call to the service.
1645 *
1646 * @param pHGCMPort The port to be used for completion confirmation.
1647 * @param pCmd The VBox HGCM context.
1648 * @param u32ClientId The client handle to be disconnected and deleted.
1649 * @param u32Function The function number.
1650 * @param cParms Number of parameters.
1651 * @param paParms Pointer to array of parameters.
1652 * @param tsArrival The STAM_GET_TS() value when the request arrived.
1653 * @return VBox rc.
1654 * @retval VINF_HGCM_ASYNC_EXECUTE on success.
1655 */
1656int HGCMService::GuestCall(PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId, uint32_t u32Function,
1657 uint32_t cParms, VBOXHGCMSVCPARM paParms[], uint64_t tsArrival)
1658{
1659 LogFlow(("MAIN::HGCMService::Call\n"));
1660
1661 int rc;
1662 HGCMMsgCall *pMsg = new (std::nothrow) HGCMMsgCall(m_pThread);
1663 if (pMsg)
1664 {
1665 pMsg->Reference();
1666
1667 pMsg->pCmd = pCmd;
1668 pMsg->pHGCMPort = pHGCMPort;
1669 pMsg->u32ClientId = u32ClientId;
1670 pMsg->u32Function = u32Function;
1671 pMsg->cParms = cParms;
1672 pMsg->paParms = paParms;
1673 pMsg->tsArrival = tsArrival;
1674
1675 rc = hgcmMsgPost(pMsg, hgcmMsgCompletionCallback);
1676 }
1677 else
1678 {
1679 Log(("MAIN::HGCMService::Call: Message allocation failed\n"));
1680 rc = VERR_NO_MEMORY;
1681 }
1682
1683 LogFlowFunc(("rc = %Rrc\n", rc));
1684 return rc;
1685}
1686
1687/** Perform a host call the service.
1688 *
1689 * @param u32Function The function number.
1690 * @param cParms Number of parameters.
1691 * @param paParms Pointer to array of parameters.
1692 * @return VBox rc.
1693 */
1694int HGCMService::HostCall(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM *paParms)
1695{
1696 LogFlowFunc(("%s u32Function = %d, cParms = %d, paParms = %p\n",
1697 m_pszSvcName, u32Function, cParms, paParms));
1698
1699 HGCMMsgCore *pCoreMsg;
1700 int rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_HOSTCALL, hgcmMessageAllocSvc);
1701
1702 if (RT_SUCCESS(rc))
1703 {
1704 HGCMMsgHostCallSvc *pMsg = (HGCMMsgHostCallSvc *)pCoreMsg;
1705
1706 pMsg->u32Function = u32Function;
1707 pMsg->cParms = cParms;
1708 pMsg->paParms = paParms;
1709
1710 rc = hgcmMsgSend(pMsg);
1711 }
1712
1713 LogFlowFunc(("rc = %Rrc\n", rc));
1714 return rc;
1715}
1716
1717#ifdef VBOX_WITH_CRHGSMI
1718
1719static DECLCALLBACK(void) hgcmMsgFastCallCompletionCallback(int32_t result, HGCMMsgCore *pMsgCore)
1720{
1721 /* Call the VMMDev port interface to issue IRQ notification. */
1722 LogFlow(("MAIN::hgcmMsgFastCallCompletionCallback: message %p\n", pMsgCore));
1723
1724 HGCMMsgHostFastCallAsyncSvc *pMsg = (HGCMMsgHostFastCallAsyncSvc *)pMsgCore;
1725 if (pMsg->pfnCompletion)
1726 pMsg->pfnCompletion(result, pMsg->u32Function, &pMsg->Param, pMsg->pvCompletion);
1727}
1728
1729int HGCMService::HandleAcquired()
1730{
1731 ++m_cHandleAcquires;
1732 return VINF_SUCCESS;
1733}
1734
1735int HGCMService::HandleReleased()
1736{
1737 Assert(m_cHandleAcquires);
1738 if (m_cHandleAcquires)
1739 {
1740 --m_cHandleAcquires;
1741 return VINF_SUCCESS;
1742 }
1743 return VERR_INVALID_STATE;
1744}
1745
1746int HGCMService::HostFastCallAsync(uint32_t u32Function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion,
1747 void *pvCompletion)
1748{
1749 LogFlowFunc(("%s u32Function = %d, pParm = %p\n",
1750 m_pszSvcName, u32Function, pParm));
1751
1752 HGCMMsgCore *pCoreMsg;
1753 int rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_HOSTFASTCALLASYNC, hgcmMessageAllocSvc);
1754
1755 if (RT_SUCCESS(rc))
1756 {
1757 HGCMMsgHostFastCallAsyncSvc *pMsg = (HGCMMsgHostFastCallAsyncSvc *)pCoreMsg;
1758
1759 pMsg->u32Function = u32Function;
1760 pMsg->Param = *pParm;
1761 pMsg->pfnCompletion = pfnCompletion;
1762 pMsg->pvCompletion = pvCompletion;
1763
1764 rc = hgcmMsgPost(pMsg, hgcmMsgFastCallCompletionCallback);
1765 }
1766
1767 LogFlowFunc(("rc = %Rrc\n", rc));
1768 return rc;
1769}
1770
1771#endif /* VBOX_WITH_CRHGSMI */
1772
1773/*
1774 * Main HGCM thread that manages services.
1775 */
1776
1777/* Messages processed by the main HGCM thread. */
1778#define HGCM_MSG_CONNECT (10) /* Connect a client to a service. */
1779#define HGCM_MSG_DISCONNECT (11) /* Disconnect the specified client id. */
1780#define HGCM_MSG_LOAD (12) /* Load the service. */
1781#define HGCM_MSG_HOSTCALL (13) /* Call the service. */
1782#define HGCM_MSG_LOADSTATE (14) /* Load saved state for the specified service. */
1783#define HGCM_MSG_SAVESTATE (15) /* Save state for the specified service. */
1784#define HGCM_MSG_RESET (16) /* Disconnect all clients from the specified service. */
1785#define HGCM_MSG_QUIT (17) /* Unload all services and terminate the thread. */
1786#define HGCM_MSG_REGEXT (18) /* Register a service extension. */
1787#define HGCM_MSG_UNREGEXT (19) /* Unregister a service extension. */
1788#ifdef VBOX_WITH_CRHGSMI
1789# define HGCM_MSG_SVCAQUIRE (30) /* Acquire a service handle (for fast host calls) */
1790# define HGCM_MSG_SVCRELEASE (31) /* Release a service */
1791#endif
1792
1793class HGCMMsgMainConnect: public HGCMMsgHeader
1794{
1795 public:
1796 /* Service name. */
1797 const char *pszServiceName;
1798 /* Where to store the client handle. */
1799 uint32_t *pu32ClientId;
1800};
1801
1802class HGCMMsgMainDisconnect: public HGCMMsgHeader
1803{
1804 public:
1805 /* Handle of the client to be disconnected. */
1806 uint32_t u32ClientId;
1807};
1808
1809class HGCMMsgMainLoad: public HGCMMsgCore
1810{
1811 public:
1812 /* Name of the library to be loaded. */
1813 const char *pszServiceLibrary;
1814 /* Name to be assigned to the service. */
1815 const char *pszServiceName;
1816 /** The user mode VM handle (for statistics and such). */
1817 PUVM pUVM;
1818};
1819
1820class HGCMMsgMainHostCall: public HGCMMsgCore
1821{
1822 public:
1823 /* Which service to call. */
1824 const char *pszServiceName;
1825 /* Function number. */
1826 uint32_t u32Function;
1827 /* Number of the function parameters. */
1828 uint32_t cParms;
1829 /* Pointer to array of the function parameters. */
1830 VBOXHGCMSVCPARM *paParms;
1831};
1832
1833class HGCMMsgMainLoadSaveState: public HGCMMsgCore
1834{
1835 public:
1836 /* SSM context. */
1837 PSSMHANDLE pSSM;
1838};
1839
1840class HGCMMsgMainReset: public HGCMMsgCore
1841{
1842};
1843
1844class HGCMMsgMainQuit: public HGCMMsgCore
1845{
1846};
1847
1848class HGCMMsgMainRegisterExtension: public HGCMMsgCore
1849{
1850 public:
1851 /* Returned handle to be used in HGCMMsgMainUnregisterExtension. */
1852 HGCMSVCEXTHANDLE *pHandle;
1853 /* Name of the service. */
1854 const char *pszServiceName;
1855 /* The extension entry point. */
1856 PFNHGCMSVCEXT pfnExtension;
1857 /* The extension pointer. */
1858 void *pvExtension;
1859};
1860
1861class HGCMMsgMainUnregisterExtension: public HGCMMsgCore
1862{
1863 public:
1864 /* Handle of the registered extension. */
1865 HGCMSVCEXTHANDLE handle;
1866};
1867
1868#ifdef VBOX_WITH_CRHGSMI
1869class HGCMMsgMainSvcAcquire: public HGCMMsgCore
1870{
1871 public:
1872 /* Which service to call. */
1873 const char *pszServiceName;
1874 /* Returned service. */
1875 HGCMService *pService;
1876};
1877
1878class HGCMMsgMainSvcRelease: public HGCMMsgCore
1879{
1880 public:
1881 /* Svc . */
1882 HGCMService *pService;
1883};
1884#endif
1885
1886
1887static HGCMMsgCore *hgcmMainMessageAlloc (uint32_t u32MsgId)
1888{
1889 switch (u32MsgId)
1890 {
1891 case HGCM_MSG_CONNECT: return new HGCMMsgMainConnect();
1892 case HGCM_MSG_DISCONNECT: return new HGCMMsgMainDisconnect();
1893 case HGCM_MSG_LOAD: return new HGCMMsgMainLoad();
1894 case HGCM_MSG_HOSTCALL: return new HGCMMsgMainHostCall();
1895 case HGCM_MSG_LOADSTATE:
1896 case HGCM_MSG_SAVESTATE: return new HGCMMsgMainLoadSaveState();
1897 case HGCM_MSG_RESET: return new HGCMMsgMainReset();
1898 case HGCM_MSG_QUIT: return new HGCMMsgMainQuit();
1899 case HGCM_MSG_REGEXT: return new HGCMMsgMainRegisterExtension();
1900 case HGCM_MSG_UNREGEXT: return new HGCMMsgMainUnregisterExtension();
1901#ifdef VBOX_WITH_CRHGSMI
1902 case HGCM_MSG_SVCAQUIRE: return new HGCMMsgMainSvcAcquire();
1903 case HGCM_MSG_SVCRELEASE: return new HGCMMsgMainSvcRelease();
1904#endif
1905
1906 default:
1907 AssertReleaseMsgFailed(("Msg id = %08X\n", u32MsgId));
1908 }
1909
1910 return NULL;
1911}
1912
1913
1914/* The main HGCM thread handler. */
1915static DECLCALLBACK(void) hgcmThread(HGCMThread *pThread, void *pvUser)
1916{
1917 LogFlowFunc(("pThread = %p, pvUser = %p\n", pThread, pvUser));
1918
1919 NOREF(pvUser);
1920
1921 bool fQuit = false;
1922
1923 while (!fQuit)
1924 {
1925 HGCMMsgCore *pMsgCore;
1926 int rc = hgcmMsgGet(pThread, &pMsgCore);
1927
1928 if (RT_FAILURE(rc))
1929 {
1930 /* The error means some serious unrecoverable problem in the hgcmMsg/hgcmThread layer. */
1931 AssertMsgFailed(("%Rrc\n", rc));
1932 break;
1933 }
1934
1935 uint32_t u32MsgId = pMsgCore->MsgId();
1936
1937 switch (u32MsgId)
1938 {
1939 case HGCM_MSG_CONNECT:
1940 {
1941 HGCMMsgMainConnect *pMsg = (HGCMMsgMainConnect *)pMsgCore;
1942
1943 LogFlowFunc(("HGCM_MSG_CONNECT pszServiceName %s, pu32ClientId %p\n",
1944 pMsg->pszServiceName, pMsg->pu32ClientId));
1945
1946 /* Resolve the service name to the pointer to service instance.
1947 */
1948 HGCMService *pService;
1949 rc = HGCMService::ResolveService(&pService, pMsg->pszServiceName);
1950
1951 if (RT_SUCCESS(rc))
1952 {
1953 /* Call the service instance method. */
1954 rc = pService->CreateAndConnectClient(pMsg->pu32ClientId, 0);
1955
1956 /* Release the service after resolve. */
1957 pService->ReleaseService();
1958 }
1959 } break;
1960
1961 case HGCM_MSG_DISCONNECT:
1962 {
1963 HGCMMsgMainDisconnect *pMsg = (HGCMMsgMainDisconnect *)pMsgCore;
1964
1965 LogFlowFunc(("HGCM_MSG_DISCONNECT u32ClientId = %d\n",
1966 pMsg->u32ClientId));
1967
1968 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(pMsg->u32ClientId, HGCMOBJ_CLIENT);
1969
1970 if (!pClient)
1971 {
1972 rc = VERR_HGCM_INVALID_CLIENT_ID;
1973 break;
1974 }
1975
1976 /* The service the client belongs to. */
1977 HGCMService *pService = pClient->pService;
1978
1979 /* Call the service instance to disconnect the client. */
1980 rc = pService->DisconnectClient(pMsg->u32ClientId, false);
1981
1982 hgcmObjDereference(pClient);
1983 } break;
1984
1985 case HGCM_MSG_LOAD:
1986 {
1987 HGCMMsgMainLoad *pMsg = (HGCMMsgMainLoad *)pMsgCore;
1988
1989 LogFlowFunc(("HGCM_MSG_LOAD pszServiceName = %s, pMsg->pszServiceLibrary = %s, pMsg->pUVM = %p\n",
1990 pMsg->pszServiceName, pMsg->pszServiceLibrary, pMsg->pUVM));
1991
1992 rc = HGCMService::LoadService(pMsg->pszServiceLibrary, pMsg->pszServiceName, pMsg->pUVM);
1993 } break;
1994
1995 case HGCM_MSG_HOSTCALL:
1996 {
1997 HGCMMsgMainHostCall *pMsg = (HGCMMsgMainHostCall *)pMsgCore;
1998
1999 LogFlowFunc(("HGCM_MSG_HOSTCALL pszServiceName %s, u32Function %d, cParms %d, paParms %p\n",
2000 pMsg->pszServiceName, pMsg->u32Function, pMsg->cParms, pMsg->paParms));
2001
2002 /* Resolve the service name to the pointer to service instance. */
2003 HGCMService *pService;
2004 rc = HGCMService::ResolveService(&pService, pMsg->pszServiceName);
2005
2006 if (RT_SUCCESS(rc))
2007 {
2008 rc = pService->HostCall(pMsg->u32Function, pMsg->cParms, pMsg->paParms);
2009
2010 pService->ReleaseService();
2011 }
2012 } break;
2013
2014#ifdef VBOX_WITH_CRHGSMI
2015 case HGCM_MSG_SVCAQUIRE:
2016 {
2017 HGCMMsgMainSvcAcquire *pMsg = (HGCMMsgMainSvcAcquire *)pMsgCore;
2018
2019 LogFlowFunc(("HGCM_MSG_SVCAQUIRE pszServiceName %s\n", pMsg->pszServiceName));
2020
2021 /* Resolve the service name to the pointer to service instance. */
2022 HGCMService *pService;
2023 rc = HGCMService::ResolveService(&pService, pMsg->pszServiceName);
2024 if (RT_SUCCESS(rc))
2025 {
2026 rc = pService->HandleAcquired();
2027 if (RT_SUCCESS(rc))
2028 {
2029 pMsg->pService = pService;
2030 }
2031 else
2032 {
2033 pService->ReleaseService();
2034 }
2035 }
2036 } break;
2037
2038 case HGCM_MSG_SVCRELEASE:
2039 {
2040 HGCMMsgMainSvcRelease *pMsg = (HGCMMsgMainSvcRelease *)pMsgCore;
2041
2042 LogFlowFunc(("HGCM_MSG_SVCARELEASE pService %p\n", pMsg->pService));
2043
2044 /* Resolve the service name to the pointer to service instance. */
2045
2046 rc = pMsg->pService->HandleReleased();
2047 if (RT_SUCCESS(rc))
2048 {
2049 pMsg->pService->ReleaseService();
2050 }
2051 } break;
2052#endif
2053
2054 case HGCM_MSG_RESET:
2055 {
2056 LogFlowFunc(("HGCM_MSG_RESET\n"));
2057
2058 HGCMService::Reset();
2059 } break;
2060
2061 case HGCM_MSG_LOADSTATE:
2062 {
2063 HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pMsgCore;
2064
2065 LogFlowFunc(("HGCM_MSG_LOADSTATE\n"));
2066
2067 rc = HGCMService::LoadState(pMsg->pSSM);
2068 } break;
2069
2070 case HGCM_MSG_SAVESTATE:
2071 {
2072 HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pMsgCore;
2073
2074 LogFlowFunc(("HGCM_MSG_SAVESTATE\n"));
2075
2076 rc = HGCMService::SaveState(pMsg->pSSM);
2077 } break;
2078
2079 case HGCM_MSG_QUIT:
2080 {
2081 LogFlowFunc(("HGCM_MSG_QUIT\n"));
2082
2083 HGCMService::UnloadAll();
2084
2085 fQuit = true;
2086 } break;
2087
2088 case HGCM_MSG_REGEXT:
2089 {
2090 HGCMMsgMainRegisterExtension *pMsg = (HGCMMsgMainRegisterExtension *)pMsgCore;
2091
2092 LogFlowFunc(("HGCM_MSG_REGEXT\n"));
2093
2094 /* Allocate the handle data. */
2095 HGCMSVCEXTHANDLE handle = (HGCMSVCEXTHANDLE)RTMemAllocZ(sizeof(struct _HGCMSVCEXTHANDLEDATA)
2096 + strlen(pMsg->pszServiceName)
2097 + sizeof(char));
2098
2099 if (handle == NULL)
2100 {
2101 rc = VERR_NO_MEMORY;
2102 }
2103 else
2104 {
2105 handle->pszServiceName = (char *)((uint8_t *)handle + sizeof(struct _HGCMSVCEXTHANDLEDATA));
2106 strcpy(handle->pszServiceName, pMsg->pszServiceName);
2107
2108 HGCMService *pService;
2109 rc = HGCMService::ResolveService(&pService, handle->pszServiceName);
2110
2111 if (RT_SUCCESS(rc))
2112 {
2113 pService->RegisterExtension(handle, pMsg->pfnExtension, pMsg->pvExtension);
2114
2115 pService->ReleaseService();
2116 }
2117
2118 if (RT_FAILURE(rc))
2119 {
2120 RTMemFree(handle);
2121 }
2122 else
2123 {
2124 *pMsg->pHandle = handle;
2125 }
2126 }
2127 } break;
2128
2129 case HGCM_MSG_UNREGEXT:
2130 {
2131 HGCMMsgMainUnregisterExtension *pMsg = (HGCMMsgMainUnregisterExtension *)pMsgCore;
2132
2133 LogFlowFunc(("HGCM_MSG_UNREGEXT\n"));
2134
2135 HGCMService *pService;
2136 rc = HGCMService::ResolveService(&pService, pMsg->handle->pszServiceName);
2137
2138 if (RT_SUCCESS(rc))
2139 {
2140 pService->UnregisterExtension(pMsg->handle);
2141
2142 pService->ReleaseService();
2143 }
2144
2145 RTMemFree(pMsg->handle);
2146 } break;
2147
2148 default:
2149 {
2150 AssertMsgFailed(("hgcmThread: Unsupported message number %08X!!!\n", u32MsgId));
2151 rc = VERR_NOT_SUPPORTED;
2152 } break;
2153 }
2154
2155 /* Complete the message processing. */
2156 hgcmMsgComplete(pMsgCore, rc);
2157
2158 LogFlowFunc(("message processed %Rrc\n", rc));
2159 }
2160}
2161
2162
2163/*
2164 * The HGCM API.
2165 */
2166
2167/** The main hgcm thread. */
2168static HGCMThread *g_pHgcmThread = 0;
2169
2170/*
2171 * Public HGCM functions.
2172 *
2173 * hgcmGuest* - called as a result of the guest HGCM requests.
2174 * hgcmHost* - called by the host.
2175 */
2176
2177/* Load a HGCM service from the specified library.
2178 * Assign the specified name to the service.
2179 *
2180 * @param pszServiceLibrary The library to be loaded.
2181 * @param pszServiceName The name to be assigned to the service.
2182 * @param pUVM The user mode VM handle (for statistics and such).
2183 * @return VBox rc.
2184 */
2185int HGCMHostLoad(const char *pszServiceLibrary,
2186 const char *pszServiceName,
2187 PUVM pUVM)
2188{
2189 LogFlowFunc(("lib = %s, name = %s\n", pszServiceLibrary, pszServiceName));
2190
2191 if (!pszServiceLibrary || !pszServiceName)
2192 {
2193 return VERR_INVALID_PARAMETER;
2194 }
2195
2196 /* Forward the request to the main hgcm thread. */
2197 HGCMMsgCore *pCoreMsg;
2198 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_LOAD, hgcmMainMessageAlloc);
2199
2200 if (RT_SUCCESS(rc))
2201 {
2202 /* Initialize the message. Since the message is synchronous, use the supplied pointers. */
2203 HGCMMsgMainLoad *pMsg = (HGCMMsgMainLoad *)pCoreMsg;
2204
2205 pMsg->pszServiceLibrary = pszServiceLibrary;
2206 pMsg->pszServiceName = pszServiceName;
2207 pMsg->pUVM = pUVM;
2208
2209 rc = hgcmMsgSend(pMsg);
2210 }
2211
2212 LogFlowFunc(("rc = %Rrc\n", rc));
2213 return rc;
2214}
2215
2216/* Register a HGCM service extension.
2217 *
2218 * @param pHandle Returned handle for the registered extension.
2219 * @param pszServiceName The name of the service.
2220 * @param pfnExtension The extension entry point (callback).
2221 * @param pvExtension The extension pointer.
2222 * @return VBox rc.
2223 */
2224int HGCMHostRegisterServiceExtension(HGCMSVCEXTHANDLE *pHandle,
2225 const char *pszServiceName,
2226 PFNHGCMSVCEXT pfnExtension,
2227 void *pvExtension)
2228{
2229 LogFlowFunc(("pHandle = %p, name = %s, pfn = %p, rv = %p\n", pHandle, pszServiceName, pfnExtension, pvExtension));
2230
2231 if (!pHandle || !pszServiceName || !pfnExtension)
2232 {
2233 return VERR_INVALID_PARAMETER;
2234 }
2235
2236 /* Forward the request to the main hgcm thread. */
2237 HGCMMsgCore *pCoreMsg;
2238 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_REGEXT, hgcmMainMessageAlloc);
2239
2240 if (RT_SUCCESS(rc))
2241 {
2242 /* Initialize the message. Since the message is synchronous, use the supplied pointers. */
2243 HGCMMsgMainRegisterExtension *pMsg = (HGCMMsgMainRegisterExtension *)pCoreMsg;
2244
2245 pMsg->pHandle = pHandle;
2246 pMsg->pszServiceName = pszServiceName;
2247 pMsg->pfnExtension = pfnExtension;
2248 pMsg->pvExtension = pvExtension;
2249
2250 rc = hgcmMsgSend(pMsg);
2251 }
2252
2253 LogFlowFunc(("*pHandle = %p, rc = %Rrc\n", *pHandle, rc));
2254 return rc;
2255}
2256
2257void HGCMHostUnregisterServiceExtension(HGCMSVCEXTHANDLE handle)
2258{
2259 LogFlowFunc(("handle = %p\n", handle));
2260
2261 /* Forward the request to the main hgcm thread. */
2262 HGCMMsgCore *pCoreMsg;
2263 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_UNREGEXT, hgcmMainMessageAlloc);
2264
2265 if (RT_SUCCESS(rc))
2266 {
2267 /* Initialize the message. */
2268 HGCMMsgMainUnregisterExtension *pMsg = (HGCMMsgMainUnregisterExtension *)pCoreMsg;
2269
2270 pMsg->handle = handle;
2271
2272 rc = hgcmMsgSend(pMsg);
2273 }
2274
2275 LogFlowFunc(("rc = %Rrc\n", rc));
2276 return;
2277}
2278
2279/* Find a service and inform it about a client connection, create a client handle.
2280 *
2281 * @param pHGCMPort The port to be used for completion confirmation.
2282 * @param pCmd The VBox HGCM context.
2283 * @param pszServiceName The name of the service to be connected to.
2284 * @param pu32ClientId Where the store the created client handle.
2285 * @return VBox rc.
2286 */
2287int HGCMGuestConnect(PPDMIHGCMPORT pHGCMPort,
2288 PVBOXHGCMCMD pCmd,
2289 const char *pszServiceName,
2290 uint32_t *pu32ClientId)
2291{
2292 LogFlowFunc(("pHGCMPort = %p, pCmd = %p, name = %s, pu32ClientId = %p\n",
2293 pHGCMPort, pCmd, pszServiceName, pu32ClientId));
2294
2295 if (pHGCMPort == NULL || pCmd == NULL || pszServiceName == NULL || pu32ClientId == NULL)
2296 {
2297 return VERR_INVALID_PARAMETER;
2298 }
2299
2300 /* Forward the request to the main hgcm thread. */
2301 HGCMMsgCore *pCoreMsg;
2302 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_CONNECT, hgcmMainMessageAlloc);
2303
2304 if (RT_SUCCESS(rc))
2305 {
2306 /* Initialize the message. Since 'pszServiceName' and 'pu32ClientId'
2307 * will not be deallocated by the caller until the message is completed,
2308 * use the supplied pointers.
2309 */
2310 HGCMMsgMainConnect *pMsg = (HGCMMsgMainConnect *)pCoreMsg;
2311
2312 pMsg->pHGCMPort = pHGCMPort;
2313 pMsg->pCmd = pCmd;
2314 pMsg->pszServiceName = pszServiceName;
2315 pMsg->pu32ClientId = pu32ClientId;
2316
2317 rc = hgcmMsgPost(pMsg, hgcmMsgCompletionCallback);
2318 }
2319
2320 LogFlowFunc(("rc = %Rrc\n", rc));
2321 return rc;
2322}
2323
2324/* Tell a service that the client is disconnecting, destroy the client handle.
2325 *
2326 * @param pHGCMPort The port to be used for completion confirmation.
2327 * @param pCmd The VBox HGCM context.
2328 * @param u32ClientId The client handle to be disconnected and deleted.
2329 * @return VBox rc.
2330 */
2331int HGCMGuestDisconnect(PPDMIHGCMPORT pHGCMPort,
2332 PVBOXHGCMCMD pCmd,
2333 uint32_t u32ClientId)
2334{
2335 LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d\n",
2336 pHGCMPort, pCmd, u32ClientId));
2337
2338 if (!pHGCMPort || !pCmd || !u32ClientId)
2339 {
2340 return VERR_INVALID_PARAMETER;
2341 }
2342
2343 /* Forward the request to the main hgcm thread. */
2344 HGCMMsgCore *pCoreMsg;
2345 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_DISCONNECT, hgcmMainMessageAlloc);
2346
2347 if (RT_SUCCESS(rc))
2348 {
2349 /* Initialize the message. */
2350 HGCMMsgMainDisconnect *pMsg = (HGCMMsgMainDisconnect *)pCoreMsg;
2351
2352 pMsg->pCmd = pCmd;
2353 pMsg->pHGCMPort = pHGCMPort;
2354 pMsg->u32ClientId = u32ClientId;
2355
2356 rc = hgcmMsgPost(pMsg, hgcmMsgCompletionCallback);
2357 }
2358
2359 LogFlowFunc(("rc = %Rrc\n", rc));
2360 return rc;
2361}
2362
2363/* Helper to send either HGCM_MSG_SAVESTATE or HGCM_MSG_LOADSTATE messages to the main HGCM thread.
2364 *
2365 * @param pSSM The SSM handle.
2366 * @param u32MsgId The message to be sent: HGCM_MSG_SAVESTATE or HGCM_MSG_LOADSTATE.
2367 * @return VBox rc.
2368 */
2369static int hgcmHostLoadSaveState(PSSMHANDLE pSSM,
2370 uint32_t u32MsgId)
2371{
2372 LogFlowFunc(("pSSM = %p, u32MsgId = %d\n", pSSM, u32MsgId));
2373
2374 HGCMMsgCore *pCoreMsg;
2375 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, u32MsgId, hgcmMainMessageAlloc);
2376
2377 if (RT_SUCCESS(rc))
2378 {
2379 HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pCoreMsg;
2380 AssertRelease(pMsg);
2381
2382 pMsg->pSSM = pSSM;
2383
2384 rc = hgcmMsgSend(pMsg);
2385 }
2386
2387 LogFlowFunc(("rc = %Rrc\n", rc));
2388 return rc;
2389}
2390
2391/* Save the state of services.
2392 *
2393 * @param pSSM The SSM handle.
2394 * @return VBox rc.
2395 */
2396int HGCMHostSaveState(PSSMHANDLE pSSM)
2397{
2398 return hgcmHostLoadSaveState(pSSM, HGCM_MSG_SAVESTATE);
2399}
2400
2401/* Load the state of services.
2402 *
2403 * @param pSSM The SSM handle.
2404 * @return VBox rc.
2405 */
2406int HGCMHostLoadState(PSSMHANDLE pSSM)
2407{
2408 return hgcmHostLoadSaveState(pSSM, HGCM_MSG_LOADSTATE);
2409}
2410
2411/* The guest calls the service.
2412 *
2413 * @param pHGCMPort The port to be used for completion confirmation.
2414 * @param pCmd The VBox HGCM context.
2415 * @param u32ClientId The client handle to be disconnected and deleted.
2416 * @param u32Function The function number.
2417 * @param cParms Number of parameters.
2418 * @param paParms Pointer to array of parameters.
2419 * @param tsArrival The STAM_GET_TS() value when the request arrived.
2420 * @return VBox rc.
2421 */
2422int HGCMGuestCall(PPDMIHGCMPORT pHGCMPort,
2423 PVBOXHGCMCMD pCmd,
2424 uint32_t u32ClientId,
2425 uint32_t u32Function,
2426 uint32_t cParms,
2427 VBOXHGCMSVCPARM *paParms,
2428 uint64_t tsArrival)
2429{
2430 LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d, u32Function = %d, cParms = %d, paParms = %p\n",
2431 pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms));
2432
2433 if (!pHGCMPort || !pCmd || u32ClientId == 0)
2434 {
2435 return VERR_INVALID_PARAMETER;
2436 }
2437
2438 int rc = VERR_HGCM_INVALID_CLIENT_ID;
2439
2440 /* Resolve the client handle to the client instance pointer. */
2441 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(u32ClientId, HGCMOBJ_CLIENT);
2442
2443 if (pClient)
2444 {
2445 AssertRelease(pClient->pService);
2446
2447 /* Forward the message to the service thread. */
2448 rc = pClient->pService->GuestCall(pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms, tsArrival);
2449
2450 hgcmObjDereference(pClient);
2451 }
2452
2453 LogFlowFunc(("rc = %Rrc\n", rc));
2454 return rc;
2455}
2456
2457/* The host calls the service.
2458 *
2459 * @param pszServiceName The service name to be called.
2460 * @param u32Function The function number.
2461 * @param cParms Number of parameters.
2462 * @param paParms Pointer to array of parameters.
2463 * @return VBox rc.
2464 */
2465int HGCMHostCall(const char *pszServiceName,
2466 uint32_t u32Function,
2467 uint32_t cParms,
2468 VBOXHGCMSVCPARM *paParms)
2469{
2470 LogFlowFunc(("name = %s, u32Function = %d, cParms = %d, paParms = %p\n",
2471 pszServiceName, u32Function, cParms, paParms));
2472
2473 if (!pszServiceName)
2474 {
2475 return VERR_INVALID_PARAMETER;
2476 }
2477
2478 /* Host calls go to main HGCM thread that resolves the service name to the
2479 * service instance pointer and then, using the service pointer, forwards
2480 * the message to the service thread.
2481 * So it is slow but host calls are intended mostly for configuration and
2482 * other non-time-critical functions.
2483 */
2484 HGCMMsgCore *pCoreMsg;
2485 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_HOSTCALL, hgcmMainMessageAlloc);
2486
2487 if (RT_SUCCESS(rc))
2488 {
2489 HGCMMsgMainHostCall *pMsg = (HGCMMsgMainHostCall *)pCoreMsg;
2490
2491 pMsg->pszServiceName = (char *)pszServiceName;
2492 pMsg->u32Function = u32Function;
2493 pMsg->cParms = cParms;
2494 pMsg->paParms = paParms;
2495
2496 rc = hgcmMsgSend(pMsg);
2497 }
2498
2499 LogFlowFunc(("rc = %Rrc\n", rc));
2500 return rc;
2501}
2502
2503#ifdef VBOX_WITH_CRHGSMI
2504int HGCMHostSvcHandleCreate(const char *pszServiceName, HGCMCVSHANDLE * phSvc)
2505{
2506 LogFlowFunc(("name = %s\n", pszServiceName));
2507
2508 if (!pszServiceName)
2509 {
2510 return VERR_INVALID_PARAMETER;
2511 }
2512
2513 if (!phSvc)
2514 {
2515 return VERR_INVALID_PARAMETER;
2516 }
2517
2518 /* Host calls go to main HGCM thread that resolves the service name to the
2519 * service instance pointer and then, using the service pointer, forwards
2520 * the message to the service thread.
2521 * So it is slow but host calls are intended mostly for configuration and
2522 * other non-time-critical functions.
2523 */
2524 HGCMMsgCore *pCoreMsg;
2525 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_SVCAQUIRE, hgcmMainMessageAlloc);
2526
2527 if (RT_SUCCESS(rc))
2528 {
2529 HGCMMsgMainSvcAcquire *pMsg = (HGCMMsgMainSvcAcquire *)pCoreMsg;
2530
2531 pMsg->pszServiceName = (char *)pszServiceName;
2532 pMsg->pService = NULL;
2533
2534 pMsg->Reference();
2535
2536 rc = hgcmMsgSend(pMsg);
2537 if (RT_SUCCESS(rc))
2538 {
2539 /* for simplicity just use a svc ptr as handle for now */
2540 *phSvc = (HGCMCVSHANDLE)pMsg->pService;
2541 }
2542 pMsg->Dereference();
2543 }
2544
2545 LogFlowFunc(("rc = %Rrc\n", rc));
2546 return rc;
2547}
2548
2549int HGCMHostSvcHandleDestroy(HGCMCVSHANDLE hSvc)
2550{
2551 LogFlowFunc(("hSvc = %p\n", hSvc));
2552
2553 if (!hSvc)
2554 {
2555 return VERR_INVALID_PARAMETER;
2556 }
2557
2558 /* Host calls go to main HGCM thread that resolves the service name to the
2559 * service instance pointer and then, using the service pointer, forwards
2560 * the message to the service thread.
2561 * So it is slow but host calls are intended mostly for configuration and
2562 * other non-time-critical functions.
2563 */
2564 HGCMMsgCore *pCoreMsg;
2565 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_SVCRELEASE, hgcmMainMessageAlloc);
2566
2567 if (RT_SUCCESS(rc))
2568 {
2569 HGCMMsgMainSvcRelease *pMsg = (HGCMMsgMainSvcRelease *)pCoreMsg;
2570
2571 pMsg->pService = (HGCMService *)hSvc;
2572
2573 rc = hgcmMsgSend(pMsg);
2574 }
2575
2576 LogFlowFunc(("rc = %Rrc\n", rc));
2577 return rc;
2578}
2579
2580int HGCMHostFastCallAsync(HGCMCVSHANDLE hSvc, uint32_t function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion,
2581 void *pvCompletion)
2582{
2583 LogFlowFunc(("hSvc = %p, u32Function = %d, pParm = %p\n",
2584 hSvc, function, pParm));
2585
2586 if (!hSvc)
2587 {
2588 return VERR_INVALID_PARAMETER;
2589 }
2590
2591 HGCMService *pService = (HGCMService *)hSvc;
2592 int rc = pService->HostFastCallAsync(function, pParm, pfnCompletion, pvCompletion);
2593
2594 LogFlowFunc(("rc = %Rrc\n", rc));
2595 return rc;
2596}
2597#endif
2598
2599int HGCMHostReset(void)
2600{
2601 LogFlowFunc(("\n"));
2602
2603 /* Disconnect all clients.
2604 */
2605
2606 HGCMMsgCore *pMsg;
2607 int rc = hgcmMsgAlloc(g_pHgcmThread, &pMsg, HGCM_MSG_RESET, hgcmMainMessageAlloc);
2608
2609 if (RT_SUCCESS(rc))
2610 rc = hgcmMsgSend(pMsg);
2611
2612 LogFlowFunc(("rc = %Rrc\n", rc));
2613 return rc;
2614}
2615
2616int HGCMHostInit(void)
2617{
2618 LogFlowFunc(("\n"));
2619
2620 int rc = hgcmThreadInit();
2621
2622 if (RT_SUCCESS(rc))
2623 {
2624 /*
2625 * Start main HGCM thread.
2626 */
2627
2628 rc = hgcmThreadCreate(&g_pHgcmThread, "MainHGCMthread", hgcmThread, NULL /*pvUser*/, NULL /*pszStatsSubDir*/, NULL /*pUVM*/);
2629
2630 if (RT_FAILURE(rc))
2631 LogRel(("Failed to start HGCM thread. HGCM services will be unavailable!!! rc = %Rrc\n", rc));
2632 }
2633
2634 LogFlowFunc(("rc = %Rrc\n", rc));
2635 return rc;
2636}
2637
2638int HGCMHostShutdown(void)
2639{
2640 LogFlowFunc(("\n"));
2641
2642 /*
2643 * Do HGCMReset and then unload all services.
2644 */
2645
2646 int rc = HGCMHostReset();
2647
2648 if (RT_SUCCESS(rc))
2649 {
2650 /* Send the quit message to the main hgcmThread. */
2651 HGCMMsgCore *pMsg;
2652 rc = hgcmMsgAlloc(g_pHgcmThread, &pMsg, HGCM_MSG_QUIT, hgcmMainMessageAlloc);
2653
2654 if (RT_SUCCESS(rc))
2655 {
2656 rc = hgcmMsgSend(pMsg);
2657
2658 if (RT_SUCCESS(rc))
2659 {
2660 /* Wait for the thread termination. */
2661 hgcmThreadWait(g_pHgcmThread);
2662 g_pHgcmThread = NULL;
2663
2664 hgcmThreadUninit();
2665 }
2666 }
2667 }
2668
2669 LogFlowFunc(("rc = %Rrc\n", rc));
2670 return rc;
2671}
2672
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette