VirtualBox

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

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

*: spelling fixes, thanks Timeless!

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