VirtualBox

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

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

Biggest check-in ever. New source code headers for all (C) innotek files.

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