VirtualBox

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

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

Hex format types (Vhx[sd] -> Rhx[sd]).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 45.9 KB
Line 
1/* $Id: VMMDevHGCM.cpp 13840 2008-11-05 03:31:46Z vboxsync $ */
2/** @file
3 * VMMDev - HGCM - Host-Guest Communication Manager Device.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23#define LOG_GROUP LOG_GROUP_DEV_VMM
24#include <iprt/alloc.h>
25#include <iprt/asm.h>
26#include <iprt/assert.h>
27#include <iprt/param.h>
28#include <iprt/string.h>
29
30#include <VBox/err.h>
31#include <VBox/hgcmsvc.h>
32
33#include <VBox/log.h>
34
35#include "VMMDevHGCM.h"
36
37typedef enum _VBOXHGCMCMDTYPE
38{
39 VBOXHGCMCMDTYPE_LOADSTATE,
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 int iParm;
51
52 /* Offset in the first physical page of the region. */
53 size_t cbOffsetFirstPage;
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 /* The type of the command. */
73 VBOXHGCMCMDTYPE enmCmdType;
74
75 /* Whether the command was cancelled by the guest. */
76 bool fCancelled;
77
78 /* GC physical address of the guest request. */
79 RTGCPHYS GCPhys;
80
81 /* Request packet size */
82 uint32_t cbSize;
83
84 /* Pointer to converted host parameters in case of a Call request. */
85 VBOXHGCMSVCPARM *paHostParms;
86
87 /* Linear pointer parameters information. */
88 int cLinPtrs;
89
90 /* Pointer to descriptions of linear pointers. */
91 VBOXHGCMLINPTR *paLinPtrs;
92};
93
94static int vmmdevHGCMCmdListLock (VMMDevState *pVMMDevState)
95{
96 int rc = RTCritSectEnter (&pVMMDevState->critsectHGCMCmdList);
97 AssertRC (rc);
98 return rc;
99}
100
101static void vmmdevHGCMCmdListUnlock (VMMDevState *pVMMDevState)
102{
103 int rc = RTCritSectLeave (&pVMMDevState->critsectHGCMCmdList);
104 AssertRC (rc);
105}
106
107static int vmmdevHGCMAddCommand (VMMDevState *pVMMDevState, PVBOXHGCMCMD pCmd, RTGCPHYS GCPhys, uint32_t cbSize, VBOXHGCMCMDTYPE enmCmdType)
108{
109 /* PPDMDEVINS pDevIns = pVMMDevState->pDevIns; */
110
111 int rc = vmmdevHGCMCmdListLock (pVMMDevState);
112
113 if (RT_SUCCESS (rc))
114 {
115 LogFlowFunc(("%p type %d\n", pCmd, enmCmdType));
116
117 /* Insert at the head of the list. The vmmdevHGCMLoadStateDone depends on this. */
118 pCmd->pNext = pVMMDevState->pHGCMCmdList;
119 pCmd->pPrev = NULL;
120
121 if (pVMMDevState->pHGCMCmdList)
122 {
123 pVMMDevState->pHGCMCmdList->pPrev = pCmd;
124 }
125
126 pVMMDevState->pHGCMCmdList = pCmd;
127
128 pCmd->enmCmdType = enmCmdType;
129 pCmd->GCPhys = GCPhys;
130 pCmd->cbSize = cbSize;
131
132 /* Automatically enable HGCM events, if there are HGCM commands. */
133 if ( enmCmdType == VBOXHGCMCMDTYPE_CONNECT
134 || enmCmdType == VBOXHGCMCMDTYPE_DISCONNECT
135 || enmCmdType == VBOXHGCMCMDTYPE_CALL)
136 {
137 Log(("vmmdevHGCMAddCommand: u32HGCMEnabled = %d\n", pVMMDevState->u32HGCMEnabled));
138 if (ASMAtomicCmpXchgU32(&pVMMDevState->u32HGCMEnabled, 1, 0))
139 {
140 VMMDevCtlSetGuestFilterMask (pVMMDevState, VMMDEV_EVENT_HGCM, 0);
141 }
142 }
143
144 vmmdevHGCMCmdListUnlock (pVMMDevState);
145 }
146
147 return rc;
148}
149
150static int vmmdevHGCMRemoveCommand (VMMDevState *pVMMDevState, PVBOXHGCMCMD pCmd)
151{
152 /* PPDMDEVINS pDevIns = pVMMDevState->pDevIns; */
153
154 int rc = vmmdevHGCMCmdListLock (pVMMDevState);
155
156 if (RT_SUCCESS (rc))
157 {
158 LogFlowFunc(("%p\n", pCmd));
159
160 if (pCmd->pNext)
161 {
162 pCmd->pNext->pPrev = pCmd->pPrev;
163 }
164 else
165 {
166 /* Tail, do nothing. */
167 }
168
169 if (pCmd->pPrev)
170 {
171 pCmd->pPrev->pNext = pCmd->pNext;
172 }
173 else
174 {
175 pVMMDevState->pHGCMCmdList = pCmd->pNext;
176 }
177
178 vmmdevHGCMCmdListUnlock (pVMMDevState);
179 }
180
181 return rc;
182}
183
184
185static PVBOXHGCMCMD vmmdevHGCMFindCommand (VMMDevState *pVMMDevState, RTGCPHYS GCPhys)
186{
187 PVBOXHGCMCMD pCmd = NULL;
188
189 int rc = vmmdevHGCMCmdListLock (pVMMDevState);
190
191 if (RT_SUCCESS (rc))
192 {
193 pCmd = pVMMDevState->pHGCMCmdList;
194
195 while (pCmd)
196 {
197 if (pCmd->GCPhys == GCPhys)
198 {
199 break;
200 }
201 pCmd = pCmd->pNext;
202 }
203
204 vmmdevHGCMCmdListUnlock (pVMMDevState);
205 }
206
207 LogFlowFunc(("%p\n", pCmd));
208 return pCmd;
209}
210
211
212static int vmmdevHGCMSaveLinPtr (PPDMDEVINS pDevIns,
213 uint32_t iParm,
214 RTGCPTR GCPtr,
215 uint32_t u32Size,
216 uint32_t iLinPtr,
217 VBOXHGCMLINPTR *paLinPtrs,
218 RTGCPHYS **ppPages)
219{
220 int rc = VINF_SUCCESS;
221
222 AssertRelease (u32Size > 0);
223
224 VBOXHGCMLINPTR *pLinPtr = &paLinPtrs[iLinPtr];
225
226 /* Take the offset into the current page also into account! */
227 u32Size += GCPtr & PAGE_OFFSET_MASK;
228
229 uint32_t cPages = (u32Size + PAGE_SIZE - 1) / PAGE_SIZE;
230
231 Log(("vmmdevHGCMSaveLinPtr: parm %d: %RGv %d = %d pages\n", iParm, GCPtr, u32Size, cPages));
232
233 pLinPtr->iParm = iParm;
234 pLinPtr->cbOffsetFirstPage = (RTGCUINTPTR)GCPtr & PAGE_OFFSET_MASK;
235 pLinPtr->cPages = cPages;
236 pLinPtr->paPages = *ppPages;
237
238 *ppPages += cPages;
239
240 uint32_t iPage = 0;
241
242 GCPtr &= PAGE_BASE_GC_MASK;
243
244 /* Gonvert the guest linear pointers of pages to HC addresses. */
245 while (iPage < cPages)
246 {
247 /* convert */
248 RTGCPHYS GCPhys;
249
250 rc = PDMDevHlpPhysGCPtr2GCPhys(pDevIns, GCPtr, &GCPhys);
251
252 Log(("vmmdevHGCMSaveLinPtr: Page %d: %RGv -> %RGp. %Rrc\n", iPage, GCPtr, GCPhys, rc));
253
254 if (RT_FAILURE (rc))
255 {
256 break;
257 }
258
259 /* store */
260 pLinPtr->paPages[iPage++] = GCPhys;
261
262 /* next */
263 GCPtr += PAGE_SIZE;
264 }
265
266 AssertRelease (iPage == cPages);
267
268 return rc;
269}
270
271static int vmmdevHGCMWriteLinPtr (PPDMDEVINS pDevIns,
272 uint32_t iParm,
273 void *pvHost,
274 uint32_t u32Size,
275 uint32_t iLinPtr,
276 VBOXHGCMLINPTR *paLinPtrs)
277{
278 int rc = VINF_SUCCESS;
279
280 VBOXHGCMLINPTR *pLinPtr = &paLinPtrs[iLinPtr];
281
282 AssertRelease (u32Size > 0 && iParm == (uint32_t)pLinPtr->iParm);
283
284 RTGCPHYS GCPhysDst = pLinPtr->paPages[0] + pLinPtr->cbOffsetFirstPage;
285 uint8_t *pu8Src = (uint8_t *)pvHost;
286
287 Log(("vmmdevHGCMWriteLinPtr: parm %d: size %d, cPages = %d\n", iParm, u32Size, pLinPtr->cPages));
288
289 uint32_t iPage = 0;
290
291 while (iPage < pLinPtr->cPages)
292 {
293 /* copy */
294 size_t cbWrite = iPage == 0?
295 PAGE_SIZE - pLinPtr->cbOffsetFirstPage:
296 PAGE_SIZE;
297
298 Log(("vmmdevHGCMWriteLinPtr: page %d: dst %RGp, src %p, cbWrite %d\n", iPage, GCPhysDst, pu8Src, cbWrite));
299
300 iPage++;
301
302 if (cbWrite >= u32Size)
303 {
304 PDMDevHlpPhysWrite(pDevIns, GCPhysDst, pu8Src, u32Size);
305 u32Size = 0;
306 break;
307 }
308
309 PDMDevHlpPhysWrite(pDevIns, GCPhysDst, pu8Src, cbWrite);
310
311 /* next */
312 u32Size -= cbWrite;
313 pu8Src += cbWrite;
314
315 GCPhysDst = pLinPtr->paPages[iPage];
316 }
317
318 AssertRelease (iPage == pLinPtr->cPages);
319 Assert(u32Size == 0);
320
321 return rc;
322}
323
324int vmmdevHGCMConnect (VMMDevState *pVMMDevState, VMMDevHGCMConnect *pHGCMConnect, RTGCPHYS GCPhys)
325{
326 int rc = VINF_SUCCESS;
327
328 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAllocZ (sizeof (struct VBOXHGCMCMD) + pHGCMConnect->header.header.size);
329
330 if (pCmd)
331 {
332 VMMDevHGCMConnect *pHGCMConnectCopy = (VMMDevHGCMConnect *)(pCmd+1);
333
334 vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMConnect->header.header.size, VBOXHGCMCMDTYPE_CONNECT);
335
336 memcpy(pHGCMConnectCopy, pHGCMConnect, pHGCMConnect->header.header.size);
337
338 pCmd->paHostParms = NULL;
339 pCmd->cLinPtrs = 0;
340 pCmd->paLinPtrs = NULL;
341
342 /* Only allow the guest to use existing services! */
343 Assert(pHGCMConnect->loc.type == VMMDevHGCMLoc_LocalHost_Existing);
344 pHGCMConnect->loc.type = VMMDevHGCMLoc_LocalHost_Existing;
345
346 rc = pVMMDevState->pHGCMDrv->pfnConnect (pVMMDevState->pHGCMDrv, pCmd, &pHGCMConnectCopy->loc, &pHGCMConnectCopy->u32ClientID);
347 }
348 else
349 {
350 rc = VERR_NO_MEMORY;
351 }
352
353 return rc;
354}
355
356int vmmdevHGCMDisconnect (VMMDevState *pVMMDevState, VMMDevHGCMDisconnect *pHGCMDisconnect, RTGCPHYS GCPhys)
357{
358 int rc = VINF_SUCCESS;
359
360 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAllocZ (sizeof (struct VBOXHGCMCMD));
361
362 if (pCmd)
363 {
364 vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMDisconnect->header.header.size, VBOXHGCMCMDTYPE_DISCONNECT);
365
366 pCmd->paHostParms = NULL;
367 pCmd->cLinPtrs = 0;
368 pCmd->paLinPtrs = NULL;
369
370 rc = pVMMDevState->pHGCMDrv->pfnDisconnect (pVMMDevState->pHGCMDrv, pCmd, pHGCMDisconnect->u32ClientID);
371 }
372 else
373 {
374 rc = VERR_NO_MEMORY;
375 }
376
377 return rc;
378}
379
380
381int vmmdevHGCMCall (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, RTGCPHYS GCPhys, bool f64Bits)
382{
383 int rc = VINF_SUCCESS;
384
385 Log(("vmmdevHGCMCall: client id = %d, function = %d, %s bit\n", pHGCMCall->u32ClientID, pHGCMCall->u32Function, f64Bits? "64": "32"));
386
387 /* Compute size and allocate memory block to hold:
388 * struct VBOXHGCMCMD
389 * VBOXHGCMSVCPARM[cParms]
390 * memory buffers for pointer parameters.
391 */
392
393 uint32_t cParms = pHGCMCall->cParms;
394
395 Log(("vmmdevHGCMCall: cParms = %d\n", cParms));
396
397 /*
398 * Compute size of required memory buffer.
399 */
400
401 uint32_t cbCmdSize = sizeof (struct VBOXHGCMCMD) + cParms * sizeof (VBOXHGCMSVCPARM);
402
403 uint32_t i;
404
405 uint32_t cLinPtrs = 0;
406 uint32_t cLinPtrPages = 0;
407
408 if (f64Bits)
409 {
410#ifdef VBOX_WITH_64_BITS_GUESTS
411 HGCMFunctionParameter64 *pGuestParm = VMMDEV_HGCM_CALL_PARMS64(pHGCMCall);
412#else
413 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
414 AssertFailed (); /* This code should not be called in this case */
415#endif /* VBOX_WITH_64_BITS_GUESTS */
416
417 /* Look for pointer parameters, which require a host buffer. */
418 for (i = 0; i < cParms && RT_SUCCESS(rc); i++, pGuestParm++)
419 {
420 switch (pGuestParm->type)
421 {
422 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
423 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
424 case VMMDevHGCMParmType_LinAddr: /* In & Out */
425 {
426 cbCmdSize += pGuestParm->u.Pointer.size;
427
428 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
429 {
430 cLinPtrs++;
431 /* Take the offset into the current page also into account! */
432 cLinPtrPages += ((pGuestParm->u.Pointer.u.linearAddr & PAGE_OFFSET_MASK)
433 + pGuestParm->u.Pointer.size + PAGE_SIZE - 1) / PAGE_SIZE;
434 }
435
436 Log(("vmmdevHGCMCall: linptr size = %d\n", pGuestParm->u.Pointer.size));
437 } break;
438
439 case VMMDevHGCMParmType_32bit:
440 case VMMDevHGCMParmType_64bit:
441 case VMMDevHGCMParmType_PhysAddr:
442 {
443 } break;
444
445 default:
446 {
447 AssertMsgFailed(("vmmdevHGCMCall: invalid parameter type %x\n", pGuestParm->type));
448 rc = VERR_INVALID_PARAMETER;
449 break;
450 }
451 }
452 }
453 }
454 else
455 {
456#ifdef VBOX_WITH_64_BITS_GUESTS
457 HGCMFunctionParameter32 *pGuestParm = VMMDEV_HGCM_CALL_PARMS32(pHGCMCall);
458#else
459 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
460#endif /* VBOX_WITH_64_BITS_GUESTS */
461
462 /* Look for pointer parameters, which require a host buffer. */
463 for (i = 0; i < cParms && RT_SUCCESS(rc); i++, pGuestParm++)
464 {
465 switch (pGuestParm->type)
466 {
467 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
468 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
469 case VMMDevHGCMParmType_LinAddr: /* In & Out */
470 {
471 cbCmdSize += pGuestParm->u.Pointer.size;
472
473 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
474 {
475 cLinPtrs++;
476 /* Take the offset into the current page also into account! */
477 cLinPtrPages += ((pGuestParm->u.Pointer.u.linearAddr & PAGE_OFFSET_MASK)
478 + pGuestParm->u.Pointer.size + PAGE_SIZE - 1) / PAGE_SIZE;
479 }
480
481 Log(("vmmdevHGCMCall: linptr size = %d\n", pGuestParm->u.Pointer.size));
482 } break;
483
484 case VMMDevHGCMParmType_32bit:
485 case VMMDevHGCMParmType_64bit:
486 case VMMDevHGCMParmType_PhysAddr:
487 {
488 } break;
489
490 default:
491 {
492 AssertMsgFailed(("vmmdevHGCMCall: invalid parameter type %x\n", pGuestParm->type));
493 rc = VERR_INVALID_PARAMETER;
494 break;
495 }
496 }
497 }
498 }
499
500 if (RT_FAILURE (rc))
501 {
502 return rc;
503 }
504
505 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAlloc (cbCmdSize);
506
507 if (pCmd == NULL)
508 {
509 return VERR_NO_MEMORY;
510 }
511
512 memset (pCmd, 0, sizeof (*pCmd));
513
514 pCmd->paHostParms = NULL;
515 pCmd->cLinPtrs = cLinPtrs;
516
517 if (cLinPtrs > 0)
518 {
519 pCmd->paLinPtrs = (VBOXHGCMLINPTR *)RTMemAlloc ( sizeof (VBOXHGCMLINPTR) * cLinPtrs
520 + sizeof (RTGCPHYS) * cLinPtrPages);
521
522 if (pCmd->paLinPtrs == NULL)
523 {
524 RTMemFree (pCmd);
525 return VERR_NO_MEMORY;
526 }
527 }
528 else
529 {
530 pCmd->paLinPtrs = NULL;
531 }
532
533 /* Process parameters, changing them to host context pointers for easy
534 * processing by connector. Guest must insure that the pointed data is actually
535 * in the guest RAM and remains locked there for entire request processing.
536 */
537
538 if (cParms != 0)
539 {
540 /* Compute addresses of host parms array and first memory buffer. */
541 VBOXHGCMSVCPARM *pHostParm = (VBOXHGCMSVCPARM *)((char *)pCmd + sizeof (struct VBOXHGCMCMD));
542
543 uint8_t *pcBuf = (uint8_t *)pHostParm + cParms * sizeof (VBOXHGCMSVCPARM);
544
545 pCmd->paHostParms = pHostParm;
546
547 uint32_t iLinPtr = 0;
548 RTGCPHYS *pPages = (RTGCPHYS *)((uint8_t *)pCmd->paLinPtrs + sizeof (VBOXHGCMLINPTR) *cLinPtrs);
549
550 if (f64Bits)
551 {
552#ifdef VBOX_WITH_64_BITS_GUESTS
553 HGCMFunctionParameter64 *pGuestParm = VMMDEV_HGCM_CALL_PARMS64(pHGCMCall);
554#else
555 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
556 AssertFailed (); /* This code should not be called in this case */
557#endif /* VBOX_WITH_64_BITS_GUESTS */
558
559
560 for (i = 0; i < cParms && RT_SUCCESS(rc); i++, pGuestParm++, pHostParm++)
561 {
562 switch (pGuestParm->type)
563 {
564 case VMMDevHGCMParmType_32bit:
565 {
566 uint32_t u32 = pGuestParm->u.value32;
567
568 pHostParm->type = VBOX_HGCM_SVC_PARM_32BIT;
569 pHostParm->u.uint32 = u32;
570
571 Log(("vmmdevHGCMCall: uint32 guest parameter %u\n", u32));
572 break;
573 }
574
575 case VMMDevHGCMParmType_64bit:
576 {
577 uint64_t u64 = pGuestParm->u.value64;
578
579 pHostParm->type = VBOX_HGCM_SVC_PARM_64BIT;
580 pHostParm->u.uint64 = u64;
581
582 Log(("vmmdevHGCMCall: uint64 guest parameter %llu\n", u64));
583 break;
584 }
585
586 case VMMDevHGCMParmType_PhysAddr:
587 {
588 uint32_t size = pGuestParm->u.Pointer.size;
589#ifdef LOG_ENABLED
590 RTGCPHYS physAddr = pGuestParm->u.Pointer.u.physAddr;
591#endif
592
593 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
594 pHostParm->u.pointer.size = size;
595
596 AssertFailed();
597 /* rc = PDMDevHlpPhys2HCVirt (pVMMDevState->pDevIns, physAddr, size, &pHostParm->u.pointer.addr); */
598
599 Log(("vmmdevHGCMCall: PhysAddr guest parameter %RGp\n", physAddr));
600 break;
601 }
602
603 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
604 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
605 case VMMDevHGCMParmType_LinAddr: /* In & Out */
606 {
607 uint32_t size = pGuestParm->u.Pointer.size;
608 RTGCPTR linearAddr = pGuestParm->u.Pointer.u.linearAddr;
609
610 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
611 pHostParm->u.pointer.size = size;
612
613 /* Copy guest data to an allocated buffer, so
614 * services can use the data.
615 */
616
617 if (size == 0)
618 {
619 pHostParm->u.pointer.addr = (void *) 0xfeeddead;
620 }
621 else
622 {
623 /* Don't overdo it */
624 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_Out)
625 rc = PDMDevHlpPhysReadGCVirt(pVMMDevState->pDevIns, pcBuf, linearAddr, size);
626 else
627 rc = VINF_SUCCESS;
628
629 if (RT_SUCCESS(rc))
630 {
631 pHostParm->u.pointer.addr = pcBuf;
632 pcBuf += size;
633
634 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
635 {
636 /* Remember the guest physical pages that belong to the virtual address
637 * region.
638 */
639 rc = vmmdevHGCMSaveLinPtr (pVMMDevState->pDevIns, i, linearAddr, size, iLinPtr++, pCmd->paLinPtrs, &pPages);
640 }
641 }
642 }
643
644 Log(("vmmdevHGCMCall: LinAddr guest parameter %RGv, rc = %Rrc\n", linearAddr, rc));
645 break;
646 }
647
648 /* just to shut up gcc */
649 default:
650 break;
651 }
652 }
653 }
654 else
655 {
656#ifdef VBOX_WITH_64_BITS_GUESTS
657 HGCMFunctionParameter32 *pGuestParm = VMMDEV_HGCM_CALL_PARMS32(pHGCMCall);
658#else
659 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
660#endif /* VBOX_WITH_64_BITS_GUESTS */
661
662 for (i = 0; i < cParms && RT_SUCCESS(rc); i++, pGuestParm++, pHostParm++)
663 {
664 switch (pGuestParm->type)
665 {
666 case VMMDevHGCMParmType_32bit:
667 {
668 uint32_t u32 = pGuestParm->u.value32;
669
670 pHostParm->type = VBOX_HGCM_SVC_PARM_32BIT;
671 pHostParm->u.uint32 = u32;
672
673 Log(("vmmdevHGCMCall: uint32 guest parameter %u\n", u32));
674 break;
675 }
676
677 case VMMDevHGCMParmType_64bit:
678 {
679 uint64_t u64 = pGuestParm->u.value64;
680
681 pHostParm->type = VBOX_HGCM_SVC_PARM_64BIT;
682 pHostParm->u.uint64 = u64;
683
684 Log(("vmmdevHGCMCall: uint64 guest parameter %llu\n", u64));
685 break;
686 }
687
688 case VMMDevHGCMParmType_PhysAddr:
689 {
690 uint32_t size = pGuestParm->u.Pointer.size;
691#ifdef LOG_ENABLED
692 RTGCPHYS physAddr = pGuestParm->u.Pointer.u.physAddr;
693#endif
694
695 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
696 pHostParm->u.pointer.size = size;
697
698 AssertFailed();
699 /* rc = PDMDevHlpPhys2HCVirt (pVMMDevState->pDevIns, physAddr, size, &pHostParm->u.pointer.addr); */
700
701 Log(("vmmdevHGCMCall: PhysAddr guest parameter %RGp\n", physAddr));
702 break;
703 }
704
705 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
706 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
707 case VMMDevHGCMParmType_LinAddr: /* In & Out */
708 {
709 uint32_t size = pGuestParm->u.Pointer.size;
710 RTGCPTR linearAddr = pGuestParm->u.Pointer.u.linearAddr;
711
712 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
713 pHostParm->u.pointer.size = size;
714
715 /* Copy guest data to an allocated buffer, so
716 * services can use the data.
717 */
718
719 if (size == 0)
720 {
721 pHostParm->u.pointer.addr = (void *) 0xfeeddead;
722 }
723 else
724 {
725 /* Don't overdo it */
726 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_Out)
727 rc = PDMDevHlpPhysReadGCVirt(pVMMDevState->pDevIns, pcBuf, linearAddr, size);
728 else
729 rc = VINF_SUCCESS;
730
731 if (RT_SUCCESS(rc))
732 {
733 pHostParm->u.pointer.addr = pcBuf;
734 pcBuf += size;
735
736 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
737 {
738 /* Remember the guest physical pages that belong to the virtual address
739 * region.
740 */
741 rc = vmmdevHGCMSaveLinPtr (pVMMDevState->pDevIns, i, linearAddr, size, iLinPtr++, pCmd->paLinPtrs, &pPages);
742 }
743 }
744 }
745
746 Log(("vmmdevHGCMCall: LinAddr guest parameter %RGv, rc = %Rrc\n", linearAddr, rc));
747 break;
748 }
749
750 /* just to shut up gcc */
751 default:
752 break;
753 }
754 }
755 }
756 }
757
758 if (RT_SUCCESS (rc))
759 {
760 vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMCall->header.header.size, VBOXHGCMCMDTYPE_CALL);
761
762 /* Pass the function call to HGCM connector for actual processing */
763 rc = pVMMDevState->pHGCMDrv->pfnCall (pVMMDevState->pHGCMDrv, pCmd, pHGCMCall->u32ClientID, pHGCMCall->u32Function, cParms, pCmd->paHostParms);
764 }
765 else
766 {
767 if (pCmd->paLinPtrs)
768 {
769 RTMemFree (pCmd->paLinPtrs);
770 }
771
772 RTMemFree (pCmd);
773 }
774
775 return rc;
776}
777
778/* @thread EMT */
779int vmmdevHGCMCancel (VMMDevState *pVMMDevState, VMMDevHGCMCancel *pHGCMCancel, RTGCPHYS GCPhys)
780{
781 int rc = VINF_SUCCESS;
782
783 NOREF(pHGCMCancel);
784
785 Log(("vmmdevHGCMCancel\n"));
786
787 /* Find the command in the list. */
788 PVBOXHGCMCMD pCmd = vmmdevHGCMFindCommand (pVMMDevState, GCPhys);
789
790 if (pCmd)
791 {
792 pCmd->fCancelled = true;
793 }
794 else
795 {
796 rc = VERR_INVALID_PARAMETER;
797 }
798
799 return rc;
800}
801
802static int vmmdevHGCMCmdVerify (PVBOXHGCMCMD pCmd, VMMDevHGCMRequestHeader *pHeader)
803{
804 switch (pCmd->enmCmdType)
805 {
806 case VBOXHGCMCMDTYPE_CONNECT:
807 if ( pHeader->header.requestType == VMMDevReq_HGCMConnect
808 || pHeader->header.requestType == VMMDevReq_HGCMCancel) return VINF_SUCCESS;
809 break;
810
811 case VBOXHGCMCMDTYPE_DISCONNECT:
812 if ( pHeader->header.requestType == VMMDevReq_HGCMDisconnect
813 || pHeader->header.requestType == VMMDevReq_HGCMCancel) return VINF_SUCCESS;
814 break;
815
816 case VBOXHGCMCMDTYPE_CALL:
817#ifdef VBOX_WITH_64_BITS_GUESTS
818 if ( pHeader->header.requestType == VMMDevReq_HGCMCall32
819 || pHeader->header.requestType == VMMDevReq_HGCMCall64
820 || pHeader->header.requestType == VMMDevReq_HGCMCancel) return VINF_SUCCESS;
821#else
822 if ( pHeader->header.requestType == VMMDevReq_HGCMCall
823 || pHeader->header.requestType == VMMDevReq_HGCMCancel) return VINF_SUCCESS;
824#endif /* VBOX_WITH_64_BITS_GUESTS */
825
826 break;
827
828 default:
829 AssertFailed ();
830 }
831
832 LogRel(("VMMDEV: Invalid HGCM command: pCmd->enmCmdType = 0x%08X, pHeader->header.requestType = 0x%08X\n",
833 pCmd->enmCmdType, pHeader->header.requestType));
834 return VERR_INVALID_PARAMETER;
835}
836
837#define PDMIHGCMPORT_2_VMMDEVSTATE(pInterface) ( (VMMDevState *) ((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, HGCMPort)) )
838
839DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result, PVBOXHGCMCMD pCmd)
840{
841 VMMDevState *pVMMDevState = PDMIHGCMPORT_2_VMMDEVSTATE(pInterface);
842
843 int rc = VINF_SUCCESS;
844
845 if (result == VINF_HGCM_SAVE_STATE)
846 {
847 /* If the completion routine was called because HGCM saves its state,
848 * then currently nothing to be done here. The pCmd stays in the list
849 * and will be saved later when the VMMDev state will be saved.
850 *
851 * It it assumed that VMMDev saves state after the HGCM services,
852 * and, therefore, VBOXHGCMCMD structures are not removed by
853 * vmmdevHGCMSaveState from the list, while HGCM uses them.
854 */
855 LogFlowFunc(("VINF_HGCM_SAVE_STATE for command %p\n", pCmd));
856 return;
857 }
858
859 /* Check whether the command has been already cancelled by the guest.
860 * If it was cancelled, then the data must not be written back to the
861 * guest RAM.
862 */
863 if (pCmd->fCancelled)
864 {
865 /* Just remove the command from the internal list, so the memory can be freed. */
866 LogFlowFunc(("A cancelled command %p\n", pCmd));
867 vmmdevHGCMRemoveCommand (pVMMDevState, pCmd);
868 }
869 else
870 {
871 /* Preallocated block for requests which have up to 8 parameters (most of requests). */
872#ifdef VBOX_WITH_64_BITS_GUESTS
873 uint8_t au8Prealloc[sizeof (VMMDevHGCMCall) + 8 * sizeof (HGCMFunctionParameter64)];
874#else
875 uint8_t au8Prealloc[sizeof (VMMDevHGCMCall) + 8 * sizeof (HGCMFunctionParameter)];
876#endif /* VBOX_WITH_64_BITS_GUESTS */
877
878 VMMDevHGCMRequestHeader *pHeader;
879
880 if (pCmd->cbSize <= sizeof (au8Prealloc))
881 {
882 pHeader = (VMMDevHGCMRequestHeader *)&au8Prealloc[0];
883 }
884 else
885 {
886 pHeader = (VMMDevHGCMRequestHeader *)RTMemAlloc (pCmd->cbSize);
887 Assert(pHeader);
888 if (pHeader == NULL)
889 {
890 LogRel(("VMMDev: Failed to allocate %d bytes for HGCM request completion!!!\n", pCmd->cbSize));
891
892 /* Do some cleanup. The command have to be excluded from list of active commands anyway. */
893 vmmdevHGCMRemoveCommand (pVMMDevState, pCmd);
894 return;
895 }
896 }
897
898 PDMDevHlpPhysRead(pVMMDevState->pDevIns, pCmd->GCPhys, pHeader, pCmd->cbSize);
899
900 /* Setup return codes. */
901 pHeader->result = result;
902
903 /* Verify the request type. */
904 rc = vmmdevHGCMCmdVerify (pCmd, pHeader);
905
906 if (RT_SUCCESS (rc))
907 {
908 /* Update parameters and data buffers. */
909
910 switch (pHeader->header.requestType)
911 {
912#ifdef VBOX_WITH_64_BITS_GUESTS
913 case VMMDevReq_HGCMCall64:
914 {
915 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pHeader;
916
917 uint32_t cParms = pHGCMCall->cParms;
918
919 VBOXHGCMSVCPARM *pHostParm = pCmd->paHostParms;
920
921 uint32_t i;
922 uint32_t iLinPtr = 0;
923
924 HGCMFunctionParameter64 *pGuestParm = VMMDEV_HGCM_CALL_PARMS64(pHGCMCall);
925
926 for (i = 0; i < cParms; i++, pGuestParm++, pHostParm++)
927 {
928 switch (pGuestParm->type)
929 {
930 case VMMDevHGCMParmType_32bit:
931 {
932 pGuestParm->u.value32 = pHostParm->u.uint32;
933 } break;
934
935 case VMMDevHGCMParmType_64bit:
936 {
937 pGuestParm->u.value64 = pHostParm->u.uint64;
938 } break;
939
940 case VMMDevHGCMParmType_PhysAddr:
941 {
942 /* do nothing */
943 } break;
944
945 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
946 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
947 case VMMDevHGCMParmType_LinAddr: /* In & Out */
948 {
949 /* Copy buffer back to guest memory. */
950 uint32_t size = pGuestParm->u.Pointer.size;
951
952 if (size > 0 && pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
953 {
954 /* Use the saved page list. */
955 rc = vmmdevHGCMWriteLinPtr (pVMMDevState->pDevIns, i, pHostParm->u.pointer.addr, size, iLinPtr++, pCmd->paLinPtrs);
956 AssertReleaseRC(rc);
957 }
958 } break;
959
960 default:
961 {
962 /* This indicates that the guest request memory was corrupted. */
963 AssertReleaseMsgFailed(("hgcmCompleted: invalid parameter type %08X\n", pGuestParm->type));
964 }
965 }
966 }
967 break;
968 }
969
970 case VMMDevReq_HGCMCall32:
971 {
972 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pHeader;
973
974 uint32_t cParms = pHGCMCall->cParms;
975
976 VBOXHGCMSVCPARM *pHostParm = pCmd->paHostParms;
977
978 uint32_t i;
979 uint32_t iLinPtr = 0;
980
981 HGCMFunctionParameter32 *pGuestParm = VMMDEV_HGCM_CALL_PARMS32(pHGCMCall);
982
983 for (i = 0; i < cParms; i++, pGuestParm++, pHostParm++)
984 {
985 switch (pGuestParm->type)
986 {
987 case VMMDevHGCMParmType_32bit:
988 {
989 pGuestParm->u.value32 = pHostParm->u.uint32;
990 } break;
991
992 case VMMDevHGCMParmType_64bit:
993 {
994 pGuestParm->u.value64 = pHostParm->u.uint64;
995 } break;
996
997 case VMMDevHGCMParmType_PhysAddr:
998 {
999 /* do nothing */
1000 } break;
1001
1002 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
1003 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
1004 case VMMDevHGCMParmType_LinAddr: /* In & Out */
1005 {
1006 /* Copy buffer back to guest memory. */
1007 uint32_t size = pGuestParm->u.Pointer.size;
1008
1009 if (size > 0 && pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
1010 {
1011 /* Use the saved page list. */
1012 rc = vmmdevHGCMWriteLinPtr (pVMMDevState->pDevIns, i, pHostParm->u.pointer.addr, size, iLinPtr++, pCmd->paLinPtrs);
1013 AssertReleaseRC(rc);
1014 }
1015 } break;
1016
1017 default:
1018 {
1019 /* This indicates that the guest request memory was corrupted. */
1020 AssertReleaseMsgFailed(("hgcmCompleted: invalid parameter type %08X\n", pGuestParm->type));
1021 }
1022 }
1023 }
1024 break;
1025 }
1026#else
1027 case VMMDevReq_HGCMCall:
1028 {
1029 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pHeader;
1030
1031 uint32_t cParms = pHGCMCall->cParms;
1032
1033 VBOXHGCMSVCPARM *pHostParm = pCmd->paHostParms;
1034
1035 uint32_t i;
1036 uint32_t iLinPtr = 0;
1037
1038 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
1039
1040 for (i = 0; i < cParms; i++, pGuestParm++, pHostParm++)
1041 {
1042 switch (pGuestParm->type)
1043 {
1044 case VMMDevHGCMParmType_32bit:
1045 {
1046 pGuestParm->u.value32 = pHostParm->u.uint32;
1047 } break;
1048
1049 case VMMDevHGCMParmType_64bit:
1050 {
1051 pGuestParm->u.value64 = pHostParm->u.uint64;
1052 } break;
1053
1054 case VMMDevHGCMParmType_PhysAddr:
1055 {
1056 /* do nothing */
1057 } break;
1058
1059 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
1060 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
1061 case VMMDevHGCMParmType_LinAddr: /* In & Out */
1062 {
1063 /* Copy buffer back to guest memory. */
1064 uint32_t size = pGuestParm->u.Pointer.size;
1065
1066 if (size > 0 && pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
1067 {
1068 /* Use the saved page list. */
1069 rc = vmmdevHGCMWriteLinPtr (pVMMDevState->pDevIns, i, pHostParm->u.pointer.addr, size, iLinPtr++, pCmd->paLinPtrs);
1070 AssertReleaseRC(rc);
1071 }
1072 } break;
1073
1074 default:
1075 {
1076 /* This indicates that the guest request memory was corrupted. */
1077 AssertReleaseMsgFailed(("hgcmCompleted: invalid parameter type %08X\n", pGuestParm->type));
1078 }
1079 }
1080 }
1081 break;
1082 }
1083#endif /* VBOX_WITH_64_BITS_GUESTS */
1084 case VMMDevReq_HGCMConnect:
1085 {
1086 VMMDevHGCMConnect *pHGCMConnectCopy = (VMMDevHGCMConnect *)(pCmd+1);
1087
1088 /* save the client id in the guest request packet */
1089 VMMDevHGCMConnect *pHGCMConnect = (VMMDevHGCMConnect *)pHeader;
1090 pHGCMConnect->u32ClientID = pHGCMConnectCopy->u32ClientID;
1091 break;
1092 }
1093
1094 default:
1095 /* make gcc happy */
1096 break;
1097 }
1098 }
1099 else
1100 {
1101 /* Command type is wrong. Return error to the guest. */
1102 pHeader->header.rc = rc;
1103 }
1104
1105 /* Mark request as processed. */
1106 pHeader->fu32Flags |= VBOX_HGCM_REQ_DONE;
1107
1108 /* Write back the request */
1109 PDMDevHlpPhysWrite(pVMMDevState->pDevIns, pCmd->GCPhys, pHeader, pCmd->cbSize);
1110
1111 /* The command has been completely processed and can be removed from the list. */
1112 vmmdevHGCMRemoveCommand (pVMMDevState, pCmd);
1113
1114 /* Now, when the command was removed from the internal list, notify the guest. */
1115 VMMDevNotifyGuest (pVMMDevState, VMMDEV_EVENT_HGCM);
1116
1117 if ((uint8_t *)pHeader != &au8Prealloc[0])
1118 {
1119 /* Only if it was allocated from heap. */
1120 RTMemFree (pHeader);
1121 }
1122 }
1123
1124 /* Deallocate the command memory. */
1125 if (pCmd->paLinPtrs)
1126 {
1127 RTMemFree (pCmd->paLinPtrs);
1128 }
1129
1130 RTMemFree (pCmd);
1131
1132 return;
1133}
1134
1135DECLCALLBACK(void) hgcmCompleted (PPDMIHGCMPORT pInterface, int32_t result, PVBOXHGCMCMD pCmd)
1136{
1137 VMMDevState *pVMMDevState = PDMIHGCMPORT_2_VMMDEVSTATE(pInterface);
1138
1139 /* Not safe to execute asynchroneously; forward to EMT */
1140 int rc = VMR3ReqCallEx(PDMDevHlpGetVM(pVMMDevState->pDevIns), VMREQDEST_ANY, NULL, 0, VMREQFLAGS_NO_WAIT | VMREQFLAGS_VOID,
1141 (PFNRT)hgcmCompletedWorker, 3, pInterface, result, pCmd);
1142 AssertRC(rc);
1143}
1144
1145/* @thread EMT */
1146int vmmdevHGCMSaveState(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
1147{
1148 /* Save information about pending requests.
1149 * Only GCPtrs are of interest.
1150 */
1151 int rc = VINF_SUCCESS;
1152
1153 LogFlowFunc(("\n"));
1154
1155 /* Compute how many commands are pending. */
1156 uint32_t cCmds = 0;
1157
1158 PVBOXHGCMCMD pIter = pVMMDevState->pHGCMCmdList;
1159
1160 while (pIter)
1161 {
1162 LogFlowFunc (("pIter %p\n", pIter));
1163 cCmds++;
1164 pIter = pIter->pNext;
1165 }
1166
1167 LogFlowFunc(("cCmds = %d\n", cCmds));
1168
1169 /* Save number of commands. */
1170 rc = SSMR3PutU32(pSSM, cCmds);
1171 AssertRCReturn(rc, rc);
1172
1173 if (cCmds > 0)
1174 {
1175 pIter = pVMMDevState->pHGCMCmdList;
1176
1177 while (pIter)
1178 {
1179 PVBOXHGCMCMD pNext = pIter->pNext;
1180
1181 LogFlowFunc (("Saving %RGp\n", pIter->GCPhys));
1182 rc = SSMR3PutGCPhys(pSSM, pIter->GCPhys);
1183 AssertRCReturn(rc, rc);
1184
1185 rc = SSMR3PutU32(pSSM, pIter->cbSize);
1186 AssertRCReturn(rc, rc);
1187
1188 vmmdevHGCMRemoveCommand (pVMMDevState, pIter);
1189
1190 pIter = pNext;
1191 }
1192 }
1193
1194 return rc;
1195}
1196
1197/* @thread EMT */
1198int vmmdevHGCMLoadState(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
1199{
1200 int rc = VINF_SUCCESS;
1201
1202 LogFlowFunc(("\n"));
1203
1204 /* Read how many commands were pending. */
1205 uint32_t cCmds = 0;
1206 rc = SSMR3GetU32(pSSM, &cCmds);
1207 AssertRCReturn(rc, rc);
1208
1209 LogFlowFunc(("cCmds = %d\n", cCmds));
1210
1211 while (cCmds--)
1212 {
1213 RTGCPHYS GCPhys;
1214 uint32_t cbSize;
1215
1216 rc = SSMR3GetGCPhys(pSSM, &GCPhys);
1217 AssertRCReturn(rc, rc);
1218
1219 rc = SSMR3GetU32(pSSM, &cbSize);
1220 AssertRCReturn(rc, rc);
1221
1222 LogFlowFunc (("Restoring %RGp size %x bytes\n", GCPhys, cbSize));
1223
1224 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAllocZ (sizeof (struct VBOXHGCMCMD));
1225 AssertReturn(pCmd, VERR_NO_MEMORY);
1226
1227 vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, cbSize, VBOXHGCMCMDTYPE_LOADSTATE);
1228 }
1229
1230 return rc;
1231}
1232
1233/* @thread EMT */
1234int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
1235{
1236 LogFlowFunc(("\n"));
1237
1238 /* Reissue pending requests. */
1239 PPDMDEVINS pDevIns = pVMMDevState->pDevIns;
1240
1241 int rc = vmmdevHGCMCmdListLock (pVMMDevState);
1242
1243 if (RT_SUCCESS (rc))
1244 {
1245 PVBOXHGCMCMD pIter = pVMMDevState->pHGCMCmdList;
1246
1247 while (pIter)
1248 {
1249 LogFlowFunc (("pIter %p\n", pIter));
1250
1251 PVBOXHGCMCMD pNext = pIter->pNext;
1252
1253 VMMDevRequestHeader *requestHeader = (VMMDevRequestHeader *)RTMemAllocZ (pIter->cbSize);
1254 Assert(requestHeader);
1255 if (requestHeader == NULL)
1256 return VERR_NO_MEMORY;
1257
1258 PDMDevHlpPhysRead(pDevIns, (RTGCPHYS)pIter->GCPhys, requestHeader, pIter->cbSize);
1259
1260 /* the structure size must be greater or equal to the header size */
1261 if (requestHeader->size < sizeof(VMMDevRequestHeader))
1262 {
1263 Log(("VMMDev request header size too small! size = %d\n", requestHeader->size));
1264 }
1265 else
1266 {
1267 /* check the version of the header structure */
1268 if (requestHeader->version != VMMDEV_REQUEST_HEADER_VERSION)
1269 {
1270 Log(("VMMDev: guest header version (0x%08X) differs from ours (0x%08X)\n", requestHeader->version, VMMDEV_REQUEST_HEADER_VERSION));
1271 }
1272 else
1273 {
1274 Log(("VMMDev request issued: %d\n", requestHeader->requestType));
1275
1276 switch (requestHeader->requestType)
1277 {
1278 case VMMDevReq_HGCMConnect:
1279 {
1280 if (requestHeader->size < sizeof(VMMDevHGCMConnect))
1281 {
1282 AssertMsgFailed(("VMMDevReq_HGCMConnect structure has invalid size!\n"));
1283 requestHeader->rc = VERR_INVALID_PARAMETER;
1284 }
1285 else if (!pVMMDevState->pHGCMDrv)
1286 {
1287 Log(("VMMDevReq_HGCMConnect HGCM Connector is NULL!\n"));
1288 requestHeader->rc = VERR_NOT_SUPPORTED;
1289 }
1290 else
1291 {
1292 VMMDevHGCMConnect *pHGCMConnect = (VMMDevHGCMConnect *)requestHeader;
1293
1294 Log(("VMMDevReq_HGCMConnect\n"));
1295
1296 requestHeader->rc = vmmdevHGCMConnect (pVMMDevState, pHGCMConnect, pIter->GCPhys);
1297 }
1298 break;
1299 }
1300
1301 case VMMDevReq_HGCMDisconnect:
1302 {
1303 if (requestHeader->size < sizeof(VMMDevHGCMDisconnect))
1304 {
1305 AssertMsgFailed(("VMMDevReq_HGCMDisconnect structure has invalid size!\n"));
1306 requestHeader->rc = VERR_INVALID_PARAMETER;
1307 }
1308 else if (!pVMMDevState->pHGCMDrv)
1309 {
1310 Log(("VMMDevReq_HGCMDisconnect HGCM Connector is NULL!\n"));
1311 requestHeader->rc = VERR_NOT_SUPPORTED;
1312 }
1313 else
1314 {
1315 VMMDevHGCMDisconnect *pHGCMDisconnect = (VMMDevHGCMDisconnect *)requestHeader;
1316
1317 Log(("VMMDevReq_VMMDevHGCMDisconnect\n"));
1318 requestHeader->rc = vmmdevHGCMDisconnect (pVMMDevState, pHGCMDisconnect, pIter->GCPhys);
1319 }
1320 break;
1321 }
1322
1323#ifdef VBOX_WITH_64_BITS_GUESTS
1324 case VMMDevReq_HGCMCall64:
1325 case VMMDevReq_HGCMCall32:
1326#else
1327 case VMMDevReq_HGCMCall:
1328#endif /* VBOX_WITH_64_BITS_GUESTS */
1329 {
1330 if (requestHeader->size < sizeof(VMMDevHGCMCall))
1331 {
1332 AssertMsgFailed(("VMMDevReq_HGCMCall structure has invalid size!\n"));
1333 requestHeader->rc = VERR_INVALID_PARAMETER;
1334 }
1335 else if (!pVMMDevState->pHGCMDrv)
1336 {
1337 Log(("VMMDevReq_HGCMCall HGCM Connector is NULL!\n"));
1338 requestHeader->rc = VERR_NOT_SUPPORTED;
1339 }
1340 else
1341 {
1342 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)requestHeader;
1343
1344 Log(("VMMDevReq_HGCMCall: sizeof (VMMDevHGCMRequest) = %04X\n", sizeof (VMMDevHGCMCall)));
1345
1346 Log(("%.*Rhxd\n", requestHeader->size, requestHeader));
1347
1348#ifdef VBOX_WITH_64_BITS_GUESTS
1349 bool f64Bits = (requestHeader->requestType == VMMDevReq_HGCMCall64);
1350#else
1351 bool f64Bits = false;
1352#endif /* VBOX_WITH_64_BITS_GUESTS */
1353 requestHeader->rc = vmmdevHGCMCall (pVMMDevState, pHGCMCall, pIter->GCPhys, f64Bits);
1354 }
1355 break;
1356 }
1357 default:
1358 AssertMsgFailed(("Unknown request type %x during LoadState\n", requestHeader->requestType));
1359 LogRel(("VMMDEV: Ignoring unknown request type %x during LoadState\n", requestHeader->requestType));
1360 }
1361 }
1362 }
1363
1364 /* Write back the request */
1365 PDMDevHlpPhysWrite(pDevIns, pIter->GCPhys, requestHeader, pIter->cbSize);
1366 RTMemFree(requestHeader);
1367
1368 vmmdevHGCMRemoveCommand (pVMMDevState, pIter);
1369 RTMemFree(pIter);
1370 pIter = pNext;
1371 }
1372
1373 vmmdevHGCMCmdListUnlock (pVMMDevState);
1374 }
1375
1376 return rc;
1377}
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