VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp@ 41216

Last change on this file since 41216 was 41067, checked in by vboxsync, 13 years ago

supdrvOSLdrNotifyOpened so we can record the load address in NVRAM if we choose to.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.3 KB
Line 
1/* $Id: SUPDrv-win.cpp 41067 2012-04-26 11:36:57Z vboxsync $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - Windows NT specifics.
4 */
5
6/*
7 * Copyright (C) 2006-2007 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/*******************************************************************************
28* Header Files *
29*******************************************************************************/
30#define LOG_GROUP LOG_GROUP_SUP_DRV
31#include "../SUPDrvInternal.h"
32#include <excpt.h>
33#include <ntimage.h>
34
35#include <iprt/assert.h>
36#include <iprt/initterm.h>
37#include <iprt/mem.h>
38#include <iprt/process.h>
39#include <iprt/power.h>
40#include <iprt/string.h>
41#include <VBox/log.h>
42
43
44/*******************************************************************************
45* Defined Constants And Macros *
46*******************************************************************************/
47/** The support service name. */
48#define SERVICE_NAME "VBoxDrv"
49/** Win32 Device name. */
50#define DEVICE_NAME "\\\\.\\VBoxDrv"
51/** NT Device name. */
52#define DEVICE_NAME_NT L"\\Device\\VBoxDrv"
53/** Win Symlink name. */
54#define DEVICE_NAME_DOS L"\\DosDevices\\VBoxDrv"
55/** The Pool tag (VBox). */
56#define SUPDRV_NT_POOL_TAG 'xoBV'
57
58
59/*******************************************************************************
60* Structures and Typedefs *
61*******************************************************************************/
62#if 0 //def RT_ARCH_AMD64
63typedef struct SUPDRVEXECMEM
64{
65 PMDL pMdl;
66 void *pvMapping;
67 void *pvAllocation;
68} SUPDRVEXECMEM, *PSUPDRVEXECMEM;
69#endif
70
71
72/*******************************************************************************
73* Internal Functions *
74*******************************************************************************/
75static void _stdcall VBoxDrvNtUnload(PDRIVER_OBJECT pDrvObj);
76static NTSTATUS _stdcall VBoxDrvNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp);
77static NTSTATUS _stdcall VBoxDrvNtCleanup(PDEVICE_OBJECT pDevObj, PIRP pIrp);
78static NTSTATUS _stdcall VBoxDrvNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp);
79static NTSTATUS _stdcall VBoxDrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
80static int VBoxDrvNtDeviceControlSlow(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PIRP pIrp, PIO_STACK_LOCATION pStack);
81static NTSTATUS _stdcall VBoxDrvNtInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
82static VOID _stdcall VBoxPowerDispatchCallback(PVOID pCallbackContext, PVOID pArgument1, PVOID pArgument2);
83static NTSTATUS _stdcall VBoxDrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp);
84static NTSTATUS VBoxDrvNtErr2NtStatus(int rc);
85
86
87/*******************************************************************************
88* Exported Functions *
89*******************************************************************************/
90RT_C_DECLS_BEGIN
91ULONG _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath);
92RT_C_DECLS_END
93
94
95/**
96 * Driver entry point.
97 *
98 * @returns appropriate status code.
99 * @param pDrvObj Pointer to driver object.
100 * @param pRegPath Registry base path.
101 */
102ULONG _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
103{
104 NTSTATUS rc;
105
106 /*
107 * Create device.
108 * (That means creating a device object and a symbolic link so the DOS
109 * subsystems (OS/2, win32, ++) can access the device.)
110 */
111 UNICODE_STRING DevName;
112 RtlInitUnicodeString(&DevName, DEVICE_NAME_NT);
113 PDEVICE_OBJECT pDevObj;
114 rc = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXT), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDevObj);
115 if (NT_SUCCESS(rc))
116 {
117 UNICODE_STRING DosName;
118 RtlInitUnicodeString(&DosName, DEVICE_NAME_DOS);
119 rc = IoCreateSymbolicLink(&DosName, &DevName);
120 if (NT_SUCCESS(rc))
121 {
122 int vrc = RTR0Init(0);
123 if (RT_SUCCESS(vrc))
124 {
125 Log(("VBoxDrv::DriverEntry\n"));
126
127 /*
128 * Initialize the device extension.
129 */
130 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pDevObj->DeviceExtension;
131 memset(pDevExt, 0, sizeof(*pDevExt));
132
133 vrc = supdrvInitDevExt(pDevExt, sizeof(SUPDRVSESSION));
134 if (!vrc)
135 {
136 /*
137 * Setup the driver entry points in pDrvObj.
138 */
139 pDrvObj->DriverUnload = VBoxDrvNtUnload;
140 pDrvObj->MajorFunction[IRP_MJ_CREATE] = VBoxDrvNtCreate;
141 pDrvObj->MajorFunction[IRP_MJ_CLEANUP] = VBoxDrvNtCleanup;
142 pDrvObj->MajorFunction[IRP_MJ_CLOSE] = VBoxDrvNtClose;
143 pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VBoxDrvNtDeviceControl;
144 pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = VBoxDrvNtInternalDeviceControl;
145 pDrvObj->MajorFunction[IRP_MJ_READ] = VBoxDrvNtNotSupportedStub;
146 pDrvObj->MajorFunction[IRP_MJ_WRITE] = VBoxDrvNtNotSupportedStub;
147
148 /* more? */
149
150 /* Register ourselves for power state changes. */
151 UNICODE_STRING CallbackName;
152 OBJECT_ATTRIBUTES Attr;
153
154 RtlInitUnicodeString(&CallbackName, L"\\Callback\\PowerState");
155 InitializeObjectAttributes(&Attr, &CallbackName, OBJ_CASE_INSENSITIVE, NULL, NULL);
156
157 rc = ExCreateCallback(&pDevExt->pObjPowerCallback, &Attr, TRUE, TRUE);
158 if (rc == STATUS_SUCCESS)
159 pDevExt->hPowerCallback = ExRegisterCallback(pDevExt->pObjPowerCallback, VBoxPowerDispatchCallback, pDevObj);
160
161 Log(("VBoxDrv::DriverEntry returning STATUS_SUCCESS\n"));
162 return STATUS_SUCCESS;
163 }
164
165 Log(("supdrvInitDevExit failed with vrc=%d!\n", vrc));
166 rc = VBoxDrvNtErr2NtStatus(vrc);
167
168 IoDeleteSymbolicLink(&DosName);
169 RTR0Term();
170 }
171 else
172 {
173 Log(("RTR0Init failed with vrc=%d!\n", vrc));
174 rc = VBoxDrvNtErr2NtStatus(vrc);
175 }
176 }
177 else
178 Log(("IoCreateSymbolicLink failed with rc=%#x!\n", rc));
179
180 IoDeleteDevice(pDevObj);
181 }
182 else
183 Log(("IoCreateDevice failed with rc=%#x!\n", rc));
184
185 if (NT_SUCCESS(rc))
186 rc = STATUS_INVALID_PARAMETER;
187 Log(("VBoxDrv::DriverEntry returning %#x\n", rc));
188 return rc;
189}
190
191
192/**
193 * Unload the driver.
194 *
195 * @param pDrvObj Driver object.
196 */
197void _stdcall VBoxDrvNtUnload(PDRIVER_OBJECT pDrvObj)
198{
199 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pDrvObj->DeviceObject->DeviceExtension;
200
201 Log(("VBoxDrvNtUnload at irql %d\n", KeGetCurrentIrql()));
202
203 /* Clean up the power callback registration. */
204 if (pDevExt->hPowerCallback)
205 ExUnregisterCallback(pDevExt->hPowerCallback);
206 if (pDevExt->pObjPowerCallback)
207 ObDereferenceObject(pDevExt->pObjPowerCallback);
208
209 /*
210 * We ASSUME that it's not possible to unload a driver with open handles.
211 * Start by deleting the symbolic link
212 */
213 UNICODE_STRING DosName;
214 RtlInitUnicodeString(&DosName, DEVICE_NAME_DOS);
215 NTSTATUS rc = IoDeleteSymbolicLink(&DosName);
216
217 /*
218 * Terminate the GIP page and delete the device extension.
219 */
220 supdrvDeleteDevExt(pDevExt);
221 RTR0Term();
222 IoDeleteDevice(pDrvObj->DeviceObject);
223}
224
225
226/**
227 * Create (i.e. Open) file entry point.
228 *
229 * @param pDevObj Device object.
230 * @param pIrp Request packet.
231 */
232NTSTATUS _stdcall VBoxDrvNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
233{
234 Log(("VBoxDrvNtCreate: RequestorMode=%d\n", pIrp->RequestorMode));
235 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
236 PFILE_OBJECT pFileObj = pStack->FileObject;
237 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pDevObj->DeviceExtension;
238
239 /*
240 * We are not remotely similar to a directory...
241 * (But this is possible.)
242 */
243 if (pStack->Parameters.Create.Options & FILE_DIRECTORY_FILE)
244 {
245 pIrp->IoStatus.Status = STATUS_NOT_A_DIRECTORY;
246 pIrp->IoStatus.Information = 0;
247 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
248 return STATUS_NOT_A_DIRECTORY;
249 }
250
251 /*
252 * Don't create a session for kernel clients, they'll close the handle
253 * immediately and work with the file object via
254 * VBoxDrvNtInternalDeviceControl. The first request will there be one
255 * to create a session.
256 */
257 NTSTATUS rcNt;
258 if (pIrp->RequestorMode == KernelMode)
259 rcNt = STATUS_SUCCESS;
260 else
261 {
262 /*
263 * Call common code for the rest.
264 */
265 pFileObj->FsContext = NULL;
266 PSUPDRVSESSION pSession;
267 int rc = supdrvCreateSession(pDevExt, true /*fUser*/, &pSession);
268 if (!rc)
269 pFileObj->FsContext = pSession;
270 rcNt = pIrp->IoStatus.Status = VBoxDrvNtErr2NtStatus(rc);
271 }
272
273 pIrp->IoStatus.Information = 0;
274 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
275
276 return rcNt;
277}
278
279
280/**
281 * Clean up file handle entry point.
282 *
283 * @param pDevObj Device object.
284 * @param pIrp Request packet.
285 */
286NTSTATUS _stdcall VBoxDrvNtCleanup(PDEVICE_OBJECT pDevObj, PIRP pIrp)
287{
288 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pDevObj->DeviceExtension;
289 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
290 PFILE_OBJECT pFileObj = pStack->FileObject;
291 PSUPDRVSESSION pSession = (PSUPDRVSESSION)pFileObj->FsContext;
292
293 Log(("VBoxDrvNtCleanup: pDevExt=%p pFileObj=%p pSession=%p\n", pDevExt, pFileObj, pSession));
294 if (pSession)
295 {
296 supdrvCloseSession(pDevExt, (PSUPDRVSESSION)pFileObj->FsContext);
297 pFileObj->FsContext = NULL;
298 }
299
300 pIrp->IoStatus.Information = 0;
301 pIrp->IoStatus.Status = STATUS_SUCCESS;
302 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
303
304 return STATUS_SUCCESS;
305}
306
307
308/**
309 * Close file entry point.
310 *
311 * @param pDevObj Device object.
312 * @param pIrp Request packet.
313 */
314NTSTATUS _stdcall VBoxDrvNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
315{
316 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pDevObj->DeviceExtension;
317 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
318 PFILE_OBJECT pFileObj = pStack->FileObject;
319 PSUPDRVSESSION pSession = (PSUPDRVSESSION)pFileObj->FsContext;
320
321 Log(("VBoxDrvNtClose: pDevExt=%p pFileObj=%p pSession=%p\n", pDevExt, pFileObj, pSession));
322 if (pSession)
323 {
324 supdrvCloseSession(pDevExt, (PSUPDRVSESSION)pFileObj->FsContext);
325 pFileObj->FsContext = NULL;
326 }
327
328 pIrp->IoStatus.Information = 0;
329 pIrp->IoStatus.Status = STATUS_SUCCESS;
330 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
331
332 return STATUS_SUCCESS;
333}
334
335
336/**
337 * Device I/O Control entry point.
338 *
339 * @param pDevObj Device object.
340 * @param pIrp Request packet.
341 */
342NTSTATUS _stdcall VBoxDrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
343{
344 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pDevObj->DeviceExtension;
345 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
346 PSUPDRVSESSION pSession = (PSUPDRVSESSION)pStack->FileObject->FsContext;
347
348 /*
349 * Deal with the two high-speed IOCtl that takes it's arguments from
350 * the session and iCmd, and only returns a VBox status code.
351 *
352 * Note: The previous method of returning the rc prior to IOC version
353 * 7.4 has been abandond, we're no longer compatible with that
354 * interface.
355 */
356 ULONG ulCmd = pStack->Parameters.DeviceIoControl.IoControlCode;
357 if ( ulCmd == SUP_IOCTL_FAST_DO_RAW_RUN
358 || ulCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
359 || ulCmd == SUP_IOCTL_FAST_DO_NOP)
360 {
361#ifdef VBOX_WITH_VMMR0_DISABLE_PREEMPTION
362 int rc = supdrvIOCtlFast(ulCmd, (unsigned)(uintptr_t)pIrp->UserBuffer /* VMCPU id */, pDevExt, pSession);
363#else
364 /* Raise the IRQL to DISPATCH_LEVEL to prevent Windows from rescheduling us to another CPU/core. */
365 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
366 KIRQL oldIrql;
367 KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
368 int rc = supdrvIOCtlFast(ulCmd, (unsigned)(uintptr_t)pIrp->UserBuffer /* VMCPU id */, pDevExt, pSession);
369 KeLowerIrql(oldIrql);
370#endif
371
372 /* Complete the I/O request. */
373 NTSTATUS rcNt = pIrp->IoStatus.Status = RT_SUCCESS(rc) ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER;
374 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
375 return rcNt;
376 }
377
378 return VBoxDrvNtDeviceControlSlow(pDevExt, pSession, pIrp, pStack);
379}
380
381
382/**
383 * Worker for VBoxDrvNtDeviceControl that takes the slow IOCtl functions.
384 *
385 * @returns NT status code.
386 *
387 * @param pDevObj Device object.
388 * @param pSession The session.
389 * @param pIrp Request packet.
390 * @param pStack The stack location containing the DeviceControl parameters.
391 */
392static int VBoxDrvNtDeviceControlSlow(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PIRP pIrp, PIO_STACK_LOCATION pStack)
393{
394 NTSTATUS rcNt;
395 unsigned cbOut = 0;
396 int rc = 0;
397 Log2(("VBoxDrvNtDeviceControlSlow(%p,%p): ioctl=%#x pBuf=%p cbIn=%#x cbOut=%#x pSession=%p\n",
398 pDevExt, pIrp, pStack->Parameters.DeviceIoControl.IoControlCode,
399 pIrp->AssociatedIrp.SystemBuffer, pStack->Parameters.DeviceIoControl.InputBufferLength,
400 pStack->Parameters.DeviceIoControl.OutputBufferLength, pSession));
401
402#ifdef RT_ARCH_AMD64
403 /* Don't allow 32-bit processes to do any I/O controls. */
404 if (!IoIs32bitProcess(pIrp))
405#endif
406 {
407 /* Verify that it's a buffered CTL. */
408 if ((pStack->Parameters.DeviceIoControl.IoControlCode & 0x3) == METHOD_BUFFERED)
409 {
410 /* Verify that the sizes in the request header are correct. */
411 PSUPREQHDR pHdr = (PSUPREQHDR)pIrp->AssociatedIrp.SystemBuffer;
412 if ( pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr)
413 && pStack->Parameters.DeviceIoControl.InputBufferLength == pHdr->cbIn
414 && pStack->Parameters.DeviceIoControl.OutputBufferLength == pHdr->cbOut)
415 {
416 /*
417 * Do the job.
418 */
419 rc = supdrvIOCtl(pStack->Parameters.DeviceIoControl.IoControlCode, pDevExt, pSession, pHdr);
420 if (!rc)
421 {
422 rcNt = STATUS_SUCCESS;
423 cbOut = pHdr->cbOut;
424 if (cbOut > pStack->Parameters.DeviceIoControl.OutputBufferLength)
425 {
426 cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
427 OSDBGPRINT(("VBoxDrvLinuxIOCtl: too much output! %#x > %#x; uCmd=%#x!\n",
428 pHdr->cbOut, cbOut, pStack->Parameters.DeviceIoControl.IoControlCode));
429 }
430 }
431 else
432 rcNt = STATUS_INVALID_PARAMETER;
433 Log2(("VBoxDrvNtDeviceControlSlow: returns %#x cbOut=%d rc=%#x\n", rcNt, cbOut, rc));
434 }
435 else
436 {
437 Log(("VBoxDrvNtDeviceControlSlow: Mismatching sizes (%#x) - Hdr=%#lx/%#lx Irp=%#lx/%#lx!\n",
438 pStack->Parameters.DeviceIoControl.IoControlCode,
439 pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cbIn : 0,
440 pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cbOut : 0,
441 pStack->Parameters.DeviceIoControl.InputBufferLength,
442 pStack->Parameters.DeviceIoControl.OutputBufferLength));
443 rcNt = STATUS_INVALID_PARAMETER;
444 }
445 }
446 else
447 {
448 Log(("VBoxDrvNtDeviceControlSlow: not buffered request (%#x) - not supported\n",
449 pStack->Parameters.DeviceIoControl.IoControlCode));
450 rcNt = STATUS_NOT_SUPPORTED;
451 }
452 }
453#ifdef RT_ARCH_AMD64
454 else
455 {
456 Log(("VBoxDrvNtDeviceControlSlow: WOW64 req - not supported\n"));
457 rcNt = STATUS_NOT_SUPPORTED;
458 }
459#endif
460
461 /* complete the request. */
462 pIrp->IoStatus.Status = rcNt;
463 pIrp->IoStatus.Information = cbOut;
464 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
465 return rcNt;
466}
467
468
469/**
470 * Internal Device I/O Control entry point, used for IDC.
471 *
472 * @param pDevObj Device object.
473 * @param pIrp Request packet.
474 */
475NTSTATUS _stdcall VBoxDrvNtInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
476{
477 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pDevObj->DeviceExtension;
478 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
479 PFILE_OBJECT pFileObj = pStack ? pStack->FileObject : NULL;
480 PSUPDRVSESSION pSession = pFileObj ? (PSUPDRVSESSION)pFileObj->FsContext : NULL;
481 NTSTATUS rcNt;
482 unsigned cbOut = 0;
483 int rc = 0;
484 Log2(("VBoxDrvNtInternalDeviceControl(%p,%p): ioctl=%#x pBuf=%p cbIn=%#x cbOut=%#x pSession=%p\n",
485 pDevExt, pIrp, pStack->Parameters.DeviceIoControl.IoControlCode,
486 pIrp->AssociatedIrp.SystemBuffer, pStack->Parameters.DeviceIoControl.InputBufferLength,
487 pStack->Parameters.DeviceIoControl.OutputBufferLength, pSession));
488
489 /* Verify that it's a buffered CTL. */
490 if ((pStack->Parameters.DeviceIoControl.IoControlCode & 0x3) == METHOD_BUFFERED)
491 {
492 /* Verify the pDevExt in the session. */
493 if ( pStack->Parameters.DeviceIoControl.IoControlCode != SUPDRV_IDC_REQ_CONNECT
494 ? VALID_PTR(pSession) && pSession->pDevExt == pDevExt
495 : !pSession
496 )
497 {
498 /* Verify that the size in the request header is correct. */
499 PSUPDRVIDCREQHDR pHdr = (PSUPDRVIDCREQHDR)pIrp->AssociatedIrp.SystemBuffer;
500 if ( pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr)
501 && pStack->Parameters.DeviceIoControl.InputBufferLength == pHdr->cb
502 && pStack->Parameters.DeviceIoControl.OutputBufferLength == pHdr->cb)
503 {
504 /*
505 * Call the generic code.
506 *
507 * Note! Connect and disconnect requires some extra attention
508 * in order to get the session handling right.
509 */
510 if (pStack->Parameters.DeviceIoControl.IoControlCode == SUPDRV_IDC_REQ_DISCONNECT)
511 pFileObj->FsContext = NULL;
512
513 rc = supdrvIDC(pStack->Parameters.DeviceIoControl.IoControlCode, pDevExt, pSession, pHdr);
514 if (!rc)
515 {
516 if (pStack->Parameters.DeviceIoControl.IoControlCode == SUPDRV_IDC_REQ_CONNECT)
517 pFileObj->FsContext = ((PSUPDRVIDCREQCONNECT)pHdr)->u.Out.pSession;
518
519 rcNt = STATUS_SUCCESS;
520 cbOut = pHdr->cb;
521 }
522 else
523 {
524 rcNt = STATUS_INVALID_PARAMETER;
525 if (pStack->Parameters.DeviceIoControl.IoControlCode == SUPDRV_IDC_REQ_DISCONNECT)
526 pFileObj->FsContext = pSession;
527 }
528 Log2(("VBoxDrvNtInternalDeviceControl: returns %#x/rc=%#x\n", rcNt, rc));
529 }
530 else
531 {
532 Log(("VBoxDrvNtInternalDeviceControl: Mismatching sizes (%#x) - Hdr=%#lx Irp=%#lx/%#lx!\n",
533 pStack->Parameters.DeviceIoControl.IoControlCode,
534 pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cb : 0,
535 pStack->Parameters.DeviceIoControl.InputBufferLength,
536 pStack->Parameters.DeviceIoControl.OutputBufferLength));
537 rcNt = STATUS_INVALID_PARAMETER;
538 }
539 }
540 else
541 rcNt = STATUS_NOT_SUPPORTED;
542 }
543 else
544 {
545 Log(("VBoxDrvNtInternalDeviceControl: not buffered request (%#x) - not supported\n",
546 pStack->Parameters.DeviceIoControl.IoControlCode));
547 rcNt = STATUS_NOT_SUPPORTED;
548 }
549
550 /* complete the request. */
551 pIrp->IoStatus.Status = rcNt;
552 pIrp->IoStatus.Information = cbOut;
553 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
554 return rcNt;
555}
556
557
558/**
559 * Stub function for functions we don't implemented.
560 *
561 * @returns STATUS_NOT_SUPPORTED
562 * @param pDevObj Device object.
563 * @param pIrp IRP.
564 */
565NTSTATUS _stdcall VBoxDrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp)
566{
567 Log(("VBoxDrvNtNotSupportedStub\n"));
568 pDevObj = pDevObj;
569
570 pIrp->IoStatus.Information = 0;
571 pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
572 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
573
574 return STATUS_NOT_SUPPORTED;
575}
576
577
578/**
579 * ExRegisterCallback handler for power events
580 *
581 * @param pCallbackContext User supplied parameter (pDevObj)
582 * @param pArgument1 First argument
583 * @param pArgument2 Second argument
584 */
585VOID _stdcall VBoxPowerDispatchCallback(PVOID pCallbackContext, PVOID pArgument1, PVOID pArgument2)
586{
587 PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pCallbackContext;
588
589 Log(("VBoxPowerDispatchCallback: %x %x\n", pArgument1, pArgument2));
590
591 /* Power change imminent? */
592 if ((unsigned)pArgument1 == PO_CB_SYSTEM_STATE_LOCK)
593 {
594 if ((unsigned)pArgument2 == 0)
595 Log(("VBoxPowerDispatchCallback: about to go into suspend mode!\n"));
596 else
597 Log(("VBoxPowerDispatchCallback: resumed!\n"));
598
599 /* Inform any clients that have registered themselves with IPRT. */
600 RTPowerSignalEvent(((unsigned)pArgument2 == 0) ? RTPOWEREVENT_SUSPEND : RTPOWEREVENT_RESUME);
601 }
602}
603
604
605/**
606 * Initializes any OS specific object creator fields.
607 */
608void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
609{
610 NOREF(pObj);
611 NOREF(pSession);
612}
613
614
615/**
616 * Checks if the session can access the object.
617 *
618 * @returns true if a decision has been made.
619 * @returns false if the default access policy should be applied.
620 *
621 * @param pObj The object in question.
622 * @param pSession The session wanting to access the object.
623 * @param pszObjName The object name, can be NULL.
624 * @param prc Where to store the result when returning true.
625 */
626bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
627{
628 NOREF(pObj);
629 NOREF(pSession);
630 NOREF(pszObjName);
631 NOREF(prc);
632 return false;
633}
634
635
636/**
637 * Force async tsc mode (stub).
638 */
639bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
640{
641 return false;
642}
643
644
645#define MY_SystemLoadGdiDriverInSystemSpaceInformation 54
646#define MY_SystemUnloadGdiDriverInformation 27
647
648typedef struct MYSYSTEMGDIDRIVERINFO
649{
650 UNICODE_STRING Name; /**< In: image file name. */
651 PVOID ImageAddress; /**< Out: the load address. */
652 PVOID SectionPointer; /**< Out: section object. */
653 PVOID EntryPointer; /**< Out: entry point address. */
654 PVOID ExportSectionPointer; /**< Out: export directory/section. */
655 ULONG ImageLength; /**< Out: SizeOfImage. */
656} MYSYSTEMGDIDRIVERINFO;
657
658extern "C" __declspec(dllimport) NTSTATUS NTAPI ZwSetSystemInformation(ULONG, PVOID, ULONG);
659
660int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
661{
662 pImage->pvNtSectionObj = NULL;
663 pImage->hMemLock = NIL_RTR0MEMOBJ;
664
665#ifdef VBOX_WITHOUT_NATIVE_R0_LOADER
666# ifndef RT_ARCH_X86
667# error "VBOX_WITHOUT_NATIVE_R0_LOADER is only safe on x86."
668# endif
669 NOREF(pDevExt); NOREF(pszFilename); NOREF(pImage);
670 return VERR_NOT_SUPPORTED;
671
672#else
673 /*
674 * Convert the filename from DOS UTF-8 to NT UTF-16.
675 */
676 size_t cwcFilename;
677 int rc = RTStrCalcUtf16LenEx(pszFilename, RTSTR_MAX, &cwcFilename);
678 if (RT_FAILURE(rc))
679 return rc;
680
681 PRTUTF16 pwcsFilename = (PRTUTF16)RTMemTmpAlloc((4 + cwcFilename + 1) * sizeof(RTUTF16));
682 if (!pwcsFilename)
683 return VERR_NO_TMP_MEMORY;
684
685 pwcsFilename[0] = '\\';
686 pwcsFilename[1] = '?';
687 pwcsFilename[2] = '?';
688 pwcsFilename[3] = '\\';
689 PRTUTF16 pwcsTmp = &pwcsFilename[4];
690 rc = RTStrToUtf16Ex(pszFilename, RTSTR_MAX, &pwcsTmp, cwcFilename + 1, NULL);
691 if (RT_SUCCESS(rc))
692 {
693 /*
694 * Try load it.
695 */
696 MYSYSTEMGDIDRIVERINFO Info;
697 RtlInitUnicodeString(&Info.Name, pwcsFilename);
698 Info.ImageAddress = NULL;
699 Info.SectionPointer = NULL;
700 Info.EntryPointer = NULL;
701 Info.ExportSectionPointer = NULL;
702 Info.ImageLength = 0;
703
704 NTSTATUS rcNt = ZwSetSystemInformation(MY_SystemLoadGdiDriverInSystemSpaceInformation, &Info, sizeof(Info));
705 if (NT_SUCCESS(rcNt))
706 {
707 pImage->pvImage = Info.ImageAddress;
708 pImage->pvNtSectionObj = Info.SectionPointer;
709 Log(("ImageAddress=%p SectionPointer=%p ImageLength=%#x cbImageBits=%#x rcNt=%#x '%ls'\n",
710 Info.ImageAddress, Info.SectionPointer, Info.ImageLength, pImage->cbImageBits, rcNt, Info.Name.Buffer));
711# ifdef DEBUG_bird
712 SUPR0Printf("ImageAddress=%p SectionPointer=%p ImageLength=%#x cbImageBits=%#x rcNt=%#x '%ws'\n",
713 Info.ImageAddress, Info.SectionPointer, Info.ImageLength, pImage->cbImageBits, rcNt, Info.Name.Buffer);
714# endif
715 if (pImage->cbImageBits == Info.ImageLength)
716 {
717 /*
718 * Lock down the entire image, just to be on the safe side.
719 */
720 rc = RTR0MemObjLockKernel(&pImage->hMemLock, pImage->pvImage, pImage->cbImageBits, RTMEM_PROT_READ);
721 if (RT_FAILURE(rc))
722 {
723 pImage->hMemLock = NIL_RTR0MEMOBJ;
724 supdrvOSLdrUnload(pDevExt, pImage);
725 }
726 }
727 else
728 {
729 supdrvOSLdrUnload(pDevExt, pImage);
730 rc = VERR_LDR_MISMATCH_NATIVE;
731 }
732 }
733 else
734 {
735 Log(("rcNt=%#x '%ls'\n", rcNt, pwcsFilename));
736 SUPR0Printf("VBoxDrv: rcNt=%x '%ws'\n", rcNt, pwcsFilename);
737 switch (rcNt)
738 {
739 case /* 0xc0000003 */ STATUS_INVALID_INFO_CLASS:
740# ifdef RT_ARCH_AMD64
741 /* Unwind will crash and BSOD, so no fallback here! */
742 rc = VERR_NOT_IMPLEMENTED;
743# else
744 /*
745 * Use the old way of loading the modules.
746 *
747 * Note! We do *NOT* try class 26 because it will probably
748 * not work correctly on terminal servers and such.
749 */
750 rc = VERR_NOT_SUPPORTED;
751# endif
752 break;
753 case /* 0xc0000034 */ STATUS_OBJECT_NAME_NOT_FOUND:
754 rc = VERR_MODULE_NOT_FOUND;
755 break;
756 case /* 0xC0000263 */ STATUS_DRIVER_ENTRYPOINT_NOT_FOUND:
757 rc = VERR_LDR_IMPORTED_SYMBOL_NOT_FOUND;
758 break;
759 case 0xC0000428 /* STATUS_INVALID_IMAGE_HASH */ :
760 rc = VERR_LDR_IMAGE_HASH;
761 break;
762 case 0xC000010E /* STATUS_IMAGE_ALREADY_LOADED */ :
763 Log(("WARNING: see #4853 for cause of this failure on Windows 7 x64\n"));
764 rc = VERR_ALREADY_LOADED;
765 break;
766 default:
767 rc = VERR_LDR_GENERAL_FAILURE;
768 break;
769 }
770
771 pImage->pvNtSectionObj = NULL;
772 }
773 }
774
775 RTMemTmpFree(pwcsFilename);
776 NOREF(pDevExt);
777 return rc;
778#endif
779}
780
781
782void VBOXCALL supdrvOSLdrNotifyOpened(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
783{
784 NOREF(pDevExt); NOREF(pImage);
785}
786
787
788int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, const uint8_t *pbImageBits)
789{
790 NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits);
791 return VINF_SUCCESS;
792}
793
794
795/**
796 * memcmp + log.
797 *
798 * @returns Same as memcmp.
799 * @param pImage The image.
800 * @param pbImageBits The image bits ring-3 uploads.
801 * @param uRva The RVA to start comparing at.
802 * @param cb The number of bytes to compare.
803 */
804static int supdrvNtCompare(PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, uint32_t uRva, uint32_t cb)
805{
806 int iDiff = memcmp((uint8_t const *)pImage->pvImage + uRva, pbImageBits + uRva, cb);
807 if (iDiff)
808 {
809 uint32_t cbLeft = cb;
810 const uint8_t *pbNativeBits = (const uint8_t *)pImage->pvImage;
811 for (size_t off = uRva; cbLeft > 0; off++, cbLeft--)
812 if (pbNativeBits[off] != pbImageBits[off])
813 {
814 char szBytes[128];
815 RTStrPrintf(szBytes, sizeof(szBytes), "native: %.*Rhxs our: %.*Rhxs",
816 RT_MIN(12, cbLeft), &pbNativeBits[off],
817 RT_MIN(12, cbLeft), &pbImageBits[off]);
818 SUPR0Printf("VBoxDrv: Mismatch at %#x of %s: %s\n", off, pImage->szName, szBytes);
819 break;
820 }
821 }
822 return iDiff;
823}
824
825int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
826{
827 NOREF(pDevExt); NOREF(pReq);
828 if (pImage->pvNtSectionObj)
829 {
830 /*
831 * Usually, the entire image matches exactly.
832 */
833 if (!memcmp(pImage->pvImage, pbImageBits, pImage->cbImageBits))
834 return VINF_SUCCESS;
835
836 /*
837 * However, on Windows Server 2003 (sp2 x86) both import thunk tables
838 * are fixed up and we typically get a mismatch in the INIT section.
839 *
840 * So, lets see if everything matches when excluding the
841 * OriginalFirstThunk tables. To make life simpler, set the max number
842 * of imports to 16 and just record and sort the locations that needs
843 * to be excluded from the comparison.
844 */
845 IMAGE_NT_HEADERS const *pNtHdrs;
846 pNtHdrs = (IMAGE_NT_HEADERS const *)(pbImageBits
847 + ( *(uint16_t *)pbImageBits == IMAGE_DOS_SIGNATURE
848 ? ((IMAGE_DOS_HEADER const *)pbImageBits)->e_lfanew
849 : 0));
850 if ( pNtHdrs->Signature == IMAGE_NT_SIGNATURE
851 && pNtHdrs->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC
852 && pNtHdrs->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IMPORT
853 && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size >= sizeof(IMAGE_IMPORT_DESCRIPTOR)
854 && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress > sizeof(IMAGE_NT_HEADERS)
855 && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress < pImage->cbImageBits
856 )
857 {
858 struct MyRegion
859 {
860 uint32_t uRva;
861 uint32_t cb;
862 } aExcludeRgns[16];
863 unsigned cExcludeRgns = 0;
864 uint32_t cImpsLeft = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
865 / sizeof(IMAGE_IMPORT_DESCRIPTOR);
866 IMAGE_IMPORT_DESCRIPTOR const *pImp;
867 pImp = (IMAGE_IMPORT_DESCRIPTOR const *)(pbImageBits
868 + pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
869 while ( cImpsLeft-- > 0
870 && cExcludeRgns < RT_ELEMENTS(aExcludeRgns))
871 {
872 uint32_t uRvaThunk = pImp->OriginalFirstThunk;
873 if ( uRvaThunk > sizeof(IMAGE_NT_HEADERS)
874 && uRvaThunk <= pImage->cbImageBits - sizeof(IMAGE_THUNK_DATA)
875 && uRvaThunk != pImp->FirstThunk)
876 {
877 /* Find the size of the thunk table. */
878 IMAGE_THUNK_DATA const *paThunk = (IMAGE_THUNK_DATA const *)(pbImageBits + uRvaThunk);
879 uint32_t cMaxThunks = (pImage->cbImageBits - uRvaThunk) / sizeof(IMAGE_THUNK_DATA);
880 uint32_t cThunks = 0;
881 while (cThunks < cMaxThunks && paThunk[cThunks].u1.Function != 0)
882 cThunks++;
883
884 /* Ordered table insert. */
885 unsigned i = 0;
886 for (; i < cExcludeRgns; i++)
887 if (uRvaThunk < aExcludeRgns[i].uRva)
888 break;
889 if (i != cExcludeRgns)
890 memmove(&aExcludeRgns[i + 1], &aExcludeRgns[i], (cExcludeRgns - i) * sizeof(aExcludeRgns[0]));
891 aExcludeRgns[i].uRva = uRvaThunk;
892 aExcludeRgns[i].cb = cThunks * sizeof(IMAGE_THUNK_DATA);
893 cExcludeRgns++;
894 }
895
896 /* advance */
897 pImp++;
898 }
899
900 /*
901 * Ok, do the comparison.
902 */
903 int iDiff = 0;
904 uint32_t uRvaNext = 0;
905 for (unsigned i = 0; !iDiff && i < cExcludeRgns; i++)
906 {
907 if (uRvaNext < aExcludeRgns[i].uRva)
908 iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, aExcludeRgns[i].uRva - uRvaNext);
909 uRvaNext = aExcludeRgns[i].uRva + aExcludeRgns[i].cb;
910 }
911 if (!iDiff && uRvaNext < pImage->cbImageBits)
912 iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, pImage->cbImageBits - uRvaNext);
913 if (!iDiff)
914 return VINF_SUCCESS;
915 }
916 else
917 supdrvNtCompare(pImage, pbImageBits, 0, pImage->cbImageBits);
918 return VERR_LDR_MISMATCH_NATIVE;
919 }
920 return VERR_INTERNAL_ERROR_4;
921}
922
923
924void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
925{
926 if (pImage->pvNtSectionObj)
927 {
928 if (pImage->hMemLock != NIL_RTR0MEMOBJ)
929 {
930 RTR0MemObjFree(pImage->hMemLock, false /*fFreeMappings*/);
931 pImage->hMemLock = NIL_RTR0MEMOBJ;
932 }
933
934 NTSTATUS rcNt = ZwSetSystemInformation(MY_SystemUnloadGdiDriverInformation,
935 &pImage->pvNtSectionObj, sizeof(pImage->pvNtSectionObj));
936 if (rcNt != STATUS_SUCCESS)
937 SUPR0Printf("VBoxDrv: failed to unload '%s', rcNt=%#x\n", pImage->szName, rcNt);
938 pImage->pvNtSectionObj = NULL;
939 }
940 NOREF(pDevExt);
941}
942
943
944/**
945 * Converts an IPRT error code to an nt status code.
946 *
947 * @returns corresponding nt status code.
948 * @param rc IPRT error status code.
949 */
950static NTSTATUS VBoxDrvNtErr2NtStatus(int rc)
951{
952 switch (rc)
953 {
954 case VINF_SUCCESS: return STATUS_SUCCESS;
955 case VERR_GENERAL_FAILURE: return STATUS_NOT_SUPPORTED;
956 case VERR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER;
957 case VERR_INVALID_MAGIC: return STATUS_UNKNOWN_REVISION;
958 case VERR_INVALID_HANDLE: return STATUS_INVALID_HANDLE;
959 case VERR_INVALID_POINTER: return STATUS_INVALID_ADDRESS;
960 case VERR_LOCK_FAILED: return STATUS_NOT_LOCKED;
961 case VERR_ALREADY_LOADED: return STATUS_IMAGE_ALREADY_LOADED;
962 case VERR_PERMISSION_DENIED: return STATUS_ACCESS_DENIED;
963 case VERR_VERSION_MISMATCH: return STATUS_REVISION_MISMATCH;
964 }
965
966 return STATUS_UNSUCCESSFUL;
967}
968
969
970
971/** @todo use the nocrt stuff? */
972int VBOXCALL mymemcmp(const void *pv1, const void *pv2, size_t cb)
973{
974 const uint8_t *pb1 = (const uint8_t *)pv1;
975 const uint8_t *pb2 = (const uint8_t *)pv2;
976 for (; cb > 0; cb--, pb1++, pb2++)
977 if (*pb1 != *pb2)
978 return *pb1 - *pb2;
979 return 0;
980}
981
982
983#if 0 /* See alternative in SUPDrvA-win.asm */
984/**
985 * Alternative version of SUPR0Printf for Windows.
986 *
987 * @returns 0.
988 * @param pszFormat The format string.
989 */
990SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...)
991{
992 va_list va;
993 char szMsg[512];
994
995 va_start(va, pszFormat);
996 size_t cch = RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
997 szMsg[sizeof(szMsg) - 1] = '\0';
998 va_end(va);
999
1000 RTLogWriteDebugger(szMsg, cch);
1001 return 0;
1002}
1003#endif
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette