VirtualBox

source: vbox/trunk/src/VBox/HostServices/testcase/TstHGCMMock.cpp@ 103068

Last change on this file since 103068 was 98587, checked in by vboxsync, 22 months ago

HostServices/TstHGCMMock.cpp: fixed memory leak that upsets the tests in asan builds and documented ownership assumptions surrounding it.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.0 KB
Line 
1/* $Id: TstHGCMMock.cpp 98587 2023-02-15 13:23:05Z vboxsync $ */
2/** @file
3 * TstHGCMMock.cpp - Mocking framework for testing HGCM-based host services.
4 *
5 * The goal is to run host service + Vbgl code as unmodified as possible as
6 * part of testcases to gain test coverage which otherwise wouldn't possible
7 * for heavily user-centric features like Shared Clipboard or drag'n drop (DnD).
8 *
9 * Currently, though, it's only the service that runs unmodified, the
10 * testcases does custom Vbgl work.
11 */
12
13/*
14 * Copyright (C) 2022-2023 Oracle and/or its affiliates.
15 *
16 * This file is part of VirtualBox base platform packages, as
17 * available from https://www.virtualbox.org.
18 *
19 * This program is free software; you can redistribute it and/or
20 * modify it under the terms of the GNU General Public License
21 * as published by the Free Software Foundation, in version 3 of the
22 * License.
23 *
24 * This program is distributed in the hope that it will be useful, but
25 * WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, see <https://www.gnu.org/licenses>.
31 *
32 * SPDX-License-Identifier: GPL-3.0-only
33 */
34
35
36/*********************************************************************************************************************************
37* Header Files *
38*********************************************************************************************************************************/
39#include <VBox/HostServices/TstHGCMMock.h>
40
41#include <iprt/asm.h>
42#include <iprt/assert.h>
43#include <iprt/list.h>
44#include <iprt/mem.h>
45#include <iprt/rand.h>
46#include <iprt/semaphore.h>
47#include <iprt/test.h>
48#include <iprt/time.h>
49#include <iprt/thread.h>
50#include <iprt/utf16.h>
51
52#include <VBox/err.h>
53#include <VBox/VBoxGuestLib.h>
54#include <VBox/hgcmsvc.h>
55
56
57/*********************************************************************************************************************************
58* Global Variables *
59*********************************************************************************************************************************/
60/** Static HGCM service to mock. */
61static TSTHGCMMOCKSVC g_tstHgcmSvc;
62
63
64/*********************************************************************************************************************************
65* Internal functions *
66*********************************************************************************************************************************/
67
68/**
69 * Initializes a HGCM mock client.
70 *
71 * @return VBox status code.
72 * @param pClient Client instance to initialize.
73 * @param idClient HGCM client ID to assign.
74 * @param cbClient Size (in bytes) of service-specific (opaque) client data to allocate.
75 */
76static int tstHgcmMockClientInit(PTSTHGCMMOCKCLIENT pClient, uint32_t idClient, size_t cbClient)
77{
78 RT_BZERO(pClient, sizeof(TSTHGCMMOCKCLIENT));
79
80 pClient->idClient = idClient;
81 if (cbClient)
82 {
83 pClient->pvClient = RTMemAllocZ(cbClient);
84 AssertPtrReturn(pClient->pvClient, VERR_NO_MEMORY);
85 pClient->cbClient = cbClient;
86 }
87
88 return RTSemEventCreate(&pClient->hEvent);
89}
90
91/**
92 * Destroys a HGCM mock client.
93 *
94 * @return VBox status code.
95 * @param pClient Client instance to destroy.
96 */
97static int tstHgcmMockClientDestroy(PTSTHGCMMOCKCLIENT pClient)
98{
99 int rc = RTSemEventDestroy(pClient->hEvent);
100 if (RT_SUCCESS(rc))
101 {
102 if (pClient->pvClient)
103 {
104 Assert(pClient->cbClient);
105 RTMemFree(pClient->pvClient);
106 pClient->pvClient = NULL;
107 pClient->cbClient = 0;
108 }
109
110 pClient->hEvent = NIL_RTSEMEVENT;
111 }
112
113 return rc;
114}
115
116/** @copydoc VBOXHGCMSVCFNTABLE::pfnConnect */
117static DECLCALLBACK(int) tstHgcmMockSvcConnect(PTSTHGCMMOCKSVC pSvc, void *pvService, uint32_t *pidClient)
118{
119 RT_NOREF(pvService);
120
121 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
122 AssertPtrReturn(pFn, VERR_NO_MEMORY);
123
124 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[pSvc->uNextClientId];
125
126 int rc = tstHgcmMockClientInit(pClient, pSvc->uNextClientId, pSvc->fnTable.cbClient);
127 if (RT_FAILURE(rc))
128 return rc;
129
130 pFn->enmType = TSTHGCMMOCKFNTYPE_CONNECT;
131 pFn->pClient = pClient;
132
133 RTListAppend(&pSvc->lstCall, &pFn->Node);
134 pFn = NULL; /* Thread takes ownership now. */
135
136 int rc2 = RTSemEventSignal(pSvc->hEventQueue);
137 AssertRCReturn(rc2, rc2);
138 rc2 = RTSemEventWait(pClient->hEvent, RT_MS_30SEC);
139 AssertRCReturn(rc2, rc2);
140
141 ASMAtomicIncU32(&pSvc->uNextClientId);
142
143 rc2 = RTSemEventSignal(pSvc->hEventConnect);
144 AssertRCReturn(rc2, rc2);
145
146 *pidClient = pClient->idClient;
147
148 return VINF_SUCCESS;
149}
150
151/** @copydoc VBOXHGCMSVCFNTABLE::pfnDisconnect */
152static DECLCALLBACK(int) tstHgcmMockSvcDisconnect(PTSTHGCMMOCKSVC pSvc, void *pvService, uint32_t idClient)
153{
154 RT_NOREF(pvService);
155
156 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[idClient];
157
158 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
159 AssertPtrReturn(pFn, VERR_NO_MEMORY);
160
161 pFn->enmType = TSTHGCMMOCKFNTYPE_DISCONNECT;
162 pFn->pClient = pClient;
163
164 RTListAppend(&pSvc->lstCall, &pFn->Node);
165 pFn = NULL; /* Thread takes ownership now. */
166
167 int rc2 = RTSemEventSignal(pSvc->hEventQueue);
168 AssertRCReturn(rc2, rc2);
169
170 rc2 = RTSemEventWait(pClient->hEvent, RT_MS_30SEC);
171 AssertRCReturn(rc2, rc2);
172
173 return tstHgcmMockClientDestroy(pClient);
174}
175
176/** @copydoc VBOXHGCMSVCFNTABLE::pfnCall */
177static DECLCALLBACK(int) tstHgcmMockSvcCall(PTSTHGCMMOCKSVC pSvc, void *pvService, VBOXHGCMCALLHANDLE callHandle, uint32_t idClient, void *pvClient,
178 int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
179{
180 RT_NOREF(pvService, pvClient);
181
182 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[idClient];
183
184 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
185 AssertPtrReturn(pFn, VERR_NO_MEMORY);
186
187 const size_t cbParms = cParms * sizeof(VBOXHGCMSVCPARM);
188
189 pFn->enmType = TSTHGCMMOCKFNTYPE_CALL;
190 pFn->pClient = pClient;
191
192 pFn->u.Call.hCall = callHandle;
193 pFn->u.Call.iFunc = function;
194 pFn->u.Call.cParms = cParms;
195 PVBOXHGCMSVCPARM const paParmsCopy = (PVBOXHGCMSVCPARM)RTMemDup(paParms, cbParms);
196 pFn->u.Call.pParms = paParmsCopy;
197 AssertPtrReturn(paParmsCopy, VERR_NO_MEMORY);
198
199 RTListAppend(&pSvc->lstCall, &pFn->Node);
200 pFn = NULL; /* Thread takes ownership now. We keep ownership of paParmsCopy. */
201
202 int rc2 = RTSemEventSignal(pSvc->hEventQueue);
203 AssertRCReturn(rc2, rc2);
204
205 rc2 = RTSemEventWait(pClient->hEvent, RT_INDEFINITE_WAIT);
206 AssertRCReturn(rc2, rc2);
207
208 memcpy(paParms, paParmsCopy, cbParms);
209 RTMemFree(paParmsCopy);
210
211 return VINF_SUCCESS; /** @todo Return host call rc */
212}
213
214/** @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall
215 * @note Public for also being able to test host calls via testcases. */
216int TstHgcmMockSvcHostCall(PTSTHGCMMOCKSVC pSvc, void *pvService, int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
217{
218 RT_NOREF(pvService);
219 AssertReturn(pSvc->cHostCallers == 0, VERR_WRONG_ORDER); /* Only one host call at a time. */
220
221 pSvc->cHostCallers++;
222
223 PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN));
224 AssertPtrReturn(pFn, VERR_INVALID_POINTER);
225
226 pFn->enmType = TSTHGCMMOCKFNTYPE_HOST_CALL;
227 pFn->u.HostCall.iFunc = function;
228 if (cParms)
229 {
230 pFn->u.HostCall.pParms = (PVBOXHGCMSVCPARM)RTMemDup(paParms, cParms * sizeof(VBOXHGCMSVCPARM));
231 AssertPtrReturn(pFn->u.HostCall.pParms, VERR_NO_MEMORY);
232 pFn->u.HostCall.cParms = cParms;
233 }
234
235 RTListAppend(&pSvc->lstCall, &pFn->Node);
236 pFn = NULL; /* Thread takes ownership now. */
237
238 int rc2 = RTSemEventSignal(pSvc->hEventQueue);
239 AssertRC(rc2);
240
241 rc2 = RTSemEventWait(pSvc->hEventHostCall, RT_INDEFINITE_WAIT);
242 AssertRCReturn(rc2, rc2);
243
244 Assert(pSvc->cHostCallers);
245 pSvc->cHostCallers--;
246
247 return pSvc->rcHostCall;
248}
249
250/**
251 * Call completion callback for guest calls.
252 *
253 * @return VBox status code.
254 * @param callHandle Call handle to complete.
255 * @param rc Return code to return to the caller.
256 */
257static DECLCALLBACK(int) tstHgcmMockSvcCallComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc)
258{
259 PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst();
260
261 size_t i = 0;
262 for (; RT_ELEMENTS(pSvc->aHgcmClient); i++)
263 {
264 PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[i];
265 if (&pClient->hCall == callHandle) /* Slow, but works for now. */
266 {
267 if (rc == VINF_HGCM_ASYNC_EXECUTE)
268 {
269 Assert(pClient->fAsyncExec == false);
270 }
271 else /* Complete call + notify client. */
272 {
273 callHandle->rc = rc;
274
275 int rc2 = RTSemEventSignal(pClient->hEvent);
276 AssertRCReturn(rc2, rc2);
277 }
278
279 return VINF_SUCCESS;
280 }
281 }
282
283 return VERR_NOT_FOUND;
284}
285
286/**
287 * Main thread of HGCM mock service.
288 *
289 * @return VBox status code.
290 * @param hThread Thread handle.
291 * @param pvUser User-supplied data of type PTSTHGCMMOCKSVC.
292 */
293static DECLCALLBACK(int) tstHgcmMockSvcThread(RTTHREAD hThread, void *pvUser)
294{
295 RT_NOREF(hThread);
296 PTSTHGCMMOCKSVC pSvc = (PTSTHGCMMOCKSVC)pvUser;
297
298 pSvc->uNextClientId = 0;
299
300 pSvc->fnTable.cbSize = sizeof(pSvc->fnTable);
301 pSvc->fnTable.u32Version = VBOX_HGCM_SVC_VERSION;
302
303 RT_ZERO(pSvc->fnHelpers);
304 pSvc->fnHelpers.pfnCallComplete = tstHgcmMockSvcCallComplete;
305 pSvc->fnTable.pHelpers = &pSvc->fnHelpers;
306
307 int rc = VBoxHGCMSvcLoad(&pSvc->fnTable);
308 if (RT_SUCCESS(rc))
309 {
310 RTThreadUserSignal(hThread);
311
312 for (;;)
313 {
314 rc = RTSemEventWait(pSvc->hEventQueue, 10 /* ms */);
315 if (ASMAtomicReadBool(&pSvc->fShutdown))
316 {
317 rc = VINF_SUCCESS;
318 break;
319 }
320 if (rc == VERR_TIMEOUT)
321 continue;
322
323 PTSTHGCMMOCKFN pFn = RTListGetFirst(&pSvc->lstCall, TSTHGCMMOCKFN, Node);
324 if (pFn)
325 {
326 switch (pFn->enmType)
327 {
328 case TSTHGCMMOCKFNTYPE_CONNECT:
329 {
330 rc = pSvc->fnTable.pfnConnect(pSvc->fnTable.pvService,
331 pFn->pClient->idClient, pFn->pClient->pvClient,
332 VMMDEV_REQUESTOR_USR_NOT_GIVEN /* fRequestor */, false /* fRestoring */);
333
334 int rc2 = RTSemEventSignal(pFn->pClient->hEvent);
335 AssertRC(rc2);
336 break;
337 }
338
339 case TSTHGCMMOCKFNTYPE_DISCONNECT:
340 {
341 rc = pSvc->fnTable.pfnDisconnect(pSvc->fnTable.pvService,
342 pFn->pClient->idClient, pFn->pClient->pvClient);
343
344 int rc2 = RTSemEventSignal(pFn->pClient->hEvent);
345 AssertRC(rc2);
346 break;
347 }
348
349 case TSTHGCMMOCKFNTYPE_CALL:
350 {
351 pSvc->fnTable.pfnCall(pSvc->fnTable.pvService, pFn->u.Call.hCall, pFn->pClient->idClient,
352 pFn->pClient->pvClient, pFn->u.Call.iFunc, pFn->u.Call.cParms,
353 pFn->u.Call.pParms, RTTimeNanoTS());
354
355 /* Note: Call will be completed in the call completion callback. */
356 break;
357 }
358
359 case TSTHGCMMOCKFNTYPE_HOST_CALL:
360 {
361 pSvc->rcHostCall = pSvc->fnTable.pfnHostCall(pSvc->fnTable.pvService, pFn->u.HostCall.iFunc,
362 pFn->u.HostCall.cParms, pFn->u.HostCall.pParms);
363
364 int rc2 = RTSemEventSignal(pSvc->hEventHostCall);
365 AssertRC(rc2);
366 break;
367 }
368
369 default:
370 AssertFailed();
371 break;
372 }
373 RTListNodeRemove(&pFn->Node);
374 RTMemFree(pFn); /* Note! caller frees the parameters? Or at least it uses them again. */
375 }
376 }
377 }
378
379 return rc;
380}
381
382
383/*********************************************************************************************************************************
384* Public functions *
385*********************************************************************************************************************************/
386
387/**
388 * Returns the pointer to the HGCM mock service instance.
389 *
390 * @return Pointer to HGCM mock service instance.
391 */
392PTSTHGCMMOCKSVC TstHgcmMockSvcInst(void)
393{
394 return &g_tstHgcmSvc;
395}
396
397/**
398 * Waits for a HGCM mock client to connect, extended version.
399 *
400 * @return Pointer to connected client, or NULL if ran into timeout.
401 * @param pSvc HGCM mock service instance.
402 * @param msTimeout Timeout (in ms) to wait for connection.
403 */
404PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnectEx(PTSTHGCMMOCKSVC pSvc, RTMSINTERVAL msTimeout)
405{
406 int rc = RTSemEventWait(pSvc->hEventConnect, msTimeout);
407 if (RT_SUCCESS(rc))
408 {
409 Assert(pSvc->uNextClientId);
410 return &pSvc->aHgcmClient[pSvc->uNextClientId - 1];
411 }
412 return NULL;
413}
414
415/**
416 * Waits for a HGCM mock client to connect.
417 *
418 * @return Pointer to connected client, or NULL if waiting for connection was aborted.
419 * @param pSvc HGCM mock service instance.
420 */
421PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnect(PTSTHGCMMOCKSVC pSvc)
422{
423 return TstHgcmMockSvcWaitForConnectEx(pSvc, RT_MS_30SEC);
424}
425
426/**
427 * Creates a HGCM mock service instance.
428 *
429 * @return VBox status code.
430 * @param pSvc HGCM mock service instance to create.
431 */
432int TstHgcmMockSvcCreate(PTSTHGCMMOCKSVC pSvc)
433{
434 RT_ZERO(pSvc->aHgcmClient);
435 pSvc->fShutdown = false;
436 int rc = RTSemEventCreate(&pSvc->hEventQueue);
437 if (RT_SUCCESS(rc))
438 {
439 rc = RTSemEventCreate(&pSvc->hEventHostCall);
440 if (RT_SUCCESS(rc))
441 {
442 rc = RTSemEventCreate(&pSvc->hEventConnect);
443 if (RT_SUCCESS(rc))
444 {
445 RTListInit(&pSvc->lstCall);
446 }
447 }
448 }
449
450 return rc;
451}
452
453/**
454 * Destroys a HGCM mock service instance.
455 *
456 * @return VBox status code.
457 * @param pSvc HGCM mock service instance to destroy.
458 */
459int TstHgcmMockSvcDestroy(PTSTHGCMMOCKSVC pSvc)
460{
461 int rc = RTSemEventDestroy(pSvc->hEventQueue);
462 if (RT_SUCCESS(rc))
463 {
464 rc = RTSemEventDestroy(pSvc->hEventHostCall);
465 if (RT_SUCCESS(rc))
466 RTSemEventDestroy(pSvc->hEventConnect);
467 }
468 return rc;
469}
470
471/**
472 * Starts a HGCM mock service instance.
473 *
474 * @return VBox status code.
475 * @param pSvc HGCM mock service instance to start.
476 */
477int TstHgcmMockSvcStart(PTSTHGCMMOCKSVC pSvc)
478{
479 int rc = RTThreadCreate(&pSvc->hThread, tstHgcmMockSvcThread, pSvc, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE,
480 "MockSvc");
481 if (RT_SUCCESS(rc))
482 rc = RTThreadUserWait(pSvc->hThread, RT_MS_30SEC);
483
484 return rc;
485}
486
487/**
488 * Stops a HGCM mock service instance.
489 *
490 * @return VBox status code.
491 * @param pSvc HGCM mock service instance to stop.
492 */
493int TstHgcmMockSvcStop(PTSTHGCMMOCKSVC pSvc)
494{
495 ASMAtomicWriteBool(&pSvc->fShutdown, true);
496
497 int rcThread;
498 int rc = RTThreadWait(pSvc->hThread, RT_MS_30SEC, &rcThread);
499 if (RT_SUCCESS(rc))
500 rc = rcThread;
501 if (RT_SUCCESS(rc))
502 pSvc->hThread = NIL_RTTHREAD;
503
504 return rc;
505}
506
507
508/*********************************************************************************************************************************
509* VbglR3 stubs *
510*********************************************************************************************************************************/
511
512/**
513 * Connects to an HGCM mock service.
514 *
515 * @returns VBox status code
516 * @param pszServiceName Name of the host service.
517 * @param pidClient Where to put the client ID on success. The client ID
518 * must be passed to all the other calls to the service.
519 */
520VBGLR3DECL(int) VbglR3HGCMConnect(const char *pszServiceName, HGCMCLIENTID *pidClient)
521{
522 RT_NOREF(pszServiceName);
523
524 PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst();
525
526 return tstHgcmMockSvcConnect(pSvc, pSvc->fnTable.pvService, pidClient);
527}
528
529/**
530 * Disconnect from an HGCM mock service.
531 *
532 * @returns VBox status code.
533 * @param idClient The client id returned by VbglR3HGCMConnect().
534 */
535VBGLR3DECL(int) VbglR3HGCMDisconnect(HGCMCLIENTID idClient)
536{
537 PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst();
538
539 return tstHgcmMockSvcDisconnect(pSvc, pSvc->fnTable.pvService, idClient);
540}
541
542/**
543 * Query the session ID of the mocked VM.
544 *
545 * @returns IPRT status code.
546 * @param pu64IdSession Session id (out).
547 */
548VBGLR3DECL(int) VbglR3GetSessionId(uint64_t *pu64IdSession)
549{
550 if (pu64IdSession)
551 *pu64IdSession = 42;
552 return VINF_SUCCESS;
553}
554
555/**
556 * Makes a fully prepared HGCM call to an HGCM mock service.
557 *
558 * @returns VBox status code.
559 * @param pInfo Fully prepared HGCM call info.
560 * @param cbInfo Size of the info. This may sometimes be larger than
561 * what the parameter count indicates because of
562 * parameter changes between versions and such.
563 */
564VBGLR3DECL(int) VbglR3HGCMCall(PVBGLIOCHGCMCALL pInfo, size_t cbInfo)
565{
566 RT_NOREF(cbInfo);
567
568 AssertMsg(pInfo->Hdr.cbIn == cbInfo, ("cbIn=%#x cbInfo=%#zx\n", pInfo->Hdr.cbIn, cbInfo));
569 AssertMsg(pInfo->Hdr.cbOut == cbInfo, ("cbOut=%#x cbInfo=%#zx\n", pInfo->Hdr.cbOut, cbInfo));
570 Assert(sizeof(*pInfo) + pInfo->cParms * sizeof(HGCMFunctionParameter) <= cbInfo);
571
572 HGCMFunctionParameter *offSrcParms = VBGL_HGCM_GET_CALL_PARMS(pInfo);
573 PVBOXHGCMSVCPARM paDstParms = (PVBOXHGCMSVCPARM)RTMemAlloc(pInfo->cParms * sizeof(VBOXHGCMSVCPARM));
574
575 uint16_t i = 0;
576 for (; i < pInfo->cParms; i++)
577 {
578 switch (offSrcParms->type)
579 {
580 case VMMDevHGCMParmType_32bit:
581 {
582 paDstParms[i].type = VBOX_HGCM_SVC_PARM_32BIT;
583 paDstParms[i].u.uint32 = offSrcParms->u.value32;
584 break;
585 }
586
587 case VMMDevHGCMParmType_64bit:
588 {
589 paDstParms[i].type = VBOX_HGCM_SVC_PARM_64BIT;
590 paDstParms[i].u.uint64 = offSrcParms->u.value64;
591 break;
592 }
593
594 case VMMDevHGCMParmType_LinAddr:
595 {
596 paDstParms[i].type = VBOX_HGCM_SVC_PARM_PTR;
597 paDstParms[i].u.pointer.addr = (void *)offSrcParms->u.LinAddr.uAddr;
598 paDstParms[i].u.pointer.size = offSrcParms->u.LinAddr.cb;
599 break;
600 }
601
602 default:
603 AssertFailed();
604 break;
605 }
606
607 offSrcParms++;
608 }
609
610 PTSTHGCMMOCKSVC const pSvc = TstHgcmMockSvcInst();
611
612 int rc2 = tstHgcmMockSvcCall(pSvc, pSvc->fnTable.pvService, &pSvc->aHgcmClient[pInfo->u32ClientID].hCall,
613 pInfo->u32ClientID, pSvc->aHgcmClient[pInfo->u32ClientID].pvClient,
614 pInfo->u32Function, pInfo->cParms, paDstParms);
615 if (RT_SUCCESS(rc2))
616 {
617 offSrcParms = VBGL_HGCM_GET_CALL_PARMS(pInfo);
618
619 for (i = 0; i < pInfo->cParms; i++)
620 {
621 paDstParms[i].type = offSrcParms->type;
622 switch (paDstParms[i].type)
623 {
624 case VMMDevHGCMParmType_32bit:
625 offSrcParms->u.value32 = paDstParms[i].u.uint32;
626 break;
627
628 case VMMDevHGCMParmType_64bit:
629 offSrcParms->u.value64 = paDstParms[i].u.uint64;
630 break;
631
632 case VMMDevHGCMParmType_LinAddr:
633 {
634 offSrcParms->u.LinAddr.cb = paDstParms[i].u.pointer.size;
635 break;
636 }
637
638 default:
639 AssertFailed();
640 break;
641 }
642
643 offSrcParms++;
644 }
645 }
646
647 RTMemFree(paDstParms);
648
649 if (RT_SUCCESS(rc2))
650 rc2 = pSvc->aHgcmClient[pInfo->u32ClientID].hCall.rc;
651
652 return rc2;
653}
654
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