VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxGuest/VBoxGuestPnP.cpp@ 3062

Last change on this file since 3062 was 3062, checked in by vboxsync, 17 years ago

Must return the same value as set in the io status structure. (Driver Verifier warning)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.3 KB
Line 
1/** @file
2 *
3 * VBoxGuest -- VirtualBox Win32 guest support driver PnP code
4 *
5 * Copyright (C) 2006-2007 innotek GmbH
6 *
7 * This file is part of VirtualBox Open Source Edition (OSE), as
8 * available from http://www.virtualbox.org. This file is free software;
9 * you can redistribute it and/or modify it under the terms of the GNU
10 * General Public License as published by the Free Software Foundation,
11 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
12 * distribution. VirtualBox OSE is distributed in the hope that it will
13 * be useful, but WITHOUT ANY WARRANTY of any kind.
14 *
15 * If you received this file as part of a commercial VirtualBox
16 * distribution, then only the terms of your commercial VirtualBox
17 * license agreement apply instead of the previous paragraph.
18 *
19 */
20
21// enable backdoor logging
22//#define LOG_ENABLED
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#include "VBoxGuestPnP.h"
28#include "Helper.h"
29#include <VBox/err.h>
30
31#include <VBox/VBoxGuestLib.h>
32
33/*******************************************************************************
34* Defined Constants And Macros *
35*******************************************************************************/
36
37
38extern "C"
39{
40static NTSTATUS sendIrpSynchronously(PDEVICE_OBJECT pDevObj, PIRP pIrp, BOOLEAN fStrict);
41static NTSTATUS pnpIrpComplete(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT event);
42static VOID showDeviceResources(PCM_PARTIAL_RESOURCE_LIST pResourceList);
43}
44
45#ifdef ALLOC_PRAGMA
46#pragma alloc_text (PAGE, VBoxGuestPnP)
47#pragma alloc_text (PAGE, VBoxGuestPower)
48#pragma alloc_text (PAGE, sendIrpSynchronously)
49#pragma alloc_text (PAGE, pnpIrpComplete)
50#pragma alloc_text (PAGE, showDeviceResources)
51#endif
52
53/* reenable logging, this was #undef'ed on iprt/log.h for RING0 */
54#define LOG_ENABLED
55
56/*******************************************************************************
57* Internal Functions *
58*******************************************************************************/
59
60/**
61 * Irp completion routine for PnP Irps we send.
62 *
63 * @param pDevObj Device object.
64 * @param pIrp Request packet.
65 * @param event Semaphore.
66 * @return NT status code
67 */
68static NTSTATUS pnpIrpComplete(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT event)
69{
70 KeSetEvent(event, 0, FALSE);
71 return STATUS_MORE_PROCESSING_REQUIRED;
72}
73
74/**
75 * Helper to send a PnP IRP and wait until it's done.
76 *
77 * @param pDevObj Device object.
78 * @param pIrp Request packet.
79 * @param fStrict When set, returns an error if the IRP gives an error.
80 * @return NT status code
81 */
82static NTSTATUS sendIrpSynchronously(PDEVICE_OBJECT pDevObj, PIRP pIrp, BOOLEAN fStrict)
83{
84 KEVENT event;
85
86 KeInitializeEvent(&event, SynchronizationEvent, FALSE);
87
88 IoCopyCurrentIrpStackLocationToNext(pIrp);
89 IoSetCompletionRoutine(pIrp, (PIO_COMPLETION_ROUTINE)pnpIrpComplete, &event, TRUE, TRUE, TRUE);
90
91 NTSTATUS rc = IoCallDriver(pDevObj, pIrp);
92
93 if (rc == STATUS_PENDING)
94 {
95 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
96 rc = pIrp->IoStatus.Status;
97 }
98
99 if (!fStrict
100 && (rc == STATUS_NOT_SUPPORTED || rc == STATUS_INVALID_DEVICE_REQUEST))
101 {
102 rc = STATUS_SUCCESS;
103 }
104
105 dprintf(("VBoxGuest::sendIrpSynchronously: returning 0x%x\n", rc));
106
107 return rc;
108}
109
110
111/**
112 * PnP Request handler.
113 *
114 * @param pDevObj Device object.
115 * @param pIrp Request packet.
116 */
117NTSTATUS VBoxGuestPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
118{
119 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
120 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
121 NTSTATUS rc = STATUS_SUCCESS;
122
123#ifdef LOG_ENABLED
124 static char* fcnname[] =
125 {
126 "IRP_MN_START_DEVICE",
127 "IRP_MN_QUERY_REMOVE_DEVICE",
128 "IRP_MN_REMOVE_DEVICE",
129 "IRP_MN_CANCEL_REMOVE_DEVICE",
130 "IRP_MN_STOP_DEVICE",
131 "IRP_MN_QUERY_STOP_DEVICE",
132 "IRP_MN_CANCEL_STOP_DEVICE",
133 "IRP_MN_QUERY_DEVICE_RELATIONS",
134 "IRP_MN_QUERY_INTERFACE",
135 "IRP_MN_QUERY_CAPABILITIES",
136 "IRP_MN_QUERY_RESOURCES",
137 "IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
138 "IRP_MN_QUERY_DEVICE_TEXT",
139 "IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
140 "",
141 "IRP_MN_READ_CONFIG",
142 "IRP_MN_WRITE_CONFIG",
143 "IRP_MN_EJECT",
144 "IRP_MN_SET_LOCK",
145 "IRP_MN_QUERY_ID",
146 "IRP_MN_QUERY_PNP_DEVICE_STATE",
147 "IRP_MN_QUERY_BUS_INFORMATION",
148 "IRP_MN_DEVICE_USAGE_NOTIFICATION",
149 "IRP_MN_SURPRISE_REMOVAL",
150 };
151 dprintf(("VBoxGuest::VBoxGuestPnp: MinorFunction: %s\n", pStack->MinorFunction < (sizeof(fcnname)/sizeof(fcnname[0])) ? fcnname[pStack->MinorFunction] : "unknown"));
152#endif
153 switch (pStack->MinorFunction)
154 {
155 case IRP_MN_START_DEVICE:
156 {
157 rc = sendIrpSynchronously(pDevExt->nextLowerDriver, pIrp, TRUE);
158
159 if (NT_SUCCESS(rc) && NT_SUCCESS(pIrp->IoStatus.Status))
160 {
161 dprintf(("VBoxGuest::START_DEVICE: pStack->Parameters.StartDevice.AllocatedResources = %p\n", pStack->Parameters.StartDevice.AllocatedResources));
162
163 if (!pStack->Parameters.StartDevice.AllocatedResources)
164 {
165 dprintf(("VBoxGuest::START_DEVICE: no resources, pDevExt = %p, nextLowerDriver = %p!!!\n", pDevExt, pDevExt? pDevExt->nextLowerDriver: NULL));
166 rc = STATUS_UNSUCCESSFUL;
167 }
168 else
169 {
170 showDeviceResources(&pStack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList);
171
172 VBoxScanPCIResourceList(pStack->Parameters.StartDevice.AllocatedResourcesTranslated,
173 pDevExt);
174
175 /** @todo cleanup and merging codepath with NT */
176 int rcVBox;
177 rcVBox = VbglInit (pDevExt->startPortAddress, pDevExt->pVMMDevMemory);
178 if (!VBOX_SUCCESS(rcVBox))
179 {
180 dprintf(("VBoxGuest::START_DEVICE: VbglInit failed. rcVBox = %d\n", rcVBox));
181 rc = STATUS_UNSUCCESSFUL;
182 }
183
184 if (NT_SUCCESS(rc))
185 {
186 rcVBox = VbglGRAlloc ((VMMDevRequestHeader **)&pDevExt->irqAckEvents, sizeof (VMMDevEvents), VMMDevReq_AcknowledgeEvents);
187 if (!VBOX_SUCCESS(rc))
188 {
189 dprintf(("VBoxGuest::START_DEVICE: VbglAlloc failed. rcVBox = %d\n", rcVBox));
190 rc = STATUS_UNSUCCESSFUL;
191 }
192 }
193
194 if (NT_SUCCESS(rc))
195 {
196 // Map physical address of VMMDev memory
197 rc = hlpVBoxMapVMMDevMemory(pDevExt);
198 if (!NT_SUCCESS(rc))
199 {
200 dprintf(("VBoxGuest::START_DEVICE: can't map physical memory, rc = %d\n", rc));
201 }
202 }
203
204 if (NT_SUCCESS(rc))
205 {
206 rc = hlpVBoxReportGuestInfo (pDevExt);
207 if (!NT_SUCCESS(rc))
208 {
209 dprintf(("VBoxGuest::START_DEVICE: could not report information to host, rc = %d\n", rc));
210 }
211 }
212
213 if (NT_SUCCESS(rc))
214 {
215 // register DPC and ISR
216 dprintf(("VBoxGuest::VBoxGuestPnp: initializing DPC...\n"));
217 IoInitializeDpcRequest(pDevExt->deviceObject, VBoxGuestDpcHandler);
218
219 rc = IoConnectInterrupt(&pDevExt->interruptObject, // out: interrupt object
220 (PKSERVICE_ROUTINE)VBoxGuestIsrHandler, // ISR
221 pDevExt, // context
222 NULL, // optional spinlock
223 pDevExt->interruptVector, // interrupt vector
224 (KIRQL)pDevExt->interruptLevel, // interrupt level
225 (KIRQL)pDevExt->interruptLevel, // interrupt level
226 pDevExt->interruptMode, // LevelSensitive or Latched
227 TRUE, // shareable interrupt
228 pDevExt->interruptAffinity, // CPU affinity
229 FALSE); // don't save FPU stack
230 if (!NT_SUCCESS(rc))
231 {
232 dprintf(("VBoxGuest::VBoxGuestPnp: could not connect interrupt: rc = 0x%x\n", rc));
233 }
234 }
235 }
236 }
237 if (NT_SUCCESS(rc))
238 {
239 createThreads(pDevExt);
240
241 // initialize the event notification semaphore
242 KeInitializeEvent(&pDevExt->keventNotification, NotificationEvent, FALSE);
243
244 // ready to rumble!
245 dprintf(("VBoxGuest::VBoxGuestPnp: device is ready!\n"));
246 pDevExt->devState = WORKING;
247 } else
248 {
249 dprintf(("VBoxGuest::VBoxGuestPnp: error: rc = 0x%x\n", rc));
250
251 // need to unmap memory in case of errors
252 hlpVBoxUnmapVMMDevMemory (pDevExt);
253 }
254 pIrp->IoStatus.Status = rc;
255 pIrp->IoStatus.Information = 0;
256 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
257 break;
258 }
259
260 case IRP_MN_QUERY_REMOVE_DEVICE:
261 {
262#ifdef VBOX_REBOOT_ON_UNINSTALL
263 /* The device can not be removed without a reboot. */
264 if (pDevExt->devState == WORKING)
265 {
266 pDevExt->devState = PENDINGREMOVE;
267 }
268 pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
269 pIrp->IoStatus.Information = 0;
270 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
271 rc = STATUS_UNSUCCESSFUL;
272
273 dprintf(("VBoxGuest::VBoxGuestPnp: refuse with rc = %p\n", pIrp->IoStatus.Status));
274#else
275 pIrp->IoStatus.Status = STATUS_SUCCESS;
276 if (pDevExt->devState == WORKING)
277 {
278 pDevExt->devState = PENDINGREMOVE;
279 }
280 IoSkipCurrentIrpStackLocation(pIrp);
281 rc = IoCallDriver(pDevExt->nextLowerDriver, pIrp);
282#endif /* VBOX_REBOOT_ON_UNINSTALL */
283 break;
284 }
285
286 case IRP_MN_REMOVE_DEVICE:
287 {
288 /* @todo merge Remove and Stop, make a helper for common actions */
289 pIrp->IoStatus.Status = STATUS_SUCCESS;
290
291 unreserveHypervisorMemory(pDevExt);
292
293 if (pDevExt->workerThread)
294 {
295 dprintf(("VBoxGuest::VBoxGuestPnp: waiting for the worker thread to terminate...\n"));
296 pDevExt->stopThread = TRUE;
297 KeSetEvent(&pDevExt->workerThreadRequest, 0, FALSE);
298 KeWaitForSingleObject(pDevExt->workerThread,
299 Executive, KernelMode, FALSE, NULL);
300 dprintf(("VBoxGuest::VBoxGuestPnp: returned from KeWaitForSingleObject for worker thread\n"));
301 }
302
303 if (pDevExt->idleThread)
304 {
305 dprintf(("VBoxGuest::VBoxGuestPnp: waiting for the idle thread to terminate...\n"));
306 pDevExt->stopThread = TRUE;
307 KeWaitForSingleObject(pDevExt->idleThread,
308 Executive, KernelMode, FALSE, NULL);
309 dprintf(("VBoxGuest::VBoxGuestPnp: returned from KeWaitForSingleObject for idle thread\n"));
310 }
311
312 VbglTerminate ();
313
314 // according to MSDN we have to unmap previously mapped memory
315 hlpVBoxUnmapVMMDevMemory (pDevExt);
316
317 if (pDevExt->nextLowerDriver != NULL)
318 {
319 IoDetachDevice(pDevExt->nextLowerDriver);
320 }
321 UNICODE_STRING win32Name;
322 RtlInitUnicodeString(&win32Name, VBOXGUEST_DEVICE_NAME_DOS);
323 IoDeleteSymbolicLink(&win32Name);
324 IoDeleteDevice(pDevObj);
325 pDevExt->devState = REMOVED;
326 IoSkipCurrentIrpStackLocation(pIrp);
327 rc = IoCallDriver(pDevExt->nextLowerDriver, pIrp);
328 break;
329 }
330
331 case IRP_MN_QUERY_STOP_DEVICE:
332 {
333#ifdef VBOX_REBOOT_ON_UNINSTALL
334 dprintf(("VBoxGuest::VBoxGuestPnp: refuse\n"));
335 /* The device can not be stopped without a reboot. */
336 if (pDevExt->devState == WORKING)
337 {
338 pDevExt->devState = PENDINGSTOP;
339 }
340 pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
341 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
342 rc = STATUS_UNSUCCESSFUL;
343#else
344 pIrp->IoStatus.Status = STATUS_SUCCESS;
345 if (pDevExt->devState == WORKING)
346 {
347 pDevExt->devState = PENDINGSTOP;
348 }
349 IoSkipCurrentIrpStackLocation(pIrp);
350 rc = IoCallDriver(pDevExt->nextLowerDriver, pIrp);
351#endif /* VBOX_REBOOT_ON_UNINSTALL */
352 break;
353 }
354
355 case IRP_MN_STOP_DEVICE:
356 {
357 pIrp->IoStatus.Status = STATUS_SUCCESS;
358 if (pDevExt->devState == PENDINGSTOP)
359 {
360 VbglTerminate ();
361
362 // according to MSDN we have to unmap previously mapped memory
363 hlpVBoxUnmapVMMDevMemory (pDevExt);
364
365 pDevExt->devState = STOPPED;
366 dprintf(("VBoxGuest::VBoxGuestPnp: device has been disabled\n"));
367 } else
368 {
369 dprintf(("VBoxGuest::VBoxGuestPnp: devState not PENDINGSTOP but %d\n", pDevExt->devState));
370 }
371 IoSkipCurrentIrpStackLocation(pIrp);
372 rc = IoCallDriver(pDevExt->nextLowerDriver, pIrp);
373 break;
374 }
375
376 default:
377 {
378 IoSkipCurrentIrpStackLocation(pIrp);
379 rc = IoCallDriver(pDevExt->nextLowerDriver, pIrp);
380 }
381
382 }
383 return rc;
384}
385
386
387/**
388 * Debug helper to dump a device resource list.
389 *
390 * @param pResourceList list of device resources.
391 */
392static VOID showDeviceResources(PCM_PARTIAL_RESOURCE_LIST pResourceList)
393{
394#ifdef LOG_ENABLED
395 PCM_PARTIAL_RESOURCE_DESCRIPTOR resource = pResourceList->PartialDescriptors;
396 ULONG nres = pResourceList->Count;
397 ULONG i;
398
399 for (i = 0; i < nres; ++i, ++resource)
400 {
401 ULONG type = resource->Type;
402
403 static char* name[] =
404 {
405 "CmResourceTypeNull",
406 "CmResourceTypePort",
407 "CmResourceTypeInterrupt",
408 "CmResourceTypeMemory",
409 "CmResourceTypeDma",
410 "CmResourceTypeDeviceSpecific",
411 "CmResourceTypeBusNumber",
412 "CmResourceTypeDevicePrivate",
413 "CmResourceTypeAssignedResource",
414 "CmResourceTypeSubAllocateFrom",
415 };
416
417 dprintf(("VBoxGuest::showDeviceResources: type %s", type < (sizeof(name)/sizeof(name[0])) ? name[type] : "unknown"));
418
419 switch (type)
420 {
421 case CmResourceTypePort:
422 case CmResourceTypeMemory:
423 dprintf(("VBoxGuest::showDeviceResources: start %8X%8.8lX length %X\n",
424 resource->u.Port.Start.HighPart, resource->u.Port.Start.LowPart,
425 resource->u.Port.Length));
426 break;
427
428 case CmResourceTypeInterrupt:
429 dprintf(("VBoxGuest::showDeviceResources: level %X, vector %X, affinity %X\n",
430 resource->u.Interrupt.Level, resource->u.Interrupt.Vector,
431 resource->u.Interrupt.Affinity));
432 break;
433
434 case CmResourceTypeDma:
435 dprintf(("VBoxGuest::showDeviceResources: channel %d, port %X\n",
436 resource->u.Dma.Channel, resource->u.Dma.Port));
437 break;
438
439 default:
440 dprintf(("\n"));
441 break;
442 }
443 }
444#endif
445}
446
447/**
448 * Handle the power completion event.
449 *
450 * @returns NT status code
451 * @param devObj targetted device object
452 * @param irp IO request packet
453 * @param context context value passed to IoSetCompletionRoutine in VBoxGuestPower
454 */
455NTSTATUS VBoxGuestPowerComplete(IN PDEVICE_OBJECT devObj,
456 IN PIRP irp, IN PVOID context)
457{
458 PIO_STACK_LOCATION irpSp;
459 PVBOXGUESTDEVEXT devExt = (PVBOXGUESTDEVEXT)context;
460
461 ASSERT(devExt);
462 ASSERT(devExt->signature == DEVICE_EXTENSION_SIGNATURE);
463
464 irpSp = IoGetCurrentIrpStackLocation(irp);
465 ASSERT(irpSp->MajorFunction == IRP_MJ_POWER);
466
467 if (NT_SUCCESS(irp->IoStatus.Status))
468 {
469 switch (irpSp->MinorFunction)
470 {
471 case IRP_MN_SET_POWER:
472
473 switch (irpSp->Parameters.Power.Type)
474 {
475 case DevicePowerState:
476 switch (irpSp->Parameters.Power.State.DeviceState)
477 {
478 case PowerDeviceD0:
479 break;
480 }
481 break;
482 }
483 break;
484 }
485 }
486
487 return STATUS_SUCCESS;
488}
489
490
491/**
492 * Handle the Power requests.
493 *
494 * @returns NT status code
495 * @param pDevObj device object
496 * @param pIrp IRP
497 */
498NTSTATUS VBoxGuestPower(PDEVICE_OBJECT pDevObj, PIRP pIrp)
499{
500 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
501 PVBOXGUESTDEVEXT pDevExt = (PVBOXGUESTDEVEXT)pDevObj->DeviceExtension;
502 POWER_STATE_TYPE powerType;
503 POWER_STATE powerState;
504 POWER_ACTION powerAction;
505
506 dprintf(("VBoxGuest::VBoxGuestPower\n"));
507
508 powerType = pStack->Parameters.Power.Type;
509 powerAction = pStack->Parameters.Power.ShutdownType;
510 powerState = pStack->Parameters.Power.State;
511
512 switch (pStack->MinorFunction)
513 {
514 case IRP_MN_SET_POWER:
515 {
516 dprintf(("VBoxGuest::VBoxGuestPower: IRP_MN_SET_POWER\n"));
517 switch (powerType)
518 {
519 case SystemPowerState:
520 {
521 dprintf(("VBoxGuest::VBoxGuestPower: SystemPowerState\n"));
522 switch (powerAction)
523 {
524 case PowerActionShutdownReset:
525 {
526 dprintf(("VBoxGuest::VBoxGuestPower: power action reset!\n"));
527 /* tell the VMM that we no longer support mouse pointer integration */
528
529 VMMDevReqMouseStatus *req = NULL;
530
531 int rc = VbglGRAlloc ((VMMDevRequestHeader **)&req, sizeof (VMMDevReqMouseStatus), VMMDevReq_SetMouseStatus);
532
533 if (VBOX_SUCCESS(rc))
534 {
535 req->mouseFeatures = 0;
536 req->pointerXPos = 0;
537 req->pointerYPos = 0;
538
539 rc = VbglGRPerform (&req->header);
540
541 if (VBOX_FAILURE(rc) || VBOX_FAILURE(req->header.rc))
542 {
543 dprintf(("VBoxGuest::PowerStateRequest: error communicating new power status to VMMDev."
544 "rc = %d, VMMDev rc = %Vrc\n", rc, req->header.rc));
545 }
546
547 VbglGRFree (&req->header);
548 }
549 break;
550 }
551
552 case PowerActionShutdown:
553 case PowerActionShutdownOff:
554 {
555 dprintf(("VBoxGuest::VBoxGuestPower: power action shutdown!\n"));
556 if (powerState.SystemState >= PowerSystemShutdown)
557 {
558 dprintf(("VBoxGuest::VBoxGuestPower: Telling the VMMDev to close the VM...\n"));
559 VMMDevPowerStateRequest *req = NULL;
560
561 int rc = VbglGRAlloc ((VMMDevRequestHeader **)&req, sizeof (VMMDevPowerStateRequest), VMMDevReq_SetPowerStatus);
562
563 if (VBOX_SUCCESS(rc))
564 {
565 req->powerState = VMMDevPowerState_PowerOff;
566
567 rc = VbglGRPerform (&req->header);
568
569 if (VBOX_FAILURE(rc) || VBOX_FAILURE(req->header.rc))
570 {
571 dprintf(("VBoxGuest::PowerStateRequest: error communicating new power status to VMMDev."
572 "rc = %d, VMMDev rc = %Vrc\n", rc, req->header.rc));
573 }
574
575 VbglGRFree (&req->header);
576 }
577 }
578 break;
579 }
580 }
581 break;
582 }
583 default:
584 break;
585 }
586 break;
587 }
588 default:
589 break;
590 }
591
592 /*
593 * Whether we are completing or relaying this power IRP,
594 * we must call PoStartNextPowerIrp.
595 */
596 PoStartNextPowerIrp(pIrp);
597
598 /*
599 * Send the IRP down the driver stack,
600 * using PoCallDriver (not IoCallDriver, as for non-power irps).
601 */
602 IoCopyCurrentIrpStackLocationToNext(pIrp);
603 IoSetCompletionRoutine(pIrp,
604 VBoxGuestPowerComplete,
605 (PVOID)pDevExt,
606 TRUE,
607 TRUE,
608 TRUE);
609 return PoCallDriver(pDevExt->nextLowerDriver, pIrp);
610}
Note: See TracBrowser for help on using the repository browser.

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