VirtualBox

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

Last change on this file since 5881 was 5524, checked in by vboxsync, 17 years ago

warning

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.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 innotek GmbH
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 as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19
20#include <iprt/alloc.h>
21#include <iprt/asm.h>
22#include <iprt/assert.h>
23#include <iprt/param.h>
24#include <iprt/string.h>
25
26#include <VBox/err.h>
27#include <VBox/hgcmsvc.h>
28
29#define LOG_GROUP LOG_GROUP_DEV_VMM
30#include <VBox/log.h>
31
32#include "VMMDevHGCM.h"
33
34typedef enum _VBOXHGCMCMDTYPE
35{
36 VBOXHGCMCMDTYPE_LOADSTATE,
37 VBOXHGCMCMDTYPE_CONNECT,
38 VBOXHGCMCMDTYPE_DISCONNECT,
39 VBOXHGCMCMDTYPE_CALL,
40 VBOXHGCMCMDTYPE_SizeHack = 0x7fffffff
41} VBOXHGCMCMDTYPE;
42
43/* Information about a linear ptr parameter. */
44typedef struct _VBOXHGCMLINPTR
45{
46 /* Index of the parameter. */
47 int iParm;
48
49 /* Offset in the first physical page of the region. */
50 size_t cbOffsetFirstPage;
51
52 /* How many pages. */
53 uint32_t cPages;
54
55 /* Pointer to array of the GC physical addresses for these pages.
56 * It is assumed that the physical address of the locked resident
57 * guest page does not change.
58 */
59 RTGCPHYS *paPages;
60
61} VBOXHGCMLINPTR;
62
63struct VBOXHGCMCMD
64{
65 /* Active commands, list is protected by critsectHGCMCmdList. */
66 struct VBOXHGCMCMD *pNext;
67 struct VBOXHGCMCMD *pPrev;
68
69 /* The type of the command. */
70 VBOXHGCMCMDTYPE enmCmdType;
71
72 /* GC physical address of the guest request. */
73 RTGCPHYS GCPhys;
74
75 /* Request packet size */
76 uint32_t cbSize;
77
78 /* Pointer to converted host parameters in case of a Call request. */
79 VBOXHGCMSVCPARM *paHostParms;
80
81 /* Linear pointer parameters information. */
82 int cLinPtrs;
83
84 /* Pointer to descriptions of linear pointers. */
85 VBOXHGCMLINPTR *paLinPtrs;
86};
87
88static int vmmdevHGCMCmdListLock (VMMDevState *pVMMDevState)
89{
90 int rc = RTCritSectEnter (&pVMMDevState->critsectHGCMCmdList);
91 AssertRC (rc);
92 return rc;
93}
94
95static void vmmdevHGCMCmdListUnlock (VMMDevState *pVMMDevState)
96{
97 int rc = RTCritSectLeave (&pVMMDevState->critsectHGCMCmdList);
98 AssertRC (rc);
99}
100
101static int vmmdevHGCMAddCommand (VMMDevState *pVMMDevState, PVBOXHGCMCMD pCmd, RTGCPHYS GCPhys, uint32_t cbSize, VBOXHGCMCMDTYPE enmCmdType)
102{
103 /* PPDMDEVINS pDevIns = pVMMDevState->pDevIns; */
104
105 int rc = vmmdevHGCMCmdListLock (pVMMDevState);
106
107 if (VBOX_SUCCESS (rc))
108 {
109 LogFlowFunc(("%p type %d\n", pCmd, enmCmdType));
110
111 /* Insert at the head of the list. The vmmdevHGCMLoadStateDone depends on this. */
112 pCmd->pNext = pVMMDevState->pHGCMCmdList;
113 pCmd->pPrev = NULL;
114
115 if (pVMMDevState->pHGCMCmdList)
116 {
117 pVMMDevState->pHGCMCmdList->pPrev = pCmd;
118 }
119
120 pVMMDevState->pHGCMCmdList = pCmd;
121
122 pCmd->enmCmdType = enmCmdType;
123 pCmd->GCPhys = GCPhys;
124 pCmd->cbSize = cbSize;
125
126 /* Automatically enable HGCM events, if there are HGCM commands. */
127 if ( enmCmdType == VBOXHGCMCMDTYPE_CONNECT
128 || enmCmdType == VBOXHGCMCMDTYPE_DISCONNECT
129 || enmCmdType == VBOXHGCMCMDTYPE_CALL)
130 {
131 Log(("vmmdevHGCMAddCommand: u32HGCMEnabled = %d\n", pVMMDevState->u32HGCMEnabled));
132 if (ASMAtomicCmpXchgU32(&pVMMDevState->u32HGCMEnabled, 1, 0))
133 {
134 VMMDevCtlSetGuestFilterMask (pVMMDevState, VMMDEV_EVENT_HGCM, 0);
135 }
136 }
137
138 vmmdevHGCMCmdListUnlock (pVMMDevState);
139 }
140
141 return rc;
142}
143
144static int vmmdevHGCMRemoveCommand (VMMDevState *pVMMDevState, PVBOXHGCMCMD pCmd)
145{
146 /* PPDMDEVINS pDevIns = pVMMDevState->pDevIns; */
147
148 int rc = vmmdevHGCMCmdListLock (pVMMDevState);
149
150 if (VBOX_SUCCESS (rc))
151 {
152 LogFlowFunc(("%p\n", pCmd));
153
154 if (pCmd->pNext)
155 {
156 pCmd->pNext->pPrev = pCmd->pPrev;
157 }
158 else
159 {
160 /* Tail, do nothing. */
161 }
162
163 if (pCmd->pPrev)
164 {
165 pCmd->pPrev->pNext = pCmd->pNext;
166 }
167 else
168 {
169 pVMMDevState->pHGCMCmdList = pCmd->pNext;
170 }
171
172 vmmdevHGCMCmdListUnlock (pVMMDevState);
173 }
174
175 return rc;
176}
177
178static int vmmdevHGCMSaveLinPtr (PPDMDEVINS pDevIns,
179 uint32_t iParm,
180 RTGCPTR GCPtr,
181 uint32_t u32Size,
182 uint32_t iLinPtr,
183 VBOXHGCMLINPTR *paLinPtrs,
184 RTGCPHYS **ppPages)
185{
186 int rc = VINF_SUCCESS;
187
188 AssertRelease (u32Size > 0);
189
190 VBOXHGCMLINPTR *pLinPtr = &paLinPtrs[iLinPtr];
191
192 /* Take the offset into the current page also into account! */
193 u32Size += GCPtr & PAGE_OFFSET_MASK;
194
195 uint32_t cPages = (u32Size + PAGE_SIZE - 1) / PAGE_SIZE;
196
197 Log(("vmmdevHGCMSaveLinPtr: parm %d: %VGv %d = %d pages\n", iParm, GCPtr, u32Size, cPages));
198
199 pLinPtr->iParm = iParm;
200 pLinPtr->cbOffsetFirstPage = (RTGCUINTPTR)GCPtr & PAGE_OFFSET_MASK;
201 pLinPtr->cPages = cPages;
202 pLinPtr->paPages = *ppPages;
203
204 *ppPages += cPages;
205
206 uint32_t iPage = 0;
207
208 GCPtr &= PAGE_BASE_GC_MASK;
209
210 /* Gonvert the guest linear pointers of pages to HC addresses. */
211 while (iPage < cPages)
212 {
213 /* convert */
214 RTGCPHYS GCPhys;
215
216 rc = PDMDevHlpPhysGCPtr2GCPhys(pDevIns, GCPtr, &GCPhys);
217
218 Log(("vmmdevHGCMSaveLinPtr: Page %d: %VGv -> %VGp. %Vrc\n", iPage, GCPtr, GCPhys, rc));
219
220 if (VBOX_FAILURE (rc))
221 {
222 break;
223 }
224
225 /* store */
226 pLinPtr->paPages[iPage++] = GCPhys;
227
228 /* next */
229 GCPtr += PAGE_SIZE;
230 }
231
232 AssertRelease (iPage == cPages);
233
234 return rc;
235}
236
237static int vmmdevHGCMWriteLinPtr (PPDMDEVINS pDevIns,
238 uint32_t iParm,
239 void *pvHost,
240 uint32_t u32Size,
241 uint32_t iLinPtr,
242 VBOXHGCMLINPTR *paLinPtrs)
243{
244 int rc = VINF_SUCCESS;
245
246 VBOXHGCMLINPTR *pLinPtr = &paLinPtrs[iLinPtr];
247
248 AssertRelease (u32Size > 0 && iParm == (uint32_t)pLinPtr->iParm);
249
250 RTGCPHYS GCPhysDst = pLinPtr->paPages[0] + pLinPtr->cbOffsetFirstPage;
251 uint8_t *pu8Src = (uint8_t *)pvHost;
252
253 Log(("vmmdevHGCMWriteLinPtr: parm %d: size %d, cPages = %d\n", iParm, u32Size, pLinPtr->cPages));
254
255 uint32_t iPage = 0;
256
257 while (iPage < pLinPtr->cPages)
258 {
259 /* copy */
260 size_t cbWrite = iPage == 0?
261 PAGE_SIZE - pLinPtr->cbOffsetFirstPage:
262 PAGE_SIZE;
263
264 Log(("vmmdevHGCMWriteLinPtr: page %d: dst %VGp, src %p, cbWrite %d\n", iPage, GCPhysDst, pu8Src, cbWrite));
265
266 iPage++;
267
268 if (cbWrite >= u32Size)
269 {
270 PDMDevHlpPhysWrite(pDevIns, GCPhysDst, pu8Src, u32Size);
271 u32Size = 0;
272 break;
273 }
274
275 PDMDevHlpPhysWrite(pDevIns, GCPhysDst, pu8Src, cbWrite);
276
277 /* next */
278 u32Size -= cbWrite;
279 pu8Src += cbWrite;
280
281 GCPhysDst = pLinPtr->paPages[iPage];
282 }
283
284 AssertRelease (iPage == pLinPtr->cPages);
285 Assert(u32Size == 0);
286
287 return rc;
288}
289
290int vmmdevHGCMConnect (VMMDevState *pVMMDevState, VMMDevHGCMConnect *pHGCMConnect, RTGCPHYS GCPhys)
291{
292 int rc = VINF_SUCCESS;
293
294 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAllocZ (sizeof (struct VBOXHGCMCMD) + pHGCMConnect->header.header.size);
295
296 if (pCmd)
297 {
298 VMMDevHGCMConnect *pHGCMConnectCopy = (VMMDevHGCMConnect *)(pCmd+1);
299
300 vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMConnect->header.header.size, VBOXHGCMCMDTYPE_CONNECT);
301
302 memcpy(pHGCMConnectCopy, pHGCMConnect, pHGCMConnect->header.header.size);
303
304 pCmd->paHostParms = NULL;
305 pCmd->cLinPtrs = 0;
306 pCmd->paLinPtrs = NULL;
307
308 /* Only allow the guest to use existing services! */
309 Assert(pHGCMConnect->loc.type == VMMDevHGCMLoc_LocalHost_Existing);
310 pHGCMConnect->loc.type = VMMDevHGCMLoc_LocalHost_Existing;
311
312 rc = pVMMDevState->pHGCMDrv->pfnConnect (pVMMDevState->pHGCMDrv, pCmd, &pHGCMConnectCopy->loc, &pHGCMConnectCopy->u32ClientID);
313 }
314 else
315 {
316 rc = VERR_NO_MEMORY;
317 }
318
319 return rc;
320}
321
322int vmmdevHGCMDisconnect (VMMDevState *pVMMDevState, VMMDevHGCMDisconnect *pHGCMDisconnect, RTGCPHYS GCPhys)
323{
324 int rc = VINF_SUCCESS;
325
326 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAllocZ (sizeof (struct VBOXHGCMCMD));
327
328 if (pCmd)
329 {
330 vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMDisconnect->header.header.size, VBOXHGCMCMDTYPE_DISCONNECT);
331
332 pCmd->paHostParms = NULL;
333 pCmd->cLinPtrs = 0;
334 pCmd->paLinPtrs = NULL;
335
336 rc = pVMMDevState->pHGCMDrv->pfnDisconnect (pVMMDevState->pHGCMDrv, pCmd, pHGCMDisconnect->u32ClientID);
337 }
338 else
339 {
340 rc = VERR_NO_MEMORY;
341 }
342
343 return rc;
344}
345
346
347int vmmdevHGCMCall (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, RTGCPHYS GCPhys)
348{
349 int rc = VINF_SUCCESS;
350
351 Log(("vmmdevHGCMCall: client id = %d, function = %d\n", pHGCMCall->u32ClientID, pHGCMCall->u32Function));
352
353 /* Compute size and allocate memory block to hold:
354 * struct VBOXHGCMCMD
355 * VBOXHGCMSVCPARM[cParms]
356 * memory buffers for pointer parameters.
357 */
358
359 uint32_t cParms = pHGCMCall->cParms;
360
361 Log(("vmmdevHGCMCall: cParms = %d\n", cParms));
362
363 /*
364 * Compute size of required memory buffer.
365 */
366
367 uint32_t cbCmdSize = sizeof (struct VBOXHGCMCMD) + cParms * sizeof (VBOXHGCMSVCPARM);
368
369 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
370
371 /* Look for pointer parameters, which require a host buffer. */
372 uint32_t i;
373
374 uint32_t cLinPtrs = 0;
375 uint32_t cLinPtrPages = 0;
376
377 for (i = 0; i < cParms && VBOX_SUCCESS(rc); i++, pGuestParm++)
378 {
379 switch (pGuestParm->type)
380 {
381 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
382 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
383 case VMMDevHGCMParmType_LinAddr: /* In & Out */
384 {
385 cbCmdSize += pGuestParm->u.Pointer.size;
386
387 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
388 {
389 cLinPtrs++;
390 /* Take the offset into the current page also into account! */
391 cLinPtrPages += ((pGuestParm->u.Pointer.u.linearAddr & PAGE_OFFSET_MASK)
392 + pGuestParm->u.Pointer.size + PAGE_SIZE - 1) / PAGE_SIZE;
393 }
394
395 Log(("vmmdevHGCMCall: linptr size = %d\n", pGuestParm->u.Pointer.size));
396 } break;
397
398 case VMMDevHGCMParmType_32bit:
399 case VMMDevHGCMParmType_64bit:
400 case VMMDevHGCMParmType_PhysAddr:
401 {
402 } break;
403
404 default:
405 {
406 AssertMsgFailed(("vmmdevHGCMCall: invalid parameter type %x\n", pGuestParm->type));
407 rc = VERR_INVALID_PARAMETER;
408 break;
409 }
410 }
411 }
412
413 if (VBOX_FAILURE (rc))
414 {
415 return rc;
416 }
417
418 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAlloc (cbCmdSize);
419
420 if (pCmd == NULL)
421 {
422 return VERR_NO_MEMORY;
423 }
424
425 memset (pCmd, 0, sizeof (*pCmd));
426
427 pCmd->paHostParms = NULL;
428 pCmd->cLinPtrs = cLinPtrs;
429
430 if (cLinPtrs > 0)
431 {
432 pCmd->paLinPtrs = (VBOXHGCMLINPTR *)RTMemAlloc ( sizeof (VBOXHGCMLINPTR) * cLinPtrs
433 + sizeof (RTGCPHYS) * cLinPtrPages);
434
435 if (pCmd->paLinPtrs == NULL)
436 {
437 RTMemFree (pCmd);
438 return VERR_NO_MEMORY;
439 }
440 }
441 else
442 {
443 pCmd->paLinPtrs = NULL;
444 }
445
446 /* Process parameters, changing them to host context pointers for easy
447 * processing by connector. Guest must insure that the pointed data is actually
448 * in the guest RAM and remains locked there for entire request processing.
449 */
450
451 if (cParms != 0)
452 {
453 /* Compute addresses of host parms array and first memory buffer. */
454 VBOXHGCMSVCPARM *pHostParm = (VBOXHGCMSVCPARM *)((char *)pCmd + sizeof (struct VBOXHGCMCMD));
455
456 uint8_t *pcBuf = (uint8_t *)pHostParm + cParms * sizeof (VBOXHGCMSVCPARM);
457
458 pCmd->paHostParms = pHostParm;
459
460 pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
461
462 uint32_t iLinPtr = 0;
463 RTGCPHYS *pPages = (RTGCPHYS *)((uint8_t *)pCmd->paLinPtrs + sizeof (VBOXHGCMLINPTR) *cLinPtrs);
464
465 for (i = 0; i < cParms && VBOX_SUCCESS(rc); i++, pGuestParm++, pHostParm++)
466 {
467 switch (pGuestParm->type)
468 {
469 case VMMDevHGCMParmType_32bit:
470 {
471 uint32_t u32 = pGuestParm->u.value32;
472
473 pHostParm->type = VBOX_HGCM_SVC_PARM_32BIT;
474 pHostParm->u.uint32 = u32;
475
476 Log(("vmmdevHGCMCall: uint32 guest parameter %u\n", u32));
477 break;
478 }
479
480 case VMMDevHGCMParmType_64bit:
481 {
482 uint64_t u64 = pGuestParm->u.value64;
483
484 pHostParm->type = VBOX_HGCM_SVC_PARM_64BIT;
485 pHostParm->u.uint64 = u64;
486
487 Log(("vmmdevHGCMCall: uint64 guest parameter %llu\n", u64));
488 break;
489 }
490
491 case VMMDevHGCMParmType_PhysAddr:
492 {
493 uint32_t size = pGuestParm->u.Pointer.size;
494#ifdef LOG_ENABLED
495 RTGCPHYS physAddr = pGuestParm->u.Pointer.u.physAddr;
496#endif
497
498 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
499 pHostParm->u.pointer.size = size;
500
501 AssertFailed();
502 /* rc = PDMDevHlpPhys2HCVirt (pVMMDevState->pDevIns, physAddr, size, &pHostParm->u.pointer.addr); */
503
504 Log(("vmmdevHGCMCall: PhysAddr guest parameter %VGp\n", physAddr));
505 break;
506 }
507
508 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
509 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
510 case VMMDevHGCMParmType_LinAddr: /* In & Out */
511 {
512 uint32_t size = pGuestParm->u.Pointer.size;
513 RTGCPTR linearAddr = pGuestParm->u.Pointer.u.linearAddr;
514
515 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
516 pHostParm->u.pointer.size = size;
517
518 /* Copy guest data to an allocated buffer, so
519 * services can use the data.
520 */
521
522 if (size == 0)
523 {
524 pHostParm->u.pointer.addr = (void *) 0xfeeddead;
525 }
526 else
527 {
528 /* Don't overdo it */
529 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_Out)
530 rc = PDMDevHlpPhysReadGCVirt(pVMMDevState->pDevIns, pcBuf, linearAddr, size);
531 else
532 rc = VINF_SUCCESS;
533
534 if (VBOX_SUCCESS(rc))
535 {
536 pHostParm->u.pointer.addr = pcBuf;
537 pcBuf += size;
538
539 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
540 {
541 /* Remember the guest physical pages that belong to the virtual address
542 * region.
543 */
544 rc = vmmdevHGCMSaveLinPtr (pVMMDevState->pDevIns, i, linearAddr, size, iLinPtr++, pCmd->paLinPtrs, &pPages);
545 }
546 }
547 }
548
549 Log(("vmmdevHGCMCall: LinAddr guest parameter %VGv, rc = %Vrc\n", linearAddr, rc));
550 break;
551 }
552
553 /* just to shut up gcc */
554 default:
555 break;
556 }
557 }
558 }
559
560 if (VBOX_SUCCESS (rc))
561 {
562 vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMCall->header.header.size, VBOXHGCMCMDTYPE_CALL);
563
564 /* Pass the function call to HGCM connector for actual processing */
565 rc = pVMMDevState->pHGCMDrv->pfnCall (pVMMDevState->pHGCMDrv, pCmd, pHGCMCall->u32ClientID, pHGCMCall->u32Function, cParms, pCmd->paHostParms);
566 }
567 else
568 {
569 if (pCmd->paLinPtrs)
570 {
571 RTMemFree (pCmd->paLinPtrs);
572 }
573
574 RTMemFree (pCmd);
575 }
576
577 return rc;
578}
579
580static int vmmdevHGCMCmdVerify (PVBOXHGCMCMD pCmd, VMMDevHGCMRequestHeader *pHeader)
581{
582 switch (pCmd->enmCmdType)
583 {
584 case VBOXHGCMCMDTYPE_CONNECT:
585 if (pHeader->header.requestType == VMMDevReq_HGCMConnect) return VINF_SUCCESS;
586 break;
587
588 case VBOXHGCMCMDTYPE_DISCONNECT:
589 if (pHeader->header.requestType == VMMDevReq_HGCMDisconnect) return VINF_SUCCESS;
590 break;
591
592 case VBOXHGCMCMDTYPE_CALL:
593 if (pHeader->header.requestType == VMMDevReq_HGCMCall) return VINF_SUCCESS;
594 break;
595
596 default:
597 AssertFailed ();
598 }
599
600 LogRel(("VMMDEV: Invalid HGCM command: pCmd->enmCmdType = 0x%08X, pHeader->header.requestType = 0x%08X\n",
601 pCmd->enmCmdType, pHeader->header.requestType));
602 return VERR_INVALID_PARAMETER;
603}
604
605#define PDMIHGCMPORT_2_VMMDEVSTATE(pInterface) ( (VMMDevState *) ((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, HGCMPort)) )
606
607DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result, PVBOXHGCMCMD pCmd)
608{
609 VMMDevState *pVMMDevState = PDMIHGCMPORT_2_VMMDEVSTATE(pInterface);
610 VMMDevHGCMRequestHeader *pHeader;
611 int rc = VINF_SUCCESS;
612
613 pHeader = (VMMDevHGCMRequestHeader *)RTMemAllocZ (pCmd->cbSize);
614 Assert(pHeader);
615 if (pHeader == NULL)
616 return;
617
618 PDMDevHlpPhysRead(pVMMDevState->pDevIns, (RTGCPHYS)pCmd->GCPhys, pHeader, pCmd->cbSize);
619
620 if (result != VINF_HGCM_SAVE_STATE)
621 {
622 /* Setup return codes. */
623 pHeader->result = result;
624
625 /* Verify the request type. */
626 rc = vmmdevHGCMCmdVerify (pCmd, pHeader);
627
628 if (VBOX_SUCCESS (rc))
629 {
630 /* Update parameters and data buffers. */
631
632 switch (pHeader->header.requestType)
633 {
634 case VMMDevReq_HGCMCall:
635 {
636 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pHeader;
637
638 uint32_t cParms = pHGCMCall->cParms;
639
640 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
641
642 VBOXHGCMSVCPARM *pHostParm = pCmd->paHostParms;
643
644 uint32_t i;
645 uint32_t iLinPtr = 0;
646
647 for (i = 0; i < cParms; i++, pGuestParm++, pHostParm++)
648 {
649 switch (pGuestParm->type)
650 {
651 case VMMDevHGCMParmType_32bit:
652 {
653 pGuestParm->u.value32 = pHostParm->u.uint32;
654 } break;
655
656 case VMMDevHGCMParmType_64bit:
657 {
658 pGuestParm->u.value64 = pHostParm->u.uint64;
659 } break;
660
661 case VMMDevHGCMParmType_PhysAddr:
662 {
663 /* do nothing */
664 } break;
665
666 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
667 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
668 case VMMDevHGCMParmType_LinAddr: /* In & Out */
669 {
670 /* Copy buffer back to guest memory. */
671 uint32_t size = pGuestParm->u.Pointer.size;
672
673 if (size > 0 && pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
674 {
675 /* Use the saved page list. */
676 rc = vmmdevHGCMWriteLinPtr (pVMMDevState->pDevIns, i, pHostParm->u.pointer.addr, size, iLinPtr++, pCmd->paLinPtrs);
677 AssertReleaseRC(rc);
678 }
679 } break;
680
681 default:
682 {
683 /* This indicates that the guest request memory was corrupted. */
684 AssertReleaseMsgFailed(("hgcmCompleted: invalid parameter type %08X\n", pGuestParm->type));
685 }
686 }
687 }
688 break;
689 }
690
691 case VMMDevReq_HGCMConnect:
692 {
693 VMMDevHGCMConnect *pHGCMConnectCopy = (VMMDevHGCMConnect *)(pCmd+1);
694
695 /* save the client id in the guest request packet */
696 VMMDevHGCMConnect *pHGCMConnect = (VMMDevHGCMConnect *)pHeader;
697 pHGCMConnect->u32ClientID = pHGCMConnectCopy->u32ClientID;
698 break;
699 }
700
701 default:
702 /* make gcc happy */
703 break;
704 }
705 }
706 else
707 {
708 /* Return error to the guest. */
709 pHeader->header.rc = rc;
710 }
711
712 /* Mark request as processed*/
713 pHeader->fu32Flags |= VBOX_HGCM_REQ_DONE;
714
715 /* Write back the request */
716 PDMDevHlpPhysWrite(pVMMDevState->pDevIns, pCmd->GCPhys, pHeader, pCmd->cbSize);
717
718 VMMDevNotifyGuest (pVMMDevState, VMMDEV_EVENT_HGCM);
719
720 /* It it assumed that VMMDev saves state after the HGCM services. */
721 vmmdevHGCMRemoveCommand (pVMMDevState, pCmd);
722
723 if (pCmd->paLinPtrs)
724 {
725 RTMemFree (pCmd->paLinPtrs);
726 }
727
728 RTMemFree (pCmd);
729 }
730 RTMemFree(pHeader);
731
732 return;
733}
734
735DECLCALLBACK(void) hgcmCompleted (PPDMIHGCMPORT pInterface, int32_t result, PVBOXHGCMCMD pCmd)
736{
737 VMMDevState *pVMMDevState = PDMIHGCMPORT_2_VMMDEVSTATE(pInterface);
738
739 /* Not safe to execute asynchroneously; forward to EMT */
740 int rc = VMR3ReqCallEx(PDMDevHlpGetVM(pVMMDevState->pDevIns), NULL, 0, VMREQFLAGS_NO_WAIT | VMREQFLAGS_VOID,
741 (PFNRT)hgcmCompletedWorker, 3, pInterface, result, pCmd);
742 AssertRC(rc);
743}
744
745/* @thread EMT */
746int vmmdevHGCMSaveState(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
747{
748 /* Save information about pending requests.
749 * Only GCPtrs are of interest.
750 */
751 int rc = VINF_SUCCESS;
752
753 LogFlowFunc(("\n"));
754
755 /* Compute how many commands are pending. */
756 uint32_t cCmds = 0;
757
758 PVBOXHGCMCMD pIter = pVMMDevState->pHGCMCmdList;
759
760 while (pIter)
761 {
762 LogFlowFunc (("pIter %p\n", pIter));
763 cCmds++;
764 pIter = pIter->pNext;
765 }
766
767 LogFlowFunc(("cCmds = %d\n", cCmds));
768
769 /* Save number of commands. */
770 rc = SSMR3PutU32(pSSM, cCmds);
771 AssertRCReturn(rc, rc);
772
773 if (cCmds > 0)
774 {
775 pIter = pVMMDevState->pHGCMCmdList;
776
777 while (pIter)
778 {
779 PVBOXHGCMCMD pNext = pIter->pNext;
780
781 LogFlowFunc (("Saving %VGp\n", pIter->GCPhys));
782 rc = SSMR3PutGCPhys(pSSM, pIter->GCPhys);
783 AssertRCReturn(rc, rc);
784
785 rc = SSMR3PutU32(pSSM, pIter->cbSize);
786 AssertRCReturn(rc, rc);
787
788 vmmdevHGCMRemoveCommand (pVMMDevState, pIter);
789
790 pIter = pNext;
791 }
792 }
793
794 return rc;
795}
796
797/* @thread EMT */
798int vmmdevHGCMLoadState(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
799{
800 int rc = VINF_SUCCESS;
801
802 LogFlowFunc(("\n"));
803
804 /* Read how many commands were pending. */
805 uint32_t cCmds = 0;
806 rc = SSMR3GetU32(pSSM, &cCmds);
807 AssertRCReturn(rc, rc);
808
809 LogFlowFunc(("cCmds = %d\n", cCmds));
810
811 while (cCmds--)
812 {
813 RTGCPHYS GCPhys;
814 uint32_t cbSize;
815
816 rc = SSMR3GetGCPhys(pSSM, &GCPhys);
817 AssertRCReturn(rc, rc);
818
819 rc = SSMR3GetU32(pSSM, &cbSize);
820 AssertRCReturn(rc, rc);
821
822 LogFlowFunc (("Restoring %VGp size %x bytes\n", GCPhys, cbSize));
823
824 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAllocZ (sizeof (struct VBOXHGCMCMD));
825 AssertReturn(pCmd, VERR_NO_MEMORY);
826
827 vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, cbSize, VBOXHGCMCMDTYPE_LOADSTATE);
828 }
829
830 return rc;
831}
832
833/* @thread EMT */
834int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
835{
836 LogFlowFunc(("\n"));
837
838 /* Reissue pending requests. */
839 PPDMDEVINS pDevIns = pVMMDevState->pDevIns;
840
841 int rc = vmmdevHGCMCmdListLock (pVMMDevState);
842
843 if (VBOX_SUCCESS (rc))
844 {
845 PVBOXHGCMCMD pIter = pVMMDevState->pHGCMCmdList;
846
847 while (pIter)
848 {
849 LogFlowFunc (("pIter %p\n", pIter));
850
851 PVBOXHGCMCMD pNext = pIter->pNext;
852
853 VMMDevRequestHeader *requestHeader = (VMMDevRequestHeader *)RTMemAllocZ (pIter->cbSize);
854 Assert(requestHeader);
855 if (requestHeader == NULL)
856 return VERR_NO_MEMORY;
857
858 PDMDevHlpPhysRead(pDevIns, (RTGCPHYS)pIter->GCPhys, requestHeader, pIter->cbSize);
859
860 /* the structure size must be greater or equal to the header size */
861 if (requestHeader->size < sizeof(VMMDevRequestHeader))
862 {
863 Log(("VMMDev request header size too small! size = %d\n", requestHeader->size));
864 }
865 else
866 {
867 /* check the version of the header structure */
868 if (requestHeader->version != VMMDEV_REQUEST_HEADER_VERSION)
869 {
870 Log(("VMMDev: guest header version (0x%08X) differs from ours (0x%08X)\n", requestHeader->version, VMMDEV_REQUEST_HEADER_VERSION));
871 }
872 else
873 {
874 Log(("VMMDev request issued: %d\n", requestHeader->requestType));
875
876 switch (requestHeader->requestType)
877 {
878 case VMMDevReq_HGCMConnect:
879 {
880 if (requestHeader->size < sizeof(VMMDevHGCMConnect))
881 {
882 AssertMsgFailed(("VMMDevReq_HGCMConnect structure has invalid size!\n"));
883 requestHeader->rc = VERR_INVALID_PARAMETER;
884 }
885 else if (!pVMMDevState->pHGCMDrv)
886 {
887 Log(("VMMDevReq_HGCMConnect HGCM Connector is NULL!\n"));
888 requestHeader->rc = VERR_NOT_SUPPORTED;
889 }
890 else
891 {
892 VMMDevHGCMConnect *pHGCMConnect = (VMMDevHGCMConnect *)requestHeader;
893
894 Log(("VMMDevReq_HGCMConnect\n"));
895
896 requestHeader->rc = vmmdevHGCMConnect (pVMMDevState, pHGCMConnect, pIter->GCPhys);
897 }
898 break;
899 }
900
901 case VMMDevReq_HGCMDisconnect:
902 {
903 if (requestHeader->size < sizeof(VMMDevHGCMDisconnect))
904 {
905 AssertMsgFailed(("VMMDevReq_HGCMDisconnect structure has invalid size!\n"));
906 requestHeader->rc = VERR_INVALID_PARAMETER;
907 }
908 else if (!pVMMDevState->pHGCMDrv)
909 {
910 Log(("VMMDevReq_HGCMDisconnect HGCM Connector is NULL!\n"));
911 requestHeader->rc = VERR_NOT_SUPPORTED;
912 }
913 else
914 {
915 VMMDevHGCMDisconnect *pHGCMDisconnect = (VMMDevHGCMDisconnect *)requestHeader;
916
917 Log(("VMMDevReq_VMMDevHGCMDisconnect\n"));
918 requestHeader->rc = vmmdevHGCMDisconnect (pVMMDevState, pHGCMDisconnect, pIter->GCPhys);
919 }
920 break;
921 }
922
923 case VMMDevReq_HGCMCall:
924 {
925 if (requestHeader->size < sizeof(VMMDevHGCMCall))
926 {
927 AssertMsgFailed(("VMMDevReq_HGCMCall structure has invalid size!\n"));
928 requestHeader->rc = VERR_INVALID_PARAMETER;
929 }
930 else if (!pVMMDevState->pHGCMDrv)
931 {
932 Log(("VMMDevReq_HGCMCall HGCM Connector is NULL!\n"));
933 requestHeader->rc = VERR_NOT_SUPPORTED;
934 }
935 else
936 {
937 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)requestHeader;
938
939 Log(("VMMDevReq_HGCMCall: sizeof (VMMDevHGCMRequest) = %04X\n", sizeof (VMMDevHGCMCall)));
940
941 Log(("%.*Vhxd\n", requestHeader->size, requestHeader));
942
943 requestHeader->rc = vmmdevHGCMCall (pVMMDevState, pHGCMCall, pIter->GCPhys);
944 }
945 break;
946 }
947 default:
948 AssertReleaseFailed();
949 }
950 }
951 }
952
953 /* Write back the request */
954 PDMDevHlpPhysWrite(pDevIns, pIter->GCPhys, requestHeader, pIter->cbSize);
955 RTMemFree(requestHeader);
956
957 vmmdevHGCMRemoveCommand (pVMMDevState, pIter);
958 RTMemFree(pIter);
959 pIter = pNext;
960 }
961
962 vmmdevHGCMCmdListUnlock (pVMMDevState);
963 }
964
965 return rc;
966}
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