VirtualBox

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

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

gcc warning

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