VirtualBox

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

Last change on this file since 1713 was 1713, checked in by vboxsync, 18 years ago

GCC warning.

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