VirtualBox

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

Last change on this file since 94521 was 93444, checked in by vboxsync, 2 years ago

VMM,Main,HostServices: Use a function table for accessing the VBoxVMM.dll/so/dylib functionality, and load it dynamically when the Console object is initialized. Also converted a few drivers in Main to use device helpers to get config values and such. bugref:10074

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

© 2023 Oracle
ContactPrivacy policyTerms of Use