1 /* $Id: SysHlp.cpp $ */
3 * VBoxGuestLibR0 - IDC with VBoxGuest and HGCM helpers.
7 * Copyright (C) 2006-2016 Oracle Corporation
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.
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.
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.
27 #define LOG_GROUP LOG_GROUP_HGCM
30 #include <VBox/VBoxGuestLib.h>
33 #include <iprt/assert.h>
37 #if !defined (RT_OS_WINDOWS)
38 # include <iprt/memobj.h>
39 # include <iprt/mem.h>
44 * Internal worker for locking a range of linear addresses.
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.
53 int vbglLockLinear(void **ppvCtx
, void *pv
, uint32_t u32Size
, bool fWriteAccess
, uint32_t fFlags
)
55 int rc
= VINF_SUCCESS
;
57 RTR0MEMOBJ MemObj
= NIL_RTR0MEMOBJ
;
58 uint32_t fAccess
= RTMEM_PROT_READ
| (fWriteAccess
? RTMEM_PROT_WRITE
: 0);
61 /* Zero size buffers shouldn't be locked. */
68 *ppvCtx
= NIL_RTR0MEMOBJ
;
73 /** @todo just use IPRT here. the extra allocation shouldn't matter much...
74 * Then we can move all this up one level even. */
76 PMDL pMdl
= IoAllocateMdl(pv
, u32Size
, FALSE
, FALSE
, NULL
);
80 rc
= VERR_NOT_SUPPORTED
;
81 AssertMsgFailed(("IoAllocateMdl %p %x failed!!\n", pv
, u32Size
));
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 */
91 (fWriteAccess
) ? IoModifyAccess
: IoReadAccess
);
95 } __except(EXCEPTION_EXECUTE_HANDLER
) {
99 rc
= VERR_INVALID_PARAMETER
;
100 AssertMsgFailed(("MmProbeAndLockPages %p %x failed!!\n", pv
, u32Size
));
106 * Lock depending on context.
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.
113 if ((fFlags
& VBGLR0_HGCMCALL_F_MODE_MASK
) == VBGLR0_HGCMCALL_F_USER
)
114 rc
= RTR0MemObjLockUser(&MemObj
, (RTR3PTR
)pv
, u32Size
, fAccess
, NIL_RTR0PROCESS
);
116 rc
= RTR0MemObjLockKernel(&MemObj
, pv
, u32Size
, fAccess
);
120 *ppvCtx
= NIL_RTR0MEMOBJ
;
127 void vbglUnlockLinear(void *pvCtx
, void *pv
, uint32_t u32Size
)
130 PMDL pMdl
= (PMDL
)pvCtx
;
140 RTR0MEMOBJ MemObj
= (RTR0MEMOBJ
)pvCtx
;
141 int rc
= RTR0MemObjFree(MemObj
, false);
150 #else /* !VBGL_VBOXGUEST */
153 # include <VBox/VBoxGuest.h> /* for VBOXGUESTOS2IDCCONNECT */
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.
160 extern VBOXGUESTOS2IDCCONNECT g_VBoxGuestIDC
;
164 # if !defined(RT_OS_OS2) \
165 && !defined(RT_OS_WINDOWS)
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
);
173 bool vbglDriverIsOpened(VBGLDRIVER
*pDriver
)
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;
180 return pDriver
->pvOpaque
!= NULL
;
184 int vbglDriverOpen(VBGLDRIVER
*pDriver
)
186 # ifdef RT_OS_WINDOWS
187 UNICODE_STRING uszDeviceName
;
188 RtlInitUnicodeString(&uszDeviceName
, L
"\\Device\\VBoxGuest");
190 PDEVICE_OBJECT pDeviceObject
= NULL
;
191 PFILE_OBJECT pFileObject
= NULL
;
193 NTSTATUS rc
= IoGetDeviceObjectPointer(&uszDeviceName
, FILE_ALL_ACCESS
, &pFileObject
, &pDeviceObject
);
196 Log(("vbglDriverOpen VBoxGuest successful pDeviceObject=%x\n", pDeviceObject
));
197 pDriver
->pDeviceObject
= pDeviceObject
;
198 pDriver
->pFileObject
= pFileObject
;
201 /** @todo return RTErrConvertFromNtStatus(rc)! */
202 Log(("vbglDriverOpen VBoxGuest failed with ntstatus=%x\n", rc
));
205 # elif defined (RT_OS_OS2)
207 * Just check whether the connection was made or not.
209 if ( g_VBoxGuestIDC
.u32Version
== VMMDEV_VERSION
210 && RT_VALID_PTR(g_VBoxGuestIDC
.u32Session
)
211 && RT_VALID_PTR(g_VBoxGuestIDC
.pfnServiceEP
))
213 pDriver
->u32Session
= g_VBoxGuestIDC
.u32Session
;
216 pDriver
->u32Session
= UINT32_MAX
;
217 Log(("vbglDriverOpen: failed\n"));
218 return VERR_FILE_NOT_FOUND
;
221 uint32_t u32VMMDevVersion
;
222 pDriver
->pvOpaque
= VBoxGuestIDCOpen(&u32VMMDevVersion
);
223 if ( pDriver
->pvOpaque
224 && u32VMMDevVersion
== VMMDEV_VERSION
)
227 Log(("vbglDriverOpen: failed\n"));
228 return VERR_FILE_NOT_FOUND
;
232 # ifdef RT_OS_WINDOWS
233 static NTSTATUS
vbglDriverIOCtlCompletion(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
, IN PVOID Context
)
235 RT_NOREF2(DeviceObject
, Irp
);
236 Log(("VBGL completion %x\n", Irp
));
238 KEVENT
*pEvent
= (KEVENT
*)Context
;
239 KeSetEvent(pEvent
, IO_NO_INCREMENT
, FALSE
);
241 return STATUS_MORE_PROCESSING_REQUIRED
;
245 int vbglDriverIOCtl(VBGLDRIVER
*pDriver
, uint32_t u32Function
, void *pvData
, uint32_t cbData
)
247 Log(("vbglDriverIOCtl: pDriver: %p, Func: %x, pvData: %p, cbData: %d\n", pDriver
, u32Function
, pvData
, cbData
));
249 # ifdef RT_OS_WINDOWS
252 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
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.
259 PIRP irp
= IoAllocateIrp(pDriver
->pDeviceObject
->StackSize
, FALSE
);
261 Log(("vbglDriverIOCtl: irp %p, IRQL = %d\n", irp
, KeGetCurrentIrql()));
265 Log(("vbglDriverIOCtl: IRP allocation failed!\n"));
266 return VERR_NO_MEMORY
;
270 * Setup the IRP_MJ_DEVICE_CONTROL IRP.
273 PIO_STACK_LOCATION nextStack
= IoGetNextIrpStackLocation(irp
);
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
;
283 irp
->AssociatedIrp
.SystemBuffer
= pvData
; /* Output buffer. */
284 irp
->MdlAddress
= NULL
;
286 /* A completion routine is required to signal the Event. */
287 IoSetCompletionRoutine(irp
, vbglDriverIOCtlCompletion
, &Event
, TRUE
, TRUE
, TRUE
);
289 NTSTATUS rc
= IoCallDriver(pDriver
->pDeviceObject
, irp
);
293 /* Wait the event to be signalled by the completion routine. */
294 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
296 rc
= irp
->IoStatus
.Status
;
298 Log(("vbglDriverIOCtl: wait completed IRQL = %d\n", KeGetCurrentIrql()));
303 if (rc
!= STATUS_SUCCESS
)
304 Log(("vbglDriverIOCtl: ntstatus=%x\n", rc
));
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
;
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
);
319 Log(("vbglDriverIOCtl: No connection\n"));
320 return VERR_WRONG_ORDER
;
323 return VBoxGuestIDCCall(pDriver
->pvOpaque
, u32Function
, pvData
, cbData
, NULL
);
327 void vbglDriverClose(VBGLDRIVER
*pDriver
)
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
;
335 # elif defined (RT_OS_OS2)
336 pDriver
->u32Session
= 0;
339 VBoxGuestIDCClose(pDriver
->pvOpaque
);
340 pDriver
->pvOpaque
= NULL
;
344 #endif /* !VBGL_VBOXGUEST */