VirtualBox

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

Last change on this file since 3209 was 3209, checked in by vboxsync, 17 years ago

Call the pfnUnload HGCM service entry.

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