VirtualBox

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

Last change on this file since 4032 was 3385, checked in by vboxsync, 18 years ago

Logging.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette