VirtualBox

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

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

doxygen fix

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