VirtualBox

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

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

Include offset into first page into page number calculation (!).

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

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