VirtualBox

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

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

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