VirtualBox

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

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

Added RTLdrLoadEx for exposing dlerror info.

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