VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuestLib/SysHlp.cpp@ 21272

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

SysHlp.cpp: build fix.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.4 KB
Line 
1/* $Revision: 21272 $ */
2/** @file
3 * VBoxGuestLibR0 - IDC with VBoxGuest and HGCM helpers.
4 */
5
6/*
7 * Copyright (C) 2006-2009 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#define LOG_GROUP LOG_GROUP_HGCM
23#include <VBox/log.h>
24
25#include <VBox/VBoxGuestLib.h>
26#include "SysHlp.h"
27
28#include <iprt/assert.h>
29
30#ifdef VBGL_VBOXGUEST
31
32#if !defined (RT_OS_WINDOWS) \
33 && (!defined (RT_OS_LINUX) || defined (VBOX_WITH_COMMON_VBOXGUEST_ON_LINUX))
34# include <iprt/memobj.h>
35#endif
36
37
38/**
39 * Internal worker for locking a range of linear addresses.
40 *
41 * @returns VBox status code.
42 * @param ppvCtx Where to store context data.
43 * @param pv The start of the range.
44 * @param u32Size The size of the range.
45 * @param fWriteAccess Lock for read-write (true) or readonly (false).
46 * @param fFlags HGCM call flags, VBGLR0_HGCM_F_XXX.
47 */
48int vbglLockLinear (void **ppvCtx, void *pv, uint32_t u32Size, bool fWriteAccess, uint32_t fFlags)
49{
50 int rc = VINF_SUCCESS;
51
52 /* Zero size buffers shouldn't be locked. */
53 if (u32Size == 0)
54 {
55 Assert(pv == NULL);
56#ifdef RT_OS_WINDOWS
57 *ppvCtx = NULL;
58#else
59 *ppvCtx = NIL_RTR0MEMOBJ;
60#endif
61 return VINF_SUCCESS;
62 }
63
64 /** @todo just use IPRT here. the extra allocation shouldn't matter much...
65 * Then we can most all this up one level even. */
66#ifdef RT_OS_WINDOWS
67 PMDL pMdl = IoAllocateMdl (pv, u32Size, FALSE, FALSE, NULL);
68
69 if (pMdl == NULL)
70 {
71 rc = VERR_NOT_SUPPORTED;
72 AssertMsgFailed(("IoAllocateMdl %p %x failed!!\n", pv, u32Size));
73 }
74 else
75 {
76 __try {
77 /* Calls to MmProbeAndLockPages must be enclosed in a try/except block. */
78 MmProbeAndLockPages (pMdl,
79 /** @todo (fFlags & VBGLR0_HGCMCALL_F_MODE_MASK) == VBGLR0_HGCMCALL_F_USER? UserMode: KernelMode */
80 KernelMode,
81 (fWriteAccess) ? IoModifyAccess : IoReadAccess);
82
83 *ppvCtx = pMdl;
84
85 } __except(EXCEPTION_EXECUTE_HANDLER) {
86
87 IoFreeMdl (pMdl);
88 /** @todo */
89 rc = VERR_INVALID_PARAMETER;
90 AssertMsgFailed(("MmProbeAndLockPages %p %x failed!!\n", pv, u32Size));
91 }
92 }
93
94#elif defined (RT_OS_LINUX) && !defined (VBOX_WITH_COMMON_VBOXGUEST_ON_LINUX)
95 /** @todo r=frank: Linux: pv is at least in some cases, e.g. with VBoxMapFolder,
96 * an R0 address -- the memory was allocated with kmalloc(). I don't know
97 * if this is true in any case.
98 * r=michael: on Linux, we sometimes have R3 addresses (e.g. shared
99 * clipboard) and sometimes R0 (e.g. shared folders). We really ought
100 * to have two separate paths here - at any rate, Linux R0 shouldn't
101 * end up calling this API. In practice, Linux R3 does it's own thing
102 * before winding up in the R0 path - which calls this stub API.
103 *
104 * bird: this will soon be obsoleted.
105 */
106 NOREF(ppvCtx);
107 NOREF(pv);
108 NOREF(u32Size);
109 NOREF(fFlags);
110
111#else
112 /*
113 * Lock depending on context.
114 *
115 * Note: We will later use the memory object here to convert the HGCM
116 * linear buffer paramter into a physical page list. This is why
117 * we lock both kernel pages on all systems, even those where we
118 * know they aren't pagable.
119 */
120 RTR0MEMOBJ MemObj = NIL_RTR0MEMOBJ;
121 if ((fFlags & VBGLR0_HGCMCALL_F_MODE_MASK) == VBGLR0_HGCMCALL_F_USER)
122 rc = RTR0MemObjLockUser(&MemObj, (RTR3PTR)pv, u32Size, NIL_RTR0PROCESS);
123 else
124 rc = RTR0MemObjLockKernel(&MemObj, pv, u32Size);
125 if (RT_SUCCESS(rc))
126 *ppvCtx = MemObj;
127 else
128 *ppvCtx = NIL_RTR0MEMOBJ;
129
130#endif
131
132 return rc;
133}
134
135void vbglUnlockLinear (void *pvCtx, void *pv, uint32_t u32Size)
136{
137 NOREF(pv);
138 NOREF(u32Size);
139
140#ifdef RT_OS_WINDOWS
141 PMDL pMdl = (PMDL)pvCtx;
142
143 Assert(pMdl);
144 if (pMdl != NULL)
145 {
146 MmUnlockPages (pMdl);
147 IoFreeMdl (pMdl);
148 }
149
150#elif defined (RT_OS_LINUX) && !defined (VBOX_WITH_COMMON_VBOXGUEST_ON_LINUX)
151 NOREF(pvCtx);
152
153#else
154 RTR0MEMOBJ MemObj = (RTR0MEMOBJ)pvCtx;
155 int rc = RTR0MemObjFree(MemObj, false);
156 AssertRC(rc);
157
158#endif
159}
160
161#else /* !VBGL_VBOXGUEST */
162
163# if defined (RT_OS_LINUX) && !defined (__KERNEL__) /** @todo r=bird: What is this for?????? */
164# include <unistd.h>
165# include <errno.h>
166# include <sys/fcntl.h>
167# include <sys/ioctl.h>
168# endif
169
170# if defined (RT_OS_LINUX) && !defined (VBOX_WITH_COMMON_VBOXGUEST_ON_LINUX)
171RT_C_DECLS_BEGIN
172extern DECLVBGL(void *) vboxadd_cmc_open (void);
173extern DECLVBGL(void) vboxadd_cmc_close (void *);
174extern DECLVBGL(int) vboxadd_cmc_call (void *opaque, uint32_t func, void *data);
175RT_C_DECLS_END
176# endif /* RT_OS_LINUX */
177
178# ifdef RT_OS_OS2
179RT_C_DECLS_BEGIN
180/*
181 * On OS/2 we'll do the connecting in the assembly code of the
182 * client driver, exporting a g_VBoxGuestIDC symbol containing
183 * the connection information obtained from the 16-bit IDC.
184 */
185extern VBOXGUESTOS2IDCCONNECT g_VBoxGuestIDC;
186RT_C_DECLS_END
187# endif
188
189# if !defined(RT_OS_OS2) \
190 && !defined(RT_OS_WINDOWS) \
191 && (!defined (RT_OS_LINUX) || defined (VBOX_WITH_COMMON_VBOXGUEST_ON_LINUX))
192RT_C_DECLS_BEGIN
193extern DECLVBGL(void *) VBoxGuestIDCOpen (uint32_t *pu32Version);
194extern DECLVBGL(void) VBoxGuestIDCClose (void *pvOpaque);
195extern DECLVBGL(int) VBoxGuestIDCCall (void *pvOpaque, unsigned int iCmd, void *pvData, size_t cbSize, size_t *pcbReturn);
196RT_C_DECLS_END
197# endif
198
199int vbglDriverOpen (VBGLDRIVER *pDriver)
200{
201# ifdef RT_OS_WINDOWS
202 UNICODE_STRING uszDeviceName;
203 RtlInitUnicodeString (&uszDeviceName, L"\\Device\\VBoxGuest");
204
205 PDEVICE_OBJECT pDeviceObject = NULL;
206 PFILE_OBJECT pFileObject = NULL;
207
208 NTSTATUS rc = IoGetDeviceObjectPointer (&uszDeviceName, FILE_ALL_ACCESS,
209 &pFileObject, &pDeviceObject);
210
211 if (NT_SUCCESS (rc))
212 {
213 Log(("vbglDriverOpen VBoxGuest successful pDeviceObject=%x\n", pDeviceObject));
214 pDriver->pDeviceObject = pDeviceObject;
215 pDriver->pFileObject = pFileObject;
216 return VINF_SUCCESS;
217 }
218 /** @todo return RTErrConvertFromNtStatus(rc)! */
219 Log(("vbglDriverOpen VBoxGuest failed with ntstatus=%x\n", rc));
220 return rc;
221
222# elif defined (RT_OS_LINUX) && !defined (VBOX_WITH_COMMON_VBOXGUEST_ON_LINUX)
223
224 void *opaque;
225
226 opaque = (void *) vboxadd_cmc_open ();
227 if (!opaque)
228 {
229 return VERR_NOT_IMPLEMENTED;
230 }
231 pDriver->opaque = opaque;
232 return VINF_SUCCESS;
233
234# elif defined (RT_OS_OS2)
235 /*
236 * Just check whether the connection was made or not.
237 */
238 if ( g_VBoxGuestIDC.u32Version == VMMDEV_VERSION
239 && VALID_PTR(g_VBoxGuestIDC.u32Session)
240 && VALID_PTR(g_VBoxGuestIDC.pfnServiceEP))
241 {
242 pDriver->u32Session = g_VBoxGuestIDC.u32Session;
243 return VINF_SUCCESS;
244 }
245 pDriver->u32Session = UINT32_MAX;
246 Log(("vbglDriverOpen: failed\n"));
247 return VERR_FILE_NOT_FOUND;
248
249# else
250 uint32_t u32VMMDevVersion;
251 pDriver->pvOpaque = VBoxGuestIDCOpen (&u32VMMDevVersion);
252 if ( pDriver->pvOpaque
253 && u32VMMDevVersion == VMMDEV_VERSION)
254 return VINF_SUCCESS;
255
256 Log(("vbglDriverOpen: failed\n"));
257 return VERR_FILE_NOT_FOUND;
258# endif
259}
260
261# ifdef RT_OS_WINDOWS
262static NTSTATUS vbglDriverIOCtlCompletion (IN PDEVICE_OBJECT DeviceObject,
263 IN PIRP Irp,
264 IN PVOID Context)
265{
266 Log(("VBGL completion %x\n", Irp));
267
268 KEVENT *pEvent = (KEVENT *)Context;
269 KeSetEvent (pEvent, IO_NO_INCREMENT, FALSE);
270
271 return STATUS_MORE_PROCESSING_REQUIRED;
272}
273# endif
274
275int vbglDriverIOCtl (VBGLDRIVER *pDriver, uint32_t u32Function, void *pvData, uint32_t cbData)
276{
277 Log(("vbglDriverIOCtl: pDriver: %p, Func: %x, pvData: %p, cbData: %d\n", pDriver, u32Function, pvData, cbData));
278
279# ifdef RT_OS_WINDOWS
280 KEVENT Event;
281
282 KeInitializeEvent (&Event, NotificationEvent, FALSE);
283
284 /* Have to use the IoAllocateIRP method because this code is generic and
285 * must work in any thread context.
286 * The IoBuildDeviceIoControlRequest, which was used here, does not work
287 * when APCs are disabled, for example.
288 */
289 PIRP irp = IoAllocateIrp (pDriver->pDeviceObject->StackSize, FALSE);
290
291 Log(("vbglDriverIOCtl: irp %p, IRQL = %d\n", irp, KeGetCurrentIrql()));
292
293 if (irp == NULL)
294 {
295 Log(("vbglDriverIOCtl: IRP allocation failed!\n"));
296 return VERR_NO_MEMORY;
297 }
298
299 /*
300 * Setup the IRP_MJ_DEVICE_CONTROL IRP.
301 */
302
303 PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation (irp);
304
305 nextStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
306 nextStack->MinorFunction = 0;
307 nextStack->DeviceObject = pDriver->pDeviceObject;
308 nextStack->Parameters.DeviceIoControl.OutputBufferLength = cbData;
309 nextStack->Parameters.DeviceIoControl.InputBufferLength = cbData;
310 nextStack->Parameters.DeviceIoControl.IoControlCode = u32Function;
311 nextStack->Parameters.DeviceIoControl.Type3InputBuffer = pvData;
312
313 irp->AssociatedIrp.SystemBuffer = pvData; /* Output buffer. */
314 irp->MdlAddress = NULL;
315
316 /* A completion routine is required to signal the Event. */
317 IoSetCompletionRoutine (irp, vbglDriverIOCtlCompletion, &Event, TRUE, TRUE, TRUE);
318
319 NTSTATUS rc = IoCallDriver (pDriver->pDeviceObject, irp);
320
321 if (NT_SUCCESS (rc))
322 {
323 /* Wait the event to be signalled by the completion routine. */
324 KeWaitForSingleObject (&Event,
325 Executive,
326 KernelMode,
327 FALSE,
328 NULL);
329
330 rc = irp->IoStatus.Status;
331
332 Log(("vbglDriverIOCtl: wait completed IRQL = %d\n", KeGetCurrentIrql()));
333 }
334
335 IoFreeIrp (irp);
336
337 if (rc != STATUS_SUCCESS)
338 Log(("vbglDriverIOCtl: ntstatus=%x\n", rc));
339
340 return NT_SUCCESS(rc)? VINF_SUCCESS: VERR_VBGL_IOCTL_FAILED;
341
342# elif defined (RT_OS_LINUX) && !defined (VBOX_WITH_COMMON_VBOXGUEST_ON_LINUX)
343 return vboxadd_cmc_call (pDriver->opaque, u32Function, pvData);
344
345# elif defined (RT_OS_OS2)
346 if ( pDriver->u32Session
347 && pDriver->u32Session == g_VBoxGuestIDC.u32Session)
348 return g_VBoxGuestIDC.pfnServiceEP(pDriver->u32Session, u32Function, pvData, cbData, NULL);
349
350 Log(("vbglDriverIOCtl: No connection\n"));
351 return VERR_WRONG_ORDER;
352
353# else
354 return VBoxGuestIDCCall(pDriver->pvOpaque, u32Function, pvData, cbData, NULL);
355# endif
356}
357
358void vbglDriverClose (VBGLDRIVER *pDriver)
359{
360# ifdef RT_OS_WINDOWS
361 Log(("vbglDriverClose pDeviceObject=%x\n", pDriver->pDeviceObject));
362 ObDereferenceObject (pDriver->pFileObject);
363
364# elif defined (RT_OS_LINUX) && !defined (VBOX_WITH_COMMON_VBOXGUEST_ON_LINUX)
365 vboxadd_cmc_close (pDriver->opaque);
366
367# elif defined (RT_OS_OS2)
368 pDriver->u32Session = 0;
369
370# else
371 VBoxGuestIDCClose (pDriver->pvOpaque);
372# endif
373}
374
375#endif /* !VBGL_VBOXGUEST */
376
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