VirtualBox

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

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

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use