VirtualBox

source: vbox/trunk/include/VBox/GuestHost/HGCMMock.h@ 93969

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

Validation Kit/HGCM: Split out the HGCM testing (mocking) framework into an own header, added documentation, more code for generalizing this.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.7 KB
Line 
1/* $Id: HGCMMock.h 93969 2022-02-28 10:21:21Z vboxsync $ */
2/** @file
3 * HGCMMock.h: Mocking framework for testing HGCM-based host services +
4 * Vbgl code on the host side.
5 *
6 * Goal is to run host service + Vbgl code as unmodified as
7 * possible as part of testcases to gain test coverage which
8 * otherwise wouldn't possible for heavily user-centric features
9 * like Shared Clipboard or drag'n drop (DnD).
10 */
11
12/*
13 * Copyright (C) 2022 Oracle Corporation
14 *
15 * This file is part of VirtualBox Open Source Edition (OSE), as
16 * available from http://www.virtualbox.org. This file is free software;
17 * you can redistribute it and/or modify it under the terms of the GNU
18 * General Public License (GPL) as published by the Free Software
19 * Foundation, in version 2 as it comes in the "COPYING" file of the
20 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
21 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
22 */
23
24#include <iprt/assert.h>
25#include <iprt/initterm.h>
26#include <iprt/mem.h>
27#include <iprt/rand.h>
28#include <iprt/semaphore.h>
29#include <iprt/stream.h>
30#include <iprt/string.h>
31#include <iprt/test.h>
32#include <iprt/utf16.h>
33
34#include <VBox/VBoxGuestLib.h>
35
36
37/*********************************************************************************************************************************
38* Definitions. *
39*********************************************************************************************************************************/
40
41extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *ptable);
42
43typedef uint32_t HGCMCLIENTID;
44# define VBGLR3DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL
45
46RT_C_DECLS_BEGIN
47
48/** Simple call handle structure for the guest call completion callback. */
49struct VBOXHGCMCALLHANDLE_TYPEDEF
50{
51 /** Where to store the result code on call completion. */
52 int32_t rc;
53};
54
55/**
56 * Enumeration for a HGCM mock function type.
57 */
58typedef enum TSTHGCMMOCKFNTYPE
59{
60 TSTHGCMMOCKFNTYPE_NONE = 0,
61 TSTHGCMMOCKFNTYPE_CONNECT,
62 TSTHGCMMOCKFNTYPE_DISCONNECT,
63 TSTHGCMMOCKFNTYPE_CALL,
64 TSTHGCMMOCKFNTYPE_HOST_CALL
65} TSTHGCMMOCKFNTYPE;
66
67/** Forward declaration of the HGCM mock service. */
68struct TSTHGCMMOCKSVC;
69
70/**
71 * Structure for mocking a server-side HGCM client.
72 */
73typedef struct TSTHGCMMOCKCLIENT
74{
75 /** Pointer to to mock service instance this client belongs to. */
76 TSTHGCMMOCKSVC *pSvc;
77 /** Assigned HGCM client ID. */
78 uint32_t idClient;
79 /** Opaque pointer to service-specific client data.
80 * Can be NULL if not being used. */
81 void *pvClient;
82 /** Size (in bytes) of \a pvClient. */
83 size_t cbClient;
84 /** The client's current HGCM call handle. */
85 VBOXHGCMCALLHANDLE_TYPEDEF hCall;
86 /** Whether the current client call has an asynchronous
87 * call pending or not. */
88 bool fAsyncExec;
89 /** Event semaphore to signal call completion. */
90 RTSEMEVENT hEvent;
91} TSTHGCMMOCKCLIENT;
92/** Pointer to a mock HGCM client. */
93typedef TSTHGCMMOCKCLIENT *PTSTHGCMMOCKCLIENT;
94
95/**
96 * Structure for keeping HGCM mock function parameters.
97 */
98typedef struct TSTHGCMMOCKFN
99{
100 /** List node for storing this struct into a queue. */
101 RTLISTNODE Node;
102 /** Function type. */
103 TSTHGCMMOCKFNTYPE enmType;
104 /** Pointer to associated client. */
105 PTSTHGCMMOCKCLIENT pClient;
106 /** Union keeping function-specific parameters,
107 * depending on \a enmType. */
108 union
109 {
110 struct
111 {
112 } Connect;
113 struct
114 {
115 } Disconnect;
116 struct
117 {
118 int32_t iFunc;
119 uint32_t cParms;
120 PVBOXHGCMSVCPARM pParms;
121 VBOXHGCMCALLHANDLE hCall;
122 } Call;
123 struct
124 {
125 int32_t iFunc;
126 uint32_t cParms;
127 PVBOXHGCMSVCPARM pParms;
128 } HostCall;
129 } u;
130} TSTHGCMMOCKFN;
131/** Pointer to a HGCM mock function parameters structure. */
132typedef TSTHGCMMOCKFN *PTSTHGCMMOCKFN;
133
134/**
135 * Structure for keeping a HGCM mock service instance.
136 */
137typedef struct TSTHGCMMOCKSVC
138{
139 /** HGCM helper table to use. */
140 VBOXHGCMSVCHELPERS fnHelpers;
141 /** HGCM service function table to use. */
142 VBOXHGCMSVCFNTABLE fnTable;
143 /** Next HGCM client ID to assign.
144 * 0 is considered as being invalid. */
145 HGCMCLIENTID uNextClientId;
146 /** Size (in bytes) of opaque pvClient area to reserve
147 * for a connected client. */
148 size_t cbClient;
149 /** Array of connected HGCM mock clients.
150 * Currently limited to 4 clients maximum. */
151 TSTHGCMMOCKCLIENT aHgcmClient[4];
152 /** Thread handle for the service's main loop. */
153 RTTHREAD hThread;
154 /** Event semaphore for signalling a message
155 * queue change. */
156 RTSEMEVENT hEventQueue;
157 /** Event semaphore for waiting on events, such
158 * as clients connecting. */
159 RTSEMEVENT hEventWait;
160 /** Number of current host calls being served.
161 * Currently limited to one call at a time. */
162 uint8_t cHostCallers;
163 /** Result code of last returned host call. */
164 int rcHostCall;
165 /** Event semaphore for host calls. */
166 RTSEMEVENT hEventHostCall;
167 /** List (queue) of function calls to process. */
168 RTLISTANCHOR lstCall;
169 /** Shutdown indicator flag. */
170 volatile bool fShutdown;
171} TSTHGCMMOCKSVC;
172/** Pointer to a mock HGCM service. */
173typedef TSTHGCMMOCKSVC *PTSTHGCMMOCKSVC;
174
175/** Static HGCM service to mock. */
176static TSTHGCMMOCKSVC s_tstHgcmSvc;
177
178
179/*********************************************************************************************************************************
180* Prototypes. *
181*********************************************************************************************************************************/
182DECLINLINE(PTSTHGCMMOCKSVC) tstHgcmMockSvcInst(void);
183
184
185/*********************************************************************************************************************************
186* Internal functions *
187*********************************************************************************************************************************/
188
189/**
190 * Initializes a HGCM mock client.
191 *
192 * @return VBox status code.
193 * @param pClient Client instance to initialize.
194 * @param idClient HGCM client ID to assign.
195 * @param cbClient Size (in bytes) of service-specific (opaque) client data to allocate.
196 */
197static int tstHgcmMockClientInit(PTSTHGCMMOCKCLIENT pClient, uint32_t idClient, size_t cbClient)
198{
199 RT_BZERO(pClient, sizeof(TSTHGCMMOCKCLIENT));
200
201 pClient->idClient = idClient;
202 if (cbClient)
203 {
204 pClient->pvClient = RTMemAllocZ(cbClient);
205 AssertPtrReturn(pClient->pvClient, VERR_NO_MEMORY);
206 pClient->cbClient = cbClient;
207 }
208
209 return RTSemEventCreate(&pClient->hEvent);
210}
211
212/**
213 * Destroys a HGCM mock client.
214 *
215 * @return VBox status code.
216 * @param pClient Client instance to destroy.
217 */
218static int tstHgcmMockClientDestroy(PTSTHGCMMOCKCLIENT pClient)
219{
220 int rc = RTSemEventDestroy(pClient->hEvent);
221 if (RT_SUCCESS(rc))
222 {
223 if (pClient->pvClient)
224 {
225 Assert(pClient->cbClient);
226 RTMemFree(pClient->pvClient);
227 pClient->pvClient = NULL;
228 pClient->cbClient = 0;
229 }
230
231 pClient->hEvent = NIL_RTSEMEVENT;
232 }
233
234 return rc;
235}
236
237/* @copydoc VBOXHGCMSVCFNTABLE::pfnConnect */
238static DECLCALLBACK(int) tstHgcmMockSvcConnect(PTSTHGCMMOCKSVC pSvc, void *pvService, uint32_t *pidClient)
239{
240 RT_NOREF(pvService);
241
242 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
243 AssertPtrReturn(pFn, VERR_NO_MEMORY);
244
245 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[pSvc->uNextClientId];
246
247 int rc = tstHgcmMockClientInit(pClient, pSvc->uNextClientId, pSvc->cbClient);
248 if (RT_FAILURE(rc))
249 return rc;
250
251 pFn->enmType = TSTHGCMMOCKFNTYPE_CONNECT;
252 pFn->pClient = pClient;
253
254 RTListAppend(&pSvc->lstCall, &pFn->Node);
255 pFn = NULL; /* Thread takes ownership now. */
256
257 int rc2 = RTSemEventSignal(pSvc->hEventQueue);
258 AssertRCReturn(rc2, rc2);
259 rc2 = RTSemEventWait(pClient->hEvent, RT_MS_30SEC);
260 AssertRCReturn(rc2, rc2);
261
262 ASMAtomicIncU32(&pSvc->uNextClientId);
263
264 *pidClient = pClient->idClient;
265
266 return VINF_SUCCESS;
267}
268
269/* @copydoc VBOXHGCMSVCFNTABLE::pfnDisconnect */
270static DECLCALLBACK(int) tstHgcmMockSvcDisconnect(PTSTHGCMMOCKSVC pSvc, void *pvService, uint32_t idClient)
271{
272 RT_NOREF(pvService);
273
274 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[idClient];
275
276 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
277 AssertPtrReturn(pFn, VERR_NO_MEMORY);
278
279 pFn->enmType = TSTHGCMMOCKFNTYPE_DISCONNECT;
280 pFn->pClient = pClient;
281
282 RTListAppend(&pSvc->lstCall, &pFn->Node);
283 pFn = NULL; /* Thread takes ownership now. */
284
285 int rc2 = RTSemEventSignal(pSvc->hEventQueue);
286 AssertRCReturn(rc2, rc2);
287
288 rc2 = RTSemEventWait(pClient->hEvent, RT_MS_30SEC);
289 AssertRCReturn(rc2, rc2);
290
291 return tstHgcmMockClientDestroy(pClient);
292}
293
294/* @copydoc VBOXHGCMSVCFNTABLE::pfnCall */
295static DECLCALLBACK(int) tstHgcmMockSvcCall(PTSTHGCMMOCKSVC pSvc, void *pvService, VBOXHGCMCALLHANDLE callHandle, uint32_t idClient, void *pvClient,
296 int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
297{
298 RT_NOREF(pvService, pvClient);
299
300 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[idClient];
301
302 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
303 AssertPtrReturn(pFn, VERR_NO_MEMORY);
304
305 const size_t cbParms = cParms * sizeof(VBOXHGCMSVCPARM);
306
307 pFn->enmType = TSTHGCMMOCKFNTYPE_CALL;
308 pFn->pClient = pClient;
309
310 pFn->u.Call.hCall = callHandle;
311 pFn->u.Call.iFunc = function;
312 pFn->u.Call.pParms = (PVBOXHGCMSVCPARM)RTMemDup(paParms, cbParms);
313 AssertPtrReturn(pFn->u.Call.pParms, VERR_NO_MEMORY);
314 pFn->u.Call.cParms = cParms;
315
316 RTListAppend(&pSvc->lstCall, &pFn->Node);
317
318 int rc2 = RTSemEventSignal(pSvc->hEventQueue);
319 AssertRCReturn(rc2, rc2);
320
321 rc2 = RTSemEventWait(pClient->hEvent, RT_INDEFINITE_WAIT);
322 AssertRCReturn(rc2, rc2);
323
324 memcpy(paParms, pFn->u.Call.pParms, cbParms);
325
326 return VINF_SUCCESS; /** @todo Return host call rc */
327}
328
329/* @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall */
330static DECLCALLBACK(int) tstHgcmMockSvcHostCall(PTSTHGCMMOCKSVC pSvc, void *pvService, int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
331{
332 RT_NOREF(pvService);
333 AssertReturn(pSvc->cHostCallers == 0, VERR_WRONG_ORDER); /* Only one host call at a time. */
334
335 pSvc->cHostCallers++;
336
337 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
338 AssertPtrReturn(pFn, VERR_INVALID_POINTER);
339
340 pFn->enmType = TSTHGCMMOCKFNTYPE_HOST_CALL;
341 pFn->u.HostCall.iFunc = function;
342 if (cParms)
343 {
344 pFn->u.HostCall.pParms = (PVBOXHGCMSVCPARM)RTMemDup(paParms, cParms * sizeof(VBOXHGCMSVCPARM));
345 AssertPtrReturn(pFn->u.HostCall.pParms, VERR_NO_MEMORY);
346 pFn->u.HostCall.cParms = cParms;
347 }
348
349 RTListAppend(&pSvc->lstCall, &pFn->Node);
350 pFn = NULL; /* Thread takes ownership now. */
351
352 int rc2 = RTSemEventSignal(pSvc->hEventQueue);
353 AssertRC(rc2);
354
355 rc2 = RTSemEventWait(pSvc->hEventHostCall, RT_INDEFINITE_WAIT);
356 AssertRCReturn(rc2, rc2);
357
358 Assert(pSvc->cHostCallers);
359 pSvc->cHostCallers--;
360
361 return pSvc->rcHostCall;
362}
363
364/**
365 * Call completion callback for guest calls.
366 *
367 * @return VBox status code.
368 * @param callHandle Call handle to complete.
369 * @param rc Return code to return to the caller.
370 */
371static DECLCALLBACK(int) tstHgcmMockSvcCallComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc)
372{
373 PTSTHGCMMOCKSVC pSvc = tstHgcmMockSvcInst();
374
375 for (size_t i = 0; RT_ELEMENTS(pSvc->aHgcmClient); i++)
376 {
377 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[i];
378 if (&pClient->hCall == callHandle) /* Slow, but works for now. */
379 {
380 if (rc == VINF_HGCM_ASYNC_EXECUTE)
381 {
382 Assert(pClient->fAsyncExec == false);
383 }
384 else /* Complete call + notify client. */
385 {
386 callHandle->rc = rc;
387
388 int rc2 = RTSemEventSignal(pClient->hEvent);
389 AssertRCReturn(rc2, rc2);
390 }
391
392 return VINF_SUCCESS;
393 }
394 }
395
396 return VERR_NOT_FOUND;
397}
398
399/**
400 * Main thread of HGCM mock service.
401 *
402 * @return VBox status code.
403 * @param hThread Thread handle.
404 * @param pvUser User-supplied data of type PTSTHGCMMOCKSVC.
405 */
406static DECLCALLBACK(int) tstHgcmMockSvcThread(RTTHREAD hThread, void *pvUser)
407{
408 RT_NOREF(hThread);
409 PTSTHGCMMOCKSVC pSvc = (PTSTHGCMMOCKSVC)pvUser;
410
411 pSvc->uNextClientId = 0;
412
413 pSvc->fnTable.cbSize = sizeof(pSvc->fnTable);
414 pSvc->fnTable.u32Version = VBOX_HGCM_SVC_VERSION;
415
416 RT_ZERO(pSvc->fnHelpers);
417 pSvc->fnHelpers.pfnCallComplete = tstHgcmMockSvcCallComplete;
418 pSvc->fnTable.pHelpers = &pSvc->fnHelpers;
419
420 int rc = VBoxHGCMSvcLoad(&pSvc->fnTable);
421 if (RT_SUCCESS(rc))
422 {
423 RTThreadUserSignal(hThread);
424
425 for (;;)
426 {
427 rc = RTSemEventWait(pSvc->hEventQueue, 10 /* ms */);
428 if (ASMAtomicReadBool(&pSvc->fShutdown))
429 {
430 rc = VINF_SUCCESS;
431 break;
432 }
433 if (rc == VERR_TIMEOUT)
434 continue;
435
436 PTSTHGCMMOCKFN pFn = RTListGetFirst(&pSvc->lstCall, TSTHGCMMOCKFN, Node);
437 if (pFn)
438 {
439 switch (pFn->enmType)
440 {
441 case TSTHGCMMOCKFNTYPE_CONNECT:
442 {
443 rc = pSvc->fnTable.pfnConnect(pSvc->fnTable.pvService,
444 pFn->pClient->idClient, pFn->pClient->pvClient,
445 VMMDEV_REQUESTOR_USR_NOT_GIVEN /* fRequestor */, false /* fRestoring */);
446
447 int rc2 = RTSemEventSignal(pFn->pClient->hEvent);
448 AssertRC(rc2);
449 break;
450 }
451
452 case TSTHGCMMOCKFNTYPE_DISCONNECT:
453 {
454 rc = pSvc->fnTable.pfnDisconnect(pSvc->fnTable.pvService,
455 pFn->pClient->idClient, pFn->pClient->pvClient);
456
457 int rc2 = RTSemEventSignal(pFn->pClient->hEvent);
458 AssertRC(rc2);
459 break;
460 }
461
462 case TSTHGCMMOCKFNTYPE_CALL:
463 {
464 pSvc->fnTable.pfnCall(NULL, pFn->u.Call.hCall, pFn->pClient->idClient, pFn->pClient->pvClient,
465 pFn->u.Call.iFunc, pFn->u.Call.cParms, pFn->u.Call.pParms, RTTimeMilliTS());
466
467 /* Note: Call will be completed in the call completion callback. */
468 break;
469 }
470
471 case TSTHGCMMOCKFNTYPE_HOST_CALL:
472 {
473 pSvc->rcHostCall = pSvc->fnTable.pfnHostCall(NULL, pFn->u.HostCall.iFunc, pFn->u.HostCall.cParms, pFn->u.HostCall.pParms);
474
475 int rc2 = RTSemEventSignal(pSvc->hEventHostCall);
476 AssertRC(rc2);
477 break;
478 }
479
480 default:
481 AssertFailed();
482 break;
483 }
484 RTListNodeRemove(&pFn->Node);
485 RTMemFree(pFn);
486 }
487 }
488 }
489
490 return rc;
491}
492
493
494/*********************************************************************************************************************************
495* Public functions *
496*********************************************************************************************************************************/
497
498/**
499 * Returns the pointer to the HGCM mock service instance.
500 *
501 * @return Pointer to HGCM mock service instance.
502 */
503DECLINLINE(PTSTHGCMMOCKSVC) tstHgcmMockSvcInst(void)
504{
505 return &s_tstHgcmSvc;
506}
507
508/**
509 * Waits for a HGCM mock client to connect.
510 *
511 * @return VBox status code.
512 * @param pSvc HGCM mock service instance.
513 */
514static PTSTHGCMMOCKCLIENT tstHgcmMockSvcWaitForConnect(PTSTHGCMMOCKSVC pSvc)
515{
516 int rc = RTSemEventWait(pSvc->hEventWait, RT_MS_30SEC);
517 if (RT_SUCCESS(rc))
518 {
519 Assert(pSvc->uNextClientId);
520 return &pSvc->aHgcmClient[pSvc->uNextClientId - 1];
521 }
522 return NULL;
523}
524
525/**
526 * Creates a HGCM mock service instance.
527 *
528 * @return VBox status code.
529 * @param pSvc HGCM mock service instance to create.
530 * @param cbClient Size (in bytes) of service-specific client data to
531 * allocate for a HGCM mock client.
532 */
533static int tstHgcmMockSvcCreate(PTSTHGCMMOCKSVC pSvc, size_t cbClient)
534{
535 AssertReturn(cbClient, VERR_INVALID_PARAMETER);
536
537 RT_ZERO(pSvc->aHgcmClient);
538 pSvc->fShutdown = false;
539 int rc = RTSemEventCreate(&pSvc->hEventQueue);
540 if (RT_SUCCESS(rc))
541 {
542 rc = RTSemEventCreate(&pSvc->hEventHostCall);
543 if (RT_SUCCESS(rc))
544 {
545 rc = RTSemEventCreate(&pSvc->hEventWait);
546 if (RT_SUCCESS(rc))
547 {
548 RTListInit(&pSvc->lstCall);
549
550 pSvc->cbClient = cbClient;
551 }
552 }
553 }
554
555 return rc;
556}
557
558/**
559 * Destroys a HGCM mock service instance.
560 *
561 * @return VBox status code.
562 * @param pSvc HGCM mock service instance to destroy.
563 */
564static int tstHgcmMockSvcDestroy(PTSTHGCMMOCKSVC pSvc)
565{
566 int rc = RTSemEventDestroy(pSvc->hEventQueue);
567 if (RT_SUCCESS(rc))
568 {
569 rc = RTSemEventDestroy(pSvc->hEventHostCall);
570 if (RT_SUCCESS(rc))
571 RTSemEventDestroy(pSvc->hEventWait);
572 }
573 return rc;
574}
575
576/**
577 * Starts a HGCM mock service instance.
578 *
579 * @return VBox status code.
580 * @param pSvc HGCM mock service instance to start.
581 */
582static int tstHgcmMockSvcStart(PTSTHGCMMOCKSVC pSvc)
583{
584 int rc = RTThreadCreate(&pSvc->hThread, tstHgcmMockSvcThread, pSvc, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
585 "MockSvc");
586 if (RT_SUCCESS(rc))
587 rc = RTThreadUserWait(pSvc->hThread, RT_MS_30SEC);
588
589 return rc;
590}
591
592/**
593 * Stops a HGCM mock service instance.
594 *
595 * @return VBox status code.
596 * @param pSvc HGCM mock service instance to stop.
597 */
598static int tstHgcmMockSvcStop(PTSTHGCMMOCKSVC pSvc)
599{
600 ASMAtomicWriteBool(&pSvc->fShutdown, true);
601
602 int rcThread;
603 int rc = RTThreadWait(pSvc->hThread, RT_MS_30SEC, &rcThread);
604 if (RT_SUCCESS(rc))
605 rc = rcThread;
606 if (RT_SUCCESS(rc))
607 {
608 pSvc->hThread = NIL_RTTHREAD;
609 }
610
611 return rc;
612}
613
614
615/*********************************************************************************************************************************
616* VbglR3 stubs *
617*********************************************************************************************************************************/
618
619/**
620 * Connects to an HGCM mock service.
621 *
622 * @returns VBox status code
623 * @param pszServiceName Name of the host service.
624 * @param pidClient Where to put the client ID on success. The client ID
625 * must be passed to all the other calls to the service.
626 */
627VBGLR3DECL(int) VbglR3HGCMConnect(const char *pszServiceName, HGCMCLIENTID *pidClient)
628{
629 RT_NOREF(pszServiceName);
630
631 PTSTHGCMMOCKSVC pSvc = tstHgcmMockSvcInst();
632
633 return tstHgcmMockSvcConnect(pSvc, pSvc->fnTable.pvService, pidClient);
634}
635
636/**
637 * Disconnect from an HGCM mock service.
638 *
639 * @returns VBox status code.
640 * @param idClient The client id returned by VbglR3HGCMConnect().
641 */
642VBGLR3DECL(int) VbglR3HGCMDisconnect(HGCMCLIENTID idClient)
643{
644 PTSTHGCMMOCKSVC pSvc = tstHgcmMockSvcInst();
645
646 return tstHgcmMockSvcDisconnect(pSvc, pSvc->fnTable.pvService, idClient);
647}
648
649/**
650 * Makes a fully prepared HGCM call to an HGCM mock service.
651 *
652 * @returns VBox status code.
653 * @param pInfo Fully prepared HGCM call info.
654 * @param cbInfo Size of the info. This may sometimes be larger than
655 * what the parameter count indicates because of
656 * parameter changes between versions and such.
657 */
658VBGLR3DECL(int) VbglR3HGCMCall(PVBGLIOCHGCMCALL pInfo, size_t cbInfo)
659{
660 AssertMsg(pInfo->Hdr.cbIn == cbInfo, ("cbIn=%#x cbInfo=%#zx\n", pInfo->Hdr.cbIn, cbInfo));
661 AssertMsg(pInfo->Hdr.cbOut == cbInfo, ("cbOut=%#x cbInfo=%#zx\n", pInfo->Hdr.cbOut, cbInfo));
662 Assert(sizeof(*pInfo) + pInfo->cParms * sizeof(HGCMFunctionParameter) <= cbInfo);
663
664 HGCMFunctionParameter *offSrcParms = VBGL_HGCM_GET_CALL_PARMS(pInfo);
665 PVBOXHGCMSVCPARM paDstParms = (PVBOXHGCMSVCPARM)RTMemAlloc(pInfo->cParms * sizeof(VBOXHGCMSVCPARM));
666 for (uint16_t i = 0; i < pInfo->cParms; i++)
667 {
668 switch (offSrcParms->type)
669 {
670 case VMMDevHGCMParmType_32bit:
671 {
672 paDstParms[i].type = VBOX_HGCM_SVC_PARM_32BIT;
673 paDstParms[i].u.uint32 = offSrcParms->u.value32;
674 break;
675 }
676
677 case VMMDevHGCMParmType_64bit:
678 {
679 paDstParms[i].type = VBOX_HGCM_SVC_PARM_64BIT;
680 paDstParms[i].u.uint64 = offSrcParms->u.value64;
681 break;
682 }
683
684 case VMMDevHGCMParmType_LinAddr:
685 {
686 paDstParms[i].type = VBOX_HGCM_SVC_PARM_PTR;
687 paDstParms[i].u.pointer.addr = (void *)offSrcParms->u.LinAddr.uAddr;
688 paDstParms[i].u.pointer.size = offSrcParms->u.LinAddr.cb;
689 break;
690 }
691
692 default:
693 AssertFailed();
694 break;
695 }
696
697 offSrcParms++;
698 }
699
700 PTSTHGCMMOCKSVC const pSvc = tstHgcmMockSvcInst();
701
702 int rc2 = tstHgcmMockSvcCall(pSvc, pSvc->fnTable.pvService, &pSvc->aHgcmClient[pInfo->u32ClientID].hCall,
703 pInfo->u32ClientID, pSvc->aHgcmClient[pInfo->u32ClientID].pvClient,
704 pInfo->u32Function, pInfo->cParms, paDstParms);
705 if (RT_SUCCESS(rc2))
706 {
707 offSrcParms = VBGL_HGCM_GET_CALL_PARMS(pInfo);
708
709 for (uint16_t i = 0; i < pInfo->cParms; i++)
710 {
711 paDstParms[i].type = offSrcParms->type;
712 switch (paDstParms[i].type)
713 {
714 case VMMDevHGCMParmType_32bit:
715 offSrcParms->u.value32 = paDstParms[i].u.uint32;
716 break;
717
718 case VMMDevHGCMParmType_64bit:
719 offSrcParms->u.value64 = paDstParms[i].u.uint64;
720 break;
721
722 case VMMDevHGCMParmType_LinAddr:
723 {
724 offSrcParms->u.LinAddr.cb = paDstParms[i].u.pointer.size;
725 break;
726 }
727
728 default:
729 AssertFailed();
730 break;
731 }
732
733 offSrcParms++;
734 }
735 }
736
737 RTMemFree(paDstParms);
738
739 if (RT_SUCCESS(rc2))
740 rc2 = pSvc->aHgcmClient[pInfo->u32ClientID].hCall.rc;
741
742 return rc2;
743}
744
745RT_C_DECLS_END
Note: See TracBrowser for help on using the repository browser.

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