VirtualBox

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

Last change on this file since 14759 was 14217, checked in by vboxsync, 16 years ago

Additions/Guest Library: comments and logging

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.5 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 (RT_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 (RT_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 (RT_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 (RT_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 (RT_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 Log (("VbglHGCMCall: pCallInfo->cParms = %d, pHGCMCall->u32Function = %d\n", pCallInfo->cParms, pCallInfo->u32Function));
141
142 pHGCMCall = NULL;
143
144 cbParms = pCallInfo->cParms * sizeof (HGCMFunctionParameter);
145
146 /* Allocate request */
147 rc = VbglGRAlloc ((VMMDevRequestHeader **)&pHGCMCall, sizeof (VMMDevHGCMCall) + cbParms, VMMDevReq_HGCMCall);
148
149 Log (("VbglHGCMCall Allocated gr %p, rc = %Rrc, cbParms = %d\n", pHGCMCall, rc, cbParms));
150
151 if (RT_SUCCESS(rc))
152 {
153 void *apvCtx[VBOX_HGCM_MAX_PARMS];
154 memset (apvCtx, 0, sizeof(void *) * pCallInfo->cParms);
155
156 /* Initialize request memory */
157 pHGCMCall->header.fu32Flags = 0;
158 pHGCMCall->header.result = VINF_SUCCESS;
159
160 pHGCMCall->u32ClientID = pCallInfo->u32ClientID;
161 pHGCMCall->u32Function = pCallInfo->u32Function;
162 pHGCMCall->cParms = pCallInfo->cParms;
163
164 if (cbParms)
165 {
166 /* Lock user buffers. */
167 pParm = VBOXGUEST_HGCM_CALL_PARMS(pCallInfo);
168
169 for (iParm = 0; iParm < pCallInfo->cParms; iParm++, pParm++)
170 {
171 switch (pParm->type)
172 {
173 case VMMDevHGCMParmType_LinAddr_Locked_In:
174 pParm->type = VMMDevHGCMParmType_LinAddr_In;
175 break;
176 case VMMDevHGCMParmType_LinAddr_Locked_Out:
177 pParm->type = VMMDevHGCMParmType_LinAddr_Out;
178 break;
179 case VMMDevHGCMParmType_LinAddr_Locked:
180 pParm->type = VMMDevHGCMParmType_LinAddr;
181 break;
182
183 case VMMDevHGCMParmType_LinAddr_In:
184 case VMMDevHGCMParmType_LinAddr_Out:
185 case VMMDevHGCMParmType_LinAddr:
186 /* PORTME: When porting this to Darwin and other systems where the entire kernel isn't mapped
187 into every process, all linear address will have to be converted to physical SG lists at
188 this point. Care must also be taken on these guests to not mix kernel and user addresses
189 in HGCM calls, or we'll end up locking the wrong memory. If VMMDev/HGCM gets a linear address
190 it will assume that it's in the current memory context (i.e. use CR3 to translate it).
191
192 These kind of problems actually applies to some patched linux kernels too, including older
193 fedora releases. (The patch is the infamous 4G/4G patch, aka 4g4g, by Ingo Molnar.) */
194 rc = vbglLockLinear (&apvCtx[iParm], (void *)pParm->u.Pointer.u.linearAddr, pParm->u.Pointer.size, (pParm->type == VMMDevHGCMParmType_LinAddr_In) ? false : true /* write access */);
195 break;
196 default:
197 /* make gcc happy */
198 break;
199 }
200 if (RT_FAILURE (rc))
201 break;
202 }
203 memcpy (VMMDEV_HGCM_CALL_PARMS(pHGCMCall), VBOXGUEST_HGCM_CALL_PARMS(pCallInfo), cbParms);
204 }
205
206 /* Check that the parameter locking was ok. */
207 if (RT_SUCCESS(rc))
208 {
209 Log (("calling VbglGRPerform\n"));
210
211 /* Issue request */
212 rc = VbglGRPerform (&pHGCMCall->header.header);
213
214 Log (("VbglGRPerform rc = %Rrc (header rc=%d)\n", rc, pHGCMCall->header.result));
215
216 /** If the call failed, but as a result of the request itself, then pretend success
217 * Upper layers will interpret the result code in the packet.
218 */
219 if (RT_FAILURE(rc) && rc == pHGCMCall->header.result)
220 {
221 Assert(pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_DONE);
222 rc = VINF_SUCCESS;
223 }
224
225 if (RT_SUCCESS(rc))
226 {
227 /* Check if host decides to process the request asynchronously. */
228 if (rc == VINF_HGCM_ASYNC_EXECUTE)
229 {
230 /* Wait for request completion interrupt notification from host */
231 Log (("Processing HGCM call asynchronously\n"));
232 pAsyncCallback (&pHGCMCall->header, pvAsyncData, u32AsyncData);
233 }
234
235 if (pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_DONE)
236 {
237 if (cbParms)
238 {
239 memcpy (VBOXGUEST_HGCM_CALL_PARMS(pCallInfo), VMMDEV_HGCM_CALL_PARMS(pHGCMCall), cbParms);
240 }
241 pCallInfo->result = pHGCMCall->header.result;
242 }
243 else
244 {
245 /* The callback returns without completing the request,
246 * that means the wait was interrrupted. That can happen
247 * if the request times out, the system reboots or the
248 * VBoxService ended abnormally.
249 *
250 * Cancel the request, the host will not write to the
251 * memory related to the cancelled request.
252 */
253 Log (("Cancelling HGCM call\n"));
254 pHGCMCall->header.fu32Flags |= VBOX_HGCM_REQ_CANCELLED;
255
256 pHGCMCall->header.header.requestType = VMMDevReq_HGCMCancel;
257 VbglGRPerform (&pHGCMCall->header.header);
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.

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