VirtualBox

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

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

VMMDevHGCM.cpp: VBOXHGCMCMD::cbCmd isn't very helpful now that the rules of the saved state game has changed. When loading / teleporting the state on a machine where VBOXHGCMCMD or/and VBOXHGCMSVCPARM is larger (either due to it being 64-bit or because of different alignment rules (GCPhys & MSC)), we would allocate too little memory for it and end up corrupting the heap.

As a very temporary measure, I have quadrupled cbSize before passing it to RTMemAllocZ and when used in comparisons. (The value in VBOXHGCMCMD::cbCmd should not be changed in case it is saved again.)

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

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