VirtualBox

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

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

Try to minimize gc to hc ptr conversion abuse.

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