VirtualBox

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

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

Use iprt/alloca.h to get the right headers for alloca().

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