VirtualBox

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

Last change on this file since 2272 was 2027, checked in by vboxsync, 18 years ago

Check types of HGCM commands.

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