summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxDrvTool.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxDrvTool.cpp')
-rw-r--r--src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxDrvTool.cpp247
1 files changed, 247 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..63ed595b
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxDrvTool.cpp
@@ -0,0 +1,247 @@
+/* $Id: VBoxDrvTool.cpp $ */
+/** @file
+ * Windows Driver R0 Tooling.
+ */
+
+/*
+ * Copyright (C) 2011-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox 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.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#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);
+}