VirtualBox

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

Last change on this file since 75416 was 75406, checked in by vboxsync, 6 years ago

VMMDev/HGCM: Added PDM interface + HGCM server helper for finding out if a command/call is being resubmitted on restore or not. This is handy for returning returning an async wait call to the guest upon restore. bugref:3544

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

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