VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/HGCM.cpp@ 75740

Last change on this file since 75740 was 75740, checked in by vboxsync, 6 years ago

HGCM,VMMDev: Made the HGCM command/message completion callback return a status code so VMMDev can indicate that a guest call was cancelled and the service could implement a way of dealing with that, rather than just dropping information. Ran into this with SIGCHLD delivery interrupting GUEST_MSG_WAIT and dropping crucial HOST_SESSION_CLOSE close messages, causing the host to wait until sometime timed out and probably left stuff/processes behind.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette