VirtualBox

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

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

IRP completion routines must be in non-pagable memory.

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