VirtualBox

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

Last change on this file since 1959 was 1687, checked in by vboxsync, 18 years ago

warnings

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