VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuestLib/HGCMInternal.cpp@ 21211

Last change on this file since 21211 was 21211, checked in by vboxsync, 15 years ago

VBoxGuest.h,VBoxGuestLib: Moved the VbglR3 API out of VBoxGuest.h and did some cleanup.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.2 KB
Line 
1/* $Revision: 21211 $ */
2/** @file
3 * VBoxGuestLib - Host-Guest Communication Manager internal functions, implemented by VBoxGuest
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/* Entire file is ifdef'ed with VBGL_VBOXGUEST */
23#ifdef VBGL_VBOXGUEST
24
25#include "VBGLInternal.h"
26#include <iprt/string.h>
27#include <iprt/assert.h>
28#include <iprt/alloca.h>
29
30/* These functions can be only used by VBoxGuest. */
31
32DECLVBGL(int) VbglHGCMConnect (VBoxGuestHGCMConnectInfo *pConnectInfo,
33 VBGLHGCMCALLBACK *pAsyncCallback, void *pvAsyncData,
34 uint32_t u32AsyncData)
35{
36 VMMDevHGCMConnect *pHGCMConnect;
37 int rc;
38
39 if (!pConnectInfo || !pAsyncCallback)
40 return VERR_INVALID_PARAMETER;
41
42 pHGCMConnect = NULL;
43
44 /* Allocate request */
45 rc = VbglGRAlloc ((VMMDevRequestHeader **)&pHGCMConnect, sizeof (VMMDevHGCMConnect), VMMDevReq_HGCMConnect);
46
47 if (RT_SUCCESS(rc))
48 {
49 /* Initialize request memory */
50 pHGCMConnect->header.fu32Flags = 0;
51
52 memcpy (&pHGCMConnect->loc, &pConnectInfo->Loc, sizeof (HGCMServiceLocation));
53 pHGCMConnect->u32ClientID = 0;
54
55 /* Issue request */
56 rc = VbglGRPerform (&pHGCMConnect->header.header);
57
58 if (RT_SUCCESS(rc))
59 {
60 /* Check if host decides to process the request asynchronously. */
61 if (rc == VINF_HGCM_ASYNC_EXECUTE)
62 {
63 /* Wait for request completion interrupt notification from host */
64 pAsyncCallback (&pHGCMConnect->header, pvAsyncData, u32AsyncData);
65 }
66
67 pConnectInfo->result = pHGCMConnect->header.result;
68
69 if (RT_SUCCESS (pConnectInfo->result))
70 pConnectInfo->u32ClientID = pHGCMConnect->u32ClientID;
71 }
72
73 VbglGRFree (&pHGCMConnect->header.header);
74 }
75
76 return rc;
77}
78
79
80DECLVBGL(int) VbglHGCMDisconnect (VBoxGuestHGCMDisconnectInfo *pDisconnectInfo,
81 VBGLHGCMCALLBACK *pAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData)
82{
83 VMMDevHGCMDisconnect *pHGCMDisconnect;
84 int rc;
85
86 if (!pDisconnectInfo || !pAsyncCallback)
87 return VERR_INVALID_PARAMETER;
88
89 pHGCMDisconnect = NULL;
90
91 /* Allocate request */
92 rc = VbglGRAlloc ((VMMDevRequestHeader **)&pHGCMDisconnect, sizeof (VMMDevHGCMDisconnect), VMMDevReq_HGCMDisconnect);
93
94 if (RT_SUCCESS(rc))
95 {
96 /* Initialize request memory */
97 pHGCMDisconnect->header.fu32Flags = 0;
98
99 pHGCMDisconnect->u32ClientID = pDisconnectInfo->u32ClientID;
100
101 /* Issue request */
102 rc = VbglGRPerform (&pHGCMDisconnect->header.header);
103
104 if (RT_SUCCESS(rc))
105 {
106 /* Check if host decides to process the request asynchronously. */
107 if (rc == VINF_HGCM_ASYNC_EXECUTE)
108 {
109 /* Wait for request completion interrupt notification from host */
110 pAsyncCallback (&pHGCMDisconnect->header, pvAsyncData, u32AsyncData);
111 }
112
113 pDisconnectInfo->result = pHGCMDisconnect->header.result;
114 }
115
116 VbglGRFree (&pHGCMDisconnect->header.header);
117 }
118
119 return rc;
120}
121
122
123/** @todo merge with the one below (use a header file). Too lazy now. */
124DECLVBGL(int) VbglHGCMCall (VBoxGuestHGCMCallInfo *pCallInfo,
125 VBGLHGCMCALLBACK *pAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData)
126{
127 VMMDevHGCMCall *pHGCMCall;
128 uint32_t cbParms;
129 HGCMFunctionParameter *pParm;
130 unsigned iParm;
131 int rc;
132
133 if (!pCallInfo || !pAsyncCallback || pCallInfo->cParms > VBOX_HGCM_MAX_PARMS)
134 {
135 AssertFailed();
136 return VERR_INVALID_PARAMETER;
137 }
138
139 Log (("VbglHGCMCall: pCallInfo->cParms = %d, pHGCMCall->u32Function = %d\n", pCallInfo->cParms, pCallInfo->u32Function));
140
141 pHGCMCall = NULL;
142
143 cbParms = pCallInfo->cParms * sizeof (HGCMFunctionParameter);
144
145 /* Allocate request */
146 rc = VbglGRAlloc ((VMMDevRequestHeader **)&pHGCMCall, sizeof (VMMDevHGCMCall) + cbParms, VMMDevReq_HGCMCall);
147
148 Log (("VbglHGCMCall Allocated gr %p, rc = %Rrc, cbParms = %d\n", pHGCMCall, rc, cbParms));
149
150 if (RT_SUCCESS(rc))
151 {
152 void *apvCtx[VBOX_HGCM_MAX_PARMS];
153 memset (apvCtx, 0, sizeof(void *) * pCallInfo->cParms);
154
155 /* Initialize request memory */
156 pHGCMCall->header.fu32Flags = 0;
157 pHGCMCall->header.result = VINF_SUCCESS;
158
159 pHGCMCall->u32ClientID = pCallInfo->u32ClientID;
160 pHGCMCall->u32Function = pCallInfo->u32Function;
161 pHGCMCall->cParms = pCallInfo->cParms;
162
163 if (cbParms)
164 {
165 /* Lock user buffers. */
166 pParm = VBOXGUEST_HGCM_CALL_PARMS(pCallInfo);
167
168 for (iParm = 0; iParm < pCallInfo->cParms; iParm++, pParm++)
169 {
170 switch (pParm->type)
171 {
172 case VMMDevHGCMParmType_LinAddr_Locked_In:
173 pParm->type = VMMDevHGCMParmType_LinAddr_In;
174 break;
175 case VMMDevHGCMParmType_LinAddr_Locked_Out:
176 pParm->type = VMMDevHGCMParmType_LinAddr_Out;
177 break;
178 case VMMDevHGCMParmType_LinAddr_Locked:
179 pParm->type = VMMDevHGCMParmType_LinAddr;
180 break;
181
182 case VMMDevHGCMParmType_LinAddr_In:
183 case VMMDevHGCMParmType_LinAddr_Out:
184 case VMMDevHGCMParmType_LinAddr:
185 /* PORTME: When porting this to Darwin and other systems where the entire kernel isn't mapped
186 into every process, all linear address will have to be converted to physical SG lists at
187 this point. Care must also be taken on these guests to not mix kernel and user addresses
188 in HGCM calls, or we'll end up locking the wrong memory. If VMMDev/HGCM gets a linear address
189 it will assume that it's in the current memory context (i.e. use CR3 to translate it).
190
191 These kind of problems actually applies to some patched linux kernels too, including older
192 fedora releases. (The patch is the infamous 4G/4G patch, aka 4g4g, by Ingo Molnar.) */
193 rc = vbglLockLinear (&apvCtx[iParm], (void *)pParm->u.Pointer.u.linearAddr, pParm->u.Pointer.size, (pParm->type == VMMDevHGCMParmType_LinAddr_In) ? false : true /* write access */);
194 break;
195 default:
196 /* make gcc happy */
197 break;
198 }
199 if (RT_FAILURE (rc))
200 break;
201 }
202 memcpy (VMMDEV_HGCM_CALL_PARMS(pHGCMCall), VBOXGUEST_HGCM_CALL_PARMS(pCallInfo), cbParms);
203 }
204
205 /* Check that the parameter locking was ok. */
206 if (RT_SUCCESS(rc))
207 {
208 Log (("calling VbglGRPerform\n"));
209
210 /* Issue request */
211 rc = VbglGRPerform (&pHGCMCall->header.header);
212
213 Log (("VbglGRPerform rc = %Rrc (header rc=%d)\n", rc, pHGCMCall->header.result));
214
215 /** If the call failed, but as a result of the request itself, then pretend success
216 * Upper layers will interpret the result code in the packet.
217 */
218 if (RT_FAILURE(rc) && rc == pHGCMCall->header.result)
219 {
220 Assert(pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_DONE);
221 rc = VINF_SUCCESS;
222 }
223
224 if (RT_SUCCESS(rc))
225 {
226 /* Check if host decides to process the request asynchronously. */
227 if (rc == VINF_HGCM_ASYNC_EXECUTE)
228 {
229 /* Wait for request completion interrupt notification from host */
230 Log (("Processing HGCM call asynchronously\n"));
231 pAsyncCallback (&pHGCMCall->header, pvAsyncData, u32AsyncData);
232 }
233
234 if (pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_DONE)
235 {
236 if (cbParms)
237 {
238 memcpy (VBOXGUEST_HGCM_CALL_PARMS(pCallInfo), VMMDEV_HGCM_CALL_PARMS(pHGCMCall), cbParms);
239 }
240 pCallInfo->result = pHGCMCall->header.result;
241 }
242 else
243 {
244 /* The callback returns without completing the request,
245 * that means the wait was interrrupted. That can happen
246 * if the request times out, the system reboots or the
247 * VBoxService ended abnormally.
248 *
249 * Cancel the request, the host will not write to the
250 * memory related to the cancelled request.
251 */
252 Log (("Cancelling HGCM call\n"));
253 pHGCMCall->header.fu32Flags |= VBOX_HGCM_REQ_CANCELLED;
254
255 pHGCMCall->header.header.requestType = VMMDevReq_HGCMCancel;
256 VbglGRPerform (&pHGCMCall->header.header);
257 }
258 }
259 }
260
261 /* Unlock user buffers. */
262 pParm = VBOXGUEST_HGCM_CALL_PARMS(pCallInfo);
263
264 for (iParm = 0; iParm < pCallInfo->cParms; iParm++, pParm++)
265 {
266 if ( pParm->type == VMMDevHGCMParmType_LinAddr_In
267 || pParm->type == VMMDevHGCMParmType_LinAddr_Out
268 || pParm->type == VMMDevHGCMParmType_LinAddr)
269 {
270 if (apvCtx[iParm] != NULL)
271 {
272 vbglUnlockLinear (apvCtx[iParm], (void *)pParm->u.Pointer.u.linearAddr, pParm->u.Pointer.size);
273 }
274 }
275 else
276 Assert(!apvCtx[iParm]);
277 }
278
279 if ((pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_CANCELLED) == 0)
280 VbglGRFree (&pHGCMCall->header.header);
281 else
282 rc = VERR_INTERRUPTED;
283 }
284
285 return rc;
286}
287# if ARCH_BITS == 64
288/** @todo merge with the one above (use a header file). Too lazy now. */
289DECLVBGL(int) VbglHGCMCall32 (VBoxGuestHGCMCallInfo *pCallInfo,
290 VBGLHGCMCALLBACK *pAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData)
291{
292 VMMDevHGCMCall *pHGCMCall;
293 uint32_t cbParms;
294 HGCMFunctionParameter32 *pParm;
295 unsigned iParm;
296 int rc;
297
298 if (!pCallInfo || !pAsyncCallback || pCallInfo->cParms > VBOX_HGCM_MAX_PARMS)
299 {
300 AssertFailed();
301 return VERR_INVALID_PARAMETER;
302 }
303
304 Log (("VbglHGCMCall: pCallInfo->cParms = %d, pHGCMCall->u32Function = %d\n", pCallInfo->cParms, pCallInfo->u32Function));
305
306 pHGCMCall = NULL;
307
308 cbParms = pCallInfo->cParms * sizeof (HGCMFunctionParameter32);
309
310 /* Allocate request */
311 rc = VbglGRAlloc ((VMMDevRequestHeader **)&pHGCMCall, sizeof (VMMDevHGCMCall) + cbParms, VMMDevReq_HGCMCall32);
312
313 Log (("VbglHGCMCall Allocated gr %p, rc = %Rrc, cbParms = %d\n", pHGCMCall, rc, cbParms));
314
315 if (RT_SUCCESS(rc))
316 {
317 void *apvCtx[VBOX_HGCM_MAX_PARMS];
318 memset (apvCtx, 0, sizeof(void *) * pCallInfo->cParms);
319
320 /* Initialize request memory */
321 pHGCMCall->header.fu32Flags = 0;
322 pHGCMCall->header.result = VINF_SUCCESS;
323
324 pHGCMCall->u32ClientID = pCallInfo->u32ClientID;
325 pHGCMCall->u32Function = pCallInfo->u32Function;
326 pHGCMCall->cParms = pCallInfo->cParms;
327
328 if (cbParms)
329 {
330 /* Lock user buffers. */
331 pParm = VBOXGUEST_HGCM_CALL_PARMS32(pCallInfo);
332
333 for (iParm = 0; iParm < pCallInfo->cParms; iParm++, pParm++)
334 {
335 switch (pParm->type)
336 {
337 case VMMDevHGCMParmType_LinAddr_Locked_In:
338 pParm->type = VMMDevHGCMParmType_LinAddr_In;
339 break;
340 case VMMDevHGCMParmType_LinAddr_Locked_Out:
341 pParm->type = VMMDevHGCMParmType_LinAddr_Out;
342 break;
343 case VMMDevHGCMParmType_LinAddr_Locked:
344 pParm->type = VMMDevHGCMParmType_LinAddr;
345 break;
346
347 case VMMDevHGCMParmType_LinAddr_In:
348 case VMMDevHGCMParmType_LinAddr_Out:
349 case VMMDevHGCMParmType_LinAddr:
350 /* PORTME: When porting this to Darwin and other systems where the entire kernel isn't mapped
351 into every process, all linear address will have to be converted to physical SG lists at
352 this point. Care must also be taken on these guests to not mix kernel and user addresses
353 in HGCM calls, or we'll end up locking the wrong memory. If VMMDev/HGCM gets a linear address
354 it will assume that it's in the current memory context (i.e. use CR3 to translate it).
355
356 These kind of problems actually applies to some patched linux kernels too, including older
357 fedora releases. (The patch is the infamous 4G/4G patch, aka 4g4g, by Ingo Molnar.) */
358 rc = vbglLockLinear (&apvCtx[iParm], (void *)pParm->u.Pointer.u.linearAddr, pParm->u.Pointer.size, (pParm->type == VMMDevHGCMParmType_LinAddr_In) ? false : true /* write access */);
359 break;
360 default:
361 /* make gcc happy */
362 break;
363 }
364 if (RT_FAILURE (rc))
365 break;
366 }
367 memcpy (VMMDEV_HGCM_CALL_PARMS32(pHGCMCall), VBOXGUEST_HGCM_CALL_PARMS32(pCallInfo), cbParms);
368 }
369
370 /* Check that the parameter locking was ok. */
371 if (RT_SUCCESS(rc))
372 {
373 Log (("calling VbglGRPerform\n"));
374
375 /* Issue request */
376 rc = VbglGRPerform (&pHGCMCall->header.header);
377
378 Log (("VbglGRPerform rc = %Rrc (header rc=%d)\n", rc, pHGCMCall->header.result));
379
380 /** If the call failed, but as a result of the request itself, then pretend success
381 * Upper layers will interpret the result code in the packet.
382 */
383 if (RT_FAILURE(rc) && rc == pHGCMCall->header.result)
384 {
385 Assert(pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_DONE);
386 rc = VINF_SUCCESS;
387 }
388
389 if (RT_SUCCESS(rc))
390 {
391 /* Check if host decides to process the request asynchronously. */
392 if (rc == VINF_HGCM_ASYNC_EXECUTE)
393 {
394 /* Wait for request completion interrupt notification from host */
395 Log (("Processing HGCM call asynchronously\n"));
396 pAsyncCallback (&pHGCMCall->header, pvAsyncData, u32AsyncData);
397 }
398
399 if (pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_DONE)
400 {
401 if (cbParms)
402 memcpy (VBOXGUEST_HGCM_CALL_PARMS32(pCallInfo), VMMDEV_HGCM_CALL_PARMS32(pHGCMCall), cbParms);
403
404 pCallInfo->result = pHGCMCall->header.result;
405 }
406 else
407 {
408 /* The callback returns without completing the request,
409 * that means the wait was interrrupted. That can happen
410 * if the request times out, the system reboots or the
411 * VBoxService ended abnormally.
412 *
413 * Cancel the request, the host will not write to the
414 * memory related to the cancelled request.
415 */
416 Log (("Cancelling HGCM call\n"));
417 pHGCMCall->header.fu32Flags |= VBOX_HGCM_REQ_CANCELLED;
418
419 pHGCMCall->header.header.requestType = VMMDevReq_HGCMCancel;
420 VbglGRPerform (&pHGCMCall->header.header);
421 }
422 }
423 }
424
425 /* Unlock user buffers. */
426 pParm = VBOXGUEST_HGCM_CALL_PARMS32(pCallInfo);
427
428 for (iParm = 0; iParm < pCallInfo->cParms; iParm++, pParm++)
429 {
430 if ( pParm->type == VMMDevHGCMParmType_LinAddr_In
431 || pParm->type == VMMDevHGCMParmType_LinAddr_Out
432 || pParm->type == VMMDevHGCMParmType_LinAddr)
433 {
434 if (apvCtx[iParm] != NULL)
435 {
436 vbglUnlockLinear (apvCtx[iParm], (void *)pParm->u.Pointer.u.linearAddr, pParm->u.Pointer.size);
437 }
438 }
439 else
440 Assert(!apvCtx[iParm]);
441 }
442
443 if ((pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_CANCELLED) == 0)
444 VbglGRFree (&pHGCMCall->header.header);
445 else
446 rc = VERR_INTERRUPTED;
447 }
448
449 return rc;
450}
451# endif /* ARCH_BITS == 64 */
452
453#endif /* VBGL_VBOXGUEST */
454
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