VirtualBox

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

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

Add,++: Switch to common addition kernel module.

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