VirtualBox

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

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

Extended interface for locked pointers

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