VirtualBox

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

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

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 89.9 KB
Line 
1/* $Id: HGCM.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * HGCM (Host-Guest Communication Manager)
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#define LOG_GROUP LOG_GROUP_HGCM
19#include "LoggingNew.h"
20
21#include "HGCM.h"
22#include "HGCMThread.h"
23
24#include <VBox/err.h>
25#include <VBox/hgcmsvc.h>
26#include <VBox/vmm/ssm.h>
27#include <VBox/vmm/stam.h>
28#include <VBox/sup.h>
29
30#include <iprt/alloc.h>
31#include <iprt/avl.h>
32#include <iprt/critsect.h>
33#include <iprt/asm.h>
34#include <iprt/ldr.h>
35#include <iprt/param.h>
36#include <iprt/path.h>
37#include <iprt/string.h>
38#include <iprt/semaphore.h>
39#include <iprt/thread.h>
40
41#include <VBox/VMMDev.h>
42#include <new>
43
44/**
45 * A service gets one thread, which synchronously delivers messages to
46 * the service. This is good for serialization.
47 *
48 * Some services may want to process messages asynchronously, and will want
49 * a next message to be delivered, while a previous message is still being
50 * processed.
51 *
52 * The dedicated service thread delivers a next message when service
53 * returns after fetching a previous one. The service will call a message
54 * completion callback when message is actually processed. So returning
55 * from the service call means only that the service is processing message.
56 *
57 * 'Message processed' condition is indicated by service, which call the
58 * callback, even if the callback is called synchronously in the dedicated
59 * thread.
60 *
61 * This message completion callback is only valid for Call requests.
62 * Connect and Disconnect are processed synchronously by the service.
63 */
64
65
66/* The maximum allowed size of a service name in bytes. */
67#define VBOX_HGCM_SVC_NAME_MAX_BYTES 1024
68
69struct _HGCMSVCEXTHANDLEDATA
70{
71 char *pszServiceName;
72 /* The service name follows. */
73};
74
75/** Internal helper service object. HGCM code would use it to
76 * hold information about services and communicate with services.
77 * The HGCMService is an (in future) abstract class that implements
78 * common functionality. There will be derived classes for specific
79 * service types.
80 */
81
82class HGCMService
83{
84 private:
85 VBOXHGCMSVCHELPERS m_svcHelpers;
86
87 static HGCMService *sm_pSvcListHead;
88 static HGCMService *sm_pSvcListTail;
89
90 static int sm_cServices;
91
92 HGCMThread *m_pThread;
93 friend DECLCALLBACK(void) hgcmServiceThread(HGCMThread *pThread, void *pvUser);
94
95 uint32_t volatile m_u32RefCnt;
96
97 HGCMService *m_pSvcNext;
98 HGCMService *m_pSvcPrev;
99
100 char *m_pszSvcName;
101 char *m_pszSvcLibrary;
102
103 RTLDRMOD m_hLdrMod;
104 PFNVBOXHGCMSVCLOAD m_pfnLoad;
105
106 VBOXHGCMSVCFNTABLE m_fntable;
107
108 uint32_t m_cClients;
109 uint32_t m_cClientsAllocated;
110
111 uint32_t *m_paClientIds;
112
113#ifdef VBOX_WITH_CRHGSMI
114 uint32_t m_cHandleAcquires;
115#endif
116
117 HGCMSVCEXTHANDLE m_hExtension;
118
119 PUVM m_pUVM;
120 PPDMIHGCMPORT m_pHgcmPort;
121
122 /** @name Statistics
123 * @{ */
124 STAMPROFILE m_StatHandleMsg;
125 /** @} */
126
127 int loadServiceDLL(void);
128 void unloadServiceDLL(void);
129
130 /*
131 * Main HGCM thread methods.
132 */
133 int instanceCreate(const char *pszServiceLibrary, const char *pszServiceName, PUVM pUVM, PPDMIHGCMPORT pHgcmPort);
134 void instanceDestroy(void);
135
136 int saveClientState(uint32_t u32ClientId, PSSMHANDLE pSSM);
137 int loadClientState(uint32_t u32ClientId, PSSMHANDLE pSSM, uint32_t uVersion);
138
139 HGCMService();
140 ~HGCMService() {};
141
142 static DECLCALLBACK(int) svcHlpCallComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc);
143 static DECLCALLBACK(void) svcHlpDisconnectClient(void *pvInstance, uint32_t u32ClientId);
144 static DECLCALLBACK(bool) svcHlpIsCallRestored(VBOXHGCMCALLHANDLE callHandle);
145 static DECLCALLBACK(bool) svcHlpIsCallCancelled(VBOXHGCMCALLHANDLE callHandle);
146 static DECLCALLBACK(int) svcHlpStamRegisterV(void *pvInstance, void *pvSample, STAMTYPE enmType,
147 STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, const char *pszDesc,
148 const char *pszName, va_list va);
149 static DECLCALLBACK(int) svcHlpStamDeregisterV(void *pvInstance, const char *pszPatFmt, va_list va);
150 static DECLCALLBACK(int) svcHlpInfoRegister(void *pvInstance, const char *pszName, const char *pszDesc,
151 PFNDBGFHANDLEREXT pfnHandler, void *pvUser);
152 static DECLCALLBACK(int) svcHlpInfoDeregister(void *pvInstance, const char *pszName);
153 static DECLCALLBACK(uint32_t) svcHlpGetRequestor(VBOXHGCMCALLHANDLE hCall);
154 static DECLCALLBACK(uint64_t) svcHlpGetVMMDevSessionId(void *pvInstance);
155
156 public:
157
158 /*
159 * Main HGCM thread methods.
160 */
161 static int LoadService(const char *pszServiceLibrary, const char *pszServiceName, PUVM pUVM, PPDMIHGCMPORT pHgcmPort);
162 void UnloadService(bool fUvmIsInvalid);
163
164 static void UnloadAll(bool fUvmIsInvalid);
165
166 static int ResolveService(HGCMService **ppsvc, const char *pszServiceName);
167 void ReferenceService(void);
168 void ReleaseService(void);
169
170 static void Reset(void);
171
172 static int SaveState(PSSMHANDLE pSSM);
173 static int LoadState(PSSMHANDLE pSSM, uint32_t uVersion);
174
175 int CreateAndConnectClient(uint32_t *pu32ClientIdOut, uint32_t u32ClientIdIn, uint32_t fRequestor, bool fRestoring);
176 int DisconnectClient(uint32_t u32ClientId, bool fFromService);
177
178 int HostCall(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM *paParms);
179 static void BroadcastNotify(HGCMNOTIFYEVENT enmEvent);
180 void Notify(HGCMNOTIFYEVENT enmEvent);
181
182#ifdef VBOX_WITH_CRHGSMI
183 int HandleAcquired();
184 int HandleReleased();
185 int HostFastCallAsync(uint32_t u32Function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion,
186 void *pvCompletion);
187#endif
188
189 uint32_t SizeOfClient(void) { return m_fntable.cbClient; };
190
191 int RegisterExtension(HGCMSVCEXTHANDLE handle, PFNHGCMSVCEXT pfnExtension, void *pvExtension);
192 void UnregisterExtension(HGCMSVCEXTHANDLE handle);
193
194 /*
195 * The service thread methods.
196 */
197
198 int GuestCall(PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId,
199 uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM aParms[], uint64_t tsArrival);
200 void GuestCancelled(PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t idClient);
201};
202
203
204class HGCMClient: public HGCMObject
205{
206 public:
207 HGCMClient(uint32_t a_fRequestor)
208 : HGCMObject(HGCMOBJ_CLIENT)
209 , pService(NULL)
210 , pvData(NULL)
211 , fRequestor(a_fRequestor)
212 {}
213 ~HGCMClient();
214
215 int Init(HGCMService *pSvc);
216
217 /** Service that the client is connected to. */
218 HGCMService *pService;
219
220 /** Client specific data. */
221 void *pvData;
222
223 /** The requestor flags this client was created with.
224 * @sa VMMDevRequestHeader::fRequestor */
225 uint32_t fRequestor;
226
227 private: /* none of this: */
228 HGCMClient();
229 HGCMClient(HGCMClient const &);
230 HGCMClient &operator=(HGCMClient const &);
231};
232
233HGCMClient::~HGCMClient()
234{
235 if (pService->SizeOfClient() > 0)
236 {
237 RTMemFree(pvData);
238 pvData = NULL;
239 }
240}
241
242
243int HGCMClient::Init(HGCMService *pSvc)
244{
245 pService = pSvc;
246
247 if (pService->SizeOfClient() > 0)
248 {
249 pvData = RTMemAllocZ(pService->SizeOfClient());
250
251 if (!pvData)
252 {
253 return VERR_NO_MEMORY;
254 }
255 }
256
257 return VINF_SUCCESS;
258}
259
260
261#define HGCM_CLIENT_DATA(pService, pClient)(pClient->pvData)
262
263
264
265HGCMService *HGCMService::sm_pSvcListHead = NULL;
266HGCMService *HGCMService::sm_pSvcListTail = NULL;
267int HGCMService::sm_cServices = 0;
268
269HGCMService::HGCMService()
270 :
271 m_pThread (NULL),
272 m_u32RefCnt (0),
273 m_pSvcNext (NULL),
274 m_pSvcPrev (NULL),
275 m_pszSvcName (NULL),
276 m_pszSvcLibrary (NULL),
277 m_hLdrMod (NIL_RTLDRMOD),
278 m_pfnLoad (NULL),
279 m_cClients (0),
280 m_cClientsAllocated (0),
281 m_paClientIds (NULL),
282#ifdef VBOX_WITH_CRHGSMI
283 m_cHandleAcquires (0),
284#endif
285 m_hExtension (NULL),
286 m_pUVM (NULL),
287 m_pHgcmPort (NULL)
288{
289 RT_ZERO(m_fntable);
290}
291
292
293static bool g_fResetting = false;
294static bool g_fSaveState = false;
295
296
297/** Helper function to load a local service DLL.
298 *
299 * @return VBox code
300 */
301int HGCMService::loadServiceDLL(void)
302{
303 LogFlowFunc(("m_pszSvcLibrary = %s\n", m_pszSvcLibrary));
304
305 if (m_pszSvcLibrary == NULL)
306 {
307 return VERR_INVALID_PARAMETER;
308 }
309
310 RTERRINFOSTATIC ErrInfo;
311 RTErrInfoInitStatic(&ErrInfo);
312
313 int rc;
314
315 if (RTPathHasPath(m_pszSvcLibrary))
316 rc = SUPR3HardenedLdrLoadPlugIn(m_pszSvcLibrary, &m_hLdrMod, &ErrInfo.Core);
317 else
318 rc = SUPR3HardenedLdrLoadAppPriv(m_pszSvcLibrary, &m_hLdrMod, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core);
319
320 if (RT_SUCCESS(rc))
321 {
322 LogFlowFunc(("successfully loaded the library.\n"));
323
324 m_pfnLoad = NULL;
325
326 rc = RTLdrGetSymbol(m_hLdrMod, VBOX_HGCM_SVCLOAD_NAME, (void**)&m_pfnLoad);
327
328 if (RT_FAILURE(rc) || !m_pfnLoad)
329 {
330 Log(("HGCMService::loadServiceDLL: Error resolving the service entry point %s, rc = %d, m_pfnLoad = %p\n",
331 VBOX_HGCM_SVCLOAD_NAME, rc, m_pfnLoad));
332
333 if (RT_SUCCESS(rc))
334 {
335 /* m_pfnLoad was NULL */
336 rc = VERR_SYMBOL_NOT_FOUND;
337 }
338 }
339
340 if (RT_SUCCESS(rc))
341 {
342 RT_ZERO(m_fntable);
343
344 m_fntable.cbSize = sizeof(m_fntable);
345 m_fntable.u32Version = VBOX_HGCM_SVC_VERSION;
346 m_fntable.pHelpers = &m_svcHelpers;
347
348 rc = m_pfnLoad(&m_fntable);
349
350 LogFlowFunc(("m_pfnLoad rc = %Rrc\n", rc));
351
352 if (RT_SUCCESS(rc))
353 {
354 if ( m_fntable.pfnUnload == NULL
355 || m_fntable.pfnConnect == NULL
356 || m_fntable.pfnDisconnect == NULL
357 || m_fntable.pfnCall == NULL
358 )
359 {
360 Log(("HGCMService::loadServiceDLL: at least one of function pointers is NULL\n"));
361
362 rc = VERR_INVALID_PARAMETER;
363
364 if (m_fntable.pfnUnload)
365 {
366 m_fntable.pfnUnload(m_fntable.pvService);
367 }
368 }
369 }
370 }
371 }
372 else
373 {
374 LogRel(("HGCM: Failed to load the service library: [%s], rc = %Rrc - %s. The service will be not available.\n",
375 m_pszSvcLibrary, rc, ErrInfo.Core.pszMsg));
376 m_hLdrMod = NIL_RTLDRMOD;
377 }
378
379 if (RT_FAILURE(rc))
380 {
381 unloadServiceDLL();
382 }
383
384 return rc;
385}
386
387/** Helper function to free a local service DLL.
388 *
389 * @return VBox code
390 */
391void HGCMService::unloadServiceDLL(void)
392{
393 if (m_hLdrMod)
394 {
395 RTLdrClose(m_hLdrMod);
396 }
397
398 RT_ZERO(m_fntable);
399 m_pfnLoad = NULL;
400 m_hLdrMod = NIL_RTLDRMOD;
401}
402
403/*
404 * Messages processed by service threads. These threads only call the service entry points.
405 */
406
407#define SVC_MSG_LOAD (0) /**< Load the service library and call VBOX_HGCM_SVCLOAD_NAME entry point. */
408#define SVC_MSG_UNLOAD (1) /**< call pfnUnload and unload the service library. */
409#define SVC_MSG_CONNECT (2) /**< pfnConnect */
410#define SVC_MSG_DISCONNECT (3) /**< pfnDisconnect */
411#define SVC_MSG_GUESTCALL (4) /**< pfnGuestCall */
412#define SVC_MSG_HOSTCALL (5) /**< pfnHostCall */
413#define SVC_MSG_LOADSTATE (6) /**< pfnLoadState. */
414#define SVC_MSG_SAVESTATE (7) /**< pfnSaveState. */
415#define SVC_MSG_QUIT (8) /**< Terminate the thread. */
416#define SVC_MSG_REGEXT (9) /**< pfnRegisterExtension */
417#define SVC_MSG_UNREGEXT (10) /**< pfnRegisterExtension */
418#define SVC_MSG_NOTIFY (11) /**< pfnNotify */
419#define SVC_MSG_GUESTCANCELLED (12) /**< pfnCancelled */
420#ifdef VBOX_WITH_CRHGSMI
421# define SVC_MSG_HOSTFASTCALLASYNC (21) /* pfnHostCall */
422#endif
423
424class HGCMMsgSvcLoad: public HGCMMsgCore
425{
426 public:
427 HGCMMsgSvcLoad() : HGCMMsgCore(), pUVM() {}
428
429 /** The user mode VM handle (for statistics and such). */
430 PUVM pUVM;
431};
432
433class HGCMMsgSvcUnload: public HGCMMsgCore
434{
435};
436
437class HGCMMsgSvcConnect: public HGCMMsgCore
438{
439 public:
440 /** client identifier */
441 uint32_t u32ClientId;
442 /** Requestor flags. */
443 uint32_t fRequestor;
444 /** Set if restoring. */
445 bool fRestoring;
446};
447
448class HGCMMsgSvcDisconnect: public HGCMMsgCore
449{
450 public:
451 /* client identifier */
452 uint32_t u32ClientId;
453};
454
455class HGCMMsgHeader: public HGCMMsgCore
456{
457 public:
458 HGCMMsgHeader() : pCmd(NULL), pHGCMPort(NULL) {};
459
460 /* Command pointer/identifier. */
461 PVBOXHGCMCMD pCmd;
462
463 /* Port to be informed on message completion. */
464 PPDMIHGCMPORT pHGCMPort;
465};
466
467class HGCMMsgCall: public HGCMMsgHeader
468{
469 public:
470 HGCMMsgCall() {}
471
472 HGCMMsgCall(HGCMThread *pThread)
473 {
474 InitializeCore(SVC_MSG_GUESTCALL, pThread);
475 Initialize();
476 }
477 ~HGCMMsgCall() { Log(("~HGCMMsgCall %p\n", this)); }
478
479 /* client identifier */
480 uint32_t u32ClientId;
481
482 /* function number */
483 uint32_t u32Function;
484
485 /* number of parameters */
486 uint32_t cParms;
487
488 VBOXHGCMSVCPARM *paParms;
489
490 /** The STAM_GET_TS() value when the request arrived. */
491 uint64_t tsArrival;
492};
493
494class HGCMMsgCancelled: public HGCMMsgHeader
495{
496 public:
497 HGCMMsgCancelled() {}
498
499 HGCMMsgCancelled(HGCMThread *pThread)
500 {
501 InitializeCore(SVC_MSG_GUESTCANCELLED, pThread);
502 Initialize();
503 }
504 ~HGCMMsgCancelled() { Log(("~HGCMMsgCancelled %p\n", this)); }
505
506 /** The client identifier. */
507 uint32_t idClient;
508};
509
510class HGCMMsgLoadSaveStateClient: public HGCMMsgCore
511{
512 public:
513 PSSMHANDLE pSSM;
514 uint32_t uVersion;
515 uint32_t u32ClientId;
516};
517
518class HGCMMsgHostCallSvc: public HGCMMsgCore
519{
520 public:
521 /* function number */
522 uint32_t u32Function;
523
524 /* number of parameters */
525 uint32_t cParms;
526
527 VBOXHGCMSVCPARM *paParms;
528};
529
530class HGCMMsgSvcRegisterExtension: public HGCMMsgCore
531{
532 public:
533 /* Handle of the extension to be registered. */
534 HGCMSVCEXTHANDLE handle;
535 /* The extension entry point. */
536 PFNHGCMSVCEXT pfnExtension;
537 /* The extension pointer. */
538 void *pvExtension;
539};
540
541class HGCMMsgSvcUnregisterExtension: public HGCMMsgCore
542{
543 public:
544 /* Handle of the registered extension. */
545 HGCMSVCEXTHANDLE handle;
546};
547
548class HGCMMsgNotify: public HGCMMsgCore
549{
550 public:
551 /** The event. */
552 HGCMNOTIFYEVENT enmEvent;
553};
554
555#ifdef VBOX_WITH_CRHGSMI
556class HGCMMsgHostFastCallAsyncSvc: public HGCMMsgCore
557{
558 public:
559 /* function number */
560 uint32_t u32Function;
561 /* parameter */
562 VBOXHGCMSVCPARM Param;
563 /* completion info */
564 PHGCMHOSTFASTCALLCB pfnCompletion;
565 void *pvCompletion;
566};
567#endif
568
569static HGCMMsgCore *hgcmMessageAllocSvc(uint32_t u32MsgId)
570{
571 switch (u32MsgId)
572 {
573#ifdef VBOX_WITH_CRHGSMI
574 case SVC_MSG_HOSTFASTCALLASYNC: return new HGCMMsgHostFastCallAsyncSvc();
575#endif
576 case SVC_MSG_LOAD: return new HGCMMsgSvcLoad();
577 case SVC_MSG_UNLOAD: return new HGCMMsgSvcUnload();
578 case SVC_MSG_CONNECT: return new HGCMMsgSvcConnect();
579 case SVC_MSG_DISCONNECT: return new HGCMMsgSvcDisconnect();
580 case SVC_MSG_HOSTCALL: return new HGCMMsgHostCallSvc();
581 case SVC_MSG_GUESTCALL: return new HGCMMsgCall();
582 case SVC_MSG_LOADSTATE:
583 case SVC_MSG_SAVESTATE: return new HGCMMsgLoadSaveStateClient();
584 case SVC_MSG_REGEXT: return new HGCMMsgSvcRegisterExtension();
585 case SVC_MSG_UNREGEXT: return new HGCMMsgSvcUnregisterExtension();
586 case SVC_MSG_NOTIFY: return new HGCMMsgNotify();
587 case SVC_MSG_GUESTCANCELLED: return new HGCMMsgCancelled();
588 default:
589 AssertReleaseMsgFailed(("Msg id = %08X\n", u32MsgId));
590 }
591
592 return NULL;
593}
594
595/*
596 * The service thread. Loads the service library and calls the service entry points.
597 */
598DECLCALLBACK(void) hgcmServiceThread(HGCMThread *pThread, void *pvUser)
599{
600 HGCMService *pSvc = (HGCMService *)pvUser;
601 AssertRelease(pSvc != NULL);
602
603 bool fQuit = false;
604
605 while (!fQuit)
606 {
607 HGCMMsgCore *pMsgCore;
608 int rc = hgcmMsgGet(pThread, &pMsgCore);
609
610 if (RT_FAILURE(rc))
611 {
612 /* The error means some serious unrecoverable problem in the hgcmMsg/hgcmThread layer. */
613 AssertMsgFailed(("%Rrc\n", rc));
614 break;
615 }
616
617 STAM_REL_PROFILE_START(&pSvc->m_StatHandleMsg, a);
618
619 /* Cache required information to avoid unnecessary pMsgCore access. */
620 uint32_t u32MsgId = pMsgCore->MsgId();
621
622 switch (u32MsgId)
623 {
624#ifdef VBOX_WITH_CRHGSMI
625 case SVC_MSG_HOSTFASTCALLASYNC:
626 {
627 HGCMMsgHostFastCallAsyncSvc *pMsg = (HGCMMsgHostFastCallAsyncSvc *)pMsgCore;
628
629 LogFlowFunc(("SVC_MSG_HOSTFASTCALLASYNC u32Function = %d, pParm = %p\n", pMsg->u32Function, &pMsg->Param));
630
631 rc = pSvc->m_fntable.pfnHostCall(pSvc->m_fntable.pvService, pMsg->u32Function, 1, &pMsg->Param);
632 } break;
633#endif
634 case SVC_MSG_LOAD:
635 {
636 LogFlowFunc(("SVC_MSG_LOAD\n"));
637 rc = pSvc->loadServiceDLL();
638 } break;
639
640 case SVC_MSG_UNLOAD:
641 {
642 LogFlowFunc(("SVC_MSG_UNLOAD\n"));
643 if (pSvc->m_fntable.pfnUnload)
644 {
645 pSvc->m_fntable.pfnUnload(pSvc->m_fntable.pvService);
646 }
647
648 pSvc->unloadServiceDLL();
649 fQuit = true;
650 } break;
651
652 case SVC_MSG_CONNECT:
653 {
654 HGCMMsgSvcConnect *pMsg = (HGCMMsgSvcConnect *)pMsgCore;
655
656 LogFlowFunc(("SVC_MSG_CONNECT u32ClientId = %d\n", pMsg->u32ClientId));
657
658 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(pMsg->u32ClientId, HGCMOBJ_CLIENT);
659
660 if (pClient)
661 {
662 rc = pSvc->m_fntable.pfnConnect(pSvc->m_fntable.pvService, pMsg->u32ClientId,
663 HGCM_CLIENT_DATA(pSvc, pClient),
664 pMsg->fRequestor, pMsg->fRestoring);
665
666 hgcmObjDereference(pClient);
667 }
668 else
669 {
670 rc = VERR_HGCM_INVALID_CLIENT_ID;
671 }
672 } break;
673
674 case SVC_MSG_DISCONNECT:
675 {
676 HGCMMsgSvcDisconnect *pMsg = (HGCMMsgSvcDisconnect *)pMsgCore;
677
678 LogFlowFunc(("SVC_MSG_DISCONNECT u32ClientId = %d\n", pMsg->u32ClientId));
679
680 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(pMsg->u32ClientId, HGCMOBJ_CLIENT);
681
682 if (pClient)
683 {
684 rc = pSvc->m_fntable.pfnDisconnect(pSvc->m_fntable.pvService, pMsg->u32ClientId,
685 HGCM_CLIENT_DATA(pSvc, pClient));
686
687 hgcmObjDereference(pClient);
688 }
689 else
690 {
691 rc = VERR_HGCM_INVALID_CLIENT_ID;
692 }
693 } break;
694
695 case SVC_MSG_GUESTCALL:
696 {
697 HGCMMsgCall *pMsg = (HGCMMsgCall *)pMsgCore;
698
699 LogFlowFunc(("SVC_MSG_GUESTCALL u32ClientId = %d, u32Function = %d, cParms = %d, paParms = %p\n",
700 pMsg->u32ClientId, pMsg->u32Function, pMsg->cParms, pMsg->paParms));
701
702 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(pMsg->u32ClientId, HGCMOBJ_CLIENT);
703
704 if (pClient)
705 {
706 pSvc->m_fntable.pfnCall(pSvc->m_fntable.pvService, (VBOXHGCMCALLHANDLE)pMsg, pMsg->u32ClientId,
707 HGCM_CLIENT_DATA(pSvc, pClient), pMsg->u32Function,
708 pMsg->cParms, pMsg->paParms, pMsg->tsArrival);
709
710 hgcmObjDereference(pClient);
711 }
712 else
713 {
714 rc = VERR_HGCM_INVALID_CLIENT_ID;
715 }
716 } break;
717
718 case SVC_MSG_GUESTCANCELLED:
719 {
720 HGCMMsgCancelled *pMsg = (HGCMMsgCancelled *)pMsgCore;
721
722 LogFlowFunc(("SVC_MSG_GUESTCANCELLED idClient = %d\n", pMsg->idClient));
723
724 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(pMsg->idClient, HGCMOBJ_CLIENT);
725
726 if (pClient)
727 {
728 pSvc->m_fntable.pfnCancelled(pSvc->m_fntable.pvService, pMsg->idClient, HGCM_CLIENT_DATA(pSvc, pClient));
729
730 hgcmObjDereference(pClient);
731 }
732 else
733 {
734 rc = VERR_HGCM_INVALID_CLIENT_ID;
735 }
736 } break;
737
738 case SVC_MSG_HOSTCALL:
739 {
740 HGCMMsgHostCallSvc *pMsg = (HGCMMsgHostCallSvc *)pMsgCore;
741
742 LogFlowFunc(("SVC_MSG_HOSTCALL u32Function = %d, cParms = %d, paParms = %p\n",
743 pMsg->u32Function, pMsg->cParms, pMsg->paParms));
744
745 rc = pSvc->m_fntable.pfnHostCall(pSvc->m_fntable.pvService, pMsg->u32Function, pMsg->cParms, pMsg->paParms);
746 } break;
747
748 case SVC_MSG_LOADSTATE:
749 {
750 HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)pMsgCore;
751
752 LogFlowFunc(("SVC_MSG_LOADSTATE\n"));
753
754 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(pMsg->u32ClientId, HGCMOBJ_CLIENT);
755
756 if (pClient)
757 {
758 /* fRequestor: Restored by the message sender already. */
759 bool fHaveClientState = pSvc->m_fntable.pfnLoadState != NULL;
760 if (pMsg->uVersion > HGCM_SAVED_STATE_VERSION_V2)
761 rc = SSMR3GetBool(pMsg->pSSM, &fHaveClientState);
762 else
763 rc = VINF_SUCCESS;
764 if (RT_SUCCESS(rc) )
765 {
766 if (pSvc->m_fntable.pfnLoadState)
767 rc = pSvc->m_fntable.pfnLoadState(pSvc->m_fntable.pvService, pMsg->u32ClientId,
768 HGCM_CLIENT_DATA(pSvc, pClient), pMsg->pSSM,
769 fHaveClientState ? pMsg->uVersion : 0);
770 else
771 AssertLogRelStmt(!fHaveClientState, rc = VERR_INTERNAL_ERROR_5);
772 }
773 hgcmObjDereference(pClient);
774 }
775 else
776 {
777 rc = VERR_HGCM_INVALID_CLIENT_ID;
778 }
779 } break;
780
781 case SVC_MSG_SAVESTATE:
782 {
783 HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)pMsgCore;
784
785 LogFlowFunc(("SVC_MSG_SAVESTATE\n"));
786
787 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(pMsg->u32ClientId, HGCMOBJ_CLIENT);
788
789 rc = VINF_SUCCESS;
790
791 if (pClient)
792 {
793 SSMR3PutU32(pMsg->pSSM, pClient->fRequestor); /* Quicker to save this here than in the message sender. */
794 rc = SSMR3PutBool(pMsg->pSSM, pSvc->m_fntable.pfnSaveState != NULL);
795 if (RT_SUCCESS(rc) && pSvc->m_fntable.pfnSaveState)
796 {
797 g_fSaveState = true;
798 rc = pSvc->m_fntable.pfnSaveState(pSvc->m_fntable.pvService, pMsg->u32ClientId,
799 HGCM_CLIENT_DATA(pSvc, pClient), pMsg->pSSM);
800 g_fSaveState = false;
801 }
802
803 hgcmObjDereference(pClient);
804 }
805 else
806 {
807 rc = VERR_HGCM_INVALID_CLIENT_ID;
808 }
809 } break;
810
811 case SVC_MSG_REGEXT:
812 {
813 HGCMMsgSvcRegisterExtension *pMsg = (HGCMMsgSvcRegisterExtension *)pMsgCore;
814
815 LogFlowFunc(("SVC_MSG_REGEXT handle = %p, pfn = %p\n", pMsg->handle, pMsg->pfnExtension));
816
817 if (pSvc->m_hExtension)
818 {
819 rc = VERR_NOT_SUPPORTED;
820 }
821 else
822 {
823 if (pSvc->m_fntable.pfnRegisterExtension)
824 {
825 rc = pSvc->m_fntable.pfnRegisterExtension(pSvc->m_fntable.pvService, pMsg->pfnExtension,
826 pMsg->pvExtension);
827 }
828 else
829 {
830 rc = VERR_NOT_SUPPORTED;
831 }
832
833 if (RT_SUCCESS(rc))
834 {
835 pSvc->m_hExtension = pMsg->handle;
836 }
837 }
838 } break;
839
840 case SVC_MSG_UNREGEXT:
841 {
842 HGCMMsgSvcUnregisterExtension *pMsg = (HGCMMsgSvcUnregisterExtension *)pMsgCore;
843
844 LogFlowFunc(("SVC_MSG_UNREGEXT handle = %p\n", pMsg->handle));
845
846 if (pSvc->m_hExtension != pMsg->handle)
847 {
848 rc = VERR_NOT_SUPPORTED;
849 }
850 else
851 {
852 if (pSvc->m_fntable.pfnRegisterExtension)
853 {
854 rc = pSvc->m_fntable.pfnRegisterExtension(pSvc->m_fntable.pvService, NULL, NULL);
855 }
856 else
857 {
858 rc = VERR_NOT_SUPPORTED;
859 }
860
861 pSvc->m_hExtension = NULL;
862 }
863 } break;
864
865 case SVC_MSG_NOTIFY:
866 {
867 HGCMMsgNotify *pMsg = (HGCMMsgNotify *)pMsgCore;
868
869 LogFlowFunc(("SVC_MSG_NOTIFY enmEvent = %d\n", pMsg->enmEvent));
870
871 pSvc->m_fntable.pfnNotify(pSvc->m_fntable.pvService, pMsg->enmEvent);
872 } break;
873
874 default:
875 {
876 AssertMsgFailed(("hgcmServiceThread::Unsupported message number %08X\n", u32MsgId));
877 rc = VERR_NOT_SUPPORTED;
878 } break;
879 }
880
881 if (u32MsgId != SVC_MSG_GUESTCALL)
882 {
883 /* For SVC_MSG_GUESTCALL the service calls the completion helper.
884 * Other messages have to be completed here.
885 */
886 hgcmMsgComplete (pMsgCore, rc);
887 }
888 STAM_REL_PROFILE_STOP(&pSvc->m_StatHandleMsg, a);
889 }
890}
891
892/**
893 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnCallComplete}
894 */
895/* static */ DECLCALLBACK(int) HGCMService::svcHlpCallComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc)
896{
897 HGCMMsgCore *pMsgCore = (HGCMMsgCore *)callHandle;
898
899 /* Only call the completion for these messages. The helper
900 * is called by the service, and the service does not get
901 * any other messages.
902 */
903 AssertMsgReturn(pMsgCore->MsgId() == SVC_MSG_GUESTCALL, ("%d\n", pMsgCore->MsgId()), VERR_WRONG_TYPE);
904 return hgcmMsgComplete(pMsgCore, rc);
905}
906
907/**
908 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnDisconnectClient}
909 */
910/* static */ DECLCALLBACK(void) HGCMService::svcHlpDisconnectClient(void *pvInstance, uint32_t u32ClientId)
911{
912 HGCMService *pService = static_cast <HGCMService *> (pvInstance);
913
914 if (pService)
915 {
916 pService->DisconnectClient(u32ClientId, true);
917 }
918}
919
920/**
921 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnIsCallRestored}
922 */
923/* static */ DECLCALLBACK(bool) HGCMService::svcHlpIsCallRestored(VBOXHGCMCALLHANDLE callHandle)
924{
925 HGCMMsgHeader *pMsgHdr = (HGCMMsgHeader *)callHandle;
926 AssertPtrReturn(pMsgHdr, false);
927
928 PVBOXHGCMCMD pCmd = pMsgHdr->pCmd;
929 AssertPtrReturn(pCmd, false);
930
931 PPDMIHGCMPORT pHgcmPort = pMsgHdr->pHGCMPort;
932 AssertPtrReturn(pHgcmPort, false);
933
934 return pHgcmPort->pfnIsCmdRestored(pHgcmPort, pCmd);
935}
936
937/**
938 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnIsCallCancelled}
939 */
940/* static */ DECLCALLBACK(bool) HGCMService::svcHlpIsCallCancelled(VBOXHGCMCALLHANDLE callHandle)
941{
942 HGCMMsgHeader *pMsgHdr = (HGCMMsgHeader *)callHandle;
943 AssertPtrReturn(pMsgHdr, false);
944
945 PVBOXHGCMCMD pCmd = pMsgHdr->pCmd;
946 AssertPtrReturn(pCmd, false);
947
948 PPDMIHGCMPORT pHgcmPort = pMsgHdr->pHGCMPort;
949 AssertPtrReturn(pHgcmPort, false);
950
951 return pHgcmPort->pfnIsCmdCancelled(pHgcmPort, pCmd);
952}
953
954/**
955 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnStamRegisterV}
956 */
957/* static */ DECLCALLBACK(int)
958HGCMService::svcHlpStamRegisterV(void *pvInstance, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
959 STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list va)
960{
961 HGCMService *pService = static_cast <HGCMService *>(pvInstance);
962 AssertPtrReturn(pService, VERR_INVALID_PARAMETER);
963
964 return STAMR3RegisterVU(pService->m_pUVM, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, va);
965}
966
967/**
968 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnStamDeregisterV}
969 */
970/* static */ DECLCALLBACK(int) HGCMService::svcHlpStamDeregisterV(void *pvInstance, const char *pszPatFmt, va_list va)
971{
972 HGCMService *pService = static_cast <HGCMService *>(pvInstance);
973 AssertPtrReturn(pService, VERR_INVALID_PARAMETER);
974
975 if (pService->m_pUVM)
976 return STAMR3DeregisterV(pService->m_pUVM, pszPatFmt, va);
977 return VINF_SUCCESS;
978}
979
980/**
981 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnInfoRegister}
982 */
983/* static */ DECLCALLBACK(int) HGCMService::svcHlpInfoRegister(void *pvInstance, const char *pszName, const char *pszDesc,
984 PFNDBGFHANDLEREXT pfnHandler, void *pvUser)
985{
986 HGCMService *pService = static_cast <HGCMService *>(pvInstance);
987 AssertPtrReturn(pService, VERR_INVALID_PARAMETER);
988
989 return DBGFR3InfoRegisterExternal(pService->m_pUVM, pszName, pszDesc, pfnHandler, pvUser);
990}
991
992/**
993 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnInfoDeregister}
994 */
995/* static */ DECLCALLBACK(int) HGCMService::svcHlpInfoDeregister(void *pvInstance, const char *pszName)
996{
997 HGCMService *pService = static_cast <HGCMService *>(pvInstance);
998 AssertPtrReturn(pService, VERR_INVALID_PARAMETER);
999 if (pService->m_pUVM)
1000 return DBGFR3InfoDeregisterExternal(pService->m_pUVM, pszName);
1001 return VINF_SUCCESS;
1002}
1003
1004/**
1005 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnGetRequestor}
1006 */
1007/* static */ DECLCALLBACK(uint32_t) HGCMService::svcHlpGetRequestor(VBOXHGCMCALLHANDLE hCall)
1008{
1009 HGCMMsgHeader *pMsgHdr = (HGCMMsgHeader *)(hCall);
1010 AssertPtrReturn(pMsgHdr, VMMDEV_REQUESTOR_LOWEST);
1011
1012 PVBOXHGCMCMD pCmd = pMsgHdr->pCmd;
1013 AssertPtrReturn(pCmd, VMMDEV_REQUESTOR_LOWEST);
1014
1015 PPDMIHGCMPORT pHgcmPort = pMsgHdr->pHGCMPort;
1016 AssertPtrReturn(pHgcmPort, VMMDEV_REQUESTOR_LOWEST);
1017
1018 return pHgcmPort->pfnGetRequestor(pHgcmPort, pCmd);
1019}
1020
1021/**
1022 * @interface_method_impl{VBOXHGCMSVCHELPERS,pfnGetVMMDevSessionId}
1023 */
1024/* static */ DECLCALLBACK(uint64_t) HGCMService::svcHlpGetVMMDevSessionId(void *pvInstance)
1025{
1026 HGCMService *pService = static_cast <HGCMService *>(pvInstance);
1027 AssertPtrReturn(pService, UINT64_MAX);
1028
1029 PPDMIHGCMPORT pHgcmPort = pService->m_pHgcmPort;
1030 AssertPtrReturn(pHgcmPort, UINT64_MAX);
1031
1032 return pHgcmPort->pfnGetVMMDevSessionId(pHgcmPort);
1033}
1034
1035
1036static DECLCALLBACK(int) hgcmMsgCompletionCallback(int32_t result, HGCMMsgCore *pMsgCore)
1037{
1038 /* Call the VMMDev port interface to issue IRQ notification. */
1039 HGCMMsgHeader *pMsgHdr = (HGCMMsgHeader *)pMsgCore;
1040
1041 LogFlow(("MAIN::hgcmMsgCompletionCallback: message %p\n", pMsgCore));
1042
1043 if (pMsgHdr->pHGCMPort)
1044 {
1045 if (!g_fResetting)
1046 return pMsgHdr->pHGCMPort->pfnCompleted(pMsgHdr->pHGCMPort,
1047 g_fSaveState ? VINF_HGCM_SAVE_STATE : result, pMsgHdr->pCmd);
1048 return VERR_ALREADY_RESET; /* best I could find. */
1049 }
1050 return VERR_NOT_AVAILABLE;
1051}
1052
1053/*
1054 * The main HGCM methods of the service.
1055 */
1056
1057int HGCMService::instanceCreate(const char *pszServiceLibrary, const char *pszServiceName, PUVM pUVM, PPDMIHGCMPORT pHgcmPort)
1058{
1059 LogFlowFunc(("name %s, lib %s\n", pszServiceName, pszServiceLibrary));
1060 /* The maximum length of the thread name, allowed by the RT is 15. */
1061 char szThreadName[16];
1062 if (!strncmp(pszServiceName, RT_STR_TUPLE("VBoxShared")))
1063 RTStrPrintf(szThreadName, sizeof(szThreadName), "Sh%s", pszServiceName + 10);
1064 else if (!strncmp(pszServiceName, RT_STR_TUPLE("VBox")))
1065 RTStrCopy(szThreadName, sizeof(szThreadName), pszServiceName + 4);
1066 else
1067 RTStrCopy(szThreadName, sizeof(szThreadName), pszServiceName);
1068
1069 int rc = hgcmThreadCreate(&m_pThread, szThreadName, hgcmServiceThread, this, pszServiceName, pUVM);
1070
1071 if (RT_SUCCESS(rc))
1072 {
1073 m_pszSvcName = RTStrDup(pszServiceName);
1074 m_pszSvcLibrary = RTStrDup(pszServiceLibrary);
1075
1076 if (!m_pszSvcName || !m_pszSvcLibrary)
1077 {
1078 RTStrFree(m_pszSvcLibrary);
1079 m_pszSvcLibrary = NULL;
1080
1081 RTStrFree(m_pszSvcName);
1082 m_pszSvcName = NULL;
1083
1084 rc = VERR_NO_MEMORY;
1085 }
1086 else
1087 {
1088 m_pUVM = pUVM;
1089 m_pHgcmPort = pHgcmPort;
1090
1091 /* Register statistics: */
1092 STAMR3RegisterFU(pUVM, &m_StatHandleMsg, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,
1093 "Message handling", "/HGCM/%s/Msg", pszServiceName);
1094
1095 /* Initialize service helpers table. */
1096 m_svcHelpers.pfnCallComplete = svcHlpCallComplete;
1097 m_svcHelpers.pvInstance = this;
1098 m_svcHelpers.pfnDisconnectClient = svcHlpDisconnectClient;
1099 m_svcHelpers.pfnIsCallRestored = svcHlpIsCallRestored;
1100 m_svcHelpers.pfnIsCallCancelled = svcHlpIsCallCancelled;
1101 m_svcHelpers.pfnStamRegisterV = svcHlpStamRegisterV;
1102 m_svcHelpers.pfnStamDeregisterV = svcHlpStamDeregisterV;
1103 m_svcHelpers.pfnInfoRegister = svcHlpInfoRegister;
1104 m_svcHelpers.pfnInfoDeregister = svcHlpInfoDeregister;
1105 m_svcHelpers.pfnGetRequestor = svcHlpGetRequestor;
1106 m_svcHelpers.pfnGetVMMDevSessionId = svcHlpGetVMMDevSessionId;
1107
1108 /* Execute the load request on the service thread. */
1109 HGCMMsgCore *pCoreMsg;
1110 rc = hgcmMsgAlloc(m_pThread, &pCoreMsg, SVC_MSG_LOAD, hgcmMessageAllocSvc);
1111
1112 if (RT_SUCCESS(rc))
1113 {
1114 HGCMMsgSvcLoad *pMsg = (HGCMMsgSvcLoad *)pCoreMsg;
1115
1116 pMsg->pUVM = pUVM;
1117
1118 rc = hgcmMsgSend(pMsg);
1119 }
1120 }
1121 }
1122
1123 if (RT_FAILURE(rc))
1124 {
1125 instanceDestroy();
1126 }
1127
1128 LogFlowFunc(("rc = %Rrc\n", rc));
1129 return rc;
1130}
1131
1132void HGCMService::instanceDestroy(void)
1133{
1134 LogFlowFunc(("%s\n", m_pszSvcName));
1135
1136 HGCMMsgCore *pMsg;
1137 int rc = hgcmMsgAlloc(m_pThread, &pMsg, SVC_MSG_UNLOAD, hgcmMessageAllocSvc);
1138
1139 if (RT_SUCCESS(rc))
1140 {
1141 rc = hgcmMsgSend(pMsg);
1142
1143 if (RT_SUCCESS(rc))
1144 hgcmThreadWait(m_pThread);
1145 }
1146
1147 if (m_pszSvcName && m_pUVM)
1148 STAMR3DeregisterF(m_pUVM, "/HGCM/%s/*", m_pszSvcName);
1149 m_pUVM = NULL;
1150 m_pHgcmPort = NULL;
1151
1152 RTStrFree(m_pszSvcLibrary);
1153 m_pszSvcLibrary = NULL;
1154
1155 RTStrFree(m_pszSvcName);
1156 m_pszSvcName = NULL;
1157}
1158
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 idClient 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 public:
2069 /** Set if this is actually a shutdown and not a VM reset. */
2070 bool fForShutdown;
2071};
2072
2073class HGCMMsgMainQuit: public HGCMMsgCore
2074{
2075 public:
2076 /** Whether UVM has gone invalid already or not. */
2077 bool fUvmIsInvalid;
2078};
2079
2080class HGCMMsgMainRegisterExtension: public HGCMMsgCore
2081{
2082 public:
2083 /** Returned handle to be used in HGCMMsgMainUnregisterExtension. */
2084 HGCMSVCEXTHANDLE *pHandle;
2085 /** Name of the service. */
2086 const char *pszServiceName;
2087 /** The extension entry point. */
2088 PFNHGCMSVCEXT pfnExtension;
2089 /** The extension pointer. */
2090 void *pvExtension;
2091};
2092
2093class HGCMMsgMainUnregisterExtension: public HGCMMsgCore
2094{
2095 public:
2096 /* Handle of the registered extension. */
2097 HGCMSVCEXTHANDLE handle;
2098};
2099
2100class HGCMMsgMainBroadcastNotify: public HGCMMsgCore
2101{
2102 public:
2103 /** The notification event. */
2104 HGCMNOTIFYEVENT enmEvent;
2105};
2106
2107#ifdef VBOX_WITH_CRHGSMI
2108class HGCMMsgMainSvcAcquire: public HGCMMsgCore
2109{
2110 public:
2111 /* Which service to call. */
2112 const char *pszServiceName;
2113 /* Returned service. */
2114 HGCMService *pService;
2115};
2116
2117class HGCMMsgMainSvcRelease: public HGCMMsgCore
2118{
2119 public:
2120 /* Svc . */
2121 HGCMService *pService;
2122};
2123#endif
2124
2125
2126static HGCMMsgCore *hgcmMainMessageAlloc (uint32_t u32MsgId)
2127{
2128 switch (u32MsgId)
2129 {
2130 case HGCM_MSG_CONNECT: return new HGCMMsgMainConnect();
2131 case HGCM_MSG_DISCONNECT: return new HGCMMsgMainDisconnect();
2132 case HGCM_MSG_LOAD: return new HGCMMsgMainLoad();
2133 case HGCM_MSG_HOSTCALL: return new HGCMMsgMainHostCall();
2134 case HGCM_MSG_LOADSTATE:
2135 case HGCM_MSG_SAVESTATE: return new HGCMMsgMainLoadSaveState();
2136 case HGCM_MSG_RESET: return new HGCMMsgMainReset();
2137 case HGCM_MSG_QUIT: return new HGCMMsgMainQuit();
2138 case HGCM_MSG_REGEXT: return new HGCMMsgMainRegisterExtension();
2139 case HGCM_MSG_UNREGEXT: return new HGCMMsgMainUnregisterExtension();
2140 case HGCM_MSG_BRD_NOTIFY: return new HGCMMsgMainBroadcastNotify();
2141#ifdef VBOX_WITH_CRHGSMI
2142 case HGCM_MSG_SVCAQUIRE: return new HGCMMsgMainSvcAcquire();
2143 case HGCM_MSG_SVCRELEASE: return new HGCMMsgMainSvcRelease();
2144#endif
2145
2146 default:
2147 AssertReleaseMsgFailed(("Msg id = %08X\n", u32MsgId));
2148 }
2149
2150 return NULL;
2151}
2152
2153
2154/* The main HGCM thread handler. */
2155static DECLCALLBACK(void) hgcmThread(HGCMThread *pThread, void *pvUser)
2156{
2157 LogFlowFunc(("pThread = %p, pvUser = %p\n", pThread, pvUser));
2158
2159 NOREF(pvUser);
2160
2161 bool fQuit = false;
2162
2163 while (!fQuit)
2164 {
2165 HGCMMsgCore *pMsgCore;
2166 int rc = hgcmMsgGet(pThread, &pMsgCore);
2167
2168 if (RT_FAILURE(rc))
2169 {
2170 /* The error means some serious unrecoverable problem in the hgcmMsg/hgcmThread layer. */
2171 AssertMsgFailed(("%Rrc\n", rc));
2172 break;
2173 }
2174
2175 uint32_t u32MsgId = pMsgCore->MsgId();
2176
2177 switch (u32MsgId)
2178 {
2179 case HGCM_MSG_CONNECT:
2180 {
2181 HGCMMsgMainConnect *pMsg = (HGCMMsgMainConnect *)pMsgCore;
2182
2183 LogFlowFunc(("HGCM_MSG_CONNECT pszServiceName %s, pu32ClientId %p\n",
2184 pMsg->pszServiceName, pMsg->pu32ClientId));
2185
2186 /* Resolve the service name to the pointer to service instance.
2187 */
2188 HGCMService *pService;
2189 rc = HGCMService::ResolveService(&pService, pMsg->pszServiceName);
2190
2191 if (RT_SUCCESS(rc))
2192 {
2193 /* Call the service instance method. */
2194 rc = pService->CreateAndConnectClient(pMsg->pu32ClientId,
2195 0,
2196 pMsg->pHGCMPort->pfnGetRequestor(pMsg->pHGCMPort, pMsg->pCmd),
2197 pMsg->pHGCMPort->pfnIsCmdRestored(pMsg->pHGCMPort, pMsg->pCmd));
2198
2199 /* Release the service after resolve. */
2200 pService->ReleaseService();
2201 }
2202 } break;
2203
2204 case HGCM_MSG_DISCONNECT:
2205 {
2206 HGCMMsgMainDisconnect *pMsg = (HGCMMsgMainDisconnect *)pMsgCore;
2207
2208 LogFlowFunc(("HGCM_MSG_DISCONNECT u32ClientId = %d\n",
2209 pMsg->u32ClientId));
2210
2211 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(pMsg->u32ClientId, HGCMOBJ_CLIENT);
2212
2213 if (!pClient)
2214 {
2215 rc = VERR_HGCM_INVALID_CLIENT_ID;
2216 break;
2217 }
2218
2219 /* The service the client belongs to. */
2220 HGCMService *pService = pClient->pService;
2221
2222 /* Call the service instance to disconnect the client. */
2223 rc = pService->DisconnectClient(pMsg->u32ClientId, false);
2224
2225 hgcmObjDereference(pClient);
2226 } break;
2227
2228 case HGCM_MSG_LOAD:
2229 {
2230 HGCMMsgMainLoad *pMsg = (HGCMMsgMainLoad *)pMsgCore;
2231
2232 LogFlowFunc(("HGCM_MSG_LOAD pszServiceName = %s, pMsg->pszServiceLibrary = %s, pMsg->pUVM = %p\n",
2233 pMsg->pszServiceName, pMsg->pszServiceLibrary, pMsg->pUVM));
2234
2235 rc = HGCMService::LoadService(pMsg->pszServiceLibrary, pMsg->pszServiceName, pMsg->pUVM, pMsg->pHgcmPort);
2236 } break;
2237
2238 case HGCM_MSG_HOSTCALL:
2239 {
2240 HGCMMsgMainHostCall *pMsg = (HGCMMsgMainHostCall *)pMsgCore;
2241
2242 LogFlowFunc(("HGCM_MSG_HOSTCALL pszServiceName %s, u32Function %d, cParms %d, paParms %p\n",
2243 pMsg->pszServiceName, pMsg->u32Function, pMsg->cParms, pMsg->paParms));
2244
2245 /* Resolve the service name to the pointer to service instance. */
2246 HGCMService *pService;
2247 rc = HGCMService::ResolveService(&pService, pMsg->pszServiceName);
2248
2249 if (RT_SUCCESS(rc))
2250 {
2251 rc = pService->HostCall(pMsg->u32Function, pMsg->cParms, pMsg->paParms);
2252
2253 pService->ReleaseService();
2254 }
2255 } break;
2256
2257 case HGCM_MSG_BRD_NOTIFY:
2258 {
2259 HGCMMsgMainBroadcastNotify *pMsg = (HGCMMsgMainBroadcastNotify *)pMsgCore;
2260
2261 LogFlowFunc(("HGCM_MSG_BRD_NOTIFY enmEvent=%d\n", pMsg->enmEvent));
2262
2263 HGCMService::BroadcastNotify(pMsg->enmEvent);
2264 } break;
2265
2266#ifdef VBOX_WITH_CRHGSMI
2267 case HGCM_MSG_SVCAQUIRE:
2268 {
2269 HGCMMsgMainSvcAcquire *pMsg = (HGCMMsgMainSvcAcquire *)pMsgCore;
2270
2271 LogFlowFunc(("HGCM_MSG_SVCAQUIRE pszServiceName %s\n", pMsg->pszServiceName));
2272
2273 /* Resolve the service name to the pointer to service instance. */
2274 HGCMService *pService;
2275 rc = HGCMService::ResolveService(&pService, pMsg->pszServiceName);
2276 if (RT_SUCCESS(rc))
2277 {
2278 rc = pService->HandleAcquired();
2279 if (RT_SUCCESS(rc))
2280 {
2281 pMsg->pService = pService;
2282 }
2283 else
2284 {
2285 pService->ReleaseService();
2286 }
2287 }
2288 } break;
2289
2290 case HGCM_MSG_SVCRELEASE:
2291 {
2292 HGCMMsgMainSvcRelease *pMsg = (HGCMMsgMainSvcRelease *)pMsgCore;
2293
2294 LogFlowFunc(("HGCM_MSG_SVCARELEASE pService %p\n", pMsg->pService));
2295
2296 /* Resolve the service name to the pointer to service instance. */
2297
2298 rc = pMsg->pService->HandleReleased();
2299 if (RT_SUCCESS(rc))
2300 {
2301 pMsg->pService->ReleaseService();
2302 }
2303 } break;
2304#endif
2305
2306 case HGCM_MSG_RESET:
2307 {
2308 LogFlowFunc(("HGCM_MSG_RESET\n"));
2309
2310 HGCMService::Reset();
2311
2312 HGCMMsgMainReset *pMsg = (HGCMMsgMainReset *)pMsgCore;
2313 if (!pMsg->fForShutdown)
2314 HGCMService::BroadcastNotify(HGCMNOTIFYEVENT_RESET);
2315 } break;
2316
2317 case HGCM_MSG_LOADSTATE:
2318 {
2319 HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pMsgCore;
2320
2321 LogFlowFunc(("HGCM_MSG_LOADSTATE\n"));
2322
2323 rc = HGCMService::LoadState(pMsg->pSSM, pMsg->uVersion);
2324 } break;
2325
2326 case HGCM_MSG_SAVESTATE:
2327 {
2328 HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pMsgCore;
2329
2330 LogFlowFunc(("HGCM_MSG_SAVESTATE\n"));
2331
2332 rc = HGCMService::SaveState(pMsg->pSSM);
2333 } break;
2334
2335 case HGCM_MSG_QUIT:
2336 {
2337 HGCMMsgMainQuit *pMsg = (HGCMMsgMainQuit *)pMsgCore;
2338 LogFlowFunc(("HGCM_MSG_QUIT\n"));
2339
2340 HGCMService::UnloadAll(pMsg->fUvmIsInvalid);
2341
2342 fQuit = true;
2343 } break;
2344
2345 case HGCM_MSG_REGEXT:
2346 {
2347 HGCMMsgMainRegisterExtension *pMsg = (HGCMMsgMainRegisterExtension *)pMsgCore;
2348
2349 LogFlowFunc(("HGCM_MSG_REGEXT\n"));
2350
2351 /* Allocate the handle data. */
2352 HGCMSVCEXTHANDLE handle = (HGCMSVCEXTHANDLE)RTMemAllocZ(sizeof(struct _HGCMSVCEXTHANDLEDATA)
2353 + strlen(pMsg->pszServiceName)
2354 + sizeof(char));
2355
2356 if (handle == NULL)
2357 {
2358 rc = VERR_NO_MEMORY;
2359 }
2360 else
2361 {
2362 handle->pszServiceName = (char *)((uint8_t *)handle + sizeof(struct _HGCMSVCEXTHANDLEDATA));
2363 strcpy(handle->pszServiceName, pMsg->pszServiceName);
2364
2365 HGCMService *pService;
2366 rc = HGCMService::ResolveService(&pService, handle->pszServiceName);
2367
2368 if (RT_SUCCESS(rc))
2369 {
2370 pService->RegisterExtension(handle, pMsg->pfnExtension, pMsg->pvExtension);
2371
2372 pService->ReleaseService();
2373 }
2374
2375 if (RT_FAILURE(rc))
2376 {
2377 RTMemFree(handle);
2378 }
2379 else
2380 {
2381 *pMsg->pHandle = handle;
2382 }
2383 }
2384 } break;
2385
2386 case HGCM_MSG_UNREGEXT:
2387 {
2388 HGCMMsgMainUnregisterExtension *pMsg = (HGCMMsgMainUnregisterExtension *)pMsgCore;
2389
2390 LogFlowFunc(("HGCM_MSG_UNREGEXT\n"));
2391
2392 HGCMService *pService;
2393 rc = HGCMService::ResolveService(&pService, pMsg->handle->pszServiceName);
2394
2395 if (RT_SUCCESS(rc))
2396 {
2397 pService->UnregisterExtension(pMsg->handle);
2398
2399 pService->ReleaseService();
2400 }
2401
2402 RTMemFree(pMsg->handle);
2403 } break;
2404
2405 default:
2406 {
2407 AssertMsgFailed(("hgcmThread: Unsupported message number %08X!!!\n", u32MsgId));
2408 rc = VERR_NOT_SUPPORTED;
2409 } break;
2410 }
2411
2412 /* Complete the message processing. */
2413 hgcmMsgComplete(pMsgCore, rc);
2414
2415 LogFlowFunc(("message processed %Rrc\n", rc));
2416 }
2417}
2418
2419
2420/*
2421 * The HGCM API.
2422 */
2423
2424/** The main hgcm thread. */
2425static HGCMThread *g_pHgcmThread = 0;
2426
2427/*
2428 * Public HGCM functions.
2429 *
2430 * hgcmGuest* - called as a result of the guest HGCM requests.
2431 * hgcmHost* - called by the host.
2432 */
2433
2434/* Load a HGCM service from the specified library.
2435 * Assign the specified name to the service.
2436 *
2437 * @param pszServiceLibrary The library to be loaded.
2438 * @param pszServiceName The name to be assigned to the service.
2439 * @param pUVM The user mode VM handle (for statistics and such).
2440 * @param pHgcmPort The HGCM port on the VMMDev device (for session ID and such).
2441 * @return VBox rc.
2442 */
2443int HGCMHostLoad(const char *pszServiceLibrary,
2444 const char *pszServiceName,
2445 PUVM pUVM,
2446 PPDMIHGCMPORT pHgcmPort)
2447{
2448 LogFlowFunc(("lib = %s, name = %s\n", pszServiceLibrary, pszServiceName));
2449
2450 if (!pszServiceLibrary || !pszServiceName)
2451 {
2452 return VERR_INVALID_PARAMETER;
2453 }
2454
2455 /* Forward the request to the main hgcm thread. */
2456 HGCMMsgCore *pCoreMsg;
2457 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_LOAD, hgcmMainMessageAlloc);
2458
2459 if (RT_SUCCESS(rc))
2460 {
2461 /* Initialize the message. Since the message is synchronous, use the supplied pointers. */
2462 HGCMMsgMainLoad *pMsg = (HGCMMsgMainLoad *)pCoreMsg;
2463
2464 pMsg->pszServiceLibrary = pszServiceLibrary;
2465 pMsg->pszServiceName = pszServiceName;
2466 pMsg->pUVM = pUVM;
2467 pMsg->pHgcmPort = pHgcmPort;
2468
2469 rc = hgcmMsgSend(pMsg);
2470 }
2471
2472 LogFlowFunc(("rc = %Rrc\n", rc));
2473 return rc;
2474}
2475
2476/* Register a HGCM service extension.
2477 *
2478 * @param pHandle Returned handle for the registered extension.
2479 * @param pszServiceName The name of the service.
2480 * @param pfnExtension The extension entry point (callback).
2481 * @param pvExtension The extension pointer.
2482 * @return VBox rc.
2483 */
2484int HGCMHostRegisterServiceExtension(HGCMSVCEXTHANDLE *pHandle,
2485 const char *pszServiceName,
2486 PFNHGCMSVCEXT pfnExtension,
2487 void *pvExtension)
2488{
2489 LogFlowFunc(("pHandle = %p, name = %s, pfn = %p, rv = %p\n", pHandle, pszServiceName, pfnExtension, pvExtension));
2490
2491 if (!pHandle || !pszServiceName || !pfnExtension)
2492 {
2493 return VERR_INVALID_PARAMETER;
2494 }
2495
2496 /* Forward the request to the main hgcm thread. */
2497 HGCMMsgCore *pCoreMsg;
2498 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_REGEXT, hgcmMainMessageAlloc);
2499
2500 if (RT_SUCCESS(rc))
2501 {
2502 /* Initialize the message. Since the message is synchronous, use the supplied pointers. */
2503 HGCMMsgMainRegisterExtension *pMsg = (HGCMMsgMainRegisterExtension *)pCoreMsg;
2504
2505 pMsg->pHandle = pHandle;
2506 pMsg->pszServiceName = pszServiceName;
2507 pMsg->pfnExtension = pfnExtension;
2508 pMsg->pvExtension = pvExtension;
2509
2510 rc = hgcmMsgSend(pMsg);
2511 }
2512
2513 LogFlowFunc(("*pHandle = %p, rc = %Rrc\n", *pHandle, rc));
2514 return rc;
2515}
2516
2517void HGCMHostUnregisterServiceExtension(HGCMSVCEXTHANDLE handle)
2518{
2519 LogFlowFunc(("handle = %p\n", handle));
2520
2521 /* Forward the request to the main hgcm thread. */
2522 HGCMMsgCore *pCoreMsg;
2523 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_UNREGEXT, hgcmMainMessageAlloc);
2524
2525 if (RT_SUCCESS(rc))
2526 {
2527 /* Initialize the message. */
2528 HGCMMsgMainUnregisterExtension *pMsg = (HGCMMsgMainUnregisterExtension *)pCoreMsg;
2529
2530 pMsg->handle = handle;
2531
2532 rc = hgcmMsgSend(pMsg);
2533 }
2534
2535 LogFlowFunc(("rc = %Rrc\n", rc));
2536 return;
2537}
2538
2539/* Find a service and inform it about a client connection, create a client handle.
2540 *
2541 * @param pHGCMPort The port to be used for completion confirmation.
2542 * @param pCmd The VBox HGCM context.
2543 * @param pszServiceName The name of the service to be connected to.
2544 * @param pu32ClientId Where the store the created client handle.
2545 * @return VBox rc.
2546 */
2547int HGCMGuestConnect(PPDMIHGCMPORT pHGCMPort,
2548 PVBOXHGCMCMD pCmd,
2549 const char *pszServiceName,
2550 uint32_t *pu32ClientId)
2551{
2552 LogFlowFunc(("pHGCMPort = %p, pCmd = %p, name = %s, pu32ClientId = %p\n",
2553 pHGCMPort, pCmd, pszServiceName, pu32ClientId));
2554
2555 if (pHGCMPort == NULL || pCmd == NULL || pszServiceName == NULL || pu32ClientId == NULL)
2556 {
2557 return VERR_INVALID_PARAMETER;
2558 }
2559
2560 /* Forward the request to the main hgcm thread. */
2561 HGCMMsgCore *pCoreMsg;
2562 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_CONNECT, hgcmMainMessageAlloc);
2563
2564 if (RT_SUCCESS(rc))
2565 {
2566 /* Initialize the message. Since 'pszServiceName' and 'pu32ClientId'
2567 * will not be deallocated by the caller until the message is completed,
2568 * use the supplied pointers.
2569 */
2570 HGCMMsgMainConnect *pMsg = (HGCMMsgMainConnect *)pCoreMsg;
2571
2572 pMsg->pHGCMPort = pHGCMPort;
2573 pMsg->pCmd = pCmd;
2574 pMsg->pszServiceName = pszServiceName;
2575 pMsg->pu32ClientId = pu32ClientId;
2576
2577 rc = hgcmMsgPost(pMsg, hgcmMsgCompletionCallback);
2578 }
2579
2580 LogFlowFunc(("rc = %Rrc\n", rc));
2581 return rc;
2582}
2583
2584/* Tell a service that the client is disconnecting, destroy the client handle.
2585 *
2586 * @param pHGCMPort The port to be used for completion confirmation.
2587 * @param pCmd The VBox HGCM context.
2588 * @param u32ClientId The client handle to be disconnected and deleted.
2589 * @return VBox rc.
2590 */
2591int HGCMGuestDisconnect(PPDMIHGCMPORT pHGCMPort,
2592 PVBOXHGCMCMD pCmd,
2593 uint32_t u32ClientId)
2594{
2595 LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d\n",
2596 pHGCMPort, pCmd, u32ClientId));
2597
2598 if (!pHGCMPort || !pCmd || !u32ClientId)
2599 {
2600 return VERR_INVALID_PARAMETER;
2601 }
2602
2603 /* Forward the request to the main hgcm thread. */
2604 HGCMMsgCore *pCoreMsg;
2605 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_DISCONNECT, hgcmMainMessageAlloc);
2606
2607 if (RT_SUCCESS(rc))
2608 {
2609 /* Initialize the message. */
2610 HGCMMsgMainDisconnect *pMsg = (HGCMMsgMainDisconnect *)pCoreMsg;
2611
2612 pMsg->pCmd = pCmd;
2613 pMsg->pHGCMPort = pHGCMPort;
2614 pMsg->u32ClientId = u32ClientId;
2615
2616 rc = hgcmMsgPost(pMsg, hgcmMsgCompletionCallback);
2617 }
2618
2619 LogFlowFunc(("rc = %Rrc\n", rc));
2620 return rc;
2621}
2622
2623/** Helper to send either HGCM_MSG_SAVESTATE or HGCM_MSG_LOADSTATE messages to the main HGCM thread.
2624 *
2625 * @param pSSM The SSM handle.
2626 * @param idMsg The message to be sent: HGCM_MSG_SAVESTATE or HGCM_MSG_LOADSTATE.
2627 * @param uVersion The state version being loaded.
2628 * @return VBox rc.
2629 */
2630static int hgcmHostLoadSaveState(PSSMHANDLE pSSM, uint32_t idMsg, uint32_t uVersion)
2631{
2632 LogFlowFunc(("pSSM = %p, idMsg = %d, uVersion = uVersion\n", pSSM, idMsg));
2633
2634 HGCMMsgCore *pCoreMsg;
2635 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, idMsg, hgcmMainMessageAlloc);
2636
2637 if (RT_SUCCESS(rc))
2638 {
2639 HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pCoreMsg;
2640 AssertRelease(pMsg);
2641
2642 pMsg->pSSM = pSSM;
2643 pMsg->uVersion = uVersion;
2644
2645 rc = hgcmMsgSend(pMsg);
2646 }
2647
2648 LogFlowFunc(("rc = %Rrc\n", rc));
2649 return rc;
2650}
2651
2652/** Save the state of services.
2653 *
2654 * @param pSSM The SSM handle.
2655 * @return VBox rc.
2656 */
2657int HGCMHostSaveState(PSSMHANDLE pSSM)
2658{
2659 return hgcmHostLoadSaveState(pSSM, HGCM_MSG_SAVESTATE, HGCM_SAVED_STATE_VERSION);
2660}
2661
2662/** Load the state of services.
2663 *
2664 * @param pSSM The SSM handle.
2665 * @param uVersion The state version being loaded.
2666 * @return VBox rc.
2667 */
2668int HGCMHostLoadState(PSSMHANDLE pSSM, uint32_t uVersion)
2669{
2670 return hgcmHostLoadSaveState(pSSM, HGCM_MSG_LOADSTATE, uVersion);
2671}
2672
2673/** The guest calls the service.
2674 *
2675 * @param pHGCMPort The port to be used for completion confirmation.
2676 * @param pCmd The VBox HGCM context.
2677 * @param u32ClientId The client handle.
2678 * @param u32Function The function number.
2679 * @param cParms Number of parameters.
2680 * @param paParms Pointer to array of parameters.
2681 * @param tsArrival The STAM_GET_TS() value when the request arrived.
2682 * @return VBox rc.
2683 */
2684int HGCMGuestCall(PPDMIHGCMPORT pHGCMPort,
2685 PVBOXHGCMCMD pCmd,
2686 uint32_t u32ClientId,
2687 uint32_t u32Function,
2688 uint32_t cParms,
2689 VBOXHGCMSVCPARM *paParms,
2690 uint64_t tsArrival)
2691{
2692 LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d, u32Function = %d, cParms = %d, paParms = %p\n",
2693 pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms));
2694
2695 if (!pHGCMPort || !pCmd || u32ClientId == 0)
2696 {
2697 return VERR_INVALID_PARAMETER;
2698 }
2699
2700 int rc = VERR_HGCM_INVALID_CLIENT_ID;
2701
2702 /* Resolve the client handle to the client instance pointer. */
2703 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(u32ClientId, HGCMOBJ_CLIENT);
2704
2705 if (pClient)
2706 {
2707 AssertRelease(pClient->pService);
2708
2709 /* Forward the message to the service thread. */
2710 rc = pClient->pService->GuestCall(pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms, tsArrival);
2711
2712 hgcmObjDereference(pClient);
2713 }
2714
2715 LogFlowFunc(("rc = %Rrc\n", rc));
2716 return rc;
2717}
2718
2719/** The guest cancelled a request (call, connect, disconnect)
2720 *
2721 * @param pHGCMPort The port to be used for completion confirmation.
2722 * @param pCmd The VBox HGCM context.
2723 * @param idClient The client handle.
2724 */
2725void HGCMGuestCancelled(PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t idClient)
2726{
2727 LogFlowFunc(("pHGCMPort = %p, pCmd = %p, idClient = %d\n", pHGCMPort, pCmd, idClient));
2728 AssertReturnVoid(pHGCMPort);
2729 AssertReturnVoid(pCmd);
2730 AssertReturnVoid(idClient != 0);
2731
2732 /* Resolve the client handle to the client instance pointer. */
2733 HGCMClient *pClient = (HGCMClient *)hgcmObjReference(idClient, HGCMOBJ_CLIENT);
2734
2735 if (pClient)
2736 {
2737 AssertRelease(pClient->pService);
2738
2739 /* Forward the message to the service thread. */
2740 pClient->pService->GuestCancelled(pHGCMPort, pCmd, idClient);
2741
2742 hgcmObjDereference(pClient);
2743 }
2744
2745 LogFlowFunc(("returns\n"));
2746}
2747
2748/** The host calls the service.
2749 *
2750 * @param pszServiceName The service name to be called.
2751 * @param u32Function The function number.
2752 * @param cParms Number of parameters.
2753 * @param paParms Pointer to array of parameters.
2754 * @return VBox rc.
2755 */
2756int HGCMHostCall(const char *pszServiceName,
2757 uint32_t u32Function,
2758 uint32_t cParms,
2759 VBOXHGCMSVCPARM *paParms)
2760{
2761 LogFlowFunc(("name = %s, u32Function = %d, cParms = %d, paParms = %p\n",
2762 pszServiceName, u32Function, cParms, paParms));
2763
2764 if (!pszServiceName)
2765 {
2766 return VERR_INVALID_PARAMETER;
2767 }
2768
2769 /* Host calls go to main HGCM thread that resolves the service name to the
2770 * service instance pointer and then, using the service pointer, forwards
2771 * the message to the service thread.
2772 * So it is slow but host calls are intended mostly for configuration and
2773 * other non-time-critical functions.
2774 */
2775 HGCMMsgCore *pCoreMsg;
2776 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_HOSTCALL, hgcmMainMessageAlloc);
2777
2778 if (RT_SUCCESS(rc))
2779 {
2780 HGCMMsgMainHostCall *pMsg = (HGCMMsgMainHostCall *)pCoreMsg;
2781
2782 pMsg->pszServiceName = (char *)pszServiceName;
2783 pMsg->u32Function = u32Function;
2784 pMsg->cParms = cParms;
2785 pMsg->paParms = paParms;
2786
2787 rc = hgcmMsgSend(pMsg);
2788 }
2789
2790 LogFlowFunc(("rc = %Rrc\n", rc));
2791 return rc;
2792}
2793
2794/** Posts a notification event to all services.
2795 *
2796 * @param enmEvent The notification event.
2797 * @return VBox rc.
2798 */
2799int HGCMBroadcastEvent(HGCMNOTIFYEVENT enmEvent)
2800{
2801 LogFlowFunc(("enmEvent=%d\n", enmEvent));
2802
2803 HGCMMsgCore *pCoreMsg;
2804 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_BRD_NOTIFY, hgcmMainMessageAlloc);
2805
2806 if (RT_SUCCESS(rc))
2807 {
2808 HGCMMsgMainBroadcastNotify *pMsg = (HGCMMsgMainBroadcastNotify *)pCoreMsg;
2809
2810 pMsg->enmEvent = enmEvent;
2811
2812 rc = hgcmMsgPost(pMsg, NULL);
2813 }
2814
2815 LogFlowFunc(("rc = %Rrc\n", rc));
2816 return rc;
2817}
2818
2819
2820#ifdef VBOX_WITH_CRHGSMI
2821int HGCMHostSvcHandleCreate(const char *pszServiceName, HGCMCVSHANDLE * phSvc)
2822{
2823 LogFlowFunc(("name = %s\n", pszServiceName));
2824
2825 if (!pszServiceName)
2826 {
2827 return VERR_INVALID_PARAMETER;
2828 }
2829
2830 if (!phSvc)
2831 {
2832 return VERR_INVALID_PARAMETER;
2833 }
2834
2835 /* Host calls go to main HGCM thread that resolves the service name to the
2836 * service instance pointer and then, using the service pointer, forwards
2837 * the message to the service thread.
2838 * So it is slow but host calls are intended mostly for configuration and
2839 * other non-time-critical functions.
2840 */
2841 HGCMMsgCore *pCoreMsg;
2842 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_SVCAQUIRE, hgcmMainMessageAlloc);
2843
2844 if (RT_SUCCESS(rc))
2845 {
2846 HGCMMsgMainSvcAcquire *pMsg = (HGCMMsgMainSvcAcquire *)pCoreMsg;
2847
2848 pMsg->pszServiceName = (char *)pszServiceName;
2849 pMsg->pService = NULL;
2850
2851 pMsg->Reference();
2852
2853 rc = hgcmMsgSend(pMsg);
2854 if (RT_SUCCESS(rc))
2855 {
2856 /* for simplicity just use a svc ptr as handle for now */
2857 *phSvc = (HGCMCVSHANDLE)pMsg->pService;
2858 }
2859 pMsg->Dereference();
2860 }
2861
2862 LogFlowFunc(("rc = %Rrc\n", rc));
2863 return rc;
2864}
2865
2866int HGCMHostSvcHandleDestroy(HGCMCVSHANDLE hSvc)
2867{
2868 LogFlowFunc(("hSvc = %p\n", hSvc));
2869
2870 if (!hSvc)
2871 {
2872 return VERR_INVALID_PARAMETER;
2873 }
2874
2875 /* Host calls go to main HGCM thread that resolves the service name to the
2876 * service instance pointer and then, using the service pointer, forwards
2877 * the message to the service thread.
2878 * So it is slow but host calls are intended mostly for configuration and
2879 * other non-time-critical functions.
2880 */
2881 HGCMMsgCore *pCoreMsg;
2882 int rc = hgcmMsgAlloc(g_pHgcmThread, &pCoreMsg, HGCM_MSG_SVCRELEASE, hgcmMainMessageAlloc);
2883
2884 if (RT_SUCCESS(rc))
2885 {
2886 HGCMMsgMainSvcRelease *pMsg = (HGCMMsgMainSvcRelease *)pCoreMsg;
2887
2888 pMsg->pService = (HGCMService *)hSvc;
2889
2890 rc = hgcmMsgSend(pMsg);
2891 }
2892
2893 LogFlowFunc(("rc = %Rrc\n", rc));
2894 return rc;
2895}
2896
2897int HGCMHostFastCallAsync(HGCMCVSHANDLE hSvc, uint32_t function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion,
2898 void *pvCompletion)
2899{
2900 LogFlowFunc(("hSvc = %p, u32Function = %d, pParm = %p\n",
2901 hSvc, function, pParm));
2902
2903 if (!hSvc)
2904 {
2905 return VERR_INVALID_PARAMETER;
2906 }
2907
2908 HGCMService *pService = (HGCMService *)hSvc;
2909 int rc = pService->HostFastCallAsync(function, pParm, pfnCompletion, pvCompletion);
2910
2911 LogFlowFunc(("rc = %Rrc\n", rc));
2912 return rc;
2913}
2914#endif
2915
2916int HGCMHostReset(bool fForShutdown)
2917{
2918 LogFlowFunc(("\n"));
2919
2920 /* Disconnect all clients.
2921 */
2922
2923 HGCMMsgCore *pMsgCore;
2924 int rc = hgcmMsgAlloc(g_pHgcmThread, &pMsgCore, HGCM_MSG_RESET, hgcmMainMessageAlloc);
2925
2926 if (RT_SUCCESS(rc))
2927 {
2928 HGCMMsgMainReset *pMsg = (HGCMMsgMainReset *)pMsgCore;
2929
2930 pMsg->fForShutdown = fForShutdown;
2931
2932 rc = hgcmMsgSend(pMsg);
2933 }
2934
2935 LogFlowFunc(("rc = %Rrc\n", rc));
2936 return rc;
2937}
2938
2939int HGCMHostInit(void)
2940{
2941 LogFlowFunc(("\n"));
2942
2943 int rc = hgcmThreadInit();
2944
2945 if (RT_SUCCESS(rc))
2946 {
2947 /*
2948 * Start main HGCM thread.
2949 */
2950
2951 rc = hgcmThreadCreate(&g_pHgcmThread, "MainHGCMthread", hgcmThread, NULL /*pvUser*/, NULL /*pszStatsSubDir*/, NULL /*pUVM*/);
2952
2953 if (RT_FAILURE(rc))
2954 LogRel(("Failed to start HGCM thread. HGCM services will be unavailable!!! rc = %Rrc\n", rc));
2955 }
2956
2957 LogFlowFunc(("rc = %Rrc\n", rc));
2958 return rc;
2959}
2960
2961int HGCMHostShutdown(bool fUvmIsInvalid /*= false*/)
2962{
2963 LogFlowFunc(("\n"));
2964
2965 /*
2966 * Do HGCMReset and then unload all services.
2967 */
2968
2969 int rc = HGCMHostReset(true /*fForShutdown*/);
2970
2971 if (RT_SUCCESS(rc))
2972 {
2973 /* Send the quit message to the main hgcmThread. */
2974 HGCMMsgCore *pMsgCore;
2975 rc = hgcmMsgAlloc(g_pHgcmThread, &pMsgCore, HGCM_MSG_QUIT, hgcmMainMessageAlloc);
2976
2977 if (RT_SUCCESS(rc))
2978 {
2979 HGCMMsgMainQuit *pMsg = (HGCMMsgMainQuit *)pMsgCore;
2980 pMsg->fUvmIsInvalid = fUvmIsInvalid;
2981
2982 rc = hgcmMsgSend(pMsg);
2983
2984 if (RT_SUCCESS(rc))
2985 {
2986 /* Wait for the thread termination. */
2987 hgcmThreadWait(g_pHgcmThread);
2988 g_pHgcmThread = NULL;
2989
2990 hgcmThreadUninit();
2991 }
2992 }
2993 }
2994
2995 LogFlowFunc(("rc = %Rrc\n", rc));
2996 return rc;
2997}
2998
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