VirtualBox

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

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

The Big Sun Rebranding Header Change

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.7 KB
Line 
1/** @file
2 *
3 * VBoxGuestLib - A support library for VirtualBox guest additions:
4 * Host-Guest Communication Manager internal functions, implemented by VBoxGuest
5 */
6
7/*
8 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23/* Entire file is ifdef'ed with VBGL_VBOXGUEST */
24#ifdef VBGL_VBOXGUEST
25
26#include <VBox/VBoxGuestLib.h>
27#include "VBGLInternal.h"
28#include <iprt/string.h>
29#include <iprt/assert.h>
30#include <iprt/alloca.h>
31
32/* These functions can be only used by VBoxGuest. */
33
34DECLVBGL(int) VbglHGCMConnect (VBoxGuestHGCMConnectInfo *pConnectInfo,
35 VBGLHGCMCALLBACK *pAsyncCallback, void *pvAsyncData,
36 uint32_t u32AsyncData)
37{
38 VMMDevHGCMConnect *pHGCMConnect;
39 int rc;
40
41 if (!pConnectInfo || !pAsyncCallback)
42 return VERR_INVALID_PARAMETER;
43
44 pHGCMConnect = NULL;
45
46 /* Allocate request */
47 rc = VbglGRAlloc ((VMMDevRequestHeader **)&pHGCMConnect, sizeof (VMMDevHGCMConnect), VMMDevReq_HGCMConnect);
48
49 if (VBOX_SUCCESS(rc))
50 {
51 /* Initialize request memory */
52 pHGCMConnect->header.fu32Flags = 0;
53
54 memcpy (&pHGCMConnect->loc, &pConnectInfo->Loc, sizeof (HGCMServiceLocation));
55 pHGCMConnect->u32ClientID = 0;
56
57 /* Issue request */
58 rc = VbglGRPerform (&pHGCMConnect->header.header);
59
60 if (VBOX_SUCCESS(rc))
61 {
62 /* Check if host decides to process the request asynchronously. */
63 if (rc == VINF_HGCM_ASYNC_EXECUTE)
64 {
65 /* Wait for request completion interrupt notification from host */
66 pAsyncCallback (&pHGCMConnect->header, pvAsyncData, u32AsyncData);
67 }
68
69 pConnectInfo->result = pHGCMConnect->header.result;
70
71 if (VBOX_SUCCESS (pConnectInfo->result))
72 pConnectInfo->u32ClientID = pHGCMConnect->u32ClientID;
73 }
74
75 VbglGRFree (&pHGCMConnect->header.header);
76 }
77
78 return rc;
79}
80
81
82DECLVBGL(int) VbglHGCMDisconnect (VBoxGuestHGCMDisconnectInfo *pDisconnectInfo,
83 VBGLHGCMCALLBACK *pAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData)
84{
85 VMMDevHGCMDisconnect *pHGCMDisconnect;
86 int rc;
87
88 if (!pDisconnectInfo || !pAsyncCallback)
89 return VERR_INVALID_PARAMETER;
90
91 pHGCMDisconnect = NULL;
92
93 /* Allocate request */
94 rc = VbglGRAlloc ((VMMDevRequestHeader **)&pHGCMDisconnect, sizeof (VMMDevHGCMDisconnect), VMMDevReq_HGCMDisconnect);
95
96 if (VBOX_SUCCESS(rc))
97 {
98 /* Initialize request memory */
99 pHGCMDisconnect->header.fu32Flags = 0;
100
101 pHGCMDisconnect->u32ClientID = pDisconnectInfo->u32ClientID;
102
103 /* Issue request */
104 rc = VbglGRPerform (&pHGCMDisconnect->header.header);
105
106 if (VBOX_SUCCESS(rc))
107 {
108 /* Check if host decides to process the request asynchronously. */
109 if (rc == VINF_HGCM_ASYNC_EXECUTE)
110 {
111 /* Wait for request completion interrupt notification from host */
112 pAsyncCallback (&pHGCMDisconnect->header, pvAsyncData, u32AsyncData);
113 }
114
115 pDisconnectInfo->result = pHGCMDisconnect->header.result;
116 }
117
118 VbglGRFree (&pHGCMDisconnect->header.header);
119 }
120
121 return rc;
122}
123
124
125DECLVBGL(int) VbglHGCMCall (VBoxGuestHGCMCallInfo *pCallInfo,
126 VBGLHGCMCALLBACK *pAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData)
127{
128 VMMDevHGCMCall *pHGCMCall;
129 uint32_t cbParms;
130 HGCMFunctionParameter *pParm;
131 unsigned iParm;
132 int rc;
133
134 if (!pCallInfo || !pAsyncCallback || pCallInfo->cParms > VBOX_HGCM_MAX_PARMS)
135 {
136 AssertFailed();
137 return VERR_INVALID_PARAMETER;
138 }
139
140 /* Anyone who needs this can re-enable it locally */
141 /* dprintf (("VbglHGCMCall: pCallInfo->cParms = %d, pHGCMCall->u32Function = %d\n", pCallInfo->cParms, pCallInfo->u32Function)); */
142
143 pHGCMCall = NULL;
144
145 cbParms = pCallInfo->cParms * sizeof (HGCMFunctionParameter);
146
147 /* Allocate request */
148 rc = VbglGRAlloc ((VMMDevRequestHeader **)&pHGCMCall, sizeof (VMMDevHGCMCall) + cbParms, VMMDevReq_HGCMCall);
149
150 /* Anyone who needs this can re-enable it locally */
151 /* dprintf (("VbglHGCMCall Allocated gr %p, rc = %Vrc, cbParms = %d\n", pHGCMCall, rc, cbParms)); */
152
153 if (VBOX_SUCCESS(rc))
154 {
155 void *apvCtx[VBOX_HGCM_MAX_PARMS];
156 memset (apvCtx, 0, sizeof(void *) * pCallInfo->cParms);
157
158 /* Initialize request memory */
159 pHGCMCall->header.fu32Flags = 0;
160 pHGCMCall->header.result = VINF_SUCCESS;
161
162 pHGCMCall->u32ClientID = pCallInfo->u32ClientID;
163 pHGCMCall->u32Function = pCallInfo->u32Function;
164 pHGCMCall->cParms = pCallInfo->cParms;
165
166 if (cbParms)
167 {
168 /* Lock user buffers. */
169 pParm = VBOXGUEST_HGCM_CALL_PARMS(pCallInfo);
170
171 for (iParm = 0; iParm < pCallInfo->cParms; iParm++, pParm++)
172 {
173 switch (pParm->type)
174 {
175 case VMMDevHGCMParmType_LinAddr_Locked_In:
176 pParm->type = VMMDevHGCMParmType_LinAddr_In;
177 break;
178 case VMMDevHGCMParmType_LinAddr_Locked_Out:
179 pParm->type = VMMDevHGCMParmType_LinAddr_Out;
180 break;
181 case VMMDevHGCMParmType_LinAddr_Locked:
182 pParm->type = VMMDevHGCMParmType_LinAddr;
183 break;
184
185 case VMMDevHGCMParmType_LinAddr_In:
186 case VMMDevHGCMParmType_LinAddr_Out:
187 case VMMDevHGCMParmType_LinAddr:
188 /* PORTME: When porting this to Darwin and other systems where the entire kernel isn't mapped
189 into every process, all linear address will have to be converted to physical SG lists at
190 this point. Care must also be taken on these guests to not mix kernel and user addresses
191 in HGCM calls, or we'll end up locking the wrong memory. If VMMDev/HGCM gets a linear address
192 it will assume that it's in the current memory context (i.e. use CR3 to translate it).
193
194 These kind of problems actually applies to some patched linux kernels too, including older
195 fedora releases. (The patch is the infamous 4G/4G patch, aka 4g4g, by Ingo Molnar.) */
196 rc = vbglLockLinear (&apvCtx[iParm], (void *)pParm->u.Pointer.u.linearAddr, pParm->u.Pointer.size, (pParm->type == VMMDevHGCMParmType_LinAddr_In) ? false : true /* write access */);
197 break;
198 default:
199 /* make gcc happy */
200 break;
201 }
202 if (VBOX_FAILURE (rc))
203 break;
204 }
205 memcpy (VMMDEV_HGCM_CALL_PARMS(pHGCMCall), VBOXGUEST_HGCM_CALL_PARMS(pCallInfo), cbParms);
206 }
207
208 /* Check that the parameter locking was ok. */
209 if (VBOX_SUCCESS(rc))
210 {
211 /* Anyone who needs this can re-enable it locally */
212 /* dprintf (("calling VbglGRPerform\n")); */
213
214 /* Issue request */
215 rc = VbglGRPerform (&pHGCMCall->header.header);
216
217 /* Anyone who needs this can re-enable it locally */
218 /* dprintf (("VbglGRPerform rc = %Vrc (header rc=%d)\n", rc, pHGCMCall->header.result)); */
219
220 /** If the call failed, but as a result of the request itself, then pretend success
221 * Upper layers will interpret the result code in the packet.
222 */
223 if (VBOX_FAILURE(rc) && rc == pHGCMCall->header.result)
224 {
225 Assert(pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_DONE);
226 rc = VINF_SUCCESS;
227 }
228
229 if (VBOX_SUCCESS(rc))
230 {
231 /* Check if host decides to process the request asynchronously. */
232 if (rc == VINF_HGCM_ASYNC_EXECUTE)
233 {
234 /* Wait for request completion interrupt notification from host */
235 pAsyncCallback (&pHGCMCall->header, pvAsyncData, u32AsyncData);
236 }
237
238 if (pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_DONE)
239 {
240 if (cbParms)
241 {
242 memcpy (VBOXGUEST_HGCM_CALL_PARMS(pCallInfo), VMMDEV_HGCM_CALL_PARMS(pHGCMCall), cbParms);
243 }
244 pCallInfo->result = pHGCMCall->header.result;
245 }
246 else
247 {
248 /* The callback returns without completing the request,
249 * that means the wait was interrrupted. That can happen
250 * if system reboots or the VBoxService ended abnormally.
251 * In both cases it is OK to just leave the allocated memory
252 * in the physical heap. The memory leak does not affect normal
253 * operations.
254 * @todo VbglGRCancel (&pHGCMCall->header.header) need to be implemented.
255 * The host will not write to the cancelled memory.
256 */
257 pHGCMCall->header.fu32Flags |= VBOX_HGCM_REQ_CANCELLED;
258 }
259 }
260 }
261
262 /* Unlock user buffers. */
263 pParm = VBOXGUEST_HGCM_CALL_PARMS(pCallInfo);
264
265 for (iParm = 0; iParm < pCallInfo->cParms; iParm++, pParm++)
266 {
267 if ( pParm->type == VMMDevHGCMParmType_LinAddr_In
268 || pParm->type == VMMDevHGCMParmType_LinAddr_Out
269 || pParm->type == VMMDevHGCMParmType_LinAddr)
270 {
271 if (apvCtx[iParm] != NULL)
272 {
273 vbglUnlockLinear (apvCtx[iParm], (void *)pParm->u.Pointer.u.linearAddr, pParm->u.Pointer.size);
274 }
275 }
276 else
277 Assert(!apvCtx[iParm]);
278 }
279
280 if ((pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_CANCELLED) == 0)
281 VbglGRFree (&pHGCMCall->header.header);
282 else
283 rc = VERR_INTERRUPTED;
284 }
285
286 return rc;
287}
288
289#endif /* VBGL_VBOXGUEST */
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