VirtualBox

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

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

HGCM,Main,SharedFolder,SharedClipboard,GuestProperties: Added HGCM service helpers for statistics and dbg info registration/deregistration. A PUVM is passed to HGCMService (where the helpers are implemented) when the service is loaded. Since this drags in both dbg.h and stam.h, LOG_GROUP defines now have to be at the top of the include list as everywhere else (i.e. hgcmsvc.h will define LOG_GROUP default by dragging in log.h). Added generic statistics of HGCM message processing and function level statistics to the shared folder service. [missing files, ++]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 78.3 KB
Line 
1/* $Id: HGCM.cpp 75498 2018-11-16 00:03:41Z 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.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
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 HGCMTHREADHANDLE m_thread;
93 friend DECLCALLBACK(void) hgcmServiceThread(HGCMTHREADHANDLE ThreadHandle, 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[]);
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_thread (0),
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
452class HGCMMsgLoadSaveStateClient: public HGCMMsgCore
453{
454 public:
455 uint32_t u32ClientId;
456 PSSMHANDLE pSSM;
457};
458
459class HGCMMsgHostCallSvc: public HGCMMsgCore
460{
461 public:
462 /* function number */
463 uint32_t u32Function;
464
465 /* number of parameters */
466 uint32_t cParms;
467
468 VBOXHGCMSVCPARM *paParms;
469};
470
471class HGCMMsgSvcRegisterExtension: public HGCMMsgCore
472{
473 public:
474 /* Handle of the extension to be registered. */
475 HGCMSVCEXTHANDLE handle;
476 /* The extension entry point. */
477 PFNHGCMSVCEXT pfnExtension;
478 /* The extension pointer. */
479 void *pvExtension;
480};
481
482class HGCMMsgSvcUnregisterExtension: public HGCMMsgCore
483{
484 public:
485 /* Handle of the registered extension. */
486 HGCMSVCEXTHANDLE handle;
487};
488
489#ifdef VBOX_WITH_CRHGSMI
490class HGCMMsgHostFastCallAsyncSvc: public HGCMMsgCore
491{
492 public:
493 /* function number */
494 uint32_t u32Function;
495 /* parameter */
496 VBOXHGCMSVCPARM Param;
497 /* completion info */
498 PHGCMHOSTFASTCALLCB pfnCompletion;
499 void *pvCompletion;
500};
501#endif
502
503static HGCMMsgCore *hgcmMessageAllocSvc(uint32_t u32MsgId)
504{
505 switch (u32MsgId)
506 {
507#ifdef VBOX_WITH_CRHGSMI
508 case SVC_MSG_HOSTFASTCALLASYNC: return new HGCMMsgHostFastCallAsyncSvc();
509#endif
510 case SVC_MSG_LOAD: return new HGCMMsgSvcLoad();
511 case SVC_MSG_UNLOAD: return new HGCMMsgSvcUnload();
512 case SVC_MSG_CONNECT: return new HGCMMsgSvcConnect();
513 case SVC_MSG_DISCONNECT: return new HGCMMsgSvcDisconnect();
514 case SVC_MSG_HOSTCALL: return new HGCMMsgHostCallSvc();
515 case SVC_MSG_GUESTCALL: return new HGCMMsgCall();
516 case SVC_MSG_LOADSTATE:
517 case SVC_MSG_SAVESTATE: return new HGCMMsgLoadSaveStateClient();
518 case SVC_MSG_REGEXT: return new HGCMMsgSvcRegisterExtension();
519 case SVC_MSG_UNREGEXT: return new HGCMMsgSvcUnregisterExtension();
520 default:
521 AssertReleaseMsgFailed(("Msg id = %08X\n", u32MsgId));
522 }
523
524 return NULL;
525}
526
527/*
528 * The service thread. Loads the service library and calls the service entry points.
529 */
530DECLCALLBACK(void) hgcmServiceThread(HGCMTHREADHANDLE ThreadHandle, void *pvUser)
531{
532 HGCMService *pSvc = (HGCMService *)pvUser;
533 AssertRelease(pSvc != NULL);
534
535 bool fQuit = false;
536
537 while (!fQuit)
538 {
539 HGCMMsgCore *pMsgCore;
540 int rc = hgcmMsgGet(ThreadHandle, &pMsgCore);
541
542 if (RT_FAILURE(rc))
543 {
544 /* The error means some serious unrecoverable problem in the hgcmMsg/hgcmThread layer. */
545 AssertMsgFailed(("%Rrc\n", rc));
546 break;
547 }
548
549 STAM_REL_PROFILE_START(&pSvc->m_StatHandleMsg, a);
550
551 /* Cache required information to avoid unnecessary pMsgCore access. */
552 uint32_t u32MsgId = pMsgCore->MsgId();
553
554 switch (u32MsgId)
555 {
556#ifdef VBOX_WITH_CRHGSMI
557 case SVC_MSG_HOSTFASTCALLASYNC:
558 {
559 HGCMMsgHostFastCallAsyncSvc *pMsg = (HGCMMsgHostFastCallAsyncSvc *)pMsgCore;
560
561 LogFlowFunc(("SVC_MSG_HOSTFASTCALLASYNC u32Function = %d, pParm = %p\n", pMsg->u32Function, &pMsg->Param));
562
563 rc = pSvc->m_fntable.pfnHostCall(pSvc->m_fntable.pvService, pMsg->u32Function, 1, &pMsg->Param);
564 } break;
565#endif
566 case SVC_MSG_LOAD:
567 {
568 LogFlowFunc(("SVC_MSG_LOAD\n"));
569 rc = pSvc->loadServiceDLL();
570 } break;
571
572 case SVC_MSG_UNLOAD:
573 {
574 LogFlowFunc(("SVC_MSG_UNLOAD\n"));
575 if (pSvc->m_fntable.pfnUnload)
576 {
577 pSvc->m_fntable.pfnUnload(pSvc->m_fntable.pvService);
578 }
579
580 pSvc->unloadServiceDLL();
581 fQuit = true;
582 } break;
583
584 case SVC_MSG_CONNECT:
585 {
586 HGCMMsgSvcConnect *pMsg = (HGCMMsgSvcConnect *)pMsgCore;
587
588 LogFlowFunc(("SVC_MSG_CONNECT u32ClientId = %d\n", pMsg->u32ClientId));
589
590 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(pMsg->u32ClientId, HGCMOBJ_CLIENT);
591
592 if (pClient)
593 {
594 rc = pSvc->m_fntable.pfnConnect(pSvc->m_fntable.pvService, pMsg->u32ClientId,
595 HGCM_CLIENT_DATA(pSvc, pClient));
596
597 hgcmObjDereference(pClient);
598 }
599 else
600 {
601 rc = VERR_HGCM_INVALID_CLIENT_ID;
602 }
603 } break;
604
605 case SVC_MSG_DISCONNECT:
606 {
607 HGCMMsgSvcDisconnect *pMsg = (HGCMMsgSvcDisconnect *)pMsgCore;
608
609 LogFlowFunc(("SVC_MSG_DISCONNECT u32ClientId = %d\n", pMsg->u32ClientId));
610
611 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(pMsg->u32ClientId, HGCMOBJ_CLIENT);
612
613 if (pClient)
614 {
615 rc = pSvc->m_fntable.pfnDisconnect(pSvc->m_fntable.pvService, pMsg->u32ClientId,
616 HGCM_CLIENT_DATA(pSvc, pClient));
617
618 hgcmObjDereference(pClient);
619 }
620 else
621 {
622 rc = VERR_HGCM_INVALID_CLIENT_ID;
623 }
624 } break;
625
626 case SVC_MSG_GUESTCALL:
627 {
628 HGCMMsgCall *pMsg = (HGCMMsgCall *)pMsgCore;
629
630 LogFlowFunc(("SVC_MSG_GUESTCALL u32ClientId = %d, u32Function = %d, cParms = %d, paParms = %p\n",
631 pMsg->u32ClientId, pMsg->u32Function, pMsg->cParms, pMsg->paParms));
632
633 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(pMsg->u32ClientId, HGCMOBJ_CLIENT);
634
635 if (pClient)
636 {
637 pSvc->m_fntable.pfnCall(pSvc->m_fntable.pvService, (VBOXHGCMCALLHANDLE)pMsg, pMsg->u32ClientId,
638 HGCM_CLIENT_DATA(pSvc, pClient), pMsg->u32Function,
639 pMsg->cParms, pMsg->paParms);
640
641 hgcmObjDereference(pClient);
642 }
643 else
644 {
645 rc = VERR_HGCM_INVALID_CLIENT_ID;
646 }
647 } break;
648
649 case SVC_MSG_HOSTCALL:
650 {
651 HGCMMsgHostCallSvc *pMsg = (HGCMMsgHostCallSvc *)pMsgCore;
652
653 LogFlowFunc(("SVC_MSG_HOSTCALL u32Function = %d, cParms = %d, paParms = %p\n",
654 pMsg->u32Function, pMsg->cParms, pMsg->paParms));
655
656 rc = pSvc->m_fntable.pfnHostCall(pSvc->m_fntable.pvService, pMsg->u32Function, pMsg->cParms, pMsg->paParms);
657 } break;
658
659 case SVC_MSG_LOADSTATE:
660 {
661 HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)pMsgCore;
662
663 LogFlowFunc(("SVC_MSG_LOADSTATE\n"));
664
665 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(pMsg->u32ClientId, HGCMOBJ_CLIENT);
666
667 if (pClient)
668 {
669 if (pSvc->m_fntable.pfnLoadState)
670 {
671 rc = pSvc->m_fntable.pfnLoadState(pSvc->m_fntable.pvService, pMsg->u32ClientId,
672 HGCM_CLIENT_DATA(pSvc, pClient), pMsg->pSSM);
673 }
674
675 hgcmObjDereference(pClient);
676 }
677 else
678 {
679 rc = VERR_HGCM_INVALID_CLIENT_ID;
680 }
681 } break;
682
683 case SVC_MSG_SAVESTATE:
684 {
685 HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)pMsgCore;
686
687 LogFlowFunc(("SVC_MSG_SAVESTATE\n"));
688
689 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(pMsg->u32ClientId, HGCMOBJ_CLIENT);
690
691 rc = VINF_SUCCESS;
692
693 if (pClient)
694 {
695 if (pSvc->m_fntable.pfnSaveState)
696 {
697 g_fSaveState = true;
698 rc = pSvc->m_fntable.pfnSaveState(pSvc->m_fntable.pvService, pMsg->u32ClientId,
699 HGCM_CLIENT_DATA(pSvc, pClient), pMsg->pSSM);
700 g_fSaveState = false;
701 }
702
703 hgcmObjDereference(pClient);
704 }
705 else
706 {
707 rc = VERR_HGCM_INVALID_CLIENT_ID;
708 }
709 } break;
710
711 case SVC_MSG_REGEXT:
712 {
713 HGCMMsgSvcRegisterExtension *pMsg = (HGCMMsgSvcRegisterExtension *)pMsgCore;
714
715 LogFlowFunc(("SVC_MSG_REGEXT handle = %p, pfn = %p\n", pMsg->handle, pMsg->pfnExtension));
716
717 if (pSvc->m_hExtension)
718 {
719 rc = VERR_NOT_SUPPORTED;
720 }
721 else
722 {
723 if (pSvc->m_fntable.pfnRegisterExtension)
724 {
725 rc = pSvc->m_fntable.pfnRegisterExtension(pSvc->m_fntable.pvService, pMsg->pfnExtension,
726 pMsg->pvExtension);
727 }
728 else
729 {
730 rc = VERR_NOT_SUPPORTED;
731 }
732
733 if (RT_SUCCESS(rc))
734 {
735 pSvc->m_hExtension = pMsg->handle;
736 }
737 }
738 } break;
739
740 case SVC_MSG_UNREGEXT:
741 {
742 HGCMMsgSvcUnregisterExtension *pMsg = (HGCMMsgSvcUnregisterExtension *)pMsgCore;
743
744 LogFlowFunc(("SVC_MSG_UNREGEXT handle = %p\n", pMsg->handle));
745
746 if (pSvc->m_hExtension != pMsg->handle)
747 {
748 rc = VERR_NOT_SUPPORTED;
749 }
750 else
751 {
752 if (pSvc->m_fntable.pfnRegisterExtension)
753 {
754 rc = pSvc->m_fntable.pfnRegisterExtension(pSvc->m_fntable.pvService, NULL, NULL);
755 }
756 else
757 {
758 rc = VERR_NOT_SUPPORTED;
759 }
760
761 pSvc->m_hExtension = NULL;
762 }
763 } break;
764
765 default:
766 {
767 AssertMsgFailed(("hgcmServiceThread::Unsupported message number %08X\n", u32MsgId));
768 rc = VERR_NOT_SUPPORTED;
769 } break;
770 }
771
772 if (u32MsgId != SVC_MSG_GUESTCALL)
773 {
774 /* For SVC_MSG_GUESTCALL the service calls the completion helper.
775 * Other messages have to be completed here.
776 */
777 hgcmMsgComplete (pMsgCore, rc);
778 }
779 STAM_REL_PROFILE_STOP(&pSvc->m_StatHandleMsg, a);
780 }
781}
782
783/**
784 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnCallComplete}
785 */
786/* static */ DECLCALLBACK(void) HGCMService::svcHlpCallComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc)
787{
788 HGCMMsgCore *pMsgCore = (HGCMMsgCore *)callHandle;
789
790 if (pMsgCore->MsgId () == SVC_MSG_GUESTCALL)
791 {
792 /* Only call the completion for these messages. The helper
793 * is called by the service, and the service does not get
794 * any other messages.
795 */
796 hgcmMsgComplete(pMsgCore, rc);
797 }
798 else
799 {
800 AssertFailed();
801 }
802}
803
804/**
805 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnDisconnectClient}
806 */
807/* static */ DECLCALLBACK(void) HGCMService::svcHlpDisconnectClient(void *pvInstance, uint32_t u32ClientId)
808{
809 HGCMService *pService = static_cast <HGCMService *> (pvInstance);
810
811 if (pService)
812 {
813 pService->DisconnectClient(u32ClientId, true);
814 }
815}
816
817/**
818 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnIsCallRestored}
819 */
820/* static */ DECLCALLBACK(bool) HGCMService::svcHlpIsCallRestored(VBOXHGCMCALLHANDLE callHandle)
821{
822 HGCMMsgHeader *pMsgHdr = (HGCMMsgHeader *)(callHandle);
823 AssertPtrReturn(pMsgHdr, false);
824
825 PVBOXHGCMCMD pCmd = pMsgHdr->pCmd;
826 AssertPtrReturn(pCmd, false);
827
828 PPDMIHGCMPORT pHgcmPort = pMsgHdr->pHGCMPort;
829 AssertPtrReturn(pHgcmPort, false);
830
831 return pHgcmPort->pfnIsCmdRestored(pHgcmPort, pCmd);
832}
833
834/**
835 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnStamRegisterV}
836 */
837/* static */ DECLCALLBACK(int)
838HGCMService::svcHlpStamRegisterV(void *pvInstance, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
839 STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list va)
840{
841 HGCMService *pService = static_cast <HGCMService *>(pvInstance);
842 AssertPtrReturn(pService, VERR_INVALID_PARAMETER);
843
844 return STAMR3RegisterVU(pService->m_pUVM, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, va);
845}
846
847/**
848 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnStamDeregisterV}
849 */
850/* static */ DECLCALLBACK(int) HGCMService::svcHlpStamDeregisterV(void *pvInstance, const char *pszPatFmt, va_list va)
851{
852 HGCMService *pService = static_cast <HGCMService *>(pvInstance);
853 AssertPtrReturn(pService, VERR_INVALID_PARAMETER);
854
855 return STAMR3DeregisterV(pService->m_pUVM, pszPatFmt, va);
856}
857
858/**
859 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnInfoRegister}
860 */
861/* static */ DECLCALLBACK(int) HGCMService::svcHlpInfoRegister(void *pvInstance, const char *pszName, const char *pszDesc,
862 PFNDBGFHANDLEREXT pfnHandler, void *pvUser)
863{
864 HGCMService *pService = static_cast <HGCMService *>(pvInstance);
865 AssertPtrReturn(pService, VERR_INVALID_PARAMETER);
866
867 return DBGFR3InfoRegisterExternal(pService->m_pUVM, pszName, pszDesc, pfnHandler, pvUser);
868}
869
870/**
871 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnInfoDeregister}
872 */
873/* static */ DECLCALLBACK(int) HGCMService::svcHlpInfoDeregister(void *pvInstance, const char *pszName)
874{
875 HGCMService *pService = static_cast <HGCMService *>(pvInstance);
876 AssertPtrReturn(pService, VERR_INVALID_PARAMETER);
877
878 return DBGFR3InfoDeregisterExternal(pService->m_pUVM, pszName);
879}
880
881
882static DECLCALLBACK(void) hgcmMsgCompletionCallback(int32_t result, HGCMMsgCore *pMsgCore)
883{
884 /* Call the VMMDev port interface to issue IRQ notification. */
885 HGCMMsgHeader *pMsgHdr = (HGCMMsgHeader *)pMsgCore;
886
887 LogFlow(("MAIN::hgcmMsgCompletionCallback: message %p\n", pMsgCore));
888
889 if (pMsgHdr->pHGCMPort && !g_fResetting)
890 {
891 pMsgHdr->pHGCMPort->pfnCompleted(pMsgHdr->pHGCMPort, g_fSaveState? VINF_HGCM_SAVE_STATE: result, pMsgHdr->pCmd);
892 }
893}
894
895/*
896 * The main HGCM methods of the service.
897 */
898
899int HGCMService::instanceCreate(const char *pszServiceLibrary, const char *pszServiceName, PUVM pUVM)
900{
901 LogFlowFunc(("name %s, lib %s\n", pszServiceName, pszServiceLibrary));
902 /* The maximum length of the thread name, allowed by the RT is 15. */
903 char szThreadName[16];
904 if (!strncmp(pszServiceName, RT_STR_TUPLE("VBoxShared")))
905 RTStrPrintf(szThreadName, sizeof(szThreadName), "Sh%s", pszServiceName + 10);
906 else if (!strncmp(pszServiceName, RT_STR_TUPLE("VBox")))
907 RTStrCopy(szThreadName, sizeof(szThreadName), pszServiceName + 4);
908 else
909 RTStrCopy(szThreadName, sizeof(szThreadName), pszServiceName);
910
911 int rc = hgcmThreadCreate(&m_thread, szThreadName, hgcmServiceThread, this, pszServiceName, pUVM);
912
913 if (RT_SUCCESS(rc))
914 {
915 m_pszSvcName = RTStrDup(pszServiceName);
916 m_pszSvcLibrary = RTStrDup(pszServiceLibrary);
917
918 if (!m_pszSvcName || !m_pszSvcLibrary)
919 {
920 RTStrFree(m_pszSvcLibrary);
921 m_pszSvcLibrary = NULL;
922
923 RTStrFree(m_pszSvcName);
924 m_pszSvcName = NULL;
925
926 rc = VERR_NO_MEMORY;
927 }
928 else
929 {
930 /* Register statistics: */
931 m_pUVM = pUVM;
932 STAMR3RegisterFU(pUVM, &m_StatHandleMsg, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
933 "Message handling", "/HGCM/%s/Msg", pszServiceName);
934
935 /* Initialize service helpers table. */
936 m_svcHelpers.pfnCallComplete = svcHlpCallComplete;
937 m_svcHelpers.pvInstance = this;
938 m_svcHelpers.pfnDisconnectClient = svcHlpDisconnectClient;
939 m_svcHelpers.pfnIsCallRestored = svcHlpIsCallRestored;
940 m_svcHelpers.pfnStamRegisterV = svcHlpStamRegisterV;
941 m_svcHelpers.pfnStamDeregisterV = svcHlpStamDeregisterV;
942 m_svcHelpers.pfnInfoRegister = svcHlpInfoRegister;
943 m_svcHelpers.pfnInfoDeregister = svcHlpInfoDeregister;
944
945 /* Execute the load request on the service thread. */
946 HGCMMSGHANDLE hMsg;
947 rc = hgcmMsgAlloc(m_thread, &hMsg, SVC_MSG_LOAD, hgcmMessageAllocSvc);
948
949 if (RT_SUCCESS(rc))
950 {
951 HGCMMsgSvcLoad *pMsg = (HGCMMsgSvcLoad *)hgcmObjReference(hMsg, HGCMOBJ_MSG);
952 AssertRelease(pMsg);
953 pMsg->pUVM = pUVM;
954 hgcmObjDereference(pMsg);
955
956 rc = hgcmMsgSend(hMsg);
957 }
958 }
959 }
960
961 if (RT_FAILURE(rc))
962 {
963 instanceDestroy();
964 }
965
966 LogFlowFunc(("rc = %Rrc\n", rc));
967 return rc;
968}
969
970void HGCMService::instanceDestroy(void)
971{
972 LogFlowFunc(("%s\n", m_pszSvcName));
973
974 HGCMMSGHANDLE hMsg;
975 int rc = hgcmMsgAlloc(m_thread, &hMsg, SVC_MSG_UNLOAD, hgcmMessageAllocSvc);
976
977 if (RT_SUCCESS(rc))
978 {
979 rc = hgcmMsgSend(hMsg);
980
981 if (RT_SUCCESS(rc))
982 {
983 hgcmThreadWait(m_thread);
984 }
985 }
986
987 if (m_pszSvcName)
988 STAMR3DeregisterF(m_pUVM, "/HGCM/%s/*", m_pszSvcName);
989 m_pUVM = NULL;
990
991 RTStrFree(m_pszSvcLibrary);
992 m_pszSvcLibrary = NULL;
993
994 RTStrFree(m_pszSvcName);
995 m_pszSvcName = NULL;
996}
997
998int HGCMService::saveClientState(uint32_t u32ClientId, PSSMHANDLE pSSM)
999{
1000 LogFlowFunc(("%s\n", m_pszSvcName));
1001
1002 HGCMMSGHANDLE hMsg;
1003 int rc = hgcmMsgAlloc(m_thread, &hMsg, SVC_MSG_SAVESTATE, hgcmMessageAllocSvc);
1004
1005 if (RT_SUCCESS(rc))
1006 {
1007 HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)hgcmObjReference(hMsg, HGCMOBJ_MSG);
1008 AssertRelease(pMsg);
1009
1010 pMsg->u32ClientId = u32ClientId;
1011 pMsg->pSSM = pSSM;
1012
1013 hgcmObjDereference(pMsg);
1014
1015 rc = hgcmMsgSend(hMsg);
1016 }
1017
1018 LogFlowFunc(("rc = %Rrc\n", rc));
1019 return rc;
1020}
1021
1022int HGCMService::loadClientState(uint32_t u32ClientId, PSSMHANDLE pSSM)
1023{
1024 LogFlowFunc(("%s\n", m_pszSvcName));
1025
1026 HGCMMSGHANDLE hMsg;
1027 int rc = hgcmMsgAlloc(m_thread, &hMsg, SVC_MSG_LOADSTATE, hgcmMessageAllocSvc);
1028
1029 if (RT_SUCCESS(rc))
1030 {
1031 HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)hgcmObjReference(hMsg, HGCMOBJ_MSG);
1032
1033 AssertRelease(pMsg);
1034
1035 pMsg->u32ClientId = u32ClientId;
1036 pMsg->pSSM = pSSM;
1037
1038 hgcmObjDereference(pMsg);
1039
1040 rc = hgcmMsgSend(hMsg);
1041 }
1042
1043 LogFlowFunc(("rc = %Rrc\n", rc));
1044 return rc;
1045}
1046
1047
1048/** The method creates a service and references it.
1049 *
1050 * @param pszServiceLibrary The library to be loaded.
1051 * @param pszServiceName The name of the service.
1052 * @param pUVM The user mode VM handle (for statistics and such).
1053 * @return VBox rc.
1054 * @thread main HGCM
1055 */
1056/* static */ int HGCMService::LoadService(const char *pszServiceLibrary, const char *pszServiceName, PUVM pUVM)
1057{
1058 LogFlowFunc(("lib %s, name = %s, pUVM = %p\n", pszServiceLibrary, pszServiceName, pUVM));
1059
1060 /* Look at already loaded services to avoid double loading. */
1061
1062 HGCMService *pSvc;
1063 int rc = HGCMService::ResolveService(&pSvc, pszServiceName);
1064
1065 if (RT_SUCCESS(rc))
1066 {
1067 /* The service is already loaded. */
1068 pSvc->ReleaseService();
1069 rc = VERR_HGCM_SERVICE_EXISTS;
1070 }
1071 else
1072 {
1073 /* Create the new service. */
1074 pSvc = new (std::nothrow) HGCMService();
1075
1076 if (!pSvc)
1077 {
1078 rc = VERR_NO_MEMORY;
1079 }
1080 else
1081 {
1082 /* Load the library and call the initialization entry point. */
1083 rc = pSvc->instanceCreate(pszServiceLibrary, pszServiceName, pUVM);
1084
1085 if (RT_SUCCESS(rc))
1086 {
1087 /* Insert the just created service to list for future references. */
1088 pSvc->m_pSvcNext = sm_pSvcListHead;
1089 pSvc->m_pSvcPrev = NULL;
1090
1091 if (sm_pSvcListHead)
1092 {
1093 sm_pSvcListHead->m_pSvcPrev = pSvc;
1094 }
1095 else
1096 {
1097 sm_pSvcListTail = pSvc;
1098 }
1099
1100 sm_pSvcListHead = pSvc;
1101
1102 sm_cServices++;
1103
1104 /* Reference the service (for first time) until it is unloaded on HGCM termination. */
1105 AssertRelease(pSvc->m_u32RefCnt == 0);
1106 pSvc->ReferenceService();
1107
1108 LogFlowFunc(("service %p\n", pSvc));
1109 }
1110 }
1111 }
1112
1113 LogFlowFunc(("rc = %Rrc\n", rc));
1114 return rc;
1115}
1116
1117/** The method unloads a service.
1118 *
1119 * @thread main HGCM
1120 */
1121void HGCMService::UnloadService(void)
1122{
1123 LogFlowFunc(("name = %s\n", m_pszSvcName));
1124
1125 /* Remove the service from the list. */
1126 if (m_pSvcNext)
1127 {
1128 m_pSvcNext->m_pSvcPrev = m_pSvcPrev;
1129 }
1130 else
1131 {
1132 sm_pSvcListTail = m_pSvcPrev;
1133 }
1134
1135 if (m_pSvcPrev)
1136 {
1137 m_pSvcPrev->m_pSvcNext = m_pSvcNext;
1138 }
1139 else
1140 {
1141 sm_pSvcListHead = m_pSvcNext;
1142 }
1143
1144 sm_cServices--;
1145
1146 /* The service must be unloaded only if all clients were disconnected. */
1147 LogFlowFunc(("m_u32RefCnt = %d\n", m_u32RefCnt));
1148 AssertRelease(m_u32RefCnt == 1);
1149
1150 /* Now the service can be released. */
1151 ReleaseService();
1152}
1153
1154/** The method unloads all services.
1155 *
1156 * @thread main HGCM
1157 */
1158/* static */ void HGCMService::UnloadAll(void)
1159{
1160 while (sm_pSvcListHead)
1161 {
1162 sm_pSvcListHead->UnloadService();
1163 }
1164}
1165
1166/** The method obtains a referenced pointer to the service with
1167 * specified name. The caller must call ReleaseService when
1168 * the pointer is no longer needed.
1169 *
1170 * @param ppSvc Where to store the pointer to the service.
1171 * @param pszServiceName The name of the service.
1172 * @return VBox rc.
1173 * @thread main HGCM
1174 */
1175/* static */ int HGCMService::ResolveService(HGCMService **ppSvc, const char *pszServiceName)
1176{
1177 LogFlowFunc(("ppSvc = %p name = %s\n",
1178 ppSvc, pszServiceName));
1179
1180 if (!ppSvc || !pszServiceName)
1181 {
1182 return VERR_INVALID_PARAMETER;
1183 }
1184
1185 HGCMService *pSvc = sm_pSvcListHead;
1186
1187 while (pSvc)
1188 {
1189 if (strcmp(pSvc->m_pszSvcName, pszServiceName) == 0)
1190 {
1191 break;
1192 }
1193
1194 pSvc = pSvc->m_pSvcNext;
1195 }
1196
1197 LogFlowFunc(("lookup in the list is %p\n", pSvc));
1198
1199 if (pSvc == NULL)
1200 {
1201 *ppSvc = NULL;
1202 return VERR_HGCM_SERVICE_NOT_FOUND;
1203 }
1204
1205 pSvc->ReferenceService();
1206
1207 *ppSvc = pSvc;
1208
1209 return VINF_SUCCESS;
1210}
1211
1212/** The method increases reference counter.
1213 *
1214 * @thread main HGCM
1215 */
1216void HGCMService::ReferenceService(void)
1217{
1218 ASMAtomicIncU32(&m_u32RefCnt);
1219 LogFlowFunc(("[%s] m_u32RefCnt = %d\n", m_pszSvcName, m_u32RefCnt));
1220}
1221
1222/** The method dereferences a service and deletes it when no more refs.
1223 *
1224 * @thread main HGCM
1225 */
1226void HGCMService::ReleaseService(void)
1227{
1228 LogFlowFunc(("m_u32RefCnt = %d\n", m_u32RefCnt));
1229 uint32_t u32RefCnt = ASMAtomicDecU32(&m_u32RefCnt);
1230 AssertRelease(u32RefCnt != ~0U);
1231
1232 LogFlowFunc(("u32RefCnt = %d, name %s\n", u32RefCnt, m_pszSvcName));
1233
1234 if (u32RefCnt == 0)
1235 {
1236 instanceDestroy();
1237 delete this;
1238 }
1239}
1240
1241/** The method is called when the VM is being reset or terminated
1242 * and disconnects all clients from all services.
1243 *
1244 * @thread main HGCM
1245 */
1246/* static */ void HGCMService::Reset(void)
1247{
1248 g_fResetting = true;
1249
1250 HGCMService *pSvc = sm_pSvcListHead;
1251
1252 while (pSvc)
1253 {
1254 while (pSvc->m_cClients && pSvc->m_paClientIds)
1255 {
1256 LogFlowFunc(("handle %d\n", pSvc->m_paClientIds[0]));
1257 pSvc->DisconnectClient(pSvc->m_paClientIds[0], false);
1258 }
1259
1260#ifdef VBOX_WITH_CRHGSMI
1261 /** @todo could this actually happen that the service is destroyed on ReleaseService? */
1262 HGCMService *pNextSvc = pSvc->m_pSvcNext;
1263 while (pSvc->m_cHandleAcquires)
1264 {
1265 pSvc->HandleReleased();
1266 pSvc->ReleaseService();
1267 }
1268 pSvc = pNextSvc;
1269#else
1270 pSvc = pSvc->m_pSvcNext;
1271#endif
1272 }
1273
1274 g_fResetting = false;
1275}
1276
1277/** The method saves the HGCM state.
1278 *
1279 * @param pSSM The saved state context.
1280 * @return VBox rc.
1281 * @thread main HGCM
1282 */
1283/* static */ int HGCMService::SaveState(PSSMHANDLE pSSM)
1284{
1285 /* Save the current handle count and restore afterwards to avoid client id conflicts. */
1286 int rc = SSMR3PutU32(pSSM, hgcmObjQueryHandleCount());
1287 AssertRCReturn(rc, rc);
1288
1289 LogFlowFunc(("%d services to be saved:\n", sm_cServices));
1290
1291 /* Save number of services. */
1292 rc = SSMR3PutU32(pSSM, sm_cServices);
1293 AssertRCReturn(rc, rc);
1294
1295 /* Save every service. */
1296 HGCMService *pSvc = sm_pSvcListHead;
1297
1298 while (pSvc)
1299 {
1300 LogFlowFunc(("Saving service [%s]\n", pSvc->m_pszSvcName));
1301
1302 /* Save the length of the service name. */
1303 rc = SSMR3PutU32(pSSM, (uint32_t) strlen(pSvc->m_pszSvcName) + 1);
1304 AssertRCReturn(rc, rc);
1305
1306 /* Save the name of the service. */
1307 rc = SSMR3PutStrZ(pSSM, pSvc->m_pszSvcName);
1308 AssertRCReturn(rc, rc);
1309
1310 /* Save the number of clients. */
1311 rc = SSMR3PutU32(pSSM, pSvc->m_cClients);
1312 AssertRCReturn(rc, rc);
1313
1314 /* Call the service for every client. Normally a service must not have
1315 * a global state to be saved: only per client info is relevant.
1316 * The global state of a service is configured during VM startup.
1317 */
1318 uint32_t i;
1319
1320 for (i = 0; i < pSvc->m_cClients; i++)
1321 {
1322 uint32_t u32ClientId = pSvc->m_paClientIds[i];
1323
1324 Log(("client id 0x%08X\n", u32ClientId));
1325
1326 /* Save the client id. */
1327 rc = SSMR3PutU32(pSSM, u32ClientId);
1328 AssertRCReturn(rc, rc);
1329
1330 /* Call the service, so the operation is executed by the service thread. */
1331 rc = pSvc->saveClientState(u32ClientId, pSSM);
1332 AssertRCReturn(rc, rc);
1333 }
1334
1335 pSvc = pSvc->m_pSvcNext;
1336 }
1337
1338 return VINF_SUCCESS;
1339}
1340
1341/** The method loads saved HGCM state.
1342 *
1343 * @param pSSM The saved state context.
1344 * @return VBox rc.
1345 * @thread main HGCM
1346 */
1347/* static */ int HGCMService::LoadState(PSSMHANDLE pSSM)
1348{
1349 /* Restore handle count to avoid client id conflicts. */
1350 uint32_t u32;
1351
1352 int rc = SSMR3GetU32(pSSM, &u32);
1353 AssertRCReturn(rc, rc);
1354
1355 hgcmObjSetHandleCount(u32);
1356
1357 /* Get the number of services. */
1358 uint32_t cServices;
1359
1360 rc = SSMR3GetU32(pSSM, &cServices);
1361 AssertRCReturn(rc, rc);
1362
1363 LogFlowFunc(("%d services to be restored:\n", cServices));
1364
1365 while (cServices--)
1366 {
1367 /* Get the length of the service name. */
1368 rc = SSMR3GetU32(pSSM, &u32);
1369 AssertRCReturn(rc, rc);
1370 AssertReturn(u32 <= VBOX_HGCM_SVC_NAME_MAX_BYTES, VERR_SSM_UNEXPECTED_DATA);
1371
1372 /* Get the service name. */
1373 char szServiceName[VBOX_HGCM_SVC_NAME_MAX_BYTES];
1374 rc = SSMR3GetStrZ(pSSM, szServiceName, u32);
1375 AssertRCReturn(rc, rc);
1376
1377 LogRel(("HGCM: Restoring [%s]\n", szServiceName));
1378
1379 /* Resolve the service instance. */
1380 HGCMService *pSvc;
1381 rc = ResolveService(&pSvc, szServiceName);
1382 AssertLogRelMsgReturn(pSvc, ("rc=%Rrc, %s\n", rc, szServiceName), VERR_SSM_UNEXPECTED_DATA);
1383
1384 /* Get the number of clients. */
1385 uint32_t cClients;
1386 rc = SSMR3GetU32(pSSM, &cClients);
1387 if (RT_FAILURE(rc))
1388 {
1389 pSvc->ReleaseService();
1390 AssertFailed();
1391 return rc;
1392 }
1393
1394 while (cClients--)
1395 {
1396 /* Get the client id. */
1397 uint32_t u32ClientId;
1398 rc = SSMR3GetU32(pSSM, &u32ClientId);
1399 if (RT_FAILURE(rc))
1400 {
1401 pSvc->ReleaseService();
1402 AssertFailed();
1403 return rc;
1404 }
1405
1406 /* Connect the client. */
1407 rc = pSvc->CreateAndConnectClient(NULL, u32ClientId);
1408 if (RT_FAILURE(rc))
1409 {
1410 pSvc->ReleaseService();
1411 AssertLogRelMsgFailed(("rc=%Rrc %s\n", rc, szServiceName));
1412 return rc;
1413 }
1414
1415 /* Call the service, so the operation is executed by the service thread. */
1416 rc = pSvc->loadClientState(u32ClientId, pSSM);
1417 if (RT_FAILURE(rc))
1418 {
1419 pSvc->ReleaseService();
1420 AssertLogRelMsgFailed(("rc=%Rrc %s\n", rc, szServiceName));
1421 return rc;
1422 }
1423 }
1424
1425 pSvc->ReleaseService();
1426 }
1427
1428 return VINF_SUCCESS;
1429}
1430
1431/* Create a new client instance and connect it to the service.
1432 *
1433 * @param pu32ClientIdOut If not NULL, then the method must generate a new handle for the client.
1434 * If NULL, use the given 'u32ClientIdIn' handle.
1435 * @param u32ClientIdIn The handle for the client, when 'pu32ClientIdOut' is NULL.
1436 * @return VBox rc.
1437 */
1438int HGCMService::CreateAndConnectClient(uint32_t *pu32ClientIdOut, uint32_t u32ClientIdIn)
1439{
1440 LogFlowFunc(("pu32ClientIdOut = %p, u32ClientIdIn = %d\n", pu32ClientIdOut, u32ClientIdIn));
1441
1442 /* Allocate a client information structure. */
1443 HGCMClient *pClient = new HGCMClient();
1444
1445 if (!pClient)
1446 {
1447 Log1WarningFunc(("Could not allocate HGCMClient!!!\n"));
1448 return VERR_NO_MEMORY;
1449 }
1450
1451 uint32_t handle;
1452
1453 if (pu32ClientIdOut != NULL)
1454 {
1455 handle = hgcmObjGenerateHandle(pClient);
1456 }
1457 else
1458 {
1459 handle = hgcmObjAssignHandle(pClient, u32ClientIdIn);
1460 }
1461
1462 LogFlowFunc(("client id = %d\n", handle));
1463
1464 AssertRelease(handle);
1465
1466 /* Initialize the HGCM part of the client. */
1467 int rc = pClient->Init(this);
1468
1469 if (RT_SUCCESS(rc))
1470 {
1471 /* Call the service. */
1472 HGCMMSGHANDLE hMsg;
1473
1474 rc = hgcmMsgAlloc(m_thread, &hMsg, SVC_MSG_CONNECT, hgcmMessageAllocSvc);
1475
1476 if (RT_SUCCESS(rc))
1477 {
1478 HGCMMsgSvcConnect *pMsg = (HGCMMsgSvcConnect *)hgcmObjReference(hMsg, HGCMOBJ_MSG);
1479 AssertRelease(pMsg);
1480
1481 pMsg->u32ClientId = handle;
1482
1483 hgcmObjDereference(pMsg);
1484
1485 rc = hgcmMsgSend(hMsg);
1486
1487 if (RT_SUCCESS(rc))
1488 {
1489 /* Add the client Id to the array. */
1490 if (m_cClients == m_cClientsAllocated)
1491 {
1492 const uint32_t cDelta = 64;
1493
1494 /* Guards against integer overflow on 32bit arch and also limits size of m_paClientIds array to 4GB*/
1495 if (m_cClientsAllocated < UINT32_MAX / sizeof(m_paClientIds[0]) - cDelta)
1496 {
1497 uint32_t *paClientIdsNew;
1498
1499 paClientIdsNew = (uint32_t *)RTMemRealloc(m_paClientIds, (m_cClientsAllocated + cDelta) *
1500 sizeof(m_paClientIds[0]));
1501 Assert(paClientIdsNew);
1502
1503 if (paClientIdsNew)
1504 {
1505 m_paClientIds = paClientIdsNew;
1506 m_cClientsAllocated += cDelta;
1507 }
1508 else
1509 {
1510 rc = VERR_NO_MEMORY;
1511 }
1512 }
1513 else
1514 {
1515 rc = VERR_NO_MEMORY;
1516 }
1517 }
1518
1519 m_paClientIds[m_cClients] = handle;
1520 m_cClients++;
1521 }
1522 }
1523 }
1524
1525 if (RT_FAILURE(rc))
1526 {
1527 hgcmObjDeleteHandle(handle);
1528 }
1529 else
1530 {
1531 if (pu32ClientIdOut != NULL)
1532 {
1533 *pu32ClientIdOut = handle;
1534 }
1535
1536 ReferenceService();
1537 }
1538
1539 LogFlowFunc(("rc = %Rrc\n", rc));
1540 return rc;
1541}
1542
1543/* Disconnect the client from the service and delete the client handle.
1544 *
1545 * @param u32ClientId The handle of the client.
1546 * @return VBox rc.
1547 */
1548int HGCMService::DisconnectClient(uint32_t u32ClientId, bool fFromService)
1549{
1550 int rc = VINF_SUCCESS;
1551
1552 LogFlowFunc(("client id = %d, fFromService = %d\n", u32ClientId, fFromService));
1553
1554 if (!fFromService)
1555 {
1556 /* Call the service. */
1557 HGCMMSGHANDLE hMsg;
1558
1559 rc = hgcmMsgAlloc(m_thread, &hMsg, SVC_MSG_DISCONNECT, hgcmMessageAllocSvc);
1560
1561 if (RT_SUCCESS(rc))
1562 {
1563 HGCMMsgSvcDisconnect *pMsg = (HGCMMsgSvcDisconnect *)hgcmObjReference(hMsg, HGCMOBJ_MSG);
1564 AssertRelease(pMsg);
1565
1566 pMsg->u32ClientId = u32ClientId;
1567
1568 hgcmObjDereference(pMsg);
1569
1570 rc = hgcmMsgSend(hMsg);
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_thread, 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 {
1590 memmove (&m_paClientIds[i], &m_paClientIds[i + 1], sizeof(m_paClientIds[0]) * (m_cClients - i));
1591 }
1592
1593 /* Delete the client handle. */
1594 hgcmObjDeleteHandle(u32ClientId);
1595
1596 /* The service must be released. */
1597 ReleaseService();
1598
1599 break;
1600 }
1601 }
1602
1603 LogFlowFunc(("rc = %Rrc\n", rc));
1604 return rc;
1605}
1606
1607int HGCMService::RegisterExtension(HGCMSVCEXTHANDLE handle,
1608 PFNHGCMSVCEXT pfnExtension,
1609 void *pvExtension)
1610{
1611 LogFlowFunc(("%s\n", handle->pszServiceName));
1612
1613 /* Forward the message to the service thread. */
1614 HGCMMSGHANDLE hMsg = 0;
1615 int rc = hgcmMsgAlloc(m_thread, &hMsg, SVC_MSG_REGEXT, hgcmMessageAllocSvc);
1616
1617 if (RT_SUCCESS(rc))
1618 {
1619 HGCMMsgSvcRegisterExtension *pMsg = (HGCMMsgSvcRegisterExtension *)hgcmObjReference(hMsg, HGCMOBJ_MSG);
1620 AssertRelease(pMsg);
1621
1622 pMsg->handle = handle;
1623 pMsg->pfnExtension = pfnExtension;
1624 pMsg->pvExtension = pvExtension;
1625
1626 hgcmObjDereference(pMsg);
1627
1628 rc = hgcmMsgSend(hMsg);
1629 }
1630
1631 LogFlowFunc(("rc = %Rrc\n", rc));
1632 return rc;
1633}
1634
1635void HGCMService::UnregisterExtension(HGCMSVCEXTHANDLE handle)
1636{
1637 /* Forward the message to the service thread. */
1638 HGCMMSGHANDLE hMsg = 0;
1639 int rc = hgcmMsgAlloc(m_thread, &hMsg, SVC_MSG_UNREGEXT, hgcmMessageAllocSvc);
1640
1641 if (RT_SUCCESS(rc))
1642 {
1643 HGCMMsgSvcUnregisterExtension *pMsg = (HGCMMsgSvcUnregisterExtension *)hgcmObjReference(hMsg, HGCMOBJ_MSG);
1644 AssertRelease(pMsg);
1645
1646 pMsg->handle = handle;
1647
1648 hgcmObjDereference(pMsg);
1649
1650 rc = hgcmMsgSend(hMsg);
1651 }
1652
1653 LogFlowFunc(("rc = %Rrc\n", rc));
1654}
1655
1656/* Perform a guest call to the service.
1657 *
1658 * @param pHGCMPort The port to be used for completion confirmation.
1659 * @param pCmd The VBox HGCM context.
1660 * @param u32ClientId The client handle to be disconnected and deleted.
1661 * @param u32Function The function number.
1662 * @param cParms Number of parameters.
1663 * @param paParms Pointer to array of parameters.
1664 * @return VBox rc.
1665 */
1666int HGCMService::GuestCall(PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId, uint32_t u32Function,
1667 uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1668{
1669 HGCMMSGHANDLE hMsg = 0;
1670
1671 LogFlow(("MAIN::HGCMService::Call\n"));
1672
1673 int rc = hgcmMsgAlloc(m_thread, &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
1689 hgcmObjDereference(pMsg);
1690
1691 rc = hgcmMsgPost(hMsg, hgcmMsgCompletionCallback);
1692 }
1693 else
1694 {
1695 Log(("MAIN::HGCMService::Call: Message allocation failed: %Rrc\n", rc));
1696 }
1697
1698 LogFlowFunc(("rc = %Rrc\n", rc));
1699 return rc;
1700}
1701
1702/* Perform a host call the service.
1703 *
1704 * @param u32Function The function number.
1705 * @param cParms Number of parameters.
1706 * @param paParms Pointer to array of parameters.
1707 * @return VBox rc.
1708 */
1709int HGCMService::HostCall(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM *paParms)
1710{
1711 LogFlowFunc(("%s u32Function = %d, cParms = %d, paParms = %p\n",
1712 m_pszSvcName, u32Function, cParms, paParms));
1713
1714 HGCMMSGHANDLE hMsg = 0;
1715 int rc = hgcmMsgAlloc(m_thread, &hMsg, SVC_MSG_HOSTCALL, hgcmMessageAllocSvc);
1716
1717 if (RT_SUCCESS(rc))
1718 {
1719 HGCMMsgHostCallSvc *pMsg = (HGCMMsgHostCallSvc *)hgcmObjReference(hMsg, HGCMOBJ_MSG);
1720 AssertRelease(pMsg);
1721
1722 pMsg->u32Function = u32Function;
1723 pMsg->cParms = cParms;
1724 pMsg->paParms = paParms;
1725
1726 hgcmObjDereference(pMsg);
1727
1728 rc = hgcmMsgSend(hMsg);
1729 }
1730
1731 LogFlowFunc(("rc = %Rrc\n", rc));
1732 return rc;
1733}
1734
1735#ifdef VBOX_WITH_CRHGSMI
1736static DECLCALLBACK(void) hgcmMsgFastCallCompletionCallback(int32_t result, HGCMMsgCore *pMsgCore)
1737{
1738 /* Call the VMMDev port interface to issue IRQ notification. */
1739 LogFlow(("MAIN::hgcmMsgFastCallCompletionCallback: message %p\n", pMsgCore));
1740
1741 HGCMMsgHostFastCallAsyncSvc *pMsg = (HGCMMsgHostFastCallAsyncSvc *)pMsgCore;
1742 if (pMsg->pfnCompletion)
1743 {
1744 pMsg->pfnCompletion(result, pMsg->u32Function, &pMsg->Param, pMsg->pvCompletion);
1745 }
1746}
1747
1748int HGCMService::HandleAcquired()
1749{
1750 ++m_cHandleAcquires;
1751 return VINF_SUCCESS;
1752}
1753
1754int HGCMService::HandleReleased()
1755{
1756 Assert(m_cHandleAcquires);
1757 if (m_cHandleAcquires)
1758 {
1759 --m_cHandleAcquires;
1760 return VINF_SUCCESS;
1761 }
1762 return VERR_INVALID_STATE;
1763}
1764
1765int HGCMService::HostFastCallAsync(uint32_t u32Function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion,
1766 void *pvCompletion)
1767{
1768 LogFlowFunc(("%s u32Function = %d, pParm = %p\n",
1769 m_pszSvcName, u32Function, pParm));
1770
1771 HGCMMSGHANDLE hMsg = 0;
1772 int rc = hgcmMsgAlloc(m_thread, &hMsg, SVC_MSG_HOSTFASTCALLASYNC, hgcmMessageAllocSvc);
1773
1774 if (RT_SUCCESS(rc))
1775 {
1776 HGCMMsgHostFastCallAsyncSvc *pMsg = (HGCMMsgHostFastCallAsyncSvc *)hgcmObjReference(hMsg, HGCMOBJ_MSG);
1777 AssertRelease(pMsg);
1778
1779 pMsg->u32Function = u32Function;
1780 pMsg->Param = *pParm;
1781 pMsg->pfnCompletion = pfnCompletion;
1782 pMsg->pvCompletion = pvCompletion;
1783
1784 hgcmObjDereference(pMsg);
1785
1786 rc = hgcmMsgPost(hMsg, hgcmMsgFastCallCompletionCallback);
1787 }
1788
1789 LogFlowFunc(("rc = %Rrc\n", rc));
1790 return rc;
1791}
1792#endif
1793
1794/*
1795 * Main HGCM thread that manages services.
1796 */
1797
1798/* Messages processed by the main HGCM thread. */
1799#define HGCM_MSG_CONNECT (10) /* Connect a client to a service. */
1800#define HGCM_MSG_DISCONNECT (11) /* Disconnect the specified client id. */
1801#define HGCM_MSG_LOAD (12) /* Load the service. */
1802#define HGCM_MSG_HOSTCALL (13) /* Call the service. */
1803#define HGCM_MSG_LOADSTATE (14) /* Load saved state for the specified service. */
1804#define HGCM_MSG_SAVESTATE (15) /* Save state for the specified service. */
1805#define HGCM_MSG_RESET (16) /* Disconnect all clients from the specified service. */
1806#define HGCM_MSG_QUIT (17) /* Unload all services and terminate the thread. */
1807#define HGCM_MSG_REGEXT (18) /* Register a service extension. */
1808#define HGCM_MSG_UNREGEXT (19) /* Unregister a service extension. */
1809#ifdef VBOX_WITH_CRHGSMI
1810# define HGCM_MSG_SVCAQUIRE (30) /* Acquire a service handle (for fast host calls) */
1811# define HGCM_MSG_SVCRELEASE (31) /* Release a service */
1812#endif
1813
1814class HGCMMsgMainConnect: public HGCMMsgHeader
1815{
1816 public:
1817 /* Service name. */
1818 const char *pszServiceName;
1819 /* Where to store the client handle. */
1820 uint32_t *pu32ClientId;
1821};
1822
1823class HGCMMsgMainDisconnect: public HGCMMsgHeader
1824{
1825 public:
1826 /* Handle of the client to be disconnected. */
1827 uint32_t u32ClientId;
1828};
1829
1830class HGCMMsgMainLoad: public HGCMMsgCore
1831{
1832 public:
1833 /* Name of the library to be loaded. */
1834 const char *pszServiceLibrary;
1835 /* Name to be assigned to the service. */
1836 const char *pszServiceName;
1837 /** The user mode VM handle (for statistics and such). */
1838 PUVM pUVM;
1839};
1840
1841class HGCMMsgMainHostCall: public HGCMMsgCore
1842{
1843 public:
1844 /* Which service to call. */
1845 const char *pszServiceName;
1846 /* Function number. */
1847 uint32_t u32Function;
1848 /* Number of the function parameters. */
1849 uint32_t cParms;
1850 /* Pointer to array of the function parameters. */
1851 VBOXHGCMSVCPARM *paParms;
1852};
1853
1854class HGCMMsgMainLoadSaveState: public HGCMMsgCore
1855{
1856 public:
1857 /* SSM context. */
1858 PSSMHANDLE pSSM;
1859};
1860
1861class HGCMMsgMainReset: public HGCMMsgCore
1862{
1863};
1864
1865class HGCMMsgMainQuit: public HGCMMsgCore
1866{
1867};
1868
1869class HGCMMsgMainRegisterExtension: public HGCMMsgCore
1870{
1871 public:
1872 /* Returned handle to be used in HGCMMsgMainUnregisterExtension. */
1873 HGCMSVCEXTHANDLE *pHandle;
1874 /* Name of the service. */
1875 const char *pszServiceName;
1876 /* The extension entry point. */
1877 PFNHGCMSVCEXT pfnExtension;
1878 /* The extension pointer. */
1879 void *pvExtension;
1880};
1881
1882class HGCMMsgMainUnregisterExtension: public HGCMMsgCore
1883{
1884 public:
1885 /* Handle of the registered extension. */
1886 HGCMSVCEXTHANDLE handle;
1887};
1888
1889#ifdef VBOX_WITH_CRHGSMI
1890class HGCMMsgMainSvcAcquire: public HGCMMsgCore
1891{
1892 public:
1893 /* Which service to call. */
1894 const char *pszServiceName;
1895 /* Returned service. */
1896 HGCMService *pService;
1897};
1898
1899class HGCMMsgMainSvcRelease: public HGCMMsgCore
1900{
1901 public:
1902 /* Svc . */
1903 HGCMService *pService;
1904};
1905#endif
1906
1907
1908static HGCMMsgCore *hgcmMainMessageAlloc (uint32_t u32MsgId)
1909{
1910 switch (u32MsgId)
1911 {
1912 case HGCM_MSG_CONNECT: return new HGCMMsgMainConnect();
1913 case HGCM_MSG_DISCONNECT: return new HGCMMsgMainDisconnect();
1914 case HGCM_MSG_LOAD: return new HGCMMsgMainLoad();
1915 case HGCM_MSG_HOSTCALL: return new HGCMMsgMainHostCall();
1916 case HGCM_MSG_LOADSTATE:
1917 case HGCM_MSG_SAVESTATE: return new HGCMMsgMainLoadSaveState();
1918 case HGCM_MSG_RESET: return new HGCMMsgMainReset();
1919 case HGCM_MSG_QUIT: return new HGCMMsgMainQuit();
1920 case HGCM_MSG_REGEXT: return new HGCMMsgMainRegisterExtension();
1921 case HGCM_MSG_UNREGEXT: return new HGCMMsgMainUnregisterExtension();
1922#ifdef VBOX_WITH_CRHGSMI
1923 case HGCM_MSG_SVCAQUIRE: return new HGCMMsgMainSvcAcquire();
1924 case HGCM_MSG_SVCRELEASE: return new HGCMMsgMainSvcRelease();
1925#endif
1926
1927 default:
1928 AssertReleaseMsgFailed(("Msg id = %08X\n", u32MsgId));
1929 }
1930
1931 return NULL;
1932}
1933
1934
1935/* The main HGCM thread handler. */
1936static DECLCALLBACK(void) hgcmThread(HGCMTHREADHANDLE ThreadHandle, void *pvUser)
1937{
1938 LogFlowFunc(("ThreadHandle = %p, pvUser = %p\n",
1939 ThreadHandle, pvUser));
1940
1941 NOREF(pvUser);
1942
1943 bool fQuit = false;
1944
1945 while (!fQuit)
1946 {
1947 HGCMMsgCore *pMsgCore;
1948 int rc = hgcmMsgGet(ThreadHandle, &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 HGCMTHREADHANDLE g_hgcmThread = 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_hgcmThread, &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_hgcmThread, &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_hgcmThread, &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_hgcmThread, &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_hgcmThread, &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_hgcmThread, &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 * @return VBox rc.
2465 */
2466int HGCMGuestCall(PPDMIHGCMPORT pHGCMPort,
2467 PVBOXHGCMCMD pCmd,
2468 uint32_t u32ClientId,
2469 uint32_t u32Function,
2470 uint32_t cParms,
2471 VBOXHGCMSVCPARM *paParms)
2472{
2473 LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d, u32Function = %d, cParms = %d, paParms = %p\n",
2474 pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms));
2475
2476 if (!pHGCMPort || !pCmd || u32ClientId == 0)
2477 {
2478 return VERR_INVALID_PARAMETER;
2479 }
2480
2481 int rc = VERR_HGCM_INVALID_CLIENT_ID;
2482
2483 /* Resolve the client handle to the client instance pointer. */
2484 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(u32ClientId, HGCMOBJ_CLIENT);
2485
2486 if (pClient)
2487 {
2488 AssertRelease(pClient->pService);
2489
2490 /* Forward the message to the service thread. */
2491 rc = pClient->pService->GuestCall(pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms);
2492
2493 hgcmObjDereference(pClient);
2494 }
2495
2496 LogFlowFunc(("rc = %Rrc\n", rc));
2497 return rc;
2498}
2499
2500/* The host calls the service.
2501 *
2502 * @param pszServiceName The service name to be called.
2503 * @param u32Function The function number.
2504 * @param cParms Number of parameters.
2505 * @param paParms Pointer to array of parameters.
2506 * @return VBox rc.
2507 */
2508int HGCMHostCall(const char *pszServiceName,
2509 uint32_t u32Function,
2510 uint32_t cParms,
2511 VBOXHGCMSVCPARM *paParms)
2512{
2513 LogFlowFunc(("name = %s, u32Function = %d, cParms = %d, paParms = %p\n",
2514 pszServiceName, u32Function, cParms, paParms));
2515
2516 if (!pszServiceName)
2517 {
2518 return VERR_INVALID_PARAMETER;
2519 }
2520
2521 HGCMMSGHANDLE hMsg = 0;
2522
2523 /* Host calls go to main HGCM thread that resolves the service name to the
2524 * service instance pointer and then, using the service pointer, forwards
2525 * the message to the service thread.
2526 * So it is slow but host calls are intended mostly for configuration and
2527 * other non-time-critical functions.
2528 */
2529 int rc = hgcmMsgAlloc(g_hgcmThread, &hMsg, HGCM_MSG_HOSTCALL, hgcmMainMessageAlloc);
2530
2531 if (RT_SUCCESS(rc))
2532 {
2533 HGCMMsgMainHostCall *pMsg = (HGCMMsgMainHostCall *)hgcmObjReference(hMsg, HGCMOBJ_MSG);
2534 AssertRelease(pMsg);
2535
2536 pMsg->pszServiceName = (char *)pszServiceName;
2537 pMsg->u32Function = u32Function;
2538 pMsg->cParms = cParms;
2539 pMsg->paParms = paParms;
2540
2541 hgcmObjDereference(pMsg);
2542
2543 rc = hgcmMsgSend(hMsg);
2544 }
2545
2546 LogFlowFunc(("rc = %Rrc\n", rc));
2547 return rc;
2548}
2549
2550#ifdef VBOX_WITH_CRHGSMI
2551int HGCMHostSvcHandleCreate(const char *pszServiceName, HGCMCVSHANDLE * phSvc)
2552{
2553 LogFlowFunc(("name = %s\n", pszServiceName));
2554
2555 if (!pszServiceName)
2556 {
2557 return VERR_INVALID_PARAMETER;
2558 }
2559
2560 if (!phSvc)
2561 {
2562 return VERR_INVALID_PARAMETER;
2563 }
2564
2565 HGCMMSGHANDLE hMsg = 0;
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 int rc = hgcmMsgAlloc(g_hgcmThread, &hMsg, HGCM_MSG_SVCAQUIRE, hgcmMainMessageAlloc);
2574
2575 if (RT_SUCCESS(rc))
2576 {
2577 HGCMMsgMainSvcAcquire *pMsg = (HGCMMsgMainSvcAcquire *)hgcmObjReference(hMsg, HGCMOBJ_MSG);
2578 AssertRelease(pMsg);
2579
2580 pMsg->pszServiceName = (char *)pszServiceName;
2581 pMsg->pService = NULL;
2582
2583 rc = hgcmMsgSend(hMsg);
2584 if (RT_SUCCESS(rc))
2585 {
2586 /* for simplicity just use a svc ptr as handle for now */
2587 *phSvc = (HGCMCVSHANDLE)pMsg->pService;
2588 }
2589
2590 hgcmObjDereference(pMsg);
2591 }
2592
2593 LogFlowFunc(("rc = %Rrc\n", rc));
2594 return rc;
2595}
2596
2597int HGCMHostSvcHandleDestroy(HGCMCVSHANDLE hSvc)
2598{
2599 LogFlowFunc(("hSvc = %p\n", hSvc));
2600
2601 if (!hSvc)
2602 {
2603 return VERR_INVALID_PARAMETER;
2604 }
2605
2606 HGCMMSGHANDLE hMsg = 0;
2607
2608 /* Host calls go to main HGCM thread that resolves the service name to the
2609 * service instance pointer and then, using the service pointer, forwards
2610 * the message to the service thread.
2611 * So it is slow but host calls are intended mostly for configuration and
2612 * other non-time-critical functions.
2613 */
2614 int rc = hgcmMsgAlloc(g_hgcmThread, &hMsg, HGCM_MSG_SVCRELEASE, hgcmMainMessageAlloc);
2615
2616 if (RT_SUCCESS(rc))
2617 {
2618 HGCMMsgMainSvcRelease *pMsg = (HGCMMsgMainSvcRelease *)hgcmObjReference(hMsg, HGCMOBJ_MSG);
2619 AssertRelease(pMsg);
2620
2621 pMsg->pService = (HGCMService *)hSvc;
2622
2623 hgcmObjDereference(pMsg);
2624
2625 rc = hgcmMsgSend(hMsg);
2626 }
2627
2628 LogFlowFunc(("rc = %Rrc\n", rc));
2629 return rc;
2630}
2631
2632int HGCMHostFastCallAsync(HGCMCVSHANDLE hSvc, uint32_t function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion,
2633 void *pvCompletion)
2634{
2635 LogFlowFunc(("hSvc = %p, u32Function = %d, pParm = %p\n",
2636 hSvc, function, pParm));
2637
2638 if (!hSvc)
2639 {
2640 return VERR_INVALID_PARAMETER;
2641 }
2642
2643 HGCMService *pService = (HGCMService *)hSvc;
2644 int rc = pService->HostFastCallAsync(function, pParm, pfnCompletion, pvCompletion);
2645
2646 LogFlowFunc(("rc = %Rrc\n", rc));
2647 return rc;
2648}
2649#endif
2650
2651int HGCMHostReset(void)
2652{
2653 LogFlowFunc(("\n"));
2654
2655 /* Disconnect all clients.
2656 */
2657
2658 HGCMMSGHANDLE hMsg = 0;
2659
2660 int rc = hgcmMsgAlloc(g_hgcmThread, &hMsg, HGCM_MSG_RESET, hgcmMainMessageAlloc);
2661
2662 if (RT_SUCCESS(rc))
2663 {
2664 rc = hgcmMsgSend(hMsg);
2665 }
2666
2667 LogFlowFunc(("rc = %Rrc\n", rc));
2668 return rc;
2669}
2670
2671int HGCMHostInit(void)
2672{
2673 LogFlowFunc(("\n"));
2674
2675 int rc = hgcmThreadInit();
2676
2677 if (RT_SUCCESS(rc))
2678 {
2679 /*
2680 * Start main HGCM thread.
2681 */
2682
2683 rc = hgcmThreadCreate(&g_hgcmThread, "MainHGCMthread", hgcmThread, NULL /*pvUser*/, NULL /*pszStatsSubDir*/, NULL /*pUVM*/);
2684
2685 if (RT_FAILURE(rc))
2686 {
2687 LogRel(("Failed to start HGCM thread. HGCM services will be unavailable!!! rc = %Rrc\n", rc));
2688 }
2689 }
2690
2691 LogFlowFunc(("rc = %Rrc\n", rc));
2692 return rc;
2693}
2694
2695int HGCMHostShutdown(void)
2696{
2697 LogFlowFunc(("\n"));
2698
2699 /*
2700 * Do HGCMReset and then unload all services.
2701 */
2702
2703 int rc = HGCMHostReset();
2704
2705 if (RT_SUCCESS(rc))
2706 {
2707 /* Send the quit message to the main hgcmThread. */
2708 HGCMMSGHANDLE hMsg = 0;
2709
2710 rc = hgcmMsgAlloc(g_hgcmThread, &hMsg, HGCM_MSG_QUIT, hgcmMainMessageAlloc);
2711
2712 if (RT_SUCCESS(rc))
2713 {
2714 rc = hgcmMsgSend(hMsg);
2715
2716 if (RT_SUCCESS(rc))
2717 {
2718 /* Wait for the thread termination. */
2719 hgcmThreadWait(g_hgcmThread);
2720 g_hgcmThread = 0;
2721
2722 hgcmThreadUninit();
2723 }
2724 }
2725 }
2726
2727 LogFlowFunc(("rc = %Rrc\n", rc));
2728 return rc;
2729}
Note: See TracBrowser for help on using the repository browser.

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