VirtualBox

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

最後變更 在這個檔案從1561是 1561,由 vboxsync 提交於 18 年 前

Extra check

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 17.1 KB
 
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.alldomusa.eu.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 /* Take the offset into the current page also into account! */
87 u32Size += GCPtr & PAGE_OFFSET_MASK;
88
89 uint32_t cPages = (u32Size + PAGE_SIZE - 1) / PAGE_SIZE;
90
91 Log(("vmmdevHGCMSaveLinPtr: parm %d: %VGv %d = %d pages\n", iParm, GCPtr, u32Size, cPages));
92
93 pLinPtr->iParm = iParm;
94 pLinPtr->cbOffsetFirstPage = (RTGCUINTPTR)GCPtr & PAGE_OFFSET_MASK;
95 pLinPtr->cPages = cPages;
96 pLinPtr->paPages = *ppPages;
97
98 *ppPages += cPages;
99
100 uint32_t iPage = 0;
101
102 GCPtr &= PAGE_BASE_GC_MASK;
103
104 /* Gonvert the guest linear pointers of pages to HC addresses. */
105 while (iPage < cPages)
106 {
107 /* convert */
108 RTHCPTR HCPtr;
109
110 rc = pDevIns->pDevHlp->pfnPhysGCPtr2HCPtr (pDevIns, GCPtr, &HCPtr);
111// rc = PGMPhysGCPtr2HCPtr (pVM, GCPtr, &HCPtr);
112
113 Log(("vmmdevHGCMSaveLinPtr: Page %d: %VGv -> %p. %Vrc\n", iPage, GCPtr, HCPtr, rc));
114
115 if (VBOX_FAILURE (rc))
116 {
117 break;
118 }
119
120 /* store */
121 pLinPtr->paPages[iPage++] = HCPtr;
122
123 /* next */
124 GCPtr += PAGE_SIZE;
125 }
126
127 AssertRelease (iPage == cPages);
128
129 return rc;
130}
131
132static int vmmdevHGCMWriteLinPtr (PPDMDEVINS pDevIns,
133 uint32_t iParm,
134 void *pvHost,
135 uint32_t u32Size,
136 uint32_t iLinPtr,
137 VBOXHGCMLINPTR *paLinPtrs)
138{
139 int rc = VINF_SUCCESS;
140
141 VBOXHGCMLINPTR *pLinPtr = &paLinPtrs[iLinPtr];
142
143 AssertRelease (u32Size > 0 && iParm == (uint32_t)pLinPtr->iParm);
144
145 uint8_t *pu8Dst = (uint8_t *)pLinPtr->paPages[0] + pLinPtr->cbOffsetFirstPage;
146 uint8_t *pu8Src = (uint8_t *)pvHost;
147
148 Log(("vmmdevHGCMWriteLinPtr: parm %d: size %d, cPages = %d\n", iParm, u32Size, pLinPtr->cPages));
149
150 uint32_t iPage = 0;
151
152 while (iPage < pLinPtr->cPages)
153 {
154 /* copy */
155 size_t cbWrite = iPage == 0?
156 PAGE_SIZE - pLinPtr->cbOffsetFirstPage:
157 PAGE_SIZE;
158
159 Log(("vmmdevHGCMWriteLinPtr: page %d: dst %p, src %p, cbWrite %d\n", iPage, pu8Dst, pu8Src, cbWrite));
160
161 iPage++;
162
163 if (cbWrite >= u32Size)
164 {
165 memcpy (pu8Dst, pu8Src, u32Size);
166 u32Size = 0;
167 break;
168 }
169
170 memcpy (pu8Dst, pu8Src, cbWrite);
171
172 /* next */
173 u32Size -= cbWrite;
174 pu8Src += cbWrite;
175
176 pu8Dst = (uint8_t *)pLinPtr->paPages[iPage];
177 }
178
179 AssertRelease (iPage == pLinPtr->cPages);
180 Assert(u32Size == 0);
181
182 return rc;
183}
184
185int vmmdevHGCMConnect (VMMDevState *pVMMDevState, VMMDevHGCMConnect *pHGCMConnect)
186{
187 int rc = VINF_SUCCESS;
188
189 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAlloc (sizeof (struct VBOXHGCMCMD));
190
191 if (pCmd)
192 {
193 pCmd->pHeader = &pHGCMConnect->header;
194 pCmd->paHostParms = NULL;
195 pCmd->cLinPtrs = 0;
196 pCmd->paLinPtrs = NULL;
197
198 /* Only allow the guest to use existing services! */
199 Assert(pHGCMConnect->loc.type == VMMDevHGCMLoc_LocalHost_Existing);
200 pHGCMConnect->loc.type = VMMDevHGCMLoc_LocalHost_Existing;
201
202 rc = pVMMDevState->pHGCMDrv->pfnConnect (pVMMDevState->pHGCMDrv, pCmd, &pHGCMConnect->loc, &pHGCMConnect->u32ClientID);
203 }
204 else
205 {
206 rc = VERR_NO_MEMORY;
207 }
208
209 return rc;
210}
211
212int vmmdevHGCMDisconnect (VMMDevState *pVMMDevState, VMMDevHGCMDisconnect *pHGCMDisconnect)
213{
214 int rc = VINF_SUCCESS;
215
216 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAlloc (sizeof (struct VBOXHGCMCMD));
217
218 if (pCmd)
219 {
220 pCmd->pHeader = &pHGCMDisconnect->header;
221 pCmd->paHostParms = NULL;
222 pCmd->cLinPtrs = 0;
223 pCmd->paLinPtrs = NULL;
224
225 rc = pVMMDevState->pHGCMDrv->pfnDisconnect (pVMMDevState->pHGCMDrv, pCmd, pHGCMDisconnect->u32ClientID);
226 }
227 else
228 {
229 rc = VERR_NO_MEMORY;
230 }
231
232 return rc;
233}
234
235
236int vmmdevHGCMCall (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall)
237{
238 int rc = VINF_SUCCESS;
239
240 Log(("vmmdevHGCMCall: client id = %d, function = %d\n", pHGCMCall->u32ClientID, pHGCMCall->u32Function));
241
242 /* Compute size and allocate memory block to hold:
243 * struct VBOXHGCMCMD
244 * VBOXHGCMSVCPARM[cParms]
245 * memory buffers for pointer parameters.
246 */
247
248 uint32_t cParms = pHGCMCall->cParms;
249
250 Log(("vmmdevHGCMCall: cParms = %d\n", cParms));
251
252 /*
253 * Compute size of required memory buffer.
254 */
255
256 uint32_t cbCmdSize = sizeof (struct VBOXHGCMCMD) + cParms * sizeof (VBOXHGCMSVCPARM);
257
258 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
259
260 /* Look for pointer parameters, which require a host buffer. */
261 uint32_t i;
262
263 uint32_t cLinPtrs = 0;
264 uint32_t cLinPtrPages = 0;
265
266 for (i = 0; i < cParms && VBOX_SUCCESS(rc); i++, pGuestParm++)
267 {
268 switch (pGuestParm->type)
269 {
270 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
271 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
272 case VMMDevHGCMParmType_LinAddr: /* In & Out */
273#if 0
274 case VMMDevHGCMParmType_Virt16Addr:
275 case VMMDevHGCMParmType_VirtAddr:
276#endif
277 {
278 cbCmdSize += pGuestParm->u.Pointer.size;
279
280 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
281 {
282 cLinPtrs++;
283 cLinPtrPages += (pGuestParm->u.Pointer.size + PAGE_SIZE - 1) / PAGE_SIZE;
284 }
285
286 Log(("vmmdevHGCMCall: linptr size = %d\n", pGuestParm->u.Pointer.size));
287 } break;
288 case VMMDevHGCMParmType_32bit:
289 case VMMDevHGCMParmType_64bit:
290 case VMMDevHGCMParmType_PhysAddr:
291 {
292 } break;
293 default:
294 {
295 rc = VERR_INVALID_PARAMETER;
296 break;
297 }
298 }
299 }
300
301 if (VBOX_FAILURE (rc))
302 {
303 return rc;
304 }
305
306 PVBOXHGCMCMD pCmd = (PVBOXHGCMCMD)RTMemAlloc (cbCmdSize);
307
308 if (pCmd == NULL)
309 {
310 return VERR_NO_MEMORY;
311 }
312
313 pCmd->pHeader = &pHGCMCall->header;
314 pCmd->paHostParms = NULL;
315 pCmd->cLinPtrs = cLinPtrs;
316
317 if (cLinPtrs > 0)
318 {
319 pCmd->paLinPtrs = (VBOXHGCMLINPTR *)RTMemAlloc ( sizeof (VBOXHGCMLINPTR) * cLinPtrs
320 + sizeof (RTHCPTR) * cLinPtrPages);
321
322 if (pCmd->paLinPtrs == NULL)
323 {
324 RTMemFree (pCmd);
325 return VERR_NO_MEMORY;
326 }
327 }
328 else
329 {
330 pCmd->paLinPtrs = NULL;
331 }
332
333 /* Process parameters, changing them to host context pointers for easy
334 * processing by connector. Guest must insure that the pointed data is actually
335 * in the guest RAM and remains locked there for entire request processing.
336 */
337
338 if (cParms != 0)
339 {
340 /* Compute addresses of host parms array and first memory buffer. */
341 VBOXHGCMSVCPARM *pHostParm = (VBOXHGCMSVCPARM *)((char *)pCmd + sizeof (struct VBOXHGCMCMD));
342
343 uint8_t *pcBuf = (uint8_t *)pHostParm + cParms * sizeof (VBOXHGCMSVCPARM);
344
345 pCmd->paHostParms = pHostParm;
346
347 pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
348
349 uint32_t iLinPtr = 0;
350 RTHCPTR *pPages = (RTHCPTR *)((uint8_t *)pCmd->paLinPtrs + sizeof (VBOXHGCMLINPTR) *cLinPtrs);
351
352 for (i = 0; i < cParms && VBOX_SUCCESS(rc); i++, pGuestParm++, pHostParm++)
353 {
354 switch (pGuestParm->type)
355 {
356 case VMMDevHGCMParmType_32bit:
357 {
358 uint32_t u32 = pGuestParm->u.value32;
359
360 pHostParm->type = VBOX_HGCM_SVC_PARM_32BIT;
361 pHostParm->u.uint32 = u32;
362
363 Log(("vmmdevHGCMCall: uint32 guest parameter %u\n", u32));
364 } break;
365
366 case VMMDevHGCMParmType_64bit:
367 {
368 uint64_t u64 = pGuestParm->u.value64;
369
370 pHostParm->type = VBOX_HGCM_SVC_PARM_64BIT;
371 pHostParm->u.uint64 = u64;
372
373 Log(("vmmdevHGCMCall: uint64 guest parameter %llu\n", u64));
374 } break;
375
376 case VMMDevHGCMParmType_PhysAddr:
377 {
378 uint32_t size = pGuestParm->u.Pointer.size;
379 RTGCPHYS physAddr = pGuestParm->u.Pointer.u.physAddr;
380
381 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
382 pHostParm->u.pointer.size = size;
383
384 rc = pVMMDevState->pDevIns->pDevHlp->pfnPhys2HCVirt (pVMMDevState->pDevIns, physAddr,
385 size, &pHostParm->u.pointer.addr);
386
387 Log(("vmmdevHGCMCall: PhysAddr guest parameter %VGp\n", physAddr));
388 } break;
389
390 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
391 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
392 case VMMDevHGCMParmType_LinAddr: /* In & Out */
393 {
394 uint32_t size = pGuestParm->u.Pointer.size;
395 RTGCPTR linearAddr = pGuestParm->u.Pointer.u.linearAddr;
396
397 pHostParm->type = VBOX_HGCM_SVC_PARM_PTR;
398 pHostParm->u.pointer.size = size;
399
400 /* Copy guest data to an allocated buffer, so
401 * services can use the data.
402 */
403
404 if (size == 0)
405 {
406 pHostParm->u.pointer.addr = (void *) 0xfeeddead;
407 }
408 else
409 {
410 /* Don't overdo it */
411 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_Out)
412 {
413 rc = pVMMDevState->pDevIns->pDevHlp->pfnPhysReadGCVirt (pVMMDevState->pDevIns, pcBuf,
414 linearAddr, size);
415 }
416 else
417 rc = VINF_SUCCESS;
418
419 if (VBOX_SUCCESS(rc))
420 {
421 pHostParm->u.pointer.addr = pcBuf;
422 pcBuf += size;
423
424 if (pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
425 {
426 /* Remember the guest physical pages that belong to the virtual address
427 * region.
428 */
429 rc = vmmdevHGCMSaveLinPtr (pVMMDevState->pDevIns, i, linearAddr, size, iLinPtr++, pCmd->paLinPtrs, &pPages);
430 }
431 }
432 }
433
434 Log(("vmmdevHGCMCall: LinAddr guest parameter %VGv, rc = %Vrc\n", linearAddr, rc));
435 } break;
436
437 /* just to shut up gcc */
438 default:
439 break;
440 }
441 }
442 }
443
444 if (VBOX_SUCCESS (rc))
445 {
446 /* Pass the function call to HGCM connector for actual processing */
447 rc = pVMMDevState->pHGCMDrv->pfnCall (pVMMDevState->pHGCMDrv, pCmd, pHGCMCall->u32ClientID, pHGCMCall->u32Function, cParms, pCmd->paHostParms);
448 }
449 else
450 {
451 if (pCmd->paLinPtrs)
452 {
453 RTMemFree (pCmd->paLinPtrs);
454 }
455
456 RTMemFree (pCmd);
457 }
458
459 return rc;
460}
461
462#define PDMIHGCMPORT_2_VMMDEVSTATE(pInterface) ( (VMMDevState *) ((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, HGCMPort)) )
463
464DECLCALLBACK(void) hgcmCompleted (PPDMIHGCMPORT pInterface, int32_t result, PVBOXHGCMCMD pCmd)
465{
466 int rc = VINF_SUCCESS;
467
468 VMMDevHGCMRequestHeader *pHeader = pCmd->pHeader;
469
470 VMMDevState *pVMMDevState = PDMIHGCMPORT_2_VMMDEVSTATE(pInterface);
471
472 /* Setup return codes. */
473 pHeader->result = result;
474
475 /* Update parameters and data buffers. */
476
477 if (pHeader->header.requestType == VMMDevReq_HGCMCall)
478 {
479 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pHeader;
480
481 uint32_t cParms = pHGCMCall->cParms;
482
483 HGCMFunctionParameter *pGuestParm = VMMDEV_HGCM_CALL_PARMS(pHGCMCall);
484
485 VBOXHGCMSVCPARM *pHostParm = pCmd->paHostParms;
486
487 uint32_t i;
488 uint32_t iLinPtr = 0;
489
490 for (i = 0; i < cParms; i++, pGuestParm++, pHostParm++)
491 {
492 switch (pGuestParm->type)
493 {
494 case VMMDevHGCMParmType_32bit:
495 {
496 pGuestParm->u.value32 = pHostParm->u.uint32;
497 } break;
498
499 case VMMDevHGCMParmType_64bit:
500 {
501 pGuestParm->u.value64 = pHostParm->u.uint64;
502 } break;
503
504 case VMMDevHGCMParmType_PhysAddr:
505 {
506 /* do nothing */
507 } break;
508
509 case VMMDevHGCMParmType_LinAddr_In: /* In (read) */
510 case VMMDevHGCMParmType_LinAddr_Out: /* Out (write) */
511 case VMMDevHGCMParmType_LinAddr: /* In & Out */
512 {
513 /* Copy buffer back to guest memory. */
514 uint32_t size = pGuestParm->u.Pointer.size;
515
516 if (size > 0 && pGuestParm->type != VMMDevHGCMParmType_LinAddr_In)
517 {
518 /* Use the saved page list. */
519 rc = vmmdevHGCMWriteLinPtr (pVMMDevState->pDevIns, i, pHostParm->u.pointer.addr, size, iLinPtr++, pCmd->paLinPtrs);
520
521// RTGCPTR linearAddr = pGuestParm->u.Pointer.u.linearAddr;
522//
523// rc = pVMMDevState->pDevIns->pDevHlp->pfnPhysWriteGCVirt (pVMMDevState->pDevIns,
524// linearAddr,
525// pHostParm->u.pointer.addr,
526// size);
527 AssertReleaseRC(rc);
528 }
529 } break;
530
531 default:
532 {
533 /* This indicates that the guest request memory was corrupted. */
534 AssertReleaseMsgFailed(("hgcmCompleted: invalid parameter type %08X\n", pGuestParm->type));
535 }
536 }
537 }
538 }
539
540 /* Mark request as processed*/
541 pHeader->fu32Flags |= VBOX_HGCM_REQ_DONE;
542
543 VMMDevNotifyGuest (pVMMDevState, VMMDEV_EVENT_HGCM);
544
545 if (pCmd->paLinPtrs)
546 {
547 RTMemFree (pCmd->paLinPtrs);
548 }
549
550 RTMemFree (pCmd);
551
552 return;
553}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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