VirtualBox

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

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

SysHlp.cpp: No need to check in vbglUnlockLinear, NIL_RTRTR0MEMOBJ doesn't need to 0, and finally, it's not ugly, just necessary.

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