VirtualBox

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

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

More logging

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.9 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
476 case VMMDevHGCMParmType_64bit:
477 {
478 uint64_t u64 = pGuestParm->u.value64;
479
480 pHostParm->type = VBOX_HGCM_SVC_PARM_64BIT;
481 pHostParm->u.uint64 = u64;
482
483 Log(("vmmdevHGCMCall: uint64 guest parameter %llu\n", u64));
484 break;
485 }
486
487 case VMMDevHGCMParmType_PhysAddr:
488 {
489 uint32_t size = pGuestParm->u.Pointer.size;
490 RTGCPHYS physAddr = pGuestParm->u.Pointer.u.physAddr;
491
492 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
493 pHostParm->u.pointer.size = size;
494
495 AssertFailed();
496 /** @todo It's no longer allowed to save a conversion address for later use! */
497 rc = PDMDevHlpPhys2HCVirt (pVMMDevState->pDevIns, physAddr, size, &pHostParm->u.pointer.addr);
498
499 Log(("vmmdevHGCMCall: PhysAddr guest parameter %VGp\n", physAddr));
500 break;
501 }
502
503 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
504 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
505 case VMMDevHGCMParmType_LinAddr: /* In & Out */
506 {
507 uint32_t size = pGuestParm->u.Pointer.size;
508 RTGCPTR linearAddr = pGuestParm->u.Pointer.u.linearAddr;
509
510 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
511 pHostParm->u.pointer.size = size;
512
513 /* Copy guest data to an allocated buffer, so
514 * services can use the data.
515 */
516
517 if (size == 0)
518 {
519 pHostParm->u.pointer.addr = (void *) 0xfeeddead;
520 }
521 else
522 {
523 /* Don't overdo it */
524 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_Out)
525 rc = PDMDevHlpPhysReadGCVirt(pVMMDevState->pDevIns, pcBuf, linearAddr, size);
526 else
527 rc = VINF_SUCCESS;
528
529 if (VBOX_SUCCESS(rc))
530 {
531 pHostParm->u.pointer.addr = pcBuf;
532 pcBuf += size;
533
534 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
535 {
536 /* Remember the guest physical pages that belong to the virtual address
537 * region.
538 */
539 rc = vmmdevHGCMSaveLinPtr (pVMMDevState->pDevIns, i, linearAddr, size, iLinPtr++, pCmd->paLinPtrs, &pPages);
540 }
541 }
542 }
543
544 Log(("vmmdevHGCMCall: LinAddr guest parameter %VGv, rc = %Vrc\n", linearAddr, rc));
545 break;
546 }
547
548 /* just to shut up gcc */
549 default:
550 break;
551 }
552 }
553 }
554
555 if (VBOX_SUCCESS (rc))
556 {
557 vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPtr, VBOXHGCMCMDTYPE_CALL);
558
559 /* Pass the function call to HGCM connector for actual processing */
560 rc = pVMMDevState->pHGCMDrv->pfnCall (pVMMDevState->pHGCMDrv, pCmd, pHGCMCall->u32ClientID, pHGCMCall->u32Function, cParms, pCmd->paHostParms);
561 }
562 else
563 {
564 if (pCmd->paLinPtrs)
565 {
566 RTMemFree (pCmd->paLinPtrs);
567 }
568
569 RTMemFree (pCmd);
570 }
571
572 return rc;
573}
574
575static int vmmdevHGCMCmdVerify (PVBOXHGCMCMD pCmd)
576{
577 VMMDevHGCMRequestHeader *pHeader = pCmd->pHeader;
578
579 switch (pCmd->enmCmdType)
580 {
581 case VBOXHGCMCMDTYPE_CONNECT:
582 if (pHeader->header.requestType == VMMDevReq_HGCMConnect) return VINF_SUCCESS;
583 break;
584
585 case VBOXHGCMCMDTYPE_DISCONNECT:
586 if (pHeader->header.requestType == VMMDevReq_HGCMDisconnect) return VINF_SUCCESS;
587 break;
588
589 case VBOXHGCMCMDTYPE_CALL:
590 if (pHeader->header.requestType == VMMDevReq_HGCMCall) return VINF_SUCCESS;
591 break;
592
593 default:
594 AssertFailed ();
595 }
596
597 LogRel(("VMMDEV: Invalid HGCM command: pCmd->enmCmdType = 0x%08X, pHeader->header.requestType = 0x%08X\n",
598 pCmd->enmCmdType, pHeader->header.requestType));
599 return VERR_INVALID_PARAMETER;
600}
601
602#define PDMIHGCMPORT_2_VMMDEVSTATE(pInterface) ( (VMMDevState *) ((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, HGCMPort)) )
603
604DECLCALLBACK(void) hgcmCompleted (PPDMIHGCMPORT pInterface, int32_t result, PVBOXHGCMCMD pCmd)
605{
606 int rc = VINF_SUCCESS;
607
608 VMMDevHGCMRequestHeader *pHeader = pCmd->pHeader;
609
610 VMMDevState *pVMMDevState = PDMIHGCMPORT_2_VMMDEVSTATE(pInterface);
611
612 if (result != VINF_HGCM_SAVE_STATE)
613 {
614 /* Setup return codes. */
615 pHeader->result = result;
616
617 /* Verify the request type. */
618 rc = vmmdevHGCMCmdVerify (pCmd);
619
620 if (VBOX_SUCCESS (rc))
621 {
622 /* Update parameters and data buffers. */
623
624 if (pHeader->header.requestType == VMMDevReq_HGCMCall)
625 {
626 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pHeader;
627
628 uint32_t cParms = pHGCMCall->cParms;
629
630 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
631
632 VBOXHGCMSVCPARM *pHostParm = pCmd->paHostParms;
633
634 uint32_t i;
635 uint32_t iLinPtr = 0;
636
637 for (i = 0; i < cParms; i++, pGuestParm++, pHostParm++)
638 {
639 switch (pGuestParm->type)
640 {
641 case VMMDevHGCMParmType_32bit:
642 {
643 pGuestParm->u.value32 = pHostParm->u.uint32;
644 } break;
645
646 case VMMDevHGCMParmType_64bit:
647 {
648 pGuestParm->u.value64 = pHostParm->u.uint64;
649 } break;
650
651 case VMMDevHGCMParmType_PhysAddr:
652 {
653 /* do nothing */
654 } break;
655
656 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
657 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
658 case VMMDevHGCMParmType_LinAddr: /* In & Out */
659 {
660 /* Copy buffer back to guest memory. */
661 uint32_t size = pGuestParm->u.Pointer.size;
662
663 if (size > 0 && pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
664 {
665 /* Use the saved page list. */
666 rc = vmmdevHGCMWriteLinPtr (pVMMDevState->pDevIns, i, pHostParm->u.pointer.addr, size, iLinPtr++, pCmd->paLinPtrs);
667 AssertReleaseRC(rc);
668 }
669 } break;
670
671 default:
672 {
673 /* This indicates that the guest request memory was corrupted. */
674 AssertReleaseMsgFailed(("hgcmCompleted: invalid parameter type %08X\n", pGuestParm->type));
675 }
676 }
677 }
678 }
679 }
680 else
681 {
682 /* Return error to the guest. */
683 pHeader->header.rc = rc;
684 }
685
686 /* Mark request as processed*/
687 pHeader->fu32Flags |= VBOX_HGCM_REQ_DONE;
688
689 VMMDevNotifyGuest (pVMMDevState, VMMDEV_EVENT_HGCM);
690
691 /* It it assumed that VMMDev saves state after the HGCM services. */
692 vmmdevHGCMRemoveCommand (pVMMDevState, pCmd);
693
694 if (pCmd->paLinPtrs)
695 {
696 RTMemFree (pCmd->paLinPtrs);
697 }
698
699 RTMemFree (pCmd);
700 }
701
702 return;
703}
704
705/* @thread EMT */
706int vmmdevHGCMSaveState(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
707{
708 /* Save information about pending requests.
709 * Only GCPtrs are of interest.
710 */
711 int rc = VINF_SUCCESS;
712
713 LogFlowFunc(("\n"));
714
715 /* Compute how many commands are pending. */
716 uint32_t cCmds = 0;
717
718 PVBOXHGCMCMD pIter = pVMMDevState->pHGCMCmdList;
719
720 while (pIter)
721 {
722 LogFlowFunc (("pIter %p\n", pIter));
723 cCmds++;
724 pIter = pIter->pNext;
725 }
726
727 LogFlowFunc(("cCmds = %d\n", cCmds));
728
729 /* Save number of commands. */
730 rc = SSMR3PutU32(pSSM, cCmds);
731 AssertRCReturn(rc, rc);
732
733 if (cCmds > 0)
734 {
735 pIter = pVMMDevState->pHGCMCmdList;
736
737 while (pIter)
738 {
739 PVBOXHGCMCMD pNext = pIter->pNext;
740
741 LogFlowFunc (("Saving %VGp\n", pIter->GCPtr));
742 rc = SSMR3PutGCPtr(pSSM, pIter->GCPtr);
743 AssertRCReturn(rc, rc);
744
745 vmmdevHGCMRemoveCommand (pVMMDevState, pIter);
746
747 pIter = pNext;
748 }
749 }
750
751 return rc;
752}
753
754/* @thread EMT */
755int vmmdevHGCMLoadState(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
756{
757 int rc = VINF_SUCCESS;
758
759 LogFlowFunc(("\n"));
760
761 /* Read how many commands were pending. */
762 uint32_t cCmds = 0;
763 rc = SSMR3GetU32(pSSM, &cCmds);
764 AssertRCReturn(rc, rc);
765
766 LogFlowFunc(("cCmds = %d\n", cCmds));
767
768 while (cCmds--)
769 {
770 RTGCPHYS GCPtr;
771 rc = SSMR3GetGCPtr(pSSM, &GCPtr);
772 AssertRCReturn(rc, rc);
773
774 LogFlowFunc (("Restoring %VGp\n", GCPtr));
775
776 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAllocZ (sizeof (struct VBOXHGCMCMD));
777 AssertReturn(pCmd, VERR_NO_MEMORY);
778
779 vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPtr, VBOXHGCMCMDTYPE_LOADSTATE);
780 }
781
782 return rc;
783}
784
785/* @thread EMT */
786int vmmdevHGCMLoadStateDone(VMMDevState *pVMMDevState, PSSMHANDLE pSSM)
787{
788 LogFlowFunc(("\n"));
789
790 /* Reissue pending requests. */
791 PPDMDEVINS pDevIns = pVMMDevState->pDevIns;
792
793 int rc = vmmdevHGCMCmdListLock (pVMMDevState);
794
795 if (VBOX_SUCCESS (rc))
796 {
797 PVBOXHGCMCMD pIter = pVMMDevState->pHGCMCmdList;
798
799 while (pIter)
800 {
801 LogFlowFunc (("pIter %p\n", pIter));
802
803 PVBOXHGCMCMD pNext = pIter->pNext;
804
805 VMMDevRequestHeader *requestHeader = NULL;
806 rc = PDMDevHlpPhys2HCVirt(pDevIns, pIter->GCPtr, 0, (PRTHCPTR)&requestHeader);
807
808 if (VBOX_FAILURE(rc) || !requestHeader)
809 {
810 AssertMsgFailed(("VMMDev::LoadStateDone: could not convert guest physical address to host virtual!!! rc = %Vrc\n", rc));
811 }
812 else
813 {
814 /* the structure size must be greater or equal to the header size */
815 if (requestHeader->size < sizeof(VMMDevRequestHeader))
816 {
817 Log(("VMMDev request header size too small! size = %d\n", requestHeader->size));
818 }
819 else
820 {
821 /* check the version of the header structure */
822 if (requestHeader->version != VMMDEV_REQUEST_HEADER_VERSION)
823 {
824 Log(("VMMDev: guest header version (0x%08X) differs from ours (0x%08X)\n", requestHeader->version, VMMDEV_REQUEST_HEADER_VERSION));
825 }
826 else
827 {
828 Log(("VMMDev request issued: %d\n", requestHeader->requestType));
829
830 switch (requestHeader->requestType)
831 {
832 case VMMDevReq_HGCMConnect:
833 {
834 if (requestHeader->size < sizeof(VMMDevHGCMConnect))
835 {
836 AssertMsgFailed(("VMMDevReq_HGCMConnect structure has invalid size!\n"));
837 requestHeader->rc = VERR_INVALID_PARAMETER;
838 }
839 else if (!pVMMDevState->pHGCMDrv)
840 {
841 Log(("VMMDevReq_HGCMConnect HGCM Connector is NULL!\n"));
842 requestHeader->rc = VERR_NOT_SUPPORTED;
843 }
844 else
845 {
846 VMMDevHGCMConnect *pHGCMConnect = (VMMDevHGCMConnect *)requestHeader;
847
848 Log(("VMMDevReq_HGCMConnect\n"));
849
850 requestHeader->rc = vmmdevHGCMConnect (pVMMDevState, pHGCMConnect, pIter->GCPtr);
851 }
852 break;
853 }
854
855 case VMMDevReq_HGCMDisconnect:
856 {
857 if (requestHeader->size < sizeof(VMMDevHGCMDisconnect))
858 {
859 AssertMsgFailed(("VMMDevReq_HGCMDisconnect structure has invalid size!\n"));
860 requestHeader->rc = VERR_INVALID_PARAMETER;
861 }
862 else if (!pVMMDevState->pHGCMDrv)
863 {
864 Log(("VMMDevReq_HGCMDisconnect HGCM Connector is NULL!\n"));
865 requestHeader->rc = VERR_NOT_SUPPORTED;
866 }
867 else
868 {
869 VMMDevHGCMDisconnect *pHGCMDisconnect = (VMMDevHGCMDisconnect *)requestHeader;
870
871 Log(("VMMDevReq_VMMDevHGCMDisconnect\n"));
872 requestHeader->rc = vmmdevHGCMDisconnect (pVMMDevState, pHGCMDisconnect, pIter->GCPtr);
873 }
874 break;
875 }
876
877 case VMMDevReq_HGCMCall:
878 {
879 if (requestHeader->size < sizeof(VMMDevHGCMCall))
880 {
881 AssertMsgFailed(("VMMDevReq_HGCMCall structure has invalid size!\n"));
882 requestHeader->rc = VERR_INVALID_PARAMETER;
883 }
884 else if (!pVMMDevState->pHGCMDrv)
885 {
886 Log(("VMMDevReq_HGCMCall HGCM Connector is NULL!\n"));
887 requestHeader->rc = VERR_NOT_SUPPORTED;
888 }
889 else
890 {
891 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)requestHeader;
892
893 Log(("VMMDevReq_HGCMCall: sizeof (VMMDevHGCMRequest) = %04X\n", sizeof (VMMDevHGCMCall)));
894
895 Log(("%.*Vhxd\n", requestHeader->size, requestHeader));
896
897 requestHeader->rc = vmmdevHGCMCall (pVMMDevState, pHGCMCall, pIter->GCPtr);
898 }
899 break;
900 }
901 default:
902 AssertReleaseFailed();
903 }
904 }
905 }
906 }
907
908 vmmdevHGCMRemoveCommand (pVMMDevState, pIter);
909 pIter = pNext;
910 }
911
912 vmmdevHGCMCmdListUnlock (pVMMDevState);
913 }
914
915 return rc;
916}
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