VirtualBox

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

Last change on this file since 86506 was 82968, checked in by vboxsync, 4 years ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use