VirtualBox

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

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

Devices: Finally adding the first dtrace probes. :-)

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