VirtualBox

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

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

wddm/3d: chromium hgsmi, host part + guest part debugging

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