VirtualBox

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

Last change on this file since 75747 was 75747, checked in by vboxsync, 6 years ago

HGCM: Continue with getting VERR_CANCELLED to the service when the guest has cancelled (or canceled if you prefer) the command.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 78.0 KB
Line 
1/* $Id: HGCM.cpp 75747 2018-11-26 18:54:55Z 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(int) 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(bool fUvmIsInvalid);
159
160 static void UnloadAll(bool fUvmIsInvalid);
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(int) HGCMService::svcHlpCallComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc)
799{
800 HGCMMsgCore *pMsgCore = (HGCMMsgCore *)callHandle;
801
802 /* Only call the completion for these messages. The helper
803 * is called by the service, and the service does not get
804 * any other messages.
805 */
806 AssertMsgReturn(pMsgCore->MsgId() == SVC_MSG_GUESTCALL, ("%d\n", pMsgCore->MsgId()), VERR_WRONG_TYPE);
807 return hgcmMsgComplete(pMsgCore, rc);
808}
809
810/**
811 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnDisconnectClient}
812 */
813/* static */ DECLCALLBACK(void) HGCMService::svcHlpDisconnectClient(void *pvInstance, uint32_t u32ClientId)
814{
815 HGCMService *pService = static_cast <HGCMService *> (pvInstance);
816
817 if (pService)
818 {
819 pService->DisconnectClient(u32ClientId, true);
820 }
821}
822
823/**
824 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnIsCallRestored}
825 */
826/* static */ DECLCALLBACK(bool) HGCMService::svcHlpIsCallRestored(VBOXHGCMCALLHANDLE callHandle)
827{
828 HGCMMsgHeader *pMsgHdr = (HGCMMsgHeader *)(callHandle);
829 AssertPtrReturn(pMsgHdr, false);
830
831 PVBOXHGCMCMD pCmd = pMsgHdr->pCmd;
832 AssertPtrReturn(pCmd, false);
833
834 PPDMIHGCMPORT pHgcmPort = pMsgHdr->pHGCMPort;
835 AssertPtrReturn(pHgcmPort, false);
836
837 return pHgcmPort->pfnIsCmdRestored(pHgcmPort, pCmd);
838}
839
840/**
841 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnStamRegisterV}
842 */
843/* static */ DECLCALLBACK(int)
844HGCMService::svcHlpStamRegisterV(void *pvInstance, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
845 STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list va)
846{
847 HGCMService *pService = static_cast <HGCMService *>(pvInstance);
848 AssertPtrReturn(pService, VERR_INVALID_PARAMETER);
849
850 return STAMR3RegisterVU(pService->m_pUVM, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, va);
851}
852
853/**
854 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnStamDeregisterV}
855 */
856/* static */ DECLCALLBACK(int) HGCMService::svcHlpStamDeregisterV(void *pvInstance, const char *pszPatFmt, va_list va)
857{
858 HGCMService *pService = static_cast <HGCMService *>(pvInstance);
859 AssertPtrReturn(pService, VERR_INVALID_PARAMETER);
860
861 if (pService->m_pUVM)
862 return STAMR3DeregisterV(pService->m_pUVM, pszPatFmt, va);
863 return VINF_SUCCESS;
864}
865
866/**
867 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnInfoRegister}
868 */
869/* static */ DECLCALLBACK(int) HGCMService::svcHlpInfoRegister(void *pvInstance, const char *pszName, const char *pszDesc,
870 PFNDBGFHANDLEREXT pfnHandler, void *pvUser)
871{
872 HGCMService *pService = static_cast <HGCMService *>(pvInstance);
873 AssertPtrReturn(pService, VERR_INVALID_PARAMETER);
874
875 return DBGFR3InfoRegisterExternal(pService->m_pUVM, pszName, pszDesc, pfnHandler, pvUser);
876}
877
878/**
879 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnInfoDeregister}
880 */
881/* static */ DECLCALLBACK(int) HGCMService::svcHlpInfoDeregister(void *pvInstance, const char *pszName)
882{
883 HGCMService *pService = static_cast <HGCMService *>(pvInstance);
884 AssertPtrReturn(pService, VERR_INVALID_PARAMETER);
885 if (pService->m_pUVM)
886 return DBGFR3InfoDeregisterExternal(pService->m_pUVM, pszName);
887 return VINF_SUCCESS;
888}
889
890
891static DECLCALLBACK(int) hgcmMsgCompletionCallback(int32_t result, HGCMMsgCore *pMsgCore)
892{
893 /* Call the VMMDev port interface to issue IRQ notification. */
894 HGCMMsgHeader *pMsgHdr = (HGCMMsgHeader *)pMsgCore;
895
896 LogFlow(("MAIN::hgcmMsgCompletionCallback: message %p\n", pMsgCore));
897
898 if (pMsgHdr->pHGCMPort)
899 {
900 if (!g_fResetting)
901 return pMsgHdr->pHGCMPort->pfnCompleted(pMsgHdr->pHGCMPort,
902 g_fSaveState ? VINF_HGCM_SAVE_STATE : result, pMsgHdr->pCmd);
903 return VERR_ALREADY_RESET; /* best I could find. */
904 }
905 return VERR_NOT_AVAILABLE;
906}
907
908/*
909 * The main HGCM methods of the service.
910 */
911
912int HGCMService::instanceCreate(const char *pszServiceLibrary, const char *pszServiceName, PUVM pUVM)
913{
914 LogFlowFunc(("name %s, lib %s\n", pszServiceName, pszServiceLibrary));
915 /* The maximum length of the thread name, allowed by the RT is 15. */
916 char szThreadName[16];
917 if (!strncmp(pszServiceName, RT_STR_TUPLE("VBoxShared")))
918 RTStrPrintf(szThreadName, sizeof(szThreadName), "Sh%s", pszServiceName + 10);
919 else if (!strncmp(pszServiceName, RT_STR_TUPLE("VBox")))
920 RTStrCopy(szThreadName, sizeof(szThreadName), pszServiceName + 4);
921 else
922 RTStrCopy(szThreadName, sizeof(szThreadName), pszServiceName);
923
924 int rc = hgcmThreadCreate(&m_pThread, szThreadName, hgcmServiceThread, this, pszServiceName, pUVM);
925
926 if (RT_SUCCESS(rc))
927 {
928 m_pszSvcName = RTStrDup(pszServiceName);
929 m_pszSvcLibrary = RTStrDup(pszServiceLibrary);
930
931 if (!m_pszSvcName || !m_pszSvcLibrary)
932 {
933 RTStrFree(m_pszSvcLibrary);
934 m_pszSvcLibrary = NULL;
935
936 RTStrFree(m_pszSvcName);
937 m_pszSvcName = NULL;
938
939 rc = VERR_NO_MEMORY;
940 }
941 else
942 {
943 /* Register statistics: */
944 m_pUVM = pUVM;
945 STAMR3RegisterFU(pUVM, &m_StatHandleMsg, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
946 "Message handling", "/HGCM/%s/Msg", pszServiceName);
947
948 /* Initialize service helpers table. */
949 m_svcHelpers.pfnCallComplete = svcHlpCallComplete;
950 m_svcHelpers.pvInstance = this;
951 m_svcHelpers.pfnDisconnectClient = svcHlpDisconnectClient;
952 m_svcHelpers.pfnIsCallRestored = svcHlpIsCallRestored;
953 m_svcHelpers.pfnStamRegisterV = svcHlpStamRegisterV;
954 m_svcHelpers.pfnStamDeregisterV = svcHlpStamDeregisterV;
955 m_svcHelpers.pfnInfoRegister = svcHlpInfoRegister;
956 m_svcHelpers.pfnInfoDeregister = svcHlpInfoDeregister;
957
958 /* Execute the load request on the service thread. */
959 HGCMMsgCore *pCoreMsg;
960 rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_LOAD, hgcmMessageAllocSvc);
961
962 if (RT_SUCCESS(rc))
963 {
964 HGCMMsgSvcLoad *pMsg = (HGCMMsgSvcLoad *)pCoreMsg;
965
966 pMsg->pUVM = pUVM;
967
968 rc = hgcmMsgSend(pMsg);
969 }
970 }
971 }
972
973 if (RT_FAILURE(rc))
974 {
975 instanceDestroy();
976 }
977
978 LogFlowFunc(("rc = %Rrc\n", rc));
979 return rc;
980}
981
982void HGCMService::instanceDestroy(void)
983{
984 LogFlowFunc(("%s\n", m_pszSvcName));
985
986 HGCMMsgCore *pMsg;
987 int rc = hgcmMsgAlloc(m_pThread, &pMsg, SVC_MSG_UNLOAD, hgcmMessageAllocSvc);
988
989 if (RT_SUCCESS(rc))
990 {
991 rc = hgcmMsgSend(pMsg);
992
993 if (RT_SUCCESS(rc))
994 hgcmThreadWait(m_pThread);
995 }
996
997 if (m_pszSvcName && m_pUVM)
998 STAMR3DeregisterF(m_pUVM, "/HGCM/%s/*", m_pszSvcName);
999 m_pUVM = NULL;
1000
1001 RTStrFree(m_pszSvcLibrary);
1002 m_pszSvcLibrary = NULL;
1003
1004 RTStrFree(m_pszSvcName);
1005 m_pszSvcName = NULL;
1006}
1007
1008int HGCMService::saveClientState(uint32_t u32ClientId, PSSMHANDLE pSSM)
1009{
1010 LogFlowFunc(("%s\n", m_pszSvcName));
1011
1012 HGCMMsgCore *pCoreMsg;
1013 int rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_SAVESTATE, hgcmMessageAllocSvc);
1014
1015 if (RT_SUCCESS(rc))
1016 {
1017 HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)pCoreMsg;
1018
1019 pMsg->u32ClientId = u32ClientId;
1020 pMsg->pSSM = pSSM;
1021
1022 rc = hgcmMsgSend(pMsg);
1023 }
1024
1025 LogFlowFunc(("rc = %Rrc\n", rc));
1026 return rc;
1027}
1028
1029int HGCMService::loadClientState(uint32_t u32ClientId, PSSMHANDLE pSSM)
1030{
1031 LogFlowFunc(("%s\n", m_pszSvcName));
1032
1033 HGCMMsgCore *pCoreMsg;
1034 int rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_LOADSTATE, hgcmMessageAllocSvc);
1035
1036 if (RT_SUCCESS(rc))
1037 {
1038 HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)pCoreMsg;
1039
1040 pMsg->u32ClientId = u32ClientId;
1041 pMsg->pSSM = pSSM;
1042
1043 rc = hgcmMsgSend(pMsg);
1044 }
1045
1046 LogFlowFunc(("rc = %Rrc\n", rc));
1047 return rc;
1048}
1049
1050
1051/** The method creates a service and references it.
1052 *
1053 * @param pszServiceLibrary The library to be loaded.
1054 * @param pszServiceName The name of the service.
1055 * @param pUVM The user mode VM handle (for statistics and such).
1056 * @return VBox rc.
1057 * @thread main HGCM
1058 */
1059/* static */ int HGCMService::LoadService(const char *pszServiceLibrary, const char *pszServiceName, PUVM pUVM)
1060{
1061 LogFlowFunc(("lib %s, name = %s, pUVM = %p\n", pszServiceLibrary, pszServiceName, pUVM));
1062
1063 /* Look at already loaded services to avoid double loading. */
1064
1065 HGCMService *pSvc;
1066 int rc = HGCMService::ResolveService(&pSvc, pszServiceName);
1067
1068 if (RT_SUCCESS(rc))
1069 {
1070 /* The service is already loaded. */
1071 pSvc->ReleaseService();
1072 rc = VERR_HGCM_SERVICE_EXISTS;
1073 }
1074 else
1075 {
1076 /* Create the new service. */
1077 pSvc = new (std::nothrow) HGCMService();
1078
1079 if (!pSvc)
1080 {
1081 rc = VERR_NO_MEMORY;
1082 }
1083 else
1084 {
1085 /* Load the library and call the initialization entry point. */
1086 rc = pSvc->instanceCreate(pszServiceLibrary, pszServiceName, pUVM);
1087
1088 if (RT_SUCCESS(rc))
1089 {
1090 /* Insert the just created service to list for future references. */
1091 pSvc->m_pSvcNext = sm_pSvcListHead;
1092 pSvc->m_pSvcPrev = NULL;
1093
1094 if (sm_pSvcListHead)
1095 {
1096 sm_pSvcListHead->m_pSvcPrev = pSvc;
1097 }
1098 else
1099 {
1100 sm_pSvcListTail = pSvc;
1101 }
1102
1103 sm_pSvcListHead = pSvc;
1104
1105 sm_cServices++;
1106
1107 /* Reference the service (for first time) until it is unloaded on HGCM termination. */
1108 AssertRelease(pSvc->m_u32RefCnt == 0);
1109 pSvc->ReferenceService();
1110
1111 LogFlowFunc(("service %p\n", pSvc));
1112 }
1113 }
1114 }
1115
1116 LogFlowFunc(("rc = %Rrc\n", rc));
1117 return rc;
1118}
1119
1120/** The method unloads a service.
1121 *
1122 * @thread main HGCM
1123 */
1124void HGCMService::UnloadService(bool fUvmIsInvalid)
1125{
1126 LogFlowFunc(("name = %s\n", m_pszSvcName));
1127
1128 if (fUvmIsInvalid)
1129 m_pUVM = NULL;
1130
1131 /* Remove the service from the list. */
1132 if (m_pSvcNext)
1133 {
1134 m_pSvcNext->m_pSvcPrev = m_pSvcPrev;
1135 }
1136 else
1137 {
1138 sm_pSvcListTail = m_pSvcPrev;
1139 }
1140
1141 if (m_pSvcPrev)
1142 {
1143 m_pSvcPrev->m_pSvcNext = m_pSvcNext;
1144 }
1145 else
1146 {
1147 sm_pSvcListHead = m_pSvcNext;
1148 }
1149
1150 sm_cServices--;
1151
1152 /* The service must be unloaded only if all clients were disconnected. */
1153 LogFlowFunc(("m_u32RefCnt = %d\n", m_u32RefCnt));
1154 AssertRelease(m_u32RefCnt == 1);
1155
1156 /* Now the service can be released. */
1157 ReleaseService();
1158}
1159
1160/** The method unloads all services.
1161 *
1162 * @thread main HGCM
1163 */
1164/* static */ void HGCMService::UnloadAll(bool fUvmIsInvalid)
1165{
1166 while (sm_pSvcListHead)
1167 {
1168 sm_pSvcListHead->UnloadService(fUvmIsInvalid);
1169 }
1170}
1171
1172/** The method obtains a referenced pointer to the service with
1173 * specified name. The caller must call ReleaseService when
1174 * the pointer is no longer needed.
1175 *
1176 * @param ppSvc Where to store the pointer to the service.
1177 * @param pszServiceName The name of the service.
1178 * @return VBox rc.
1179 * @thread main HGCM
1180 */
1181/* static */ int HGCMService::ResolveService(HGCMService **ppSvc, const char *pszServiceName)
1182{
1183 LogFlowFunc(("ppSvc = %p name = %s\n",
1184 ppSvc, pszServiceName));
1185
1186 if (!ppSvc || !pszServiceName)
1187 {
1188 return VERR_INVALID_PARAMETER;
1189 }
1190
1191 HGCMService *pSvc = sm_pSvcListHead;
1192
1193 while (pSvc)
1194 {
1195 if (strcmp(pSvc->m_pszSvcName, pszServiceName) == 0)
1196 {
1197 break;
1198 }
1199
1200 pSvc = pSvc->m_pSvcNext;
1201 }
1202
1203 LogFlowFunc(("lookup in the list is %p\n", pSvc));
1204
1205 if (pSvc == NULL)
1206 {
1207 *ppSvc = NULL;
1208 return VERR_HGCM_SERVICE_NOT_FOUND;
1209 }
1210
1211 pSvc->ReferenceService();
1212
1213 *ppSvc = pSvc;
1214
1215 return VINF_SUCCESS;
1216}
1217
1218/** The method increases reference counter.
1219 *
1220 * @thread main HGCM
1221 */
1222void HGCMService::ReferenceService(void)
1223{
1224 ASMAtomicIncU32(&m_u32RefCnt);
1225 LogFlowFunc(("[%s] m_u32RefCnt = %d\n", m_pszSvcName, m_u32RefCnt));
1226}
1227
1228/** The method dereferences a service and deletes it when no more refs.
1229 *
1230 * @thread main HGCM
1231 */
1232void HGCMService::ReleaseService(void)
1233{
1234 LogFlowFunc(("m_u32RefCnt = %d\n", m_u32RefCnt));
1235 uint32_t u32RefCnt = ASMAtomicDecU32(&m_u32RefCnt);
1236 AssertRelease(u32RefCnt != ~0U);
1237
1238 LogFlowFunc(("u32RefCnt = %d, name %s\n", u32RefCnt, m_pszSvcName));
1239
1240 if (u32RefCnt == 0)
1241 {
1242 instanceDestroy();
1243 delete this;
1244 }
1245}
1246
1247/** The method is called when the VM is being reset or terminated
1248 * and disconnects all clients from all services.
1249 *
1250 * @thread main HGCM
1251 */
1252/* static */ void HGCMService::Reset(void)
1253{
1254 g_fResetting = true;
1255
1256 HGCMService *pSvc = sm_pSvcListHead;
1257
1258 while (pSvc)
1259 {
1260 while (pSvc->m_cClients && pSvc->m_paClientIds)
1261 {
1262 LogFlowFunc(("handle %d\n", pSvc->m_paClientIds[0]));
1263 pSvc->DisconnectClient(pSvc->m_paClientIds[0], false);
1264 }
1265
1266#ifdef VBOX_WITH_CRHGSMI
1267 /** @todo could this actually happen that the service is destroyed on ReleaseService? */
1268 HGCMService *pNextSvc = pSvc->m_pSvcNext;
1269 while (pSvc->m_cHandleAcquires)
1270 {
1271 pSvc->HandleReleased();
1272 pSvc->ReleaseService();
1273 }
1274 pSvc = pNextSvc;
1275#else
1276 pSvc = pSvc->m_pSvcNext;
1277#endif
1278 }
1279
1280 g_fResetting = false;
1281}
1282
1283/** The method saves the HGCM state.
1284 *
1285 * @param pSSM The saved state context.
1286 * @return VBox rc.
1287 * @thread main HGCM
1288 */
1289/* static */ int HGCMService::SaveState(PSSMHANDLE pSSM)
1290{
1291 /* Save the current handle count and restore afterwards to avoid client id conflicts. */
1292 int rc = SSMR3PutU32(pSSM, hgcmObjQueryHandleCount());
1293 AssertRCReturn(rc, rc);
1294
1295 LogFlowFunc(("%d services to be saved:\n", sm_cServices));
1296
1297 /* Save number of services. */
1298 rc = SSMR3PutU32(pSSM, sm_cServices);
1299 AssertRCReturn(rc, rc);
1300
1301 /* Save every service. */
1302 HGCMService *pSvc = sm_pSvcListHead;
1303
1304 while (pSvc)
1305 {
1306 LogFlowFunc(("Saving service [%s]\n", pSvc->m_pszSvcName));
1307
1308 /* Save the length of the service name. */
1309 rc = SSMR3PutU32(pSSM, (uint32_t) strlen(pSvc->m_pszSvcName) + 1);
1310 AssertRCReturn(rc, rc);
1311
1312 /* Save the name of the service. */
1313 rc = SSMR3PutStrZ(pSSM, pSvc->m_pszSvcName);
1314 AssertRCReturn(rc, rc);
1315
1316 /* Save the number of clients. */
1317 rc = SSMR3PutU32(pSSM, pSvc->m_cClients);
1318 AssertRCReturn(rc, rc);
1319
1320 /* Call the service for every client. Normally a service must not have
1321 * a global state to be saved: only per client info is relevant.
1322 * The global state of a service is configured during VM startup.
1323 */
1324 uint32_t i;
1325
1326 for (i = 0; i < pSvc->m_cClients; i++)
1327 {
1328 uint32_t u32ClientId = pSvc->m_paClientIds[i];
1329
1330 Log(("client id 0x%08X\n", u32ClientId));
1331
1332 /* Save the client id. */
1333 rc = SSMR3PutU32(pSSM, u32ClientId);
1334 AssertRCReturn(rc, rc);
1335
1336 /* Call the service, so the operation is executed by the service thread. */
1337 rc = pSvc->saveClientState(u32ClientId, pSSM);
1338 AssertRCReturn(rc, rc);
1339 }
1340
1341 pSvc = pSvc->m_pSvcNext;
1342 }
1343
1344 return VINF_SUCCESS;
1345}
1346
1347/** The method loads saved HGCM state.
1348 *
1349 * @param pSSM The saved state context.
1350 * @return VBox rc.
1351 * @thread main HGCM
1352 */
1353/* static */ int HGCMService::LoadState(PSSMHANDLE pSSM)
1354{
1355 /* Restore handle count to avoid client id conflicts. */
1356 uint32_t u32;
1357
1358 int rc = SSMR3GetU32(pSSM, &u32);
1359 AssertRCReturn(rc, rc);
1360
1361 hgcmObjSetHandleCount(u32);
1362
1363 /* Get the number of services. */
1364 uint32_t cServices;
1365
1366 rc = SSMR3GetU32(pSSM, &cServices);
1367 AssertRCReturn(rc, rc);
1368
1369 LogFlowFunc(("%d services to be restored:\n", cServices));
1370
1371 while (cServices--)
1372 {
1373 /* Get the length of the service name. */
1374 rc = SSMR3GetU32(pSSM, &u32);
1375 AssertRCReturn(rc, rc);
1376 AssertReturn(u32 <= VBOX_HGCM_SVC_NAME_MAX_BYTES, VERR_SSM_UNEXPECTED_DATA);
1377
1378 /* Get the service name. */
1379 char szServiceName[VBOX_HGCM_SVC_NAME_MAX_BYTES];
1380 rc = SSMR3GetStrZ(pSSM, szServiceName, u32);
1381 AssertRCReturn(rc, rc);
1382
1383 LogRel(("HGCM: Restoring [%s]\n", szServiceName));
1384
1385 /* Resolve the service instance. */
1386 HGCMService *pSvc;
1387 rc = ResolveService(&pSvc, szServiceName);
1388 AssertLogRelMsgReturn(pSvc, ("rc=%Rrc, %s\n", rc, szServiceName), VERR_SSM_UNEXPECTED_DATA);
1389
1390 /* Get the number of clients. */
1391 uint32_t cClients;
1392 rc = SSMR3GetU32(pSSM, &cClients);
1393 if (RT_FAILURE(rc))
1394 {
1395 pSvc->ReleaseService();
1396 AssertFailed();
1397 return rc;
1398 }
1399
1400 while (cClients--)
1401 {
1402 /* Get the client id. */
1403 uint32_t u32ClientId;
1404 rc = SSMR3GetU32(pSSM, &u32ClientId);
1405 if (RT_FAILURE(rc))
1406 {
1407 pSvc->ReleaseService();
1408 AssertFailed();
1409 return rc;
1410 }
1411
1412 /* Connect the client. */
1413 rc = pSvc->CreateAndConnectClient(NULL, u32ClientId);
1414 if (RT_FAILURE(rc))
1415 {
1416 pSvc->ReleaseService();
1417 AssertLogRelMsgFailed(("rc=%Rrc %s\n", rc, szServiceName));
1418 return rc;
1419 }
1420
1421 /* Call the service, so the operation is executed by the service thread. */
1422 rc = pSvc->loadClientState(u32ClientId, pSSM);
1423 if (RT_FAILURE(rc))
1424 {
1425 pSvc->ReleaseService();
1426 AssertLogRelMsgFailed(("rc=%Rrc %s\n", rc, szServiceName));
1427 return rc;
1428 }
1429 }
1430
1431 pSvc->ReleaseService();
1432 }
1433
1434 return VINF_SUCCESS;
1435}
1436
1437/* Create a new client instance and connect it to the service.
1438 *
1439 * @param pu32ClientIdOut If not NULL, then the method must generate a new handle for the client.
1440 * If NULL, use the given 'u32ClientIdIn' handle.
1441 * @param u32ClientIdIn The handle for the client, when 'pu32ClientIdOut' is NULL.
1442 * @return VBox rc.
1443 */
1444int HGCMService::CreateAndConnectClient(uint32_t *pu32ClientIdOut, uint32_t u32ClientIdIn)
1445{
1446 LogFlowFunc(("pu32ClientIdOut = %p, u32ClientIdIn = %d\n", pu32ClientIdOut, u32ClientIdIn));
1447
1448 /* Allocate a client information structure. */
1449 HGCMClient *pClient = new HGCMClient();
1450
1451 if (!pClient)
1452 {
1453 Log1WarningFunc(("Could not allocate HGCMClient!!!\n"));
1454 return VERR_NO_MEMORY;
1455 }
1456
1457 uint32_t handle;
1458
1459 if (pu32ClientIdOut != NULL)
1460 {
1461 handle = hgcmObjGenerateHandle(pClient);
1462 }
1463 else
1464 {
1465 handle = hgcmObjAssignHandle(pClient, u32ClientIdIn);
1466 }
1467
1468 LogFlowFunc(("client id = %d\n", handle));
1469
1470 AssertRelease(handle);
1471
1472 /* Initialize the HGCM part of the client. */
1473 int rc = pClient->Init(this);
1474
1475 if (RT_SUCCESS(rc))
1476 {
1477 /* Call the service. */
1478 HGCMMsgCore *pCoreMsg;
1479
1480 rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_CONNECT, hgcmMessageAllocSvc);
1481
1482 if (RT_SUCCESS(rc))
1483 {
1484 HGCMMsgSvcConnect *pMsg = (HGCMMsgSvcConnect *)pCoreMsg;
1485
1486 pMsg->u32ClientId = handle;
1487
1488 rc = hgcmMsgSend(pMsg);
1489
1490 if (RT_SUCCESS(rc))
1491 {
1492 /* Add the client Id to the array. */
1493 if (m_cClients == m_cClientsAllocated)
1494 {
1495 const uint32_t cDelta = 64;
1496
1497 /* Guards against integer overflow on 32bit arch and also limits size of m_paClientIds array to 4GB*/
1498 if (m_cClientsAllocated < UINT32_MAX / sizeof(m_paClientIds[0]) - cDelta)
1499 {
1500 uint32_t *paClientIdsNew;
1501
1502 paClientIdsNew = (uint32_t *)RTMemRealloc(m_paClientIds,
1503 (m_cClientsAllocated + cDelta) * sizeof(m_paClientIds[0]));
1504 Assert(paClientIdsNew);
1505
1506 if (paClientIdsNew)
1507 {
1508 m_paClientIds = paClientIdsNew;
1509 m_cClientsAllocated += cDelta;
1510 }
1511 else
1512 {
1513 rc = VERR_NO_MEMORY;
1514 }
1515 }
1516 else
1517 {
1518 rc = VERR_NO_MEMORY;
1519 }
1520 }
1521
1522 m_paClientIds[m_cClients] = handle;
1523 m_cClients++;
1524 }
1525 }
1526 }
1527
1528 if (RT_FAILURE(rc))
1529 {
1530 hgcmObjDeleteHandle(handle);
1531 }
1532 else
1533 {
1534 if (pu32ClientIdOut != NULL)
1535 {
1536 *pu32ClientIdOut = handle;
1537 }
1538
1539 ReferenceService();
1540 }
1541
1542 LogFlowFunc(("rc = %Rrc\n", rc));
1543 return rc;
1544}
1545
1546/* Disconnect the client from the service and delete the client handle.
1547 *
1548 * @param u32ClientId The handle of the client.
1549 * @return VBox rc.
1550 */
1551int HGCMService::DisconnectClient(uint32_t u32ClientId, bool fFromService)
1552{
1553 int rc = VINF_SUCCESS;
1554
1555 LogFlowFunc(("client id = %d, fFromService = %d\n", u32ClientId, fFromService));
1556
1557 if (!fFromService)
1558 {
1559 /* Call the service. */
1560 HGCMMsgCore *pCoreMsg;
1561
1562 rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_DISCONNECT, hgcmMessageAllocSvc);
1563
1564 if (RT_SUCCESS(rc))
1565 {
1566 HGCMMsgSvcDisconnect *pMsg = (HGCMMsgSvcDisconnect *)pCoreMsg;
1567
1568 pMsg->u32ClientId = u32ClientId;
1569
1570 rc = hgcmMsgSend(pMsg);
1571 }
1572 else
1573 {
1574 LogRel(("(%d, %d) [%s] hgcmMsgAlloc(%p, SVC_MSG_DISCONNECT) failed %Rrc\n",
1575 u32ClientId, fFromService, RT_VALID_PTR(m_pszSvcName)? m_pszSvcName: "", m_pThread, rc));
1576 }
1577 }
1578
1579 /* Remove the client id from the array in any case, rc does not matter. */
1580 uint32_t i;
1581
1582 for (i = 0; i < m_cClients; i++)
1583 {
1584 if (m_paClientIds[i] == u32ClientId)
1585 {
1586 m_cClients--;
1587
1588 if (m_cClients > i)
1589 memmove(&m_paClientIds[i], &m_paClientIds[i + 1], sizeof(m_paClientIds[0]) * (m_cClients - i));
1590
1591 /* Delete the client handle. */
1592 hgcmObjDeleteHandle(u32ClientId);
1593
1594 /* The service must be released. */
1595 ReleaseService();
1596
1597 break;
1598 }
1599 }
1600
1601 LogFlowFunc(("rc = %Rrc\n", rc));
1602 return rc;
1603}
1604
1605int HGCMService::RegisterExtension(HGCMSVCEXTHANDLE handle,
1606 PFNHGCMSVCEXT pfnExtension,
1607 void *pvExtension)
1608{
1609 LogFlowFunc(("%s\n", handle->pszServiceName));
1610
1611 /* Forward the message to the service thread. */
1612 HGCMMsgCore *pCoreMsg;
1613 int rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_REGEXT, hgcmMessageAllocSvc);
1614
1615 if (RT_SUCCESS(rc))
1616 {
1617 HGCMMsgSvcRegisterExtension *pMsg = (HGCMMsgSvcRegisterExtension *)pCoreMsg;
1618
1619 pMsg->handle = handle;
1620 pMsg->pfnExtension = pfnExtension;
1621 pMsg->pvExtension = pvExtension;
1622
1623 rc = hgcmMsgSend(pMsg);
1624 }
1625
1626 LogFlowFunc(("rc = %Rrc\n", rc));
1627 return rc;
1628}
1629
1630void HGCMService::UnregisterExtension(HGCMSVCEXTHANDLE handle)
1631{
1632 /* Forward the message to the service thread. */
1633 HGCMMsgCore *pCoreMsg;
1634 int rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_UNREGEXT, hgcmMessageAllocSvc);
1635
1636 if (RT_SUCCESS(rc))
1637 {
1638 HGCMMsgSvcUnregisterExtension *pMsg = (HGCMMsgSvcUnregisterExtension *)pCoreMsg;
1639
1640 pMsg->handle = handle;
1641
1642 rc = hgcmMsgSend(pMsg);
1643 }
1644
1645 LogFlowFunc(("rc = %Rrc\n", rc));
1646}
1647
1648/** Perform a guest call to the service.
1649 *
1650 * @param pHGCMPort The port to be used for completion confirmation.
1651 * @param pCmd The VBox HGCM context.
1652 * @param u32ClientId The client handle to be disconnected and deleted.
1653 * @param u32Function The function number.
1654 * @param cParms Number of parameters.
1655 * @param paParms Pointer to array of parameters.
1656 * @param tsArrival The STAM_GET_TS() value when the request arrived.
1657 * @return VBox rc.
1658 * @retval VINF_HGCM_ASYNC_EXECUTE on success.
1659 */
1660int HGCMService::GuestCall(PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId, uint32_t u32Function,
1661 uint32_t cParms, VBOXHGCMSVCPARM paParms[], uint64_t tsArrival)
1662{
1663 LogFlow(("MAIN::HGCMService::Call\n"));
1664
1665 int rc;
1666 HGCMMsgCall *pMsg = new (std::nothrow) HGCMMsgCall(m_pThread);
1667 if (pMsg)
1668 {
1669 pMsg->Reference();
1670
1671 pMsg->pCmd = pCmd;
1672 pMsg->pHGCMPort = pHGCMPort;
1673 pMsg->u32ClientId = u32ClientId;
1674 pMsg->u32Function = u32Function;
1675 pMsg->cParms = cParms;
1676 pMsg->paParms = paParms;
1677 pMsg->tsArrival = tsArrival;
1678
1679 rc = hgcmMsgPost(pMsg, hgcmMsgCompletionCallback);
1680 }
1681 else
1682 {
1683 Log(("MAIN::HGCMService::Call: Message allocation failed\n"));
1684 rc = VERR_NO_MEMORY;
1685 }
1686
1687 LogFlowFunc(("rc = %Rrc\n", rc));
1688 return rc;
1689}
1690
1691/** Perform a host call the service.
1692 *
1693 * @param u32Function The function number.
1694 * @param cParms Number of parameters.
1695 * @param paParms Pointer to array of parameters.
1696 * @return VBox rc.
1697 */
1698int HGCMService::HostCall(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM *paParms)
1699{
1700 LogFlowFunc(("%s u32Function = %d, cParms = %d, paParms = %p\n",
1701 m_pszSvcName, u32Function, cParms, paParms));
1702
1703 HGCMMsgCore *pCoreMsg;
1704 int rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_HOSTCALL, hgcmMessageAllocSvc);
1705
1706 if (RT_SUCCESS(rc))
1707 {
1708 HGCMMsgHostCallSvc *pMsg = (HGCMMsgHostCallSvc *)pCoreMsg;
1709
1710 pMsg->u32Function = u32Function;
1711 pMsg->cParms = cParms;
1712 pMsg->paParms = paParms;
1713
1714 rc = hgcmMsgSend(pMsg);
1715 }
1716
1717 LogFlowFunc(("rc = %Rrc\n", rc));
1718 return rc;
1719}
1720
1721#ifdef VBOX_WITH_CRHGSMI
1722
1723static DECLCALLBACK(int) hgcmMsgFastCallCompletionCallback(int32_t result, HGCMMsgCore *pMsgCore)
1724{
1725 /* Call the VMMDev port interface to issue IRQ notification. */
1726 LogFlow(("MAIN::hgcmMsgFastCallCompletionCallback: message %p\n", pMsgCore));
1727
1728 HGCMMsgHostFastCallAsyncSvc *pMsg = (HGCMMsgHostFastCallAsyncSvc *)pMsgCore;
1729 if (pMsg->pfnCompletion)
1730 pMsg->pfnCompletion(result, pMsg->u32Function, &pMsg->Param, pMsg->pvCompletion);
1731 return VINF_SUCCESS;
1732}
1733
1734int HGCMService::HandleAcquired()
1735{
1736 ++m_cHandleAcquires;
1737 return VINF_SUCCESS;
1738}
1739
1740int HGCMService::HandleReleased()
1741{
1742 Assert(m_cHandleAcquires);
1743 if (m_cHandleAcquires)
1744 {
1745 --m_cHandleAcquires;
1746 return VINF_SUCCESS;
1747 }
1748 return VERR_INVALID_STATE;
1749}
1750
1751int HGCMService::HostFastCallAsync(uint32_t u32Function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion,
1752 void *pvCompletion)
1753{
1754 LogFlowFunc(("%s u32Function = %d, pParm = %p\n",
1755 m_pszSvcName, u32Function, pParm));
1756
1757 HGCMMsgCore *pCoreMsg;
1758 int rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_HOSTFASTCALLASYNC, hgcmMessageAllocSvc);
1759
1760 if (RT_SUCCESS(rc))
1761 {
1762 HGCMMsgHostFastCallAsyncSvc *pMsg = (HGCMMsgHostFastCallAsyncSvc *)pCoreMsg;
1763
1764 pMsg->u32Function = u32Function;
1765 pMsg->Param = *pParm;
1766 pMsg->pfnCompletion = pfnCompletion;
1767 pMsg->pvCompletion = pvCompletion;
1768
1769 rc = hgcmMsgPost(pMsg, hgcmMsgFastCallCompletionCallback);
1770 }
1771
1772 LogFlowFunc(("rc = %Rrc\n", rc));
1773 return rc;
1774}
1775
1776#endif /* VBOX_WITH_CRHGSMI */
1777
1778/*
1779 * Main HGCM thread that manages services.
1780 */
1781
1782/* Messages processed by the main HGCM thread. */
1783#define HGCM_MSG_CONNECT (10) /* Connect a client to a service. */
1784#define HGCM_MSG_DISCONNECT (11) /* Disconnect the specified client id. */
1785#define HGCM_MSG_LOAD (12) /* Load the service. */
1786#define HGCM_MSG_HOSTCALL (13) /* Call the service. */
1787#define HGCM_MSG_LOADSTATE (14) /* Load saved state for the specified service. */
1788#define HGCM_MSG_SAVESTATE (15) /* Save state for the specified service. */
1789#define HGCM_MSG_RESET (16) /* Disconnect all clients from the specified service. */
1790#define HGCM_MSG_QUIT (17) /* Unload all services and terminate the thread. */
1791#define HGCM_MSG_REGEXT (18) /* Register a service extension. */
1792#define HGCM_MSG_UNREGEXT (19) /* Unregister a service extension. */
1793#ifdef VBOX_WITH_CRHGSMI
1794# define HGCM_MSG_SVCAQUIRE (30) /* Acquire a service handle (for fast host calls) */
1795# define HGCM_MSG_SVCRELEASE (31) /* Release a service */
1796#endif
1797
1798class HGCMMsgMainConnect: public HGCMMsgHeader
1799{
1800 public:
1801 /* Service name. */
1802 const char *pszServiceName;
1803 /* Where to store the client handle. */
1804 uint32_t *pu32ClientId;
1805};
1806
1807class HGCMMsgMainDisconnect: public HGCMMsgHeader
1808{
1809 public:
1810 /* Handle of the client to be disconnected. */
1811 uint32_t u32ClientId;
1812};
1813
1814class HGCMMsgMainLoad: public HGCMMsgCore
1815{
1816 public:
1817 /* Name of the library to be loaded. */
1818 const char *pszServiceLibrary;
1819 /* Name to be assigned to the service. */
1820 const char *pszServiceName;
1821 /** The user mode VM handle (for statistics and such). */
1822 PUVM pUVM;
1823};
1824
1825class HGCMMsgMainHostCall: public HGCMMsgCore
1826{
1827 public:
1828 /* Which service to call. */
1829 const char *pszServiceName;
1830 /* Function number. */
1831 uint32_t u32Function;
1832 /* Number of the function parameters. */
1833 uint32_t cParms;
1834 /* Pointer to array of the function parameters. */
1835 VBOXHGCMSVCPARM *paParms;
1836};
1837
1838class HGCMMsgMainLoadSaveState: public HGCMMsgCore
1839{
1840 public:
1841 /* SSM context. */
1842 PSSMHANDLE pSSM;
1843};
1844
1845class HGCMMsgMainReset: public HGCMMsgCore
1846{
1847};
1848
1849class HGCMMsgMainQuit: public HGCMMsgCore
1850{
1851 public:
1852 /** Whether UVM has gone invalid already or not. */
1853 bool fUvmIsInvalid;
1854};
1855
1856class HGCMMsgMainRegisterExtension: public HGCMMsgCore
1857{
1858 public:
1859 /** Returned handle to be used in HGCMMsgMainUnregisterExtension. */
1860 HGCMSVCEXTHANDLE *pHandle;
1861 /** Name of the service. */
1862 const char *pszServiceName;
1863 /** The extension entry point. */
1864 PFNHGCMSVCEXT pfnExtension;
1865 /** The extension pointer. */
1866 void *pvExtension;
1867};
1868
1869class HGCMMsgMainUnregisterExtension: public HGCMMsgCore
1870{
1871 public:
1872 /* Handle of the registered extension. */
1873 HGCMSVCEXTHANDLE handle;
1874};
1875
1876#ifdef VBOX_WITH_CRHGSMI
1877class HGCMMsgMainSvcAcquire: public HGCMMsgCore
1878{
1879 public:
1880 /* Which service to call. */
1881 const char *pszServiceName;
1882 /* Returned service. */
1883 HGCMService *pService;
1884};
1885
1886class HGCMMsgMainSvcRelease: public HGCMMsgCore
1887{
1888 public:
1889 /* Svc . */
1890 HGCMService *pService;
1891};
1892#endif
1893
1894
1895static HGCMMsgCore *hgcmMainMessageAlloc (uint32_t u32MsgId)
1896{
1897 switch (u32MsgId)
1898 {
1899 case HGCM_MSG_CONNECT: return new HGCMMsgMainConnect();
1900 case HGCM_MSG_DISCONNECT: return new HGCMMsgMainDisconnect();
1901 case HGCM_MSG_LOAD: return new HGCMMsgMainLoad();
1902 case HGCM_MSG_HOSTCALL: return new HGCMMsgMainHostCall();
1903 case HGCM_MSG_LOADSTATE:
1904 case HGCM_MSG_SAVESTATE: return new HGCMMsgMainLoadSaveState();
1905 case HGCM_MSG_RESET: return new HGCMMsgMainReset();
1906 case HGCM_MSG_QUIT: return new HGCMMsgMainQuit();
1907 case HGCM_MSG_REGEXT: return new HGCMMsgMainRegisterExtension();
1908 case HGCM_MSG_UNREGEXT: return new HGCMMsgMainUnregisterExtension();
1909#ifdef VBOX_WITH_CRHGSMI
1910 case HGCM_MSG_SVCAQUIRE: return new HGCMMsgMainSvcAcquire();
1911 case HGCM_MSG_SVCRELEASE: return new HGCMMsgMainSvcRelease();
1912#endif
1913
1914 default:
1915 AssertReleaseMsgFailed(("Msg id = %08X\n", u32MsgId));
1916 }
1917
1918 return NULL;
1919}
1920
1921
1922/* The main HGCM thread handler. */
1923static DECLCALLBACK(void) hgcmThread(HGCMThread *pThread, void *pvUser)
1924{
1925 LogFlowFunc(("pThread = %p, pvUser = %p\n", pThread, pvUser));
1926
1927 NOREF(pvUser);
1928
1929 bool fQuit = false;
1930
1931 while (!fQuit)
1932 {
1933 HGCMMsgCore *pMsgCore;
1934 int rc = hgcmMsgGet(pThread, &pMsgCore);
1935
1936 if (RT_FAILURE(rc))
1937 {
1938 /* The error means some serious unrecoverable problem in the hgcmMsg/hgcmThread layer. */
1939 AssertMsgFailed(("%Rrc\n", rc));
1940 break;
1941 }
1942
1943 uint32_t u32MsgId = pMsgCore->MsgId();
1944
1945 switch (u32MsgId)
1946 {
1947 case HGCM_MSG_CONNECT:
1948 {
1949 HGCMMsgMainConnect *pMsg = (HGCMMsgMainConnect *)pMsgCore;
1950
1951 LogFlowFunc(("HGCM_MSG_CONNECT pszServiceName %s, pu32ClientId %p\n",
1952 pMsg->pszServiceName, pMsg->pu32ClientId));
1953
1954 /* Resolve the service name to the pointer to service instance.
1955 */
1956 HGCMService *pService;
1957 rc = HGCMService::ResolveService(&pService, pMsg->pszServiceName);
1958
1959 if (RT_SUCCESS(rc))
1960 {
1961 /* Call the service instance method. */
1962 rc = pService->CreateAndConnectClient(pMsg->pu32ClientId, 0);
1963
1964 /* Release the service after resolve. */
1965 pService->ReleaseService();
1966 }
1967 } break;
1968
1969 case HGCM_MSG_DISCONNECT:
1970 {
1971 HGCMMsgMainDisconnect *pMsg = (HGCMMsgMainDisconnect *)pMsgCore;
1972
1973 LogFlowFunc(("HGCM_MSG_DISCONNECT u32ClientId = %d\n",
1974 pMsg->u32ClientId));
1975
1976 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(pMsg->u32ClientId, HGCMOBJ_CLIENT);
1977
1978 if (!pClient)
1979 {
1980 rc = VERR_HGCM_INVALID_CLIENT_ID;
1981 break;
1982 }
1983
1984 /* The service the client belongs to. */
1985 HGCMService *pService = pClient->pService;
1986
1987 /* Call the service instance to disconnect the client. */
1988 rc = pService->DisconnectClient(pMsg->u32ClientId, false);
1989
1990 hgcmObjDereference(pClient);
1991 } break;
1992
1993 case HGCM_MSG_LOAD:
1994 {
1995 HGCMMsgMainLoad *pMsg = (HGCMMsgMainLoad *)pMsgCore;
1996
1997 LogFlowFunc(("HGCM_MSG_LOAD pszServiceName = %s, pMsg->pszServiceLibrary = %s, pMsg->pUVM = %p\n",
1998 pMsg->pszServiceName, pMsg->pszServiceLibrary, pMsg->pUVM));
1999
2000 rc = HGCMService::LoadService(pMsg->pszServiceLibrary, pMsg->pszServiceName, pMsg->pUVM);
2001 } break;
2002
2003 case HGCM_MSG_HOSTCALL:
2004 {
2005 HGCMMsgMainHostCall *pMsg = (HGCMMsgMainHostCall *)pMsgCore;
2006
2007 LogFlowFunc(("HGCM_MSG_HOSTCALL pszServiceName %s, u32Function %d, cParms %d, paParms %p\n",
2008 pMsg->pszServiceName, pMsg->u32Function, pMsg->cParms, pMsg->paParms));
2009
2010 /* Resolve the service name to the pointer to service instance. */
2011 HGCMService *pService;
2012 rc = HGCMService::ResolveService(&pService, pMsg->pszServiceName);
2013
2014 if (RT_SUCCESS(rc))
2015 {
2016 rc = pService->HostCall(pMsg->u32Function, pMsg->cParms, pMsg->paParms);
2017
2018 pService->ReleaseService();
2019 }
2020 } break;
2021
2022#ifdef VBOX_WITH_CRHGSMI
2023 case HGCM_MSG_SVCAQUIRE:
2024 {
2025 HGCMMsgMainSvcAcquire *pMsg = (HGCMMsgMainSvcAcquire *)pMsgCore;
2026
2027 LogFlowFunc(("HGCM_MSG_SVCAQUIRE pszServiceName %s\n", pMsg->pszServiceName));
2028
2029 /* Resolve the service name to the pointer to service instance. */
2030 HGCMService *pService;
2031 rc = HGCMService::ResolveService(&pService, pMsg->pszServiceName);
2032 if (RT_SUCCESS(rc))
2033 {
2034 rc = pService->HandleAcquired();
2035 if (RT_SUCCESS(rc))
2036 {
2037 pMsg->pService = pService;
2038 }
2039 else
2040 {
2041 pService->ReleaseService();
2042 }
2043 }
2044 } break;
2045
2046 case HGCM_MSG_SVCRELEASE:
2047 {
2048 HGCMMsgMainSvcRelease *pMsg = (HGCMMsgMainSvcRelease *)pMsgCore;
2049
2050 LogFlowFunc(("HGCM_MSG_SVCARELEASE pService %p\n", pMsg->pService));
2051
2052 /* Resolve the service name to the pointer to service instance. */
2053
2054 rc = pMsg->pService->HandleReleased();
2055 if (RT_SUCCESS(rc))
2056 {
2057 pMsg->pService->ReleaseService();
2058 }
2059 } break;
2060#endif
2061
2062 case HGCM_MSG_RESET:
2063 {
2064 LogFlowFunc(("HGCM_MSG_RESET\n"));
2065
2066 HGCMService::Reset();
2067 } break;
2068
2069 case HGCM_MSG_LOADSTATE:
2070 {
2071 HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pMsgCore;
2072
2073 LogFlowFunc(("HGCM_MSG_LOADSTATE\n"));
2074
2075 rc = HGCMService::LoadState(pMsg->pSSM);
2076 } break;
2077
2078 case HGCM_MSG_SAVESTATE:
2079 {
2080 HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pMsgCore;
2081
2082 LogFlowFunc(("HGCM_MSG_SAVESTATE\n"));
2083
2084 rc = HGCMService::SaveState(pMsg->pSSM);
2085 } break;
2086
2087 case HGCM_MSG_QUIT:
2088 {
2089 HGCMMsgMainQuit *pMsg = (HGCMMsgMainQuit *)pMsgCore;
2090 LogFlowFunc(("HGCM_MSG_QUIT\n"));
2091
2092 HGCMService::UnloadAll(pMsg->fUvmIsInvalid);
2093
2094 fQuit = true;
2095 } break;
2096
2097 case HGCM_MSG_REGEXT:
2098 {
2099 HGCMMsgMainRegisterExtension *pMsg = (HGCMMsgMainRegisterExtension *)pMsgCore;
2100
2101 LogFlowFunc(("HGCM_MSG_REGEXT\n"));
2102
2103 /* Allocate the handle data. */
2104 HGCMSVCEXTHANDLE handle = (HGCMSVCEXTHANDLE)RTMemAllocZ(sizeof(struct _HGCMSVCEXTHANDLEDATA)
2105 + strlen(pMsg->pszServiceName)
2106 + sizeof(char));
2107
2108 if (handle == NULL)
2109 {
2110 rc = VERR_NO_MEMORY;
2111 }
2112 else
2113 {
2114 handle->pszServiceName = (char *)((uint8_t *)handle + sizeof(struct _HGCMSVCEXTHANDLEDATA));
2115 strcpy(handle->pszServiceName, pMsg->pszServiceName);
2116
2117 HGCMService *pService;
2118 rc = HGCMService::ResolveService(&pService, handle->pszServiceName);
2119
2120 if (RT_SUCCESS(rc))
2121 {
2122 pService->RegisterExtension(handle, pMsg->pfnExtension, pMsg->pvExtension);
2123
2124 pService->ReleaseService();
2125 }
2126
2127 if (RT_FAILURE(rc))
2128 {
2129 RTMemFree(handle);
2130 }
2131 else
2132 {
2133 *pMsg->pHandle = handle;
2134 }
2135 }
2136 } break;
2137
2138 case HGCM_MSG_UNREGEXT:
2139 {
2140 HGCMMsgMainUnregisterExtension *pMsg = (HGCMMsgMainUnregisterExtension *)pMsgCore;
2141
2142 LogFlowFunc(("HGCM_MSG_UNREGEXT\n"));
2143
2144 HGCMService *pService;
2145 rc = HGCMService::ResolveService(&pService, pMsg->handle->pszServiceName);
2146
2147 if (RT_SUCCESS(rc))
2148 {
2149 pService->UnregisterExtension(pMsg->handle);
2150
2151 pService->ReleaseService();
2152 }
2153
2154 RTMemFree(pMsg->handle);
2155 } break;
2156
2157 default:
2158 {
2159 AssertMsgFailed(("hgcmThread: Unsupported message number %08X!!!\n", u32MsgId));
2160 rc = VERR_NOT_SUPPORTED;
2161 } break;
2162 }
2163
2164 /* Complete the message processing. */
2165 hgcmMsgComplete(pMsgCore, rc);
2166
2167 LogFlowFunc(("message processed %Rrc\n", rc));
2168 }
2169}
2170
2171
2172/*
2173 * The HGCM API.
2174 */
2175
2176/** The main hgcm thread. */
2177static HGCMThread *g_pHgcmThread = 0;
2178
2179/*
2180 * Public HGCM functions.
2181 *
2182 * hgcmGuest* - called as a result of the guest HGCM requests.
2183 * hgcmHost* - called by the host.
2184 */
2185
2186/* Load a HGCM service from the specified library.
2187 * Assign the specified name to the service.
2188 *
2189 * @param pszServiceLibrary The library to be loaded.
2190 * @param pszServiceName The name to be assigned to the service.
2191 * @param pUVM The user mode VM handle (for statistics and such).
2192 * @return VBox rc.
2193 */
2194int HGCMHostLoad(const char *pszServiceLibrary,
2195 const char *pszServiceName,
2196 PUVM pUVM)
2197{
2198 LogFlowFunc(("lib = %s, name = %s\n", pszServiceLibrary, pszServiceName));
2199
2200 if (!pszServiceLibrary || !pszServiceName)
2201 {
2202 return VERR_INVALID_PARAMETER;
2203 }
2204
2205 /* Forward the request to the main hgcm thread. */
2206 HGCMMsgCore *pCoreMsg;
2207 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_LOAD, hgcmMainMessageAlloc);
2208
2209 if (RT_SUCCESS(rc))
2210 {
2211 /* Initialize the message. Since the message is synchronous, use the supplied pointers. */
2212 HGCMMsgMainLoad *pMsg = (HGCMMsgMainLoad *)pCoreMsg;
2213
2214 pMsg->pszServiceLibrary = pszServiceLibrary;
2215 pMsg->pszServiceName = pszServiceName;
2216 pMsg->pUVM = pUVM;
2217
2218 rc = hgcmMsgSend(pMsg);
2219 }
2220
2221 LogFlowFunc(("rc = %Rrc\n", rc));
2222 return rc;
2223}
2224
2225/* Register a HGCM service extension.
2226 *
2227 * @param pHandle Returned handle for the registered extension.
2228 * @param pszServiceName The name of the service.
2229 * @param pfnExtension The extension entry point (callback).
2230 * @param pvExtension The extension pointer.
2231 * @return VBox rc.
2232 */
2233int HGCMHostRegisterServiceExtension(HGCMSVCEXTHANDLE *pHandle,
2234 const char *pszServiceName,
2235 PFNHGCMSVCEXT pfnExtension,
2236 void *pvExtension)
2237{
2238 LogFlowFunc(("pHandle = %p, name = %s, pfn = %p, rv = %p\n", pHandle, pszServiceName, pfnExtension, pvExtension));
2239
2240 if (!pHandle || !pszServiceName || !pfnExtension)
2241 {
2242 return VERR_INVALID_PARAMETER;
2243 }
2244
2245 /* Forward the request to the main hgcm thread. */
2246 HGCMMsgCore *pCoreMsg;
2247 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_REGEXT, hgcmMainMessageAlloc);
2248
2249 if (RT_SUCCESS(rc))
2250 {
2251 /* Initialize the message. Since the message is synchronous, use the supplied pointers. */
2252 HGCMMsgMainRegisterExtension *pMsg = (HGCMMsgMainRegisterExtension *)pCoreMsg;
2253
2254 pMsg->pHandle = pHandle;
2255 pMsg->pszServiceName = pszServiceName;
2256 pMsg->pfnExtension = pfnExtension;
2257 pMsg->pvExtension = pvExtension;
2258
2259 rc = hgcmMsgSend(pMsg);
2260 }
2261
2262 LogFlowFunc(("*pHandle = %p, rc = %Rrc\n", *pHandle, rc));
2263 return rc;
2264}
2265
2266void HGCMHostUnregisterServiceExtension(HGCMSVCEXTHANDLE handle)
2267{
2268 LogFlowFunc(("handle = %p\n", handle));
2269
2270 /* Forward the request to the main hgcm thread. */
2271 HGCMMsgCore *pCoreMsg;
2272 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_UNREGEXT, hgcmMainMessageAlloc);
2273
2274 if (RT_SUCCESS(rc))
2275 {
2276 /* Initialize the message. */
2277 HGCMMsgMainUnregisterExtension *pMsg = (HGCMMsgMainUnregisterExtension *)pCoreMsg;
2278
2279 pMsg->handle = handle;
2280
2281 rc = hgcmMsgSend(pMsg);
2282 }
2283
2284 LogFlowFunc(("rc = %Rrc\n", rc));
2285 return;
2286}
2287
2288/* Find a service and inform it about a client connection, create a client handle.
2289 *
2290 * @param pHGCMPort The port to be used for completion confirmation.
2291 * @param pCmd The VBox HGCM context.
2292 * @param pszServiceName The name of the service to be connected to.
2293 * @param pu32ClientId Where the store the created client handle.
2294 * @return VBox rc.
2295 */
2296int HGCMGuestConnect(PPDMIHGCMPORT pHGCMPort,
2297 PVBOXHGCMCMD pCmd,
2298 const char *pszServiceName,
2299 uint32_t *pu32ClientId)
2300{
2301 LogFlowFunc(("pHGCMPort = %p, pCmd = %p, name = %s, pu32ClientId = %p\n",
2302 pHGCMPort, pCmd, pszServiceName, pu32ClientId));
2303
2304 if (pHGCMPort == NULL || pCmd == NULL || pszServiceName == NULL || pu32ClientId == NULL)
2305 {
2306 return VERR_INVALID_PARAMETER;
2307 }
2308
2309 /* Forward the request to the main hgcm thread. */
2310 HGCMMsgCore *pCoreMsg;
2311 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_CONNECT, hgcmMainMessageAlloc);
2312
2313 if (RT_SUCCESS(rc))
2314 {
2315 /* Initialize the message. Since 'pszServiceName' and 'pu32ClientId'
2316 * will not be deallocated by the caller until the message is completed,
2317 * use the supplied pointers.
2318 */
2319 HGCMMsgMainConnect *pMsg = (HGCMMsgMainConnect *)pCoreMsg;
2320
2321 pMsg->pHGCMPort = pHGCMPort;
2322 pMsg->pCmd = pCmd;
2323 pMsg->pszServiceName = pszServiceName;
2324 pMsg->pu32ClientId = pu32ClientId;
2325
2326 rc = hgcmMsgPost(pMsg, hgcmMsgCompletionCallback);
2327 }
2328
2329 LogFlowFunc(("rc = %Rrc\n", rc));
2330 return rc;
2331}
2332
2333/* Tell a service that the client is disconnecting, destroy the client handle.
2334 *
2335 * @param pHGCMPort The port to be used for completion confirmation.
2336 * @param pCmd The VBox HGCM context.
2337 * @param u32ClientId The client handle to be disconnected and deleted.
2338 * @return VBox rc.
2339 */
2340int HGCMGuestDisconnect(PPDMIHGCMPORT pHGCMPort,
2341 PVBOXHGCMCMD pCmd,
2342 uint32_t u32ClientId)
2343{
2344 LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d\n",
2345 pHGCMPort, pCmd, u32ClientId));
2346
2347 if (!pHGCMPort || !pCmd || !u32ClientId)
2348 {
2349 return VERR_INVALID_PARAMETER;
2350 }
2351
2352 /* Forward the request to the main hgcm thread. */
2353 HGCMMsgCore *pCoreMsg;
2354 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_DISCONNECT, hgcmMainMessageAlloc);
2355
2356 if (RT_SUCCESS(rc))
2357 {
2358 /* Initialize the message. */
2359 HGCMMsgMainDisconnect *pMsg = (HGCMMsgMainDisconnect *)pCoreMsg;
2360
2361 pMsg->pCmd = pCmd;
2362 pMsg->pHGCMPort = pHGCMPort;
2363 pMsg->u32ClientId = u32ClientId;
2364
2365 rc = hgcmMsgPost(pMsg, hgcmMsgCompletionCallback);
2366 }
2367
2368 LogFlowFunc(("rc = %Rrc\n", rc));
2369 return rc;
2370}
2371
2372/* Helper to send either HGCM_MSG_SAVESTATE or HGCM_MSG_LOADSTATE messages to the main HGCM thread.
2373 *
2374 * @param pSSM The SSM handle.
2375 * @param u32MsgId The message to be sent: HGCM_MSG_SAVESTATE or HGCM_MSG_LOADSTATE.
2376 * @return VBox rc.
2377 */
2378static int hgcmHostLoadSaveState(PSSMHANDLE pSSM,
2379 uint32_t u32MsgId)
2380{
2381 LogFlowFunc(("pSSM = %p, u32MsgId = %d\n", pSSM, u32MsgId));
2382
2383 HGCMMsgCore *pCoreMsg;
2384 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, u32MsgId, hgcmMainMessageAlloc);
2385
2386 if (RT_SUCCESS(rc))
2387 {
2388 HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pCoreMsg;
2389 AssertRelease(pMsg);
2390
2391 pMsg->pSSM = pSSM;
2392
2393 rc = hgcmMsgSend(pMsg);
2394 }
2395
2396 LogFlowFunc(("rc = %Rrc\n", rc));
2397 return rc;
2398}
2399
2400/* Save the state of services.
2401 *
2402 * @param pSSM The SSM handle.
2403 * @return VBox rc.
2404 */
2405int HGCMHostSaveState(PSSMHANDLE pSSM)
2406{
2407 return hgcmHostLoadSaveState(pSSM, HGCM_MSG_SAVESTATE);
2408}
2409
2410/* Load the state of services.
2411 *
2412 * @param pSSM The SSM handle.
2413 * @return VBox rc.
2414 */
2415int HGCMHostLoadState(PSSMHANDLE pSSM)
2416{
2417 return hgcmHostLoadSaveState(pSSM, HGCM_MSG_LOADSTATE);
2418}
2419
2420/* The guest calls the service.
2421 *
2422 * @param pHGCMPort The port to be used for completion confirmation.
2423 * @param pCmd The VBox HGCM context.
2424 * @param u32ClientId The client handle to be disconnected and deleted.
2425 * @param u32Function The function number.
2426 * @param cParms Number of parameters.
2427 * @param paParms Pointer to array of parameters.
2428 * @param tsArrival The STAM_GET_TS() value when the request arrived.
2429 * @return VBox rc.
2430 */
2431int HGCMGuestCall(PPDMIHGCMPORT pHGCMPort,
2432 PVBOXHGCMCMD pCmd,
2433 uint32_t u32ClientId,
2434 uint32_t u32Function,
2435 uint32_t cParms,
2436 VBOXHGCMSVCPARM *paParms,
2437 uint64_t tsArrival)
2438{
2439 LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d, u32Function = %d, cParms = %d, paParms = %p\n",
2440 pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms));
2441
2442 if (!pHGCMPort || !pCmd || u32ClientId == 0)
2443 {
2444 return VERR_INVALID_PARAMETER;
2445 }
2446
2447 int rc = VERR_HGCM_INVALID_CLIENT_ID;
2448
2449 /* Resolve the client handle to the client instance pointer. */
2450 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(u32ClientId, HGCMOBJ_CLIENT);
2451
2452 if (pClient)
2453 {
2454 AssertRelease(pClient->pService);
2455
2456 /* Forward the message to the service thread. */
2457 rc = pClient->pService->GuestCall(pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms, tsArrival);
2458
2459 hgcmObjDereference(pClient);
2460 }
2461
2462 LogFlowFunc(("rc = %Rrc\n", rc));
2463 return rc;
2464}
2465
2466/* The host calls the service.
2467 *
2468 * @param pszServiceName The service name to be called.
2469 * @param u32Function The function number.
2470 * @param cParms Number of parameters.
2471 * @param paParms Pointer to array of parameters.
2472 * @return VBox rc.
2473 */
2474int HGCMHostCall(const char *pszServiceName,
2475 uint32_t u32Function,
2476 uint32_t cParms,
2477 VBOXHGCMSVCPARM *paParms)
2478{
2479 LogFlowFunc(("name = %s, u32Function = %d, cParms = %d, paParms = %p\n",
2480 pszServiceName, u32Function, cParms, paParms));
2481
2482 if (!pszServiceName)
2483 {
2484 return VERR_INVALID_PARAMETER;
2485 }
2486
2487 /* Host calls go to main HGCM thread that resolves the service name to the
2488 * service instance pointer and then, using the service pointer, forwards
2489 * the message to the service thread.
2490 * So it is slow but host calls are intended mostly for configuration and
2491 * other non-time-critical functions.
2492 */
2493 HGCMMsgCore *pCoreMsg;
2494 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_HOSTCALL, hgcmMainMessageAlloc);
2495
2496 if (RT_SUCCESS(rc))
2497 {
2498 HGCMMsgMainHostCall *pMsg = (HGCMMsgMainHostCall *)pCoreMsg;
2499
2500 pMsg->pszServiceName = (char *)pszServiceName;
2501 pMsg->u32Function = u32Function;
2502 pMsg->cParms = cParms;
2503 pMsg->paParms = paParms;
2504
2505 rc = hgcmMsgSend(pMsg);
2506 }
2507
2508 LogFlowFunc(("rc = %Rrc\n", rc));
2509 return rc;
2510}
2511
2512#ifdef VBOX_WITH_CRHGSMI
2513int HGCMHostSvcHandleCreate(const char *pszServiceName, HGCMCVSHANDLE * phSvc)
2514{
2515 LogFlowFunc(("name = %s\n", pszServiceName));
2516
2517 if (!pszServiceName)
2518 {
2519 return VERR_INVALID_PARAMETER;
2520 }
2521
2522 if (!phSvc)
2523 {
2524 return VERR_INVALID_PARAMETER;
2525 }
2526
2527 /* Host calls go to main HGCM thread that resolves the service name to the
2528 * service instance pointer and then, using the service pointer, forwards
2529 * the message to the service thread.
2530 * So it is slow but host calls are intended mostly for configuration and
2531 * other non-time-critical functions.
2532 */
2533 HGCMMsgCore *pCoreMsg;
2534 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_SVCAQUIRE, hgcmMainMessageAlloc);
2535
2536 if (RT_SUCCESS(rc))
2537 {
2538 HGCMMsgMainSvcAcquire *pMsg = (HGCMMsgMainSvcAcquire *)pCoreMsg;
2539
2540 pMsg->pszServiceName = (char *)pszServiceName;
2541 pMsg->pService = NULL;
2542
2543 pMsg->Reference();
2544
2545 rc = hgcmMsgSend(pMsg);
2546 if (RT_SUCCESS(rc))
2547 {
2548 /* for simplicity just use a svc ptr as handle for now */
2549 *phSvc = (HGCMCVSHANDLE)pMsg->pService;
2550 }
2551 pMsg->Dereference();
2552 }
2553
2554 LogFlowFunc(("rc = %Rrc\n", rc));
2555 return rc;
2556}
2557
2558int HGCMHostSvcHandleDestroy(HGCMCVSHANDLE hSvc)
2559{
2560 LogFlowFunc(("hSvc = %p\n", hSvc));
2561
2562 if (!hSvc)
2563 {
2564 return VERR_INVALID_PARAMETER;
2565 }
2566
2567 /* Host calls go to main HGCM thread that resolves the service name to the
2568 * service instance pointer and then, using the service pointer, forwards
2569 * the message to the service thread.
2570 * So it is slow but host calls are intended mostly for configuration and
2571 * other non-time-critical functions.
2572 */
2573 HGCMMsgCore *pCoreMsg;
2574 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_SVCRELEASE, hgcmMainMessageAlloc);
2575
2576 if (RT_SUCCESS(rc))
2577 {
2578 HGCMMsgMainSvcRelease *pMsg = (HGCMMsgMainSvcRelease *)pCoreMsg;
2579
2580 pMsg->pService = (HGCMService *)hSvc;
2581
2582 rc = hgcmMsgSend(pMsg);
2583 }
2584
2585 LogFlowFunc(("rc = %Rrc\n", rc));
2586 return rc;
2587}
2588
2589int HGCMHostFastCallAsync(HGCMCVSHANDLE hSvc, uint32_t function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion,
2590 void *pvCompletion)
2591{
2592 LogFlowFunc(("hSvc = %p, u32Function = %d, pParm = %p\n",
2593 hSvc, function, pParm));
2594
2595 if (!hSvc)
2596 {
2597 return VERR_INVALID_PARAMETER;
2598 }
2599
2600 HGCMService *pService = (HGCMService *)hSvc;
2601 int rc = pService->HostFastCallAsync(function, pParm, pfnCompletion, pvCompletion);
2602
2603 LogFlowFunc(("rc = %Rrc\n", rc));
2604 return rc;
2605}
2606#endif
2607
2608int HGCMHostReset(void)
2609{
2610 LogFlowFunc(("\n"));
2611
2612 /* Disconnect all clients.
2613 */
2614
2615 HGCMMsgCore *pMsg;
2616 int rc = hgcmMsgAlloc(g_pHgcmThread, &pMsg, HGCM_MSG_RESET, hgcmMainMessageAlloc);
2617
2618 if (RT_SUCCESS(rc))
2619 rc = hgcmMsgSend(pMsg);
2620
2621 LogFlowFunc(("rc = %Rrc\n", rc));
2622 return rc;
2623}
2624
2625int HGCMHostInit(void)
2626{
2627 LogFlowFunc(("\n"));
2628
2629 int rc = hgcmThreadInit();
2630
2631 if (RT_SUCCESS(rc))
2632 {
2633 /*
2634 * Start main HGCM thread.
2635 */
2636
2637 rc = hgcmThreadCreate(&g_pHgcmThread, "MainHGCMthread", hgcmThread, NULL /*pvUser*/, NULL /*pszStatsSubDir*/, NULL /*pUVM*/);
2638
2639 if (RT_FAILURE(rc))
2640 LogRel(("Failed to start HGCM thread. HGCM services will be unavailable!!! rc = %Rrc\n", rc));
2641 }
2642
2643 LogFlowFunc(("rc = %Rrc\n", rc));
2644 return rc;
2645}
2646
2647int HGCMHostShutdown(bool fUvmIsInvalid /*= false*/)
2648{
2649 LogFlowFunc(("\n"));
2650
2651 /*
2652 * Do HGCMReset and then unload all services.
2653 */
2654
2655 int rc = HGCMHostReset();
2656
2657 if (RT_SUCCESS(rc))
2658 {
2659 /* Send the quit message to the main hgcmThread. */
2660 HGCMMsgCore *pMsgCore;
2661 rc = hgcmMsgAlloc(g_pHgcmThread, &pMsgCore, HGCM_MSG_QUIT, hgcmMainMessageAlloc);
2662
2663 if (RT_SUCCESS(rc))
2664 {
2665 HGCMMsgMainQuit *pMsg = (HGCMMsgMainQuit *)pMsgCore;
2666 pMsg->fUvmIsInvalid = fUvmIsInvalid;
2667
2668 rc = hgcmMsgSend(pMsg);
2669
2670 if (RT_SUCCESS(rc))
2671 {
2672 /* Wait for the thread termination. */
2673 hgcmThreadWait(g_pHgcmThread);
2674 g_pHgcmThread = NULL;
2675
2676 hgcmThreadUninit();
2677 }
2678 }
2679 }
2680
2681 LogFlowFunc(("rc = %Rrc\n", rc));
2682 return rc;
2683}
2684
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