VirtualBox

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

Last change on this file since 21506 was 21506, checked in by vboxsync, 16 years ago

VBoxGuest,VMMDev: New HGCM cancellation request.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette