VirtualBox

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

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

VMMDev: Ensure read/write order in hgcmCompletedWorker. (bug 4052)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 78.5 KB
Line 
1/* $Id: VMMDevHGCM.cpp 21062 2009-06-30 10:14:10Z 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 /*
1327 * Enter and leave the critical section here so we make sure
1328 * vmmdevRequestHandler has completed before we read & write
1329 * the request. (This isn't 100% optimal, but it solves the
1330 * 3.0 blocker.)
1331 */
1332 /** @todo s/pVMMDevState/pThis/g */
1333 /** @todo It would be faster if this interface would use MMIO2 memory and we
1334 * didn't have to mess around with PDMDevHlpPhysRead/Write. We're
1335 * reading the header 3 times now and writing the request back twice. */
1336 PDMCritSectEnter(&pVMMDevState->CritSect, VERR_SEM_BUSY);
1337 PDMCritSectLeave(&pVMMDevState->CritSect);
1338
1339 PDMDevHlpPhysRead(pVMMDevState->pDevIns, pCmd->GCPhys, pHeader, pCmd->cbSize);
1340
1341 /* Setup return codes. */
1342 pHeader->result = result;
1343
1344 /* Verify the request type. */
1345 rc = vmmdevHGCMCmdVerify (pCmd, pHeader);
1346
1347 if (RT_SUCCESS (rc))
1348 {
1349 /* Update parameters and data buffers. */
1350
1351 switch (pHeader->header.requestType)
1352 {
1353#ifdef VBOX_WITH_64_BITS_GUESTS
1354 case VMMDevReq_HGCMCall64:
1355 {
1356 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pHeader;
1357
1358 uint32_t cParms = pHGCMCall->cParms;
1359
1360 VBOXHGCMSVCPARM *pHostParm = pCmd->paHostParms;
1361
1362 uint32_t i;
1363 uint32_t iLinPtr = 0;
1364
1365 HGCMFunctionParameter64 *pGuestParm = VMMDEV_HGCM_CALL_PARMS64(pHGCMCall);
1366
1367 for (i = 0; i < cParms; i++, pGuestParm++, pHostParm++)
1368 {
1369 switch (pGuestParm->type)
1370 {
1371 case VMMDevHGCMParmType_32bit:
1372 {
1373 pGuestParm->u.value32 = pHostParm->u.uint32;
1374 } break;
1375
1376 case VMMDevHGCMParmType_64bit:
1377 {
1378 pGuestParm->u.value64 = pHostParm->u.uint64;
1379 } break;
1380
1381 case VMMDevHGCMParmType_PhysAddr:
1382 {
1383 /* do nothing */
1384 } break;
1385
1386 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
1387 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
1388 case VMMDevHGCMParmType_LinAddr: /* In & Out */
1389 {
1390 /* Copy buffer back to guest memory. */
1391 uint32_t size = pGuestParm->u.Pointer.size;
1392
1393 if (size > 0)
1394 {
1395 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
1396 {
1397 /* Use the saved page list to write data back to the guest RAM. */
1398 rc = vmmdevHGCMWriteLinPtr (pVMMDevState->pDevIns, i, pHostParm->u.pointer.addr, size, iLinPtr, pCmd->paLinPtrs);
1399 AssertReleaseRC(rc);
1400 }
1401
1402 /* All linptrs with size > 0 were saved. Advance the index to the next linptr. */
1403 iLinPtr++;
1404 }
1405 } break;
1406
1407 default:
1408 {
1409 /* This indicates that the guest request memory was corrupted. */
1410 AssertReleaseMsgFailed(("hgcmCompleted: invalid parameter type %08X\n", pGuestParm->type));
1411 }
1412 }
1413 }
1414 break;
1415 }
1416
1417 case VMMDevReq_HGCMCall32:
1418 {
1419 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pHeader;
1420
1421 uint32_t cParms = pHGCMCall->cParms;
1422
1423 VBOXHGCMSVCPARM *pHostParm = pCmd->paHostParms;
1424
1425 uint32_t i;
1426 uint32_t iLinPtr = 0;
1427
1428 HGCMFunctionParameter32 *pGuestParm = VMMDEV_HGCM_CALL_PARMS32(pHGCMCall);
1429
1430 for (i = 0; i < cParms; i++, pGuestParm++, pHostParm++)
1431 {
1432 switch (pGuestParm->type)
1433 {
1434 case VMMDevHGCMParmType_32bit:
1435 {
1436 pGuestParm->u.value32 = pHostParm->u.uint32;
1437 } break;
1438
1439 case VMMDevHGCMParmType_64bit:
1440 {
1441 pGuestParm->u.value64 = pHostParm->u.uint64;
1442 } break;
1443
1444 case VMMDevHGCMParmType_PhysAddr:
1445 {
1446 /* do nothing */
1447 } break;
1448
1449 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
1450 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
1451 case VMMDevHGCMParmType_LinAddr: /* In & Out */
1452 {
1453 /* Copy buffer back to guest memory. */
1454 uint32_t size = pGuestParm->u.Pointer.size;
1455
1456 if (size > 0)
1457 {
1458 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
1459 {
1460 /* Use the saved page list to write data back to the guest RAM. */
1461 rc = vmmdevHGCMWriteLinPtr (pVMMDevState->pDevIns, i, pHostParm->u.pointer.addr, size, iLinPtr, pCmd->paLinPtrs);
1462 AssertReleaseRC(rc);
1463 }
1464
1465 /* All linptrs with size > 0 were saved. Advance the index to the next linptr. */
1466 iLinPtr++;
1467 }
1468 } break;
1469
1470 default:
1471 {
1472 /* This indicates that the guest request memory was corrupted. */
1473 AssertReleaseMsgFailed(("hgcmCompleted: invalid parameter type %08X\n", pGuestParm->type));
1474 }
1475 }
1476 }
1477 break;
1478 }
1479#else
1480 case VMMDevReq_HGCMCall:
1481 {
1482 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pHeader;
1483
1484 uint32_t cParms = pHGCMCall->cParms;
1485
1486 VBOXHGCMSVCPARM *pHostParm = pCmd->paHostParms;
1487
1488 uint32_t i;
1489 uint32_t iLinPtr = 0;
1490
1491 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
1492
1493 for (i = 0; i < cParms; i++, pGuestParm++, pHostParm++)
1494 {
1495 switch (pGuestParm->type)
1496 {
1497 case VMMDevHGCMParmType_32bit:
1498 {
1499 pGuestParm->u.value32 = pHostParm->u.uint32;
1500 } break;
1501
1502 case VMMDevHGCMParmType_64bit:
1503 {
1504 pGuestParm->u.value64 = pHostParm->u.uint64;
1505 } break;
1506
1507 case VMMDevHGCMParmType_PhysAddr:
1508 {
1509 /* do nothing */
1510 } break;
1511
1512 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
1513 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
1514 case VMMDevHGCMParmType_LinAddr: /* In & Out */
1515 {
1516 /* Copy buffer back to guest memory. */
1517 uint32_t size = pGuestParm->u.Pointer.size;
1518
1519 if (size > 0)
1520 {
1521 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
1522 {
1523 /* Use the saved page list to write data back to the guest RAM. */
1524 rc = vmmdevHGCMWriteLinPtr (pVMMDevState->pDevIns, i, pHostParm->u.pointer.addr, size, iLinPtr, pCmd->paLinPtrs);
1525 AssertReleaseRC(rc);
1526 }
1527
1528 /* All linptrs with size > 0 were saved. Advance the index to the next linptr. */
1529 iLinPtr++;
1530 }
1531 } break;
1532
1533 default:
1534 {
1535 /* This indicates that the guest request memory was corrupted. */
1536 AssertReleaseMsgFailed(("hgcmCompleted: invalid parameter type %08X\n", pGuestParm->type));
1537 }
1538 }
1539 }
1540 break;
1541 }
1542#endif /* VBOX_WITH_64_BITS_GUESTS */
1543 case VMMDevReq_HGCMConnect:
1544 {
1545 VMMDevHGCMConnect *pHGCMConnectCopy = (VMMDevHGCMConnect *)(pCmd+1);
1546
1547 /* save the client id in the guest request packet */
1548 VMMDevHGCMConnect *pHGCMConnect = (VMMDevHGCMConnect *)pHeader;
1549 pHGCMConnect->u32ClientID = pHGCMConnectCopy->u32ClientID;
1550 break;
1551 }
1552
1553 default:
1554 /* make gcc happy */
1555 break;
1556 }
1557 }
1558 else
1559 {
1560 /* Command type is wrong. Return error to the guest. */
1561 pHeader->header.rc = rc;
1562 }
1563
1564 /* Mark request as processed. */
1565 pHeader->fu32Flags |= VBOX_HGCM_REQ_DONE;
1566
1567 /* Write back the request */
1568 PDMDevHlpPhysWrite(pVMMDevState->pDevIns, pCmd->GCPhys, pHeader, pCmd->cbSize);
1569
1570 /* The command has been completely processed and can be removed from the list. */
1571 vmmdevHGCMRemoveCommand (pVMMDevState, pCmd);
1572
1573 /* Now, when the command was removed from the internal list, notify the guest. */
1574 VMMDevNotifyGuest (pVMMDevState, VMMDEV_EVENT_HGCM);
1575
1576 if ((uint8_t *)pHeader != &au8Prealloc[0])
1577 {
1578 /* Only if it was allocated from heap. */
1579 RTMemFree (pHeader);
1580 }
1581 }
1582
1583 /* Deallocate the command memory. */
1584 if (pCmd->paLinPtrs)
1585 {
1586 RTMemFree (pCmd->paLinPtrs);
1587 }
1588
1589 RTMemFree (pCmd);
1590
1591 return;
1592}
1593
1594DECLCALLBACK(void) hgcmCompleted (PPDMIHGCMPORT pInterface, int32_t result, PVBOXHGCMCMD pCmd)
1595{
1596 VMMDevState *pVMMDevState = PDMIHGCMPORT_2_VMMDEVSTATE(pInterface);
1597
1598/** @todo no longer necessary to forward to EMT, but it might be more
1599 * efficient...? */
1600 /* Not safe to execute asynchroneously; forward to EMT */
1601 int rc = VMR3ReqCallEx(PDMDevHlpGetVM(pVMMDevState->pDevIns), VMCPUID_ANY, NULL, 0, VMREQFLAGS_NO_WAIT | VMREQFLAGS_VOID,
1602 (PFNRT)hgcmCompletedWorker, 3, pInterface, result, pCmd);
1603 AssertRC(rc);
1604}
1605
1606/* @thread EMT */
1607int vmmdevHGCMSaveState(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
1608{
1609 /* Save information about pending requests.
1610 * Only GCPtrs are of interest.
1611 */
1612 int rc = VINF_SUCCESS;
1613
1614 LogFlowFunc(("\n"));
1615
1616 /* Compute how many commands are pending. */
1617 uint32_t cCmds = 0;
1618
1619 PVBOXHGCMCMD pIter = pVMMDevState->pHGCMCmdList;
1620
1621 while (pIter)
1622 {
1623 LogFlowFunc (("pIter %p\n", pIter));
1624 cCmds++;
1625 pIter = pIter->pNext;
1626 }
1627
1628 LogFlowFunc(("cCmds = %d\n", cCmds));
1629
1630 /* Save number of commands. */
1631 rc = SSMR3PutU32(pSSM, cCmds);
1632 AssertRCReturn(rc, rc);
1633
1634 if (cCmds > 0)
1635 {
1636 pIter = pVMMDevState->pHGCMCmdList;
1637
1638 while (pIter)
1639 {
1640 PVBOXHGCMCMD pNext = pIter->pNext;
1641
1642 LogFlowFunc (("Saving %RGp, size %d\n", pIter->GCPhys, pIter->cbSize));
1643
1644 /* GC physical address of the guest request. */
1645 rc = SSMR3PutGCPhys(pSSM, pIter->GCPhys);
1646 AssertRCReturn(rc, rc);
1647
1648 /* Request packet size */
1649 rc = SSMR3PutU32(pSSM, pIter->cbSize);
1650 AssertRCReturn(rc, rc);
1651
1652 /*
1653 * Version 9+: save complete information about commands.
1654 */
1655
1656 /* Size of entire command. */
1657 rc = SSMR3PutU32(pSSM, pIter->cbCmd);
1658 AssertRCReturn(rc, rc);
1659
1660 /* The type of the command. */
1661 rc = SSMR3PutU32(pSSM, (uint32_t)pIter->enmCmdType);
1662 AssertRCReturn(rc, rc);
1663
1664 /* Whether the command was cancelled by the guest. */
1665 rc = SSMR3PutBool(pSSM, pIter->fCancelled);
1666 AssertRCReturn(rc, rc);
1667
1668 /* Linear pointer parameters information. How many pointers. Always 0 if not a call command. */
1669 rc = SSMR3PutU32(pSSM, (uint32_t)pIter->cLinPtrs);
1670 AssertRCReturn(rc, rc);
1671
1672 if (pIter->cLinPtrs > 0)
1673 {
1674 /* How many pages for all linptrs in this command. */
1675 rc = SSMR3PutU32(pSSM, (uint32_t)pIter->cLinPtrPages);
1676 AssertRCReturn(rc, rc);
1677 }
1678
1679 int i;
1680 for (i = 0; i < pIter->cLinPtrs; i++)
1681 {
1682 /* Pointer to descriptions of linear pointers. */
1683 VBOXHGCMLINPTR *pLinPtr = &pIter->paLinPtrs[i];
1684
1685 /* Index of the parameter. */
1686 rc = SSMR3PutU32(pSSM, (uint32_t)pLinPtr->iParm);
1687 AssertRCReturn(rc, rc);
1688
1689 /* Offset in the first physical page of the region. */
1690 rc = SSMR3PutU32(pSSM, pLinPtr->offFirstPage);
1691 AssertRCReturn(rc, rc);
1692
1693 /* How many pages. */
1694 rc = SSMR3PutU32(pSSM, pLinPtr->cPages);
1695 AssertRCReturn(rc, rc);
1696
1697 uint32_t iPage;
1698 for (iPage = 0; iPage < pLinPtr->cPages; iPage++)
1699 {
1700 /* Array of the GC physical addresses for these pages.
1701 * It is assumed that the physical address of the locked resident
1702 * guest page does not change.
1703 */
1704 rc = SSMR3PutGCPhys(pSSM, pLinPtr->paPages[iPage]);
1705 AssertRCReturn(rc, rc);
1706 }
1707 }
1708
1709 /* A reserved field, will allow to extend saved data for a command. */
1710 rc = SSMR3PutU32(pSSM, 0);
1711 AssertRCReturn(rc, rc);
1712
1713 vmmdevHGCMRemoveCommand (pVMMDevState, pIter);
1714
1715 pIter = pNext;
1716 }
1717 }
1718
1719 /* A reserved field, will allow to extend saved data for VMMDevHGCM. */
1720 rc = SSMR3PutU32(pSSM, 0);
1721 AssertRCReturn(rc, rc);
1722
1723 return rc;
1724}
1725
1726/* @thread EMT */
1727int vmmdevHGCMLoadState(VMMDevState *pVMMDevState, PSSMHANDLE pSSM, uint32_t u32Version)
1728{
1729 int rc = VINF_SUCCESS;
1730
1731 LogFlowFunc(("\n"));
1732
1733 /* Read how many commands were pending. */
1734 uint32_t cCmds = 0;
1735 rc = SSMR3GetU32(pSSM, &cCmds);
1736 AssertRCReturn(rc, rc);
1737
1738 LogFlowFunc(("cCmds = %d\n", cCmds));
1739
1740 if ( SSM_VERSION_MAJOR(u32Version) == 0
1741 && SSM_VERSION_MINOR(u32Version) < 9)
1742 {
1743 /* Only the guest physical address is saved. */
1744 while (cCmds--)
1745 {
1746 RTGCPHYS GCPhys;
1747 uint32_t cbSize;
1748
1749 rc = SSMR3GetGCPhys(pSSM, &GCPhys);
1750 AssertRCReturn(rc, rc);
1751
1752 rc = SSMR3GetU32(pSSM, &cbSize);
1753 AssertRCReturn(rc, rc);
1754
1755 LogFlowFunc (("Restoring %RGp size %x bytes\n", GCPhys, cbSize));
1756
1757 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAllocZ (sizeof (struct VBOXHGCMCMD));
1758 AssertReturn(pCmd, VERR_NO_MEMORY);
1759
1760 vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, cbSize, VBOXHGCMCMDTYPE_LOADSTATE);
1761 }
1762 }
1763 else
1764 {
1765 /*
1766 * Version 9+: Load complete information about commands.
1767 */
1768 uint32_t u32;
1769 bool f;
1770
1771 while (cCmds--)
1772 {
1773 RTGCPHYS GCPhys;
1774 uint32_t cbSize;
1775
1776 /* GC physical address of the guest request. */
1777 rc = SSMR3GetGCPhys(pSSM, &GCPhys);
1778 AssertRCReturn(rc, rc);
1779
1780 /* The request packet size */
1781 rc = SSMR3GetU32(pSSM, &cbSize);
1782 AssertRCReturn(rc, rc);
1783
1784 LogFlowFunc (("Restoring %RGp size %x bytes\n", GCPhys, cbSize));
1785
1786 /* Size of entire command. */
1787 rc = SSMR3GetU32(pSSM, &u32);
1788 AssertRCReturn(rc, rc);
1789
1790 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAllocZ (u32);
1791 AssertReturn(pCmd, VERR_NO_MEMORY);
1792 pCmd->cbCmd = u32;
1793
1794 /* The type of the command. */
1795 rc = SSMR3GetU32(pSSM, &u32);
1796 AssertRCReturn(rc, rc);
1797 pCmd->enmCmdType = (VBOXHGCMCMDTYPE)u32;
1798
1799 /* Whether the command was cancelled by the guest. */
1800 rc = SSMR3GetBool(pSSM, &f);
1801 AssertRCReturn(rc, rc);
1802 pCmd->fCancelled = f;
1803
1804 /* Linear pointer parameters information. How many pointers. Always 0 if not a call command. */
1805 rc = SSMR3GetU32(pSSM, &u32);
1806 AssertRCReturn(rc, rc);
1807 pCmd->cLinPtrs = u32;
1808
1809 if (pCmd->cLinPtrs > 0)
1810 {
1811 /* How many pages for all linptrs in this command. */
1812 rc = SSMR3GetU32(pSSM, &u32);
1813 AssertRCReturn(rc, rc);
1814 pCmd->cLinPtrPages = u32;
1815
1816 pCmd->paLinPtrs = (VBOXHGCMLINPTR *)RTMemAllocZ ( sizeof (VBOXHGCMLINPTR) * pCmd->cLinPtrs
1817 + sizeof (RTGCPHYS) * pCmd->cLinPtrPages);
1818 AssertReturn(pCmd->paLinPtrs, VERR_NO_MEMORY);
1819
1820 RTGCPHYS *pPages = (RTGCPHYS *)((uint8_t *)pCmd->paLinPtrs + sizeof (VBOXHGCMLINPTR) * pCmd->cLinPtrs);
1821 int cPages = 0;
1822
1823 int i;
1824 for (i = 0; i < pCmd->cLinPtrs; i++)
1825 {
1826 /* Pointer to descriptions of linear pointers. */
1827 VBOXHGCMLINPTR *pLinPtr = &pCmd->paLinPtrs[i];
1828
1829 pLinPtr->paPages = pPages;
1830
1831 /* Index of the parameter. */
1832 rc = SSMR3GetU32(pSSM, &u32);
1833 AssertRCReturn(rc, rc);
1834 pLinPtr->iParm = u32;
1835
1836 /* Offset in the first physical page of the region. */
1837 rc = SSMR3GetU32(pSSM, &u32);
1838 AssertRCReturn(rc, rc);
1839 pLinPtr->offFirstPage = u32;
1840
1841 /* How many pages. */
1842 rc = SSMR3GetU32(pSSM, &u32);
1843 AssertRCReturn(rc, rc);
1844 pLinPtr->cPages = u32;
1845
1846 uint32_t iPage;
1847 for (iPage = 0; iPage < pLinPtr->cPages; iPage++)
1848 {
1849 /* Array of the GC physical addresses for these pages.
1850 * It is assumed that the physical address of the locked resident
1851 * guest page does not change.
1852 */
1853 RTGCPHYS GCPhysPage;
1854 rc = SSMR3GetGCPhys(pSSM, &GCPhysPage);
1855 AssertRCReturn(rc, rc);
1856
1857 /* Verify that the number of loaded pages is valid. */
1858 cPages++;
1859 if (cPages > pCmd->cLinPtrPages)
1860 {
1861 LogRel(("VMMDevHGCM load state failure: cPages %d, expected %d, ptr %d/%d\n",
1862 cPages, pCmd->cLinPtrPages, i, pCmd->cLinPtrs));
1863 return VERR_SSM_UNEXPECTED_DATA;
1864 }
1865
1866 *pPages++ = GCPhysPage;
1867 }
1868 }
1869 }
1870
1871 /* A reserved field, will allow to extend saved data for a command. */
1872 rc = SSMR3GetU32(pSSM, &u32);
1873 AssertRCReturn(rc, rc);
1874
1875 vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, cbSize, VBOXHGCMCMDTYPE_LOADSTATE);
1876 }
1877
1878 /* A reserved field, will allow to extend saved data for VMMDevHGCM. */
1879 rc = SSMR3GetU32(pSSM, &u32);
1880 AssertRCReturn(rc, rc);
1881 }
1882
1883 return rc;
1884}
1885
1886/* @thread EMT */
1887int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
1888{
1889 LogFlowFunc(("\n"));
1890
1891 /* Reissue pending requests. */
1892 PPDMDEVINS pDevIns = pVMMDevState->pDevIns;
1893
1894 int rc = vmmdevHGCMCmdListLock (pVMMDevState);
1895
1896 if (RT_SUCCESS (rc))
1897 {
1898 /* Start from the current list head and commands loaded from saved state.
1899 * New commands will be inserted at the list head, so they will not be seen by
1900 * this loop.
1901 */
1902 PVBOXHGCMCMD pIter = pVMMDevState->pHGCMCmdList;
1903
1904 while (pIter)
1905 {
1906 /* This will remove the command from the list if resubmitting fails. */
1907 bool fHGCMCalled = false;
1908
1909 LogFlowFunc (("pIter %p\n", pIter));
1910
1911 PVBOXHGCMCMD pNext = pIter->pNext;
1912
1913 VMMDevHGCMRequestHeader *requestHeader = (VMMDevHGCMRequestHeader *)RTMemAllocZ (pIter->cbSize);
1914 Assert(requestHeader);
1915 if (requestHeader == NULL)
1916 return VERR_NO_MEMORY;
1917
1918 PDMDevHlpPhysRead(pDevIns, pIter->GCPhys, requestHeader, pIter->cbSize);
1919
1920 /* the structure size must be greater or equal to the header size */
1921 if (requestHeader->header.size < sizeof(VMMDevHGCMRequestHeader))
1922 {
1923 Log(("VMMDev request header size too small! size = %d\n", requestHeader->header.size));
1924 }
1925 else
1926 {
1927 /* check the version of the header structure */
1928 if (requestHeader->header.version != VMMDEV_REQUEST_HEADER_VERSION)
1929 {
1930 Log(("VMMDev: guest header version (0x%08X) differs from ours (0x%08X)\n", requestHeader->header.version, VMMDEV_REQUEST_HEADER_VERSION));
1931 }
1932 else
1933 {
1934 Log(("VMMDev request issued: %d, command type %d\n", requestHeader->header.requestType, pIter->enmCmdType));
1935
1936 /* Use the saved command type. Even if the guest has changed the memory already,
1937 * HGCM should see the same command as it was before saving state.
1938 */
1939 switch (pIter->enmCmdType)
1940 {
1941 case VBOXHGCMCMDTYPE_CONNECT:
1942 {
1943 if (requestHeader->header.size < sizeof(VMMDevHGCMConnect))
1944 {
1945 AssertMsgFailed(("VMMDevReq_HGCMConnect structure has invalid size!\n"));
1946 requestHeader->header.rc = VERR_INVALID_PARAMETER;
1947 }
1948 else if (!pVMMDevState->pHGCMDrv)
1949 {
1950 Log(("VMMDevReq_HGCMConnect HGCM Connector is NULL!\n"));
1951 requestHeader->header.rc = VERR_NOT_SUPPORTED;
1952 }
1953 else
1954 {
1955 VMMDevHGCMConnect *pHGCMConnect = (VMMDevHGCMConnect *)requestHeader;
1956
1957 Log(("VMMDevReq_HGCMConnect\n"));
1958
1959 requestHeader->header.rc = vmmdevHGCMConnectSaved (pVMMDevState, pHGCMConnect, &fHGCMCalled, pIter);
1960 }
1961 break;
1962 }
1963
1964 case VBOXHGCMCMDTYPE_DISCONNECT:
1965 {
1966 if (requestHeader->header.size < sizeof(VMMDevHGCMDisconnect))
1967 {
1968 AssertMsgFailed(("VMMDevReq_HGCMDisconnect structure has invalid size!\n"));
1969 requestHeader->header.rc = VERR_INVALID_PARAMETER;
1970 }
1971 else if (!pVMMDevState->pHGCMDrv)
1972 {
1973 Log(("VMMDevReq_HGCMDisconnect HGCM Connector is NULL!\n"));
1974 requestHeader->header.rc = VERR_NOT_SUPPORTED;
1975 }
1976 else
1977 {
1978 VMMDevHGCMDisconnect *pHGCMDisconnect = (VMMDevHGCMDisconnect *)requestHeader;
1979
1980 Log(("VMMDevReq_VMMDevHGCMDisconnect\n"));
1981 requestHeader->header.rc = vmmdevHGCMDisconnectSaved (pVMMDevState, pHGCMDisconnect, &fHGCMCalled, pIter);
1982 }
1983 break;
1984 }
1985
1986 case VBOXHGCMCMDTYPE_CALL:
1987 {
1988 if (requestHeader->header.size < sizeof(VMMDevHGCMCall))
1989 {
1990 AssertMsgFailed(("VMMDevReq_HGCMCall structure has invalid size!\n"));
1991 requestHeader->header.rc = VERR_INVALID_PARAMETER;
1992 }
1993 else if (!pVMMDevState->pHGCMDrv)
1994 {
1995 Log(("VMMDevReq_HGCMCall HGCM Connector is NULL!\n"));
1996 requestHeader->header.rc = VERR_NOT_SUPPORTED;
1997 }
1998 else
1999 {
2000 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)requestHeader;
2001
2002 Log(("VMMDevReq_HGCMCall: sizeof (VMMDevHGCMRequest) = %04X\n", sizeof (VMMDevHGCMCall)));
2003
2004 Log(("%.*Rhxd\n", requestHeader->header.size, requestHeader));
2005
2006#ifdef VBOX_WITH_64_BITS_GUESTS
2007 bool f64Bits = (requestHeader->header.requestType == VMMDevReq_HGCMCall64);
2008#else
2009 bool f64Bits = false;
2010#endif /* VBOX_WITH_64_BITS_GUESTS */
2011 requestHeader->header.rc = vmmdevHGCMCallSaved (pVMMDevState, pHGCMCall, f64Bits, &fHGCMCalled, pIter);
2012 }
2013 break;
2014 }
2015 case VBOXHGCMCMDTYPE_LOADSTATE:
2016 {
2017 /* Old saved state. */
2018 switch (requestHeader->header.requestType)
2019 {
2020 case VMMDevReq_HGCMConnect:
2021 {
2022 if (requestHeader->header.size < sizeof(VMMDevHGCMConnect))
2023 {
2024 AssertMsgFailed(("VMMDevReq_HGCMConnect structure has invalid size!\n"));
2025 requestHeader->header.rc = VERR_INVALID_PARAMETER;
2026 }
2027 else if (!pVMMDevState->pHGCMDrv)
2028 {
2029 Log(("VMMDevReq_HGCMConnect HGCM Connector is NULL!\n"));
2030 requestHeader->header.rc = VERR_NOT_SUPPORTED;
2031 }
2032 else
2033 {
2034 VMMDevHGCMConnect *pHGCMConnect = (VMMDevHGCMConnect *)requestHeader;
2035
2036 Log(("VMMDevReq_HGCMConnect\n"));
2037
2038 requestHeader->header.rc = vmmdevHGCMConnect (pVMMDevState, pHGCMConnect, pIter->GCPhys);
2039 }
2040 break;
2041 }
2042
2043 case VMMDevReq_HGCMDisconnect:
2044 {
2045 if (requestHeader->header.size < sizeof(VMMDevHGCMDisconnect))
2046 {
2047 AssertMsgFailed(("VMMDevReq_HGCMDisconnect structure has invalid size!\n"));
2048 requestHeader->header.rc = VERR_INVALID_PARAMETER;
2049 }
2050 else if (!pVMMDevState->pHGCMDrv)
2051 {
2052 Log(("VMMDevReq_HGCMDisconnect HGCM Connector is NULL!\n"));
2053 requestHeader->header.rc = VERR_NOT_SUPPORTED;
2054 }
2055 else
2056 {
2057 VMMDevHGCMDisconnect *pHGCMDisconnect = (VMMDevHGCMDisconnect *)requestHeader;
2058
2059 Log(("VMMDevReq_VMMDevHGCMDisconnect\n"));
2060 requestHeader->header.rc = vmmdevHGCMDisconnect (pVMMDevState, pHGCMDisconnect, pIter->GCPhys);
2061 }
2062 break;
2063 }
2064
2065#ifdef VBOX_WITH_64_BITS_GUESTS
2066 case VMMDevReq_HGCMCall64:
2067 case VMMDevReq_HGCMCall32:
2068#else
2069 case VMMDevReq_HGCMCall:
2070#endif /* VBOX_WITH_64_BITS_GUESTS */
2071 {
2072 if (requestHeader->header.size < sizeof(VMMDevHGCMCall))
2073 {
2074 AssertMsgFailed(("VMMDevReq_HGCMCall structure has invalid size!\n"));
2075 requestHeader->header.rc = VERR_INVALID_PARAMETER;
2076 }
2077 else if (!pVMMDevState->pHGCMDrv)
2078 {
2079 Log(("VMMDevReq_HGCMCall HGCM Connector is NULL!\n"));
2080 requestHeader->header.rc = VERR_NOT_SUPPORTED;
2081 }
2082 else
2083 {
2084 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)requestHeader;
2085
2086 Log(("VMMDevReq_HGCMCall: sizeof (VMMDevHGCMRequest) = %04X\n", sizeof (VMMDevHGCMCall)));
2087
2088 Log(("%.*Rhxd\n", requestHeader->header.size, requestHeader));
2089
2090#ifdef VBOX_WITH_64_BITS_GUESTS
2091 bool f64Bits = (requestHeader->header.requestType == VMMDevReq_HGCMCall64);
2092#else
2093 bool f64Bits = false;
2094#endif /* VBOX_WITH_64_BITS_GUESTS */
2095 requestHeader->header.rc = vmmdevHGCMCall (pVMMDevState, pHGCMCall, pIter->GCPhys, f64Bits);
2096 }
2097 break;
2098 }
2099 default:
2100 AssertMsgFailed(("Unknown request type %x during LoadState\n", requestHeader->header.requestType));
2101 LogRel(("VMMDEV: Ignoring unknown request type %x during LoadState\n", requestHeader->header.requestType));
2102 }
2103 } break;
2104
2105 default:
2106 AssertMsgFailed(("Unknown request type %x during LoadState\n", requestHeader->header.requestType));
2107 LogRel(("VMMDEV: Ignoring unknown request type %x during LoadState\n", requestHeader->header.requestType));
2108 }
2109 }
2110 }
2111
2112 if (pIter->enmCmdType == VBOXHGCMCMDTYPE_LOADSTATE)
2113 {
2114 /* Old saved state. Remove the LOADSTATE command. */
2115
2116 /* Write back the request */
2117 PDMDevHlpPhysWrite(pDevIns, pIter->GCPhys, requestHeader, pIter->cbSize);
2118 RTMemFree(requestHeader);
2119 requestHeader = NULL;
2120
2121 vmmdevHGCMRemoveCommand (pVMMDevState, pIter);
2122
2123 if (pIter->paLinPtrs != NULL)
2124 {
2125 RTMemFree(pIter->paLinPtrs);
2126 }
2127
2128 RTMemFree(pIter);
2129 }
2130 else
2131 {
2132 if (!fHGCMCalled)
2133 {
2134 /* HGCM was not called. Return the error to the guest. Guest may try to repeat the call. */
2135 requestHeader->header.rc = VERR_TRY_AGAIN;
2136 requestHeader->fu32Flags |= VBOX_HGCM_REQ_DONE;
2137 }
2138
2139 /* Write back the request */
2140 PDMDevHlpPhysWrite(pDevIns, pIter->GCPhys, requestHeader, pIter->cbSize);
2141 RTMemFree(requestHeader);
2142 requestHeader = NULL;
2143
2144 if (!fHGCMCalled)
2145 {
2146 /* HGCM was not called. Deallocate the current command and then notify guest. */
2147 vmmdevHGCMRemoveCommand (pVMMDevState, pIter);
2148
2149 if (pIter->paLinPtrs != NULL)
2150 {
2151 RTMemFree(pIter->paLinPtrs);
2152 }
2153
2154 RTMemFree(pIter);
2155
2156 VMMDevNotifyGuest (pVMMDevState, VMMDEV_EVENT_HGCM);
2157 }
2158 }
2159
2160 pIter = pNext;
2161 }
2162
2163 vmmdevHGCMCmdListUnlock (pVMMDevState);
2164 }
2165
2166 return rc;
2167}
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