VirtualBox

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

Last change on this file since 61 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.0 KB
Line 
1/** @file
2 *
3 * VBox Guest/VMM/host communication:
4 * HGCM - Host-Guest Communication Manager device
5 */
6
7/*
8 * Copyright (C) 2006 InnoTek Systemberatung GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
21 */
22
23
24#include <iprt/alloc.h>
25#include <iprt/assert.h>
26#include <iprt/param.h>
27#include <iprt/string.h>
28
29#include <VBox/err.h>
30#include <VBox/hgcmsvc.h>
31
32#define LOG_GROUP LOG_GROUP_DEV_VMM
33#include <VBox/log.h>
34
35#include "VMMDevHGCM.h"
36
37/* Information about a linear ptr parameter. */
38typedef struct _VBOXHGCMLINPTR
39{
40 /* Index of the parameter. */
41 int iParm;
42
43 /* Offset in the first physical page of the region. */
44 size_t cbOffsetFirstPage;
45
46 /* How many pages. */
47 uint32_t cPages;
48
49 /* Pointer to array of the HC addresses for these pages.
50 * It is assumed that the HC address of the locked resident
51 * guest physical page does not change.
52 */
53 RTHCPTR *paPages;
54
55} VBOXHGCMLINPTR;
56
57struct VBOXHGCMCMD
58{
59 /* Pointer to guest request. */
60 VMMDevHGCMRequestHeader *pHeader;
61
62 /* Pointer to converted host parameters in case of a Call request. */
63 VBOXHGCMSVCPARM *paHostParms;
64
65 /* Linear pointer parameters information. */
66 int cLinPtrs;
67
68 /* Pointer to descriptions of linear pointers. */
69 VBOXHGCMLINPTR *paLinPtrs;
70};
71
72static int vmmdevHGCMSaveLinPtr (PPDMDEVINS pDevIns,
73 uint32_t iParm,
74 RTGCPTR GCPtr,
75 uint32_t u32Size,
76 uint32_t iLinPtr,
77 VBOXHGCMLINPTR *paLinPtrs,
78 RTHCPTR **ppPages)
79{
80 int rc = VINF_SUCCESS;
81
82 AssertRelease (u32Size > 0);
83
84 VBOXHGCMLINPTR *pLinPtr = &paLinPtrs[iLinPtr];
85
86 uint32_t cPages = (u32Size + PAGE_SIZE - 1) / PAGE_SIZE;
87
88 Log(("vmmdevHGCMSaveLinPtr: parm %d: %VGv %d = %d pages\n", iParm, GCPtr, u32Size, cPages));
89
90 pLinPtr->iParm = iParm;
91 pLinPtr->cbOffsetFirstPage = (RTGCUINTPTR)GCPtr & PAGE_OFFSET_MASK;
92 pLinPtr->cPages = cPages;
93 pLinPtr->paPages = *ppPages;
94
95 *ppPages += cPages;
96
97 uint32_t iPage = 0;
98
99 GCPtr &= PAGE_BASE_GC_MASK;
100
101 /* Gonvert the guest linear pointers of pages to HC addresses. */
102 while (iPage < cPages)
103 {
104 /* convert */
105 RTHCPTR HCPtr;
106
107 rc = pDevIns->pDevHlp->pfnPhysGCPtr2HCPtr (pDevIns, GCPtr, &HCPtr);
108// rc = PGMPhysGCPtr2HCPtr (pVM, GCPtr, &HCPtr);
109
110 Log(("vmmdevHGCMSaveLinPtr: Page %d: %VGv -> %p. %Vrc\n", iPage, GCPtr, HCPtr, rc));
111
112 if (VBOX_FAILURE (rc))
113 {
114 break;
115 }
116
117 /* store */
118 pLinPtr->paPages[iPage++] = HCPtr;
119
120 /* next */
121 GCPtr += PAGE_SIZE;
122 }
123
124 AssertRelease (iPage == cPages);
125
126 return rc;
127}
128
129static int vmmdevHGCMWriteLinPtr (PPDMDEVINS pDevIns,
130 uint32_t iParm,
131 void *pvHost,
132 uint32_t u32Size,
133 uint32_t iLinPtr,
134 VBOXHGCMLINPTR *paLinPtrs)
135{
136 int rc = VINF_SUCCESS;
137
138 VBOXHGCMLINPTR *pLinPtr = &paLinPtrs[iLinPtr];
139
140 AssertRelease (u32Size > 0 && iParm == (uint32_t)pLinPtr->iParm);
141
142 uint8_t *pu8Dst = (uint8_t *)pLinPtr->paPages[0] + pLinPtr->cbOffsetFirstPage;
143 uint8_t *pu8Src = (uint8_t *)pvHost;
144
145 Log(("vmmdevHGCMWriteLinPtr: parm %d: size %d, cPages = %d\n", iParm, u32Size, pLinPtr->cPages));
146
147 uint32_t iPage = 0;
148
149 while (iPage < pLinPtr->cPages)
150 {
151 /* copy */
152 size_t cbWrite = iPage == 0?
153 PAGE_SIZE - pLinPtr->cbOffsetFirstPage:
154 PAGE_SIZE;
155
156 Log(("vmmdevHGCMWriteLinPtr: page %d: dst %p, src %p, cbWrite %d\n", iPage, pu8Dst, pu8Src, cbWrite));
157
158 iPage++;
159
160 if (cbWrite >= u32Size)
161 {
162 memcpy (pu8Dst, pu8Src, u32Size);
163 break;
164 }
165
166 memcpy (pu8Dst, pu8Src, cbWrite);
167
168 /* next */
169 u32Size -= cbWrite;
170 pu8Src += cbWrite;
171
172 pu8Dst = (uint8_t *)pLinPtr->paPages[iPage];
173 }
174
175 AssertRelease (iPage == pLinPtr->cPages);
176
177 return rc;
178}
179
180int vmmdevHGCMConnect (VMMDevState *pVMMDevState, VMMDevHGCMConnect *pHGCMConnect)
181{
182 int rc = VINF_SUCCESS;
183
184 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAlloc (sizeof (struct VBOXHGCMCMD));
185
186 if (pCmd)
187 {
188 pCmd->pHeader = &pHGCMConnect->header;
189 pCmd->paHostParms = NULL;
190 pCmd->cLinPtrs = 0;
191 pCmd->paLinPtrs = NULL;
192
193 /* Only allow the guest to use existing services! */
194 Assert(pHGCMConnect->loc.type == VMMDevHGCMLoc_LocalHost_Existing);
195 pHGCMConnect->loc.type = VMMDevHGCMLoc_LocalHost_Existing;
196
197 rc = pVMMDevState->pHGCMDrv->pfnConnect (pVMMDevState->pHGCMDrv, pCmd, &pHGCMConnect->loc, &pHGCMConnect->u32ClientID);
198 }
199 else
200 {
201 rc = VERR_NO_MEMORY;
202 }
203
204 return rc;
205}
206
207int vmmdevHGCMDisconnect (VMMDevState *pVMMDevState, VMMDevHGCMDisconnect *pHGCMDisconnect)
208{
209 int rc = VINF_SUCCESS;
210
211 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAlloc (sizeof (struct VBOXHGCMCMD));
212
213 if (pCmd)
214 {
215 pCmd->pHeader = &pHGCMDisconnect->header;
216 pCmd->paHostParms = NULL;
217 pCmd->cLinPtrs = 0;
218 pCmd->paLinPtrs = NULL;
219
220 rc = pVMMDevState->pHGCMDrv->pfnDisconnect (pVMMDevState->pHGCMDrv, pCmd, pHGCMDisconnect->u32ClientID);
221 }
222 else
223 {
224 rc = VERR_NO_MEMORY;
225 }
226
227 return rc;
228}
229
230
231int vmmdevHGCMCall (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall)
232{
233 int rc = VINF_SUCCESS;
234
235 Log(("vmmdevHGCMCall: client id = %d, function = %d\n", pHGCMCall->u32ClientID, pHGCMCall->u32Function));
236
237 /* Compute size and allocate memory block to hold:
238 * struct VBOXHGCMCMD
239 * VBOXHGCMSVCPARM[cParms]
240 * memory buffers for pointer parameters.
241 */
242
243 uint32_t cParms = pHGCMCall->cParms;
244
245 Log(("vmmdevHGCMCall: cParms = %d\n", cParms));
246
247 /*
248 * Compute size of required memory buffer.
249 */
250
251 uint32_t cbCmdSize = sizeof (struct VBOXHGCMCMD) + cParms * sizeof (VBOXHGCMSVCPARM);
252
253 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
254
255 /* Look for pointer parameters, which require a host buffer. */
256 uint32_t i;
257
258 uint32_t cLinPtrs = 0;
259 uint32_t cLinPtrPages = 0;
260
261 for (i = 0; i < cParms && VBOX_SUCCESS(rc); i++, pGuestParm++)
262 {
263 switch (pGuestParm->type)
264 {
265 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
266 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
267 case VMMDevHGCMParmType_LinAddr: /* In & Out */
268#if 0
269 case VMMDevHGCMParmType_Virt16Addr:
270 case VMMDevHGCMParmType_VirtAddr:
271#endif
272 {
273 cbCmdSize += pGuestParm->u.Pointer.size;
274
275 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
276 {
277 cLinPtrs++;
278 cLinPtrPages += (pGuestParm->u.Pointer.size + PAGE_SIZE - 1) / PAGE_SIZE;
279 }
280
281 Log(("vmmdevHGCMCall: linptr size = %d\n", pGuestParm->u.Pointer.size));
282 } break;
283 case VMMDevHGCMParmType_32bit:
284 case VMMDevHGCMParmType_64bit:
285 case VMMDevHGCMParmType_PhysAddr:
286 {
287 } break;
288 default:
289 {
290 rc = VERR_INVALID_PARAMETER;
291 break;
292 }
293 }
294 }
295
296 if (VBOX_FAILURE (rc))
297 {
298 return rc;
299 }
300
301 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAlloc (cbCmdSize);
302
303 if (pCmd == NULL)
304 {
305 return VERR_NO_MEMORY;
306 }
307
308 pCmd->pHeader = &pHGCMCall->header;
309 pCmd->paHostParms = NULL;
310 pCmd->cLinPtrs = cLinPtrs;
311
312 if (cLinPtrs > 0)
313 {
314 pCmd->paLinPtrs = (VBOXHGCMLINPTR *)RTMemAlloc ( sizeof (VBOXHGCMLINPTR) * cLinPtrs
315 + sizeof (RTHCPTR) * cLinPtrPages);
316
317 if (pCmd->paLinPtrs == NULL)
318 {
319 RTMemFree (pCmd);
320 return VERR_NO_MEMORY;
321 }
322 }
323 else
324 {
325 pCmd->paLinPtrs = NULL;
326 }
327
328 /* Process parameters, changing them to host context pointers for easy
329 * processing by connector. Guest must insure that the pointed data is actually
330 * in the guest RAM and remains locked there for entire request processing.
331 */
332
333 if (cParms != 0)
334 {
335 /* Compute addresses of host parms array and first memory buffer. */
336 VBOXHGCMSVCPARM *pHostParm = (VBOXHGCMSVCPARM *)((char *)pCmd + sizeof (struct VBOXHGCMCMD));
337
338 uint8_t *pcBuf = (uint8_t *)pHostParm + cParms * sizeof (VBOXHGCMSVCPARM);
339
340 pCmd->paHostParms = pHostParm;
341
342 pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
343
344 uint32_t iLinPtr = 0;
345 RTHCPTR *pPages = (RTHCPTR *)((uint8_t *)pCmd->paLinPtrs + sizeof (VBOXHGCMLINPTR) *cLinPtrs);
346
347 for (i = 0; i < cParms && VBOX_SUCCESS(rc); i++, pGuestParm++, pHostParm++)
348 {
349 switch (pGuestParm->type)
350 {
351 case VMMDevHGCMParmType_32bit:
352 {
353 uint32_t u32 = pGuestParm->u.value32;
354
355 pHostParm->type = VBOX_HGCM_SVC_PARM_32BIT;
356 pHostParm->u.uint32 = u32;
357
358 Log(("vmmdevHGCMCall: uint32 guest parameter %u\n", u32));
359 } break;
360
361 case VMMDevHGCMParmType_64bit:
362 {
363 uint64_t u64 = pGuestParm->u.value64;
364
365 pHostParm->type = VBOX_HGCM_SVC_PARM_64BIT;
366 pHostParm->u.uint64 = u64;
367
368 Log(("vmmdevHGCMCall: uint64 guest parameter %llu\n", u64));
369 } break;
370
371 case VMMDevHGCMParmType_PhysAddr:
372 {
373 uint32_t size = pGuestParm->u.Pointer.size;
374 RTGCPHYS physAddr = pGuestParm->u.Pointer.u.physAddr;
375
376 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
377 pHostParm->u.pointer.size = size;
378
379 rc = pVMMDevState->pDevIns->pDevHlp->pfnPhys2HCVirt (pVMMDevState->pDevIns, physAddr,
380 size, &pHostParm->u.pointer.addr);
381
382 Log(("vmmdevHGCMCall: PhysAddr guest parameter %VGp\n", physAddr));
383 } break;
384
385 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
386 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
387 case VMMDevHGCMParmType_LinAddr: /* In & Out */
388 {
389 uint32_t size = pGuestParm->u.Pointer.size;
390 RTGCPTR linearAddr = pGuestParm->u.Pointer.u.linearAddr;
391
392 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
393 pHostParm->u.pointer.size = size;
394
395 /* Copy guest data to an allocated buffer, so
396 * services can use the data.
397 */
398
399 if (size == 0)
400 {
401 pHostParm->u.pointer.addr = (void *) 0xfeeddead;
402 }
403 else
404 {
405 /* Don't overdo it */
406 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_Out)
407 {
408 rc = pVMMDevState->pDevIns->pDevHlp->pfnPhysReadGCVirt (pVMMDevState->pDevIns, pcBuf,
409 linearAddr, size);
410 }
411 else
412 rc = VINF_SUCCESS;
413
414 if (VBOX_SUCCESS(rc))
415 {
416 pHostParm->u.pointer.addr = pcBuf;
417 pcBuf += size;
418
419 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
420 {
421 /* Remember the guest physical pages those belongs to the virtual address
422 * region.
423 */
424 rc = vmmdevHGCMSaveLinPtr (pVMMDevState->pDevIns, i, linearAddr, size, iLinPtr++, pCmd->paLinPtrs, &pPages);
425 }
426 }
427 }
428
429 Log(("vmmdevHGCMCall: LinAddr guest parameter %VGv, rc = %Vrc\n", linearAddr, rc));
430 } break;
431
432 /* just to shut up gcc */
433 default:
434 break;
435 }
436 }
437 }
438
439 if (VBOX_SUCCESS (rc))
440 {
441 /* Pass the function call to HGCM connector for actual processing */
442 rc = pVMMDevState->pHGCMDrv->pfnCall (pVMMDevState->pHGCMDrv, pCmd, pHGCMCall->u32ClientID, pHGCMCall->u32Function, cParms, pCmd->paHostParms);
443 }
444 else
445 {
446 if (pCmd->paLinPtrs)
447 {
448 RTMemFree (pCmd->paLinPtrs);
449 }
450
451 RTMemFree (pCmd);
452 }
453
454 return rc;
455}
456
457#define PDMIHGCMPORT_2_VMMDEVSTATE(pInterface) ( (VMMDevState *) ((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, HGCMPort)) )
458
459DECLCALLBACK(void) hgcmCompleted (PPDMIHGCMPORT pInterface, int32_t result, PVBOXHGCMCMD pCmd)
460{
461 int rc = VINF_SUCCESS;
462
463 VMMDevHGCMRequestHeader *pHeader = pCmd->pHeader;
464
465 VMMDevState *pVMMDevState = PDMIHGCMPORT_2_VMMDEVSTATE(pInterface);
466
467 /* Setup return codes. */
468 pHeader->result = result;
469
470 /* Update parameters and data buffers. */
471
472 if (pHeader->header.requestType == VMMDevReq_HGCMCall)
473 {
474 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pHeader;
475
476 uint32_t cParms = pHGCMCall->cParms;
477
478 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
479
480 VBOXHGCMSVCPARM *pHostParm = pCmd->paHostParms;
481
482 uint32_t i;
483 uint32_t iLinPtr = 0;
484
485 for (i = 0; i < cParms; i++, pGuestParm++, pHostParm++)
486 {
487 switch (pGuestParm->type)
488 {
489 case VMMDevHGCMParmType_32bit:
490 {
491 pGuestParm->u.value32 = pHostParm->u.uint32;
492 } break;
493
494 case VMMDevHGCMParmType_64bit:
495 {
496 pGuestParm->u.value64 = pHostParm->u.uint64;
497 } break;
498
499 case VMMDevHGCMParmType_PhysAddr:
500 {
501 /* do nothing */
502 } break;
503
504 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
505 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
506 case VMMDevHGCMParmType_LinAddr: /* In & Out */
507 {
508 /* Copy buffer back to guest memory. */
509 uint32_t size = pGuestParm->u.Pointer.size;
510
511 if (size > 0 && pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
512 {
513 /* Use the saved page list. */
514 rc = vmmdevHGCMWriteLinPtr (pVMMDevState->pDevIns, i, pHostParm->u.pointer.addr, size, iLinPtr++, pCmd->paLinPtrs);
515
516// RTGCPTR linearAddr = pGuestParm->u.Pointer.u.linearAddr;
517//
518// rc = pVMMDevState->pDevIns->pDevHlp->pfnPhysWriteGCVirt (pVMMDevState->pDevIns,
519// linearAddr,
520// pHostParm->u.pointer.addr,
521// size);
522 AssertReleaseRC(rc);
523 }
524 } break;
525
526 default:
527 {
528 /* This indicates that the guest request memory was corrupted. */
529 AssertReleaseMsgFailed(("hgcmCompleted: invalid parameter type %08X\n", pGuestParm->type));
530 }
531 }
532 }
533 }
534
535 /* Mark request as processed*/
536 pHeader->fu32Flags |= VBOX_HGCM_REQ_DONE;
537
538 VMMDevNotifyGuest (pVMMDevState, VMMDEV_EVENT_HGCM);
539
540 if (pCmd->paLinPtrs)
541 {
542 RTMemFree (pCmd->paLinPtrs);
543 }
544
545 RTMemFree (pCmd);
546
547 return;
548}
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