VirtualBox

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

Last change on this file since 38838 was 38838, checked in by vboxsync, 13 years ago

VMM,++: Try fix the async reset, suspend and power-off problems in PDM wrt conflicting VMM requests. Split them into priority requests and normal requests. The priority requests can safely be processed when PDM is doing async state change waits, the normal ones cannot. (The problem I bumped into was a unmap-chunk request from PGM being processed during PDMR3Reset, causing a recursive VMMR3EmtRendezvous deadlock.)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 84.3 KB
Line 
1/* $Id: PDM.cpp 38838 2011-09-23 11:21:55Z 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 int rc = VINF_SUCCESS; pDevIns->pReg->pfnPowerOn(pDevIns);
1060 if (RT_FAILURE(rc))
1061 {
1062 LogRel(("PDMR3PowerOn: device '%s'/%d -> %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
1063 return rc;
1064 }
1065 }
1066 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1067 return VINF_SUCCESS;
1068}
1069
1070
1071/**
1072 * This function will notify all the devices and their
1073 * attached drivers about the VM now being powered on.
1074 *
1075 * @param pVM VM Handle.
1076 */
1077VMMR3DECL(void) PDMR3PowerOn(PVM pVM)
1078{
1079 LogFlow(("PDMR3PowerOn:\n"));
1080
1081 /*
1082 * Iterate thru the device instances and USB device instances,
1083 * processing the drivers associated with those.
1084 */
1085 int rc = VINF_SUCCESS;
1086 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns && RT_SUCCESS(rc); pDevIns = pDevIns->Internal.s.pNextR3)
1087 {
1088 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1089 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1090 rc = pdmR3PowerOnDrv(pDrvIns, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun);
1091 if (RT_SUCCESS(rc))
1092 rc = pdmR3PowerOnDev(pDevIns);
1093 }
1094
1095#ifdef VBOX_WITH_USB
1096 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns && RT_SUCCESS(rc); pUsbIns = pUsbIns->Internal.s.pNext)
1097 {
1098 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1099 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1100 rc = pdmR3PowerOnDrv(pDrvIns, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun);
1101 if (RT_SUCCESS(rc))
1102 rc = pdmR3PowerOnUsb(pUsbIns);
1103 }
1104#endif
1105
1106#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
1107 pdmR3AsyncCompletionResume(pVM);
1108#endif
1109
1110 /*
1111 * Resume all threads.
1112 */
1113 if (RT_SUCCESS(rc))
1114 pdmR3ThreadResumeAll(pVM);
1115
1116 /*
1117 * On failure, clean up via PDMR3Suspend.
1118 */
1119 if (RT_FAILURE(rc))
1120 PDMR3Suspend(pVM);
1121
1122 LogFlow(("PDMR3PowerOn: returns %Rrc\n", rc));
1123 return /*rc*/;
1124}
1125
1126
1127/**
1128 * Initializes the asynchronous notifi stats structure.
1129 *
1130 * @param pThis The asynchronous notifification stats.
1131 * @param pszOp The name of the operation.
1132 */
1133static void pdmR3NotifyAsyncInit(PPDMNOTIFYASYNCSTATS pThis, const char *pszOp)
1134{
1135 pThis->uStartNsTs = RTTimeNanoTS();
1136 pThis->cNsElapsedNextLog = 0;
1137 pThis->cLoops = 0;
1138 pThis->cAsync = 0;
1139 pThis->pszOp = pszOp;
1140 pThis->offList = 0;
1141 pThis->szList[0] = '\0';
1142}
1143
1144
1145/**
1146 * Begin a new loop, prepares to gather new stats.
1147 *
1148 * @param pThis The asynchronous notifification stats.
1149 */
1150static void pdmR3NotifyAsyncBeginLoop(PPDMNOTIFYASYNCSTATS pThis)
1151{
1152 pThis->cLoops++;
1153 pThis->cAsync = 0;
1154 pThis->offList = 0;
1155 pThis->szList[0] = '\0';
1156}
1157
1158
1159/**
1160 * Records a device or USB device with a pending asynchronous notification.
1161 *
1162 * @param pThis The asynchronous notifification stats.
1163 * @param pszName The name of the thing.
1164 * @param iInstance The instance number.
1165 */
1166static void pdmR3NotifyAsyncAdd(PPDMNOTIFYASYNCSTATS pThis, const char *pszName, uint32_t iInstance)
1167{
1168 pThis->cAsync++;
1169 if (pThis->offList < sizeof(pThis->szList) - 4)
1170 pThis->offList += RTStrPrintf(&pThis->szList[pThis->offList], sizeof(pThis->szList) - pThis->offList,
1171 pThis->offList == 0 ? "%s/%u" : ", %s/%u",
1172 pszName, iInstance);
1173}
1174
1175
1176/**
1177 * Records the asynchronous completition of a reset, suspend or power off.
1178 *
1179 * @param pThis The asynchronous notifification stats.
1180 * @param pszDrvName The driver name.
1181 * @param iDrvInstance The driver instance number.
1182 * @param pszDevName The device or USB device name.
1183 * @param iDevInstance The device or USB device instance number.
1184 * @param iLun The LUN.
1185 */
1186static void pdmR3NotifyAsyncAddDrv(PPDMNOTIFYASYNCSTATS pThis, const char *pszDrvName, uint32_t iDrvInstance,
1187 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1188{
1189 pThis->cAsync++;
1190 if (pThis->offList < sizeof(pThis->szList) - 8)
1191 pThis->offList += RTStrPrintf(&pThis->szList[pThis->offList], sizeof(pThis->szList) - pThis->offList,
1192 pThis->offList == 0 ? "%s/%u/%u/%s/%u" : ", %s/%u/%u/%s/%u",
1193 pszDevName, iDevInstance, iLun, pszDrvName, iDrvInstance);
1194}
1195
1196
1197/**
1198 * Log the stats.
1199 *
1200 * @param pThis The asynchronous notifification stats.
1201 */
1202static void pdmR3NotifyAsyncLog(PPDMNOTIFYASYNCSTATS pThis)
1203{
1204 /*
1205 * Return if we shouldn't log at this point.
1206 * We log with an internval increasing from 0 sec to 60 sec.
1207 */
1208 if (!pThis->cAsync)
1209 return;
1210
1211 uint64_t cNsElapsed = RTTimeNanoTS() - pThis->uStartNsTs;
1212 if (cNsElapsed < pThis->cNsElapsedNextLog)
1213 return;
1214
1215 if (pThis->cNsElapsedNextLog == 0)
1216 pThis->cNsElapsedNextLog = RT_NS_1SEC;
1217 else if (pThis->cNsElapsedNextLog >= RT_NS_1MIN / 2)
1218 pThis->cNsElapsedNextLog = RT_NS_1MIN;
1219 else
1220 pThis->cNsElapsedNextLog *= 2;
1221
1222 /*
1223 * Do the logging.
1224 */
1225 LogRel(("%s: after %5llu ms, %u loops: %u async tasks - %s\n",
1226 pThis->pszOp, cNsElapsed / RT_NS_1MS, pThis->cLoops, pThis->cAsync, pThis->szList));
1227}
1228
1229
1230/**
1231 * Wait for events and process pending requests.
1232 *
1233 * @param pThis The asynchronous notifification stats.
1234 * @param pVM The VM handle.
1235 */
1236static void pdmR3NotifyAsyncWaitAndProcessRequests(PPDMNOTIFYASYNCSTATS pThis, PVM pVM)
1237{
1238 VM_ASSERT_EMT0(pVM);
1239 int rc = VMR3AsyncPdmNotificationWaitU(&pVM->pUVM->aCpus[0]);
1240 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc - %s - %s\n", rc, pThis->pszOp, pThis->szList));
1241
1242 rc = VMR3ReqProcessU(pVM->pUVM, VMCPUID_ANY, true /*fPriorityOnly*/);
1243 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc - %s - %s\n", rc, pThis->pszOp, pThis->szList));
1244 rc = VMR3ReqProcessU(pVM->pUVM, 0/*idDstCpu*/, true /*fPriorityOnly*/);
1245 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc - %s - %s\n", rc, pThis->pszOp, pThis->szList));
1246}
1247
1248
1249/**
1250 * Worker for PDMR3Reset that deals with one driver.
1251 *
1252 * @param pDrvIns The driver instance.
1253 * @param pAsync The structure for recording asynchronous
1254 * notification tasks.
1255 * @param pszDevName The parent device name.
1256 * @param iDevInstance The parent device instance number.
1257 * @param iLun The parent LUN number.
1258 */
1259DECLINLINE(bool) pdmR3ResetDrv(PPDMDRVINS pDrvIns, PPDMNOTIFYASYNCSTATS pAsync,
1260 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1261{
1262 if (!pDrvIns->Internal.s.fVMReset)
1263 {
1264 pDrvIns->Internal.s.fVMReset = true;
1265 if (pDrvIns->pReg->pfnReset)
1266 {
1267 if (!pDrvIns->Internal.s.pfnAsyncNotify)
1268 {
1269 LogFlow(("PDMR3Reset: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1270 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1271 pDrvIns->pReg->pfnReset(pDrvIns);
1272 if (pDrvIns->Internal.s.pfnAsyncNotify)
1273 LogFlow(("PDMR3Reset: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1274 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1275 }
1276 else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
1277 {
1278 pDrvIns->Internal.s.pfnAsyncNotify = false;
1279 LogFlow(("PDMR3Reset: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1280 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1281 }
1282 if (pDrvIns->Internal.s.pfnAsyncNotify)
1283 {
1284 pDrvIns->Internal.s.fVMReset = false;
1285 pdmR3NotifyAsyncAddDrv(pAsync, pDrvIns->Internal.s.pDrv->pReg->szName, pDrvIns->iInstance,
1286 pszDevName, iDevInstance, iLun);
1287 return false;
1288 }
1289 }
1290 }
1291 return true;
1292}
1293
1294
1295/**
1296 * Worker for PDMR3Reset that deals with one USB device instance.
1297 *
1298 * @param pUsbIns The USB device instance.
1299 * @param pAsync The structure for recording asynchronous
1300 * notification tasks.
1301 */
1302DECLINLINE(void) pdmR3ResetUsb(PPDMUSBINS pUsbIns, PPDMNOTIFYASYNCSTATS pAsync)
1303{
1304 if (!pUsbIns->Internal.s.fVMReset)
1305 {
1306 pUsbIns->Internal.s.fVMReset = true;
1307 if (pUsbIns->pReg->pfnVMReset)
1308 {
1309 if (!pUsbIns->Internal.s.pfnAsyncNotify)
1310 {
1311 LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1312 pUsbIns->pReg->pfnVMReset(pUsbIns);
1313 if (pUsbIns->Internal.s.pfnAsyncNotify)
1314 LogFlow(("PDMR3Reset: Async notification started - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1315 }
1316 else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
1317 {
1318 LogFlow(("PDMR3Reset: Async notification completed - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1319 pUsbIns->Internal.s.pfnAsyncNotify = NULL;
1320 }
1321 if (pUsbIns->Internal.s.pfnAsyncNotify)
1322 {
1323 pUsbIns->Internal.s.fVMReset = false;
1324 pdmR3NotifyAsyncAdd(pAsync, pUsbIns->Internal.s.pUsbDev->pReg->szName, pUsbIns->iInstance);
1325 }
1326 }
1327 }
1328}
1329
1330
1331/**
1332 * Worker for PDMR3Reset that deals with one device instance.
1333 *
1334 * @param pDevIns The device instance.
1335 * @param pAsync The structure for recording asynchronous
1336 * notification tasks.
1337 */
1338DECLINLINE(void) pdmR3ResetDev(PPDMDEVINS pDevIns, PPDMNOTIFYASYNCSTATS pAsync)
1339{
1340 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_RESET))
1341 {
1342 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_RESET;
1343 if (pDevIns->pReg->pfnReset)
1344 {
1345 if (!pDevIns->Internal.s.pfnAsyncNotify)
1346 {
1347 LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1348 pDevIns->pReg->pfnReset(pDevIns);
1349 if (pDevIns->Internal.s.pfnAsyncNotify)
1350 LogFlow(("PDMR3Reset: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1351 }
1352 else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
1353 {
1354 LogFlow(("PDMR3Reset: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1355 pDevIns->Internal.s.pfnAsyncNotify = NULL;
1356 }
1357 if (pDevIns->Internal.s.pfnAsyncNotify)
1358 {
1359 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_RESET;
1360 pdmR3NotifyAsyncAdd(pAsync, pDevIns->Internal.s.pDevR3->pReg->szName, pDevIns->iInstance);
1361 }
1362 }
1363 }
1364}
1365
1366
1367/**
1368 * Resets a virtual CPU.
1369 *
1370 * Used by PDMR3Reset and CPU hot plugging.
1371 *
1372 * @param pVCpu The virtual CPU handle.
1373 */
1374VMMR3DECL(void) PDMR3ResetCpu(PVMCPU pVCpu)
1375{
1376 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
1377 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
1378 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
1379 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_SMI);
1380}
1381
1382
1383/**
1384 * This function will notify all the devices and their attached drivers about
1385 * the VM now being reset.
1386 *
1387 * @param pVM VM Handle.
1388 */
1389VMMR3DECL(void) PDMR3Reset(PVM pVM)
1390{
1391 LogFlow(("PDMR3Reset:\n"));
1392
1393 /*
1394 * Clear all the reset flags.
1395 */
1396 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1397 {
1398 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_RESET;
1399 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1400 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1401 pDrvIns->Internal.s.fVMReset = false;
1402 }
1403#ifdef VBOX_WITH_USB
1404 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1405 {
1406 pUsbIns->Internal.s.fVMReset = false;
1407 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1408 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1409 pDrvIns->Internal.s.fVMReset = false;
1410 }
1411#endif
1412
1413 /*
1414 * The outer loop repeats until there are no more async requests.
1415 */
1416 PDMNOTIFYASYNCSTATS Async;
1417 pdmR3NotifyAsyncInit(&Async, "PDMR3Reset");
1418 for (;;)
1419 {
1420 pdmR3NotifyAsyncBeginLoop(&Async);
1421
1422 /*
1423 * Iterate thru the device instances and USB device instances,
1424 * processing the drivers associated with those.
1425 */
1426 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1427 {
1428 unsigned const cAsyncStart = Async.cAsync;
1429
1430 if (Async.cAsync == cAsyncStart)
1431 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1432 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1433 if (!pdmR3ResetDrv(pDrvIns, &Async, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
1434 break;
1435
1436 if (Async.cAsync == cAsyncStart)
1437 pdmR3ResetDev(pDevIns, &Async);
1438 }
1439
1440#ifdef VBOX_WITH_USB
1441 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1442 {
1443 unsigned const cAsyncStart = Async.cAsync;
1444
1445 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1446 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1447 if (!pdmR3ResetDrv(pDrvIns, &Async, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
1448 break;
1449
1450 if (Async.cAsync == cAsyncStart)
1451 pdmR3ResetUsb(pUsbIns, &Async);
1452 }
1453#endif
1454 if (!Async.cAsync)
1455 break;
1456 pdmR3NotifyAsyncLog(&Async);
1457 pdmR3NotifyAsyncWaitAndProcessRequests(&Async, pVM);
1458 }
1459
1460 /*
1461 * Clear all pending interrupts and DMA operations.
1462 */
1463 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1464 PDMR3ResetCpu(&pVM->aCpus[idCpu]);
1465 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
1466
1467 LogFlow(("PDMR3Reset: returns void\n"));
1468}
1469
1470
1471/**
1472 * Worker for PDMR3Suspend that deals with one driver.
1473 *
1474 * @param pDrvIns The driver instance.
1475 * @param pAsync The structure for recording asynchronous
1476 * notification tasks.
1477 * @param pszDevName The parent device name.
1478 * @param iDevInstance The parent device instance number.
1479 * @param iLun The parent LUN number.
1480 */
1481DECLINLINE(bool) pdmR3SuspendDrv(PPDMDRVINS pDrvIns, PPDMNOTIFYASYNCSTATS pAsync,
1482 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1483{
1484 if (!pDrvIns->Internal.s.fVMSuspended)
1485 {
1486 pDrvIns->Internal.s.fVMSuspended = true;
1487 if (pDrvIns->pReg->pfnSuspend)
1488 {
1489 uint64_t cNsElapsed = RTTimeNanoTS();
1490
1491 if (!pDrvIns->Internal.s.pfnAsyncNotify)
1492 {
1493 LogFlow(("PDMR3Suspend: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1494 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1495 pDrvIns->pReg->pfnSuspend(pDrvIns);
1496 if (pDrvIns->Internal.s.pfnAsyncNotify)
1497 LogFlow(("PDMR3Suspend: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1498 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1499 }
1500 else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
1501 {
1502 pDrvIns->Internal.s.pfnAsyncNotify = NULL;
1503 LogFlow(("PDMR3Suspend: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1504 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1505 }
1506
1507 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1508 if (cNsElapsed >= PDMSUSPEND_WARN_AT_NS)
1509 LogRel(("PDMR3Suspend: Driver '%s'/%d on LUN#%d of device '%s'/%d took %'llu ns to suspend\n",
1510 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance, cNsElapsed));
1511
1512 if (pDrvIns->Internal.s.pfnAsyncNotify)
1513 {
1514 pDrvIns->Internal.s.fVMSuspended = false;
1515 pdmR3NotifyAsyncAddDrv(pAsync, pDrvIns->Internal.s.pDrv->pReg->szName, pDrvIns->iInstance, pszDevName, iDevInstance, iLun);
1516 return false;
1517 }
1518 }
1519 }
1520 return true;
1521}
1522
1523
1524/**
1525 * Worker for PDMR3Suspend that deals with one USB device instance.
1526 *
1527 * @param pUsbIns The USB device instance.
1528 * @param pAsync The structure for recording asynchronous
1529 * notification tasks.
1530 */
1531DECLINLINE(void) pdmR3SuspendUsb(PPDMUSBINS pUsbIns, PPDMNOTIFYASYNCSTATS pAsync)
1532{
1533 if (!pUsbIns->Internal.s.fVMSuspended)
1534 {
1535 pUsbIns->Internal.s.fVMSuspended = true;
1536 if (pUsbIns->pReg->pfnVMSuspend)
1537 {
1538 uint64_t cNsElapsed = RTTimeNanoTS();
1539
1540 if (!pUsbIns->Internal.s.pfnAsyncNotify)
1541 {
1542 LogFlow(("PDMR3Suspend: Notifying - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1543 pUsbIns->pReg->pfnVMSuspend(pUsbIns);
1544 if (pUsbIns->Internal.s.pfnAsyncNotify)
1545 LogFlow(("PDMR3Suspend: Async notification started - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1546 }
1547 else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
1548 {
1549 LogFlow(("PDMR3Suspend: Async notification completed - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1550 pUsbIns->Internal.s.pfnAsyncNotify = NULL;
1551 }
1552 if (pUsbIns->Internal.s.pfnAsyncNotify)
1553 {
1554 pUsbIns->Internal.s.fVMSuspended = false;
1555 pdmR3NotifyAsyncAdd(pAsync, pUsbIns->Internal.s.pUsbDev->pReg->szName, pUsbIns->iInstance);
1556 }
1557
1558 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1559 if (cNsElapsed >= PDMSUSPEND_WARN_AT_NS)
1560 LogRel(("PDMR3Suspend: USB device '%s'/%d took %'llu ns to suspend\n",
1561 pUsbIns->pReg->szName, pUsbIns->iInstance, cNsElapsed));
1562 }
1563 }
1564}
1565
1566
1567/**
1568 * Worker for PDMR3Suspend that deals with one device instance.
1569 *
1570 * @param pDevIns The device instance.
1571 * @param pAsync The structure for recording asynchronous
1572 * notification tasks.
1573 */
1574DECLINLINE(void) pdmR3SuspendDev(PPDMDEVINS pDevIns, PPDMNOTIFYASYNCSTATS pAsync)
1575{
1576 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED))
1577 {
1578 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_SUSPENDED;
1579 if (pDevIns->pReg->pfnSuspend)
1580 {
1581 uint64_t cNsElapsed = RTTimeNanoTS();
1582
1583 if (!pDevIns->Internal.s.pfnAsyncNotify)
1584 {
1585 LogFlow(("PDMR3Suspend: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1586 pDevIns->pReg->pfnSuspend(pDevIns);
1587 if (pDevIns->Internal.s.pfnAsyncNotify)
1588 LogFlow(("PDMR3Suspend: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1589 }
1590 else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
1591 {
1592 LogFlow(("PDMR3Suspend: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1593 pDevIns->Internal.s.pfnAsyncNotify = NULL;
1594 }
1595 if (pDevIns->Internal.s.pfnAsyncNotify)
1596 {
1597 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1598 pdmR3NotifyAsyncAdd(pAsync, pDevIns->Internal.s.pDevR3->pReg->szName, pDevIns->iInstance);
1599 }
1600
1601 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1602 if (cNsElapsed >= PDMSUSPEND_WARN_AT_NS)
1603 LogRel(("PDMR3Suspend: device '%s'/%d took %'llu ns to suspend\n",
1604 pDevIns->pReg->szName, pDevIns->iInstance, cNsElapsed));
1605 }
1606 }
1607}
1608
1609
1610/**
1611 * This function will notify all the devices and their attached drivers about
1612 * the VM now being suspended.
1613 *
1614 * @param pVM The VM Handle.
1615 * @thread EMT(0)
1616 */
1617VMMR3DECL(void) PDMR3Suspend(PVM pVM)
1618{
1619 LogFlow(("PDMR3Suspend:\n"));
1620 VM_ASSERT_EMT0(pVM);
1621 uint64_t cNsElapsed = RTTimeNanoTS();
1622
1623 /*
1624 * The outer loop repeats until there are no more async requests.
1625 *
1626 * Note! We depend on the suspended indicators to be in the desired state
1627 * and we do not reset them before starting because this allows
1628 * PDMR3PowerOn and PDMR3Resume to use PDMR3Suspend for cleaning up
1629 * on failure.
1630 */
1631 PDMNOTIFYASYNCSTATS Async;
1632 pdmR3NotifyAsyncInit(&Async, "PDMR3Suspend");
1633 for (;;)
1634 {
1635 pdmR3NotifyAsyncBeginLoop(&Async);
1636
1637 /*
1638 * Iterate thru the device instances and USB device instances,
1639 * processing the drivers associated with those.
1640 *
1641 * The attached drivers are normally processed first. Some devices
1642 * (like DevAHCI) though needs to be notified before the drivers so
1643 * that it doesn't kick off any new requests after the drivers stopped
1644 * taking any. (DrvVD changes to read-only in this particular case.)
1645 */
1646 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1647 {
1648 unsigned const cAsyncStart = Async.cAsync;
1649
1650 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION)
1651 pdmR3SuspendDev(pDevIns, &Async);
1652
1653 if (Async.cAsync == cAsyncStart)
1654 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1655 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1656 if (!pdmR3SuspendDrv(pDrvIns, &Async, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
1657 break;
1658
1659 if ( Async.cAsync == cAsyncStart
1660 && !(pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION))
1661 pdmR3SuspendDev(pDevIns, &Async);
1662 }
1663
1664#ifdef VBOX_WITH_USB
1665 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1666 {
1667 unsigned const cAsyncStart = Async.cAsync;
1668
1669 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1670 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1671 if (!pdmR3SuspendDrv(pDrvIns, &Async, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
1672 break;
1673
1674 if (Async.cAsync == cAsyncStart)
1675 pdmR3SuspendUsb(pUsbIns, &Async);
1676 }
1677#endif
1678 if (!Async.cAsync)
1679 break;
1680 pdmR3NotifyAsyncLog(&Async);
1681 pdmR3NotifyAsyncWaitAndProcessRequests(&Async, pVM);
1682 }
1683
1684 /*
1685 * Suspend all threads.
1686 */
1687 pdmR3ThreadSuspendAll(pVM);
1688
1689 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1690 LogRel(("PDMR3Suspend: %'llu ns run time\n", cNsElapsed));
1691}
1692
1693
1694/**
1695 * Worker for PDMR3Resume that deals with one driver.
1696 *
1697 * @param pDrvIns The driver instance.
1698 * @param pszDevName The parent device name.
1699 * @param iDevInstance The parent device instance number.
1700 * @param iLun The parent LUN number.
1701 */
1702DECLINLINE(int) pdmR3ResumeDrv(PPDMDRVINS pDrvIns, const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1703{
1704 Assert(pDrvIns->Internal.s.fVMSuspended);
1705 if (pDrvIns->pReg->pfnResume)
1706 {
1707 LogFlow(("PDMR3Resume: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1708 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1709 int rc = VINF_SUCCESS; pDrvIns->pReg->pfnResume(pDrvIns);
1710 if (RT_FAILURE(rc))
1711 {
1712 LogRel(("PDMR3Resume: driver '%s'/%d on LUN#%d of device '%s'/%d -> %Rrc\n",
1713 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance, rc));
1714 return rc;
1715 }
1716 }
1717 pDrvIns->Internal.s.fVMSuspended = false;
1718 return VINF_SUCCESS;
1719}
1720
1721
1722/**
1723 * Worker for PDMR3Resume that deals with one USB device instance.
1724 *
1725 * @returns VBox status code.
1726 * @param pUsbIns The USB device instance.
1727 */
1728DECLINLINE(int) pdmR3ResumeUsb(PPDMUSBINS pUsbIns)
1729{
1730 Assert(pUsbIns->Internal.s.fVMSuspended);
1731 if (pUsbIns->pReg->pfnVMResume)
1732 {
1733 LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1734 int rc = VINF_SUCCESS; pUsbIns->pReg->pfnVMResume(pUsbIns);
1735 if (RT_FAILURE(rc))
1736 {
1737 LogRel(("PDMR3Resume: device '%s'/%d -> %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1738 return rc;
1739 }
1740 }
1741 pUsbIns->Internal.s.fVMSuspended = false;
1742 return VINF_SUCCESS;
1743}
1744
1745
1746/**
1747 * Worker for PDMR3Resume that deals with one device instance.
1748 *
1749 * @returns VBox status code.
1750 * @param pDevIns The device instance.
1751 */
1752DECLINLINE(int) pdmR3ResumeDev(PPDMDEVINS pDevIns)
1753{
1754 Assert(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED);
1755 if (pDevIns->pReg->pfnResume)
1756 {
1757 LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1758 int rc = VINF_SUCCESS; pDevIns->pReg->pfnResume(pDevIns);
1759 if (RT_FAILURE(rc))
1760 {
1761 LogRel(("PDMR3Resume: device '%s'/%d -> %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
1762 return rc;
1763 }
1764 }
1765 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1766 return VINF_SUCCESS;
1767}
1768
1769
1770/**
1771 * This function will notify all the devices and their
1772 * attached drivers about the VM now being resumed.
1773 *
1774 * @param pVM VM Handle.
1775 */
1776VMMR3DECL(void) PDMR3Resume(PVM pVM)
1777{
1778 LogFlow(("PDMR3Resume:\n"));
1779
1780 /*
1781 * Iterate thru the device instances and USB device instances,
1782 * processing the drivers associated with those.
1783 */
1784 int rc = VINF_SUCCESS;
1785 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns && RT_SUCCESS(rc); pDevIns = pDevIns->Internal.s.pNextR3)
1786 {
1787 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1788 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1789 rc = pdmR3ResumeDrv(pDrvIns, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun);
1790 if (RT_SUCCESS(rc))
1791 rc = pdmR3ResumeDev(pDevIns);
1792 }
1793
1794#ifdef VBOX_WITH_USB
1795 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns && RT_SUCCESS(rc); pUsbIns = pUsbIns->Internal.s.pNext)
1796 {
1797 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1798 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1799 rc = pdmR3ResumeDrv(pDrvIns, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun);
1800 if (RT_SUCCESS(rc))
1801 rc = pdmR3ResumeUsb(pUsbIns);
1802 }
1803#endif
1804
1805 /*
1806 * Resume all threads.
1807 */
1808 if (RT_SUCCESS(rc))
1809 pdmR3ThreadResumeAll(pVM);
1810
1811 /*
1812 * Resume the block cache.
1813 */
1814 if (RT_SUCCESS(rc))
1815 pdmR3BlkCacheResume(pVM);
1816
1817 /*
1818 * On failure, clean up via PDMR3Suspend.
1819 */
1820 if (RT_FAILURE(rc))
1821 PDMR3Suspend(pVM);
1822
1823 LogFlow(("PDMR3Resume: returns %Rrc\n", rc));
1824 return /*rc*/;
1825}
1826
1827
1828/**
1829 * Worker for PDMR3PowerOff that deals with one driver.
1830 *
1831 * @param pDrvIns The driver instance.
1832 * @param pAsync The structure for recording asynchronous
1833 * notification tasks.
1834 * @param pszDevName The parent device name.
1835 * @param iDevInstance The parent device instance number.
1836 * @param iLun The parent LUN number.
1837 */
1838DECLINLINE(bool) pdmR3PowerOffDrv(PPDMDRVINS pDrvIns, PPDMNOTIFYASYNCSTATS pAsync,
1839 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1840{
1841 if (!pDrvIns->Internal.s.fVMSuspended)
1842 {
1843 pDrvIns->Internal.s.fVMSuspended = true;
1844 if (pDrvIns->pReg->pfnPowerOff)
1845 {
1846 uint64_t cNsElapsed = RTTimeNanoTS();
1847
1848 if (!pDrvIns->Internal.s.pfnAsyncNotify)
1849 {
1850 LogFlow(("PDMR3PowerOff: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1851 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1852 pDrvIns->pReg->pfnPowerOff(pDrvIns);
1853 if (pDrvIns->Internal.s.pfnAsyncNotify)
1854 LogFlow(("PDMR3PowerOff: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1855 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1856 }
1857 else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
1858 {
1859 pDrvIns->Internal.s.pfnAsyncNotify = false;
1860 LogFlow(("PDMR3PowerOff: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1861 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1862 }
1863
1864 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1865 if (cNsElapsed >= PDMPOWEROFF_WARN_AT_NS)
1866 LogRel(("PDMR3PowerOff: Driver '%s'/%d on LUN#%d of device '%s'/%d took %'llu ns to power off\n",
1867 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance, cNsElapsed));
1868
1869 if (pDrvIns->Internal.s.pfnAsyncNotify)
1870 {
1871 pDrvIns->Internal.s.fVMSuspended = false;
1872 pdmR3NotifyAsyncAddDrv(pAsync, pDrvIns->Internal.s.pDrv->pReg->szName, pDrvIns->iInstance,
1873 pszDevName, iDevInstance, iLun);
1874 return false;
1875 }
1876 }
1877 }
1878 return true;
1879}
1880
1881
1882/**
1883 * Worker for PDMR3PowerOff that deals with one USB device instance.
1884 *
1885 * @param pUsbIns The USB device instance.
1886 * @param pAsync The structure for recording asynchronous
1887 * notification tasks.
1888 */
1889DECLINLINE(void) pdmR3PowerOffUsb(PPDMUSBINS pUsbIns, PPDMNOTIFYASYNCSTATS pAsync)
1890{
1891 if (!pUsbIns->Internal.s.fVMSuspended)
1892 {
1893 pUsbIns->Internal.s.fVMSuspended = true;
1894 if (pUsbIns->pReg->pfnVMPowerOff)
1895 {
1896 uint64_t cNsElapsed = RTTimeNanoTS();
1897
1898 if (!pUsbIns->Internal.s.pfnAsyncNotify)
1899 {
1900 LogFlow(("PDMR3PowerOff: Notifying - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1901 pUsbIns->pReg->pfnVMPowerOff(pUsbIns);
1902 if (pUsbIns->Internal.s.pfnAsyncNotify)
1903 LogFlow(("PDMR3PowerOff: Async notification started - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1904 }
1905 else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
1906 {
1907 LogFlow(("PDMR3PowerOff: Async notification completed - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1908 pUsbIns->Internal.s.pfnAsyncNotify = NULL;
1909 }
1910 if (pUsbIns->Internal.s.pfnAsyncNotify)
1911 {
1912 pUsbIns->Internal.s.fVMSuspended = false;
1913 pdmR3NotifyAsyncAdd(pAsync, pUsbIns->Internal.s.pUsbDev->pReg->szName, pUsbIns->iInstance);
1914 }
1915
1916 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1917 if (cNsElapsed >= PDMPOWEROFF_WARN_AT_NS)
1918 LogRel(("PDMR3PowerOff: USB device '%s'/%d took %'llu ns to power off\n",
1919 pUsbIns->pReg->szName, pUsbIns->iInstance, cNsElapsed));
1920
1921 }
1922 }
1923}
1924
1925
1926/**
1927 * Worker for PDMR3PowerOff that deals with one device instance.
1928 *
1929 * @param pDevIns The device instance.
1930 * @param pAsync The structure for recording asynchronous
1931 * notification tasks.
1932 */
1933DECLINLINE(void) pdmR3PowerOffDev(PPDMDEVINS pDevIns, PPDMNOTIFYASYNCSTATS pAsync)
1934{
1935 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED))
1936 {
1937 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_SUSPENDED;
1938 if (pDevIns->pReg->pfnPowerOff)
1939 {
1940 uint64_t cNsElapsed = RTTimeNanoTS();
1941
1942 if (!pDevIns->Internal.s.pfnAsyncNotify)
1943 {
1944 LogFlow(("PDMR3PowerOff: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1945 pDevIns->pReg->pfnPowerOff(pDevIns);
1946 if (pDevIns->Internal.s.pfnAsyncNotify)
1947 LogFlow(("PDMR3PowerOff: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1948 }
1949 else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
1950 {
1951 LogFlow(("PDMR3PowerOff: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1952 pDevIns->Internal.s.pfnAsyncNotify = NULL;
1953 }
1954 if (pDevIns->Internal.s.pfnAsyncNotify)
1955 {
1956 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1957 pdmR3NotifyAsyncAdd(pAsync, pDevIns->Internal.s.pDevR3->pReg->szName, pDevIns->iInstance);
1958 }
1959
1960 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1961 if (cNsElapsed >= PDMPOWEROFF_WARN_AT_NS)
1962 LogFlow(("PDMR3PowerOff: Device '%s'/%d took %'llu ns to power off\n",
1963 pDevIns->pReg->szName, pDevIns->iInstance, cNsElapsed));
1964 }
1965 }
1966}
1967
1968
1969/**
1970 * This function will notify all the devices and their
1971 * attached drivers about the VM being powered off.
1972 *
1973 * @param pVM VM Handle.
1974 */
1975VMMR3DECL(void) PDMR3PowerOff(PVM pVM)
1976{
1977 LogFlow(("PDMR3PowerOff:\n"));
1978 uint64_t cNsElapsed = RTTimeNanoTS();
1979
1980 /*
1981 * The outer loop repeats until there are no more async requests.
1982 */
1983 PDMNOTIFYASYNCSTATS Async;
1984 pdmR3NotifyAsyncInit(&Async, "PDMR3PowerOff");
1985 for (;;)
1986 {
1987 pdmR3NotifyAsyncBeginLoop(&Async);
1988
1989 /*
1990 * Iterate thru the device instances and USB device instances,
1991 * processing the drivers associated with those.
1992 *
1993 * The attached drivers are normally processed first. Some devices
1994 * (like DevAHCI) though needs to be notified before the drivers so
1995 * that it doesn't kick off any new requests after the drivers stopped
1996 * taking any. (DrvVD changes to read-only in this particular case.)
1997 */
1998 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1999 {
2000 unsigned const cAsyncStart = Async.cAsync;
2001
2002 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION)
2003 pdmR3PowerOffDev(pDevIns, &Async);
2004
2005 if (Async.cAsync == cAsyncStart)
2006 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
2007 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2008 if (!pdmR3PowerOffDrv(pDrvIns, &Async, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
2009 break;
2010
2011 if ( Async.cAsync == cAsyncStart
2012 && !(pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION))
2013 pdmR3PowerOffDev(pDevIns, &Async);
2014 }
2015
2016#ifdef VBOX_WITH_USB
2017 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2018 {
2019 unsigned const cAsyncStart = Async.cAsync;
2020
2021 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
2022 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2023 if (!pdmR3PowerOffDrv(pDrvIns, &Async, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
2024 break;
2025
2026 if (Async.cAsync == cAsyncStart)
2027 pdmR3PowerOffUsb(pUsbIns, &Async);
2028 }
2029#endif
2030 if (!Async.cAsync)
2031 break;
2032 pdmR3NotifyAsyncLog(&Async);
2033 pdmR3NotifyAsyncWaitAndProcessRequests(&Async, pVM);
2034 }
2035
2036 /*
2037 * Suspend all threads.
2038 */
2039 pdmR3ThreadSuspendAll(pVM);
2040
2041 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
2042 LogRel(("PDMR3PowerOff: %'llu ns run time\n", cNsElapsed));
2043}
2044
2045
2046/**
2047 * Queries the base interface of a device instance.
2048 *
2049 * The caller can use this to query other interfaces the device implements
2050 * and use them to talk to the device.
2051 *
2052 * @returns VBox status code.
2053 * @param pVM VM handle.
2054 * @param pszDevice Device name.
2055 * @param iInstance Device instance.
2056 * @param ppBase Where to store the pointer to the base device interface on success.
2057 * @remark We're not doing any locking ATM, so don't try call this at times when the
2058 * device chain is known to be updated.
2059 */
2060VMMR3DECL(int) PDMR3QueryDevice(PVM pVM, const char *pszDevice, unsigned iInstance, PPDMIBASE *ppBase)
2061{
2062 LogFlow(("PDMR3DeviceQuery: pszDevice=%p:{%s} iInstance=%u ppBase=%p\n", pszDevice, pszDevice, iInstance, ppBase));
2063
2064 /*
2065 * Iterate registered devices looking for the device.
2066 */
2067 size_t cchDevice = strlen(pszDevice);
2068 for (PPDMDEV pDev = pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
2069 {
2070 if ( pDev->cchName == cchDevice
2071 && !memcmp(pDev->pReg->szName, pszDevice, cchDevice))
2072 {
2073 /*
2074 * Iterate device instances.
2075 */
2076 for (PPDMDEVINS pDevIns = pDev->pInstances; pDevIns; pDevIns = pDevIns->Internal.s.pPerDeviceNextR3)
2077 {
2078 if (pDevIns->iInstance == iInstance)
2079 {
2080 if (pDevIns->IBase.pfnQueryInterface)
2081 {
2082 *ppBase = &pDevIns->IBase;
2083 LogFlow(("PDMR3DeviceQuery: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
2084 return VINF_SUCCESS;
2085 }
2086
2087 LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NO_IBASE\n"));
2088 return VERR_PDM_DEVICE_INSTANCE_NO_IBASE;
2089 }
2090 }
2091
2092 LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NOT_FOUND\n"));
2093 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND;
2094 }
2095 }
2096
2097 LogFlow(("PDMR3QueryDevice: returns VERR_PDM_DEVICE_NOT_FOUND\n"));
2098 return VERR_PDM_DEVICE_NOT_FOUND;
2099}
2100
2101
2102/**
2103 * Queries the base interface of a device LUN.
2104 *
2105 * This differs from PDMR3QueryLun by that it returns the interface on the
2106 * device and not the top level driver.
2107 *
2108 * @returns VBox status code.
2109 * @param pVM VM Handle.
2110 * @param pszDevice Device name.
2111 * @param iInstance Device instance.
2112 * @param iLun The Logical Unit to obtain the interface of.
2113 * @param ppBase Where to store the base interface pointer.
2114 * @remark We're not doing any locking ATM, so don't try call this at times when the
2115 * device chain is known to be updated.
2116 */
2117VMMR3DECL(int) PDMR3QueryDeviceLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
2118{
2119 LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
2120 pszDevice, pszDevice, iInstance, iLun, ppBase));
2121
2122 /*
2123 * Find the LUN.
2124 */
2125 PPDMLUN pLun;
2126 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
2127 if (RT_SUCCESS(rc))
2128 {
2129 *ppBase = pLun->pBase;
2130 LogFlow(("PDMR3QueryDeviceLun: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
2131 return VINF_SUCCESS;
2132 }
2133 LogFlow(("PDMR3QueryDeviceLun: returns %Rrc\n", rc));
2134 return rc;
2135}
2136
2137
2138/**
2139 * Query the interface of the top level driver on a LUN.
2140 *
2141 * @returns VBox status code.
2142 * @param pVM VM Handle.
2143 * @param pszDevice Device name.
2144 * @param iInstance Device instance.
2145 * @param iLun The Logical Unit to obtain the interface of.
2146 * @param ppBase Where to store the base interface pointer.
2147 * @remark We're not doing any locking ATM, so don't try call this at times when the
2148 * device chain is known to be updated.
2149 */
2150VMMR3DECL(int) PDMR3QueryLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
2151{
2152 LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
2153 pszDevice, pszDevice, iInstance, iLun, ppBase));
2154 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
2155
2156 /*
2157 * Find the LUN.
2158 */
2159 PPDMLUN pLun;
2160 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
2161 if (RT_SUCCESS(rc))
2162 {
2163 if (pLun->pTop)
2164 {
2165 *ppBase = &pLun->pTop->IBase;
2166 LogFlow(("PDMR3QueryLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
2167 return VINF_SUCCESS;
2168 }
2169 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
2170 }
2171 LogFlow(("PDMR3QueryLun: returns %Rrc\n", rc));
2172 return rc;
2173}
2174
2175
2176/**
2177 * Query the interface of a named driver on a LUN.
2178 *
2179 * If the driver appears more than once in the driver chain, the first instance
2180 * is returned.
2181 *
2182 * @returns VBox status code.
2183 * @param pVM VM Handle.
2184 * @param pszDevice Device name.
2185 * @param iInstance Device instance.
2186 * @param iLun The Logical Unit to obtain the interface of.
2187 * @param pszDriver The driver name.
2188 * @param ppBase Where to store the base interface pointer.
2189 *
2190 * @remark We're not doing any locking ATM, so don't try call this at times when the
2191 * device chain is known to be updated.
2192 */
2193VMMR3DECL(int) PDMR3QueryDriverOnLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, const char *pszDriver, PPPDMIBASE ppBase)
2194{
2195 LogFlow(("PDMR3QueryDriverOnLun: pszDevice=%p:{%s} iInstance=%u iLun=%u pszDriver=%p:{%s} ppBase=%p\n",
2196 pszDevice, pszDevice, iInstance, iLun, pszDriver, pszDriver, ppBase));
2197
2198 /*
2199 * Find the LUN.
2200 */
2201 PPDMLUN pLun;
2202 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
2203 if (RT_SUCCESS(rc))
2204 {
2205 if (pLun->pTop)
2206 {
2207 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2208 if (!strcmp(pDrvIns->pReg->szName, pszDriver))
2209 {
2210 *ppBase = &pDrvIns->IBase;
2211 LogFlow(("PDMR3QueryDriverOnLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
2212 return VINF_SUCCESS;
2213
2214 }
2215 rc = VERR_PDM_DRIVER_NOT_FOUND;
2216 }
2217 else
2218 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
2219 }
2220 LogFlow(("PDMR3QueryDriverOnLun: returns %Rrc\n", rc));
2221 return rc;
2222}
2223
2224/**
2225 * Executes pending DMA transfers.
2226 * Forced Action handler.
2227 *
2228 * @param pVM VM handle.
2229 */
2230VMMR3DECL(void) PDMR3DmaRun(PVM pVM)
2231{
2232 /* Note! Not really SMP safe; restrict it to VCPU 0. */
2233 if (VMMGetCpuId(pVM) != 0)
2234 return;
2235
2236 if (VM_FF_TESTANDCLEAR(pVM, VM_FF_PDM_DMA))
2237 {
2238 if (pVM->pdm.s.pDmac)
2239 {
2240 bool fMore = pVM->pdm.s.pDmac->Reg.pfnRun(pVM->pdm.s.pDmac->pDevIns);
2241 if (fMore)
2242 VM_FF_SET(pVM, VM_FF_PDM_DMA);
2243 }
2244 }
2245}
2246
2247
2248/**
2249 * Service a VMMCALLRING3_PDM_LOCK call.
2250 *
2251 * @returns VBox status code.
2252 * @param pVM The VM handle.
2253 */
2254VMMR3DECL(int) PDMR3LockCall(PVM pVM)
2255{
2256 return PDMR3CritSectEnterEx(&pVM->pdm.s.CritSect, true /* fHostCall */);
2257}
2258
2259
2260/**
2261 * Registers the VMM device heap
2262 *
2263 * @returns VBox status code.
2264 * @param pVM VM handle.
2265 * @param GCPhys The physical address.
2266 * @param pvHeap Ring-3 pointer.
2267 * @param cbSize Size of the heap.
2268 */
2269VMMR3DECL(int) PDMR3RegisterVMMDevHeap(PVM pVM, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbSize)
2270{
2271 Assert(pVM->pdm.s.pvVMMDevHeap == NULL);
2272
2273 Log(("PDMR3RegisterVMMDevHeap %RGp %RHv %x\n", GCPhys, pvHeap, cbSize));
2274 pVM->pdm.s.pvVMMDevHeap = pvHeap;
2275 pVM->pdm.s.GCPhysVMMDevHeap = GCPhys;
2276 pVM->pdm.s.cbVMMDevHeap = cbSize;
2277 pVM->pdm.s.cbVMMDevHeapLeft = cbSize;
2278 return VINF_SUCCESS;
2279}
2280
2281
2282/**
2283 * Unregisters the VMM device heap
2284 *
2285 * @returns VBox status code.
2286 * @param pVM VM handle.
2287 * @param GCPhys The physical address.
2288 */
2289VMMR3DECL(int) PDMR3UnregisterVMMDevHeap(PVM pVM, RTGCPHYS GCPhys)
2290{
2291 Assert(pVM->pdm.s.GCPhysVMMDevHeap == GCPhys);
2292
2293 Log(("PDMR3UnregisterVMMDevHeap %RGp\n", GCPhys));
2294 pVM->pdm.s.pvVMMDevHeap = NULL;
2295 pVM->pdm.s.GCPhysVMMDevHeap = NIL_RTGCPHYS;
2296 pVM->pdm.s.cbVMMDevHeap = 0;
2297 pVM->pdm.s.cbVMMDevHeapLeft = 0;
2298 return VINF_SUCCESS;
2299}
2300
2301
2302/**
2303 * Allocates memory from the VMM device heap
2304 *
2305 * @returns VBox status code.
2306 * @param pVM VM handle.
2307 * @param cbSize Allocation size.
2308 * @param pv Ring-3 pointer. (out)
2309 */
2310VMMR3DECL(int) PDMR3VMMDevHeapAlloc(PVM pVM, unsigned cbSize, RTR3PTR *ppv)
2311{
2312#ifdef DEBUG_bird
2313 if (!cbSize || cbSize > pVM->pdm.s.cbVMMDevHeapLeft)
2314 return VERR_NO_MEMORY;
2315#else
2316 AssertReturn(cbSize && cbSize <= pVM->pdm.s.cbVMMDevHeapLeft, VERR_NO_MEMORY);
2317#endif
2318
2319 Log(("PDMR3VMMDevHeapAlloc %x\n", cbSize));
2320
2321 /** @todo not a real heap as there's currently only one user. */
2322 *ppv = pVM->pdm.s.pvVMMDevHeap;
2323 pVM->pdm.s.cbVMMDevHeapLeft = 0;
2324 return VINF_SUCCESS;
2325}
2326
2327
2328/**
2329 * Frees memory from the VMM device heap
2330 *
2331 * @returns VBox status code.
2332 * @param pVM VM handle.
2333 * @param pv Ring-3 pointer.
2334 */
2335VMMR3DECL(int) PDMR3VMMDevHeapFree(PVM pVM, RTR3PTR pv)
2336{
2337 Log(("PDMR3VMMDevHeapFree %RHv\n", pv));
2338
2339 /** @todo not a real heap as there's currently only one user. */
2340 pVM->pdm.s.cbVMMDevHeapLeft = pVM->pdm.s.cbVMMDevHeap;
2341 return VINF_SUCCESS;
2342}
2343
Note: See TracBrowser for help on using the repository browser.

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