VirtualBox

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

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

Main/src-client/HGCM.cpp: Fix memory leak

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