VirtualBox

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

Last change on this file since 107577 was 107577, checked in by vboxsync, 3 weeks ago

src/VBox/Main/src-client/HGCM: Fixed warnings found by Parfait (assignment unused). jiraref:VBP-1424

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette