VirtualBox

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

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

VMMDev,HGCM: Added cancellation notification and query helper.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 89.6 KB
Line 
1/* $Id: HGCM.cpp 75990 2018-12-05 19:51:01Z 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 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
1159int HGCMService::saveClientState(uint32_t u32ClientId, PSSMHANDLE pSSM)
1160{
1161 LogFlowFunc(("%s\n", m_pszSvcName));
1162
1163 HGCMMsgCore *pCoreMsg;
1164 int rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_SAVESTATE, hgcmMessageAllocSvc);
1165
1166 if (RT_SUCCESS(rc))
1167 {
1168 HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)pCoreMsg;
1169
1170 pMsg->u32ClientId = u32ClientId;
1171 pMsg->pSSM = pSSM;
1172
1173 rc = hgcmMsgSend(pMsg);
1174 }
1175
1176 LogFlowFunc(("rc = %Rrc\n", rc));
1177 return rc;
1178}
1179
1180int HGCMService::loadClientState(uint32_t u32ClientId, PSSMHANDLE pSSM, uint32_t uVersion)
1181{
1182 LogFlowFunc(("%s\n", m_pszSvcName));
1183
1184 HGCMMsgCore *pCoreMsg;
1185 int rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_LOADSTATE, hgcmMessageAllocSvc);
1186
1187 if (RT_SUCCESS(rc))
1188 {
1189 HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)pCoreMsg;
1190
1191 pMsg->pSSM = pSSM;
1192 pMsg->uVersion = uVersion;
1193 pMsg->u32ClientId = u32ClientId;
1194
1195 rc = hgcmMsgSend(pMsg);
1196 }
1197
1198 LogFlowFunc(("rc = %Rrc\n", rc));
1199 return rc;
1200}
1201
1202
1203/** The method creates a service and references it.
1204 *
1205 * @param pszServiceLibrary The library to be loaded.
1206 * @param pszServiceName The name of the service.
1207 * @param pUVM The user mode VM handle (for statistics and such).
1208 * @param pHgcmPort The VMMDev HGCM port interface.
1209 *
1210 * @return VBox rc.
1211 * @thread main HGCM
1212 */
1213/* static */ int HGCMService::LoadService(const char *pszServiceLibrary, const char *pszServiceName,
1214 PUVM pUVM, PPDMIHGCMPORT pHgcmPort)
1215{
1216 LogFlowFunc(("lib %s, name = %s, pUVM = %p\n", pszServiceLibrary, pszServiceName, pUVM));
1217
1218 /* Look at already loaded services to avoid double loading. */
1219
1220 HGCMService *pSvc;
1221 int rc = HGCMService::ResolveService(&pSvc, pszServiceName);
1222
1223 if (RT_SUCCESS(rc))
1224 {
1225 /* The service is already loaded. */
1226 pSvc->ReleaseService();
1227 rc = VERR_HGCM_SERVICE_EXISTS;
1228 }
1229 else
1230 {
1231 /* Create the new service. */
1232 pSvc = new (std::nothrow) HGCMService();
1233
1234 if (!pSvc)
1235 {
1236 rc = VERR_NO_MEMORY;
1237 }
1238 else
1239 {
1240 /* Load the library and call the initialization entry point. */
1241 rc = pSvc->instanceCreate(pszServiceLibrary, pszServiceName, pUVM, pHgcmPort);
1242
1243 if (RT_SUCCESS(rc))
1244 {
1245 /* Insert the just created service to list for future references. */
1246 pSvc->m_pSvcNext = sm_pSvcListHead;
1247 pSvc->m_pSvcPrev = NULL;
1248
1249 if (sm_pSvcListHead)
1250 {
1251 sm_pSvcListHead->m_pSvcPrev = pSvc;
1252 }
1253 else
1254 {
1255 sm_pSvcListTail = pSvc;
1256 }
1257
1258 sm_pSvcListHead = pSvc;
1259
1260 sm_cServices++;
1261
1262 /* Reference the service (for first time) until it is unloaded on HGCM termination. */
1263 AssertRelease(pSvc->m_u32RefCnt == 0);
1264 pSvc->ReferenceService();
1265
1266 LogFlowFunc(("service %p\n", pSvc));
1267 }
1268 }
1269 }
1270
1271 LogFlowFunc(("rc = %Rrc\n", rc));
1272 return rc;
1273}
1274
1275/** The method unloads a service.
1276 *
1277 * @thread main HGCM
1278 */
1279void HGCMService::UnloadService(bool fUvmIsInvalid)
1280{
1281 LogFlowFunc(("name = %s\n", m_pszSvcName));
1282
1283 if (fUvmIsInvalid)
1284 {
1285 m_pUVM = NULL;
1286 m_pHgcmPort = NULL;
1287 }
1288
1289 /* Remove the service from the list. */
1290 if (m_pSvcNext)
1291 {
1292 m_pSvcNext->m_pSvcPrev = m_pSvcPrev;
1293 }
1294 else
1295 {
1296 sm_pSvcListTail = m_pSvcPrev;
1297 }
1298
1299 if (m_pSvcPrev)
1300 {
1301 m_pSvcPrev->m_pSvcNext = m_pSvcNext;
1302 }
1303 else
1304 {
1305 sm_pSvcListHead = m_pSvcNext;
1306 }
1307
1308 sm_cServices--;
1309
1310 /* The service must be unloaded only if all clients were disconnected. */
1311 LogFlowFunc(("m_u32RefCnt = %d\n", m_u32RefCnt));
1312 AssertRelease(m_u32RefCnt == 1);
1313
1314 /* Now the service can be released. */
1315 ReleaseService();
1316}
1317
1318/** The method unloads all services.
1319 *
1320 * @thread main HGCM
1321 */
1322/* static */ void HGCMService::UnloadAll(bool fUvmIsInvalid)
1323{
1324 while (sm_pSvcListHead)
1325 {
1326 sm_pSvcListHead->UnloadService(fUvmIsInvalid);
1327 }
1328}
1329
1330/** The method obtains a referenced pointer to the service with
1331 * specified name. The caller must call ReleaseService when
1332 * the pointer is no longer needed.
1333 *
1334 * @param ppSvc Where to store the pointer to the service.
1335 * @param pszServiceName The name of the service.
1336 * @return VBox rc.
1337 * @thread main HGCM
1338 */
1339/* static */ int HGCMService::ResolveService(HGCMService **ppSvc, const char *pszServiceName)
1340{
1341 LogFlowFunc(("ppSvc = %p name = %s\n",
1342 ppSvc, pszServiceName));
1343
1344 if (!ppSvc || !pszServiceName)
1345 {
1346 return VERR_INVALID_PARAMETER;
1347 }
1348
1349 HGCMService *pSvc = sm_pSvcListHead;
1350
1351 while (pSvc)
1352 {
1353 if (strcmp(pSvc->m_pszSvcName, pszServiceName) == 0)
1354 {
1355 break;
1356 }
1357
1358 pSvc = pSvc->m_pSvcNext;
1359 }
1360
1361 LogFlowFunc(("lookup in the list is %p\n", pSvc));
1362
1363 if (pSvc == NULL)
1364 {
1365 *ppSvc = NULL;
1366 return VERR_HGCM_SERVICE_NOT_FOUND;
1367 }
1368
1369 pSvc->ReferenceService();
1370
1371 *ppSvc = pSvc;
1372
1373 return VINF_SUCCESS;
1374}
1375
1376/** The method increases reference counter.
1377 *
1378 * @thread main HGCM
1379 */
1380void HGCMService::ReferenceService(void)
1381{
1382 ASMAtomicIncU32(&m_u32RefCnt);
1383 LogFlowFunc(("[%s] m_u32RefCnt = %d\n", m_pszSvcName, m_u32RefCnt));
1384}
1385
1386/** The method dereferences a service and deletes it when no more refs.
1387 *
1388 * @thread main HGCM
1389 */
1390void HGCMService::ReleaseService(void)
1391{
1392 LogFlowFunc(("m_u32RefCnt = %d\n", m_u32RefCnt));
1393 uint32_t u32RefCnt = ASMAtomicDecU32(&m_u32RefCnt);
1394 AssertRelease(u32RefCnt != ~0U);
1395
1396 LogFlowFunc(("u32RefCnt = %d, name %s\n", u32RefCnt, m_pszSvcName));
1397
1398 if (u32RefCnt == 0)
1399 {
1400 instanceDestroy();
1401 delete this;
1402 }
1403}
1404
1405/** The method is called when the VM is being reset or terminated
1406 * and disconnects all clients from all services.
1407 *
1408 * @thread main HGCM
1409 */
1410/* static */ void HGCMService::Reset(void)
1411{
1412 g_fResetting = true;
1413
1414 HGCMService *pSvc = sm_pSvcListHead;
1415
1416 while (pSvc)
1417 {
1418 while (pSvc->m_cClients && pSvc->m_paClientIds)
1419 {
1420 LogFlowFunc(("handle %d\n", pSvc->m_paClientIds[0]));
1421 pSvc->DisconnectClient(pSvc->m_paClientIds[0], false);
1422 }
1423
1424#ifdef VBOX_WITH_CRHGSMI
1425 /** @todo could this actually happen that the service is destroyed on ReleaseService? */
1426 HGCMService *pNextSvc = pSvc->m_pSvcNext;
1427 while (pSvc->m_cHandleAcquires)
1428 {
1429 pSvc->HandleReleased();
1430 pSvc->ReleaseService();
1431 }
1432 pSvc = pNextSvc;
1433#else
1434 pSvc = pSvc->m_pSvcNext;
1435#endif
1436 }
1437
1438 g_fResetting = false;
1439}
1440
1441/** The method saves the HGCM state.
1442 *
1443 * @param pSSM The saved state context.
1444 * @return VBox rc.
1445 * @thread main HGCM
1446 */
1447/* static */ int HGCMService::SaveState(PSSMHANDLE pSSM)
1448{
1449 /* Save the current handle count and restore afterwards to avoid client id conflicts. */
1450 int rc = SSMR3PutU32(pSSM, hgcmObjQueryHandleCount());
1451 AssertRCReturn(rc, rc);
1452
1453 LogFlowFunc(("%d services to be saved:\n", sm_cServices));
1454
1455 /* Save number of services. */
1456 rc = SSMR3PutU32(pSSM, sm_cServices);
1457 AssertRCReturn(rc, rc);
1458
1459 /* Save every service. */
1460 HGCMService *pSvc = sm_pSvcListHead;
1461
1462 while (pSvc)
1463 {
1464 LogFlowFunc(("Saving service [%s]\n", pSvc->m_pszSvcName));
1465
1466 /* Save the length of the service name. */
1467 rc = SSMR3PutU32(pSSM, (uint32_t) strlen(pSvc->m_pszSvcName) + 1);
1468 AssertRCReturn(rc, rc);
1469
1470 /* Save the name of the service. */
1471 rc = SSMR3PutStrZ(pSSM, pSvc->m_pszSvcName);
1472 AssertRCReturn(rc, rc);
1473
1474 /* Save the number of clients. */
1475 rc = SSMR3PutU32(pSSM, pSvc->m_cClients);
1476 AssertRCReturn(rc, rc);
1477
1478 /* Call the service for every client. Normally a service must not have
1479 * a global state to be saved: only per client info is relevant.
1480 * The global state of a service is configured during VM startup.
1481 */
1482 uint32_t i;
1483
1484 for (i = 0; i < pSvc->m_cClients; i++)
1485 {
1486 uint32_t u32ClientId = pSvc->m_paClientIds[i];
1487
1488 Log(("client id 0x%08X\n", u32ClientId));
1489
1490 /* Save the client id. (fRequestor is saved via SVC_MSG_SAVESTATE for convenience.) */
1491 rc = SSMR3PutU32(pSSM, u32ClientId);
1492 AssertRCReturn(rc, rc);
1493
1494 /* Call the service, so the operation is executed by the service thread. */
1495 rc = pSvc->saveClientState(u32ClientId, pSSM);
1496 AssertRCReturn(rc, rc);
1497 }
1498
1499 pSvc = pSvc->m_pSvcNext;
1500 }
1501
1502 return VINF_SUCCESS;
1503}
1504
1505/** The method loads saved HGCM state.
1506 *
1507 * @param pSSM The saved state handle.
1508 * @param uVersion The state version being loaded.
1509 * @return VBox rc.
1510 * @thread main HGCM
1511 */
1512/* static */ int HGCMService::LoadState(PSSMHANDLE pSSM, uint32_t uVersion)
1513{
1514 /* Restore handle count to avoid client id conflicts. */
1515 uint32_t u32;
1516
1517 int rc = SSMR3GetU32(pSSM, &u32);
1518 AssertRCReturn(rc, rc);
1519
1520 hgcmObjSetHandleCount(u32);
1521
1522 /* Get the number of services. */
1523 uint32_t cServices;
1524
1525 rc = SSMR3GetU32(pSSM, &cServices);
1526 AssertRCReturn(rc, rc);
1527
1528 LogFlowFunc(("%d services to be restored:\n", cServices));
1529
1530 while (cServices--)
1531 {
1532 /* Get the length of the service name. */
1533 rc = SSMR3GetU32(pSSM, &u32);
1534 AssertRCReturn(rc, rc);
1535 AssertReturn(u32 <= VBOX_HGCM_SVC_NAME_MAX_BYTES, VERR_SSM_UNEXPECTED_DATA);
1536
1537 /* Get the service name. */
1538 char szServiceName[VBOX_HGCM_SVC_NAME_MAX_BYTES];
1539 rc = SSMR3GetStrZ(pSSM, szServiceName, u32);
1540 AssertRCReturn(rc, rc);
1541
1542 LogRel(("HGCM: Restoring [%s]\n", szServiceName));
1543
1544 /* Resolve the service instance. */
1545 HGCMService *pSvc;
1546 rc = ResolveService(&pSvc, szServiceName);
1547 AssertLogRelMsgReturn(pSvc, ("rc=%Rrc, %s\n", rc, szServiceName), VERR_SSM_UNEXPECTED_DATA);
1548
1549 /* Get the number of clients. */
1550 uint32_t cClients;
1551 rc = SSMR3GetU32(pSSM, &cClients);
1552 if (RT_FAILURE(rc))
1553 {
1554 pSvc->ReleaseService();
1555 AssertFailed();
1556 return rc;
1557 }
1558
1559 while (cClients--)
1560 {
1561 /* Get the client ID and fRequest (convieniently save via SVC_MSG_SAVESTATE
1562 but restored here in time for calling CreateAndConnectClient). */
1563 uint32_t u32ClientId;
1564 rc = SSMR3GetU32(pSSM, &u32ClientId);
1565 uint32_t fRequestor = VMMDEV_REQUESTOR_LEGACY;
1566 if (RT_SUCCESS(rc) && uVersion > HGCM_SAVED_STATE_VERSION_V2)
1567 rc = SSMR3GetU32(pSSM, &fRequestor);
1568 AssertLogRelMsgRCReturnStmt(rc, ("rc=%Rrc, %s\n", rc, szServiceName), pSvc->ReleaseService(), rc);
1569
1570 /* Connect the client. */
1571 rc = pSvc->CreateAndConnectClient(NULL, u32ClientId, fRequestor, true /*fRestoring*/);
1572 AssertLogRelMsgRCReturnStmt(rc, ("rc=%Rrc, %s\n", rc, szServiceName), pSvc->ReleaseService(), rc);
1573
1574 /* Call the service, so the operation is executed by the service thread. */
1575 rc = pSvc->loadClientState(u32ClientId, pSSM, uVersion);
1576 AssertLogRelMsgRCReturnStmt(rc, ("rc=%Rrc, %s\n", rc, szServiceName), pSvc->ReleaseService(), rc);
1577 }
1578
1579 pSvc->ReleaseService();
1580 }
1581
1582 return VINF_SUCCESS;
1583}
1584
1585/* Create a new client instance and connect it to the service.
1586 *
1587 * @param pu32ClientIdOut If not NULL, then the method must generate a new handle for the client.
1588 * If NULL, use the given 'u32ClientIdIn' handle.
1589 * @param u32ClientIdIn The handle for the client, when 'pu32ClientIdOut' is NULL.
1590 * @param fRequestor The requestor flags, VMMDEV_REQUESTOR_LEGACY if not available.
1591 * @param fRestoring Set if we're restoring a saved state.
1592 * @return VBox status code.
1593 */
1594int HGCMService::CreateAndConnectClient(uint32_t *pu32ClientIdOut, uint32_t u32ClientIdIn, uint32_t fRequestor, bool fRestoring)
1595{
1596 LogFlowFunc(("pu32ClientIdOut = %p, u32ClientIdIn = %d, fRequestor = %#x, fRestoring = %d\n",
1597 pu32ClientIdOut, u32ClientIdIn, fRequestor, fRestoring));
1598
1599 /* Allocate a client information structure. */
1600 HGCMClient *pClient = new (std::nothrow) HGCMClient(fRequestor);
1601
1602 if (!pClient)
1603 {
1604 Log1WarningFunc(("Could not allocate HGCMClient!!!\n"));
1605 return VERR_NO_MEMORY;
1606 }
1607
1608 uint32_t handle;
1609
1610 if (pu32ClientIdOut != NULL)
1611 {
1612 handle = hgcmObjGenerateHandle(pClient);
1613 }
1614 else
1615 {
1616 handle = hgcmObjAssignHandle(pClient, u32ClientIdIn);
1617 }
1618
1619 LogFlowFunc(("client id = %d\n", handle));
1620
1621 AssertRelease(handle);
1622
1623 /* Initialize the HGCM part of the client. */
1624 int rc = pClient->Init(this);
1625
1626 if (RT_SUCCESS(rc))
1627 {
1628 /* Call the service. */
1629 HGCMMsgCore *pCoreMsg;
1630
1631 rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_CONNECT, hgcmMessageAllocSvc);
1632
1633 if (RT_SUCCESS(rc))
1634 {
1635 HGCMMsgSvcConnect *pMsg = (HGCMMsgSvcConnect *)pCoreMsg;
1636
1637 pMsg->u32ClientId = handle;
1638 pMsg->fRequestor = fRequestor;
1639 pMsg->fRestoring = fRestoring;
1640
1641 rc = hgcmMsgSend(pMsg);
1642
1643 if (RT_SUCCESS(rc))
1644 {
1645 /* Add the client Id to the array. */
1646 if (m_cClients == m_cClientsAllocated)
1647 {
1648 const uint32_t cDelta = 64;
1649
1650 /* Guards against integer overflow on 32bit arch and also limits size of m_paClientIds array to 4GB*/
1651 if (m_cClientsAllocated < UINT32_MAX / sizeof(m_paClientIds[0]) - cDelta)
1652 {
1653 uint32_t *paClientIdsNew;
1654
1655 paClientIdsNew = (uint32_t *)RTMemRealloc(m_paClientIds,
1656 (m_cClientsAllocated + cDelta) * sizeof(m_paClientIds[0]));
1657 Assert(paClientIdsNew);
1658
1659 if (paClientIdsNew)
1660 {
1661 m_paClientIds = paClientIdsNew;
1662 m_cClientsAllocated += cDelta;
1663 }
1664 else
1665 {
1666 rc = VERR_NO_MEMORY;
1667 }
1668 }
1669 else
1670 {
1671 rc = VERR_NO_MEMORY;
1672 }
1673 }
1674
1675 m_paClientIds[m_cClients] = handle;
1676 m_cClients++;
1677 }
1678 }
1679 }
1680
1681 if (RT_FAILURE(rc))
1682 {
1683 hgcmObjDeleteHandle(handle);
1684 }
1685 else
1686 {
1687 if (pu32ClientIdOut != NULL)
1688 {
1689 *pu32ClientIdOut = handle;
1690 }
1691
1692 ReferenceService();
1693 }
1694
1695 LogFlowFunc(("rc = %Rrc\n", rc));
1696 return rc;
1697}
1698
1699/* Disconnect the client from the service and delete the client handle.
1700 *
1701 * @param u32ClientId The handle of the client.
1702 * @return VBox rc.
1703 */
1704int HGCMService::DisconnectClient(uint32_t u32ClientId, bool fFromService)
1705{
1706 int rc = VINF_SUCCESS;
1707
1708 LogFlowFunc(("client id = %d, fFromService = %d\n", u32ClientId, fFromService));
1709
1710 if (!fFromService)
1711 {
1712 /* Call the service. */
1713 HGCMMsgCore *pCoreMsg;
1714
1715 rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_DISCONNECT, hgcmMessageAllocSvc);
1716
1717 if (RT_SUCCESS(rc))
1718 {
1719 HGCMMsgSvcDisconnect *pMsg = (HGCMMsgSvcDisconnect *)pCoreMsg;
1720
1721 pMsg->u32ClientId = u32ClientId;
1722
1723 rc = hgcmMsgSend(pMsg);
1724 }
1725 else
1726 {
1727 LogRel(("(%d, %d) [%s] hgcmMsgAlloc(%p, SVC_MSG_DISCONNECT) failed %Rrc\n",
1728 u32ClientId, fFromService, RT_VALID_PTR(m_pszSvcName)? m_pszSvcName: "", m_pThread, rc));
1729 }
1730 }
1731
1732 /* Remove the client id from the array in any case, rc does not matter. */
1733 uint32_t i;
1734
1735 for (i = 0; i < m_cClients; i++)
1736 {
1737 if (m_paClientIds[i] == u32ClientId)
1738 {
1739 m_cClients--;
1740
1741 if (m_cClients > i)
1742 memmove(&m_paClientIds[i], &m_paClientIds[i + 1], sizeof(m_paClientIds[0]) * (m_cClients - i));
1743
1744 /* Delete the client handle. */
1745 hgcmObjDeleteHandle(u32ClientId);
1746
1747 /* The service must be released. */
1748 ReleaseService();
1749
1750 break;
1751 }
1752 }
1753
1754 LogFlowFunc(("rc = %Rrc\n", rc));
1755 return rc;
1756}
1757
1758int HGCMService::RegisterExtension(HGCMSVCEXTHANDLE handle,
1759 PFNHGCMSVCEXT pfnExtension,
1760 void *pvExtension)
1761{
1762 LogFlowFunc(("%s\n", handle->pszServiceName));
1763
1764 /* Forward the message to the service thread. */
1765 HGCMMsgCore *pCoreMsg;
1766 int rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_REGEXT, hgcmMessageAllocSvc);
1767
1768 if (RT_SUCCESS(rc))
1769 {
1770 HGCMMsgSvcRegisterExtension *pMsg = (HGCMMsgSvcRegisterExtension *)pCoreMsg;
1771
1772 pMsg->handle = handle;
1773 pMsg->pfnExtension = pfnExtension;
1774 pMsg->pvExtension = pvExtension;
1775
1776 rc = hgcmMsgSend(pMsg);
1777 }
1778
1779 LogFlowFunc(("rc = %Rrc\n", rc));
1780 return rc;
1781}
1782
1783void HGCMService::UnregisterExtension(HGCMSVCEXTHANDLE handle)
1784{
1785 /* Forward the message to the service thread. */
1786 HGCMMsgCore *pCoreMsg;
1787 int rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_UNREGEXT, hgcmMessageAllocSvc);
1788
1789 if (RT_SUCCESS(rc))
1790 {
1791 HGCMMsgSvcUnregisterExtension *pMsg = (HGCMMsgSvcUnregisterExtension *)pCoreMsg;
1792
1793 pMsg->handle = handle;
1794
1795 rc = hgcmMsgSend(pMsg);
1796 }
1797
1798 LogFlowFunc(("rc = %Rrc\n", rc));
1799}
1800
1801/** Perform a guest call to the service.
1802 *
1803 * @param pHGCMPort The port to be used for completion confirmation.
1804 * @param pCmd The VBox HGCM context.
1805 * @param u32ClientId The client handle to be disconnected and deleted.
1806 * @param u32Function The function number.
1807 * @param cParms Number of parameters.
1808 * @param paParms Pointer to array of parameters.
1809 * @param tsArrival The STAM_GET_TS() value when the request arrived.
1810 * @return VBox rc.
1811 * @retval VINF_HGCM_ASYNC_EXECUTE on success.
1812 */
1813int HGCMService::GuestCall(PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId, uint32_t u32Function,
1814 uint32_t cParms, VBOXHGCMSVCPARM paParms[], uint64_t tsArrival)
1815{
1816 LogFlow(("MAIN::HGCMService::GuestCall\n"));
1817
1818 int rc;
1819 HGCMMsgCall *pMsg = new (std::nothrow) HGCMMsgCall(m_pThread);
1820 if (pMsg)
1821 {
1822 pMsg->Reference(); /** @todo starts out with zero references. */
1823
1824 pMsg->pCmd = pCmd;
1825 pMsg->pHGCMPort = pHGCMPort;
1826 pMsg->u32ClientId = u32ClientId;
1827 pMsg->u32Function = u32Function;
1828 pMsg->cParms = cParms;
1829 pMsg->paParms = paParms;
1830 pMsg->tsArrival = tsArrival;
1831
1832 rc = hgcmMsgPost(pMsg, hgcmMsgCompletionCallback);
1833 }
1834 else
1835 {
1836 Log(("MAIN::HGCMService::GuestCall: Message allocation failed\n"));
1837 rc = VERR_NO_MEMORY;
1838 }
1839
1840 LogFlowFunc(("rc = %Rrc\n", rc));
1841 return rc;
1842}
1843
1844/** Guest cancelled a request (call, connection attempt, disconnect attempt).
1845 *
1846 * @param pHGCMPort The port to be used for completion confirmation.
1847 * @param pCmd The VBox HGCM context.
1848 * @param u32ClientId The client handle to be disconnected and deleted.
1849 * @return VBox rc.
1850 */
1851void HGCMService::GuestCancelled(PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t idClient)
1852{
1853 LogFlow(("MAIN::HGCMService::GuestCancelled\n"));
1854
1855 if (m_fntable.pfnCancelled)
1856 {
1857 HGCMMsgCancelled *pMsg = new (std::nothrow) HGCMMsgCancelled(m_pThread);
1858 if (pMsg)
1859 {
1860 pMsg->Reference(); /** @todo starts out with zero references. */
1861
1862 pMsg->pCmd = pCmd;
1863 pMsg->pHGCMPort = pHGCMPort;
1864 pMsg->idClient = idClient;
1865
1866 hgcmMsgPost(pMsg, NULL);
1867 }
1868 else
1869 Log(("MAIN::HGCMService::GuestCancelled: Message allocation failed\n"));
1870 }
1871}
1872
1873/** Perform a host call the service.
1874 *
1875 * @param u32Function The function number.
1876 * @param cParms Number of parameters.
1877 * @param paParms Pointer to array of parameters.
1878 * @return VBox rc.
1879 */
1880int HGCMService::HostCall(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM *paParms)
1881{
1882 LogFlowFunc(("%s u32Function = %d, cParms = %d, paParms = %p\n",
1883 m_pszSvcName, u32Function, cParms, paParms));
1884
1885 HGCMMsgCore *pCoreMsg;
1886 int rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_HOSTCALL, hgcmMessageAllocSvc);
1887
1888 if (RT_SUCCESS(rc))
1889 {
1890 HGCMMsgHostCallSvc *pMsg = (HGCMMsgHostCallSvc *)pCoreMsg;
1891
1892 pMsg->u32Function = u32Function;
1893 pMsg->cParms = cParms;
1894 pMsg->paParms = paParms;
1895
1896 rc = hgcmMsgSend(pMsg);
1897 }
1898
1899 LogFlowFunc(("rc = %Rrc\n", rc));
1900 return rc;
1901}
1902
1903/** Posts a broadcast notification event to all interested services.
1904 *
1905 * @param enmEvent The notification event.
1906 */
1907/*static*/ void HGCMService::BroadcastNotify(HGCMNOTIFYEVENT enmEvent)
1908{
1909 for (HGCMService *pService = sm_pSvcListHead; pService != NULL; pService = pService->m_pSvcNext)
1910 {
1911 pService->Notify(enmEvent);
1912 }
1913}
1914
1915/** Posts a broadcast notification event to the service.
1916 *
1917 * @param enmEvent The notification event.
1918 */
1919void HGCMService::Notify(HGCMNOTIFYEVENT enmEvent)
1920{
1921 LogFlowFunc(("%s enmEvent=%d pfnNotify=%p\n", m_pszSvcName, enmEvent, m_fntable.pfnNotify));
1922 if (m_fntable.pfnNotify)
1923 {
1924 HGCMMsgCore *pCoreMsg;
1925 int rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_NOTIFY, hgcmMessageAllocSvc);
1926 if (RT_SUCCESS(rc))
1927 {
1928 HGCMMsgNotify *pMsg = (HGCMMsgNotify *)pCoreMsg;
1929 pMsg->enmEvent = enmEvent;
1930
1931 rc = hgcmMsgPost(pMsg, NULL);
1932 AssertRC(rc);
1933 }
1934 }
1935}
1936
1937#ifdef VBOX_WITH_CRHGSMI
1938
1939static DECLCALLBACK(int) hgcmMsgFastCallCompletionCallback(int32_t result, HGCMMsgCore *pMsgCore)
1940{
1941 /* Call the VMMDev port interface to issue IRQ notification. */
1942 LogFlow(("MAIN::hgcmMsgFastCallCompletionCallback: message %p\n", pMsgCore));
1943
1944 HGCMMsgHostFastCallAsyncSvc *pMsg = (HGCMMsgHostFastCallAsyncSvc *)pMsgCore;
1945 if (pMsg->pfnCompletion)
1946 pMsg->pfnCompletion(result, pMsg->u32Function, &pMsg->Param, pMsg->pvCompletion);
1947 return VINF_SUCCESS;
1948}
1949
1950int HGCMService::HandleAcquired()
1951{
1952 ++m_cHandleAcquires;
1953 return VINF_SUCCESS;
1954}
1955
1956int HGCMService::HandleReleased()
1957{
1958 Assert(m_cHandleAcquires);
1959 if (m_cHandleAcquires)
1960 {
1961 --m_cHandleAcquires;
1962 return VINF_SUCCESS;
1963 }
1964 return VERR_INVALID_STATE;
1965}
1966
1967int HGCMService::HostFastCallAsync(uint32_t u32Function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion,
1968 void *pvCompletion)
1969{
1970 LogFlowFunc(("%s u32Function = %d, pParm = %p\n",
1971 m_pszSvcName, u32Function, pParm));
1972
1973 HGCMMsgCore *pCoreMsg;
1974 int rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_HOSTFASTCALLASYNC, hgcmMessageAllocSvc);
1975
1976 if (RT_SUCCESS(rc))
1977 {
1978 HGCMMsgHostFastCallAsyncSvc *pMsg = (HGCMMsgHostFastCallAsyncSvc *)pCoreMsg;
1979
1980 pMsg->u32Function = u32Function;
1981 pMsg->Param = *pParm;
1982 pMsg->pfnCompletion = pfnCompletion;
1983 pMsg->pvCompletion = pvCompletion;
1984
1985 rc = hgcmMsgPost(pMsg, hgcmMsgFastCallCompletionCallback);
1986 }
1987
1988 LogFlowFunc(("rc = %Rrc\n", rc));
1989 return rc;
1990}
1991
1992#endif /* VBOX_WITH_CRHGSMI */
1993
1994/*
1995 * Main HGCM thread that manages services.
1996 */
1997
1998/* Messages processed by the main HGCM thread. */
1999#define HGCM_MSG_CONNECT (10) /**< Connect a client to a service. */
2000#define HGCM_MSG_DISCONNECT (11) /**< Disconnect the specified client id. */
2001#define HGCM_MSG_LOAD (12) /**< Load the service. */
2002#define HGCM_MSG_HOSTCALL (13) /**< Call the service. */
2003#define HGCM_MSG_LOADSTATE (14) /**< Load saved state for the specified service. */
2004#define HGCM_MSG_SAVESTATE (15) /**< Save state for the specified service. */
2005#define HGCM_MSG_RESET (16) /**< Disconnect all clients from the specified service. */
2006#define HGCM_MSG_QUIT (17) /**< Unload all services and terminate the thread. */
2007#define HGCM_MSG_REGEXT (18) /**< Register a service extension. */
2008#define HGCM_MSG_UNREGEXT (19) /**< Unregister a service extension. */
2009#define HGCM_MSG_BRD_NOTIFY (20) /**< Broadcast notification event (VM state change). */
2010#ifdef VBOX_WITH_CRHGSMI
2011# define HGCM_MSG_SVCAQUIRE (30) /**< Acquire a service handle (for fast host calls) */
2012# define HGCM_MSG_SVCRELEASE (31) /**< Release a service */
2013#endif
2014
2015class HGCMMsgMainConnect: public HGCMMsgHeader
2016{
2017 public:
2018 /* Service name. */
2019 const char *pszServiceName;
2020 /* Where to store the client handle. */
2021 uint32_t *pu32ClientId;
2022};
2023
2024class HGCMMsgMainDisconnect: public HGCMMsgHeader
2025{
2026 public:
2027 /* Handle of the client to be disconnected. */
2028 uint32_t u32ClientId;
2029};
2030
2031class HGCMMsgMainLoad: public HGCMMsgCore
2032{
2033 public:
2034 /* Name of the library to be loaded. */
2035 const char *pszServiceLibrary;
2036 /* Name to be assigned to the service. */
2037 const char *pszServiceName;
2038 /** The user mode VM handle (for statistics and such). */
2039 PUVM pUVM;
2040 /** The HGCM port on the VMMDev device (for session ID and such). */
2041 PPDMIHGCMPORT pHgcmPort;
2042};
2043
2044class HGCMMsgMainHostCall: public HGCMMsgCore
2045{
2046 public:
2047 /* Which service to call. */
2048 const char *pszServiceName;
2049 /* Function number. */
2050 uint32_t u32Function;
2051 /* Number of the function parameters. */
2052 uint32_t cParms;
2053 /* Pointer to array of the function parameters. */
2054 VBOXHGCMSVCPARM *paParms;
2055};
2056
2057class HGCMMsgMainLoadSaveState: public HGCMMsgCore
2058{
2059 public:
2060 /** Saved state handle. */
2061 PSSMHANDLE pSSM;
2062 /** The HGCM saved state version being loaded (ignore for save). */
2063 uint32_t uVersion;
2064};
2065
2066class HGCMMsgMainReset: public HGCMMsgCore
2067{
2068};
2069
2070class HGCMMsgMainQuit: public HGCMMsgCore
2071{
2072 public:
2073 /** Whether UVM has gone invalid already or not. */
2074 bool fUvmIsInvalid;
2075};
2076
2077class HGCMMsgMainRegisterExtension: public HGCMMsgCore
2078{
2079 public:
2080 /** Returned handle to be used in HGCMMsgMainUnregisterExtension. */
2081 HGCMSVCEXTHANDLE *pHandle;
2082 /** Name of the service. */
2083 const char *pszServiceName;
2084 /** The extension entry point. */
2085 PFNHGCMSVCEXT pfnExtension;
2086 /** The extension pointer. */
2087 void *pvExtension;
2088};
2089
2090class HGCMMsgMainUnregisterExtension: public HGCMMsgCore
2091{
2092 public:
2093 /* Handle of the registered extension. */
2094 HGCMSVCEXTHANDLE handle;
2095};
2096
2097class HGCMMsgMainBroadcastNotify: public HGCMMsgCore
2098{
2099 public:
2100 /** The notification event. */
2101 HGCMNOTIFYEVENT enmEvent;
2102};
2103
2104#ifdef VBOX_WITH_CRHGSMI
2105class HGCMMsgMainSvcAcquire: public HGCMMsgCore
2106{
2107 public:
2108 /* Which service to call. */
2109 const char *pszServiceName;
2110 /* Returned service. */
2111 HGCMService *pService;
2112};
2113
2114class HGCMMsgMainSvcRelease: public HGCMMsgCore
2115{
2116 public:
2117 /* Svc . */
2118 HGCMService *pService;
2119};
2120#endif
2121
2122
2123static HGCMMsgCore *hgcmMainMessageAlloc (uint32_t u32MsgId)
2124{
2125 switch (u32MsgId)
2126 {
2127 case HGCM_MSG_CONNECT: return new HGCMMsgMainConnect();
2128 case HGCM_MSG_DISCONNECT: return new HGCMMsgMainDisconnect();
2129 case HGCM_MSG_LOAD: return new HGCMMsgMainLoad();
2130 case HGCM_MSG_HOSTCALL: return new HGCMMsgMainHostCall();
2131 case HGCM_MSG_LOADSTATE:
2132 case HGCM_MSG_SAVESTATE: return new HGCMMsgMainLoadSaveState();
2133 case HGCM_MSG_RESET: return new HGCMMsgMainReset();
2134 case HGCM_MSG_QUIT: return new HGCMMsgMainQuit();
2135 case HGCM_MSG_REGEXT: return new HGCMMsgMainRegisterExtension();
2136 case HGCM_MSG_UNREGEXT: return new HGCMMsgMainUnregisterExtension();
2137 case HGCM_MSG_BRD_NOTIFY: return new HGCMMsgMainBroadcastNotify();
2138#ifdef VBOX_WITH_CRHGSMI
2139 case HGCM_MSG_SVCAQUIRE: return new HGCMMsgMainSvcAcquire();
2140 case HGCM_MSG_SVCRELEASE: return new HGCMMsgMainSvcRelease();
2141#endif
2142
2143 default:
2144 AssertReleaseMsgFailed(("Msg id = %08X\n", u32MsgId));
2145 }
2146
2147 return NULL;
2148}
2149
2150
2151/* The main HGCM thread handler. */
2152static DECLCALLBACK(void) hgcmThread(HGCMThread *pThread, void *pvUser)
2153{
2154 LogFlowFunc(("pThread = %p, pvUser = %p\n", pThread, pvUser));
2155
2156 NOREF(pvUser);
2157
2158 bool fQuit = false;
2159
2160 while (!fQuit)
2161 {
2162 HGCMMsgCore *pMsgCore;
2163 int rc = hgcmMsgGet(pThread, &pMsgCore);
2164
2165 if (RT_FAILURE(rc))
2166 {
2167 /* The error means some serious unrecoverable problem in the hgcmMsg/hgcmThread layer. */
2168 AssertMsgFailed(("%Rrc\n", rc));
2169 break;
2170 }
2171
2172 uint32_t u32MsgId = pMsgCore->MsgId();
2173
2174 switch (u32MsgId)
2175 {
2176 case HGCM_MSG_CONNECT:
2177 {
2178 HGCMMsgMainConnect *pMsg = (HGCMMsgMainConnect *)pMsgCore;
2179
2180 LogFlowFunc(("HGCM_MSG_CONNECT pszServiceName %s, pu32ClientId %p\n",
2181 pMsg->pszServiceName, pMsg->pu32ClientId));
2182
2183 /* Resolve the service name to the pointer to service instance.
2184 */
2185 HGCMService *pService;
2186 rc = HGCMService::ResolveService(&pService, pMsg->pszServiceName);
2187
2188 if (RT_SUCCESS(rc))
2189 {
2190 /* Call the service instance method. */
2191 rc = pService->CreateAndConnectClient(pMsg->pu32ClientId,
2192 0,
2193 pMsg->pHGCMPort->pfnGetRequestor(pMsg->pHGCMPort, pMsg->pCmd),
2194 pMsg->pHGCMPort->pfnIsCmdRestored(pMsg->pHGCMPort, pMsg->pCmd));
2195
2196 /* Release the service after resolve. */
2197 pService->ReleaseService();
2198 }
2199 } break;
2200
2201 case HGCM_MSG_DISCONNECT:
2202 {
2203 HGCMMsgMainDisconnect *pMsg = (HGCMMsgMainDisconnect *)pMsgCore;
2204
2205 LogFlowFunc(("HGCM_MSG_DISCONNECT u32ClientId = %d\n",
2206 pMsg->u32ClientId));
2207
2208 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(pMsg->u32ClientId, HGCMOBJ_CLIENT);
2209
2210 if (!pClient)
2211 {
2212 rc = VERR_HGCM_INVALID_CLIENT_ID;
2213 break;
2214 }
2215
2216 /* The service the client belongs to. */
2217 HGCMService *pService = pClient->pService;
2218
2219 /* Call the service instance to disconnect the client. */
2220 rc = pService->DisconnectClient(pMsg->u32ClientId, false);
2221
2222 hgcmObjDereference(pClient);
2223 } break;
2224
2225 case HGCM_MSG_LOAD:
2226 {
2227 HGCMMsgMainLoad *pMsg = (HGCMMsgMainLoad *)pMsgCore;
2228
2229 LogFlowFunc(("HGCM_MSG_LOAD pszServiceName = %s, pMsg->pszServiceLibrary = %s, pMsg->pUVM = %p\n",
2230 pMsg->pszServiceName, pMsg->pszServiceLibrary, pMsg->pUVM));
2231
2232 rc = HGCMService::LoadService(pMsg->pszServiceLibrary, pMsg->pszServiceName, pMsg->pUVM, pMsg->pHgcmPort);
2233 } break;
2234
2235 case HGCM_MSG_HOSTCALL:
2236 {
2237 HGCMMsgMainHostCall *pMsg = (HGCMMsgMainHostCall *)pMsgCore;
2238
2239 LogFlowFunc(("HGCM_MSG_HOSTCALL pszServiceName %s, u32Function %d, cParms %d, paParms %p\n",
2240 pMsg->pszServiceName, pMsg->u32Function, pMsg->cParms, pMsg->paParms));
2241
2242 /* Resolve the service name to the pointer to service instance. */
2243 HGCMService *pService;
2244 rc = HGCMService::ResolveService(&pService, pMsg->pszServiceName);
2245
2246 if (RT_SUCCESS(rc))
2247 {
2248 rc = pService->HostCall(pMsg->u32Function, pMsg->cParms, pMsg->paParms);
2249
2250 pService->ReleaseService();
2251 }
2252 } break;
2253
2254 case HGCM_MSG_BRD_NOTIFY:
2255 {
2256 HGCMMsgMainBroadcastNotify *pMsg = (HGCMMsgMainBroadcastNotify *)pMsgCore;
2257
2258 LogFlowFunc(("HGCM_MSG_BRD_NOTIFY enmEvent=%d\n", pMsg->enmEvent));
2259
2260 HGCMService::BroadcastNotify(pMsg->enmEvent);
2261 } break;
2262
2263#ifdef VBOX_WITH_CRHGSMI
2264 case HGCM_MSG_SVCAQUIRE:
2265 {
2266 HGCMMsgMainSvcAcquire *pMsg = (HGCMMsgMainSvcAcquire *)pMsgCore;
2267
2268 LogFlowFunc(("HGCM_MSG_SVCAQUIRE pszServiceName %s\n", pMsg->pszServiceName));
2269
2270 /* Resolve the service name to the pointer to service instance. */
2271 HGCMService *pService;
2272 rc = HGCMService::ResolveService(&pService, pMsg->pszServiceName);
2273 if (RT_SUCCESS(rc))
2274 {
2275 rc = pService->HandleAcquired();
2276 if (RT_SUCCESS(rc))
2277 {
2278 pMsg->pService = pService;
2279 }
2280 else
2281 {
2282 pService->ReleaseService();
2283 }
2284 }
2285 } break;
2286
2287 case HGCM_MSG_SVCRELEASE:
2288 {
2289 HGCMMsgMainSvcRelease *pMsg = (HGCMMsgMainSvcRelease *)pMsgCore;
2290
2291 LogFlowFunc(("HGCM_MSG_SVCARELEASE pService %p\n", pMsg->pService));
2292
2293 /* Resolve the service name to the pointer to service instance. */
2294
2295 rc = pMsg->pService->HandleReleased();
2296 if (RT_SUCCESS(rc))
2297 {
2298 pMsg->pService->ReleaseService();
2299 }
2300 } break;
2301#endif
2302
2303 case HGCM_MSG_RESET:
2304 {
2305 LogFlowFunc(("HGCM_MSG_RESET\n"));
2306
2307 HGCMService::Reset();
2308
2309 HGCMService::BroadcastNotify(HGCMNOTIFYEVENT_RESET);
2310 } break;
2311
2312 case HGCM_MSG_LOADSTATE:
2313 {
2314 HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pMsgCore;
2315
2316 LogFlowFunc(("HGCM_MSG_LOADSTATE\n"));
2317
2318 rc = HGCMService::LoadState(pMsg->pSSM, pMsg->uVersion);
2319 } break;
2320
2321 case HGCM_MSG_SAVESTATE:
2322 {
2323 HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pMsgCore;
2324
2325 LogFlowFunc(("HGCM_MSG_SAVESTATE\n"));
2326
2327 rc = HGCMService::SaveState(pMsg->pSSM);
2328 } break;
2329
2330 case HGCM_MSG_QUIT:
2331 {
2332 HGCMMsgMainQuit *pMsg = (HGCMMsgMainQuit *)pMsgCore;
2333 LogFlowFunc(("HGCM_MSG_QUIT\n"));
2334
2335 HGCMService::UnloadAll(pMsg->fUvmIsInvalid);
2336
2337 fQuit = true;
2338 } break;
2339
2340 case HGCM_MSG_REGEXT:
2341 {
2342 HGCMMsgMainRegisterExtension *pMsg = (HGCMMsgMainRegisterExtension *)pMsgCore;
2343
2344 LogFlowFunc(("HGCM_MSG_REGEXT\n"));
2345
2346 /* Allocate the handle data. */
2347 HGCMSVCEXTHANDLE handle = (HGCMSVCEXTHANDLE)RTMemAllocZ(sizeof(struct _HGCMSVCEXTHANDLEDATA)
2348 + strlen(pMsg->pszServiceName)
2349 + sizeof(char));
2350
2351 if (handle == NULL)
2352 {
2353 rc = VERR_NO_MEMORY;
2354 }
2355 else
2356 {
2357 handle->pszServiceName = (char *)((uint8_t *)handle + sizeof(struct _HGCMSVCEXTHANDLEDATA));
2358 strcpy(handle->pszServiceName, pMsg->pszServiceName);
2359
2360 HGCMService *pService;
2361 rc = HGCMService::ResolveService(&pService, handle->pszServiceName);
2362
2363 if (RT_SUCCESS(rc))
2364 {
2365 pService->RegisterExtension(handle, pMsg->pfnExtension, pMsg->pvExtension);
2366
2367 pService->ReleaseService();
2368 }
2369
2370 if (RT_FAILURE(rc))
2371 {
2372 RTMemFree(handle);
2373 }
2374 else
2375 {
2376 *pMsg->pHandle = handle;
2377 }
2378 }
2379 } break;
2380
2381 case HGCM_MSG_UNREGEXT:
2382 {
2383 HGCMMsgMainUnregisterExtension *pMsg = (HGCMMsgMainUnregisterExtension *)pMsgCore;
2384
2385 LogFlowFunc(("HGCM_MSG_UNREGEXT\n"));
2386
2387 HGCMService *pService;
2388 rc = HGCMService::ResolveService(&pService, pMsg->handle->pszServiceName);
2389
2390 if (RT_SUCCESS(rc))
2391 {
2392 pService->UnregisterExtension(pMsg->handle);
2393
2394 pService->ReleaseService();
2395 }
2396
2397 RTMemFree(pMsg->handle);
2398 } break;
2399
2400 default:
2401 {
2402 AssertMsgFailed(("hgcmThread: Unsupported message number %08X!!!\n", u32MsgId));
2403 rc = VERR_NOT_SUPPORTED;
2404 } break;
2405 }
2406
2407 /* Complete the message processing. */
2408 hgcmMsgComplete(pMsgCore, rc);
2409
2410 LogFlowFunc(("message processed %Rrc\n", rc));
2411 }
2412}
2413
2414
2415/*
2416 * The HGCM API.
2417 */
2418
2419/** The main hgcm thread. */
2420static HGCMThread *g_pHgcmThread = 0;
2421
2422/*
2423 * Public HGCM functions.
2424 *
2425 * hgcmGuest* - called as a result of the guest HGCM requests.
2426 * hgcmHost* - called by the host.
2427 */
2428
2429/* Load a HGCM service from the specified library.
2430 * Assign the specified name to the service.
2431 *
2432 * @param pszServiceLibrary The library to be loaded.
2433 * @param pszServiceName The name to be assigned to the service.
2434 * @param pUVM The user mode VM handle (for statistics and such).
2435 * @param pHgcmPort The HGCM port on the VMMDev device (for session ID and such).
2436 * @return VBox rc.
2437 */
2438int HGCMHostLoad(const char *pszServiceLibrary,
2439 const char *pszServiceName,
2440 PUVM pUVM,
2441 PPDMIHGCMPORT pHgcmPort)
2442{
2443 LogFlowFunc(("lib = %s, name = %s\n", pszServiceLibrary, pszServiceName));
2444
2445 if (!pszServiceLibrary || !pszServiceName)
2446 {
2447 return VERR_INVALID_PARAMETER;
2448 }
2449
2450 /* Forward the request to the main hgcm thread. */
2451 HGCMMsgCore *pCoreMsg;
2452 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_LOAD, hgcmMainMessageAlloc);
2453
2454 if (RT_SUCCESS(rc))
2455 {
2456 /* Initialize the message. Since the message is synchronous, use the supplied pointers. */
2457 HGCMMsgMainLoad *pMsg = (HGCMMsgMainLoad *)pCoreMsg;
2458
2459 pMsg->pszServiceLibrary = pszServiceLibrary;
2460 pMsg->pszServiceName = pszServiceName;
2461 pMsg->pUVM = pUVM;
2462 pMsg->pHgcmPort = pHgcmPort;
2463
2464 rc = hgcmMsgSend(pMsg);
2465 }
2466
2467 LogFlowFunc(("rc = %Rrc\n", rc));
2468 return rc;
2469}
2470
2471/* Register a HGCM service extension.
2472 *
2473 * @param pHandle Returned handle for the registered extension.
2474 * @param pszServiceName The name of the service.
2475 * @param pfnExtension The extension entry point (callback).
2476 * @param pvExtension The extension pointer.
2477 * @return VBox rc.
2478 */
2479int HGCMHostRegisterServiceExtension(HGCMSVCEXTHANDLE *pHandle,
2480 const char *pszServiceName,
2481 PFNHGCMSVCEXT pfnExtension,
2482 void *pvExtension)
2483{
2484 LogFlowFunc(("pHandle = %p, name = %s, pfn = %p, rv = %p\n", pHandle, pszServiceName, pfnExtension, pvExtension));
2485
2486 if (!pHandle || !pszServiceName || !pfnExtension)
2487 {
2488 return VERR_INVALID_PARAMETER;
2489 }
2490
2491 /* Forward the request to the main hgcm thread. */
2492 HGCMMsgCore *pCoreMsg;
2493 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_REGEXT, hgcmMainMessageAlloc);
2494
2495 if (RT_SUCCESS(rc))
2496 {
2497 /* Initialize the message. Since the message is synchronous, use the supplied pointers. */
2498 HGCMMsgMainRegisterExtension *pMsg = (HGCMMsgMainRegisterExtension *)pCoreMsg;
2499
2500 pMsg->pHandle = pHandle;
2501 pMsg->pszServiceName = pszServiceName;
2502 pMsg->pfnExtension = pfnExtension;
2503 pMsg->pvExtension = pvExtension;
2504
2505 rc = hgcmMsgSend(pMsg);
2506 }
2507
2508 LogFlowFunc(("*pHandle = %p, rc = %Rrc\n", *pHandle, rc));
2509 return rc;
2510}
2511
2512void HGCMHostUnregisterServiceExtension(HGCMSVCEXTHANDLE handle)
2513{
2514 LogFlowFunc(("handle = %p\n", handle));
2515
2516 /* Forward the request to the main hgcm thread. */
2517 HGCMMsgCore *pCoreMsg;
2518 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_UNREGEXT, hgcmMainMessageAlloc);
2519
2520 if (RT_SUCCESS(rc))
2521 {
2522 /* Initialize the message. */
2523 HGCMMsgMainUnregisterExtension *pMsg = (HGCMMsgMainUnregisterExtension *)pCoreMsg;
2524
2525 pMsg->handle = handle;
2526
2527 rc = hgcmMsgSend(pMsg);
2528 }
2529
2530 LogFlowFunc(("rc = %Rrc\n", rc));
2531 return;
2532}
2533
2534/* Find a service and inform it about a client connection, create a client handle.
2535 *
2536 * @param pHGCMPort The port to be used for completion confirmation.
2537 * @param pCmd The VBox HGCM context.
2538 * @param pszServiceName The name of the service to be connected to.
2539 * @param pu32ClientId Where the store the created client handle.
2540 * @return VBox rc.
2541 */
2542int HGCMGuestConnect(PPDMIHGCMPORT pHGCMPort,
2543 PVBOXHGCMCMD pCmd,
2544 const char *pszServiceName,
2545 uint32_t *pu32ClientId)
2546{
2547 LogFlowFunc(("pHGCMPort = %p, pCmd = %p, name = %s, pu32ClientId = %p\n",
2548 pHGCMPort, pCmd, pszServiceName, pu32ClientId));
2549
2550 if (pHGCMPort == NULL || pCmd == NULL || pszServiceName == NULL || pu32ClientId == NULL)
2551 {
2552 return VERR_INVALID_PARAMETER;
2553 }
2554
2555 /* Forward the request to the main hgcm thread. */
2556 HGCMMsgCore *pCoreMsg;
2557 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_CONNECT, hgcmMainMessageAlloc);
2558
2559 if (RT_SUCCESS(rc))
2560 {
2561 /* Initialize the message. Since 'pszServiceName' and 'pu32ClientId'
2562 * will not be deallocated by the caller until the message is completed,
2563 * use the supplied pointers.
2564 */
2565 HGCMMsgMainConnect *pMsg = (HGCMMsgMainConnect *)pCoreMsg;
2566
2567 pMsg->pHGCMPort = pHGCMPort;
2568 pMsg->pCmd = pCmd;
2569 pMsg->pszServiceName = pszServiceName;
2570 pMsg->pu32ClientId = pu32ClientId;
2571
2572 rc = hgcmMsgPost(pMsg, hgcmMsgCompletionCallback);
2573 }
2574
2575 LogFlowFunc(("rc = %Rrc\n", rc));
2576 return rc;
2577}
2578
2579/* Tell a service that the client is disconnecting, destroy the client handle.
2580 *
2581 * @param pHGCMPort The port to be used for completion confirmation.
2582 * @param pCmd The VBox HGCM context.
2583 * @param u32ClientId The client handle to be disconnected and deleted.
2584 * @return VBox rc.
2585 */
2586int HGCMGuestDisconnect(PPDMIHGCMPORT pHGCMPort,
2587 PVBOXHGCMCMD pCmd,
2588 uint32_t u32ClientId)
2589{
2590 LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d\n",
2591 pHGCMPort, pCmd, u32ClientId));
2592
2593 if (!pHGCMPort || !pCmd || !u32ClientId)
2594 {
2595 return VERR_INVALID_PARAMETER;
2596 }
2597
2598 /* Forward the request to the main hgcm thread. */
2599 HGCMMsgCore *pCoreMsg;
2600 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_DISCONNECT, hgcmMainMessageAlloc);
2601
2602 if (RT_SUCCESS(rc))
2603 {
2604 /* Initialize the message. */
2605 HGCMMsgMainDisconnect *pMsg = (HGCMMsgMainDisconnect *)pCoreMsg;
2606
2607 pMsg->pCmd = pCmd;
2608 pMsg->pHGCMPort = pHGCMPort;
2609 pMsg->u32ClientId = u32ClientId;
2610
2611 rc = hgcmMsgPost(pMsg, hgcmMsgCompletionCallback);
2612 }
2613
2614 LogFlowFunc(("rc = %Rrc\n", rc));
2615 return rc;
2616}
2617
2618/** Helper to send either HGCM_MSG_SAVESTATE or HGCM_MSG_LOADSTATE messages to the main HGCM thread.
2619 *
2620 * @param pSSM The SSM handle.
2621 * @param idMsg The message to be sent: HGCM_MSG_SAVESTATE or HGCM_MSG_LOADSTATE.
2622 * @param uVersion The state version being loaded.
2623 * @return VBox rc.
2624 */
2625static int hgcmHostLoadSaveState(PSSMHANDLE pSSM, uint32_t idMsg, uint32_t uVersion)
2626{
2627 LogFlowFunc(("pSSM = %p, idMsg = %d, uVersion = uVersion\n", pSSM, idMsg));
2628
2629 HGCMMsgCore *pCoreMsg;
2630 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, idMsg, hgcmMainMessageAlloc);
2631
2632 if (RT_SUCCESS(rc))
2633 {
2634 HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pCoreMsg;
2635 AssertRelease(pMsg);
2636
2637 pMsg->pSSM = pSSM;
2638 pMsg->uVersion = uVersion;
2639
2640 rc = hgcmMsgSend(pMsg);
2641 }
2642
2643 LogFlowFunc(("rc = %Rrc\n", rc));
2644 return rc;
2645}
2646
2647/** Save the state of services.
2648 *
2649 * @param pSSM The SSM handle.
2650 * @return VBox rc.
2651 */
2652int HGCMHostSaveState(PSSMHANDLE pSSM)
2653{
2654 return hgcmHostLoadSaveState(pSSM, HGCM_MSG_SAVESTATE, HGCM_SAVED_STATE_VERSION);
2655}
2656
2657/** Load the state of services.
2658 *
2659 * @param pSSM The SSM handle.
2660 * @param uVersion The state version being loaded.
2661 * @return VBox rc.
2662 */
2663int HGCMHostLoadState(PSSMHANDLE pSSM, uint32_t uVersion)
2664{
2665 return hgcmHostLoadSaveState(pSSM, HGCM_MSG_LOADSTATE, uVersion);
2666}
2667
2668/** The guest calls the service.
2669 *
2670 * @param pHGCMPort The port to be used for completion confirmation.
2671 * @param pCmd The VBox HGCM context.
2672 * @param u32ClientId The client handle.
2673 * @param u32Function The function number.
2674 * @param cParms Number of parameters.
2675 * @param paParms Pointer to array of parameters.
2676 * @param tsArrival The STAM_GET_TS() value when the request arrived.
2677 * @return VBox rc.
2678 */
2679int HGCMGuestCall(PPDMIHGCMPORT pHGCMPort,
2680 PVBOXHGCMCMD pCmd,
2681 uint32_t u32ClientId,
2682 uint32_t u32Function,
2683 uint32_t cParms,
2684 VBOXHGCMSVCPARM *paParms,
2685 uint64_t tsArrival)
2686{
2687 LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d, u32Function = %d, cParms = %d, paParms = %p\n",
2688 pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms));
2689
2690 if (!pHGCMPort || !pCmd || u32ClientId == 0)
2691 {
2692 return VERR_INVALID_PARAMETER;
2693 }
2694
2695 int rc = VERR_HGCM_INVALID_CLIENT_ID;
2696
2697 /* Resolve the client handle to the client instance pointer. */
2698 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(u32ClientId, HGCMOBJ_CLIENT);
2699
2700 if (pClient)
2701 {
2702 AssertRelease(pClient->pService);
2703
2704 /* Forward the message to the service thread. */
2705 rc = pClient->pService->GuestCall(pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms, tsArrival);
2706
2707 hgcmObjDereference(pClient);
2708 }
2709
2710 LogFlowFunc(("rc = %Rrc\n", rc));
2711 return rc;
2712}
2713
2714/** The guest cancelled a request (call, connect, disconnect)
2715 *
2716 * @param pHGCMPort The port to be used for completion confirmation.
2717 * @param pCmd The VBox HGCM context.
2718 * @param idClient The client handle.
2719 */
2720void HGCMGuestCancelled(PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t idClient)
2721{
2722 LogFlowFunc(("pHGCMPort = %p, pCmd = %p, idClient = %d\n", pHGCMPort, pCmd, idClient));
2723 AssertReturnVoid(pHGCMPort);
2724 AssertReturnVoid(pCmd);
2725 AssertReturnVoid(idClient != 0);
2726
2727 /* Resolve the client handle to the client instance pointer. */
2728 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(idClient, HGCMOBJ_CLIENT);
2729
2730 if (pClient)
2731 {
2732 AssertRelease(pClient->pService);
2733
2734 /* Forward the message to the service thread. */
2735 pClient->pService->GuestCancelled(pHGCMPort, pCmd, idClient);
2736
2737 hgcmObjDereference(pClient);
2738 }
2739
2740 LogFlowFunc(("returns\n"));
2741}
2742
2743/** The host calls the service.
2744 *
2745 * @param pszServiceName The service name to be called.
2746 * @param u32Function The function number.
2747 * @param cParms Number of parameters.
2748 * @param paParms Pointer to array of parameters.
2749 * @return VBox rc.
2750 */
2751int HGCMHostCall(const char *pszServiceName,
2752 uint32_t u32Function,
2753 uint32_t cParms,
2754 VBOXHGCMSVCPARM *paParms)
2755{
2756 LogFlowFunc(("name = %s, u32Function = %d, cParms = %d, paParms = %p\n",
2757 pszServiceName, u32Function, cParms, paParms));
2758
2759 if (!pszServiceName)
2760 {
2761 return VERR_INVALID_PARAMETER;
2762 }
2763
2764 /* Host calls go to main HGCM thread that resolves the service name to the
2765 * service instance pointer and then, using the service pointer, forwards
2766 * the message to the service thread.
2767 * So it is slow but host calls are intended mostly for configuration and
2768 * other non-time-critical functions.
2769 */
2770 HGCMMsgCore *pCoreMsg;
2771 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_HOSTCALL, hgcmMainMessageAlloc);
2772
2773 if (RT_SUCCESS(rc))
2774 {
2775 HGCMMsgMainHostCall *pMsg = (HGCMMsgMainHostCall *)pCoreMsg;
2776
2777 pMsg->pszServiceName = (char *)pszServiceName;
2778 pMsg->u32Function = u32Function;
2779 pMsg->cParms = cParms;
2780 pMsg->paParms = paParms;
2781
2782 rc = hgcmMsgSend(pMsg);
2783 }
2784
2785 LogFlowFunc(("rc = %Rrc\n", rc));
2786 return rc;
2787}
2788
2789/** Posts a notification event to all services.
2790 *
2791 * @param enmEvent The notification event.
2792 * @return VBox rc.
2793 */
2794int HGCMBroadcastEvent(HGCMNOTIFYEVENT enmEvent)
2795{
2796 LogFlowFunc(("enmEvent=%d\n", enmEvent));
2797
2798 HGCMMsgCore *pCoreMsg;
2799 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_BRD_NOTIFY, hgcmMainMessageAlloc);
2800
2801 if (RT_SUCCESS(rc))
2802 {
2803 HGCMMsgMainBroadcastNotify *pMsg = (HGCMMsgMainBroadcastNotify *)pCoreMsg;
2804
2805 pMsg->enmEvent = enmEvent;
2806
2807 rc = hgcmMsgPost(pMsg, NULL);
2808 }
2809
2810 LogFlowFunc(("rc = %Rrc\n", rc));
2811 return rc;
2812}
2813
2814
2815#ifdef VBOX_WITH_CRHGSMI
2816int HGCMHostSvcHandleCreate(const char *pszServiceName, HGCMCVSHANDLE * phSvc)
2817{
2818 LogFlowFunc(("name = %s\n", pszServiceName));
2819
2820 if (!pszServiceName)
2821 {
2822 return VERR_INVALID_PARAMETER;
2823 }
2824
2825 if (!phSvc)
2826 {
2827 return VERR_INVALID_PARAMETER;
2828 }
2829
2830 /* Host calls go to main HGCM thread that resolves the service name to the
2831 * service instance pointer and then, using the service pointer, forwards
2832 * the message to the service thread.
2833 * So it is slow but host calls are intended mostly for configuration and
2834 * other non-time-critical functions.
2835 */
2836 HGCMMsgCore *pCoreMsg;
2837 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_SVCAQUIRE, hgcmMainMessageAlloc);
2838
2839 if (RT_SUCCESS(rc))
2840 {
2841 HGCMMsgMainSvcAcquire *pMsg = (HGCMMsgMainSvcAcquire *)pCoreMsg;
2842
2843 pMsg->pszServiceName = (char *)pszServiceName;
2844 pMsg->pService = NULL;
2845
2846 pMsg->Reference();
2847
2848 rc = hgcmMsgSend(pMsg);
2849 if (RT_SUCCESS(rc))
2850 {
2851 /* for simplicity just use a svc ptr as handle for now */
2852 *phSvc = (HGCMCVSHANDLE)pMsg->pService;
2853 }
2854 pMsg->Dereference();
2855 }
2856
2857 LogFlowFunc(("rc = %Rrc\n", rc));
2858 return rc;
2859}
2860
2861int HGCMHostSvcHandleDestroy(HGCMCVSHANDLE hSvc)
2862{
2863 LogFlowFunc(("hSvc = %p\n", hSvc));
2864
2865 if (!hSvc)
2866 {
2867 return VERR_INVALID_PARAMETER;
2868 }
2869
2870 /* Host calls go to main HGCM thread that resolves the service name to the
2871 * service instance pointer and then, using the service pointer, forwards
2872 * the message to the service thread.
2873 * So it is slow but host calls are intended mostly for configuration and
2874 * other non-time-critical functions.
2875 */
2876 HGCMMsgCore *pCoreMsg;
2877 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_SVCRELEASE, hgcmMainMessageAlloc);
2878
2879 if (RT_SUCCESS(rc))
2880 {
2881 HGCMMsgMainSvcRelease *pMsg = (HGCMMsgMainSvcRelease *)pCoreMsg;
2882
2883 pMsg->pService = (HGCMService *)hSvc;
2884
2885 rc = hgcmMsgSend(pMsg);
2886 }
2887
2888 LogFlowFunc(("rc = %Rrc\n", rc));
2889 return rc;
2890}
2891
2892int HGCMHostFastCallAsync(HGCMCVSHANDLE hSvc, uint32_t function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion,
2893 void *pvCompletion)
2894{
2895 LogFlowFunc(("hSvc = %p, u32Function = %d, pParm = %p\n",
2896 hSvc, function, pParm));
2897
2898 if (!hSvc)
2899 {
2900 return VERR_INVALID_PARAMETER;
2901 }
2902
2903 HGCMService *pService = (HGCMService *)hSvc;
2904 int rc = pService->HostFastCallAsync(function, pParm, pfnCompletion, pvCompletion);
2905
2906 LogFlowFunc(("rc = %Rrc\n", rc));
2907 return rc;
2908}
2909#endif
2910
2911int HGCMHostReset(void)
2912{
2913 LogFlowFunc(("\n"));
2914
2915 /* Disconnect all clients.
2916 */
2917
2918 HGCMMsgCore *pMsg;
2919 int rc = hgcmMsgAlloc(g_pHgcmThread, &pMsg, HGCM_MSG_RESET, hgcmMainMessageAlloc);
2920
2921 if (RT_SUCCESS(rc))
2922 rc = hgcmMsgSend(pMsg);
2923
2924 LogFlowFunc(("rc = %Rrc\n", rc));
2925 return rc;
2926}
2927
2928int HGCMHostInit(void)
2929{
2930 LogFlowFunc(("\n"));
2931
2932 int rc = hgcmThreadInit();
2933
2934 if (RT_SUCCESS(rc))
2935 {
2936 /*
2937 * Start main HGCM thread.
2938 */
2939
2940 rc = hgcmThreadCreate(&g_pHgcmThread, "MainHGCMthread", hgcmThread, NULL /*pvUser*/, NULL /*pszStatsSubDir*/, NULL /*pUVM*/);
2941
2942 if (RT_FAILURE(rc))
2943 LogRel(("Failed to start HGCM thread. HGCM services will be unavailable!!! rc = %Rrc\n", rc));
2944 }
2945
2946 LogFlowFunc(("rc = %Rrc\n", rc));
2947 return rc;
2948}
2949
2950int HGCMHostShutdown(bool fUvmIsInvalid /*= false*/)
2951{
2952 LogFlowFunc(("\n"));
2953
2954 /*
2955 * Do HGCMReset and then unload all services.
2956 */
2957
2958 int rc = HGCMHostReset();
2959
2960 if (RT_SUCCESS(rc))
2961 {
2962 /* Send the quit message to the main hgcmThread. */
2963 HGCMMsgCore *pMsgCore;
2964 rc = hgcmMsgAlloc(g_pHgcmThread, &pMsgCore, HGCM_MSG_QUIT, hgcmMainMessageAlloc);
2965
2966 if (RT_SUCCESS(rc))
2967 {
2968 HGCMMsgMainQuit *pMsg = (HGCMMsgMainQuit *)pMsgCore;
2969 pMsg->fUvmIsInvalid = fUvmIsInvalid;
2970
2971 rc = hgcmMsgSend(pMsg);
2972
2973 if (RT_SUCCESS(rc))
2974 {
2975 /* Wait for the thread termination. */
2976 hgcmThreadWait(g_pHgcmThread);
2977 g_pHgcmThread = NULL;
2978
2979 hgcmThreadUninit();
2980 }
2981 }
2982 }
2983
2984 LogFlowFunc(("rc = %Rrc\n", rc));
2985 return rc;
2986}
2987
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