VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxUSB/win/cmn/VBoxDrvTool.cpp

Last change on this file was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.7 KB
Line 
1/* $Id: VBoxDrvTool.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * Windows Driver R0 Tooling.
4 */
5
6/*
7 * Copyright (C) 2011-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37#include "VBoxDrvTool.h"
38
39#include <iprt/assert.h>
40#include <VBox/log.h>
41
42#include "../../../win/VBoxDbgLog.h"
43
44#define VBOXDRVTOOL_MEMTAG 'TDBV'
45
46static PVOID vboxDrvToolMemAlloc(SIZE_T cbBytes)
47{
48 PVOID pvMem = ExAllocatePoolWithTag(NonPagedPool, cbBytes, VBOXDRVTOOL_MEMTAG);
49 Assert(pvMem);
50 return pvMem;
51}
52
53static PVOID vboxDrvToolMemAllocZ(SIZE_T cbBytes)
54{
55 PVOID pvMem = vboxDrvToolMemAlloc(cbBytes);
56 if (pvMem)
57 {
58 RtlZeroMemory(pvMem, cbBytes);
59 }
60 return pvMem;
61}
62
63static VOID vboxDrvToolMemFree(PVOID pvMem)
64{
65 ExFreePoolWithTag(pvMem, VBOXDRVTOOL_MEMTAG);
66}
67
68VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolRegOpenKeyU(OUT PHANDLE phKey, IN PUNICODE_STRING pName, IN ACCESS_MASK fAccess)
69{
70 OBJECT_ATTRIBUTES ObjAttr;
71
72 InitializeObjectAttributes(&ObjAttr, pName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
73
74 return ZwOpenKey(phKey, fAccess, &ObjAttr);
75}
76
77VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolRegOpenKey(OUT PHANDLE phKey, IN PWCHAR pName, IN ACCESS_MASK fAccess)
78{
79 UNICODE_STRING RtlStr;
80 RtlInitUnicodeString(&RtlStr, pName);
81
82 return VBoxDrvToolRegOpenKeyU(phKey, &RtlStr, fAccess);
83}
84
85VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolRegCloseKey(IN HANDLE hKey)
86{
87 return ZwClose(hKey);
88}
89
90VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolRegQueryValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT PULONG pDword)
91{
92 struct
93 {
94 KEY_VALUE_PARTIAL_INFORMATION Info;
95 UCHAR Buf[32]; /* should be enough */
96 } Buf;
97 ULONG cbBuf;
98 UNICODE_STRING RtlStr;
99 RtlInitUnicodeString(&RtlStr, pName);
100 NTSTATUS Status = ZwQueryValueKey(hKey,
101 &RtlStr,
102 KeyValuePartialInformation,
103 &Buf.Info,
104 sizeof(Buf),
105 &cbBuf);
106 if (Status == STATUS_SUCCESS)
107 {
108 if (Buf.Info.Type == REG_DWORD)
109 {
110 Assert(Buf.Info.DataLength == 4);
111 *pDword = *((PULONG)Buf.Info.Data);
112 return STATUS_SUCCESS;
113 }
114 }
115
116 return STATUS_INVALID_PARAMETER;
117}
118
119VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolRegSetValueDword(IN HANDLE hKey, IN PWCHAR pName, OUT ULONG val)
120{
121 UNICODE_STRING RtlStr;
122 RtlInitUnicodeString(&RtlStr, pName);
123 return ZwSetValueKey(hKey, &RtlStr,
124 NULL, /* IN ULONG TitleIndex OPTIONAL, reserved */
125 REG_DWORD,
126 &val,
127 sizeof(val));
128}
129
130static NTSTATUS vboxDrvToolIoCompletionSetEvent(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp, IN PVOID pvContext)
131{
132 RT_NOREF2(pDevObj, pIrp);
133 PKEVENT pEvent = (PKEVENT)pvContext;
134 KeSetEvent(pEvent, 0, FALSE);
135 return STATUS_MORE_PROCESSING_REQUIRED;
136}
137
138VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolIoPostAsync(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT pEvent)
139{
140 IoSetCompletionRoutine(pIrp, vboxDrvToolIoCompletionSetEvent, pEvent, TRUE, TRUE, TRUE);
141 return IoCallDriver(pDevObj, pIrp);
142}
143
144VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolIoPostSync(PDEVICE_OBJECT pDevObj, PIRP pIrp)
145{
146 KEVENT Event;
147 KeInitializeEvent(&Event, NotificationEvent, FALSE);
148 NTSTATUS Status = VBoxDrvToolIoPostAsync(pDevObj, pIrp, &Event);
149 if (Status == STATUS_PENDING)
150 {
151 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
152 Status = pIrp->IoStatus.Status;
153 }
154 return Status;
155}
156
157/* !!!NOTE: the caller MUST be the IRP owner!!! *
158 * !! one can not post threaded IRPs this way!! */
159VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolIoPostSyncWithTimeout(PDEVICE_OBJECT pDevObj, PIRP pIrp, ULONG dwTimeoutMs)
160{
161 KEVENT Event;
162 LOG(("post irp (0x%p) to DevObj(0x%p) with timeout (%u)", pIrp, pDevObj, dwTimeoutMs));
163
164 KeInitializeEvent(&Event, NotificationEvent, FALSE);
165 NTSTATUS Status = VBoxDrvToolIoPostAsync(pDevObj, pIrp, &Event);
166 if (Status == STATUS_PENDING)
167 {
168 LARGE_INTEGER Interval;
169 PLARGE_INTEGER pInterval = NULL;
170 if (dwTimeoutMs != RT_INDEFINITE_WAIT)
171 {
172 Interval.QuadPart = -(int64_t) dwTimeoutMs /* ms */ * 10000;
173 pInterval = &Interval;
174 }
175
176 Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, pInterval);
177 if (Status == STATUS_TIMEOUT)
178 {
179 WARN(("irp (0x%p) to DevObj(0x%p) was not completed within timeout (%u), cancelling", pIrp, pDevObj, dwTimeoutMs));
180 if (!IoCancelIrp(pIrp))
181 {
182 /* this may happen, but this is something the caller with timeout is not expecting */
183 WARN(("IoCancelIrp failed"));
184 }
185
186 /* wait for the IRP to complete */
187 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
188 }
189 else
190 {
191 ASSERT_WARN(Status == STATUS_SUCCESS, ("uunexpected Status (0x%x)", Status));
192 }
193
194 /* by this time the IRP is completed */
195 Status = pIrp->IoStatus.Status;
196 LOG(("Pending IRP(0x%p) completed with status(0x%x)", pIrp, Status));
197 }
198 else
199 {
200 LOG(("IRP(0x%p) completed with status(0x%x)", pIrp, Status));
201 }
202 return Status;
203}
204
205VBOXDRVTOOL_DECL(VOID) VBoxDrvToolRefWaitEqual(PVBOXDRVTOOL_REF pRef, uint32_t u32Val)
206{
207 LARGE_INTEGER Interval;
208 Interval.QuadPart = -(int64_t) 2 /* ms */ * 10000;
209 uint32_t cRefs;
210 size_t loops = 0;
211 KTIMER kTimer;
212 NTSTATUS status = STATUS_SUCCESS;
213
214 KeInitializeTimer(&kTimer);
215
216 while ((cRefs = ASMAtomicReadU32(&pRef->cRefs)) > u32Val && loops < 256)
217 {
218 Assert(cRefs >= u32Val);
219 Assert(cRefs < UINT32_MAX/2);
220
221 KeSetTimer(&kTimer, Interval, NULL);
222 status = KeWaitForSingleObject(&kTimer, Executive, KernelMode, false, NULL);
223 Assert(NT_SUCCESS(status));
224 loops++;
225 }
226}
227
228VBOXDRVTOOL_DECL(NTSTATUS) VBoxDrvToolStrCopy(PUNICODE_STRING pDst, CONST PUNICODE_STRING pSrc)
229{
230 USHORT cbLength = pSrc->Length + sizeof (pDst->Buffer[0]);
231 pDst->Buffer = (PWCHAR)vboxDrvToolMemAlloc(cbLength);
232 Assert(pDst->Buffer);
233 if (pDst->Buffer)
234 {
235 RtlMoveMemory(pDst->Buffer, pSrc->Buffer, pSrc->Length);
236 pDst->Buffer[pSrc->Length / sizeof (pDst->Buffer[0])] = L'\0';
237 pDst->Length = pSrc->Length;
238 pDst->MaximumLength = cbLength;
239 return STATUS_SUCCESS;
240 }
241 return STATUS_NO_MEMORY;
242}
243
244VBOXDRVTOOL_DECL(VOID) VBoxDrvToolStrFree(PUNICODE_STRING pStr)
245{
246 vboxDrvToolMemFree(pStr->Buffer);
247}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use