VirtualBox

source: vbox/trunk/src/VBox/Main/hgcm/HGCM.cpp@ 35346

Last change on this file since 35346 was 35346, checked in by vboxsync, 14 years ago

VMM reorg: Moving the public include files from include/VBox to include/VBox/vmm.

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