VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/PDM.cpp@ 38990

Last change on this file since 38990 was 38847, checked in by vboxsync, 14 years ago

PDM: Enter the device critical section for PDM callback.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 85.2 KB
Line 
1/* $Id: PDM.cpp 38847 2011-09-23 13:19:23Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device Manager.
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
18
19/** @page pg_pdm PDM - The Pluggable Device & Driver Manager
20 *
21 * VirtualBox is designed to be very configurable, i.e. the ability to select
22 * virtual devices and configure them uniquely for a VM. For this reason
23 * virtual devices are not statically linked with the VMM but loaded, linked and
24 * instantiated at runtime by PDM using the information found in the
25 * Configuration Manager (CFGM).
26 *
27 * While the chief purpose of PDM is to manager of devices their drivers, it
28 * also serves as somewhere to put usful things like cross context queues, cross
29 * context synchronization (like critsect), VM centric thread management,
30 * asynchronous I/O framework, and so on.
31 *
32 * @see grp_pdm
33 *
34 *
35 * @section sec_pdm_dev The Pluggable Devices
36 *
37 * Devices register themselves when the module containing them is loaded. PDM
38 * will call the entry point 'VBoxDevicesRegister' when loading a device module.
39 * The device module will then use the supplied callback table to check the VMM
40 * version and to register its devices. Each device have an unique (for the
41 * configured VM) name. The name is not only used in PDM but also in CFGM (to
42 * organize device and device instance settings) and by anyone who wants to talk
43 * to a specific device instance.
44 *
45 * When all device modules have been successfully loaded PDM will instantiate
46 * those devices which are configured for the VM. Note that a device may have
47 * more than one instance, see network adaptors for instance. When
48 * instantiating a device PDM provides device instance memory and a callback
49 * table (aka Device Helpers / DevHlp) with the VM APIs which the device
50 * instance is trusted with.
51 *
52 * Some devices are trusted devices, most are not. The trusted devices are an
53 * integrated part of the VM and can obtain the VM handle from their device
54 * instance handles, thus enabling them to call any VM api. Untrusted devices
55 * can only use the callbacks provided during device instantiation.
56 *
57 * The main purpose in having DevHlps rather than just giving all the devices
58 * the VM handle and let them call the internal VM APIs directly, is both to
59 * create a binary interface that can be supported across releases and to
60 * create a barrier between devices and the VM. (The trusted / untrusted bit
61 * hasn't turned out to be of much use btw., but it's easy to maintain so there
62 * isn't any point in removing it.)
63 *
64 * A device can provide a ring-0 and/or a raw-mode context extension to improve
65 * the VM performance by handling exits and traps (respectively) without
66 * requiring context switches (to ring-3). Callbacks for MMIO and I/O ports can
67 * needs to be registered specifically for the additional contexts for this to
68 * make sense. Also, the device has to be trusted to be loaded into R0/RC
69 * because of the extra privilege it entails. Note that raw-mode code and data
70 * will be subject to relocation.
71 *
72 *
73 * @section sec_pdm_special_devs Special Devices
74 *
75 * Several kinds of devices interacts with the VMM and/or other device and PDM
76 * will work like a mediator for these. The typical pattern is that the device
77 * calls a special registration device helper with a set of callbacks, PDM
78 * responds by copying this and providing a pointer to a set helper callbacks
79 * for that particular kind of device. Unlike interfaces where the callback
80 * table pointer is used a 'this' pointer, these arrangements will use the
81 * device instance pointer (PPDMDEVINS) as a kind of 'this' pointer.
82 *
83 * For an example of this kind of setup, see the PIC. The PIC registers itself
84 * by calling PDMDEVHLPR3::pfnPICRegister. PDM saves the device instance,
85 * copies the callback tables (PDMPICREG), resolving the ring-0 and raw-mode
86 * addresses in the process, and hands back the pointer to a set of helper
87 * methods (PDMPICHLPR3). The PCI device then queries the ring-0 and raw-mode
88 * helpers using PDMPICHLPR3::pfnGetR0Helpers and PDMPICHLPR3::pfnGetRCHelpers.
89 * The PCI device repeats ths pfnGetRCHelpers call in it's relocation method
90 * since the address changes when RC is relocated.
91 *
92 * @see grp_pdm_device
93 *
94 *
95 * @section sec_pdm_usbdev The Pluggable USB Devices
96 *
97 * USB devices are handled a little bit differently than other devices. The
98 * general concepts wrt. pluggability are mostly the same, but the details
99 * varies. The registration entry point is 'VBoxUsbRegister', the device
100 * instance is PDMUSBINS and the callbacks helpers are different. Also, USB
101 * device are restricted to ring-3 and cannot have any ring-0 or raw-mode
102 * extensions (at least not yet).
103 *
104 * The way USB devices work differs greatly from other devices though since they
105 * aren't attaches directly to the PCI/ISA/whatever system buses but via a
106 * USB host control (OHCI, UHCI or EHCI). USB devices handles USB requests
107 * (URBs) and does not register I/O ports, MMIO ranges or PCI bus
108 * devices/functions.
109 *
110 * @see grp_pdm_usbdev
111 *
112 *
113 * @section sec_pdm_drv The Pluggable Drivers
114 *
115 * The VM devices are often accessing host hardware or OS facilities. For most
116 * devices these facilities can be abstracted in one or more levels. These
117 * abstractions are called drivers.
118 *
119 * For instance take a DVD/CD drive. This can be connected to a SCSI
120 * controller, an ATA controller or a SATA controller. The basics of the DVD/CD
121 * drive implementation remains the same - eject, insert, read, seek, and such.
122 * (For the scsi case, you might wanna speak SCSI directly to, but that can of
123 * course be fixed - see SCSI passthru.) So, it
124 * makes much sense to have a generic CD/DVD driver which implements this.
125 *
126 * Then the media 'inserted' into the DVD/CD drive can be a ISO image, or it can
127 * be read from a real CD or DVD drive (there are probably other custom formats
128 * someone could desire to read or construct too). So, it would make sense to
129 * have abstracted interfaces for dealing with this in a generic way so the
130 * cdrom unit doesn't have to implement it all. Thus we have created the
131 * CDROM/DVD media driver family.
132 *
133 * So, for this example the IDE controller #1 (i.e. secondary) will have
134 * the DVD/CD Driver attached to it's LUN #0 (master). When a media is mounted
135 * the DVD/CD Driver will have a ISO, HostDVD or RAW (media) Driver attached.
136 *
137 * It is possible to configure many levels of drivers inserting filters, loggers,
138 * or whatever you desire into the chain. We're using this for network sniffing
139 * for instance.
140 *
141 * The drivers are loaded in a similar manner to that of the device, namely by
142 * iterating a keyspace in CFGM, load the modules listed there and call
143 * 'VBoxDriversRegister' with a callback table.
144 *
145 * @see grp_pdm_driver
146 *
147 *
148 * @section sec_pdm_ifs Interfaces
149 *
150 * The pluggable drivers and devices exposes one standard interface (callback
151 * table) which is used to construct, destruct, attach, detach,( ++,) and query
152 * other interfaces. A device will query the interfaces required for it's
153 * operation during init and hot-plug. PDM may query some interfaces during
154 * runtime mounting too.
155 *
156 * An interface here means a function table contained within the device or
157 * driver instance data. Its method are invoked with the function table pointer
158 * as the first argument and they will calculate the address of the device or
159 * driver instance data from it. (This is one of the aspects which *might* have
160 * been better done in C++.)
161 *
162 * @see grp_pdm_interfaces
163 *
164 *
165 * @section sec_pdm_utils Utilities
166 *
167 * As mentioned earlier, PDM is the location of any usful constructs that doesn't
168 * quite fit into IPRT. The next subsections will discuss these.
169 *
170 * One thing these APIs all have in common is that resources will be associated
171 * with a device / driver and automatically freed after it has been destroyed if
172 * the destructor didn't do this.
173 *
174 *
175 * @subsection sec_pdm_async_completion Async I/O
176 *
177 * The PDM Async I/O API provides a somewhat platform agnostic interface for
178 * asynchronous I/O. For reasons of performance and complexity this does not
179 * build upon any IPRT API.
180 *
181 * @todo more details.
182 *
183 * @see grp_pdm_async_completion
184 *
185 *
186 * @subsection sec_pdm_async_task Async Task - not implemented
187 *
188 * @todo implement and describe
189 *
190 * @see grp_pdm_async_task
191 *
192 *
193 * @subsection sec_pdm_critsect Critical Section
194 *
195 * The PDM Critical Section API is currently building on the IPRT API with the
196 * same name. It adds the possibility to use critical sections in ring-0 and
197 * raw-mode as well as in ring-3. There are certain restrictions on the RC and
198 * R0 usage though since we're not able to wait on it, nor wake up anyone that
199 * is waiting on it. These restrictions origins with the use of a ring-3 event
200 * semaphore. In a later incarnation we plan to replace the ring-3 event
201 * semaphore with a ring-0 one, thus enabling us to wake up waiters while
202 * exectuing in ring-0 and making the hardware assisted execution mode more
203 * efficient. (Raw-mode won't benefit much from this, naturally.)
204 *
205 * @see grp_pdm_critsect
206 *
207 *
208 * @subsection sec_pdm_queue Queue
209 *
210 * The PDM Queue API is for queuing one or more tasks for later consumption in
211 * ring-3 by EMT, and optionally forcing a delayed or ASAP return to ring-3. The
212 * queues can also be run on a timer basis as an alternative to the ASAP thing.
213 * The queue will be flushed at forced action time.
214 *
215 * A queue can also be used by another thread (a I/O worker for instance) to
216 * send work / events over to the EMT.
217 *
218 * @see grp_pdm_queue
219 *
220 *
221 * @subsection sec_pdm_task Task - not implemented yet
222 *
223 * The PDM Task API is for flagging a task for execution at a later point when
224 * we're back in ring-3, optionally forcing the ring-3 return to happen ASAP.
225 * As you can see the concept is similar to queues only simpler.
226 *
227 * A task can also be scheduled by another thread (a I/O worker for instance) as
228 * a mean of getting something done in EMT.
229 *
230 * @see grp_pdm_task
231 *
232 *
233 * @subsection sec_pdm_thread Thread
234 *
235 * The PDM Thread API is there to help devices and drivers manage their threads
236 * correctly wrt. power on, suspend, resume, power off and destruction.
237 *
238 * The general usage pattern for threads in the employ of devices and drivers is
239 * that they shuffle data or requests while the VM is running and stop doing
240 * this when the VM is paused or powered down. Rogue threads running while the
241 * VM is paused can cause the state to change during saving or have other
242 * unwanted side effects. The PDM Threads API ensures that this won't happen.
243 *
244 * @see grp_pdm_thread
245 *
246 */
247
248
249/*******************************************************************************
250* Header Files *
251*******************************************************************************/
252#define LOG_GROUP LOG_GROUP_PDM
253#include "PDMInternal.h"
254#include <VBox/vmm/pdm.h>
255#include <VBox/vmm/mm.h>
256#include <VBox/vmm/pgm.h>
257#include <VBox/vmm/ssm.h>
258#include <VBox/vmm/vm.h>
259#include <VBox/vmm/uvm.h>
260#include <VBox/vmm/vmm.h>
261#include <VBox/param.h>
262#include <VBox/err.h>
263#include <VBox/sup.h>
264
265#include <VBox/log.h>
266#include <iprt/asm.h>
267#include <iprt/assert.h>
268#include <iprt/alloc.h>
269#include <iprt/ldr.h>
270#include <iprt/path.h>
271#include <iprt/string.h>
272
273
274/*******************************************************************************
275* Defined Constants And Macros *
276*******************************************************************************/
277/** The PDM saved state version. */
278#define PDM_SAVED_STATE_VERSION 4
279#define PDM_SAVED_STATE_VERSION_PRE_NMI_FF 3
280
281/** The number of nanoseconds a suspend callback needs to take before
282 * PDMR3Suspend warns about it taking too long. */
283#define PDMSUSPEND_WARN_AT_NS UINT64_C(1200000000)
284
285/** The number of nanoseconds a suspend callback needs to take before
286 * PDMR3PowerOff warns about it taking too long. */
287#define PDMPOWEROFF_WARN_AT_NS UINT64_C( 900000000)
288
289
290/*******************************************************************************
291* Structures and Typedefs *
292*******************************************************************************/
293/**
294 * Statistics of asynchronous notification tasks - used by reset, suspend and
295 * power off.
296 */
297typedef struct PDMNOTIFYASYNCSTATS
298{
299 /** The the start timestamp. */
300 uint64_t uStartNsTs;
301 /** When to log the next time. */
302 uint64_t cNsElapsedNextLog;
303 /** The loop counter. */
304 uint32_t cLoops;
305 /** The number of pending asynchronous notification tasks. */
306 uint32_t cAsync;
307 /** The name of the operation (log prefix). */
308 const char *pszOp;
309 /** The current list buffer position. */
310 size_t offList;
311 /** String containing a list of the pending tasks. */
312 char szList[1024];
313} PDMNOTIFYASYNCSTATS;
314/** Pointer to the stats of pending asynchronous notification tasks. */
315typedef PDMNOTIFYASYNCSTATS *PPDMNOTIFYASYNCSTATS;
316
317
318/*******************************************************************************
319* Internal Functions *
320*******************************************************************************/
321static DECLCALLBACK(int) pdmR3LiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass);
322static DECLCALLBACK(int) pdmR3SaveExec(PVM pVM, PSSMHANDLE pSSM);
323static DECLCALLBACK(int) pdmR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
324static DECLCALLBACK(int) pdmR3LoadPrep(PVM pVM, PSSMHANDLE pSSM);
325
326
327
328/**
329 * Initializes the PDM part of the UVM.
330 *
331 * This doesn't really do much right now but has to be here for the sake
332 * of completeness.
333 *
334 * @returns VBox status code.
335 * @param pUVM Pointer to the user mode VM structure.
336 */
337VMMR3DECL(int) PDMR3InitUVM(PUVM pUVM)
338{
339 AssertCompile(sizeof(pUVM->pdm.s) <= sizeof(pUVM->pdm.padding));
340 AssertRelease(sizeof(pUVM->pdm.s) <= sizeof(pUVM->pdm.padding));
341 pUVM->pdm.s.pModules = NULL;
342 pUVM->pdm.s.pCritSects = NULL;
343 return RTCritSectInit(&pUVM->pdm.s.ListCritSect);
344}
345
346
347/**
348 * Initializes the PDM.
349 *
350 * @returns VBox status code.
351 * @param pVM The VM to operate on.
352 */
353VMMR3DECL(int) PDMR3Init(PVM pVM)
354{
355 LogFlow(("PDMR3Init\n"));
356
357 /*
358 * Assert alignment and sizes.
359 */
360 AssertRelease(!(RT_OFFSETOF(VM, pdm.s) & 31));
361 AssertRelease(sizeof(pVM->pdm.s) <= sizeof(pVM->pdm.padding));
362 AssertCompileMemberAlignment(PDM, CritSect, sizeof(uintptr_t));
363
364 /*
365 * Init the structure.
366 */
367 pVM->pdm.s.GCPhysVMMDevHeap = NIL_RTGCPHYS;
368
369 /*
370 * Initialize critical sections first.
371 */
372 int rc = pdmR3CritSectInitStats(pVM);
373 if (RT_SUCCESS(rc))
374 rc = PDMR3CritSectInit(pVM, &pVM->pdm.s.CritSect, RT_SRC_POS, "PDM");
375 if (RT_SUCCESS(rc))
376 {
377 rc = PDMR3CritSectInit(pVM, &pVM->pdm.s.NopCritSect, RT_SRC_POS, "NOP");
378 if (RT_SUCCESS(rc))
379 pVM->pdm.s.NopCritSect.s.Core.fFlags |= RTCRITSECT_FLAGS_NOP;
380 }
381
382 /*
383 * Initialize sub components.
384 */
385 if (RT_SUCCESS(rc))
386 rc = pdmR3LdrInitU(pVM->pUVM);
387#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
388 if (RT_SUCCESS(rc))
389 rc = pdmR3AsyncCompletionInit(pVM);
390#endif
391 if (RT_SUCCESS(rc))
392 rc = pdmR3BlkCacheInit(pVM);
393 if (RT_SUCCESS(rc))
394 rc = pdmR3DrvInit(pVM);
395 if (RT_SUCCESS(rc))
396 rc = pdmR3DevInit(pVM);
397 if (RT_SUCCESS(rc))
398 {
399 /*
400 * Register the saved state data unit.
401 */
402 rc = SSMR3RegisterInternal(pVM, "pdm", 1, PDM_SAVED_STATE_VERSION, 128,
403 NULL, pdmR3LiveExec, NULL,
404 NULL, pdmR3SaveExec, NULL,
405 pdmR3LoadPrep, pdmR3LoadExec, NULL);
406 if (RT_SUCCESS(rc))
407 {
408 LogFlow(("PDM: Successfully initialized\n"));
409 return rc;
410 }
411 }
412
413 /*
414 * Cleanup and return failure.
415 */
416 PDMR3Term(pVM);
417 LogFlow(("PDMR3Init: returns %Rrc\n", rc));
418 return rc;
419}
420
421
422/**
423 * Applies relocations to data and code managed by this
424 * component. This function will be called at init and
425 * whenever the VMM need to relocate it self inside the GC.
426 *
427 * @param pVM VM handle.
428 * @param offDelta Relocation delta relative to old location.
429 * @remark The loader subcomponent is relocated by PDMR3LdrRelocate() very
430 * early in the relocation phase.
431 */
432VMMR3DECL(void) PDMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
433{
434 LogFlow(("PDMR3Relocate\n"));
435
436 /*
437 * Queues.
438 */
439 pdmR3QueueRelocate(pVM, offDelta);
440 pVM->pdm.s.pDevHlpQueueRC = PDMQueueRCPtr(pVM->pdm.s.pDevHlpQueueR3);
441
442 /*
443 * Critical sections.
444 */
445 pdmR3CritSectRelocate(pVM);
446
447 /*
448 * The registered PIC.
449 */
450 if (pVM->pdm.s.Pic.pDevInsRC)
451 {
452 pVM->pdm.s.Pic.pDevInsRC += offDelta;
453 pVM->pdm.s.Pic.pfnSetIrqRC += offDelta;
454 pVM->pdm.s.Pic.pfnGetInterruptRC += offDelta;
455 }
456
457 /*
458 * The registered APIC.
459 */
460 if (pVM->pdm.s.Apic.pDevInsRC)
461 {
462 pVM->pdm.s.Apic.pDevInsRC += offDelta;
463 pVM->pdm.s.Apic.pfnGetInterruptRC += offDelta;
464 pVM->pdm.s.Apic.pfnSetBaseRC += offDelta;
465 pVM->pdm.s.Apic.pfnGetBaseRC += offDelta;
466 pVM->pdm.s.Apic.pfnSetTPRRC += offDelta;
467 pVM->pdm.s.Apic.pfnGetTPRRC += offDelta;
468 pVM->pdm.s.Apic.pfnBusDeliverRC += offDelta;
469 if (pVM->pdm.s.Apic.pfnLocalInterruptRC)
470 pVM->pdm.s.Apic.pfnLocalInterruptRC += offDelta;
471 pVM->pdm.s.Apic.pfnWriteMSRRC += offDelta;
472 pVM->pdm.s.Apic.pfnReadMSRRC += offDelta;
473 }
474
475 /*
476 * The registered I/O APIC.
477 */
478 if (pVM->pdm.s.IoApic.pDevInsRC)
479 {
480 pVM->pdm.s.IoApic.pDevInsRC += offDelta;
481 pVM->pdm.s.IoApic.pfnSetIrqRC += offDelta;
482 if (pVM->pdm.s.IoApic.pfnSendMsiRC)
483 pVM->pdm.s.IoApic.pfnSendMsiRC += offDelta;
484 }
485
486 /*
487 * The register PCI Buses.
488 */
489 for (unsigned i = 0; i < RT_ELEMENTS(pVM->pdm.s.aPciBuses); i++)
490 {
491 if (pVM->pdm.s.aPciBuses[i].pDevInsRC)
492 {
493 pVM->pdm.s.aPciBuses[i].pDevInsRC += offDelta;
494 pVM->pdm.s.aPciBuses[i].pfnSetIrqRC += offDelta;
495 }
496 }
497
498 /*
499 * Devices & Drivers.
500 */
501 PCPDMDEVHLPRC pDevHlpRC;
502 int rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDevHlp", &pDevHlpRC);
503 AssertReleaseMsgRC(rc, ("rc=%Rrc when resolving g_pdmRCDevHlp\n", rc));
504
505 PCPDMDRVHLPRC pDrvHlpRC;
506 rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDevHlp", &pDrvHlpRC);
507 AssertReleaseMsgRC(rc, ("rc=%Rrc when resolving g_pdmRCDevHlp\n", rc));
508
509 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
510 {
511 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_RC)
512 {
513 pDevIns->pHlpRC = pDevHlpRC;
514 pDevIns->pvInstanceDataRC = MMHyperR3ToRC(pVM, pDevIns->pvInstanceDataR3);
515 if (pDevIns->pCritSectRoR3)
516 pDevIns->pCritSectRoRC = MMHyperR3ToRC(pVM, pDevIns->pCritSectRoR3);
517 pDevIns->Internal.s.pVMRC = pVM->pVMRC;
518 if (pDevIns->Internal.s.pPciBusR3)
519 pDevIns->Internal.s.pPciBusRC = MMHyperR3ToRC(pVM, pDevIns->Internal.s.pPciBusR3);
520 if (pDevIns->Internal.s.pPciDeviceR3)
521 pDevIns->Internal.s.pPciDeviceRC = MMHyperR3ToRC(pVM, pDevIns->Internal.s.pPciDeviceR3);
522 if (pDevIns->pReg->pfnRelocate)
523 {
524 LogFlow(("PDMR3Relocate: Relocating device '%s'/%d\n",
525 pDevIns->pReg->szName, pDevIns->iInstance));
526 pDevIns->pReg->pfnRelocate(pDevIns, offDelta);
527 }
528 }
529
530 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
531 {
532 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
533 {
534 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_RC)
535 {
536 pDrvIns->pHlpRC = pDrvHlpRC;
537 pDrvIns->pvInstanceDataRC = MMHyperR3ToRC(pVM, pDrvIns->pvInstanceDataR3);
538 pDrvIns->Internal.s.pVMRC = pVM->pVMRC;
539 if (pDrvIns->pReg->pfnRelocate)
540 {
541 LogFlow(("PDMR3Relocate: Relocating driver '%s'/%u attached to '%s'/%d/%u\n",
542 pDrvIns->pReg->szName, pDrvIns->iInstance,
543 pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun));
544 pDrvIns->pReg->pfnRelocate(pDrvIns, offDelta);
545 }
546 }
547 }
548 }
549
550 }
551}
552
553
554/**
555 * Worker for pdmR3Term that terminates a LUN chain.
556 *
557 * @param pVM Pointer to the shared VM structure.
558 * @param pLun The head of the chain.
559 * @param pszDevice The name of the device (for logging).
560 * @param iInstance The device instance number (for logging).
561 */
562static void pdmR3TermLuns(PVM pVM, PPDMLUN pLun, const char *pszDevice, unsigned iInstance)
563{
564 for (; pLun; pLun = pLun->pNext)
565 {
566 /*
567 * Destroy them one at a time from the bottom up.
568 * (The serial device/drivers depends on this - bad.)
569 */
570 PPDMDRVINS pDrvIns = pLun->pBottom;
571 pLun->pBottom = pLun->pTop = NULL;
572 while (pDrvIns)
573 {
574 PPDMDRVINS pDrvNext = pDrvIns->Internal.s.pUp;
575
576 if (pDrvIns->pReg->pfnDestruct)
577 {
578 LogFlow(("pdmR3DevTerm: Destroying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
579 pDrvIns->pReg->szName, pDrvIns->iInstance, pLun->iLun, pszDevice, iInstance));
580 pDrvIns->pReg->pfnDestruct(pDrvIns);
581 }
582 pDrvIns->Internal.s.pDrv->cInstances--;
583
584 TMR3TimerDestroyDriver(pVM, pDrvIns);
585 //PDMR3QueueDestroyDriver(pVM, pDrvIns);
586 //pdmR3ThreadDestroyDriver(pVM, pDrvIns);
587 SSMR3DeregisterDriver(pVM, pDrvIns, NULL, 0);
588
589 pDrvIns = pDrvNext;
590 }
591 }
592}
593
594
595/**
596 * Terminates the PDM.
597 *
598 * Termination means cleaning up and freeing all resources,
599 * the VM it self is at this point powered off or suspended.
600 *
601 * @returns VBox status code.
602 * @param pVM The VM to operate on.
603 */
604VMMR3DECL(int) PDMR3Term(PVM pVM)
605{
606 LogFlow(("PDMR3Term:\n"));
607 AssertMsg(PDMCritSectIsInitialized(&pVM->pdm.s.CritSect), ("bad init order!\n"));
608
609 /*
610 * Iterate the device instances and attach drivers, doing
611 * relevant destruction processing.
612 *
613 * N.B. There is no need to mess around freeing memory allocated
614 * from any MM heap since MM will do that in its Term function.
615 */
616 /* usb ones first. */
617 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
618 {
619 pdmR3TermLuns(pVM, pUsbIns->Internal.s.pLuns, pUsbIns->pReg->szName, pUsbIns->iInstance);
620
621 if (pUsbIns->pReg->pfnDestruct)
622 {
623 LogFlow(("pdmR3DevTerm: Destroying - device '%s'/%d\n",
624 pUsbIns->pReg->szName, pUsbIns->iInstance));
625 pUsbIns->pReg->pfnDestruct(pUsbIns);
626 }
627
628 //TMR3TimerDestroyUsb(pVM, pUsbIns);
629 //SSMR3DeregisterUsb(pVM, pUsbIns, NULL, 0);
630 pdmR3ThreadDestroyUsb(pVM, pUsbIns);
631 }
632
633 /* then the 'normal' ones. */
634 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
635 {
636 pdmR3TermLuns(pVM, pDevIns->Internal.s.pLunsR3, pDevIns->pReg->szName, pDevIns->iInstance);
637
638 if (pDevIns->pReg->pfnDestruct)
639 {
640 LogFlow(("pdmR3DevTerm: Destroying - device '%s'/%d\n",
641 pDevIns->pReg->szName, pDevIns->iInstance));
642 pDevIns->pReg->pfnDestruct(pDevIns);
643 }
644
645 TMR3TimerDestroyDevice(pVM, pDevIns);
646 //SSMR3DeregisterDriver(pVM, pDevIns, NULL, 0);
647 pdmR3CritSectDeleteDevice(pVM, pDevIns);
648 //pdmR3ThreadDestroyDevice(pVM, pDevIns);
649 //PDMR3QueueDestroyDevice(pVM, pDevIns);
650 PGMR3PhysMMIO2Deregister(pVM, pDevIns, UINT32_MAX);
651 }
652
653 /*
654 * Destroy all threads.
655 */
656 pdmR3ThreadDestroyAll(pVM);
657
658 /*
659 * Destroy the block cache.
660 */
661 pdmR3BlkCacheTerm(pVM);
662
663#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
664 /*
665 * Free async completion managers.
666 */
667 pdmR3AsyncCompletionTerm(pVM);
668#endif
669
670 /*
671 * Free modules.
672 */
673 pdmR3LdrTermU(pVM->pUVM);
674
675 /*
676 * Destroy the PDM lock.
677 */
678 PDMR3CritSectDelete(&pVM->pdm.s.CritSect);
679 /* The MiscCritSect is deleted by PDMR3CritSectTerm. */
680
681 LogFlow(("PDMR3Term: returns %Rrc\n", VINF_SUCCESS));
682 return VINF_SUCCESS;
683}
684
685
686/**
687 * Terminates the PDM part of the UVM.
688 *
689 * This will unload any modules left behind.
690 *
691 * @param pUVM Pointer to the user mode VM structure.
692 */
693VMMR3DECL(void) PDMR3TermUVM(PUVM pUVM)
694{
695 /*
696 * In the normal cause of events we will now call pdmR3LdrTermU for
697 * the second time. In the case of init failure however, this might
698 * the first time, which is why we do it.
699 */
700 pdmR3LdrTermU(pUVM);
701
702 Assert(pUVM->pdm.s.pCritSects == NULL);
703 RTCritSectDelete(&pUVM->pdm.s.ListCritSect);
704}
705
706
707/**
708 * Bits that are saved in pass 0 and in the final pass.
709 *
710 * @param pVM The VM handle.
711 * @param pSSM The saved state handle.
712 */
713static void pdmR3SaveBoth(PVM pVM, PSSMHANDLE pSSM)
714{
715 /*
716 * Save the list of device instances so we can check that they're all still
717 * there when we load the state and that nothing new has been added.
718 */
719 uint32_t i = 0;
720 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3, i++)
721 {
722 SSMR3PutU32(pSSM, i);
723 SSMR3PutStrZ(pSSM, pDevIns->pReg->szName);
724 SSMR3PutU32(pSSM, pDevIns->iInstance);
725 }
726 SSMR3PutU32(pSSM, UINT32_MAX); /* terminator */
727}
728
729
730/**
731 * Live save.
732 *
733 * @returns VBox status code.
734 * @param pVM The VM handle.
735 * @param pSSM The saved state handle.
736 * @param uPass The pass.
737 */
738static DECLCALLBACK(int) pdmR3LiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass)
739{
740 LogFlow(("pdmR3LiveExec:\n"));
741 AssertReturn(uPass == 0, VERR_INTERNAL_ERROR_4);
742 pdmR3SaveBoth(pVM, pSSM);
743 return VINF_SSM_DONT_CALL_AGAIN;
744}
745
746
747/**
748 * Execute state save operation.
749 *
750 * @returns VBox status code.
751 * @param pVM The VM handle.
752 * @param pSSM The saved state handle.
753 */
754static DECLCALLBACK(int) pdmR3SaveExec(PVM pVM, PSSMHANDLE pSSM)
755{
756 LogFlow(("pdmR3SaveExec:\n"));
757
758 /*
759 * Save interrupt and DMA states.
760 */
761 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
762 {
763 PVMCPU pVCpu = &pVM->aCpus[idCpu];
764 SSMR3PutU32(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC));
765 SSMR3PutU32(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC));
766 SSMR3PutU32(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_NMI));
767 SSMR3PutU32(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_SMI));
768 }
769 SSMR3PutU32(pSSM, VM_FF_ISSET(pVM, VM_FF_PDM_DMA));
770
771 pdmR3SaveBoth(pVM, pSSM);
772 return VINF_SUCCESS;
773}
774
775
776/**
777 * Prepare state load operation.
778 *
779 * This will dispatch pending operations and clear the FFs governed by PDM and its devices.
780 *
781 * @returns VBox status code.
782 * @param pVM The VM handle.
783 * @param pSSM The SSM handle.
784 */
785static DECLCALLBACK(int) pdmR3LoadPrep(PVM pVM, PSSMHANDLE pSSM)
786{
787 LogFlow(("pdmR3LoadPrep: %s%s\n",
788 VM_FF_ISSET(pVM, VM_FF_PDM_QUEUES) ? " VM_FF_PDM_QUEUES" : "",
789 VM_FF_ISSET(pVM, VM_FF_PDM_DMA) ? " VM_FF_PDM_DMA" : ""));
790#ifdef LOG_ENABLED
791 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
792 {
793 PVMCPU pVCpu = &pVM->aCpus[idCpu];
794 LogFlow(("pdmR3LoadPrep: VCPU %u %s%s\n", idCpu,
795 VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC) ? " VMCPU_FF_INTERRUPT_APIC" : "",
796 VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC) ? " VMCPU_FF_INTERRUPT_PIC" : ""));
797 }
798#endif
799
800 /*
801 * In case there is work pending that will raise an interrupt,
802 * start a DMA transfer, or release a lock. (unlikely)
803 */
804 if (VM_FF_ISSET(pVM, VM_FF_PDM_QUEUES))
805 PDMR3QueueFlushAll(pVM);
806
807 /* Clear the FFs. */
808 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
809 {
810 PVMCPU pVCpu = &pVM->aCpus[idCpu];
811 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
812 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
813 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
814 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_SMI);
815 }
816 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
817
818 return VINF_SUCCESS;
819}
820
821
822/**
823 * Execute state load operation.
824 *
825 * @returns VBox status code.
826 * @param pVM VM Handle.
827 * @param pSSM SSM operation handle.
828 * @param uVersion Data layout version.
829 * @param uPass The data pass.
830 */
831static DECLCALLBACK(int) pdmR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
832{
833 int rc;
834
835 LogFlow(("pdmR3LoadExec: uPass=%#x\n", uPass));
836
837 /*
838 * Validate version.
839 */
840 if ( uVersion != PDM_SAVED_STATE_VERSION
841 && uVersion != PDM_SAVED_STATE_VERSION_PRE_NMI_FF)
842 {
843 AssertMsgFailed(("Invalid version uVersion=%d!\n", uVersion));
844 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
845 }
846
847 if (uPass == SSM_PASS_FINAL)
848 {
849 /*
850 * Load the interrupt and DMA states.
851 */
852 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
853 {
854 PVMCPU pVCpu = &pVM->aCpus[idCpu];
855
856 /* APIC interrupt */
857 uint32_t fInterruptPending = 0;
858 rc = SSMR3GetU32(pSSM, &fInterruptPending);
859 if (RT_FAILURE(rc))
860 return rc;
861 if (fInterruptPending & ~1)
862 {
863 AssertMsgFailed(("fInterruptPending=%#x (APIC)\n", fInterruptPending));
864 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
865 }
866 AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC));
867 if (fInterruptPending)
868 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC);
869
870 /* PIC interrupt */
871 fInterruptPending = 0;
872 rc = SSMR3GetU32(pSSM, &fInterruptPending);
873 if (RT_FAILURE(rc))
874 return rc;
875 if (fInterruptPending & ~1)
876 {
877 AssertMsgFailed(("fInterruptPending=%#x (PIC)\n", fInterruptPending));
878 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
879 }
880 AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC));
881 if (fInterruptPending)
882 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC);
883
884 if (uVersion > PDM_SAVED_STATE_VERSION_PRE_NMI_FF)
885 {
886 /* NMI interrupt */
887 fInterruptPending = 0;
888 rc = SSMR3GetU32(pSSM, &fInterruptPending);
889 if (RT_FAILURE(rc))
890 return rc;
891 if (fInterruptPending & ~1)
892 {
893 AssertMsgFailed(("fInterruptPending=%#x (NMI)\n", fInterruptPending));
894 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
895 }
896 AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_NMI));
897 if (fInterruptPending)
898 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI);
899
900 /* SMI interrupt */
901 fInterruptPending = 0;
902 rc = SSMR3GetU32(pSSM, &fInterruptPending);
903 if (RT_FAILURE(rc))
904 return rc;
905 if (fInterruptPending & ~1)
906 {
907 AssertMsgFailed(("fInterruptPending=%#x (SMI)\n", fInterruptPending));
908 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
909 }
910 AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_SMI));
911 if (fInterruptPending)
912 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_SMI);
913 }
914 }
915
916 /* DMA pending */
917 uint32_t fDMAPending = 0;
918 rc = SSMR3GetU32(pSSM, &fDMAPending);
919 if (RT_FAILURE(rc))
920 return rc;
921 if (fDMAPending & ~1)
922 {
923 AssertMsgFailed(("fDMAPending=%#x\n", fDMAPending));
924 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
925 }
926 if (fDMAPending)
927 VM_FF_SET(pVM, VM_FF_PDM_DMA);
928 Log(("pdmR3LoadExec: VM_FF_PDM_DMA=%RTbool\n", VM_FF_ISSET(pVM, VM_FF_PDM_DMA)));
929 }
930
931 /*
932 * Load the list of devices and verify that they are all there.
933 */
934 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
935 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_FOUND;
936
937 for (uint32_t i = 0; ; i++)
938 {
939 /* Get the sequence number / terminator. */
940 uint32_t u32Sep;
941 rc = SSMR3GetU32(pSSM, &u32Sep);
942 if (RT_FAILURE(rc))
943 return rc;
944 if (u32Sep == UINT32_MAX)
945 break;
946 if (u32Sep != i)
947 AssertMsgFailedReturn(("Out of sequence. u32Sep=%#x i=%#x\n", u32Sep, i), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
948
949 /* Get the name and instance number. */
950 char szName[RT_SIZEOFMEMB(PDMDEVREG, szName)];
951 rc = SSMR3GetStrZ(pSSM, szName, sizeof(szName));
952 if (RT_FAILURE(rc))
953 return rc;
954 uint32_t iInstance;
955 rc = SSMR3GetU32(pSSM, &iInstance);
956 if (RT_FAILURE(rc))
957 return rc;
958
959 /* Try locate it. */
960 PPDMDEVINS pDevIns;
961 for (pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
962 if ( !strcmp(szName, pDevIns->pReg->szName)
963 && pDevIns->iInstance == iInstance)
964 {
965 AssertLogRelMsgReturn(!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_FOUND),
966 ("%s/#%u\n", pDevIns->pReg->szName, pDevIns->iInstance),
967 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
968 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_FOUND;
969 break;
970 }
971 if (!pDevIns)
972 {
973 LogRel(("Device '%s'/%d not found in current config\n", szName, iInstance));
974 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
975 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device '%s'/%d not found in current config"), szName, iInstance);
976 }
977 }
978
979 /*
980 * Check that no additional devices were configured.
981 */
982 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
983 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_FOUND))
984 {
985 LogRel(("Device '%s'/%d not found in the saved state\n", pDevIns->pReg->szName, pDevIns->iInstance));
986 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
987 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device '%s'/%d not found in the saved state"),
988 pDevIns->pReg->szName, pDevIns->iInstance);
989 }
990
991 return VINF_SUCCESS;
992}
993
994
995/**
996 * Worker for PDMR3PowerOn that deals with one driver.
997 *
998 * @param pDrvIns The driver instance.
999 * @param pszDevName The parent device name.
1000 * @param iDevInstance The parent device instance number.
1001 * @param iLun The parent LUN number.
1002 */
1003DECLINLINE(int) pdmR3PowerOnDrv(PPDMDRVINS pDrvIns, const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1004{
1005 Assert(pDrvIns->Internal.s.fVMSuspended);
1006 if (pDrvIns->pReg->pfnPowerOn)
1007 {
1008 LogFlow(("PDMR3PowerOn: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1009 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1010 int rc = VINF_SUCCESS; pDrvIns->pReg->pfnPowerOn(pDrvIns);
1011 if (RT_FAILURE(rc))
1012 {
1013 LogRel(("PDMR3PowerOn: driver '%s'/%d on LUN#%d of device '%s'/%d -> %Rrc\n",
1014 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance, rc));
1015 return rc;
1016 }
1017 }
1018 pDrvIns->Internal.s.fVMSuspended = false;
1019 return VINF_SUCCESS;
1020}
1021
1022
1023/**
1024 * Worker for PDMR3PowerOn that deals with one USB device instance.
1025 *
1026 * @returns VBox status code.
1027 * @param pUsbIns The USB device instance.
1028 */
1029DECLINLINE(int) pdmR3PowerOnUsb(PPDMUSBINS pUsbIns)
1030{
1031 Assert(pUsbIns->Internal.s.fVMSuspended);
1032 if (pUsbIns->pReg->pfnVMPowerOn)
1033 {
1034 LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1035 int rc = VINF_SUCCESS; pUsbIns->pReg->pfnVMPowerOn(pUsbIns);
1036 if (RT_FAILURE(rc))
1037 {
1038 LogRel(("PDMR3PowerOn: device '%s'/%d -> %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1039 return rc;
1040 }
1041 }
1042 pUsbIns->Internal.s.fVMSuspended = false;
1043 return VINF_SUCCESS;
1044}
1045
1046
1047/**
1048 * Worker for PDMR3PowerOn that deals with one device instance.
1049 *
1050 * @returns VBox status code.
1051 * @param pDevIns The device instance.
1052 */
1053DECLINLINE(int) pdmR3PowerOnDev(PPDMDEVINS pDevIns)
1054{
1055 Assert(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED);
1056 if (pDevIns->pReg->pfnPowerOn)
1057 {
1058 LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1059 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
1060 int rc = VINF_SUCCESS; pDevIns->pReg->pfnPowerOn(pDevIns);
1061 PDMCritSectLeave(pDevIns->pCritSectRoR3);
1062 if (RT_FAILURE(rc))
1063 {
1064 LogRel(("PDMR3PowerOn: device '%s'/%d -> %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
1065 return rc;
1066 }
1067 }
1068 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1069 return VINF_SUCCESS;
1070}
1071
1072
1073/**
1074 * This function will notify all the devices and their
1075 * attached drivers about the VM now being powered on.
1076 *
1077 * @param pVM VM Handle.
1078 */
1079VMMR3DECL(void) PDMR3PowerOn(PVM pVM)
1080{
1081 LogFlow(("PDMR3PowerOn:\n"));
1082
1083 /*
1084 * Iterate thru the device instances and USB device instances,
1085 * processing the drivers associated with those.
1086 */
1087 int rc = VINF_SUCCESS;
1088 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns && RT_SUCCESS(rc); pDevIns = pDevIns->Internal.s.pNextR3)
1089 {
1090 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1091 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1092 rc = pdmR3PowerOnDrv(pDrvIns, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun);
1093 if (RT_SUCCESS(rc))
1094 rc = pdmR3PowerOnDev(pDevIns);
1095 }
1096
1097#ifdef VBOX_WITH_USB
1098 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns && RT_SUCCESS(rc); pUsbIns = pUsbIns->Internal.s.pNext)
1099 {
1100 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1101 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1102 rc = pdmR3PowerOnDrv(pDrvIns, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun);
1103 if (RT_SUCCESS(rc))
1104 rc = pdmR3PowerOnUsb(pUsbIns);
1105 }
1106#endif
1107
1108#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
1109 pdmR3AsyncCompletionResume(pVM);
1110#endif
1111
1112 /*
1113 * Resume all threads.
1114 */
1115 if (RT_SUCCESS(rc))
1116 pdmR3ThreadResumeAll(pVM);
1117
1118 /*
1119 * On failure, clean up via PDMR3Suspend.
1120 */
1121 if (RT_FAILURE(rc))
1122 PDMR3Suspend(pVM);
1123
1124 LogFlow(("PDMR3PowerOn: returns %Rrc\n", rc));
1125 return /*rc*/;
1126}
1127
1128
1129/**
1130 * Initializes the asynchronous notifi stats structure.
1131 *
1132 * @param pThis The asynchronous notifification stats.
1133 * @param pszOp The name of the operation.
1134 */
1135static void pdmR3NotifyAsyncInit(PPDMNOTIFYASYNCSTATS pThis, const char *pszOp)
1136{
1137 pThis->uStartNsTs = RTTimeNanoTS();
1138 pThis->cNsElapsedNextLog = 0;
1139 pThis->cLoops = 0;
1140 pThis->cAsync = 0;
1141 pThis->pszOp = pszOp;
1142 pThis->offList = 0;
1143 pThis->szList[0] = '\0';
1144}
1145
1146
1147/**
1148 * Begin a new loop, prepares to gather new stats.
1149 *
1150 * @param pThis The asynchronous notifification stats.
1151 */
1152static void pdmR3NotifyAsyncBeginLoop(PPDMNOTIFYASYNCSTATS pThis)
1153{
1154 pThis->cLoops++;
1155 pThis->cAsync = 0;
1156 pThis->offList = 0;
1157 pThis->szList[0] = '\0';
1158}
1159
1160
1161/**
1162 * Records a device or USB device with a pending asynchronous notification.
1163 *
1164 * @param pThis The asynchronous notifification stats.
1165 * @param pszName The name of the thing.
1166 * @param iInstance The instance number.
1167 */
1168static void pdmR3NotifyAsyncAdd(PPDMNOTIFYASYNCSTATS pThis, const char *pszName, uint32_t iInstance)
1169{
1170 pThis->cAsync++;
1171 if (pThis->offList < sizeof(pThis->szList) - 4)
1172 pThis->offList += RTStrPrintf(&pThis->szList[pThis->offList], sizeof(pThis->szList) - pThis->offList,
1173 pThis->offList == 0 ? "%s/%u" : ", %s/%u",
1174 pszName, iInstance);
1175}
1176
1177
1178/**
1179 * Records the asynchronous completition of a reset, suspend or power off.
1180 *
1181 * @param pThis The asynchronous notifification stats.
1182 * @param pszDrvName The driver name.
1183 * @param iDrvInstance The driver instance number.
1184 * @param pszDevName The device or USB device name.
1185 * @param iDevInstance The device or USB device instance number.
1186 * @param iLun The LUN.
1187 */
1188static void pdmR3NotifyAsyncAddDrv(PPDMNOTIFYASYNCSTATS pThis, const char *pszDrvName, uint32_t iDrvInstance,
1189 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1190{
1191 pThis->cAsync++;
1192 if (pThis->offList < sizeof(pThis->szList) - 8)
1193 pThis->offList += RTStrPrintf(&pThis->szList[pThis->offList], sizeof(pThis->szList) - pThis->offList,
1194 pThis->offList == 0 ? "%s/%u/%u/%s/%u" : ", %s/%u/%u/%s/%u",
1195 pszDevName, iDevInstance, iLun, pszDrvName, iDrvInstance);
1196}
1197
1198
1199/**
1200 * Log the stats.
1201 *
1202 * @param pThis The asynchronous notifification stats.
1203 */
1204static void pdmR3NotifyAsyncLog(PPDMNOTIFYASYNCSTATS pThis)
1205{
1206 /*
1207 * Return if we shouldn't log at this point.
1208 * We log with an internval increasing from 0 sec to 60 sec.
1209 */
1210 if (!pThis->cAsync)
1211 return;
1212
1213 uint64_t cNsElapsed = RTTimeNanoTS() - pThis->uStartNsTs;
1214 if (cNsElapsed < pThis->cNsElapsedNextLog)
1215 return;
1216
1217 if (pThis->cNsElapsedNextLog == 0)
1218 pThis->cNsElapsedNextLog = RT_NS_1SEC;
1219 else if (pThis->cNsElapsedNextLog >= RT_NS_1MIN / 2)
1220 pThis->cNsElapsedNextLog = RT_NS_1MIN;
1221 else
1222 pThis->cNsElapsedNextLog *= 2;
1223
1224 /*
1225 * Do the logging.
1226 */
1227 LogRel(("%s: after %5llu ms, %u loops: %u async tasks - %s\n",
1228 pThis->pszOp, cNsElapsed / RT_NS_1MS, pThis->cLoops, pThis->cAsync, pThis->szList));
1229}
1230
1231
1232/**
1233 * Wait for events and process pending requests.
1234 *
1235 * @param pThis The asynchronous notifification stats.
1236 * @param pVM The VM handle.
1237 */
1238static void pdmR3NotifyAsyncWaitAndProcessRequests(PPDMNOTIFYASYNCSTATS pThis, PVM pVM)
1239{
1240 VM_ASSERT_EMT0(pVM);
1241 int rc = VMR3AsyncPdmNotificationWaitU(&pVM->pUVM->aCpus[0]);
1242 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc - %s - %s\n", rc, pThis->pszOp, pThis->szList));
1243
1244 rc = VMR3ReqProcessU(pVM->pUVM, VMCPUID_ANY, true /*fPriorityOnly*/);
1245 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc - %s - %s\n", rc, pThis->pszOp, pThis->szList));
1246 rc = VMR3ReqProcessU(pVM->pUVM, 0/*idDstCpu*/, true /*fPriorityOnly*/);
1247 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc - %s - %s\n", rc, pThis->pszOp, pThis->szList));
1248}
1249
1250
1251/**
1252 * Worker for PDMR3Reset that deals with one driver.
1253 *
1254 * @param pDrvIns The driver instance.
1255 * @param pAsync The structure for recording asynchronous
1256 * notification tasks.
1257 * @param pszDevName The parent device name.
1258 * @param iDevInstance The parent device instance number.
1259 * @param iLun The parent LUN number.
1260 */
1261DECLINLINE(bool) pdmR3ResetDrv(PPDMDRVINS pDrvIns, PPDMNOTIFYASYNCSTATS pAsync,
1262 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1263{
1264 if (!pDrvIns->Internal.s.fVMReset)
1265 {
1266 pDrvIns->Internal.s.fVMReset = true;
1267 if (pDrvIns->pReg->pfnReset)
1268 {
1269 if (!pDrvIns->Internal.s.pfnAsyncNotify)
1270 {
1271 LogFlow(("PDMR3Reset: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1272 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1273 pDrvIns->pReg->pfnReset(pDrvIns);
1274 if (pDrvIns->Internal.s.pfnAsyncNotify)
1275 LogFlow(("PDMR3Reset: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1276 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1277 }
1278 else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
1279 {
1280 pDrvIns->Internal.s.pfnAsyncNotify = false;
1281 LogFlow(("PDMR3Reset: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1282 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1283 }
1284 if (pDrvIns->Internal.s.pfnAsyncNotify)
1285 {
1286 pDrvIns->Internal.s.fVMReset = false;
1287 pdmR3NotifyAsyncAddDrv(pAsync, pDrvIns->Internal.s.pDrv->pReg->szName, pDrvIns->iInstance,
1288 pszDevName, iDevInstance, iLun);
1289 return false;
1290 }
1291 }
1292 }
1293 return true;
1294}
1295
1296
1297/**
1298 * Worker for PDMR3Reset that deals with one USB device instance.
1299 *
1300 * @param pUsbIns The USB device instance.
1301 * @param pAsync The structure for recording asynchronous
1302 * notification tasks.
1303 */
1304DECLINLINE(void) pdmR3ResetUsb(PPDMUSBINS pUsbIns, PPDMNOTIFYASYNCSTATS pAsync)
1305{
1306 if (!pUsbIns->Internal.s.fVMReset)
1307 {
1308 pUsbIns->Internal.s.fVMReset = true;
1309 if (pUsbIns->pReg->pfnVMReset)
1310 {
1311 if (!pUsbIns->Internal.s.pfnAsyncNotify)
1312 {
1313 LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1314 pUsbIns->pReg->pfnVMReset(pUsbIns);
1315 if (pUsbIns->Internal.s.pfnAsyncNotify)
1316 LogFlow(("PDMR3Reset: Async notification started - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1317 }
1318 else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
1319 {
1320 LogFlow(("PDMR3Reset: Async notification completed - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1321 pUsbIns->Internal.s.pfnAsyncNotify = NULL;
1322 }
1323 if (pUsbIns->Internal.s.pfnAsyncNotify)
1324 {
1325 pUsbIns->Internal.s.fVMReset = false;
1326 pdmR3NotifyAsyncAdd(pAsync, pUsbIns->Internal.s.pUsbDev->pReg->szName, pUsbIns->iInstance);
1327 }
1328 }
1329 }
1330}
1331
1332
1333/**
1334 * Worker for PDMR3Reset that deals with one device instance.
1335 *
1336 * @param pDevIns The device instance.
1337 * @param pAsync The structure for recording asynchronous
1338 * notification tasks.
1339 */
1340DECLINLINE(void) pdmR3ResetDev(PPDMDEVINS pDevIns, PPDMNOTIFYASYNCSTATS pAsync)
1341{
1342 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_RESET))
1343 {
1344 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_RESET;
1345 if (pDevIns->pReg->pfnReset)
1346 {
1347 uint64_t cNsElapsed = RTTimeNanoTS();
1348 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
1349
1350 if (!pDevIns->Internal.s.pfnAsyncNotify)
1351 {
1352 LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1353 pDevIns->pReg->pfnReset(pDevIns);
1354 if (pDevIns->Internal.s.pfnAsyncNotify)
1355 LogFlow(("PDMR3Reset: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1356 }
1357 else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
1358 {
1359 LogFlow(("PDMR3Reset: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1360 pDevIns->Internal.s.pfnAsyncNotify = NULL;
1361 }
1362 if (pDevIns->Internal.s.pfnAsyncNotify)
1363 {
1364 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_RESET;
1365 pdmR3NotifyAsyncAdd(pAsync, pDevIns->Internal.s.pDevR3->pReg->szName, pDevIns->iInstance);
1366 }
1367
1368 PDMCritSectLeave(pDevIns->pCritSectRoR3);
1369 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1370 if (cNsElapsed >= PDMSUSPEND_WARN_AT_NS)
1371 LogRel(("PDMR3Reset: device '%s'/%d took %'llu ns to reset\n",
1372 pDevIns->pReg->szName, pDevIns->iInstance, cNsElapsed));
1373 }
1374 }
1375}
1376
1377
1378/**
1379 * Resets a virtual CPU.
1380 *
1381 * Used by PDMR3Reset and CPU hot plugging.
1382 *
1383 * @param pVCpu The virtual CPU handle.
1384 */
1385VMMR3DECL(void) PDMR3ResetCpu(PVMCPU pVCpu)
1386{
1387 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
1388 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
1389 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
1390 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_SMI);
1391}
1392
1393
1394/**
1395 * This function will notify all the devices and their attached drivers about
1396 * the VM now being reset.
1397 *
1398 * @param pVM VM Handle.
1399 */
1400VMMR3DECL(void) PDMR3Reset(PVM pVM)
1401{
1402 LogFlow(("PDMR3Reset:\n"));
1403
1404 /*
1405 * Clear all the reset flags.
1406 */
1407 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1408 {
1409 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_RESET;
1410 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1411 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1412 pDrvIns->Internal.s.fVMReset = false;
1413 }
1414#ifdef VBOX_WITH_USB
1415 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1416 {
1417 pUsbIns->Internal.s.fVMReset = false;
1418 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1419 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1420 pDrvIns->Internal.s.fVMReset = false;
1421 }
1422#endif
1423
1424 /*
1425 * The outer loop repeats until there are no more async requests.
1426 */
1427 PDMNOTIFYASYNCSTATS Async;
1428 pdmR3NotifyAsyncInit(&Async, "PDMR3Reset");
1429 for (;;)
1430 {
1431 pdmR3NotifyAsyncBeginLoop(&Async);
1432
1433 /*
1434 * Iterate thru the device instances and USB device instances,
1435 * processing the drivers associated with those.
1436 */
1437 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1438 {
1439 unsigned const cAsyncStart = Async.cAsync;
1440
1441 if (Async.cAsync == cAsyncStart)
1442 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1443 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1444 if (!pdmR3ResetDrv(pDrvIns, &Async, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
1445 break;
1446
1447 if (Async.cAsync == cAsyncStart)
1448 pdmR3ResetDev(pDevIns, &Async);
1449 }
1450
1451#ifdef VBOX_WITH_USB
1452 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1453 {
1454 unsigned const cAsyncStart = Async.cAsync;
1455
1456 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1457 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1458 if (!pdmR3ResetDrv(pDrvIns, &Async, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
1459 break;
1460
1461 if (Async.cAsync == cAsyncStart)
1462 pdmR3ResetUsb(pUsbIns, &Async);
1463 }
1464#endif
1465 if (!Async.cAsync)
1466 break;
1467 pdmR3NotifyAsyncLog(&Async);
1468 pdmR3NotifyAsyncWaitAndProcessRequests(&Async, pVM);
1469 }
1470
1471 /*
1472 * Clear all pending interrupts and DMA operations.
1473 */
1474 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1475 PDMR3ResetCpu(&pVM->aCpus[idCpu]);
1476 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
1477
1478 LogFlow(("PDMR3Reset: returns void\n"));
1479}
1480
1481
1482/**
1483 * Worker for PDMR3Suspend that deals with one driver.
1484 *
1485 * @param pDrvIns The driver instance.
1486 * @param pAsync The structure for recording asynchronous
1487 * notification tasks.
1488 * @param pszDevName The parent device name.
1489 * @param iDevInstance The parent device instance number.
1490 * @param iLun The parent LUN number.
1491 */
1492DECLINLINE(bool) pdmR3SuspendDrv(PPDMDRVINS pDrvIns, PPDMNOTIFYASYNCSTATS pAsync,
1493 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1494{
1495 if (!pDrvIns->Internal.s.fVMSuspended)
1496 {
1497 pDrvIns->Internal.s.fVMSuspended = true;
1498 if (pDrvIns->pReg->pfnSuspend)
1499 {
1500 uint64_t cNsElapsed = RTTimeNanoTS();
1501
1502 if (!pDrvIns->Internal.s.pfnAsyncNotify)
1503 {
1504 LogFlow(("PDMR3Suspend: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1505 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1506 pDrvIns->pReg->pfnSuspend(pDrvIns);
1507 if (pDrvIns->Internal.s.pfnAsyncNotify)
1508 LogFlow(("PDMR3Suspend: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1509 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1510 }
1511 else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
1512 {
1513 pDrvIns->Internal.s.pfnAsyncNotify = NULL;
1514 LogFlow(("PDMR3Suspend: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1515 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1516 }
1517
1518 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1519 if (cNsElapsed >= PDMSUSPEND_WARN_AT_NS)
1520 LogRel(("PDMR3Suspend: Driver '%s'/%d on LUN#%d of device '%s'/%d took %'llu ns to suspend\n",
1521 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance, cNsElapsed));
1522
1523 if (pDrvIns->Internal.s.pfnAsyncNotify)
1524 {
1525 pDrvIns->Internal.s.fVMSuspended = false;
1526 pdmR3NotifyAsyncAddDrv(pAsync, pDrvIns->Internal.s.pDrv->pReg->szName, pDrvIns->iInstance, pszDevName, iDevInstance, iLun);
1527 return false;
1528 }
1529 }
1530 }
1531 return true;
1532}
1533
1534
1535/**
1536 * Worker for PDMR3Suspend that deals with one USB device instance.
1537 *
1538 * @param pUsbIns The USB device instance.
1539 * @param pAsync The structure for recording asynchronous
1540 * notification tasks.
1541 */
1542DECLINLINE(void) pdmR3SuspendUsb(PPDMUSBINS pUsbIns, PPDMNOTIFYASYNCSTATS pAsync)
1543{
1544 if (!pUsbIns->Internal.s.fVMSuspended)
1545 {
1546 pUsbIns->Internal.s.fVMSuspended = true;
1547 if (pUsbIns->pReg->pfnVMSuspend)
1548 {
1549 uint64_t cNsElapsed = RTTimeNanoTS();
1550
1551 if (!pUsbIns->Internal.s.pfnAsyncNotify)
1552 {
1553 LogFlow(("PDMR3Suspend: Notifying - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1554 pUsbIns->pReg->pfnVMSuspend(pUsbIns);
1555 if (pUsbIns->Internal.s.pfnAsyncNotify)
1556 LogFlow(("PDMR3Suspend: Async notification started - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1557 }
1558 else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
1559 {
1560 LogFlow(("PDMR3Suspend: Async notification completed - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1561 pUsbIns->Internal.s.pfnAsyncNotify = NULL;
1562 }
1563 if (pUsbIns->Internal.s.pfnAsyncNotify)
1564 {
1565 pUsbIns->Internal.s.fVMSuspended = false;
1566 pdmR3NotifyAsyncAdd(pAsync, pUsbIns->Internal.s.pUsbDev->pReg->szName, pUsbIns->iInstance);
1567 }
1568
1569 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1570 if (cNsElapsed >= PDMSUSPEND_WARN_AT_NS)
1571 LogRel(("PDMR3Suspend: USB device '%s'/%d took %'llu ns to suspend\n",
1572 pUsbIns->pReg->szName, pUsbIns->iInstance, cNsElapsed));
1573 }
1574 }
1575}
1576
1577
1578/**
1579 * Worker for PDMR3Suspend that deals with one device instance.
1580 *
1581 * @param pDevIns The device instance.
1582 * @param pAsync The structure for recording asynchronous
1583 * notification tasks.
1584 */
1585DECLINLINE(void) pdmR3SuspendDev(PPDMDEVINS pDevIns, PPDMNOTIFYASYNCSTATS pAsync)
1586{
1587 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED))
1588 {
1589 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_SUSPENDED;
1590 if (pDevIns->pReg->pfnSuspend)
1591 {
1592 uint64_t cNsElapsed = RTTimeNanoTS();
1593 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
1594
1595 if (!pDevIns->Internal.s.pfnAsyncNotify)
1596 {
1597 LogFlow(("PDMR3Suspend: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1598 pDevIns->pReg->pfnSuspend(pDevIns);
1599 if (pDevIns->Internal.s.pfnAsyncNotify)
1600 LogFlow(("PDMR3Suspend: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1601 }
1602 else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
1603 {
1604 LogFlow(("PDMR3Suspend: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1605 pDevIns->Internal.s.pfnAsyncNotify = NULL;
1606 }
1607 if (pDevIns->Internal.s.pfnAsyncNotify)
1608 {
1609 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1610 pdmR3NotifyAsyncAdd(pAsync, pDevIns->Internal.s.pDevR3->pReg->szName, pDevIns->iInstance);
1611 }
1612
1613 PDMCritSectLeave(pDevIns->pCritSectRoR3);
1614 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1615 if (cNsElapsed >= PDMSUSPEND_WARN_AT_NS)
1616 LogRel(("PDMR3Suspend: device '%s'/%d took %'llu ns to suspend\n",
1617 pDevIns->pReg->szName, pDevIns->iInstance, cNsElapsed));
1618 }
1619 }
1620}
1621
1622
1623/**
1624 * This function will notify all the devices and their attached drivers about
1625 * the VM now being suspended.
1626 *
1627 * @param pVM The VM Handle.
1628 * @thread EMT(0)
1629 */
1630VMMR3DECL(void) PDMR3Suspend(PVM pVM)
1631{
1632 LogFlow(("PDMR3Suspend:\n"));
1633 VM_ASSERT_EMT0(pVM);
1634 uint64_t cNsElapsed = RTTimeNanoTS();
1635
1636 /*
1637 * The outer loop repeats until there are no more async requests.
1638 *
1639 * Note! We depend on the suspended indicators to be in the desired state
1640 * and we do not reset them before starting because this allows
1641 * PDMR3PowerOn and PDMR3Resume to use PDMR3Suspend for cleaning up
1642 * on failure.
1643 */
1644 PDMNOTIFYASYNCSTATS Async;
1645 pdmR3NotifyAsyncInit(&Async, "PDMR3Suspend");
1646 for (;;)
1647 {
1648 pdmR3NotifyAsyncBeginLoop(&Async);
1649
1650 /*
1651 * Iterate thru the device instances and USB device instances,
1652 * processing the drivers associated with those.
1653 *
1654 * The attached drivers are normally processed first. Some devices
1655 * (like DevAHCI) though needs to be notified before the drivers so
1656 * that it doesn't kick off any new requests after the drivers stopped
1657 * taking any. (DrvVD changes to read-only in this particular case.)
1658 */
1659 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1660 {
1661 unsigned const cAsyncStart = Async.cAsync;
1662
1663 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION)
1664 pdmR3SuspendDev(pDevIns, &Async);
1665
1666 if (Async.cAsync == cAsyncStart)
1667 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1668 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1669 if (!pdmR3SuspendDrv(pDrvIns, &Async, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
1670 break;
1671
1672 if ( Async.cAsync == cAsyncStart
1673 && !(pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION))
1674 pdmR3SuspendDev(pDevIns, &Async);
1675 }
1676
1677#ifdef VBOX_WITH_USB
1678 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1679 {
1680 unsigned const cAsyncStart = Async.cAsync;
1681
1682 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1683 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1684 if (!pdmR3SuspendDrv(pDrvIns, &Async, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
1685 break;
1686
1687 if (Async.cAsync == cAsyncStart)
1688 pdmR3SuspendUsb(pUsbIns, &Async);
1689 }
1690#endif
1691 if (!Async.cAsync)
1692 break;
1693 pdmR3NotifyAsyncLog(&Async);
1694 pdmR3NotifyAsyncWaitAndProcessRequests(&Async, pVM);
1695 }
1696
1697 /*
1698 * Suspend all threads.
1699 */
1700 pdmR3ThreadSuspendAll(pVM);
1701
1702 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1703 LogRel(("PDMR3Suspend: %'llu ns run time\n", cNsElapsed));
1704}
1705
1706
1707/**
1708 * Worker for PDMR3Resume that deals with one driver.
1709 *
1710 * @param pDrvIns The driver instance.
1711 * @param pszDevName The parent device name.
1712 * @param iDevInstance The parent device instance number.
1713 * @param iLun The parent LUN number.
1714 */
1715DECLINLINE(int) pdmR3ResumeDrv(PPDMDRVINS pDrvIns, const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1716{
1717 Assert(pDrvIns->Internal.s.fVMSuspended);
1718 if (pDrvIns->pReg->pfnResume)
1719 {
1720 LogFlow(("PDMR3Resume: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1721 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1722 int rc = VINF_SUCCESS; pDrvIns->pReg->pfnResume(pDrvIns);
1723 if (RT_FAILURE(rc))
1724 {
1725 LogRel(("PDMR3Resume: driver '%s'/%d on LUN#%d of device '%s'/%d -> %Rrc\n",
1726 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance, rc));
1727 return rc;
1728 }
1729 }
1730 pDrvIns->Internal.s.fVMSuspended = false;
1731 return VINF_SUCCESS;
1732}
1733
1734
1735/**
1736 * Worker for PDMR3Resume that deals with one USB device instance.
1737 *
1738 * @returns VBox status code.
1739 * @param pUsbIns The USB device instance.
1740 */
1741DECLINLINE(int) pdmR3ResumeUsb(PPDMUSBINS pUsbIns)
1742{
1743 Assert(pUsbIns->Internal.s.fVMSuspended);
1744 if (pUsbIns->pReg->pfnVMResume)
1745 {
1746 LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1747 int rc = VINF_SUCCESS; pUsbIns->pReg->pfnVMResume(pUsbIns);
1748 if (RT_FAILURE(rc))
1749 {
1750 LogRel(("PDMR3Resume: device '%s'/%d -> %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1751 return rc;
1752 }
1753 }
1754 pUsbIns->Internal.s.fVMSuspended = false;
1755 return VINF_SUCCESS;
1756}
1757
1758
1759/**
1760 * Worker for PDMR3Resume that deals with one device instance.
1761 *
1762 * @returns VBox status code.
1763 * @param pDevIns The device instance.
1764 */
1765DECLINLINE(int) pdmR3ResumeDev(PPDMDEVINS pDevIns)
1766{
1767 Assert(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED);
1768 if (pDevIns->pReg->pfnResume)
1769 {
1770 LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1771 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
1772 int rc = VINF_SUCCESS; pDevIns->pReg->pfnResume(pDevIns);
1773 PDMCritSectLeave(pDevIns->pCritSectRoR3);
1774 if (RT_FAILURE(rc))
1775 {
1776 LogRel(("PDMR3Resume: device '%s'/%d -> %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
1777 return rc;
1778 }
1779 }
1780 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1781 return VINF_SUCCESS;
1782}
1783
1784
1785/**
1786 * This function will notify all the devices and their
1787 * attached drivers about the VM now being resumed.
1788 *
1789 * @param pVM VM Handle.
1790 */
1791VMMR3DECL(void) PDMR3Resume(PVM pVM)
1792{
1793 LogFlow(("PDMR3Resume:\n"));
1794
1795 /*
1796 * Iterate thru the device instances and USB device instances,
1797 * processing the drivers associated with those.
1798 */
1799 int rc = VINF_SUCCESS;
1800 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns && RT_SUCCESS(rc); pDevIns = pDevIns->Internal.s.pNextR3)
1801 {
1802 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1803 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1804 rc = pdmR3ResumeDrv(pDrvIns, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun);
1805 if (RT_SUCCESS(rc))
1806 rc = pdmR3ResumeDev(pDevIns);
1807 }
1808
1809#ifdef VBOX_WITH_USB
1810 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns && RT_SUCCESS(rc); pUsbIns = pUsbIns->Internal.s.pNext)
1811 {
1812 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1813 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1814 rc = pdmR3ResumeDrv(pDrvIns, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun);
1815 if (RT_SUCCESS(rc))
1816 rc = pdmR3ResumeUsb(pUsbIns);
1817 }
1818#endif
1819
1820 /*
1821 * Resume all threads.
1822 */
1823 if (RT_SUCCESS(rc))
1824 pdmR3ThreadResumeAll(pVM);
1825
1826 /*
1827 * Resume the block cache.
1828 */
1829 if (RT_SUCCESS(rc))
1830 pdmR3BlkCacheResume(pVM);
1831
1832 /*
1833 * On failure, clean up via PDMR3Suspend.
1834 */
1835 if (RT_FAILURE(rc))
1836 PDMR3Suspend(pVM);
1837
1838 LogFlow(("PDMR3Resume: returns %Rrc\n", rc));
1839 return /*rc*/;
1840}
1841
1842
1843/**
1844 * Worker for PDMR3PowerOff that deals with one driver.
1845 *
1846 * @param pDrvIns The driver instance.
1847 * @param pAsync The structure for recording asynchronous
1848 * notification tasks.
1849 * @param pszDevName The parent device name.
1850 * @param iDevInstance The parent device instance number.
1851 * @param iLun The parent LUN number.
1852 */
1853DECLINLINE(bool) pdmR3PowerOffDrv(PPDMDRVINS pDrvIns, PPDMNOTIFYASYNCSTATS pAsync,
1854 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1855{
1856 if (!pDrvIns->Internal.s.fVMSuspended)
1857 {
1858 pDrvIns->Internal.s.fVMSuspended = true;
1859 if (pDrvIns->pReg->pfnPowerOff)
1860 {
1861 uint64_t cNsElapsed = RTTimeNanoTS();
1862
1863 if (!pDrvIns->Internal.s.pfnAsyncNotify)
1864 {
1865 LogFlow(("PDMR3PowerOff: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1866 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1867 pDrvIns->pReg->pfnPowerOff(pDrvIns);
1868 if (pDrvIns->Internal.s.pfnAsyncNotify)
1869 LogFlow(("PDMR3PowerOff: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1870 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1871 }
1872 else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
1873 {
1874 pDrvIns->Internal.s.pfnAsyncNotify = false;
1875 LogFlow(("PDMR3PowerOff: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1876 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1877 }
1878
1879 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1880 if (cNsElapsed >= PDMPOWEROFF_WARN_AT_NS)
1881 LogRel(("PDMR3PowerOff: Driver '%s'/%d on LUN#%d of device '%s'/%d took %'llu ns to power off\n",
1882 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance, cNsElapsed));
1883
1884 if (pDrvIns->Internal.s.pfnAsyncNotify)
1885 {
1886 pDrvIns->Internal.s.fVMSuspended = false;
1887 pdmR3NotifyAsyncAddDrv(pAsync, pDrvIns->Internal.s.pDrv->pReg->szName, pDrvIns->iInstance,
1888 pszDevName, iDevInstance, iLun);
1889 return false;
1890 }
1891 }
1892 }
1893 return true;
1894}
1895
1896
1897/**
1898 * Worker for PDMR3PowerOff that deals with one USB device instance.
1899 *
1900 * @param pUsbIns The USB device instance.
1901 * @param pAsync The structure for recording asynchronous
1902 * notification tasks.
1903 */
1904DECLINLINE(void) pdmR3PowerOffUsb(PPDMUSBINS pUsbIns, PPDMNOTIFYASYNCSTATS pAsync)
1905{
1906 if (!pUsbIns->Internal.s.fVMSuspended)
1907 {
1908 pUsbIns->Internal.s.fVMSuspended = true;
1909 if (pUsbIns->pReg->pfnVMPowerOff)
1910 {
1911 uint64_t cNsElapsed = RTTimeNanoTS();
1912
1913 if (!pUsbIns->Internal.s.pfnAsyncNotify)
1914 {
1915 LogFlow(("PDMR3PowerOff: Notifying - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1916 pUsbIns->pReg->pfnVMPowerOff(pUsbIns);
1917 if (pUsbIns->Internal.s.pfnAsyncNotify)
1918 LogFlow(("PDMR3PowerOff: Async notification started - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1919 }
1920 else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
1921 {
1922 LogFlow(("PDMR3PowerOff: Async notification completed - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1923 pUsbIns->Internal.s.pfnAsyncNotify = NULL;
1924 }
1925 if (pUsbIns->Internal.s.pfnAsyncNotify)
1926 {
1927 pUsbIns->Internal.s.fVMSuspended = false;
1928 pdmR3NotifyAsyncAdd(pAsync, pUsbIns->Internal.s.pUsbDev->pReg->szName, pUsbIns->iInstance);
1929 }
1930
1931 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1932 if (cNsElapsed >= PDMPOWEROFF_WARN_AT_NS)
1933 LogRel(("PDMR3PowerOff: USB device '%s'/%d took %'llu ns to power off\n",
1934 pUsbIns->pReg->szName, pUsbIns->iInstance, cNsElapsed));
1935
1936 }
1937 }
1938}
1939
1940
1941/**
1942 * Worker for PDMR3PowerOff that deals with one device instance.
1943 *
1944 * @param pDevIns The device instance.
1945 * @param pAsync The structure for recording asynchronous
1946 * notification tasks.
1947 */
1948DECLINLINE(void) pdmR3PowerOffDev(PPDMDEVINS pDevIns, PPDMNOTIFYASYNCSTATS pAsync)
1949{
1950 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED))
1951 {
1952 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_SUSPENDED;
1953 if (pDevIns->pReg->pfnPowerOff)
1954 {
1955 uint64_t cNsElapsed = RTTimeNanoTS();
1956 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
1957
1958 if (!pDevIns->Internal.s.pfnAsyncNotify)
1959 {
1960 LogFlow(("PDMR3PowerOff: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1961 pDevIns->pReg->pfnPowerOff(pDevIns);
1962 if (pDevIns->Internal.s.pfnAsyncNotify)
1963 LogFlow(("PDMR3PowerOff: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1964 }
1965 else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
1966 {
1967 LogFlow(("PDMR3PowerOff: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1968 pDevIns->Internal.s.pfnAsyncNotify = NULL;
1969 }
1970 if (pDevIns->Internal.s.pfnAsyncNotify)
1971 {
1972 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1973 pdmR3NotifyAsyncAdd(pAsync, pDevIns->Internal.s.pDevR3->pReg->szName, pDevIns->iInstance);
1974 }
1975
1976 PDMCritSectLeave(pDevIns->pCritSectRoR3);
1977 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1978 if (cNsElapsed >= PDMPOWEROFF_WARN_AT_NS)
1979 LogFlow(("PDMR3PowerOff: Device '%s'/%d took %'llu ns to power off\n",
1980 pDevIns->pReg->szName, pDevIns->iInstance, cNsElapsed));
1981 }
1982 }
1983}
1984
1985
1986/**
1987 * This function will notify all the devices and their
1988 * attached drivers about the VM being powered off.
1989 *
1990 * @param pVM VM Handle.
1991 */
1992VMMR3DECL(void) PDMR3PowerOff(PVM pVM)
1993{
1994 LogFlow(("PDMR3PowerOff:\n"));
1995 uint64_t cNsElapsed = RTTimeNanoTS();
1996
1997 /*
1998 * The outer loop repeats until there are no more async requests.
1999 */
2000 PDMNOTIFYASYNCSTATS Async;
2001 pdmR3NotifyAsyncInit(&Async, "PDMR3PowerOff");
2002 for (;;)
2003 {
2004 pdmR3NotifyAsyncBeginLoop(&Async);
2005
2006 /*
2007 * Iterate thru the device instances and USB device instances,
2008 * processing the drivers associated with those.
2009 *
2010 * The attached drivers are normally processed first. Some devices
2011 * (like DevAHCI) though needs to be notified before the drivers so
2012 * that it doesn't kick off any new requests after the drivers stopped
2013 * taking any. (DrvVD changes to read-only in this particular case.)
2014 */
2015 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2016 {
2017 unsigned const cAsyncStart = Async.cAsync;
2018
2019 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION)
2020 pdmR3PowerOffDev(pDevIns, &Async);
2021
2022 if (Async.cAsync == cAsyncStart)
2023 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
2024 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2025 if (!pdmR3PowerOffDrv(pDrvIns, &Async, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
2026 break;
2027
2028 if ( Async.cAsync == cAsyncStart
2029 && !(pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION))
2030 pdmR3PowerOffDev(pDevIns, &Async);
2031 }
2032
2033#ifdef VBOX_WITH_USB
2034 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2035 {
2036 unsigned const cAsyncStart = Async.cAsync;
2037
2038 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
2039 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2040 if (!pdmR3PowerOffDrv(pDrvIns, &Async, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
2041 break;
2042
2043 if (Async.cAsync == cAsyncStart)
2044 pdmR3PowerOffUsb(pUsbIns, &Async);
2045 }
2046#endif
2047 if (!Async.cAsync)
2048 break;
2049 pdmR3NotifyAsyncLog(&Async);
2050 pdmR3NotifyAsyncWaitAndProcessRequests(&Async, pVM);
2051 }
2052
2053 /*
2054 * Suspend all threads.
2055 */
2056 pdmR3ThreadSuspendAll(pVM);
2057
2058 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
2059 LogRel(("PDMR3PowerOff: %'llu ns run time\n", cNsElapsed));
2060}
2061
2062
2063/**
2064 * Queries the base interface of a device instance.
2065 *
2066 * The caller can use this to query other interfaces the device implements
2067 * and use them to talk to the device.
2068 *
2069 * @returns VBox status code.
2070 * @param pVM VM handle.
2071 * @param pszDevice Device name.
2072 * @param iInstance Device instance.
2073 * @param ppBase Where to store the pointer to the base device interface on success.
2074 * @remark We're not doing any locking ATM, so don't try call this at times when the
2075 * device chain is known to be updated.
2076 */
2077VMMR3DECL(int) PDMR3QueryDevice(PVM pVM, const char *pszDevice, unsigned iInstance, PPDMIBASE *ppBase)
2078{
2079 LogFlow(("PDMR3DeviceQuery: pszDevice=%p:{%s} iInstance=%u ppBase=%p\n", pszDevice, pszDevice, iInstance, ppBase));
2080
2081 /*
2082 * Iterate registered devices looking for the device.
2083 */
2084 size_t cchDevice = strlen(pszDevice);
2085 for (PPDMDEV pDev = pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
2086 {
2087 if ( pDev->cchName == cchDevice
2088 && !memcmp(pDev->pReg->szName, pszDevice, cchDevice))
2089 {
2090 /*
2091 * Iterate device instances.
2092 */
2093 for (PPDMDEVINS pDevIns = pDev->pInstances; pDevIns; pDevIns = pDevIns->Internal.s.pPerDeviceNextR3)
2094 {
2095 if (pDevIns->iInstance == iInstance)
2096 {
2097 if (pDevIns->IBase.pfnQueryInterface)
2098 {
2099 *ppBase = &pDevIns->IBase;
2100 LogFlow(("PDMR3DeviceQuery: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
2101 return VINF_SUCCESS;
2102 }
2103
2104 LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NO_IBASE\n"));
2105 return VERR_PDM_DEVICE_INSTANCE_NO_IBASE;
2106 }
2107 }
2108
2109 LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NOT_FOUND\n"));
2110 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND;
2111 }
2112 }
2113
2114 LogFlow(("PDMR3QueryDevice: returns VERR_PDM_DEVICE_NOT_FOUND\n"));
2115 return VERR_PDM_DEVICE_NOT_FOUND;
2116}
2117
2118
2119/**
2120 * Queries the base interface of a device LUN.
2121 *
2122 * This differs from PDMR3QueryLun by that it returns the interface on the
2123 * device and not the top level driver.
2124 *
2125 * @returns VBox status code.
2126 * @param pVM VM Handle.
2127 * @param pszDevice Device name.
2128 * @param iInstance Device instance.
2129 * @param iLun The Logical Unit to obtain the interface of.
2130 * @param ppBase Where to store the base interface pointer.
2131 * @remark We're not doing any locking ATM, so don't try call this at times when the
2132 * device chain is known to be updated.
2133 */
2134VMMR3DECL(int) PDMR3QueryDeviceLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
2135{
2136 LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
2137 pszDevice, pszDevice, iInstance, iLun, ppBase));
2138
2139 /*
2140 * Find the LUN.
2141 */
2142 PPDMLUN pLun;
2143 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
2144 if (RT_SUCCESS(rc))
2145 {
2146 *ppBase = pLun->pBase;
2147 LogFlow(("PDMR3QueryDeviceLun: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
2148 return VINF_SUCCESS;
2149 }
2150 LogFlow(("PDMR3QueryDeviceLun: returns %Rrc\n", rc));
2151 return rc;
2152}
2153
2154
2155/**
2156 * Query the interface of the top level driver on a LUN.
2157 *
2158 * @returns VBox status code.
2159 * @param pVM VM Handle.
2160 * @param pszDevice Device name.
2161 * @param iInstance Device instance.
2162 * @param iLun The Logical Unit to obtain the interface of.
2163 * @param ppBase Where to store the base interface pointer.
2164 * @remark We're not doing any locking ATM, so don't try call this at times when the
2165 * device chain is known to be updated.
2166 */
2167VMMR3DECL(int) PDMR3QueryLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
2168{
2169 LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
2170 pszDevice, pszDevice, iInstance, iLun, ppBase));
2171 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
2172
2173 /*
2174 * Find the LUN.
2175 */
2176 PPDMLUN pLun;
2177 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
2178 if (RT_SUCCESS(rc))
2179 {
2180 if (pLun->pTop)
2181 {
2182 *ppBase = &pLun->pTop->IBase;
2183 LogFlow(("PDMR3QueryLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
2184 return VINF_SUCCESS;
2185 }
2186 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
2187 }
2188 LogFlow(("PDMR3QueryLun: returns %Rrc\n", rc));
2189 return rc;
2190}
2191
2192
2193/**
2194 * Query the interface of a named driver on a LUN.
2195 *
2196 * If the driver appears more than once in the driver chain, the first instance
2197 * is returned.
2198 *
2199 * @returns VBox status code.
2200 * @param pVM VM Handle.
2201 * @param pszDevice Device name.
2202 * @param iInstance Device instance.
2203 * @param iLun The Logical Unit to obtain the interface of.
2204 * @param pszDriver The driver name.
2205 * @param ppBase Where to store the base interface pointer.
2206 *
2207 * @remark We're not doing any locking ATM, so don't try call this at times when the
2208 * device chain is known to be updated.
2209 */
2210VMMR3DECL(int) PDMR3QueryDriverOnLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, const char *pszDriver, PPPDMIBASE ppBase)
2211{
2212 LogFlow(("PDMR3QueryDriverOnLun: pszDevice=%p:{%s} iInstance=%u iLun=%u pszDriver=%p:{%s} ppBase=%p\n",
2213 pszDevice, pszDevice, iInstance, iLun, pszDriver, pszDriver, ppBase));
2214
2215 /*
2216 * Find the LUN.
2217 */
2218 PPDMLUN pLun;
2219 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
2220 if (RT_SUCCESS(rc))
2221 {
2222 if (pLun->pTop)
2223 {
2224 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2225 if (!strcmp(pDrvIns->pReg->szName, pszDriver))
2226 {
2227 *ppBase = &pDrvIns->IBase;
2228 LogFlow(("PDMR3QueryDriverOnLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
2229 return VINF_SUCCESS;
2230
2231 }
2232 rc = VERR_PDM_DRIVER_NOT_FOUND;
2233 }
2234 else
2235 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
2236 }
2237 LogFlow(("PDMR3QueryDriverOnLun: returns %Rrc\n", rc));
2238 return rc;
2239}
2240
2241/**
2242 * Executes pending DMA transfers.
2243 * Forced Action handler.
2244 *
2245 * @param pVM VM handle.
2246 */
2247VMMR3DECL(void) PDMR3DmaRun(PVM pVM)
2248{
2249 /* Note! Not really SMP safe; restrict it to VCPU 0. */
2250 if (VMMGetCpuId(pVM) != 0)
2251 return;
2252
2253 if (VM_FF_TESTANDCLEAR(pVM, VM_FF_PDM_DMA))
2254 {
2255 if (pVM->pdm.s.pDmac)
2256 {
2257 bool fMore = pVM->pdm.s.pDmac->Reg.pfnRun(pVM->pdm.s.pDmac->pDevIns);
2258 if (fMore)
2259 VM_FF_SET(pVM, VM_FF_PDM_DMA);
2260 }
2261 }
2262}
2263
2264
2265/**
2266 * Service a VMMCALLRING3_PDM_LOCK call.
2267 *
2268 * @returns VBox status code.
2269 * @param pVM The VM handle.
2270 */
2271VMMR3DECL(int) PDMR3LockCall(PVM pVM)
2272{
2273 return PDMR3CritSectEnterEx(&pVM->pdm.s.CritSect, true /* fHostCall */);
2274}
2275
2276
2277/**
2278 * Registers the VMM device heap
2279 *
2280 * @returns VBox status code.
2281 * @param pVM VM handle.
2282 * @param GCPhys The physical address.
2283 * @param pvHeap Ring-3 pointer.
2284 * @param cbSize Size of the heap.
2285 */
2286VMMR3DECL(int) PDMR3RegisterVMMDevHeap(PVM pVM, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbSize)
2287{
2288 Assert(pVM->pdm.s.pvVMMDevHeap == NULL);
2289
2290 Log(("PDMR3RegisterVMMDevHeap %RGp %RHv %x\n", GCPhys, pvHeap, cbSize));
2291 pVM->pdm.s.pvVMMDevHeap = pvHeap;
2292 pVM->pdm.s.GCPhysVMMDevHeap = GCPhys;
2293 pVM->pdm.s.cbVMMDevHeap = cbSize;
2294 pVM->pdm.s.cbVMMDevHeapLeft = cbSize;
2295 return VINF_SUCCESS;
2296}
2297
2298
2299/**
2300 * Unregisters the VMM device heap
2301 *
2302 * @returns VBox status code.
2303 * @param pVM VM handle.
2304 * @param GCPhys The physical address.
2305 */
2306VMMR3DECL(int) PDMR3UnregisterVMMDevHeap(PVM pVM, RTGCPHYS GCPhys)
2307{
2308 Assert(pVM->pdm.s.GCPhysVMMDevHeap == GCPhys);
2309
2310 Log(("PDMR3UnregisterVMMDevHeap %RGp\n", GCPhys));
2311 pVM->pdm.s.pvVMMDevHeap = NULL;
2312 pVM->pdm.s.GCPhysVMMDevHeap = NIL_RTGCPHYS;
2313 pVM->pdm.s.cbVMMDevHeap = 0;
2314 pVM->pdm.s.cbVMMDevHeapLeft = 0;
2315 return VINF_SUCCESS;
2316}
2317
2318
2319/**
2320 * Allocates memory from the VMM device heap
2321 *
2322 * @returns VBox status code.
2323 * @param pVM VM handle.
2324 * @param cbSize Allocation size.
2325 * @param pv Ring-3 pointer. (out)
2326 */
2327VMMR3DECL(int) PDMR3VMMDevHeapAlloc(PVM pVM, unsigned cbSize, RTR3PTR *ppv)
2328{
2329#ifdef DEBUG_bird
2330 if (!cbSize || cbSize > pVM->pdm.s.cbVMMDevHeapLeft)
2331 return VERR_NO_MEMORY;
2332#else
2333 AssertReturn(cbSize && cbSize <= pVM->pdm.s.cbVMMDevHeapLeft, VERR_NO_MEMORY);
2334#endif
2335
2336 Log(("PDMR3VMMDevHeapAlloc %x\n", cbSize));
2337
2338 /** @todo not a real heap as there's currently only one user. */
2339 *ppv = pVM->pdm.s.pvVMMDevHeap;
2340 pVM->pdm.s.cbVMMDevHeapLeft = 0;
2341 return VINF_SUCCESS;
2342}
2343
2344
2345/**
2346 * Frees memory from the VMM device heap
2347 *
2348 * @returns VBox status code.
2349 * @param pVM VM handle.
2350 * @param pv Ring-3 pointer.
2351 */
2352VMMR3DECL(int) PDMR3VMMDevHeapFree(PVM pVM, RTR3PTR pv)
2353{
2354 Log(("PDMR3VMMDevHeapFree %RHv\n", pv));
2355
2356 /** @todo not a real heap as there's currently only one user. */
2357 pVM->pdm.s.cbVMMDevHeapLeft = pVM->pdm.s.cbVMMDevHeap;
2358 return VINF_SUCCESS;
2359}
2360
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