VirtualBox

source: vbox/trunk/src/VBox/Devices/VMMDev/VMMDevHGCM.cpp@ 9584

Last change on this file since 9584 was 9435, checked in by vboxsync, 17 years ago

Extend HGCM interface to support 64 bit pointers.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.1 KB
Line 
1/** @file
2 *
3 * VBox Guest/VMM/host communication:
4 * HGCM - Host-Guest Communication Manager device
5 */
6
7/*
8 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23
24#include <iprt/alloc.h>
25#include <iprt/asm.h>
26#include <iprt/assert.h>
27#include <iprt/param.h>
28#include <iprt/string.h>
29
30#include <VBox/err.h>
31#include <VBox/hgcmsvc.h>
32
33#define LOG_GROUP LOG_GROUP_DEV_VMM
34#include <VBox/log.h>
35
36#include "VMMDevHGCM.h"
37
38typedef enum _VBOXHGCMCMDTYPE
39{
40 VBOXHGCMCMDTYPE_LOADSTATE,
41 VBOXHGCMCMDTYPE_CONNECT,
42 VBOXHGCMCMDTYPE_DISCONNECT,
43 VBOXHGCMCMDTYPE_CALL,
44 VBOXHGCMCMDTYPE_SizeHack = 0x7fffffff
45} VBOXHGCMCMDTYPE;
46
47/* Information about a linear ptr parameter. */
48typedef struct _VBOXHGCMLINPTR
49{
50 /* Index of the parameter. */
51 int iParm;
52
53 /* Offset in the first physical page of the region. */
54 size_t cbOffsetFirstPage;
55
56 /* How many pages. */
57 uint32_t cPages;
58
59 /* Pointer to array of the GC physical addresses for these pages.
60 * It is assumed that the physical address of the locked resident
61 * guest page does not change.
62 */
63 RTGCPHYS *paPages;
64
65} VBOXHGCMLINPTR;
66
67struct VBOXHGCMCMD
68{
69 /* Active commands, list is protected by critsectHGCMCmdList. */
70 struct VBOXHGCMCMD *pNext;
71 struct VBOXHGCMCMD *pPrev;
72
73 /* The type of the command. */
74 VBOXHGCMCMDTYPE enmCmdType;
75
76 /* GC physical address of the guest request. */
77 RTGCPHYS GCPhys;
78
79 /* Request packet size */
80 uint32_t cbSize;
81
82 /* Pointer to converted host parameters in case of a Call request. */
83 VBOXHGCMSVCPARM *paHostParms;
84
85 /* Linear pointer parameters information. */
86 int cLinPtrs;
87
88 /* Pointer to descriptions of linear pointers. */
89 VBOXHGCMLINPTR *paLinPtrs;
90};
91
92static int vmmdevHGCMCmdListLock (VMMDevState *pVMMDevState)
93{
94 int rc = RTCritSectEnter (&pVMMDevState->critsectHGCMCmdList);
95 AssertRC (rc);
96 return rc;
97}
98
99static void vmmdevHGCMCmdListUnlock (VMMDevState *pVMMDevState)
100{
101 int rc = RTCritSectLeave (&pVMMDevState->critsectHGCMCmdList);
102 AssertRC (rc);
103}
104
105static int vmmdevHGCMAddCommand (VMMDevState *pVMMDevState, PVBOXHGCMCMD pCmd, RTGCPHYS GCPhys, uint32_t cbSize, VBOXHGCMCMDTYPE enmCmdType)
106{
107 /* PPDMDEVINS pDevIns = pVMMDevState->pDevIns; */
108
109 int rc = vmmdevHGCMCmdListLock (pVMMDevState);
110
111 if (VBOX_SUCCESS (rc))
112 {
113 LogFlowFunc(("%p type %d\n", pCmd, enmCmdType));
114
115 /* Insert at the head of the list. The vmmdevHGCMLoadStateDone depends on this. */
116 pCmd->pNext = pVMMDevState->pHGCMCmdList;
117 pCmd->pPrev = NULL;
118
119 if (pVMMDevState->pHGCMCmdList)
120 {
121 pVMMDevState->pHGCMCmdList->pPrev = pCmd;
122 }
123
124 pVMMDevState->pHGCMCmdList = pCmd;
125
126 pCmd->enmCmdType = enmCmdType;
127 pCmd->GCPhys = GCPhys;
128 pCmd->cbSize = cbSize;
129
130 /* Automatically enable HGCM events, if there are HGCM commands. */
131 if ( enmCmdType == VBOXHGCMCMDTYPE_CONNECT
132 || enmCmdType == VBOXHGCMCMDTYPE_DISCONNECT
133 || enmCmdType == VBOXHGCMCMDTYPE_CALL)
134 {
135 Log(("vmmdevHGCMAddCommand: u32HGCMEnabled = %d\n", pVMMDevState->u32HGCMEnabled));
136 if (ASMAtomicCmpXchgU32(&pVMMDevState->u32HGCMEnabled, 1, 0))
137 {
138 VMMDevCtlSetGuestFilterMask (pVMMDevState, VMMDEV_EVENT_HGCM, 0);
139 }
140 }
141
142 vmmdevHGCMCmdListUnlock (pVMMDevState);
143 }
144
145 return rc;
146}
147
148static int vmmdevHGCMRemoveCommand (VMMDevState *pVMMDevState, PVBOXHGCMCMD pCmd)
149{
150 /* PPDMDEVINS pDevIns = pVMMDevState->pDevIns; */
151
152 int rc = vmmdevHGCMCmdListLock (pVMMDevState);
153
154 if (VBOX_SUCCESS (rc))
155 {
156 LogFlowFunc(("%p\n", pCmd));
157
158 if (pCmd->pNext)
159 {
160 pCmd->pNext->pPrev = pCmd->pPrev;
161 }
162 else
163 {
164 /* Tail, do nothing. */
165 }
166
167 if (pCmd->pPrev)
168 {
169 pCmd->pPrev->pNext = pCmd->pNext;
170 }
171 else
172 {
173 pVMMDevState->pHGCMCmdList = pCmd->pNext;
174 }
175
176 vmmdevHGCMCmdListUnlock (pVMMDevState);
177 }
178
179 return rc;
180}
181
182static int vmmdevHGCMSaveLinPtr (PPDMDEVINS pDevIns,
183 uint32_t iParm,
184 RTGCPTR GCPtr,
185 uint32_t u32Size,
186 uint32_t iLinPtr,
187 VBOXHGCMLINPTR *paLinPtrs,
188 RTGCPHYS **ppPages)
189{
190 int rc = VINF_SUCCESS;
191
192 AssertRelease (u32Size > 0);
193
194 VBOXHGCMLINPTR *pLinPtr = &paLinPtrs[iLinPtr];
195
196 /* Take the offset into the current page also into account! */
197 u32Size += GCPtr & PAGE_OFFSET_MASK;
198
199 uint32_t cPages = (u32Size + PAGE_SIZE - 1) / PAGE_SIZE;
200
201 Log(("vmmdevHGCMSaveLinPtr: parm %d: %VGv %d = %d pages\n", iParm, GCPtr, u32Size, cPages));
202
203 pLinPtr->iParm = iParm;
204 pLinPtr->cbOffsetFirstPage = (RTGCUINTPTR)GCPtr & PAGE_OFFSET_MASK;
205 pLinPtr->cPages = cPages;
206 pLinPtr->paPages = *ppPages;
207
208 *ppPages += cPages;
209
210 uint32_t iPage = 0;
211
212 GCPtr &= PAGE_BASE_GC_MASK;
213
214 /* Gonvert the guest linear pointers of pages to HC addresses. */
215 while (iPage < cPages)
216 {
217 /* convert */
218 RTGCPHYS GCPhys;
219
220 rc = PDMDevHlpPhysGCPtr2GCPhys(pDevIns, GCPtr, &GCPhys);
221
222 Log(("vmmdevHGCMSaveLinPtr: Page %d: %VGv -> %VGp. %Vrc\n", iPage, GCPtr, GCPhys, rc));
223
224 if (VBOX_FAILURE (rc))
225 {
226 break;
227 }
228
229 /* store */
230 pLinPtr->paPages[iPage++] = GCPhys;
231
232 /* next */
233 GCPtr += PAGE_SIZE;
234 }
235
236 AssertRelease (iPage == cPages);
237
238 return rc;
239}
240
241static int vmmdevHGCMWriteLinPtr (PPDMDEVINS pDevIns,
242 uint32_t iParm,
243 void *pvHost,
244 uint32_t u32Size,
245 uint32_t iLinPtr,
246 VBOXHGCMLINPTR *paLinPtrs)
247{
248 int rc = VINF_SUCCESS;
249
250 VBOXHGCMLINPTR *pLinPtr = &paLinPtrs[iLinPtr];
251
252 AssertRelease (u32Size > 0 && iParm == (uint32_t)pLinPtr->iParm);
253
254 RTGCPHYS GCPhysDst = pLinPtr->paPages[0] + pLinPtr->cbOffsetFirstPage;
255 uint8_t *pu8Src = (uint8_t *)pvHost;
256
257 Log(("vmmdevHGCMWriteLinPtr: parm %d: size %d, cPages = %d\n", iParm, u32Size, pLinPtr->cPages));
258
259 uint32_t iPage = 0;
260
261 while (iPage < pLinPtr->cPages)
262 {
263 /* copy */
264 size_t cbWrite = iPage == 0?
265 PAGE_SIZE - pLinPtr->cbOffsetFirstPage:
266 PAGE_SIZE;
267
268 Log(("vmmdevHGCMWriteLinPtr: page %d: dst %VGp, src %p, cbWrite %d\n", iPage, GCPhysDst, pu8Src, cbWrite));
269
270 iPage++;
271
272 if (cbWrite >= u32Size)
273 {
274 PDMDevHlpPhysWrite(pDevIns, GCPhysDst, pu8Src, u32Size);
275 u32Size = 0;
276 break;
277 }
278
279 PDMDevHlpPhysWrite(pDevIns, GCPhysDst, pu8Src, cbWrite);
280
281 /* next */
282 u32Size -= cbWrite;
283 pu8Src += cbWrite;
284
285 GCPhysDst = pLinPtr->paPages[iPage];
286 }
287
288 AssertRelease (iPage == pLinPtr->cPages);
289 Assert(u32Size == 0);
290
291 return rc;
292}
293
294int vmmdevHGCMConnect (VMMDevState *pVMMDevState, VMMDevHGCMConnect *pHGCMConnect, RTGCPHYS GCPhys)
295{
296 int rc = VINF_SUCCESS;
297
298 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAllocZ (sizeof (struct VBOXHGCMCMD) + pHGCMConnect->header.header.size);
299
300 if (pCmd)
301 {
302 VMMDevHGCMConnect *pHGCMConnectCopy = (VMMDevHGCMConnect *)(pCmd+1);
303
304 vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMConnect->header.header.size, VBOXHGCMCMDTYPE_CONNECT);
305
306 memcpy(pHGCMConnectCopy, pHGCMConnect, pHGCMConnect->header.header.size);
307
308 pCmd->paHostParms = NULL;
309 pCmd->cLinPtrs = 0;
310 pCmd->paLinPtrs = NULL;
311
312 /* Only allow the guest to use existing services! */
313 Assert(pHGCMConnect->loc.type == VMMDevHGCMLoc_LocalHost_Existing);
314 pHGCMConnect->loc.type = VMMDevHGCMLoc_LocalHost_Existing;
315
316 rc = pVMMDevState->pHGCMDrv->pfnConnect (pVMMDevState->pHGCMDrv, pCmd, &pHGCMConnectCopy->loc, &pHGCMConnectCopy->u32ClientID);
317 }
318 else
319 {
320 rc = VERR_NO_MEMORY;
321 }
322
323 return rc;
324}
325
326int vmmdevHGCMDisconnect (VMMDevState *pVMMDevState, VMMDevHGCMDisconnect *pHGCMDisconnect, RTGCPHYS GCPhys)
327{
328 int rc = VINF_SUCCESS;
329
330 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAllocZ (sizeof (struct VBOXHGCMCMD));
331
332 if (pCmd)
333 {
334 vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMDisconnect->header.header.size, VBOXHGCMCMDTYPE_DISCONNECT);
335
336 pCmd->paHostParms = NULL;
337 pCmd->cLinPtrs = 0;
338 pCmd->paLinPtrs = NULL;
339
340 rc = pVMMDevState->pHGCMDrv->pfnDisconnect (pVMMDevState->pHGCMDrv, pCmd, pHGCMDisconnect->u32ClientID);
341 }
342 else
343 {
344 rc = VERR_NO_MEMORY;
345 }
346
347 return rc;
348}
349
350
351int vmmdevHGCMCall (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, RTGCPHYS GCPhys, bool f64Bits)
352{
353 int rc = VINF_SUCCESS;
354
355 Log(("vmmdevHGCMCall: client id = %d, function = %d, %s bit\n", pHGCMCall->u32ClientID, pHGCMCall->u32Function, f64Bits? "64": "32"));
356
357 /* Compute size and allocate memory block to hold:
358 * struct VBOXHGCMCMD
359 * VBOXHGCMSVCPARM[cParms]
360 * memory buffers for pointer parameters.
361 */
362
363 uint32_t cParms = pHGCMCall->cParms;
364
365 Log(("vmmdevHGCMCall: cParms = %d\n", cParms));
366
367 /*
368 * Compute size of required memory buffer.
369 */
370
371 uint32_t cbCmdSize = sizeof (struct VBOXHGCMCMD) + cParms * sizeof (VBOXHGCMSVCPARM);
372
373 uint32_t i;
374
375 uint32_t cLinPtrs = 0;
376 uint32_t cLinPtrPages = 0;
377
378 if (f64Bits)
379 {
380#ifdef VBOX_WITH_64_BITS_GUESTS
381 HGCMFunctionParameter64 *pGuestParm = VMMDEV_HGCM_CALL_PARMS64(pHGCMCall);
382#else
383 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
384 AssertFailed (); /* This code should not be called in this case */
385#endif /* VBOX_WITH_64_BITS_GUESTS */
386
387 /* Look for pointer parameters, which require a host buffer. */
388 for (i = 0; i < cParms && VBOX_SUCCESS(rc); i++, pGuestParm++)
389 {
390 switch (pGuestParm->type)
391 {
392 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
393 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
394 case VMMDevHGCMParmType_LinAddr: /* In & Out */
395 {
396 cbCmdSize += pGuestParm->u.Pointer.size;
397
398 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
399 {
400 cLinPtrs++;
401 /* Take the offset into the current page also into account! */
402 cLinPtrPages += ((pGuestParm->u.Pointer.u.linearAddr & PAGE_OFFSET_MASK)
403 + pGuestParm->u.Pointer.size + PAGE_SIZE - 1) / PAGE_SIZE;
404 }
405
406 Log(("vmmdevHGCMCall: linptr size = %d\n", pGuestParm->u.Pointer.size));
407 } break;
408
409 case VMMDevHGCMParmType_32bit:
410 case VMMDevHGCMParmType_64bit:
411 case VMMDevHGCMParmType_PhysAddr:
412 {
413 } break;
414
415 default:
416 {
417 AssertMsgFailed(("vmmdevHGCMCall: invalid parameter type %x\n", pGuestParm->type));
418 rc = VERR_INVALID_PARAMETER;
419 break;
420 }
421 }
422 }
423 }
424 else
425 {
426#ifdef VBOX_WITH_64_BITS_GUESTS
427 HGCMFunctionParameter32 *pGuestParm = VMMDEV_HGCM_CALL_PARMS32(pHGCMCall);
428#else
429 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
430#endif /* VBOX_WITH_64_BITS_GUESTS */
431
432 /* Look for pointer parameters, which require a host buffer. */
433 for (i = 0; i < cParms && VBOX_SUCCESS(rc); i++, pGuestParm++)
434 {
435 switch (pGuestParm->type)
436 {
437 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
438 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
439 case VMMDevHGCMParmType_LinAddr: /* In & Out */
440 {
441 cbCmdSize += pGuestParm->u.Pointer.size;
442
443 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
444 {
445 cLinPtrs++;
446 /* Take the offset into the current page also into account! */
447 cLinPtrPages += ((pGuestParm->u.Pointer.u.linearAddr & PAGE_OFFSET_MASK)
448 + pGuestParm->u.Pointer.size + PAGE_SIZE - 1) / PAGE_SIZE;
449 }
450
451 Log(("vmmdevHGCMCall: linptr size = %d\n", pGuestParm->u.Pointer.size));
452 } break;
453
454 case VMMDevHGCMParmType_32bit:
455 case VMMDevHGCMParmType_64bit:
456 case VMMDevHGCMParmType_PhysAddr:
457 {
458 } break;
459
460 default:
461 {
462 AssertMsgFailed(("vmmdevHGCMCall: invalid parameter type %x\n", pGuestParm->type));
463 rc = VERR_INVALID_PARAMETER;
464 break;
465 }
466 }
467 }
468 }
469
470 if (VBOX_FAILURE (rc))
471 {
472 return rc;
473 }
474
475 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAlloc (cbCmdSize);
476
477 if (pCmd == NULL)
478 {
479 return VERR_NO_MEMORY;
480 }
481
482 memset (pCmd, 0, sizeof (*pCmd));
483
484 pCmd->paHostParms = NULL;
485 pCmd->cLinPtrs = cLinPtrs;
486
487 if (cLinPtrs > 0)
488 {
489 pCmd->paLinPtrs = (VBOXHGCMLINPTR *)RTMemAlloc ( sizeof (VBOXHGCMLINPTR) * cLinPtrs
490 + sizeof (RTGCPHYS) * cLinPtrPages);
491
492 if (pCmd->paLinPtrs == NULL)
493 {
494 RTMemFree (pCmd);
495 return VERR_NO_MEMORY;
496 }
497 }
498 else
499 {
500 pCmd->paLinPtrs = NULL;
501 }
502
503 /* Process parameters, changing them to host context pointers for easy
504 * processing by connector. Guest must insure that the pointed data is actually
505 * in the guest RAM and remains locked there for entire request processing.
506 */
507
508 if (cParms != 0)
509 {
510 /* Compute addresses of host parms array and first memory buffer. */
511 VBOXHGCMSVCPARM *pHostParm = (VBOXHGCMSVCPARM *)((char *)pCmd + sizeof (struct VBOXHGCMCMD));
512
513 uint8_t *pcBuf = (uint8_t *)pHostParm + cParms * sizeof (VBOXHGCMSVCPARM);
514
515 pCmd->paHostParms = pHostParm;
516
517 uint32_t iLinPtr = 0;
518 RTGCPHYS *pPages = (RTGCPHYS *)((uint8_t *)pCmd->paLinPtrs + sizeof (VBOXHGCMLINPTR) *cLinPtrs);
519
520 if (f64Bits)
521 {
522#ifdef VBOX_WITH_64_BITS_GUESTS
523 HGCMFunctionParameter64 *pGuestParm = VMMDEV_HGCM_CALL_PARMS64(pHGCMCall);
524#else
525 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
526 AssertFailed (); /* This code should not be called in this case */
527#endif /* VBOX_WITH_64_BITS_GUESTS */
528
529
530 for (i = 0; i < cParms && VBOX_SUCCESS(rc); i++, pGuestParm++, pHostParm++)
531 {
532 switch (pGuestParm->type)
533 {
534 case VMMDevHGCMParmType_32bit:
535 {
536 uint32_t u32 = pGuestParm->u.value32;
537
538 pHostParm->type = VBOX_HGCM_SVC_PARM_32BIT;
539 pHostParm->u.uint32 = u32;
540
541 Log(("vmmdevHGCMCall: uint32 guest parameter %u\n", u32));
542 break;
543 }
544
545 case VMMDevHGCMParmType_64bit:
546 {
547 uint64_t u64 = pGuestParm->u.value64;
548
549 pHostParm->type = VBOX_HGCM_SVC_PARM_64BIT;
550 pHostParm->u.uint64 = u64;
551
552 Log(("vmmdevHGCMCall: uint64 guest parameter %llu\n", u64));
553 break;
554 }
555
556 case VMMDevHGCMParmType_PhysAddr:
557 {
558 uint32_t size = pGuestParm->u.Pointer.size;
559#ifdef LOG_ENABLED
560 RTGCPHYS physAddr = pGuestParm->u.Pointer.u.physAddr;
561#endif
562
563 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
564 pHostParm->u.pointer.size = size;
565
566 AssertFailed();
567 /* rc = PDMDevHlpPhys2HCVirt (pVMMDevState->pDevIns, physAddr, size, &pHostParm->u.pointer.addr); */
568
569 Log(("vmmdevHGCMCall: PhysAddr guest parameter %VGp\n", physAddr));
570 break;
571 }
572
573 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
574 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
575 case VMMDevHGCMParmType_LinAddr: /* In & Out */
576 {
577 uint32_t size = pGuestParm->u.Pointer.size;
578 RTGCPTR linearAddr = pGuestParm->u.Pointer.u.linearAddr;
579
580 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
581 pHostParm->u.pointer.size = size;
582
583 /* Copy guest data to an allocated buffer, so
584 * services can use the data.
585 */
586
587 if (size == 0)
588 {
589 pHostParm->u.pointer.addr = (void *) 0xfeeddead;
590 }
591 else
592 {
593 /* Don't overdo it */
594 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_Out)
595 rc = PDMDevHlpPhysReadGCVirt(pVMMDevState->pDevIns, pcBuf, linearAddr, size);
596 else
597 rc = VINF_SUCCESS;
598
599 if (VBOX_SUCCESS(rc))
600 {
601 pHostParm->u.pointer.addr = pcBuf;
602 pcBuf += size;
603
604 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
605 {
606 /* Remember the guest physical pages that belong to the virtual address
607 * region.
608 */
609 rc = vmmdevHGCMSaveLinPtr (pVMMDevState->pDevIns, i, linearAddr, size, iLinPtr++, pCmd->paLinPtrs, &pPages);
610 }
611 }
612 }
613
614 Log(("vmmdevHGCMCall: LinAddr guest parameter %VGv, rc = %Vrc\n", linearAddr, rc));
615 break;
616 }
617
618 /* just to shut up gcc */
619 default:
620 break;
621 }
622 }
623 }
624 else
625 {
626#ifdef VBOX_WITH_64_BITS_GUESTS
627 HGCMFunctionParameter32 *pGuestParm = VMMDEV_HGCM_CALL_PARMS32(pHGCMCall);
628#else
629 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
630#endif /* VBOX_WITH_64_BITS_GUESTS */
631
632 for (i = 0; i < cParms && VBOX_SUCCESS(rc); i++, pGuestParm++, pHostParm++)
633 {
634 switch (pGuestParm->type)
635 {
636 case VMMDevHGCMParmType_32bit:
637 {
638 uint32_t u32 = pGuestParm->u.value32;
639
640 pHostParm->type = VBOX_HGCM_SVC_PARM_32BIT;
641 pHostParm->u.uint32 = u32;
642
643 Log(("vmmdevHGCMCall: uint32 guest parameter %u\n", u32));
644 break;
645 }
646
647 case VMMDevHGCMParmType_64bit:
648 {
649 uint64_t u64 = pGuestParm->u.value64;
650
651 pHostParm->type = VBOX_HGCM_SVC_PARM_64BIT;
652 pHostParm->u.uint64 = u64;
653
654 Log(("vmmdevHGCMCall: uint64 guest parameter %llu\n", u64));
655 break;
656 }
657
658 case VMMDevHGCMParmType_PhysAddr:
659 {
660 uint32_t size = pGuestParm->u.Pointer.size;
661#ifdef LOG_ENABLED
662 RTGCPHYS physAddr = pGuestParm->u.Pointer.u.physAddr;
663#endif
664
665 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
666 pHostParm->u.pointer.size = size;
667
668 AssertFailed();
669 /* rc = PDMDevHlpPhys2HCVirt (pVMMDevState->pDevIns, physAddr, size, &pHostParm->u.pointer.addr); */
670
671 Log(("vmmdevHGCMCall: PhysAddr guest parameter %VGp\n", physAddr));
672 break;
673 }
674
675 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
676 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
677 case VMMDevHGCMParmType_LinAddr: /* In & Out */
678 {
679 uint32_t size = pGuestParm->u.Pointer.size;
680 RTGCPTR linearAddr = pGuestParm->u.Pointer.u.linearAddr;
681
682 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
683 pHostParm->u.pointer.size = size;
684
685 /* Copy guest data to an allocated buffer, so
686 * services can use the data.
687 */
688
689 if (size == 0)
690 {
691 pHostParm->u.pointer.addr = (void *) 0xfeeddead;
692 }
693 else
694 {
695 /* Don't overdo it */
696 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_Out)
697 rc = PDMDevHlpPhysReadGCVirt(pVMMDevState->pDevIns, pcBuf, linearAddr, size);
698 else
699 rc = VINF_SUCCESS;
700
701 if (VBOX_SUCCESS(rc))
702 {
703 pHostParm->u.pointer.addr = pcBuf;
704 pcBuf += size;
705
706 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
707 {
708 /* Remember the guest physical pages that belong to the virtual address
709 * region.
710 */
711 rc = vmmdevHGCMSaveLinPtr (pVMMDevState->pDevIns, i, linearAddr, size, iLinPtr++, pCmd->paLinPtrs, &pPages);
712 }
713 }
714 }
715
716 Log(("vmmdevHGCMCall: LinAddr guest parameter %VGv, rc = %Vrc\n", linearAddr, rc));
717 break;
718 }
719
720 /* just to shut up gcc */
721 default:
722 break;
723 }
724 }
725 }
726 }
727
728 if (VBOX_SUCCESS (rc))
729 {
730 vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMCall->header.header.size, VBOXHGCMCMDTYPE_CALL);
731
732 /* Pass the function call to HGCM connector for actual processing */
733 rc = pVMMDevState->pHGCMDrv->pfnCall (pVMMDevState->pHGCMDrv, pCmd, pHGCMCall->u32ClientID, pHGCMCall->u32Function, cParms, pCmd->paHostParms);
734 }
735 else
736 {
737 if (pCmd->paLinPtrs)
738 {
739 RTMemFree (pCmd->paLinPtrs);
740 }
741
742 RTMemFree (pCmd);
743 }
744
745 return rc;
746}
747
748static int vmmdevHGCMCmdVerify (PVBOXHGCMCMD pCmd, VMMDevHGCMRequestHeader *pHeader)
749{
750 switch (pCmd->enmCmdType)
751 {
752 case VBOXHGCMCMDTYPE_CONNECT:
753 if (pHeader->header.requestType == VMMDevReq_HGCMConnect) return VINF_SUCCESS;
754 break;
755
756 case VBOXHGCMCMDTYPE_DISCONNECT:
757 if (pHeader->header.requestType == VMMDevReq_HGCMDisconnect) return VINF_SUCCESS;
758 break;
759
760 case VBOXHGCMCMDTYPE_CALL:
761#ifdef VBOX_WITH_64_BITS_GUESTS
762 if ( pHeader->header.requestType == VMMDevReq_HGCMCall32
763 || pHeader->header.requestType == VMMDevReq_HGCMCall64) return VINF_SUCCESS;
764#else
765 if ( pHeader->header.requestType == VMMDevReq_HGCMCall) return VINF_SUCCESS;
766#endif /* VBOX_WITH_64_BITS_GUESTS */
767
768 break;
769
770 default:
771 AssertFailed ();
772 }
773
774 LogRel(("VMMDEV: Invalid HGCM command: pCmd->enmCmdType = 0x%08X, pHeader->header.requestType = 0x%08X\n",
775 pCmd->enmCmdType, pHeader->header.requestType));
776 return VERR_INVALID_PARAMETER;
777}
778
779#define PDMIHGCMPORT_2_VMMDEVSTATE(pInterface) ( (VMMDevState *) ((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, HGCMPort)) )
780
781DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result, PVBOXHGCMCMD pCmd)
782{
783 VMMDevState *pVMMDevState = PDMIHGCMPORT_2_VMMDEVSTATE(pInterface);
784 VMMDevHGCMRequestHeader *pHeader;
785 int rc = VINF_SUCCESS;
786
787 pHeader = (VMMDevHGCMRequestHeader *)RTMemAllocZ (pCmd->cbSize);
788 Assert(pHeader);
789 if (pHeader == NULL)
790 return;
791
792 PDMDevHlpPhysRead(pVMMDevState->pDevIns, (RTGCPHYS)pCmd->GCPhys, pHeader, pCmd->cbSize);
793
794 if (result != VINF_HGCM_SAVE_STATE)
795 {
796 /* Setup return codes. */
797 pHeader->result = result;
798
799 /* Verify the request type. */
800 rc = vmmdevHGCMCmdVerify (pCmd, pHeader);
801
802 if (VBOX_SUCCESS (rc))
803 {
804 /* Update parameters and data buffers. */
805
806 switch (pHeader->header.requestType)
807 {
808#ifdef VBOX_WITH_64_BITS_GUESTS
809 case VMMDevReq_HGCMCall64:
810 {
811 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pHeader;
812
813 uint32_t cParms = pHGCMCall->cParms;
814
815 VBOXHGCMSVCPARM *pHostParm = pCmd->paHostParms;
816
817 uint32_t i;
818 uint32_t iLinPtr = 0;
819
820 HGCMFunctionParameter64 *pGuestParm = VMMDEV_HGCM_CALL_PARMS64(pHGCMCall);
821
822 for (i = 0; i < cParms; i++, pGuestParm++, pHostParm++)
823 {
824 switch (pGuestParm->type)
825 {
826 case VMMDevHGCMParmType_32bit:
827 {
828 pGuestParm->u.value32 = pHostParm->u.uint32;
829 } break;
830
831 case VMMDevHGCMParmType_64bit:
832 {
833 pGuestParm->u.value64 = pHostParm->u.uint64;
834 } break;
835
836 case VMMDevHGCMParmType_PhysAddr:
837 {
838 /* do nothing */
839 } break;
840
841 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
842 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
843 case VMMDevHGCMParmType_LinAddr: /* In & Out */
844 {
845 /* Copy buffer back to guest memory. */
846 uint32_t size = pGuestParm->u.Pointer.size;
847
848 if (size > 0 && pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
849 {
850 /* Use the saved page list. */
851 rc = vmmdevHGCMWriteLinPtr (pVMMDevState->pDevIns, i, pHostParm->u.pointer.addr, size, iLinPtr++, pCmd->paLinPtrs);
852 AssertReleaseRC(rc);
853 }
854 } break;
855
856 default:
857 {
858 /* This indicates that the guest request memory was corrupted. */
859 AssertReleaseMsgFailed(("hgcmCompleted: invalid parameter type %08X\n", pGuestParm->type));
860 }
861 }
862 }
863 break;
864 }
865
866 case VMMDevReq_HGCMCall32:
867 {
868 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pHeader;
869
870 uint32_t cParms = pHGCMCall->cParms;
871
872 VBOXHGCMSVCPARM *pHostParm = pCmd->paHostParms;
873
874 uint32_t i;
875 uint32_t iLinPtr = 0;
876
877 HGCMFunctionParameter32 *pGuestParm = VMMDEV_HGCM_CALL_PARMS32(pHGCMCall);
878
879 for (i = 0; i < cParms; i++, pGuestParm++, pHostParm++)
880 {
881 switch (pGuestParm->type)
882 {
883 case VMMDevHGCMParmType_32bit:
884 {
885 pGuestParm->u.value32 = pHostParm->u.uint32;
886 } break;
887
888 case VMMDevHGCMParmType_64bit:
889 {
890 pGuestParm->u.value64 = pHostParm->u.uint64;
891 } break;
892
893 case VMMDevHGCMParmType_PhysAddr:
894 {
895 /* do nothing */
896 } break;
897
898 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
899 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
900 case VMMDevHGCMParmType_LinAddr: /* In & Out */
901 {
902 /* Copy buffer back to guest memory. */
903 uint32_t size = pGuestParm->u.Pointer.size;
904
905 if (size > 0 && pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
906 {
907 /* Use the saved page list. */
908 rc = vmmdevHGCMWriteLinPtr (pVMMDevState->pDevIns, i, pHostParm->u.pointer.addr, size, iLinPtr++, pCmd->paLinPtrs);
909 AssertReleaseRC(rc);
910 }
911 } break;
912
913 default:
914 {
915 /* This indicates that the guest request memory was corrupted. */
916 AssertReleaseMsgFailed(("hgcmCompleted: invalid parameter type %08X\n", pGuestParm->type));
917 }
918 }
919 }
920 break;
921 }
922#else
923 case VMMDevReq_HGCMCall:
924 {
925 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pHeader;
926
927 uint32_t cParms = pHGCMCall->cParms;
928
929 VBOXHGCMSVCPARM *pHostParm = pCmd->paHostParms;
930
931 uint32_t i;
932 uint32_t iLinPtr = 0;
933
934 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
935
936 for (i = 0; i < cParms; i++, pGuestParm++, pHostParm++)
937 {
938 switch (pGuestParm->type)
939 {
940 case VMMDevHGCMParmType_32bit:
941 {
942 pGuestParm->u.value32 = pHostParm->u.uint32;
943 } break;
944
945 case VMMDevHGCMParmType_64bit:
946 {
947 pGuestParm->u.value64 = pHostParm->u.uint64;
948 } break;
949
950 case VMMDevHGCMParmType_PhysAddr:
951 {
952 /* do nothing */
953 } break;
954
955 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
956 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
957 case VMMDevHGCMParmType_LinAddr: /* In & Out */
958 {
959 /* Copy buffer back to guest memory. */
960 uint32_t size = pGuestParm->u.Pointer.size;
961
962 if (size > 0 && pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
963 {
964 /* Use the saved page list. */
965 rc = vmmdevHGCMWriteLinPtr (pVMMDevState->pDevIns, i, pHostParm->u.pointer.addr, size, iLinPtr++, pCmd->paLinPtrs);
966 AssertReleaseRC(rc);
967 }
968 } break;
969
970 default:
971 {
972 /* This indicates that the guest request memory was corrupted. */
973 AssertReleaseMsgFailed(("hgcmCompleted: invalid parameter type %08X\n", pGuestParm->type));
974 }
975 }
976 }
977 break;
978 }
979#endif /* VBOX_WITH_64_BITS_GUESTS */
980 case VMMDevReq_HGCMConnect:
981 {
982 VMMDevHGCMConnect *pHGCMConnectCopy = (VMMDevHGCMConnect *)(pCmd+1);
983
984 /* save the client id in the guest request packet */
985 VMMDevHGCMConnect *pHGCMConnect = (VMMDevHGCMConnect *)pHeader;
986 pHGCMConnect->u32ClientID = pHGCMConnectCopy->u32ClientID;
987 break;
988 }
989
990 default:
991 /* make gcc happy */
992 break;
993 }
994 }
995 else
996 {
997 /* Return error to the guest. */
998 pHeader->header.rc = rc;
999 }
1000
1001 /* Mark request as processed*/
1002 pHeader->fu32Flags |= VBOX_HGCM_REQ_DONE;
1003
1004 /* Write back the request */
1005 PDMDevHlpPhysWrite(pVMMDevState->pDevIns, pCmd->GCPhys, pHeader, pCmd->cbSize);
1006
1007 /* It it assumed that VMMDev saves state after the HGCM services. */
1008 vmmdevHGCMRemoveCommand (pVMMDevState, pCmd);
1009
1010 /* Now, when the command was removed from the internal list, notify the guest. */
1011 VMMDevNotifyGuest (pVMMDevState, VMMDEV_EVENT_HGCM);
1012
1013 if (pCmd->paLinPtrs)
1014 {
1015 RTMemFree (pCmd->paLinPtrs);
1016 }
1017
1018 RTMemFree (pCmd);
1019 }
1020 RTMemFree(pHeader);
1021
1022 return;
1023}
1024
1025DECLCALLBACK(void) hgcmCompleted (PPDMIHGCMPORT pInterface, int32_t result, PVBOXHGCMCMD pCmd)
1026{
1027 VMMDevState *pVMMDevState = PDMIHGCMPORT_2_VMMDEVSTATE(pInterface);
1028
1029 /* Not safe to execute asynchroneously; forward to EMT */
1030 int rc = VMR3ReqCallEx(PDMDevHlpGetVM(pVMMDevState->pDevIns), NULL, 0, VMREQFLAGS_NO_WAIT | VMREQFLAGS_VOID,
1031 (PFNRT)hgcmCompletedWorker, 3, pInterface, result, pCmd);
1032 AssertRC(rc);
1033}
1034
1035/* @thread EMT */
1036int vmmdevHGCMSaveState(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
1037{
1038 /* Save information about pending requests.
1039 * Only GCPtrs are of interest.
1040 */
1041 int rc = VINF_SUCCESS;
1042
1043 LogFlowFunc(("\n"));
1044
1045 /* Compute how many commands are pending. */
1046 uint32_t cCmds = 0;
1047
1048 PVBOXHGCMCMD pIter = pVMMDevState->pHGCMCmdList;
1049
1050 while (pIter)
1051 {
1052 LogFlowFunc (("pIter %p\n", pIter));
1053 cCmds++;
1054 pIter = pIter->pNext;
1055 }
1056
1057 LogFlowFunc(("cCmds = %d\n", cCmds));
1058
1059 /* Save number of commands. */
1060 rc = SSMR3PutU32(pSSM, cCmds);
1061 AssertRCReturn(rc, rc);
1062
1063 if (cCmds > 0)
1064 {
1065 pIter = pVMMDevState->pHGCMCmdList;
1066
1067 while (pIter)
1068 {
1069 PVBOXHGCMCMD pNext = pIter->pNext;
1070
1071 LogFlowFunc (("Saving %VGp\n", pIter->GCPhys));
1072 rc = SSMR3PutGCPhys(pSSM, pIter->GCPhys);
1073 AssertRCReturn(rc, rc);
1074
1075 rc = SSMR3PutU32(pSSM, pIter->cbSize);
1076 AssertRCReturn(rc, rc);
1077
1078 vmmdevHGCMRemoveCommand (pVMMDevState, pIter);
1079
1080 pIter = pNext;
1081 }
1082 }
1083
1084 return rc;
1085}
1086
1087/* @thread EMT */
1088int vmmdevHGCMLoadState(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
1089{
1090 int rc = VINF_SUCCESS;
1091
1092 LogFlowFunc(("\n"));
1093
1094 /* Read how many commands were pending. */
1095 uint32_t cCmds = 0;
1096 rc = SSMR3GetU32(pSSM, &cCmds);
1097 AssertRCReturn(rc, rc);
1098
1099 LogFlowFunc(("cCmds = %d\n", cCmds));
1100
1101 while (cCmds--)
1102 {
1103 RTGCPHYS GCPhys;
1104 uint32_t cbSize;
1105
1106 rc = SSMR3GetGCPhys(pSSM, &GCPhys);
1107 AssertRCReturn(rc, rc);
1108
1109 rc = SSMR3GetU32(pSSM, &cbSize);
1110 AssertRCReturn(rc, rc);
1111
1112 LogFlowFunc (("Restoring %VGp size %x bytes\n", GCPhys, cbSize));
1113
1114 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAllocZ (sizeof (struct VBOXHGCMCMD));
1115 AssertReturn(pCmd, VERR_NO_MEMORY);
1116
1117 vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, cbSize, VBOXHGCMCMDTYPE_LOADSTATE);
1118 }
1119
1120 return rc;
1121}
1122
1123/* @thread EMT */
1124int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
1125{
1126 LogFlowFunc(("\n"));
1127
1128 /* Reissue pending requests. */
1129 PPDMDEVINS pDevIns = pVMMDevState->pDevIns;
1130
1131 int rc = vmmdevHGCMCmdListLock (pVMMDevState);
1132
1133 if (VBOX_SUCCESS (rc))
1134 {
1135 PVBOXHGCMCMD pIter = pVMMDevState->pHGCMCmdList;
1136
1137 while (pIter)
1138 {
1139 LogFlowFunc (("pIter %p\n", pIter));
1140
1141 PVBOXHGCMCMD pNext = pIter->pNext;
1142
1143 VMMDevRequestHeader *requestHeader = (VMMDevRequestHeader *)RTMemAllocZ (pIter->cbSize);
1144 Assert(requestHeader);
1145 if (requestHeader == NULL)
1146 return VERR_NO_MEMORY;
1147
1148 PDMDevHlpPhysRead(pDevIns, (RTGCPHYS)pIter->GCPhys, requestHeader, pIter->cbSize);
1149
1150 /* the structure size must be greater or equal to the header size */
1151 if (requestHeader->size < sizeof(VMMDevRequestHeader))
1152 {
1153 Log(("VMMDev request header size too small! size = %d\n", requestHeader->size));
1154 }
1155 else
1156 {
1157 /* check the version of the header structure */
1158 if (requestHeader->version != VMMDEV_REQUEST_HEADER_VERSION)
1159 {
1160 Log(("VMMDev: guest header version (0x%08X) differs from ours (0x%08X)\n", requestHeader->version, VMMDEV_REQUEST_HEADER_VERSION));
1161 }
1162 else
1163 {
1164 Log(("VMMDev request issued: %d\n", requestHeader->requestType));
1165
1166 switch (requestHeader->requestType)
1167 {
1168 case VMMDevReq_HGCMConnect:
1169 {
1170 if (requestHeader->size < sizeof(VMMDevHGCMConnect))
1171 {
1172 AssertMsgFailed(("VMMDevReq_HGCMConnect structure has invalid size!\n"));
1173 requestHeader->rc = VERR_INVALID_PARAMETER;
1174 }
1175 else if (!pVMMDevState->pHGCMDrv)
1176 {
1177 Log(("VMMDevReq_HGCMConnect HGCM Connector is NULL!\n"));
1178 requestHeader->rc = VERR_NOT_SUPPORTED;
1179 }
1180 else
1181 {
1182 VMMDevHGCMConnect *pHGCMConnect = (VMMDevHGCMConnect *)requestHeader;
1183
1184 Log(("VMMDevReq_HGCMConnect\n"));
1185
1186 requestHeader->rc = vmmdevHGCMConnect (pVMMDevState, pHGCMConnect, pIter->GCPhys);
1187 }
1188 break;
1189 }
1190
1191 case VMMDevReq_HGCMDisconnect:
1192 {
1193 if (requestHeader->size < sizeof(VMMDevHGCMDisconnect))
1194 {
1195 AssertMsgFailed(("VMMDevReq_HGCMDisconnect structure has invalid size!\n"));
1196 requestHeader->rc = VERR_INVALID_PARAMETER;
1197 }
1198 else if (!pVMMDevState->pHGCMDrv)
1199 {
1200 Log(("VMMDevReq_HGCMDisconnect HGCM Connector is NULL!\n"));
1201 requestHeader->rc = VERR_NOT_SUPPORTED;
1202 }
1203 else
1204 {
1205 VMMDevHGCMDisconnect *pHGCMDisconnect = (VMMDevHGCMDisconnect *)requestHeader;
1206
1207 Log(("VMMDevReq_VMMDevHGCMDisconnect\n"));
1208 requestHeader->rc = vmmdevHGCMDisconnect (pVMMDevState, pHGCMDisconnect, pIter->GCPhys);
1209 }
1210 break;
1211 }
1212
1213#ifdef VBOX_WITH_64_BITS_GUESTS
1214 case VMMDevReq_HGCMCall64:
1215 case VMMDevReq_HGCMCall32:
1216#else
1217 case VMMDevReq_HGCMCall:
1218#endif /* VBOX_WITH_64_BITS_GUESTS */
1219 {
1220 if (requestHeader->size < sizeof(VMMDevHGCMCall))
1221 {
1222 AssertMsgFailed(("VMMDevReq_HGCMCall structure has invalid size!\n"));
1223 requestHeader->rc = VERR_INVALID_PARAMETER;
1224 }
1225 else if (!pVMMDevState->pHGCMDrv)
1226 {
1227 Log(("VMMDevReq_HGCMCall HGCM Connector is NULL!\n"));
1228 requestHeader->rc = VERR_NOT_SUPPORTED;
1229 }
1230 else
1231 {
1232 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)requestHeader;
1233
1234 Log(("VMMDevReq_HGCMCall: sizeof (VMMDevHGCMRequest) = %04X\n", sizeof (VMMDevHGCMCall)));
1235
1236 Log(("%.*Vhxd\n", requestHeader->size, requestHeader));
1237
1238#ifdef VBOX_WITH_64_BITS_GUESTS
1239 bool f64Bits = (requestHeader->requestType == VMMDevReq_HGCMCall64);
1240#else
1241 bool f64Bits = false;
1242#endif /* VBOX_WITH_64_BITS_GUESTS */
1243 requestHeader->rc = vmmdevHGCMCall (pVMMDevState, pHGCMCall, pIter->GCPhys, f64Bits);
1244 }
1245 break;
1246 }
1247 default:
1248 AssertMsgFailed(("Unknown request type %x during LoadState\n", requestHeader->requestType));
1249 LogRel(("VMMDEV: Ignoring unknown request type %x during LoadState\n", requestHeader->requestType));
1250 }
1251 }
1252 }
1253
1254 /* Write back the request */
1255 PDMDevHlpPhysWrite(pDevIns, pIter->GCPhys, requestHeader, pIter->cbSize);
1256 RTMemFree(requestHeader);
1257
1258 vmmdevHGCMRemoveCommand (pVMMDevState, pIter);
1259 RTMemFree(pIter);
1260 pIter = pNext;
1261 }
1262
1263 vmmdevHGCMCmdListUnlock (pVMMDevState);
1264 }
1265
1266 return rc;
1267}
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