VirtualBox

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

Last change on this file since 1176 was 1, checked in by vboxsync, 55 years ago

import

  • 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 InnoTek Systemberatung 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#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