VirtualBox

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

Last change on this file since 93115 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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