VirtualBox

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

Last change on this file since 10390 was 9662, checked in by vboxsync, 17 years ago

Implemented cancelling of HGCM requests from the guest.

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