VirtualBox

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

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

VMMDevHGCM.cpp: Hacking, seems combining PDMDEvHlpPhysRead doesn't make much of a difference.

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