VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuest-win-pnp.cpp@ 70100

Last change on this file since 70100 was 70100, checked in by vboxsync, 7 years ago

VBoxGuest-win*: drop the PAGE alloc stuff (leave INIT as that section is unavoidable).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.4 KB
Line 
1/* $Id: VBoxGuest-win-pnp.cpp 70100 2017-12-13 09:24:42Z vboxsync $ */
2/** @file
3 * VBoxGuest-win-pnp - Windows Plug'n'Play specifics.
4 */
5
6/*
7 * Copyright (C) 2010-2017 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/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include "VBoxGuest-win.h"
32#include "VBoxGuestInternal.h"
33#include <VBox/err.h>
34#include <VBox/log.h>
35#include <VBox/version.h>
36#include <VBox/VBoxGuestLib.h>
37#include <iprt/assert.h>
38
39
40/*********************************************************************************************************************************
41* Defined Constants And Macros *
42*********************************************************************************************************************************/
43RT_C_DECLS_BEGIN
44static NTSTATUS vgdrvNtSendIrpSynchronously(PDEVICE_OBJECT pDevObj, PIRP pIrp, BOOLEAN fStrict);
45static NTSTATUS vgdrvNtPnPIrpComplete(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT pEvent);
46static VOID vgdrvNtShowDeviceResources(PCM_PARTIAL_RESOURCE_LIST pResourceList);
47RT_C_DECLS_END
48
49
50
51/**
52 * Irp completion routine for PnP Irps we send.
53 *
54 * @returns NT status code.
55 * @param pDevObj Device object.
56 * @param pIrp Request packet.
57 * @param pEvent Semaphore.
58 */
59static NTSTATUS vgdrvNtPnpIrpComplete(PDEVICE_OBJECT pDevObj, PIRP pIrp, PKEVENT pEvent)
60{
61 RT_NOREF2(pDevObj, pIrp);
62 KeSetEvent(pEvent, 0, FALSE);
63 return STATUS_MORE_PROCESSING_REQUIRED;
64}
65
66
67/**
68 * Helper to send a PnP IRP and wait until it's done.
69 *
70 * @returns NT status code.
71 * @param pDevObj Device object.
72 * @param pIrp Request packet.
73 * @param fStrict When set, returns an error if the IRP gives an error.
74 */
75static NTSTATUS vgdrvNtSendIrpSynchronously(PDEVICE_OBJECT pDevObj, PIRP pIrp, BOOLEAN fStrict)
76{
77 KEVENT Event;
78
79 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
80
81 IoCopyCurrentIrpStackLocationToNext(pIrp);
82 IoSetCompletionRoutine(pIrp, (PIO_COMPLETION_ROUTINE)vgdrvNtPnpIrpComplete, &Event, TRUE, TRUE, TRUE);
83
84 NTSTATUS rc = IoCallDriver(pDevObj, pIrp);
85
86 if (rc == STATUS_PENDING)
87 {
88 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
89 rc = pIrp->IoStatus.Status;
90 }
91
92 if ( !fStrict
93 && (rc == STATUS_NOT_SUPPORTED || rc == STATUS_INVALID_DEVICE_REQUEST))
94 {
95 rc = STATUS_SUCCESS;
96 }
97
98 Log(("vgdrvNtSendIrpSynchronously: Returning 0x%x\n", rc));
99 return rc;
100}
101
102
103/**
104 * PnP Request handler.
105 *
106 * @param pDevObj Device object.
107 * @param pIrp Request packet.
108 */
109NTSTATUS vgdrvNtPnP(PDEVICE_OBJECT pDevObj, PIRP pIrp)
110{
111 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
112 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
113
114#ifdef LOG_ENABLED
115 static char *s_apszFnctName[] =
116 {
117 "IRP_MN_START_DEVICE",
118 "IRP_MN_QUERY_REMOVE_DEVICE",
119 "IRP_MN_REMOVE_DEVICE",
120 "IRP_MN_CANCEL_REMOVE_DEVICE",
121 "IRP_MN_STOP_DEVICE",
122 "IRP_MN_QUERY_STOP_DEVICE",
123 "IRP_MN_CANCEL_STOP_DEVICE",
124 "IRP_MN_QUERY_DEVICE_RELATIONS",
125 "IRP_MN_QUERY_INTERFACE",
126 "IRP_MN_QUERY_CAPABILITIES",
127 "IRP_MN_QUERY_RESOURCES",
128 "IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
129 "IRP_MN_QUERY_DEVICE_TEXT",
130 "IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
131 "IRP_MN_0xE",
132 "IRP_MN_READ_CONFIG",
133 "IRP_MN_WRITE_CONFIG",
134 "IRP_MN_EJECT",
135 "IRP_MN_SET_LOCK",
136 "IRP_MN_QUERY_ID",
137 "IRP_MN_QUERY_PNP_DEVICE_STATE",
138 "IRP_MN_QUERY_BUS_INFORMATION",
139 "IRP_MN_DEVICE_USAGE_NOTIFICATION",
140 "IRP_MN_SURPRISE_REMOVAL",
141 };
142 Log(("vgdrvNtPnP: MinorFunction: %s\n",
143 pStack->MinorFunction < RT_ELEMENTS(s_apszFnctName) ? s_apszFnctName[pStack->MinorFunction] : "Unknown"));
144#endif
145
146 NTSTATUS rc = STATUS_SUCCESS;
147 switch (pStack->MinorFunction)
148 {
149 case IRP_MN_START_DEVICE:
150 {
151 Log(("vgdrvNtPnP: START_DEVICE\n"));
152
153 /* This must be handled first by the lower driver. */
154 rc = vgdrvNtSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE);
155
156 if ( NT_SUCCESS(rc)
157 && NT_SUCCESS(pIrp->IoStatus.Status))
158 {
159 Log(("vgdrvNtPnP: START_DEVICE: pStack->Parameters.StartDevice.AllocatedResources = %p\n",
160 pStack->Parameters.StartDevice.AllocatedResources));
161
162 if (pStack->Parameters.StartDevice.AllocatedResources)
163 rc = vgdrvNtInit(pDevObj, pIrp);
164 else
165 {
166 Log(("vgdrvNtPnP: START_DEVICE: No resources, pDevExt = %p, nextLowerDriver = %p!\n",
167 pDevExt, pDevExt ? pDevExt->pNextLowerDriver : NULL));
168 rc = STATUS_UNSUCCESSFUL;
169 }
170 }
171
172 if (NT_ERROR(rc))
173 {
174 Log(("vgdrvNtPnP: START_DEVICE: Error: rc = 0x%x\n", rc));
175
176 /* Need to unmap memory in case of errors ... */
177/** @todo r=bird: vgdrvNtInit maps it and is responsible for cleaning up its own friggin mess...
178 * Fix it instead of kind of working around things there!! */
179 vgdrvNtUnmapVMMDevMemory(pDevExt);
180 }
181 break;
182 }
183
184 case IRP_MN_CANCEL_REMOVE_DEVICE:
185 {
186 Log(("vgdrvNtPnP: CANCEL_REMOVE_DEVICE\n"));
187
188 /* This must be handled first by the lower driver. */
189 rc = vgdrvNtSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE);
190
191 if (NT_SUCCESS(rc) && pDevExt->enmDevState == VGDRVNTDEVSTATE_PENDINGREMOVE)
192 {
193 /* Return to the state prior to receiving the IRP_MN_QUERY_REMOVE_DEVICE request. */
194 pDevExt->enmDevState = pDevExt->enmPrevDevState;
195 }
196
197 /* Complete the IRP. */
198 break;
199 }
200
201 case IRP_MN_SURPRISE_REMOVAL:
202 {
203 Log(("vgdrvNtPnP: IRP_MN_SURPRISE_REMOVAL\n"));
204
205 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, VGDRVNTDEVSTATE_SURPRISEREMOVED);
206
207 /* Do nothing here actually. Cleanup is done in IRP_MN_REMOVE_DEVICE.
208 * This request is not expected for VBoxGuest.
209 */
210 LogRel(("VBoxGuest: unexpected device removal\n"));
211
212 /* Pass to the lower driver. */
213 pIrp->IoStatus.Status = STATUS_SUCCESS;
214
215 IoSkipCurrentIrpStackLocation(pIrp);
216
217 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
218
219 /* Do not complete the IRP. */
220 return rc;
221 }
222
223 case IRP_MN_QUERY_REMOVE_DEVICE:
224 {
225 Log(("vgdrvNtPnP: QUERY_REMOVE_DEVICE\n"));
226
227#ifdef VBOX_REBOOT_ON_UNINSTALL
228 Log(("vgdrvNtPnP: QUERY_REMOVE_DEVICE: Device cannot be removed without a reboot.\n"));
229 rc = STATUS_UNSUCCESSFUL;
230#endif
231
232 if (NT_SUCCESS(rc))
233 {
234 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, VGDRVNTDEVSTATE_PENDINGREMOVE);
235
236 /* This IRP passed down to lower driver. */
237 pIrp->IoStatus.Status = STATUS_SUCCESS;
238
239 IoSkipCurrentIrpStackLocation(pIrp);
240
241 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
242 Log(("vgdrvNtPnP: QUERY_REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
243
244 /* we must not do anything the IRP after doing IoSkip & CallDriver
245 * since the driver below us will complete (or already have completed) the IRP.
246 * I.e. just return the status we got from IoCallDriver */
247 return rc;
248 }
249
250 /* Complete the IRP on failure. */
251 break;
252 }
253
254 case IRP_MN_REMOVE_DEVICE:
255 {
256 Log(("vgdrvNtPnP: REMOVE_DEVICE\n"));
257
258 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, VGDRVNTDEVSTATE_REMOVED);
259
260 /* Free hardware resources. */
261 /** @todo this should actually free I/O ports, interrupts, etc.
262 * Update/bird: vgdrvNtCleanup actually does that... So, what's there to do? */
263 rc = vgdrvNtCleanup(pDevObj);
264 Log(("vgdrvNtPnP: REMOVE_DEVICE: vgdrvNtCleanup rc = 0x%08X\n", rc));
265
266 /*
267 * We need to send the remove down the stack before we detach,
268 * but we don't need to wait for the completion of this operation
269 * (and to register a completion routine).
270 */
271 pIrp->IoStatus.Status = STATUS_SUCCESS;
272
273 IoSkipCurrentIrpStackLocation(pIrp);
274
275 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
276 Log(("vgdrvNtPnP: REMOVE_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
277
278 IoDetachDevice(pDevExt->pNextLowerDriver);
279
280 Log(("vgdrvNtPnP: REMOVE_DEVICE: Removing device ...\n"));
281
282 /* Destroy device extension and clean up everything else. */
283 VGDrvCommonDeleteDevExt(&pDevExt->Core);
284
285 /* Remove DOS device + symbolic link. */
286 UNICODE_STRING win32Name;
287 RtlInitUnicodeString(&win32Name, VBOXGUEST_DEVICE_NAME_DOS);
288 IoDeleteSymbolicLink(&win32Name);
289
290 Log(("vgdrvNtPnP: REMOVE_DEVICE: Deleting device ...\n"));
291
292 /* Last action: Delete our device! pDevObj is *not* failed
293 * anymore after this call! */
294 IoDeleteDevice(pDevObj);
295
296 Log(("vgdrvNtPnP: REMOVE_DEVICE: Device removed!\n"));
297
298 /* Propagating rc from IoCallDriver. */
299 return rc; /* Make sure that we don't do anything below here anymore! */
300 }
301
302 case IRP_MN_CANCEL_STOP_DEVICE:
303 {
304 Log(("vgdrvNtPnP: CANCEL_STOP_DEVICE\n"));
305
306 /* This must be handled first by the lower driver. */
307 rc = vgdrvNtSendIrpSynchronously(pDevExt->pNextLowerDriver, pIrp, TRUE);
308
309 if (NT_SUCCESS(rc) && pDevExt->enmDevState == VGDRVNTDEVSTATE_PENDINGSTOP)
310 {
311 /* Return to the state prior to receiving the IRP_MN_QUERY_STOP_DEVICE request. */
312 pDevExt->enmDevState = pDevExt->enmPrevDevState;
313 }
314
315 /* Complete the IRP. */
316 break;
317 }
318
319 case IRP_MN_QUERY_STOP_DEVICE:
320 {
321 Log(("vgdrvNtPnP: QUERY_STOP_DEVICE\n"));
322
323#ifdef VBOX_REBOOT_ON_UNINSTALL
324 Log(("vgdrvNtPnP: QUERY_STOP_DEVICE: Device cannot be stopped without a reboot!\n"));
325 pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
326#endif
327
328 if (NT_SUCCESS(rc))
329 {
330 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, VGDRVNTDEVSTATE_PENDINGSTOP);
331
332 /* This IRP passed down to lower driver. */
333 pIrp->IoStatus.Status = STATUS_SUCCESS;
334
335 IoSkipCurrentIrpStackLocation(pIrp);
336
337 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
338 Log(("vgdrvNtPnP: QUERY_STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
339
340 /* we must not do anything with the IRP after doing IoSkip & CallDriver
341 * since the driver below us will complete (or already have completed) the IRP.
342 * I.e. just return the status we got from IoCallDriver */
343 return rc;
344 }
345
346 /* Complete the IRP on failure. */
347 break;
348 }
349
350 case IRP_MN_STOP_DEVICE:
351 {
352 Log(("vgdrvNtPnP: STOP_DEVICE\n"));
353
354 VBOXGUEST_UPDATE_DEVSTATE(pDevExt, VGDRVNTDEVSTATE_STOPPED);
355
356 /* Free hardware resources. */
357 /** @todo this should actually free I/O ports, interrupts, etc.
358 * Update/bird: vgdrvNtCleanup actually does that... So, what's there to do? */
359 rc = vgdrvNtCleanup(pDevObj);
360 Log(("vgdrvNtPnP: STOP_DEVICE: cleaning up, rc = 0x%x\n", rc));
361
362 /* Pass to the lower driver. */
363 pIrp->IoStatus.Status = STATUS_SUCCESS;
364
365 IoSkipCurrentIrpStackLocation(pIrp);
366
367 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
368 Log(("vgdrvNtPnP: STOP_DEVICE: Next lower driver replied rc = 0x%x\n", rc));
369
370 return rc;
371 }
372
373 default:
374 {
375 IoSkipCurrentIrpStackLocation(pIrp);
376 rc = IoCallDriver(pDevExt->pNextLowerDriver, pIrp);
377 return rc;
378 }
379 }
380
381 pIrp->IoStatus.Status = rc;
382 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
383
384 Log(("vgdrvNtPnP: Returning with rc = 0x%x\n", rc));
385 return rc;
386}
387
388
389/**
390 * Handle the power completion event.
391 *
392 * @returns NT status code.
393 * @param pDevObj Targetted device object.
394 * @param pIrp IO request packet.
395 * @param pContext Context value passed to IoSetCompletionRoutine in VBoxGuestPower.
396 */
397static NTSTATUS vgdrvNtPowerComplete(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp, IN PVOID pContext)
398{
399#ifdef VBOX_STRICT
400 RT_NOREF1(pDevObj);
401 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pContext;
402 PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
403
404 Assert(pDevExt);
405
406 if (pIrpSp)
407 {
408 Assert(pIrpSp->MajorFunction == IRP_MJ_POWER);
409 if (NT_SUCCESS(pIrp->IoStatus.Status))
410 {
411 switch (pIrpSp->MinorFunction)
412 {
413 case IRP_MN_SET_POWER:
414 switch (pIrpSp->Parameters.Power.Type)
415 {
416 case DevicePowerState:
417 switch (pIrpSp->Parameters.Power.State.DeviceState)
418 {
419 case PowerDeviceD0:
420 break;
421 default: /* Shut up MSC */ break;
422 }
423 break;
424 default: /* Shut up MSC */ break;
425 }
426 break;
427 }
428 }
429 }
430#else
431 RT_NOREF3(pDevObj, pIrp, pContext);
432#endif
433
434 return STATUS_SUCCESS;
435}
436
437
438/**
439 * Handle the Power requests.
440 *
441 * @returns NT status code
442 * @param pDevObj device object
443 * @param pIrp IRP
444 */
445NTSTATUS vgdrvNtPower(PDEVICE_OBJECT pDevObj, PIRP pIrp)
446{
447 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
448 PVBOXGUESTDEVEXTWIN pDevExt = (PVBOXGUESTDEVEXTWIN)pDevObj->DeviceExtension;
449 POWER_STATE_TYPE enmPowerType = pStack->Parameters.Power.Type;
450 POWER_STATE PowerState = pStack->Parameters.Power.State;
451 POWER_ACTION enmPowerAction = pStack->Parameters.Power.ShutdownType;
452
453 Log(("vgdrvNtPower:\n"));
454
455 switch (pStack->MinorFunction)
456 {
457 case IRP_MN_SET_POWER:
458 {
459 Log(("vgdrvNtPower: IRP_MN_SET_POWER, type= %d\n", enmPowerType));
460 switch (enmPowerType)
461 {
462 case SystemPowerState:
463 {
464 Log(("vgdrvNtPower: SystemPowerState, action = %d, state = %d/%d\n",
465 enmPowerAction, PowerState.SystemState, PowerState.DeviceState));
466
467 switch (enmPowerAction)
468 {
469 case PowerActionSleep:
470
471 /* System now is in a working state. */
472 if (PowerState.SystemState == PowerSystemWorking)
473 {
474 if ( pDevExt
475 && pDevExt->LastSystemPowerAction == PowerActionHibernate)
476 {
477 Log(("vgdrvNtPower: Returning from hibernation!\n"));
478 int rc = VGDrvCommonReinitDevExtAfterHibernation(&pDevExt->Core,
479 vgdrvNtVersionToOSType(g_enmVGDrvNtVer));
480 if (RT_FAILURE(rc))
481 Log(("vgdrvNtPower: Cannot re-init VMMDev chain, rc = %d!\n", rc));
482 }
483 }
484 break;
485
486 case PowerActionShutdownReset:
487 {
488 Log(("vgdrvNtPower: Power action reset!\n"));
489
490 /* Tell the VMM that we no longer support mouse pointer integration. */
491 VMMDevReqMouseStatus *pReq = NULL;
492 int vrc = VbglR0GRAlloc((VMMDevRequestHeader **)&pReq, sizeof (VMMDevReqMouseStatus),
493 VMMDevReq_SetMouseStatus);
494 if (RT_SUCCESS(vrc))
495 {
496 pReq->mouseFeatures = 0;
497 pReq->pointerXPos = 0;
498 pReq->pointerYPos = 0;
499
500 vrc = VbglR0GRPerform(&pReq->header);
501 if (RT_FAILURE(vrc))
502 {
503 Log(("vgdrvNtPower: error communicating new power status to VMMDev. vrc = %Rrc\n", vrc));
504 }
505
506 VbglR0GRFree(&pReq->header);
507 }
508
509 /* Don't do any cleanup here; there might be still coming in some IOCtls after we got this
510 * power action and would assert/crash when we already cleaned up all the stuff! */
511 break;
512 }
513
514 case PowerActionShutdown:
515 case PowerActionShutdownOff:
516 {
517 Log(("vgdrvNtPower: Power action shutdown!\n"));
518 if (PowerState.SystemState >= PowerSystemShutdown)
519 {
520 Log(("vgdrvNtPower: Telling the VMMDev to close the VM ...\n"));
521
522 VMMDevPowerStateRequest *pReq = pDevExt->pPowerStateRequest;
523 int vrc = VERR_NOT_IMPLEMENTED;
524 if (pReq)
525 {
526 pReq->header.requestType = VMMDevReq_SetPowerStatus;
527 pReq->powerState = VMMDevPowerState_PowerOff;
528
529 vrc = VbglR0GRPerform(&pReq->header);
530 }
531 if (RT_FAILURE(vrc))
532 Log(("vgdrvNtPower: Error communicating new power status to VMMDev. vrc = %Rrc\n", vrc));
533
534 /* No need to do cleanup here; at this point we should've been
535 * turned off by VMMDev already! */
536 }
537 break;
538 }
539
540 case PowerActionHibernate:
541
542 Log(("vgdrvNtPower: Power action hibernate!\n"));
543 break;
544
545 case PowerActionWarmEject:
546 Log(("vgdrvNtPower: PowerActionWarmEject!\n"));
547 break;
548
549 default:
550 Log(("vgdrvNtPower: %d\n", enmPowerAction));
551 break;
552 }
553
554 /*
555 * Save the current system power action for later use.
556 * This becomes handy when we return from hibernation for example.
557 */
558 if (pDevExt)
559 pDevExt->LastSystemPowerAction = enmPowerAction;
560
561 break;
562 }
563 default:
564 break;
565 }
566 break;
567 }
568 default:
569 break;
570 }
571
572 /*
573 * Whether we are completing or relaying this power IRP,
574 * we must call PoStartNextPowerIrp.
575 */
576 PoStartNextPowerIrp(pIrp);
577
578 /*
579 * Send the IRP down the driver stack, using PoCallDriver
580 * (not IoCallDriver, as for non-power irps).
581 */
582 IoCopyCurrentIrpStackLocationToNext(pIrp);
583 IoSetCompletionRoutine(pIrp,
584 vgdrvNtPowerComplete,
585 (PVOID)pDevExt,
586 TRUE,
587 TRUE,
588 TRUE);
589 return PoCallDriver(pDevExt->pNextLowerDriver, pIrp);
590}
591
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