diff options
Diffstat (limited to 'src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxDrvTool.cpp')
-rw-r--r-- | src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxDrvTool.cpp | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxDrvTool.cpp b/src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxDrvTool.cpp new file mode 100644 index 00000000..bb2fe14b --- /dev/null +++ b/src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxDrvTool.cpp @@ -0,0 +1,237 @@ +/* $Id: VBoxDrvTool.cpp $ */ +/** @file + * Windows Driver R0 Tooling. + */ + +/* + * Copyright (C) 2011-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#include "VBoxDrvTool.h" + +#include <iprt/assert.h> +#include <VBox/log.h> + +#include "../../../win/VBoxDbgLog.h" + +#define VBOXDRVTOOL_MEMTAG 'TDBV' + +static PVOID vboxDrvToolMemAlloc(SIZE_T cbBytes) +{ + PVOID pvMem = ExAllocatePoolWithTag(NonPagedPool, cbBytes, VBOXDRVTOOL_MEMTAG); + Assert(pvMem); + return pvMem; +} + +static PVOID vboxDrvToolMemAllocZ(SIZE_T cbBytes) +{ + PVOID pvMem = vboxDrvToolMemAlloc(cbBytes); + if (pvMem) + { + RtlZeroMemory(pvMem, cbBytes); + } + return pvMem; +} + +static VOID vboxDrvToolMemFree(PVOID pvMem) +{ + ExFreePoolWithTag(pvMem, VBOXDRVTOOL_MEMTAG); +} + +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolRegOpenKeyU(OUT PHANDLE phKey, IN PUNICODE_STRING pName, IN ACCESS_MASK fAccess) +{ + OBJECT_ATTRIBUTES ObjAttr; + + InitializeObjectAttributes(&ObjAttr, pName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); + + return ZwOpenKey(phKey, fAccess, &ObjAttr); +} + +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolRegOpenKey(OUT PHANDLE phKey, IN PWCHAR pName, IN ACCESS_MASK fAccess) +{ + UNICODE_STRING RtlStr; + RtlInitUnicodeString(&RtlStr, pName); + + return VBoxDrvToolRegOpenKeyU(phKey, &RtlStr, fAccess); +} + +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolRegCloseKey(IN HANDLE hKey) +{ + return ZwClose(hKey); +} + +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolRegQueryValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT PULONG pDword) +{ + struct + { + KEY_VALUE_PARTIAL_INFORMATION Info; + UCHAR Buf[32]; /* should be enough */ + } Buf; + ULONG cbBuf; + UNICODE_STRING RtlStr; + RtlInitUnicodeString(&RtlStr, pName); + NTSTATUS Status = ZwQueryValueKey(hKey, + &RtlStr, + KeyValuePartialInformation, + &Buf.Info, + sizeof(Buf), + &cbBuf); + if (Status == STATUS_SUCCESS) + { + if (Buf.Info.Type == REG_DWORD) + { + Assert(Buf.Info.DataLength == 4); + *pDword = *((PULONG)Buf.Info.Data); + return STATUS_SUCCESS; + } + } + + return STATUS_INVALID_PARAMETER; +} + +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolRegSetValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT ULONG val) +{ + UNICODE_STRING RtlStr; + RtlInitUnicodeString(&RtlStr, pName); + return ZwSetValueKey(hKey, &RtlStr, + NULL, /* IN ULONG TitleIndex OPTIONAL, reserved */ + REG_DWORD, + &val, + sizeof(val)); +} + +static NTSTATUS vboxDrvToolIoCompletionSetEvent(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp, IN PVOID pvContext) +{ + RT_NOREF2(pDevObj, pIrp); + PKEVENT pEvent = (PKEVENT)pvContext; + KeSetEvent(pEvent, 0, FALSE); + return STATUS_MORE_PROCESSING_REQUIRED; +} + +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolIoPostAsync(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT pEvent) +{ + IoSetCompletionRoutine(pIrp, vboxDrvToolIoCompletionSetEvent, pEvent, TRUE, TRUE, TRUE); + return IoCallDriver(pDevObj, pIrp); +} + +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolIoPostSync(PDEVICE_OBJECT pDevObj, PIRP pIrp) +{ + KEVENT Event; + KeInitializeEvent(&Event, NotificationEvent, FALSE); + NTSTATUS Status = VBoxDrvToolIoPostAsync(pDevObj, pIrp, &Event); + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + Status = pIrp->IoStatus.Status; + } + return Status; +} + +/* !!!NOTE: the caller MUST be the IRP owner!!! * + * !! one can not post threaded IRPs this way!! */ +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolIoPostSyncWithTimeout(PDEVICE_OBJECT pDevObj, PIRP pIrp, ULONG dwTimeoutMs) +{ + KEVENT Event; + LOG(("post irp (0x%p) to DevObj(0x%p) with timeout (%u)", pIrp, pDevObj, dwTimeoutMs)); + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + NTSTATUS Status = VBoxDrvToolIoPostAsync(pDevObj, pIrp, &Event); + if (Status == STATUS_PENDING) + { + LARGE_INTEGER Interval; + PLARGE_INTEGER pInterval = NULL; + if (dwTimeoutMs != RT_INDEFINITE_WAIT) + { + Interval.QuadPart = -(int64_t) dwTimeoutMs /* ms */ * 10000; + pInterval = &Interval; + } + + Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, pInterval); + if (Status == STATUS_TIMEOUT) + { + WARN(("irp (0x%p) to DevObj(0x%p) was not completed within timeout (%u), cancelling", pIrp, pDevObj, dwTimeoutMs)); + if (!IoCancelIrp(pIrp)) + { + /* this may happen, but this is something the caller with timeout is not expecting */ + WARN(("IoCancelIrp failed")); + } + + /* wait for the IRP to complete */ + KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); + } + else + { + ASSERT_WARN(Status == STATUS_SUCCESS, ("uunexpected Status (0x%x)", Status)); + } + + /* by this time the IRP is completed */ + Status = pIrp->IoStatus.Status; + LOG(("Pending IRP(0x%p) completed with status(0x%x)", pIrp, Status)); + } + else + { + LOG(("IRP(0x%p) completed with status(0x%x)", pIrp, Status)); + } + return Status; +} + +VBOXDRVTOOL_DECL(VOID) VBoxDrvToolRefWaitEqual(PVBOXDRVTOOL_REF pRef, uint32_t u32Val) +{ + LARGE_INTEGER Interval; + Interval.QuadPart = -(int64_t) 2 /* ms */ * 10000; + uint32_t cRefs; + size_t loops = 0; + KTIMER kTimer; + NTSTATUS status = STATUS_SUCCESS; + + KeInitializeTimer(&kTimer); + + while ((cRefs = ASMAtomicReadU32(&pRef->cRefs)) > u32Val && loops < 256) + { + Assert(cRefs >= u32Val); + Assert(cRefs < UINT32_MAX/2); + + KeSetTimer(&kTimer, Interval, NULL); + status = KeWaitForSingleObject(&kTimer, Executive, KernelMode, false, NULL); + Assert(NT_SUCCESS(status)); + loops++; + } +} + +VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolStrCopy(PUNICODE_STRING pDst, CONST PUNICODE_STRING pSrc) +{ + USHORT cbLength = pSrc->Length + sizeof (pDst->Buffer[0]); + pDst->Buffer = (PWCHAR)vboxDrvToolMemAlloc(cbLength); + Assert(pDst->Buffer); + if (pDst->Buffer) + { + RtlMoveMemory(pDst->Buffer, pSrc->Buffer, pSrc->Length); + pDst->Buffer[pSrc->Length / sizeof (pDst->Buffer[0])] = L'\0'; + pDst->Length = pSrc->Length; + pDst->MaximumLength = cbLength; + return STATUS_SUCCESS; + } + return STATUS_NO_MEMORY; +} + +VBOXDRVTOOL_DECL(VOID) VBoxDrvToolStrFree(PUNICODE_STRING pStr) +{ + vboxDrvToolMemFree(pStr->Buffer); +} |