VirtualBox

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

Last change on this file since 20999 was 20731, checked in by vboxsync, 15 years ago

Save more info about pending HGCM requests (xTracker #4032).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 77.9 KB
Line 
1/* $Id: VMMDevHGCM.cpp 20731 2009-06-19 17:24:41Z vboxsync $ */
2/** @file
3 * VMMDev - HGCM - Host-Guest Communication Manager Device.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23#define LOG_GROUP LOG_GROUP_DEV_VMM
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#include <VBox/log.h>
34
35#include "VMMDevHGCM.h"
36
37typedef enum _VBOXHGCMCMDTYPE
38{
39 VBOXHGCMCMDTYPE_LOADSTATE = 0,
40 VBOXHGCMCMDTYPE_CONNECT,
41 VBOXHGCMCMDTYPE_DISCONNECT,
42 VBOXHGCMCMDTYPE_CALL,
43 VBOXHGCMCMDTYPE_SizeHack = 0x7fffffff
44} VBOXHGCMCMDTYPE;
45
46/* Information about a linear ptr parameter. */
47typedef struct _VBOXHGCMLINPTR
48{
49 /* Index of the parameter. */
50 uint32_t iParm;
51
52 /* Offset in the first physical page of the region. */
53 uint32_t offFirstPage;
54
55 /* How many pages. */
56 uint32_t cPages;
57
58 /* Pointer to array of the GC physical addresses for these pages.
59 * It is assumed that the physical address of the locked resident
60 * guest page does not change.
61 */
62 RTGCPHYS *paPages;
63
64} VBOXHGCMLINPTR;
65
66struct VBOXHGCMCMD
67{
68 /* Active commands, list is protected by critsectHGCMCmdList. */
69 struct VBOXHGCMCMD *pNext;
70 struct VBOXHGCMCMD *pPrev;
71
72 /* Size of memory buffer for this command structure, including trailing paHostParms.
73 * This field simplifies loading of saved state.
74 */
75 uint32_t cbCmd;
76
77 /* The type of the command. */
78 VBOXHGCMCMDTYPE enmCmdType;
79
80 /* Whether the command was cancelled by the guest. */
81 bool fCancelled;
82
83 /* GC physical address of the guest request. */
84 RTGCPHYS GCPhys;
85
86 /* Request packet size */
87 uint32_t cbSize;
88
89 /* Pointer to converted host parameters in case of a Call request.
90 * Parameters follow this structure in the same memory block.
91 */
92 VBOXHGCMSVCPARM *paHostParms;
93
94 /* Linear pointer parameters information. */
95 int cLinPtrs;
96
97 /* How many pages for all linptrs of this command.
98 * Only valid if cLinPtrs > 0. This field simplifies loading of saved state.
99 */
100 int cLinPtrPages;
101
102 /* Pointer to descriptions of linear pointers. */
103 VBOXHGCMLINPTR *paLinPtrs;
104};
105
106static int vmmdevHGCMCmdListLock (VMMDevState *pVMMDevState)
107{
108 int rc = RTCritSectEnter (&pVMMDevState->critsectHGCMCmdList);
109 AssertRC (rc);
110 return rc;
111}
112
113static void vmmdevHGCMCmdListUnlock (VMMDevState *pVMMDevState)
114{
115 int rc = RTCritSectLeave (&pVMMDevState->critsectHGCMCmdList);
116 AssertRC (rc);
117}
118
119static int vmmdevHGCMAddCommand (VMMDevState *pVMMDevState, PVBOXHGCMCMD pCmd, RTGCPHYS GCPhys, uint32_t cbSize, VBOXHGCMCMDTYPE enmCmdType)
120{
121 /* PPDMDEVINS pDevIns = pVMMDevState->pDevIns; */
122
123 int rc = vmmdevHGCMCmdListLock (pVMMDevState);
124
125 if (RT_SUCCESS (rc))
126 {
127 LogFlowFunc(("%p type %d\n", pCmd, enmCmdType));
128
129 /* Insert at the head of the list. The vmmdevHGCMLoadStateDone depends on this. */
130 pCmd->pNext = pVMMDevState->pHGCMCmdList;
131 pCmd->pPrev = NULL;
132
133 if (pVMMDevState->pHGCMCmdList)
134 {
135 pVMMDevState->pHGCMCmdList->pPrev = pCmd;
136 }
137
138 pVMMDevState->pHGCMCmdList = pCmd;
139
140 if (enmCmdType != VBOXHGCMCMDTYPE_LOADSTATE)
141 {
142 /* Loaded commands already have the right type. */
143 pCmd->enmCmdType = enmCmdType;
144 }
145 pCmd->GCPhys = GCPhys;
146 pCmd->cbSize = cbSize;
147
148 /* Automatically enable HGCM events, if there are HGCM commands. */
149 if ( enmCmdType == VBOXHGCMCMDTYPE_CONNECT
150 || enmCmdType == VBOXHGCMCMDTYPE_DISCONNECT
151 || enmCmdType == VBOXHGCMCMDTYPE_CALL)
152 {
153 Log(("vmmdevHGCMAddCommand: u32HGCMEnabled = %d\n", pVMMDevState->u32HGCMEnabled));
154 if (ASMAtomicCmpXchgU32(&pVMMDevState->u32HGCMEnabled, 1, 0))
155 {
156 VMMDevCtlSetGuestFilterMask (pVMMDevState, VMMDEV_EVENT_HGCM, 0);
157 }
158 }
159
160 vmmdevHGCMCmdListUnlock (pVMMDevState);
161 }
162
163 return rc;
164}
165
166static int vmmdevHGCMRemoveCommand (VMMDevState *pVMMDevState, PVBOXHGCMCMD pCmd)
167{
168 /* PPDMDEVINS pDevIns = pVMMDevState->pDevIns; */
169
170 int rc = vmmdevHGCMCmdListLock (pVMMDevState);
171
172 if (RT_SUCCESS (rc))
173 {
174 LogFlowFunc(("%p\n", pCmd));
175
176 if (pCmd->pNext)
177 {
178 pCmd->pNext->pPrev = pCmd->pPrev;
179 }
180 else
181 {
182 /* Tail, do nothing. */
183 }
184
185 if (pCmd->pPrev)
186 {
187 pCmd->pPrev->pNext = pCmd->pNext;
188 }
189 else
190 {
191 pVMMDevState->pHGCMCmdList = pCmd->pNext;
192 }
193
194 vmmdevHGCMCmdListUnlock (pVMMDevState);
195 }
196
197 return rc;
198}
199
200
201static PVBOXHGCMCMD vmmdevHGCMFindCommand (VMMDevState *pVMMDevState, RTGCPHYS GCPhys)
202{
203 PVBOXHGCMCMD pCmd = NULL;
204
205 int rc = vmmdevHGCMCmdListLock (pVMMDevState);
206
207 if (RT_SUCCESS (rc))
208 {
209 pCmd = pVMMDevState->pHGCMCmdList;
210
211 while (pCmd)
212 {
213 if (pCmd->GCPhys == GCPhys)
214 {
215 break;
216 }
217 pCmd = pCmd->pNext;
218 }
219
220 vmmdevHGCMCmdListUnlock (pVMMDevState);
221 }
222
223 LogFlowFunc(("%p\n", pCmd));
224 return pCmd;
225}
226
227
228static int vmmdevHGCMSaveLinPtr (PPDMDEVINS pDevIns,
229 uint32_t iParm,
230 RTGCPTR GCPtr,
231 uint32_t u32Size,
232 uint32_t iLinPtr,
233 VBOXHGCMLINPTR *paLinPtrs,
234 RTGCPHYS **ppPages)
235{
236 int rc = VINF_SUCCESS;
237
238 AssertRelease (u32Size > 0);
239
240 VBOXHGCMLINPTR *pLinPtr = &paLinPtrs[iLinPtr];
241
242 /* Take the offset into the current page also into account! */
243 u32Size += GCPtr & PAGE_OFFSET_MASK;
244
245 uint32_t cPages = (u32Size + PAGE_SIZE - 1) / PAGE_SIZE;
246
247 Log(("vmmdevHGCMSaveLinPtr: parm %d: %RGv %d = %d pages\n", iParm, GCPtr, u32Size, cPages));
248
249 pLinPtr->iParm = iParm;
250 pLinPtr->offFirstPage = GCPtr & PAGE_OFFSET_MASK;
251 pLinPtr->cPages = cPages;
252 pLinPtr->paPages = *ppPages;
253
254 *ppPages += cPages;
255
256 uint32_t iPage = 0;
257
258 GCPtr &= PAGE_BASE_GC_MASK;
259
260 /* Gonvert the guest linear pointers of pages to HC addresses. */
261 while (iPage < cPages)
262 {
263 /* convert */
264 RTGCPHYS GCPhys;
265
266 rc = PDMDevHlpPhysGCPtr2GCPhys(pDevIns, GCPtr, &GCPhys);
267
268 Log(("vmmdevHGCMSaveLinPtr: Page %d: %RGv -> %RGp. %Rrc\n", iPage, GCPtr, GCPhys, rc));
269
270 if (RT_FAILURE (rc))
271 {
272 break;
273 }
274
275 /* store */
276 pLinPtr->paPages[iPage++] = GCPhys;
277
278 /* next */
279 GCPtr += PAGE_SIZE;
280 }
281
282 AssertRelease (iPage == cPages);
283
284 return rc;
285}
286
287static int vmmdevHGCMWriteLinPtr (PPDMDEVINS pDevIns,
288 uint32_t iParm,
289 void *pvHost,
290 uint32_t u32Size,
291 uint32_t iLinPtr,
292 VBOXHGCMLINPTR *paLinPtrs)
293{
294 int rc = VINF_SUCCESS;
295
296 VBOXHGCMLINPTR *pLinPtr = &paLinPtrs[iLinPtr];
297
298 AssertRelease (u32Size > 0 && iParm == (uint32_t)pLinPtr->iParm);
299
300 RTGCPHYS GCPhysDst = pLinPtr->paPages[0] + pLinPtr->offFirstPage;
301 uint8_t *pu8Src = (uint8_t *)pvHost;
302
303 Log(("vmmdevHGCMWriteLinPtr: parm %d: size %d, cPages = %d\n", iParm, u32Size, pLinPtr->cPages));
304
305 uint32_t iPage = 0;
306
307 while (iPage < pLinPtr->cPages)
308 {
309 /* copy */
310 uint32_t cbWrite = iPage == 0?
311 PAGE_SIZE - pLinPtr->offFirstPage:
312 PAGE_SIZE;
313
314 Log(("vmmdevHGCMWriteLinPtr: page %d: dst %RGp, src %p, cbWrite %d\n", iPage, GCPhysDst, pu8Src, cbWrite));
315
316 iPage++;
317
318 if (cbWrite >= u32Size)
319 {
320 PDMDevHlpPhysWrite(pDevIns, GCPhysDst, pu8Src, u32Size);
321 u32Size = 0;
322 break;
323 }
324
325 PDMDevHlpPhysWrite(pDevIns, GCPhysDst, pu8Src, cbWrite);
326
327 /* next */
328 u32Size -= cbWrite;
329 pu8Src += cbWrite;
330
331 GCPhysDst = pLinPtr->paPages[iPage];
332 }
333
334 AssertRelease (iPage == pLinPtr->cPages);
335 Assert(u32Size == 0);
336
337 return rc;
338}
339
340static void logRelSavedCmdSizeMismatch (const char *pszFunction, uint32_t cbExpected, uint32_t cbCmdSize)
341{
342 LogRel(("Warning: VMMDev %s command length %d (expected %d)\n",
343 pszFunction, cbCmdSize, cbExpected));
344}
345
346int vmmdevHGCMConnect (VMMDevState *pVMMDevState, VMMDevHGCMConnect *pHGCMConnect, RTGCPHYS GCPhys)
347{
348 int rc = VINF_SUCCESS;
349
350 uint32_t cbCmdSize = sizeof (struct VBOXHGCMCMD) + pHGCMConnect->header.header.size;
351
352 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAllocZ (cbCmdSize);
353
354 if (pCmd)
355 {
356 VMMDevHGCMConnect *pHGCMConnectCopy = (VMMDevHGCMConnect *)(pCmd+1);
357
358 vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMConnect->header.header.size, VBOXHGCMCMDTYPE_CONNECT);
359
360 memcpy(pHGCMConnectCopy, pHGCMConnect, pHGCMConnect->header.header.size);
361
362 pCmd->cbCmd = cbCmdSize;
363 pCmd->paHostParms = NULL;
364 pCmd->cLinPtrs = 0;
365 pCmd->paLinPtrs = NULL;
366
367 /* Only allow the guest to use existing services! */
368 Assert(pHGCMConnect->loc.type == VMMDevHGCMLoc_LocalHost_Existing);
369 pHGCMConnect->loc.type = VMMDevHGCMLoc_LocalHost_Existing;
370
371 rc = pVMMDevState->pHGCMDrv->pfnConnect (pVMMDevState->pHGCMDrv, pCmd, &pHGCMConnectCopy->loc, &pHGCMConnectCopy->u32ClientID);
372 }
373 else
374 {
375 rc = VERR_NO_MEMORY;
376 }
377
378 return rc;
379}
380
381static int vmmdevHGCMConnectSaved (VMMDevState *pVMMDevState, VMMDevHGCMConnect *pHGCMConnect, bool *pfHGCMCalled, VBOXHGCMCMD *pSavedCmd)
382{
383 int rc = VINF_SUCCESS;
384
385 uint32_t cbCmdSize = sizeof (struct VBOXHGCMCMD) + pHGCMConnect->header.header.size;
386
387 if (pSavedCmd->cbCmd < cbCmdSize)
388 {
389 logRelSavedCmdSizeMismatch ("HGCMConnect", pSavedCmd->cbCmd, cbCmdSize);
390 return VERR_INVALID_PARAMETER;
391 }
392
393 VMMDevHGCMConnect *pHGCMConnectCopy = (VMMDevHGCMConnect *)(pSavedCmd+1);
394
395 memcpy(pHGCMConnectCopy, pHGCMConnect, pHGCMConnect->header.header.size);
396
397 /* Only allow the guest to use existing services! */
398 Assert(pHGCMConnect->loc.type == VMMDevHGCMLoc_LocalHost_Existing);
399 pHGCMConnect->loc.type = VMMDevHGCMLoc_LocalHost_Existing;
400
401 rc = pVMMDevState->pHGCMDrv->pfnConnect (pVMMDevState->pHGCMDrv, pSavedCmd, &pHGCMConnectCopy->loc, &pHGCMConnectCopy->u32ClientID);
402 if (RT_SUCCESS (rc))
403 {
404 *pfHGCMCalled = true;
405 }
406
407 return rc;
408}
409
410int vmmdevHGCMDisconnect (VMMDevState *pVMMDevState, VMMDevHGCMDisconnect *pHGCMDisconnect, RTGCPHYS GCPhys)
411{
412 int rc = VINF_SUCCESS;
413
414 uint32_t cbCmdSize = sizeof (struct VBOXHGCMCMD);
415
416 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAllocZ (cbCmdSize);
417
418 if (pCmd)
419 {
420 vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMDisconnect->header.header.size, VBOXHGCMCMDTYPE_DISCONNECT);
421
422 pCmd->cbCmd = cbCmdSize;
423 pCmd->paHostParms = NULL;
424 pCmd->cLinPtrs = 0;
425 pCmd->paLinPtrs = NULL;
426
427 rc = pVMMDevState->pHGCMDrv->pfnDisconnect (pVMMDevState->pHGCMDrv, pCmd, pHGCMDisconnect->u32ClientID);
428 }
429 else
430 {
431 rc = VERR_NO_MEMORY;
432 }
433
434 return rc;
435}
436
437static int vmmdevHGCMDisconnectSaved (VMMDevState *pVMMDevState, VMMDevHGCMDisconnect *pHGCMDisconnect, bool *pfHGCMCalled, VBOXHGCMCMD *pSavedCmd)
438{
439 int rc = VINF_SUCCESS;
440
441 uint32_t cbCmdSize = sizeof (struct VBOXHGCMCMD);
442
443 if (pSavedCmd->cbCmd < cbCmdSize)
444 {
445 logRelSavedCmdSizeMismatch ("HGCMConnect", pSavedCmd->cbCmd, cbCmdSize);
446 return VERR_INVALID_PARAMETER;
447 }
448
449 rc = pVMMDevState->pHGCMDrv->pfnDisconnect (pVMMDevState->pHGCMDrv, pSavedCmd, pHGCMDisconnect->u32ClientID);
450 if (RT_SUCCESS (rc))
451 {
452 *pfHGCMCalled = true;
453 }
454
455 return rc;
456}
457
458
459int vmmdevHGCMCall (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, RTGCPHYS GCPhys, bool f64Bits)
460{
461 int rc = VINF_SUCCESS;
462
463 Log(("vmmdevHGCMCall: client id = %d, function = %d, %s bit\n", pHGCMCall->u32ClientID, pHGCMCall->u32Function, f64Bits? "64": "32"));
464
465 /* Compute size and allocate memory block to hold:
466 * struct VBOXHGCMCMD
467 * VBOXHGCMSVCPARM[cParms]
468 * memory buffers for pointer parameters.
469 */
470
471 uint32_t cParms = pHGCMCall->cParms;
472
473 Log(("vmmdevHGCMCall: cParms = %d\n", cParms));
474
475 /*
476 * Compute size of required memory buffer.
477 */
478
479 uint32_t cbCmdSize = sizeof (struct VBOXHGCMCMD) + cParms * sizeof (VBOXHGCMSVCPARM);
480
481 uint32_t i;
482
483 uint32_t cLinPtrs = 0;
484 uint32_t cLinPtrPages = 0;
485
486 if (f64Bits)
487 {
488#ifdef VBOX_WITH_64_BITS_GUESTS
489 HGCMFunctionParameter64 *pGuestParm = VMMDEV_HGCM_CALL_PARMS64(pHGCMCall);
490#else
491 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
492 AssertFailed (); /* This code should not be called in this case */
493#endif /* VBOX_WITH_64_BITS_GUESTS */
494
495 /* Look for pointer parameters, which require a host buffer. */
496 for (i = 0; i < cParms && RT_SUCCESS(rc); i++, pGuestParm++)
497 {
498 switch (pGuestParm->type)
499 {
500 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
501 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
502 case VMMDevHGCMParmType_LinAddr: /* In & Out */
503 {
504 if (pGuestParm->u.Pointer.size > 0)
505 {
506 /* Only pointers with some actual data are counted. */
507 cbCmdSize += pGuestParm->u.Pointer.size;
508
509 cLinPtrs++;
510 /* Take the offset into the current page also into account! */
511 cLinPtrPages += ((pGuestParm->u.Pointer.u.linearAddr & PAGE_OFFSET_MASK)
512 + pGuestParm->u.Pointer.size + PAGE_SIZE - 1) / PAGE_SIZE;
513 }
514
515 Log(("vmmdevHGCMCall: linptr size = %d\n", pGuestParm->u.Pointer.size));
516 } break;
517
518 case VMMDevHGCMParmType_32bit:
519 case VMMDevHGCMParmType_64bit:
520 case VMMDevHGCMParmType_PhysAddr:
521 {
522 } break;
523
524 default:
525 {
526 AssertMsgFailed(("vmmdevHGCMCall: invalid parameter type %x\n", pGuestParm->type));
527 rc = VERR_INVALID_PARAMETER;
528 break;
529 }
530 }
531 }
532 }
533 else
534 {
535#ifdef VBOX_WITH_64_BITS_GUESTS
536 HGCMFunctionParameter32 *pGuestParm = VMMDEV_HGCM_CALL_PARMS32(pHGCMCall);
537#else
538 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
539#endif /* VBOX_WITH_64_BITS_GUESTS */
540
541 /* Look for pointer parameters, which require a host buffer. */
542 for (i = 0; i < cParms && RT_SUCCESS(rc); i++, pGuestParm++)
543 {
544 switch (pGuestParm->type)
545 {
546 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
547 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
548 case VMMDevHGCMParmType_LinAddr: /* In & Out */
549 {
550 if (pGuestParm->u.Pointer.size > 0)
551 {
552 /* Only pointers with some actual data are counted. */
553 cbCmdSize += pGuestParm->u.Pointer.size;
554
555 cLinPtrs++;
556 /* Take the offset into the current page also into account! */
557 cLinPtrPages += ((pGuestParm->u.Pointer.u.linearAddr & PAGE_OFFSET_MASK)
558 + pGuestParm->u.Pointer.size + PAGE_SIZE - 1) / PAGE_SIZE;
559 }
560
561 Log(("vmmdevHGCMCall: linptr size = %d\n", pGuestParm->u.Pointer.size));
562 } break;
563
564 case VMMDevHGCMParmType_32bit:
565 case VMMDevHGCMParmType_64bit:
566 case VMMDevHGCMParmType_PhysAddr:
567 {
568 } break;
569
570 default:
571 {
572 AssertMsgFailed(("vmmdevHGCMCall: invalid parameter type %x\n", pGuestParm->type));
573 rc = VERR_INVALID_PARAMETER;
574 break;
575 }
576 }
577 }
578 }
579
580 if (RT_FAILURE (rc))
581 {
582 return rc;
583 }
584
585 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAlloc (cbCmdSize);
586
587 if (pCmd == NULL)
588 {
589 return VERR_NO_MEMORY;
590 }
591
592 memset (pCmd, 0, sizeof (*pCmd));
593
594 pCmd->cbCmd = cbCmdSize;
595 pCmd->paHostParms = NULL;
596 pCmd->cLinPtrs = cLinPtrs;
597 pCmd->cLinPtrPages = cLinPtrPages;
598
599 if (cLinPtrs > 0)
600 {
601 pCmd->paLinPtrs = (VBOXHGCMLINPTR *)RTMemAlloc ( sizeof (VBOXHGCMLINPTR) * cLinPtrs
602 + sizeof (RTGCPHYS) * cLinPtrPages);
603
604 if (pCmd->paLinPtrs == NULL)
605 {
606 RTMemFree (pCmd);
607 return VERR_NO_MEMORY;
608 }
609 }
610 else
611 {
612 pCmd->paLinPtrs = NULL;
613 }
614
615 /* Process parameters, changing them to host context pointers for easy
616 * processing by connector. Guest must insure that the pointed data is actually
617 * in the guest RAM and remains locked there for entire request processing.
618 */
619
620 if (cParms != 0)
621 {
622 /* Compute addresses of host parms array and first memory buffer. */
623 VBOXHGCMSVCPARM *pHostParm = (VBOXHGCMSVCPARM *)((char *)pCmd + sizeof (struct VBOXHGCMCMD));
624
625 uint8_t *pcBuf = (uint8_t *)pHostParm + cParms * sizeof (VBOXHGCMSVCPARM);
626
627 pCmd->paHostParms = pHostParm;
628
629 uint32_t iLinPtr = 0;
630 RTGCPHYS *pPages = (RTGCPHYS *)((uint8_t *)pCmd->paLinPtrs + sizeof (VBOXHGCMLINPTR) *cLinPtrs);
631
632 if (f64Bits)
633 {
634#ifdef VBOX_WITH_64_BITS_GUESTS
635 HGCMFunctionParameter64 *pGuestParm = VMMDEV_HGCM_CALL_PARMS64(pHGCMCall);
636#else
637 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
638 AssertFailed (); /* This code should not be called in this case */
639#endif /* VBOX_WITH_64_BITS_GUESTS */
640
641
642 for (i = 0; i < cParms && RT_SUCCESS(rc); i++, pGuestParm++, pHostParm++)
643 {
644 switch (pGuestParm->type)
645 {
646 case VMMDevHGCMParmType_32bit:
647 {
648 uint32_t u32 = pGuestParm->u.value32;
649
650 pHostParm->type = VBOX_HGCM_SVC_PARM_32BIT;
651 pHostParm->u.uint32 = u32;
652
653 Log(("vmmdevHGCMCall: uint32 guest parameter %u\n", u32));
654 break;
655 }
656
657 case VMMDevHGCMParmType_64bit:
658 {
659 uint64_t u64 = pGuestParm->u.value64;
660
661 pHostParm->type = VBOX_HGCM_SVC_PARM_64BIT;
662 pHostParm->u.uint64 = u64;
663
664 Log(("vmmdevHGCMCall: uint64 guest parameter %llu\n", u64));
665 break;
666 }
667
668 case VMMDevHGCMParmType_PhysAddr:
669 {
670 uint32_t size = pGuestParm->u.Pointer.size;
671#ifdef LOG_ENABLED
672 RTGCPHYS physAddr = pGuestParm->u.Pointer.u.physAddr;
673#endif
674
675 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
676 pHostParm->u.pointer.size = size;
677
678 AssertFailed();
679 /* rc = PDMDevHlpPhys2HCVirt (pVMMDevState->pDevIns, physAddr, size, &pHostParm->u.pointer.addr); */
680
681 Log(("vmmdevHGCMCall: PhysAddr guest parameter %RGp\n", physAddr));
682 break;
683 }
684
685 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
686 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
687 case VMMDevHGCMParmType_LinAddr: /* In & Out */
688 {
689 uint32_t size = pGuestParm->u.Pointer.size;
690 RTGCPTR linearAddr = pGuestParm->u.Pointer.u.linearAddr;
691
692 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
693 pHostParm->u.pointer.size = size;
694
695 /* Copy guest data to an allocated buffer, so
696 * services can use the data.
697 */
698
699 if (size == 0)
700 {
701 pHostParm->u.pointer.addr = NULL;
702 }
703 else
704 {
705 /* Don't overdo it */
706 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_Out)
707 rc = PDMDevHlpPhysReadGCVirt(pVMMDevState->pDevIns, pcBuf, linearAddr, size);
708 else
709 rc = VINF_SUCCESS;
710
711 if (RT_SUCCESS(rc))
712 {
713 pHostParm->u.pointer.addr = pcBuf;
714 pcBuf += size;
715
716 /* Remember the guest physical pages that belong to the virtual address region.
717 * Do it for all linear pointers because load state will require In pointer info too.
718 */
719 rc = vmmdevHGCMSaveLinPtr (pVMMDevState->pDevIns, i, linearAddr, size, iLinPtr, pCmd->paLinPtrs, &pPages);
720
721 iLinPtr++;
722 }
723 }
724
725 Log(("vmmdevHGCMCall: LinAddr guest parameter %RGv, rc = %Rrc\n", linearAddr, rc));
726 break;
727 }
728
729 /* just to shut up gcc */
730 default:
731 break;
732 }
733 }
734 }
735 else
736 {
737#ifdef VBOX_WITH_64_BITS_GUESTS
738 HGCMFunctionParameter32 *pGuestParm = VMMDEV_HGCM_CALL_PARMS32(pHGCMCall);
739#else
740 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
741#endif /* VBOX_WITH_64_BITS_GUESTS */
742
743 for (i = 0; i < cParms && RT_SUCCESS(rc); i++, pGuestParm++, pHostParm++)
744 {
745 switch (pGuestParm->type)
746 {
747 case VMMDevHGCMParmType_32bit:
748 {
749 uint32_t u32 = pGuestParm->u.value32;
750
751 pHostParm->type = VBOX_HGCM_SVC_PARM_32BIT;
752 pHostParm->u.uint32 = u32;
753
754 Log(("vmmdevHGCMCall: uint32 guest parameter %u\n", u32));
755 break;
756 }
757
758 case VMMDevHGCMParmType_64bit:
759 {
760 uint64_t u64 = pGuestParm->u.value64;
761
762 pHostParm->type = VBOX_HGCM_SVC_PARM_64BIT;
763 pHostParm->u.uint64 = u64;
764
765 Log(("vmmdevHGCMCall: uint64 guest parameter %llu\n", u64));
766 break;
767 }
768
769 case VMMDevHGCMParmType_PhysAddr:
770 {
771 uint32_t size = pGuestParm->u.Pointer.size;
772#ifdef LOG_ENABLED
773 RTGCPHYS physAddr = pGuestParm->u.Pointer.u.physAddr;
774#endif
775
776 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
777 pHostParm->u.pointer.size = size;
778
779 AssertFailed();
780 /* rc = PDMDevHlpPhys2HCVirt (pVMMDevState->pDevIns, physAddr, size, &pHostParm->u.pointer.addr); */
781
782 Log(("vmmdevHGCMCall: PhysAddr guest parameter %RGp\n", physAddr));
783 break;
784 }
785
786 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
787 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
788 case VMMDevHGCMParmType_LinAddr: /* In & Out */
789 {
790 uint32_t size = pGuestParm->u.Pointer.size;
791 RTGCPTR linearAddr = pGuestParm->u.Pointer.u.linearAddr;
792
793 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
794 pHostParm->u.pointer.size = size;
795
796 /* Copy guest data to an allocated buffer, so
797 * services can use the data.
798 */
799
800 if (size == 0)
801 {
802 pHostParm->u.pointer.addr = NULL;
803 }
804 else
805 {
806 /* Don't overdo it */
807 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_Out)
808 rc = PDMDevHlpPhysReadGCVirt(pVMMDevState->pDevIns, pcBuf, linearAddr, size);
809 else
810 rc = VINF_SUCCESS;
811
812 if (RT_SUCCESS(rc))
813 {
814 pHostParm->u.pointer.addr = pcBuf;
815 pcBuf += size;
816
817 /* Remember the guest physical pages that belong to the virtual address region.
818 * Do it for all linear pointers because load state will require In pointer info too.
819 */
820 rc = vmmdevHGCMSaveLinPtr (pVMMDevState->pDevIns, i, linearAddr, size, iLinPtr, pCmd->paLinPtrs, &pPages);
821
822 iLinPtr++;
823 }
824 }
825
826 Log(("vmmdevHGCMCall: LinAddr guest parameter %RGv, rc = %Rrc\n", linearAddr, rc));
827 break;
828 }
829
830 /* just to shut up gcc */
831 default:
832 break;
833 }
834 }
835 }
836 }
837
838 if (RT_SUCCESS (rc))
839 {
840 vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMCall->header.header.size, VBOXHGCMCMDTYPE_CALL);
841
842 /* Pass the function call to HGCM connector for actual processing */
843 rc = pVMMDevState->pHGCMDrv->pfnCall (pVMMDevState->pHGCMDrv, pCmd, pHGCMCall->u32ClientID, pHGCMCall->u32Function, cParms, pCmd->paHostParms);
844 }
845 else
846 {
847 if (pCmd->paLinPtrs)
848 {
849 RTMemFree (pCmd->paLinPtrs);
850 }
851
852 RTMemFree (pCmd);
853 }
854
855 return rc;
856}
857
858static void logRelLoadStatePointerIndexMismatch (uint32_t iParm, uint32_t iSavedParm, int iLinPtr, int cLinPtrs)
859{
860 LogRel(("Warning: VMMDev load state: a pointer parameter index mismatch %d (expected %d) (%d/%d)\n",
861 (int)iParm, (int)iSavedParm, iLinPtr, cLinPtrs));
862}
863
864static void logRelLoadStateBufferSizeMismatch (uint32_t size, uint32_t iPage, uint32_t cPages)
865{
866 LogRel(("Warning: VMMDev load state: buffer size mismatch: size %d, page %d/%d\n",
867 (int)size, (int)iPage, (int)cPages));
868}
869
870
871static int vmmdevHGCMCallSaved (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, bool f64Bits, bool *pfHGCMCalled, VBOXHGCMCMD *pSavedCmd)
872{
873 int rc = VINF_SUCCESS;
874
875 Log(("vmmdevHGCMCallSaved: client id = %d, function = %d, %s bit\n", pHGCMCall->u32ClientID, pHGCMCall->u32Function, f64Bits? "64": "32"));
876
877 /* Compute size and allocate memory block to hold:
878 * struct VBOXHGCMCMD
879 * VBOXHGCMSVCPARM[cParms]
880 * memory buffers for pointer parameters.
881 */
882
883 uint32_t cParms = pHGCMCall->cParms;
884
885 Log(("vmmdevHGCMCall: cParms = %d\n", cParms));
886
887 /*
888 * Compute size of required memory buffer.
889 */
890
891 pSavedCmd->paHostParms = NULL;
892
893 /* Process parameters, changing them to host context pointers for easy
894 * processing by connector. Guest must insure that the pointed data is actually
895 * in the guest RAM and remains locked there for entire request processing.
896 */
897
898 if (cParms != 0)
899 {
900 /* Compute addresses of host parms array and first memory buffer. */
901 VBOXHGCMSVCPARM *pHostParm = (VBOXHGCMSVCPARM *)((uint8_t *)pSavedCmd + sizeof (struct VBOXHGCMCMD));
902
903 uint8_t *pu8Buf = (uint8_t *)pHostParm + cParms * sizeof (VBOXHGCMSVCPARM);
904
905 pSavedCmd->paHostParms = pHostParm;
906
907 uint32_t iParm;
908 int iLinPtr = 0;
909
910 if (f64Bits)
911 {
912#ifdef VBOX_WITH_64_BITS_GUESTS
913 HGCMFunctionParameter64 *pGuestParm = VMMDEV_HGCM_CALL_PARMS64(pHGCMCall);
914#else
915 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
916 AssertFailed (); /* This code should not be called in this case */
917#endif /* VBOX_WITH_64_BITS_GUESTS */
918
919 for (iParm = 0; iParm < cParms && RT_SUCCESS(rc); iParm++, pGuestParm++, pHostParm++)
920 {
921 switch (pGuestParm->type)
922 {
923 case VMMDevHGCMParmType_32bit:
924 {
925 uint32_t u32 = pGuestParm->u.value32;
926
927 pHostParm->type = VBOX_HGCM_SVC_PARM_32BIT;
928 pHostParm->u.uint32 = u32;
929
930 Log(("vmmdevHGCMCall: uint32 guest parameter %u\n", u32));
931 break;
932 }
933
934 case VMMDevHGCMParmType_64bit:
935 {
936 uint64_t u64 = pGuestParm->u.value64;
937
938 pHostParm->type = VBOX_HGCM_SVC_PARM_64BIT;
939 pHostParm->u.uint64 = u64;
940
941 Log(("vmmdevHGCMCall: uint64 guest parameter %llu\n", u64));
942 break;
943 }
944
945 case VMMDevHGCMParmType_PhysAddr:
946 {
947 uint32_t size = pGuestParm->u.Pointer.size;
948#ifdef LOG_ENABLED
949 RTGCPHYS physAddr = pGuestParm->u.Pointer.u.physAddr;
950#endif
951
952 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
953 pHostParm->u.pointer.size = size;
954
955 AssertFailed();
956 /* rc = PDMDevHlpPhys2HCVirt (pVMMDevState->pDevIns, physAddr, size, &pHostParm->u.pointer.addr); */
957
958 Log(("vmmdevHGCMCall: PhysAddr guest parameter %RGp\n", physAddr));
959 break;
960 }
961
962 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
963 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
964 case VMMDevHGCMParmType_LinAddr: /* In & Out */
965 {
966 uint32_t size = pGuestParm->u.Pointer.size;
967
968 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
969 pHostParm->u.pointer.size = size;
970
971 /* Copy guest data to an allocated buffer, so
972 * services can use the data.
973 */
974
975 if (size == 0)
976 {
977 pHostParm->u.pointer.addr = NULL;
978 }
979 else
980 {
981 /* The saved command already have the page list in pCmd->paLinPtrs.
982 * Read data from guest pages.
983 */
984 /* Don't overdo it */
985 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_Out)
986 {
987 if ( iLinPtr >= pSavedCmd->cLinPtrs
988 || pSavedCmd->paLinPtrs[iLinPtr].iParm != iParm)
989 {
990 logRelLoadStatePointerIndexMismatch (iParm, pSavedCmd->paLinPtrs[iLinPtr].iParm, iLinPtr, pSavedCmd->cLinPtrs);
991 rc = VERR_INVALID_PARAMETER;
992 }
993 else
994 {
995 VBOXHGCMLINPTR *pLinPtr = &pSavedCmd->paLinPtrs[iLinPtr];
996
997 uint32_t iPage;
998 uint32_t offPage = pLinPtr->offFirstPage;
999 size_t cbRemaining = size;
1000 uint8_t *pu8Dst = pu8Buf;
1001 for (iPage = 0; iPage < pLinPtr->cPages; iPage++)
1002 {
1003 if (cbRemaining == 0)
1004 {
1005 logRelLoadStateBufferSizeMismatch (size, iPage, pLinPtr->cPages);
1006 break;
1007 }
1008
1009 size_t cbChunk = PAGE_SIZE - offPage;
1010
1011 if (cbChunk > cbRemaining)
1012 {
1013 cbChunk = cbRemaining;
1014 }
1015
1016 rc = PDMDevHlpPhysRead(pVMMDevState->pDevIns,
1017 pLinPtr->paPages[iPage] + offPage,
1018 pu8Dst, cbChunk);
1019
1020 AssertRCBreak(rc);
1021
1022 offPage = 0; /* A next page is read from 0 offset. */
1023 cbRemaining -= cbChunk;
1024 pu8Dst += cbChunk;
1025 }
1026 }
1027 }
1028 else
1029 rc = VINF_SUCCESS;
1030
1031 if (RT_SUCCESS(rc))
1032 {
1033 pHostParm->u.pointer.addr = pu8Buf;
1034 pu8Buf += size;
1035
1036 iLinPtr++;
1037 }
1038 }
1039
1040 Log(("vmmdevHGCMCall: LinAddr guest parameter %RGv, rc = %Rrc\n",
1041 pGuestParm->u.Pointer.u.linearAddr, rc));
1042 break;
1043 }
1044
1045 /* just to shut up gcc */
1046 default:
1047 break;
1048 }
1049 }
1050 }
1051 else
1052 {
1053#ifdef VBOX_WITH_64_BITS_GUESTS
1054 HGCMFunctionParameter32 *pGuestParm = VMMDEV_HGCM_CALL_PARMS32(pHGCMCall);
1055#else
1056 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
1057#endif /* VBOX_WITH_64_BITS_GUESTS */
1058
1059 for (iParm = 0; iParm < cParms && RT_SUCCESS(rc); iParm++, pGuestParm++, pHostParm++)
1060 {
1061 switch (pGuestParm->type)
1062 {
1063 case VMMDevHGCMParmType_32bit:
1064 {
1065 uint32_t u32 = pGuestParm->u.value32;
1066
1067 pHostParm->type = VBOX_HGCM_SVC_PARM_32BIT;
1068 pHostParm->u.uint32 = u32;
1069
1070 Log(("vmmdevHGCMCall: uint32 guest parameter %u\n", u32));
1071 break;
1072 }
1073
1074 case VMMDevHGCMParmType_64bit:
1075 {
1076 uint64_t u64 = pGuestParm->u.value64;
1077
1078 pHostParm->type = VBOX_HGCM_SVC_PARM_64BIT;
1079 pHostParm->u.uint64 = u64;
1080
1081 Log(("vmmdevHGCMCall: uint64 guest parameter %llu\n", u64));
1082 break;
1083 }
1084
1085 case VMMDevHGCMParmType_PhysAddr:
1086 {
1087 uint32_t size = pGuestParm->u.Pointer.size;
1088#ifdef LOG_ENABLED
1089 RTGCPHYS physAddr = pGuestParm->u.Pointer.u.physAddr;
1090#endif
1091
1092 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
1093 pHostParm->u.pointer.size = size;
1094
1095 AssertFailed();
1096 /* rc = PDMDevHlpPhys2HCVirt (pVMMDevState->pDevIns, physAddr, size, &pHostParm->u.pointer.addr); */
1097
1098 Log(("vmmdevHGCMCall: PhysAddr guest parameter %RGp\n", physAddr));
1099 break;
1100 }
1101
1102 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
1103 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
1104 case VMMDevHGCMParmType_LinAddr: /* In & Out */
1105 {
1106 uint32_t size = pGuestParm->u.Pointer.size;
1107
1108 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
1109 pHostParm->u.pointer.size = size;
1110
1111 /* Copy guest data to an allocated buffer, so
1112 * services can use the data.
1113 */
1114
1115 if (size == 0)
1116 {
1117 pHostParm->u.pointer.addr = NULL;
1118 }
1119 else
1120 {
1121 /* The saved command already have the page list in pCmd->paLinPtrs.
1122 * Read data from guest pages.
1123 */
1124 /* Don't overdo it */
1125 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_Out)
1126 {
1127 if ( iLinPtr >= pSavedCmd->cLinPtrs
1128 || pSavedCmd->paLinPtrs[iLinPtr].iParm != iParm)
1129 {
1130 logRelLoadStatePointerIndexMismatch (iParm, pSavedCmd->paLinPtrs[iLinPtr].iParm, iLinPtr, pSavedCmd->cLinPtrs);
1131 rc = VERR_INVALID_PARAMETER;
1132 }
1133 else
1134 {
1135 VBOXHGCMLINPTR *pLinPtr = &pSavedCmd->paLinPtrs[iLinPtr];
1136
1137 uint32_t iPage;
1138 uint32_t offPage = pLinPtr->offFirstPage;
1139 size_t cbRemaining = size;
1140 uint8_t *pu8Dst = pu8Buf;
1141 for (iPage = 0; iPage < pLinPtr->cPages; iPage++)
1142 {
1143 if (cbRemaining == 0)
1144 {
1145 logRelLoadStateBufferSizeMismatch (size, iPage, pLinPtr->cPages);
1146 break;
1147 }
1148
1149 size_t cbChunk = PAGE_SIZE - offPage;
1150
1151 if (cbChunk > cbRemaining)
1152 {
1153 cbChunk = cbRemaining;
1154 }
1155
1156 rc = PDMDevHlpPhysRead(pVMMDevState->pDevIns,
1157 pLinPtr->paPages[iPage] + offPage,
1158 pu8Dst, cbChunk);
1159
1160 AssertRCBreak(rc);
1161
1162 offPage = 0; /* A next page is read from 0 offset. */
1163 cbRemaining -= cbChunk;
1164 pu8Dst += cbChunk;
1165 }
1166 }
1167 }
1168 else
1169 rc = VINF_SUCCESS;
1170
1171 if (RT_SUCCESS(rc))
1172 {
1173 pHostParm->u.pointer.addr = pu8Buf;
1174 pu8Buf += size;
1175
1176 iLinPtr++;
1177 }
1178 }
1179
1180 Log(("vmmdevHGCMCall: LinAddr guest parameter %RGv, rc = %Rrc\n",
1181 pGuestParm->u.Pointer.u.linearAddr, rc));
1182 break;
1183 }
1184
1185 /* just to shut up gcc */
1186 default:
1187 break;
1188 }
1189 }
1190 }
1191 }
1192
1193 if (RT_SUCCESS (rc))
1194 {
1195 /* Pass the function call to HGCM connector for actual processing */
1196 rc = pVMMDevState->pHGCMDrv->pfnCall (pVMMDevState->pHGCMDrv, pSavedCmd, pHGCMCall->u32ClientID, pHGCMCall->u32Function, cParms, pSavedCmd->paHostParms);
1197 if (RT_SUCCESS (rc))
1198 {
1199 *pfHGCMCalled = true;
1200 }
1201 }
1202
1203 return rc;
1204}
1205
1206/* @thread EMT */
1207int vmmdevHGCMCancel (VMMDevState *pVMMDevState, VMMDevHGCMCancel *pHGCMCancel, RTGCPHYS GCPhys)
1208{
1209 int rc = VINF_SUCCESS;
1210
1211 NOREF(pHGCMCancel);
1212
1213 Log(("vmmdevHGCMCancel\n"));
1214
1215 /* Find the command in the list. */
1216 PVBOXHGCMCMD pCmd = vmmdevHGCMFindCommand (pVMMDevState, GCPhys);
1217
1218 if (pCmd)
1219 {
1220 pCmd->fCancelled = true;
1221 }
1222 else
1223 {
1224 rc = VERR_INVALID_PARAMETER;
1225 }
1226
1227 return rc;
1228}
1229
1230static int vmmdevHGCMCmdVerify (PVBOXHGCMCMD pCmd, VMMDevHGCMRequestHeader *pHeader)
1231{
1232 switch (pCmd->enmCmdType)
1233 {
1234 case VBOXHGCMCMDTYPE_CONNECT:
1235 if ( pHeader->header.requestType == VMMDevReq_HGCMConnect
1236 || pHeader->header.requestType == VMMDevReq_HGCMCancel) return VINF_SUCCESS;
1237 break;
1238
1239 case VBOXHGCMCMDTYPE_DISCONNECT:
1240 if ( pHeader->header.requestType == VMMDevReq_HGCMDisconnect
1241 || pHeader->header.requestType == VMMDevReq_HGCMCancel) return VINF_SUCCESS;
1242 break;
1243
1244 case VBOXHGCMCMDTYPE_CALL:
1245#ifdef VBOX_WITH_64_BITS_GUESTS
1246 if ( pHeader->header.requestType == VMMDevReq_HGCMCall32
1247 || pHeader->header.requestType == VMMDevReq_HGCMCall64
1248 || pHeader->header.requestType == VMMDevReq_HGCMCancel) return VINF_SUCCESS;
1249#else
1250 if ( pHeader->header.requestType == VMMDevReq_HGCMCall
1251 || pHeader->header.requestType == VMMDevReq_HGCMCancel) return VINF_SUCCESS;
1252#endif /* VBOX_WITH_64_BITS_GUESTS */
1253
1254 break;
1255
1256 default:
1257 AssertFailed ();
1258 }
1259
1260 LogRel(("VMMDEV: Invalid HGCM command: pCmd->enmCmdType = 0x%08X, pHeader->header.requestType = 0x%08X\n",
1261 pCmd->enmCmdType, pHeader->header.requestType));
1262 return VERR_INVALID_PARAMETER;
1263}
1264
1265#define PDMIHGCMPORT_2_VMMDEVSTATE(pInterface) ( (VMMDevState *) ((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, HGCMPort)) )
1266
1267DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result, PVBOXHGCMCMD pCmd)
1268{
1269 VMMDevState *pVMMDevState = PDMIHGCMPORT_2_VMMDEVSTATE(pInterface);
1270
1271 int rc = VINF_SUCCESS;
1272
1273 if (result == VINF_HGCM_SAVE_STATE)
1274 {
1275 /* If the completion routine was called because HGCM saves its state,
1276 * then currently nothing to be done here. The pCmd stays in the list
1277 * and will be saved later when the VMMDev state will be saved.
1278 *
1279 * It it assumed that VMMDev saves state after the HGCM services,
1280 * and, therefore, VBOXHGCMCMD structures are not removed by
1281 * vmmdevHGCMSaveState from the list, while HGCM uses them.
1282 */
1283 LogFlowFunc(("VINF_HGCM_SAVE_STATE for command %p\n", pCmd));
1284 return;
1285 }
1286
1287 /* Check whether the command has been already cancelled by the guest.
1288 * If it was cancelled, then the data must not be written back to the
1289 * guest RAM.
1290 */
1291 if (pCmd->fCancelled)
1292 {
1293 /* Just remove the command from the internal list, so the memory can be freed. */
1294 LogFlowFunc(("A cancelled command %p\n", pCmd));
1295 vmmdevHGCMRemoveCommand (pVMMDevState, pCmd);
1296 }
1297 else
1298 {
1299 /* Preallocated block for requests which have up to 8 parameters (most of requests). */
1300#ifdef VBOX_WITH_64_BITS_GUESTS
1301 uint8_t au8Prealloc[sizeof (VMMDevHGCMCall) + 8 * sizeof (HGCMFunctionParameter64)];
1302#else
1303 uint8_t au8Prealloc[sizeof (VMMDevHGCMCall) + 8 * sizeof (HGCMFunctionParameter)];
1304#endif /* VBOX_WITH_64_BITS_GUESTS */
1305
1306 VMMDevHGCMRequestHeader *pHeader;
1307
1308 if (pCmd->cbSize <= sizeof (au8Prealloc))
1309 {
1310 pHeader = (VMMDevHGCMRequestHeader *)&au8Prealloc[0];
1311 }
1312 else
1313 {
1314 pHeader = (VMMDevHGCMRequestHeader *)RTMemAlloc (pCmd->cbSize);
1315 Assert(pHeader);
1316 if (pHeader == NULL)
1317 {
1318 LogRel(("VMMDev: Failed to allocate %d bytes for HGCM request completion!!!\n", pCmd->cbSize));
1319
1320 /* Do some cleanup. The command have to be excluded from list of active commands anyway. */
1321 vmmdevHGCMRemoveCommand (pVMMDevState, pCmd);
1322 return;
1323 }
1324 }
1325
1326 PDMDevHlpPhysRead(pVMMDevState->pDevIns, pCmd->GCPhys, pHeader, pCmd->cbSize);
1327
1328 /* Setup return codes. */
1329 pHeader->result = result;
1330
1331 /* Verify the request type. */
1332 rc = vmmdevHGCMCmdVerify (pCmd, pHeader);
1333
1334 if (RT_SUCCESS (rc))
1335 {
1336 /* Update parameters and data buffers. */
1337
1338 switch (pHeader->header.requestType)
1339 {
1340#ifdef VBOX_WITH_64_BITS_GUESTS
1341 case VMMDevReq_HGCMCall64:
1342 {
1343 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pHeader;
1344
1345 uint32_t cParms = pHGCMCall->cParms;
1346
1347 VBOXHGCMSVCPARM *pHostParm = pCmd->paHostParms;
1348
1349 uint32_t i;
1350 uint32_t iLinPtr = 0;
1351
1352 HGCMFunctionParameter64 *pGuestParm = VMMDEV_HGCM_CALL_PARMS64(pHGCMCall);
1353
1354 for (i = 0; i < cParms; i++, pGuestParm++, pHostParm++)
1355 {
1356 switch (pGuestParm->type)
1357 {
1358 case VMMDevHGCMParmType_32bit:
1359 {
1360 pGuestParm->u.value32 = pHostParm->u.uint32;
1361 } break;
1362
1363 case VMMDevHGCMParmType_64bit:
1364 {
1365 pGuestParm->u.value64 = pHostParm->u.uint64;
1366 } break;
1367
1368 case VMMDevHGCMParmType_PhysAddr:
1369 {
1370 /* do nothing */
1371 } break;
1372
1373 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
1374 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
1375 case VMMDevHGCMParmType_LinAddr: /* In & Out */
1376 {
1377 /* Copy buffer back to guest memory. */
1378 uint32_t size = pGuestParm->u.Pointer.size;
1379
1380 if (size > 0)
1381 {
1382 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
1383 {
1384 /* Use the saved page list to write data back to the guest RAM. */
1385 rc = vmmdevHGCMWriteLinPtr (pVMMDevState->pDevIns, i, pHostParm->u.pointer.addr, size, iLinPtr, pCmd->paLinPtrs);
1386 AssertReleaseRC(rc);
1387 }
1388
1389 /* All linptrs with size > 0 were saved. Advance the index to the next linptr. */
1390 iLinPtr++;
1391 }
1392 } break;
1393
1394 default:
1395 {
1396 /* This indicates that the guest request memory was corrupted. */
1397 AssertReleaseMsgFailed(("hgcmCompleted: invalid parameter type %08X\n", pGuestParm->type));
1398 }
1399 }
1400 }
1401 break;
1402 }
1403
1404 case VMMDevReq_HGCMCall32:
1405 {
1406 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pHeader;
1407
1408 uint32_t cParms = pHGCMCall->cParms;
1409
1410 VBOXHGCMSVCPARM *pHostParm = pCmd->paHostParms;
1411
1412 uint32_t i;
1413 uint32_t iLinPtr = 0;
1414
1415 HGCMFunctionParameter32 *pGuestParm = VMMDEV_HGCM_CALL_PARMS32(pHGCMCall);
1416
1417 for (i = 0; i < cParms; i++, pGuestParm++, pHostParm++)
1418 {
1419 switch (pGuestParm->type)
1420 {
1421 case VMMDevHGCMParmType_32bit:
1422 {
1423 pGuestParm->u.value32 = pHostParm->u.uint32;
1424 } break;
1425
1426 case VMMDevHGCMParmType_64bit:
1427 {
1428 pGuestParm->u.value64 = pHostParm->u.uint64;
1429 } break;
1430
1431 case VMMDevHGCMParmType_PhysAddr:
1432 {
1433 /* do nothing */
1434 } break;
1435
1436 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
1437 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
1438 case VMMDevHGCMParmType_LinAddr: /* In & Out */
1439 {
1440 /* Copy buffer back to guest memory. */
1441 uint32_t size = pGuestParm->u.Pointer.size;
1442
1443 if (size > 0)
1444 {
1445 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
1446 {
1447 /* Use the saved page list to write data back to the guest RAM. */
1448 rc = vmmdevHGCMWriteLinPtr (pVMMDevState->pDevIns, i, pHostParm->u.pointer.addr, size, iLinPtr, pCmd->paLinPtrs);
1449 AssertReleaseRC(rc);
1450 }
1451
1452 /* All linptrs with size > 0 were saved. Advance the index to the next linptr. */
1453 iLinPtr++;
1454 }
1455 } break;
1456
1457 default:
1458 {
1459 /* This indicates that the guest request memory was corrupted. */
1460 AssertReleaseMsgFailed(("hgcmCompleted: invalid parameter type %08X\n", pGuestParm->type));
1461 }
1462 }
1463 }
1464 break;
1465 }
1466#else
1467 case VMMDevReq_HGCMCall:
1468 {
1469 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pHeader;
1470
1471 uint32_t cParms = pHGCMCall->cParms;
1472
1473 VBOXHGCMSVCPARM *pHostParm = pCmd->paHostParms;
1474
1475 uint32_t i;
1476 uint32_t iLinPtr = 0;
1477
1478 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
1479
1480 for (i = 0; i < cParms; i++, pGuestParm++, pHostParm++)
1481 {
1482 switch (pGuestParm->type)
1483 {
1484 case VMMDevHGCMParmType_32bit:
1485 {
1486 pGuestParm->u.value32 = pHostParm->u.uint32;
1487 } break;
1488
1489 case VMMDevHGCMParmType_64bit:
1490 {
1491 pGuestParm->u.value64 = pHostParm->u.uint64;
1492 } break;
1493
1494 case VMMDevHGCMParmType_PhysAddr:
1495 {
1496 /* do nothing */
1497 } break;
1498
1499 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
1500 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
1501 case VMMDevHGCMParmType_LinAddr: /* In & Out */
1502 {
1503 /* Copy buffer back to guest memory. */
1504 uint32_t size = pGuestParm->u.Pointer.size;
1505
1506 if (size > 0)
1507 {
1508 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
1509 {
1510 /* Use the saved page list to write data back to the guest RAM. */
1511 rc = vmmdevHGCMWriteLinPtr (pVMMDevState->pDevIns, i, pHostParm->u.pointer.addr, size, iLinPtr, pCmd->paLinPtrs);
1512 AssertReleaseRC(rc);
1513 }
1514
1515 /* All linptrs with size > 0 were saved. Advance the index to the next linptr. */
1516 iLinPtr++;
1517 }
1518 } break;
1519
1520 default:
1521 {
1522 /* This indicates that the guest request memory was corrupted. */
1523 AssertReleaseMsgFailed(("hgcmCompleted: invalid parameter type %08X\n", pGuestParm->type));
1524 }
1525 }
1526 }
1527 break;
1528 }
1529#endif /* VBOX_WITH_64_BITS_GUESTS */
1530 case VMMDevReq_HGCMConnect:
1531 {
1532 VMMDevHGCMConnect *pHGCMConnectCopy = (VMMDevHGCMConnect *)(pCmd+1);
1533
1534 /* save the client id in the guest request packet */
1535 VMMDevHGCMConnect *pHGCMConnect = (VMMDevHGCMConnect *)pHeader;
1536 pHGCMConnect->u32ClientID = pHGCMConnectCopy->u32ClientID;
1537 break;
1538 }
1539
1540 default:
1541 /* make gcc happy */
1542 break;
1543 }
1544 }
1545 else
1546 {
1547 /* Command type is wrong. Return error to the guest. */
1548 pHeader->header.rc = rc;
1549 }
1550
1551 /* Mark request as processed. */
1552 pHeader->fu32Flags |= VBOX_HGCM_REQ_DONE;
1553
1554 /* Write back the request */
1555 PDMDevHlpPhysWrite(pVMMDevState->pDevIns, pCmd->GCPhys, pHeader, pCmd->cbSize);
1556
1557 /* The command has been completely processed and can be removed from the list. */
1558 vmmdevHGCMRemoveCommand (pVMMDevState, pCmd);
1559
1560 /* Now, when the command was removed from the internal list, notify the guest. */
1561 VMMDevNotifyGuest (pVMMDevState, VMMDEV_EVENT_HGCM);
1562
1563 if ((uint8_t *)pHeader != &au8Prealloc[0])
1564 {
1565 /* Only if it was allocated from heap. */
1566 RTMemFree (pHeader);
1567 }
1568 }
1569
1570 /* Deallocate the command memory. */
1571 if (pCmd->paLinPtrs)
1572 {
1573 RTMemFree (pCmd->paLinPtrs);
1574 }
1575
1576 RTMemFree (pCmd);
1577
1578 return;
1579}
1580
1581DECLCALLBACK(void) hgcmCompleted (PPDMIHGCMPORT pInterface, int32_t result, PVBOXHGCMCMD pCmd)
1582{
1583 VMMDevState *pVMMDevState = PDMIHGCMPORT_2_VMMDEVSTATE(pInterface);
1584
1585 /* Not safe to execute asynchroneously; forward to EMT */
1586 int rc = VMR3ReqCallEx(PDMDevHlpGetVM(pVMMDevState->pDevIns), VMCPUID_ANY, NULL, 0, VMREQFLAGS_NO_WAIT | VMREQFLAGS_VOID,
1587 (PFNRT)hgcmCompletedWorker, 3, pInterface, result, pCmd);
1588 AssertRC(rc);
1589}
1590
1591/* @thread EMT */
1592int vmmdevHGCMSaveState(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
1593{
1594 /* Save information about pending requests.
1595 * Only GCPtrs are of interest.
1596 */
1597 int rc = VINF_SUCCESS;
1598
1599 LogFlowFunc(("\n"));
1600
1601 /* Compute how many commands are pending. */
1602 uint32_t cCmds = 0;
1603
1604 PVBOXHGCMCMD pIter = pVMMDevState->pHGCMCmdList;
1605
1606 while (pIter)
1607 {
1608 LogFlowFunc (("pIter %p\n", pIter));
1609 cCmds++;
1610 pIter = pIter->pNext;
1611 }
1612
1613 LogFlowFunc(("cCmds = %d\n", cCmds));
1614
1615 /* Save number of commands. */
1616 rc = SSMR3PutU32(pSSM, cCmds);
1617 AssertRCReturn(rc, rc);
1618
1619 if (cCmds > 0)
1620 {
1621 pIter = pVMMDevState->pHGCMCmdList;
1622
1623 while (pIter)
1624 {
1625 PVBOXHGCMCMD pNext = pIter->pNext;
1626
1627 LogFlowFunc (("Saving %RGp, size %d\n", pIter->GCPhys, pIter->cbSize));
1628
1629 /* GC physical address of the guest request. */
1630 rc = SSMR3PutGCPhys(pSSM, pIter->GCPhys);
1631 AssertRCReturn(rc, rc);
1632
1633 /* Request packet size */
1634 rc = SSMR3PutU32(pSSM, pIter->cbSize);
1635 AssertRCReturn(rc, rc);
1636
1637 /*
1638 * Version 9+: save complete information about commands.
1639 */
1640
1641 /* Size of entire command. */
1642 rc = SSMR3PutU32(pSSM, pIter->cbCmd);
1643 AssertRCReturn(rc, rc);
1644
1645 /* The type of the command. */
1646 rc = SSMR3PutU32(pSSM, (uint32_t)pIter->enmCmdType);
1647 AssertRCReturn(rc, rc);
1648
1649 /* Whether the command was cancelled by the guest. */
1650 rc = SSMR3PutBool(pSSM, pIter->fCancelled);
1651 AssertRCReturn(rc, rc);
1652
1653 /* Linear pointer parameters information. How many pointers. Always 0 if not a call command. */
1654 rc = SSMR3PutU32(pSSM, (uint32_t)pIter->cLinPtrs);
1655 AssertRCReturn(rc, rc);
1656
1657 if (pIter->cLinPtrs > 0)
1658 {
1659 /* How many pages for all linptrs in this command. */
1660 rc = SSMR3PutU32(pSSM, (uint32_t)pIter->cLinPtrPages);
1661 AssertRCReturn(rc, rc);
1662 }
1663
1664 int i;
1665 for (i = 0; i < pIter->cLinPtrs; i++)
1666 {
1667 /* Pointer to descriptions of linear pointers. */
1668 VBOXHGCMLINPTR *pLinPtr = &pIter->paLinPtrs[i];
1669
1670 /* Index of the parameter. */
1671 rc = SSMR3PutU32(pSSM, (uint32_t)pLinPtr->iParm);
1672 AssertRCReturn(rc, rc);
1673
1674 /* Offset in the first physical page of the region. */
1675 rc = SSMR3PutU32(pSSM, pLinPtr->offFirstPage);
1676 AssertRCReturn(rc, rc);
1677
1678 /* How many pages. */
1679 rc = SSMR3PutU32(pSSM, pLinPtr->cPages);
1680 AssertRCReturn(rc, rc);
1681
1682 uint32_t iPage;
1683 for (iPage = 0; iPage < pLinPtr->cPages; iPage++)
1684 {
1685 /* Array of the GC physical addresses for these pages.
1686 * It is assumed that the physical address of the locked resident
1687 * guest page does not change.
1688 */
1689 rc = SSMR3PutGCPhys(pSSM, pLinPtr->paPages[iPage]);
1690 AssertRCReturn(rc, rc);
1691 }
1692 }
1693
1694 /* A reserved field, will allow to extend saved data for a command. */
1695 rc = SSMR3PutU32(pSSM, 0);
1696 AssertRCReturn(rc, rc);
1697
1698 vmmdevHGCMRemoveCommand (pVMMDevState, pIter);
1699
1700 pIter = pNext;
1701 }
1702 }
1703
1704 /* A reserved field, will allow to extend saved data for VMMDevHGCM. */
1705 rc = SSMR3PutU32(pSSM, 0);
1706 AssertRCReturn(rc, rc);
1707
1708 return rc;
1709}
1710
1711/* @thread EMT */
1712int vmmdevHGCMLoadState(VMMDevState *pVMMDevState, PSSMHANDLE pSSM, uint32_t u32Version)
1713{
1714 int rc = VINF_SUCCESS;
1715
1716 LogFlowFunc(("\n"));
1717
1718 /* Read how many commands were pending. */
1719 uint32_t cCmds = 0;
1720 rc = SSMR3GetU32(pSSM, &cCmds);
1721 AssertRCReturn(rc, rc);
1722
1723 LogFlowFunc(("cCmds = %d\n", cCmds));
1724
1725 if ( SSM_VERSION_MAJOR(u32Version) == 0
1726 && SSM_VERSION_MINOR(u32Version) < 9)
1727 {
1728 /* Only the guest physical address is saved. */
1729 while (cCmds--)
1730 {
1731 RTGCPHYS GCPhys;
1732 uint32_t cbSize;
1733
1734 rc = SSMR3GetGCPhys(pSSM, &GCPhys);
1735 AssertRCReturn(rc, rc);
1736
1737 rc = SSMR3GetU32(pSSM, &cbSize);
1738 AssertRCReturn(rc, rc);
1739
1740 LogFlowFunc (("Restoring %RGp size %x bytes\n", GCPhys, cbSize));
1741
1742 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAllocZ (sizeof (struct VBOXHGCMCMD));
1743 AssertReturn(pCmd, VERR_NO_MEMORY);
1744
1745 vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, cbSize, VBOXHGCMCMDTYPE_LOADSTATE);
1746 }
1747 }
1748 else
1749 {
1750 /*
1751 * Version 9+: Load complete information about commands.
1752 */
1753 uint32_t u32;
1754 bool f;
1755
1756 while (cCmds--)
1757 {
1758 RTGCPHYS GCPhys;
1759 uint32_t cbSize;
1760
1761 /* GC physical address of the guest request. */
1762 rc = SSMR3GetGCPhys(pSSM, &GCPhys);
1763 AssertRCReturn(rc, rc);
1764
1765 /* The request packet size */
1766 rc = SSMR3GetU32(pSSM, &cbSize);
1767 AssertRCReturn(rc, rc);
1768
1769 LogFlowFunc (("Restoring %RGp size %x bytes\n", GCPhys, cbSize));
1770
1771 /* Size of entire command. */
1772 rc = SSMR3GetU32(pSSM, &u32);
1773 AssertRCReturn(rc, rc);
1774
1775 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAllocZ (u32);
1776 AssertReturn(pCmd, VERR_NO_MEMORY);
1777 pCmd->cbCmd = u32;
1778
1779 /* The type of the command. */
1780 rc = SSMR3GetU32(pSSM, &u32);
1781 AssertRCReturn(rc, rc);
1782 pCmd->enmCmdType = (VBOXHGCMCMDTYPE)u32;
1783
1784 /* Whether the command was cancelled by the guest. */
1785 rc = SSMR3GetBool(pSSM, &f);
1786 AssertRCReturn(rc, rc);
1787 pCmd->fCancelled = f;
1788
1789 /* Linear pointer parameters information. How many pointers. Always 0 if not a call command. */
1790 rc = SSMR3GetU32(pSSM, &u32);
1791 AssertRCReturn(rc, rc);
1792 pCmd->cLinPtrs = u32;
1793
1794 if (pCmd->cLinPtrs > 0)
1795 {
1796 /* How many pages for all linptrs in this command. */
1797 rc = SSMR3GetU32(pSSM, &u32);
1798 AssertRCReturn(rc, rc);
1799 pCmd->cLinPtrPages = u32;
1800
1801 pCmd->paLinPtrs = (VBOXHGCMLINPTR *)RTMemAllocZ ( sizeof (VBOXHGCMLINPTR) * pCmd->cLinPtrs
1802 + sizeof (RTGCPHYS) * pCmd->cLinPtrPages);
1803 AssertReturn(pCmd->paLinPtrs, VERR_NO_MEMORY);
1804
1805 RTGCPHYS *pPages = (RTGCPHYS *)((uint8_t *)pCmd->paLinPtrs + sizeof (VBOXHGCMLINPTR) * pCmd->cLinPtrs);
1806 int cPages = 0;
1807
1808 int i;
1809 for (i = 0; i < pCmd->cLinPtrs; i++)
1810 {
1811 /* Pointer to descriptions of linear pointers. */
1812 VBOXHGCMLINPTR *pLinPtr = &pCmd->paLinPtrs[i];
1813
1814 pLinPtr->paPages = pPages;
1815
1816 /* Index of the parameter. */
1817 rc = SSMR3GetU32(pSSM, &u32);
1818 AssertRCReturn(rc, rc);
1819 pLinPtr->iParm = u32;
1820
1821 /* Offset in the first physical page of the region. */
1822 rc = SSMR3GetU32(pSSM, &u32);
1823 AssertRCReturn(rc, rc);
1824 pLinPtr->offFirstPage = u32;
1825
1826 /* How many pages. */
1827 rc = SSMR3GetU32(pSSM, &u32);
1828 AssertRCReturn(rc, rc);
1829 pLinPtr->cPages = u32;
1830
1831 uint32_t iPage;
1832 for (iPage = 0; iPage < pLinPtr->cPages; iPage++)
1833 {
1834 /* Array of the GC physical addresses for these pages.
1835 * It is assumed that the physical address of the locked resident
1836 * guest page does not change.
1837 */
1838 RTGCPHYS GCPhysPage;
1839 rc = SSMR3GetGCPhys(pSSM, &GCPhysPage);
1840 AssertRCReturn(rc, rc);
1841
1842 /* Verify that the number of loaded pages is valid. */
1843 cPages++;
1844 if (cPages > pCmd->cLinPtrPages)
1845 {
1846 LogRel(("VMMDevHGCM load state failure: cPages %d, expected %d, ptr %d/%d\n",
1847 cPages, pCmd->cLinPtrPages, i, pCmd->cLinPtrs));
1848 return VERR_SSM_UNEXPECTED_DATA;
1849 }
1850
1851 *pPages++ = GCPhysPage;
1852 }
1853 }
1854 }
1855
1856 /* A reserved field, will allow to extend saved data for a command. */
1857 rc = SSMR3GetU32(pSSM, &u32);
1858 AssertRCReturn(rc, rc);
1859
1860 vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, cbSize, VBOXHGCMCMDTYPE_LOADSTATE);
1861 }
1862
1863 /* A reserved field, will allow to extend saved data for VMMDevHGCM. */
1864 rc = SSMR3GetU32(pSSM, &u32);
1865 AssertRCReturn(rc, rc);
1866 }
1867
1868 return rc;
1869}
1870
1871/* @thread EMT */
1872int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
1873{
1874 LogFlowFunc(("\n"));
1875
1876 /* Reissue pending requests. */
1877 PPDMDEVINS pDevIns = pVMMDevState->pDevIns;
1878
1879 int rc = vmmdevHGCMCmdListLock (pVMMDevState);
1880
1881 if (RT_SUCCESS (rc))
1882 {
1883 /* Start from the current list head and commands loaded from saved state.
1884 * New commands will be inserted at the list head, so they will not be seen by
1885 * this loop.
1886 */
1887 PVBOXHGCMCMD pIter = pVMMDevState->pHGCMCmdList;
1888
1889 while (pIter)
1890 {
1891 /* This will remove the command from the list if resubmitting fails. */
1892 bool fHGCMCalled = false;
1893
1894 LogFlowFunc (("pIter %p\n", pIter));
1895
1896 PVBOXHGCMCMD pNext = pIter->pNext;
1897
1898 VMMDevHGCMRequestHeader *requestHeader = (VMMDevHGCMRequestHeader *)RTMemAllocZ (pIter->cbSize);
1899 Assert(requestHeader);
1900 if (requestHeader == NULL)
1901 return VERR_NO_MEMORY;
1902
1903 PDMDevHlpPhysRead(pDevIns, pIter->GCPhys, requestHeader, pIter->cbSize);
1904
1905 /* the structure size must be greater or equal to the header size */
1906 if (requestHeader->header.size < sizeof(VMMDevHGCMRequestHeader))
1907 {
1908 Log(("VMMDev request header size too small! size = %d\n", requestHeader->header.size));
1909 }
1910 else
1911 {
1912 /* check the version of the header structure */
1913 if (requestHeader->header.version != VMMDEV_REQUEST_HEADER_VERSION)
1914 {
1915 Log(("VMMDev: guest header version (0x%08X) differs from ours (0x%08X)\n", requestHeader->header.version, VMMDEV_REQUEST_HEADER_VERSION));
1916 }
1917 else
1918 {
1919 Log(("VMMDev request issued: %d, command type %d\n", requestHeader->header.requestType, pIter->enmCmdType));
1920
1921 /* Use the saved command type. Even if the guest has changed the memory already,
1922 * HGCM should see the same command as it was before saving state.
1923 */
1924 switch (pIter->enmCmdType)
1925 {
1926 case VBOXHGCMCMDTYPE_CONNECT:
1927 {
1928 if (requestHeader->header.size < sizeof(VMMDevHGCMConnect))
1929 {
1930 AssertMsgFailed(("VMMDevReq_HGCMConnect structure has invalid size!\n"));
1931 requestHeader->header.rc = VERR_INVALID_PARAMETER;
1932 }
1933 else if (!pVMMDevState->pHGCMDrv)
1934 {
1935 Log(("VMMDevReq_HGCMConnect HGCM Connector is NULL!\n"));
1936 requestHeader->header.rc = VERR_NOT_SUPPORTED;
1937 }
1938 else
1939 {
1940 VMMDevHGCMConnect *pHGCMConnect = (VMMDevHGCMConnect *)requestHeader;
1941
1942 Log(("VMMDevReq_HGCMConnect\n"));
1943
1944 requestHeader->header.rc = vmmdevHGCMConnectSaved (pVMMDevState, pHGCMConnect, &fHGCMCalled, pIter);
1945 }
1946 break;
1947 }
1948
1949 case VBOXHGCMCMDTYPE_DISCONNECT:
1950 {
1951 if (requestHeader->header.size < sizeof(VMMDevHGCMDisconnect))
1952 {
1953 AssertMsgFailed(("VMMDevReq_HGCMDisconnect structure has invalid size!\n"));
1954 requestHeader->header.rc = VERR_INVALID_PARAMETER;
1955 }
1956 else if (!pVMMDevState->pHGCMDrv)
1957 {
1958 Log(("VMMDevReq_HGCMDisconnect HGCM Connector is NULL!\n"));
1959 requestHeader->header.rc = VERR_NOT_SUPPORTED;
1960 }
1961 else
1962 {
1963 VMMDevHGCMDisconnect *pHGCMDisconnect = (VMMDevHGCMDisconnect *)requestHeader;
1964
1965 Log(("VMMDevReq_VMMDevHGCMDisconnect\n"));
1966 requestHeader->header.rc = vmmdevHGCMDisconnectSaved (pVMMDevState, pHGCMDisconnect, &fHGCMCalled, pIter);
1967 }
1968 break;
1969 }
1970
1971 case VBOXHGCMCMDTYPE_CALL:
1972 {
1973 if (requestHeader->header.size < sizeof(VMMDevHGCMCall))
1974 {
1975 AssertMsgFailed(("VMMDevReq_HGCMCall structure has invalid size!\n"));
1976 requestHeader->header.rc = VERR_INVALID_PARAMETER;
1977 }
1978 else if (!pVMMDevState->pHGCMDrv)
1979 {
1980 Log(("VMMDevReq_HGCMCall HGCM Connector is NULL!\n"));
1981 requestHeader->header.rc = VERR_NOT_SUPPORTED;
1982 }
1983 else
1984 {
1985 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)requestHeader;
1986
1987 Log(("VMMDevReq_HGCMCall: sizeof (VMMDevHGCMRequest) = %04X\n", sizeof (VMMDevHGCMCall)));
1988
1989 Log(("%.*Rhxd\n", requestHeader->header.size, requestHeader));
1990
1991#ifdef VBOX_WITH_64_BITS_GUESTS
1992 bool f64Bits = (requestHeader->header.requestType == VMMDevReq_HGCMCall64);
1993#else
1994 bool f64Bits = false;
1995#endif /* VBOX_WITH_64_BITS_GUESTS */
1996 requestHeader->header.rc = vmmdevHGCMCallSaved (pVMMDevState, pHGCMCall, f64Bits, &fHGCMCalled, pIter);
1997 }
1998 break;
1999 }
2000 case VBOXHGCMCMDTYPE_LOADSTATE:
2001 {
2002 /* Old saved state. */
2003 switch (requestHeader->header.requestType)
2004 {
2005 case VMMDevReq_HGCMConnect:
2006 {
2007 if (requestHeader->header.size < sizeof(VMMDevHGCMConnect))
2008 {
2009 AssertMsgFailed(("VMMDevReq_HGCMConnect structure has invalid size!\n"));
2010 requestHeader->header.rc = VERR_INVALID_PARAMETER;
2011 }
2012 else if (!pVMMDevState->pHGCMDrv)
2013 {
2014 Log(("VMMDevReq_HGCMConnect HGCM Connector is NULL!\n"));
2015 requestHeader->header.rc = VERR_NOT_SUPPORTED;
2016 }
2017 else
2018 {
2019 VMMDevHGCMConnect *pHGCMConnect = (VMMDevHGCMConnect *)requestHeader;
2020
2021 Log(("VMMDevReq_HGCMConnect\n"));
2022
2023 requestHeader->header.rc = vmmdevHGCMConnect (pVMMDevState, pHGCMConnect, pIter->GCPhys);
2024 }
2025 break;
2026 }
2027
2028 case VMMDevReq_HGCMDisconnect:
2029 {
2030 if (requestHeader->header.size < sizeof(VMMDevHGCMDisconnect))
2031 {
2032 AssertMsgFailed(("VMMDevReq_HGCMDisconnect structure has invalid size!\n"));
2033 requestHeader->header.rc = VERR_INVALID_PARAMETER;
2034 }
2035 else if (!pVMMDevState->pHGCMDrv)
2036 {
2037 Log(("VMMDevReq_HGCMDisconnect HGCM Connector is NULL!\n"));
2038 requestHeader->header.rc = VERR_NOT_SUPPORTED;
2039 }
2040 else
2041 {
2042 VMMDevHGCMDisconnect *pHGCMDisconnect = (VMMDevHGCMDisconnect *)requestHeader;
2043
2044 Log(("VMMDevReq_VMMDevHGCMDisconnect\n"));
2045 requestHeader->header.rc = vmmdevHGCMDisconnect (pVMMDevState, pHGCMDisconnect, pIter->GCPhys);
2046 }
2047 break;
2048 }
2049
2050#ifdef VBOX_WITH_64_BITS_GUESTS
2051 case VMMDevReq_HGCMCall64:
2052 case VMMDevReq_HGCMCall32:
2053#else
2054 case VMMDevReq_HGCMCall:
2055#endif /* VBOX_WITH_64_BITS_GUESTS */
2056 {
2057 if (requestHeader->header.size < sizeof(VMMDevHGCMCall))
2058 {
2059 AssertMsgFailed(("VMMDevReq_HGCMCall structure has invalid size!\n"));
2060 requestHeader->header.rc = VERR_INVALID_PARAMETER;
2061 }
2062 else if (!pVMMDevState->pHGCMDrv)
2063 {
2064 Log(("VMMDevReq_HGCMCall HGCM Connector is NULL!\n"));
2065 requestHeader->header.rc = VERR_NOT_SUPPORTED;
2066 }
2067 else
2068 {
2069 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)requestHeader;
2070
2071 Log(("VMMDevReq_HGCMCall: sizeof (VMMDevHGCMRequest) = %04X\n", sizeof (VMMDevHGCMCall)));
2072
2073 Log(("%.*Rhxd\n", requestHeader->header.size, requestHeader));
2074
2075#ifdef VBOX_WITH_64_BITS_GUESTS
2076 bool f64Bits = (requestHeader->header.requestType == VMMDevReq_HGCMCall64);
2077#else
2078 bool f64Bits = false;
2079#endif /* VBOX_WITH_64_BITS_GUESTS */
2080 requestHeader->header.rc = vmmdevHGCMCall (pVMMDevState, pHGCMCall, pIter->GCPhys, f64Bits);
2081 }
2082 break;
2083 }
2084 default:
2085 AssertMsgFailed(("Unknown request type %x during LoadState\n", requestHeader->header.requestType));
2086 LogRel(("VMMDEV: Ignoring unknown request type %x during LoadState\n", requestHeader->header.requestType));
2087 }
2088 } break;
2089
2090 default:
2091 AssertMsgFailed(("Unknown request type %x during LoadState\n", requestHeader->header.requestType));
2092 LogRel(("VMMDEV: Ignoring unknown request type %x during LoadState\n", requestHeader->header.requestType));
2093 }
2094 }
2095 }
2096
2097 if (pIter->enmCmdType == VBOXHGCMCMDTYPE_LOADSTATE)
2098 {
2099 /* Old saved state. Remove the LOADSTATE command. */
2100
2101 /* Write back the request */
2102 PDMDevHlpPhysWrite(pDevIns, pIter->GCPhys, requestHeader, pIter->cbSize);
2103 RTMemFree(requestHeader);
2104 requestHeader = NULL;
2105
2106 vmmdevHGCMRemoveCommand (pVMMDevState, pIter);
2107
2108 if (pIter->paLinPtrs != NULL)
2109 {
2110 RTMemFree(pIter->paLinPtrs);
2111 }
2112
2113 RTMemFree(pIter);
2114 }
2115 else
2116 {
2117 if (!fHGCMCalled)
2118 {
2119 /* HGCM was not called. Return the error to the guest. Guest may try to repeat the call. */
2120 requestHeader->header.rc = VERR_TRY_AGAIN;
2121 requestHeader->fu32Flags |= VBOX_HGCM_REQ_DONE;
2122 }
2123
2124 /* Write back the request */
2125 PDMDevHlpPhysWrite(pDevIns, pIter->GCPhys, requestHeader, pIter->cbSize);
2126 RTMemFree(requestHeader);
2127 requestHeader = NULL;
2128
2129 if (!fHGCMCalled)
2130 {
2131 /* HGCM was not called. Deallocate the current command and then notify guest. */
2132 vmmdevHGCMRemoveCommand (pVMMDevState, pIter);
2133
2134 if (pIter->paLinPtrs != NULL)
2135 {
2136 RTMemFree(pIter->paLinPtrs);
2137 }
2138
2139 RTMemFree(pIter);
2140
2141 VMMDevNotifyGuest (pVMMDevState, VMMDEV_EVENT_HGCM);
2142 }
2143 }
2144
2145 pIter = pNext;
2146 }
2147
2148 vmmdevHGCMCmdListUnlock (pVMMDevState);
2149 }
2150
2151 return rc;
2152}
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