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