VirtualBox

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

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

Logging

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 53.4 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 %Vrc\n", rc));
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 if (VBOX_SUCCESS (rc))
703 {
704 hgcmThreadWait (m_thread);
705 }
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\n", 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 /* Wait for the thread termination. */
1955 hgcmThreadWait (g_hgcmThread);
1956
1957 hgcmThreadUninit ();
1958 }
1959 }
1960 }
1961
1962 LogFlowFunc(("rc = %Vrc\n", rc));
1963 return rc;
1964}
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