VirtualBox

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

Last change on this file since 45733 was 45152, checked in by vboxsync, 12 years ago

PDMCritSectRw: Early morphing stage - untested, ring-3 only.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 101.7 KB
Line 
1/* $Id: PDM.cpp 45152 2013-03-23 20:36:23Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device Manager.
4 */
5
6/*
7 * Copyright (C) 2006-2013 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/ctype.h>
270#include <iprt/ldr.h>
271#include <iprt/path.h>
272#include <iprt/string.h>
273
274
275/*******************************************************************************
276* Defined Constants And Macros *
277*******************************************************************************/
278/** The PDM saved state version. */
279#define PDM_SAVED_STATE_VERSION 4
280#define PDM_SAVED_STATE_VERSION_PRE_NMI_FF 3
281
282/** The number of nanoseconds a suspend callback needs to take before
283 * PDMR3Suspend warns about it taking too long. */
284#define PDMSUSPEND_WARN_AT_NS UINT64_C(1200000000)
285
286/** The number of nanoseconds a suspend callback needs to take before
287 * PDMR3PowerOff warns about it taking too long. */
288#define PDMPOWEROFF_WARN_AT_NS UINT64_C( 900000000)
289
290
291/*******************************************************************************
292* Structures and Typedefs *
293*******************************************************************************/
294/**
295 * Statistics of asynchronous notification tasks - used by reset, suspend and
296 * power off.
297 */
298typedef struct PDMNOTIFYASYNCSTATS
299{
300 /** The start timestamp. */
301 uint64_t uStartNsTs;
302 /** When to log the next time. */
303 uint64_t cNsElapsedNextLog;
304 /** The loop counter. */
305 uint32_t cLoops;
306 /** The number of pending asynchronous notification tasks. */
307 uint32_t cAsync;
308 /** The name of the operation (log prefix). */
309 const char *pszOp;
310 /** The current list buffer position. */
311 size_t offList;
312 /** String containing a list of the pending tasks. */
313 char szList[1024];
314} PDMNOTIFYASYNCSTATS;
315/** Pointer to the stats of pending asynchronous notification tasks. */
316typedef PDMNOTIFYASYNCSTATS *PPDMNOTIFYASYNCSTATS;
317
318
319/*******************************************************************************
320* Internal Functions *
321*******************************************************************************/
322static DECLCALLBACK(int) pdmR3LiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass);
323static DECLCALLBACK(int) pdmR3SaveExec(PVM pVM, PSSMHANDLE pSSM);
324static DECLCALLBACK(int) pdmR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
325static DECLCALLBACK(int) pdmR3LoadPrep(PVM pVM, PSSMHANDLE pSSM);
326
327static FNDBGFHANDLERINT pdmR3InfoTracingIds;
328
329
330/**
331 * Initializes the PDM part of the UVM.
332 *
333 * This doesn't really do much right now but has to be here for the sake
334 * of completeness.
335 *
336 * @returns VBox status code.
337 * @param pUVM Pointer to the user mode VM structure.
338 */
339VMMR3_INT_DECL(int) PDMR3InitUVM(PUVM pUVM)
340{
341 AssertCompile(sizeof(pUVM->pdm.s) <= sizeof(pUVM->pdm.padding));
342 AssertRelease(sizeof(pUVM->pdm.s) <= sizeof(pUVM->pdm.padding));
343 pUVM->pdm.s.pModules = NULL;
344 pUVM->pdm.s.pCritSects = NULL;
345 pUVM->pdm.s.pRwCritSects = NULL;
346 return RTCritSectInit(&pUVM->pdm.s.ListCritSect);
347}
348
349
350/**
351 * Initializes the PDM.
352 *
353 * @returns VBox status code.
354 * @param pVM Pointer to the VM.
355 */
356VMMR3_INT_DECL(int) PDMR3Init(PVM pVM)
357{
358 LogFlow(("PDMR3Init\n"));
359
360 /*
361 * Assert alignment and sizes.
362 */
363 AssertRelease(!(RT_OFFSETOF(VM, pdm.s) & 31));
364 AssertRelease(sizeof(pVM->pdm.s) <= sizeof(pVM->pdm.padding));
365 AssertCompileMemberAlignment(PDM, CritSect, sizeof(uintptr_t));
366
367 /*
368 * Init the structure.
369 */
370 pVM->pdm.s.GCPhysVMMDevHeap = NIL_RTGCPHYS;
371 //pVM->pdm.s.idTracingDev = 0;
372 pVM->pdm.s.idTracingOther = 1024;
373
374 /*
375 * Initialize critical sections first.
376 */
377 int rc = pdmR3CritSectBothInitStats(pVM);
378 if (RT_SUCCESS(rc))
379 rc = PDMR3CritSectInit(pVM, &pVM->pdm.s.CritSect, RT_SRC_POS, "PDM");
380 if (RT_SUCCESS(rc))
381 {
382 rc = PDMR3CritSectInit(pVM, &pVM->pdm.s.NopCritSect, RT_SRC_POS, "NOP");
383 if (RT_SUCCESS(rc))
384 pVM->pdm.s.NopCritSect.s.Core.fFlags |= RTCRITSECT_FLAGS_NOP;
385 }
386
387 /*
388 * Initialize sub components.
389 */
390 if (RT_SUCCESS(rc))
391 rc = pdmR3LdrInitU(pVM->pUVM);
392#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
393 if (RT_SUCCESS(rc))
394 rc = pdmR3AsyncCompletionInit(pVM);
395#endif
396#ifdef VBOX_WITH_NETSHAPER
397 if (RT_SUCCESS(rc))
398 rc = pdmR3NetShaperInit(pVM);
399#endif
400 if (RT_SUCCESS(rc))
401 rc = pdmR3BlkCacheInit(pVM);
402 if (RT_SUCCESS(rc))
403 rc = pdmR3DrvInit(pVM);
404 if (RT_SUCCESS(rc))
405 rc = pdmR3DevInit(pVM);
406 if (RT_SUCCESS(rc))
407 {
408 /*
409 * Register the saved state data unit.
410 */
411 rc = SSMR3RegisterInternal(pVM, "pdm", 1, PDM_SAVED_STATE_VERSION, 128,
412 NULL, pdmR3LiveExec, NULL,
413 NULL, pdmR3SaveExec, NULL,
414 pdmR3LoadPrep, pdmR3LoadExec, NULL);
415 if (RT_SUCCESS(rc))
416 {
417 /*
418 * Register the info handlers.
419 */
420 DBGFR3InfoRegisterInternal(pVM, "pdmtracingids",
421 "Displays the tracing IDs assigned by PDM to devices, USB device, drivers and more.",
422 pdmR3InfoTracingIds);
423
424 LogFlow(("PDM: Successfully initialized\n"));
425 return rc;
426 }
427 }
428
429 /*
430 * Cleanup and return failure.
431 */
432 PDMR3Term(pVM);
433 LogFlow(("PDMR3Init: returns %Rrc\n", rc));
434 return rc;
435}
436
437
438/**
439 * Applies relocations to data and code managed by this
440 * component. This function will be called at init and
441 * whenever the VMM need to relocate it self inside the GC.
442 *
443 * @param pVM Pointer to the VM.
444 * @param offDelta Relocation delta relative to old location.
445 * @remark The loader subcomponent is relocated by PDMR3LdrRelocate() very
446 * early in the relocation phase.
447 */
448VMMR3_INT_DECL(void) PDMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
449{
450 LogFlow(("PDMR3Relocate\n"));
451
452 /*
453 * Queues.
454 */
455 pdmR3QueueRelocate(pVM, offDelta);
456 pVM->pdm.s.pDevHlpQueueRC = PDMQueueRCPtr(pVM->pdm.s.pDevHlpQueueR3);
457
458 /*
459 * Critical sections.
460 */
461 pdmR3CritSectBothRelocate(pVM);
462
463 /*
464 * The registered PIC.
465 */
466 if (pVM->pdm.s.Pic.pDevInsRC)
467 {
468 pVM->pdm.s.Pic.pDevInsRC += offDelta;
469 pVM->pdm.s.Pic.pfnSetIrqRC += offDelta;
470 pVM->pdm.s.Pic.pfnGetInterruptRC += offDelta;
471 }
472
473 /*
474 * The registered APIC.
475 */
476 if (pVM->pdm.s.Apic.pDevInsRC)
477 {
478 pVM->pdm.s.Apic.pDevInsRC += offDelta;
479 pVM->pdm.s.Apic.pfnGetInterruptRC += offDelta;
480 pVM->pdm.s.Apic.pfnSetBaseRC += offDelta;
481 pVM->pdm.s.Apic.pfnGetBaseRC += offDelta;
482 pVM->pdm.s.Apic.pfnSetTPRRC += offDelta;
483 pVM->pdm.s.Apic.pfnGetTPRRC += offDelta;
484 pVM->pdm.s.Apic.pfnBusDeliverRC += offDelta;
485 if (pVM->pdm.s.Apic.pfnLocalInterruptRC)
486 pVM->pdm.s.Apic.pfnLocalInterruptRC += offDelta;
487 pVM->pdm.s.Apic.pfnWriteMSRRC += offDelta;
488 pVM->pdm.s.Apic.pfnReadMSRRC += offDelta;
489 }
490
491 /*
492 * The registered I/O APIC.
493 */
494 if (pVM->pdm.s.IoApic.pDevInsRC)
495 {
496 pVM->pdm.s.IoApic.pDevInsRC += offDelta;
497 pVM->pdm.s.IoApic.pfnSetIrqRC += offDelta;
498 if (pVM->pdm.s.IoApic.pfnSendMsiRC)
499 pVM->pdm.s.IoApic.pfnSendMsiRC += offDelta;
500 }
501
502 /*
503 * The register PCI Buses.
504 */
505 for (unsigned i = 0; i < RT_ELEMENTS(pVM->pdm.s.aPciBuses); i++)
506 {
507 if (pVM->pdm.s.aPciBuses[i].pDevInsRC)
508 {
509 pVM->pdm.s.aPciBuses[i].pDevInsRC += offDelta;
510 pVM->pdm.s.aPciBuses[i].pfnSetIrqRC += offDelta;
511 }
512 }
513
514 /*
515 * Devices & Drivers.
516 */
517 PCPDMDEVHLPRC pDevHlpRC;
518 int rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDevHlp", &pDevHlpRC);
519 AssertReleaseMsgRC(rc, ("rc=%Rrc when resolving g_pdmRCDevHlp\n", rc));
520
521 PCPDMDRVHLPRC pDrvHlpRC;
522 rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDevHlp", &pDrvHlpRC);
523 AssertReleaseMsgRC(rc, ("rc=%Rrc when resolving g_pdmRCDevHlp\n", rc));
524
525 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
526 {
527 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_RC)
528 {
529 pDevIns->pHlpRC = pDevHlpRC;
530 pDevIns->pvInstanceDataRC = MMHyperR3ToRC(pVM, pDevIns->pvInstanceDataR3);
531 if (pDevIns->pCritSectRoR3)
532 pDevIns->pCritSectRoRC = MMHyperR3ToRC(pVM, pDevIns->pCritSectRoR3);
533 pDevIns->Internal.s.pVMRC = pVM->pVMRC;
534 if (pDevIns->Internal.s.pPciBusR3)
535 pDevIns->Internal.s.pPciBusRC = MMHyperR3ToRC(pVM, pDevIns->Internal.s.pPciBusR3);
536 if (pDevIns->Internal.s.pPciDeviceR3)
537 pDevIns->Internal.s.pPciDeviceRC = MMHyperR3ToRC(pVM, pDevIns->Internal.s.pPciDeviceR3);
538 if (pDevIns->pReg->pfnRelocate)
539 {
540 LogFlow(("PDMR3Relocate: Relocating device '%s'/%d\n",
541 pDevIns->pReg->szName, pDevIns->iInstance));
542 pDevIns->pReg->pfnRelocate(pDevIns, offDelta);
543 }
544 }
545
546 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
547 {
548 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
549 {
550 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_RC)
551 {
552 pDrvIns->pHlpRC = pDrvHlpRC;
553 pDrvIns->pvInstanceDataRC = MMHyperR3ToRC(pVM, pDrvIns->pvInstanceDataR3);
554 pDrvIns->Internal.s.pVMRC = pVM->pVMRC;
555 if (pDrvIns->pReg->pfnRelocate)
556 {
557 LogFlow(("PDMR3Relocate: Relocating driver '%s'/%u attached to '%s'/%d/%u\n",
558 pDrvIns->pReg->szName, pDrvIns->iInstance,
559 pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun));
560 pDrvIns->pReg->pfnRelocate(pDrvIns, offDelta);
561 }
562 }
563 }
564 }
565
566 }
567}
568
569
570/**
571 * Worker for pdmR3Term that terminates a LUN chain.
572 *
573 * @param pVM Pointer to the VM.
574 * @param pLun The head of the chain.
575 * @param pszDevice The name of the device (for logging).
576 * @param iInstance The device instance number (for logging).
577 */
578static void pdmR3TermLuns(PVM pVM, PPDMLUN pLun, const char *pszDevice, unsigned iInstance)
579{
580 for (; pLun; pLun = pLun->pNext)
581 {
582 /*
583 * Destroy them one at a time from the bottom up.
584 * (The serial device/drivers depends on this - bad.)
585 */
586 PPDMDRVINS pDrvIns = pLun->pBottom;
587 pLun->pBottom = pLun->pTop = NULL;
588 while (pDrvIns)
589 {
590 PPDMDRVINS pDrvNext = pDrvIns->Internal.s.pUp;
591
592 if (pDrvIns->pReg->pfnDestruct)
593 {
594 LogFlow(("pdmR3DevTerm: Destroying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
595 pDrvIns->pReg->szName, pDrvIns->iInstance, pLun->iLun, pszDevice, iInstance));
596 pDrvIns->pReg->pfnDestruct(pDrvIns);
597 }
598 pDrvIns->Internal.s.pDrv->cInstances--;
599
600 TMR3TimerDestroyDriver(pVM, pDrvIns);
601 //PDMR3QueueDestroyDriver(pVM, pDrvIns);
602 //pdmR3ThreadDestroyDriver(pVM, pDrvIns);
603 SSMR3DeregisterDriver(pVM, pDrvIns, NULL, 0);
604
605 pDrvIns = pDrvNext;
606 }
607 }
608}
609
610
611/**
612 * Terminates the PDM.
613 *
614 * Termination means cleaning up and freeing all resources,
615 * the VM it self is at this point powered off or suspended.
616 *
617 * @returns VBox status code.
618 * @param pVM Pointer to the VM.
619 */
620VMMR3_INT_DECL(int) PDMR3Term(PVM pVM)
621{
622 LogFlow(("PDMR3Term:\n"));
623 AssertMsg(PDMCritSectIsInitialized(&pVM->pdm.s.CritSect), ("bad init order!\n"));
624
625 /*
626 * Iterate the device instances and attach drivers, doing
627 * relevant destruction processing.
628 *
629 * N.B. There is no need to mess around freeing memory allocated
630 * from any MM heap since MM will do that in its Term function.
631 */
632 /* usb ones first. */
633 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
634 {
635 pdmR3TermLuns(pVM, pUsbIns->Internal.s.pLuns, pUsbIns->pReg->szName, pUsbIns->iInstance);
636
637 if (pUsbIns->pReg->pfnDestruct)
638 {
639 LogFlow(("pdmR3DevTerm: Destroying - device '%s'/%d\n",
640 pUsbIns->pReg->szName, pUsbIns->iInstance));
641 pUsbIns->pReg->pfnDestruct(pUsbIns);
642 }
643
644 //TMR3TimerDestroyUsb(pVM, pUsbIns);
645 //SSMR3DeregisterUsb(pVM, pUsbIns, NULL, 0);
646 pdmR3ThreadDestroyUsb(pVM, pUsbIns);
647 }
648
649 /* then the 'normal' ones. */
650 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
651 {
652 pdmR3TermLuns(pVM, pDevIns->Internal.s.pLunsR3, pDevIns->pReg->szName, pDevIns->iInstance);
653
654 if (pDevIns->pReg->pfnDestruct)
655 {
656 LogFlow(("pdmR3DevTerm: Destroying - device '%s'/%d\n",
657 pDevIns->pReg->szName, pDevIns->iInstance));
658 pDevIns->pReg->pfnDestruct(pDevIns);
659 }
660
661 TMR3TimerDestroyDevice(pVM, pDevIns);
662 SSMR3DeregisterDevice(pVM, pDevIns, NULL, 0);
663 pdmR3CritSectBothDeleteDevice(pVM, pDevIns);
664 pdmR3ThreadDestroyDevice(pVM, pDevIns);
665 PDMR3QueueDestroyDevice(pVM, pDevIns);
666 PGMR3PhysMMIO2Deregister(pVM, pDevIns, UINT32_MAX);
667#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
668 pdmR3AsyncCompletionTemplateDestroyDevice(pVM, pDevIns);
669#endif
670 DBGFR3InfoDeregisterDevice(pVM, pDevIns, NULL);
671 }
672
673 /*
674 * Destroy all threads.
675 */
676 pdmR3ThreadDestroyAll(pVM);
677
678 /*
679 * Destroy the block cache.
680 */
681 pdmR3BlkCacheTerm(pVM);
682
683#ifdef VBOX_WITH_NETSHAPER
684 /*
685 * Destroy network bandwidth groups.
686 */
687 pdmR3NetShaperTerm(pVM);
688#endif
689#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
690 /*
691 * Free async completion managers.
692 */
693 pdmR3AsyncCompletionTerm(pVM);
694#endif
695
696 /*
697 * Free modules.
698 */
699 pdmR3LdrTermU(pVM->pUVM);
700
701 /*
702 * Destroy the PDM lock.
703 */
704 PDMR3CritSectDelete(&pVM->pdm.s.CritSect);
705 /* The MiscCritSect is deleted by PDMR3CritSectBothTerm later. */
706
707 LogFlow(("PDMR3Term: returns %Rrc\n", VINF_SUCCESS));
708 return VINF_SUCCESS;
709}
710
711
712/**
713 * Terminates the PDM part of the UVM.
714 *
715 * This will unload any modules left behind.
716 *
717 * @param pUVM Pointer to the user mode VM structure.
718 */
719VMMR3_INT_DECL(void) PDMR3TermUVM(PUVM pUVM)
720{
721 /*
722 * In the normal cause of events we will now call pdmR3LdrTermU for
723 * the second time. In the case of init failure however, this might
724 * the first time, which is why we do it.
725 */
726 pdmR3LdrTermU(pUVM);
727
728 Assert(pUVM->pdm.s.pCritSects == NULL);
729 Assert(pUVM->pdm.s.pRwCritSects == NULL);
730 RTCritSectDelete(&pUVM->pdm.s.ListCritSect);
731}
732
733
734/**
735 * Bits that are saved in pass 0 and in the final pass.
736 *
737 * @param pVM Pointer to the VM.
738 * @param pSSM The saved state handle.
739 */
740static void pdmR3SaveBoth(PVM pVM, PSSMHANDLE pSSM)
741{
742 /*
743 * Save the list of device instances so we can check that they're all still
744 * there when we load the state and that nothing new has been added.
745 */
746 uint32_t i = 0;
747 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3, i++)
748 {
749 SSMR3PutU32(pSSM, i);
750 SSMR3PutStrZ(pSSM, pDevIns->pReg->szName);
751 SSMR3PutU32(pSSM, pDevIns->iInstance);
752 }
753 SSMR3PutU32(pSSM, UINT32_MAX); /* terminator */
754}
755
756
757/**
758 * Live save.
759 *
760 * @returns VBox status code.
761 * @param pVM Pointer to the VM.
762 * @param pSSM The saved state handle.
763 * @param uPass The pass.
764 */
765static DECLCALLBACK(int) pdmR3LiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass)
766{
767 LogFlow(("pdmR3LiveExec:\n"));
768 AssertReturn(uPass == 0, VERR_SSM_UNEXPECTED_PASS);
769 pdmR3SaveBoth(pVM, pSSM);
770 return VINF_SSM_DONT_CALL_AGAIN;
771}
772
773
774/**
775 * Execute state save operation.
776 *
777 * @returns VBox status code.
778 * @param pVM Pointer to the VM.
779 * @param pSSM The saved state handle.
780 */
781static DECLCALLBACK(int) pdmR3SaveExec(PVM pVM, PSSMHANDLE pSSM)
782{
783 LogFlow(("pdmR3SaveExec:\n"));
784
785 /*
786 * Save interrupt and DMA states.
787 */
788 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
789 {
790 PVMCPU pVCpu = &pVM->aCpus[idCpu];
791 SSMR3PutU32(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC));
792 SSMR3PutU32(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC));
793 SSMR3PutU32(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_NMI));
794 SSMR3PutU32(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_SMI));
795 }
796 SSMR3PutU32(pSSM, VM_FF_ISSET(pVM, VM_FF_PDM_DMA));
797
798 pdmR3SaveBoth(pVM, pSSM);
799 return VINF_SUCCESS;
800}
801
802
803/**
804 * Prepare state load operation.
805 *
806 * This will dispatch pending operations and clear the FFs governed by PDM and its devices.
807 *
808 * @returns VBox status code.
809 * @param pVM Pointer to the VM.
810 * @param pSSM The SSM handle.
811 */
812static DECLCALLBACK(int) pdmR3LoadPrep(PVM pVM, PSSMHANDLE pSSM)
813{
814 LogFlow(("pdmR3LoadPrep: %s%s\n",
815 VM_FF_ISSET(pVM, VM_FF_PDM_QUEUES) ? " VM_FF_PDM_QUEUES" : "",
816 VM_FF_ISSET(pVM, VM_FF_PDM_DMA) ? " VM_FF_PDM_DMA" : ""));
817#ifdef LOG_ENABLED
818 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
819 {
820 PVMCPU pVCpu = &pVM->aCpus[idCpu];
821 LogFlow(("pdmR3LoadPrep: VCPU %u %s%s\n", idCpu,
822 VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC) ? " VMCPU_FF_INTERRUPT_APIC" : "",
823 VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC) ? " VMCPU_FF_INTERRUPT_PIC" : ""));
824 }
825#endif
826 NOREF(pSSM);
827
828 /*
829 * In case there is work pending that will raise an interrupt,
830 * start a DMA transfer, or release a lock. (unlikely)
831 */
832 if (VM_FF_ISSET(pVM, VM_FF_PDM_QUEUES))
833 PDMR3QueueFlushAll(pVM);
834
835 /* Clear the FFs. */
836 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
837 {
838 PVMCPU pVCpu = &pVM->aCpus[idCpu];
839 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
840 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
841 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
842 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_SMI);
843 }
844 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
845
846 return VINF_SUCCESS;
847}
848
849
850/**
851 * Execute state load operation.
852 *
853 * @returns VBox status code.
854 * @param pVM Pointer to the VM.
855 * @param pSSM SSM operation handle.
856 * @param uVersion Data layout version.
857 * @param uPass The data pass.
858 */
859static DECLCALLBACK(int) pdmR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
860{
861 int rc;
862
863 LogFlow(("pdmR3LoadExec: uPass=%#x\n", uPass));
864
865 /*
866 * Validate version.
867 */
868 if ( uVersion != PDM_SAVED_STATE_VERSION
869 && uVersion != PDM_SAVED_STATE_VERSION_PRE_NMI_FF)
870 {
871 AssertMsgFailed(("Invalid version uVersion=%d!\n", uVersion));
872 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
873 }
874
875 if (uPass == SSM_PASS_FINAL)
876 {
877 /*
878 * Load the interrupt and DMA states.
879 */
880 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
881 {
882 PVMCPU pVCpu = &pVM->aCpus[idCpu];
883
884 /* APIC interrupt */
885 uint32_t fInterruptPending = 0;
886 rc = SSMR3GetU32(pSSM, &fInterruptPending);
887 if (RT_FAILURE(rc))
888 return rc;
889 if (fInterruptPending & ~1)
890 {
891 AssertMsgFailed(("fInterruptPending=%#x (APIC)\n", fInterruptPending));
892 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
893 }
894 AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC));
895 if (fInterruptPending)
896 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC);
897
898 /* PIC interrupt */
899 fInterruptPending = 0;
900 rc = SSMR3GetU32(pSSM, &fInterruptPending);
901 if (RT_FAILURE(rc))
902 return rc;
903 if (fInterruptPending & ~1)
904 {
905 AssertMsgFailed(("fInterruptPending=%#x (PIC)\n", fInterruptPending));
906 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
907 }
908 AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC));
909 if (fInterruptPending)
910 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC);
911
912 if (uVersion > PDM_SAVED_STATE_VERSION_PRE_NMI_FF)
913 {
914 /* NMI interrupt */
915 fInterruptPending = 0;
916 rc = SSMR3GetU32(pSSM, &fInterruptPending);
917 if (RT_FAILURE(rc))
918 return rc;
919 if (fInterruptPending & ~1)
920 {
921 AssertMsgFailed(("fInterruptPending=%#x (NMI)\n", fInterruptPending));
922 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
923 }
924 AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_NMI));
925 if (fInterruptPending)
926 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI);
927
928 /* SMI interrupt */
929 fInterruptPending = 0;
930 rc = SSMR3GetU32(pSSM, &fInterruptPending);
931 if (RT_FAILURE(rc))
932 return rc;
933 if (fInterruptPending & ~1)
934 {
935 AssertMsgFailed(("fInterruptPending=%#x (SMI)\n", fInterruptPending));
936 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
937 }
938 AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_SMI));
939 if (fInterruptPending)
940 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_SMI);
941 }
942 }
943
944 /* DMA pending */
945 uint32_t fDMAPending = 0;
946 rc = SSMR3GetU32(pSSM, &fDMAPending);
947 if (RT_FAILURE(rc))
948 return rc;
949 if (fDMAPending & ~1)
950 {
951 AssertMsgFailed(("fDMAPending=%#x\n", fDMAPending));
952 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
953 }
954 if (fDMAPending)
955 VM_FF_SET(pVM, VM_FF_PDM_DMA);
956 Log(("pdmR3LoadExec: VM_FF_PDM_DMA=%RTbool\n", VM_FF_ISSET(pVM, VM_FF_PDM_DMA)));
957 }
958
959 /*
960 * Load the list of devices and verify that they are all there.
961 */
962 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
963 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_FOUND;
964
965 for (uint32_t i = 0; ; i++)
966 {
967 /* Get the sequence number / terminator. */
968 uint32_t u32Sep;
969 rc = SSMR3GetU32(pSSM, &u32Sep);
970 if (RT_FAILURE(rc))
971 return rc;
972 if (u32Sep == UINT32_MAX)
973 break;
974 if (u32Sep != i)
975 AssertMsgFailedReturn(("Out of sequence. u32Sep=%#x i=%#x\n", u32Sep, i), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
976
977 /* Get the name and instance number. */
978 char szName[RT_SIZEOFMEMB(PDMDEVREG, szName)];
979 rc = SSMR3GetStrZ(pSSM, szName, sizeof(szName));
980 if (RT_FAILURE(rc))
981 return rc;
982 uint32_t iInstance;
983 rc = SSMR3GetU32(pSSM, &iInstance);
984 if (RT_FAILURE(rc))
985 return rc;
986
987 /* Try locate it. */
988 PPDMDEVINS pDevIns;
989 for (pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
990 if ( !strcmp(szName, pDevIns->pReg->szName)
991 && pDevIns->iInstance == iInstance)
992 {
993 AssertLogRelMsgReturn(!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_FOUND),
994 ("%s/#%u\n", pDevIns->pReg->szName, pDevIns->iInstance),
995 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
996 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_FOUND;
997 break;
998 }
999 if (!pDevIns)
1000 {
1001 LogRel(("Device '%s'/%d not found in current config\n", szName, iInstance));
1002 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
1003 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device '%s'/%d not found in current config"), szName, iInstance);
1004 }
1005 }
1006
1007 /*
1008 * Check that no additional devices were configured.
1009 */
1010 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1011 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_FOUND))
1012 {
1013 LogRel(("Device '%s'/%d not found in the saved state\n", pDevIns->pReg->szName, pDevIns->iInstance));
1014 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
1015 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device '%s'/%d not found in the saved state"),
1016 pDevIns->pReg->szName, pDevIns->iInstance);
1017 }
1018
1019 return VINF_SUCCESS;
1020}
1021
1022
1023/**
1024 * Worker for PDMR3PowerOn that deals with one driver.
1025 *
1026 * @param pDrvIns The driver instance.
1027 * @param pszDevName The parent device name.
1028 * @param iDevInstance The parent device instance number.
1029 * @param iLun The parent LUN number.
1030 */
1031DECLINLINE(int) pdmR3PowerOnDrv(PPDMDRVINS pDrvIns, const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1032{
1033 Assert(pDrvIns->Internal.s.fVMSuspended);
1034 if (pDrvIns->pReg->pfnPowerOn)
1035 {
1036 LogFlow(("PDMR3PowerOn: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1037 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1038 int rc = VINF_SUCCESS; pDrvIns->pReg->pfnPowerOn(pDrvIns);
1039 if (RT_FAILURE(rc))
1040 {
1041 LogRel(("PDMR3PowerOn: driver '%s'/%d on LUN#%d of device '%s'/%d -> %Rrc\n",
1042 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance, rc));
1043 return rc;
1044 }
1045 }
1046 pDrvIns->Internal.s.fVMSuspended = false;
1047 return VINF_SUCCESS;
1048}
1049
1050
1051/**
1052 * Worker for PDMR3PowerOn that deals with one USB device instance.
1053 *
1054 * @returns VBox status code.
1055 * @param pUsbIns The USB device instance.
1056 */
1057DECLINLINE(int) pdmR3PowerOnUsb(PPDMUSBINS pUsbIns)
1058{
1059 Assert(pUsbIns->Internal.s.fVMSuspended);
1060 if (pUsbIns->pReg->pfnVMPowerOn)
1061 {
1062 LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1063 int rc = VINF_SUCCESS; pUsbIns->pReg->pfnVMPowerOn(pUsbIns);
1064 if (RT_FAILURE(rc))
1065 {
1066 LogRel(("PDMR3PowerOn: device '%s'/%d -> %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1067 return rc;
1068 }
1069 }
1070 pUsbIns->Internal.s.fVMSuspended = false;
1071 return VINF_SUCCESS;
1072}
1073
1074
1075/**
1076 * Worker for PDMR3PowerOn that deals with one device instance.
1077 *
1078 * @returns VBox status code.
1079 * @param pDevIns The device instance.
1080 */
1081DECLINLINE(int) pdmR3PowerOnDev(PPDMDEVINS pDevIns)
1082{
1083 Assert(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED);
1084 if (pDevIns->pReg->pfnPowerOn)
1085 {
1086 LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1087 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
1088 int rc = VINF_SUCCESS; pDevIns->pReg->pfnPowerOn(pDevIns);
1089 PDMCritSectLeave(pDevIns->pCritSectRoR3);
1090 if (RT_FAILURE(rc))
1091 {
1092 LogRel(("PDMR3PowerOn: device '%s'/%d -> %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
1093 return rc;
1094 }
1095 }
1096 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1097 return VINF_SUCCESS;
1098}
1099
1100
1101/**
1102 * This function will notify all the devices and their
1103 * attached drivers about the VM now being powered on.
1104 *
1105 * @param pVM Pointer to the VM.
1106 */
1107VMMR3DECL(void) PDMR3PowerOn(PVM pVM)
1108{
1109 LogFlow(("PDMR3PowerOn:\n"));
1110
1111 /*
1112 * Iterate thru the device instances and USB device instances,
1113 * processing the drivers associated with those.
1114 */
1115 int rc = VINF_SUCCESS;
1116 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns && RT_SUCCESS(rc); pDevIns = pDevIns->Internal.s.pNextR3)
1117 {
1118 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1119 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1120 rc = pdmR3PowerOnDrv(pDrvIns, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun);
1121 if (RT_SUCCESS(rc))
1122 rc = pdmR3PowerOnDev(pDevIns);
1123 }
1124
1125#ifdef VBOX_WITH_USB
1126 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns && RT_SUCCESS(rc); pUsbIns = pUsbIns->Internal.s.pNext)
1127 {
1128 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1129 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1130 rc = pdmR3PowerOnDrv(pDrvIns, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun);
1131 if (RT_SUCCESS(rc))
1132 rc = pdmR3PowerOnUsb(pUsbIns);
1133 }
1134#endif
1135
1136#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
1137 pdmR3AsyncCompletionResume(pVM);
1138#endif
1139
1140 /*
1141 * Resume all threads.
1142 */
1143 if (RT_SUCCESS(rc))
1144 pdmR3ThreadResumeAll(pVM);
1145
1146 /*
1147 * On failure, clean up via PDMR3Suspend.
1148 */
1149 if (RT_FAILURE(rc))
1150 PDMR3Suspend(pVM);
1151
1152 LogFlow(("PDMR3PowerOn: returns %Rrc\n", rc));
1153 return /*rc*/;
1154}
1155
1156
1157/**
1158 * Initializes the asynchronous notifi stats structure.
1159 *
1160 * @param pThis The asynchronous notifification stats.
1161 * @param pszOp The name of the operation.
1162 */
1163static void pdmR3NotifyAsyncInit(PPDMNOTIFYASYNCSTATS pThis, const char *pszOp)
1164{
1165 pThis->uStartNsTs = RTTimeNanoTS();
1166 pThis->cNsElapsedNextLog = 0;
1167 pThis->cLoops = 0;
1168 pThis->cAsync = 0;
1169 pThis->pszOp = pszOp;
1170 pThis->offList = 0;
1171 pThis->szList[0] = '\0';
1172}
1173
1174
1175/**
1176 * Begin a new loop, prepares to gather new stats.
1177 *
1178 * @param pThis The asynchronous notifification stats.
1179 */
1180static void pdmR3NotifyAsyncBeginLoop(PPDMNOTIFYASYNCSTATS pThis)
1181{
1182 pThis->cLoops++;
1183 pThis->cAsync = 0;
1184 pThis->offList = 0;
1185 pThis->szList[0] = '\0';
1186}
1187
1188
1189/**
1190 * Records a device or USB device with a pending asynchronous notification.
1191 *
1192 * @param pThis The asynchronous notifification stats.
1193 * @param pszName The name of the thing.
1194 * @param iInstance The instance number.
1195 */
1196static void pdmR3NotifyAsyncAdd(PPDMNOTIFYASYNCSTATS pThis, const char *pszName, uint32_t iInstance)
1197{
1198 pThis->cAsync++;
1199 if (pThis->offList < sizeof(pThis->szList) - 4)
1200 pThis->offList += RTStrPrintf(&pThis->szList[pThis->offList], sizeof(pThis->szList) - pThis->offList,
1201 pThis->offList == 0 ? "%s/%u" : ", %s/%u",
1202 pszName, iInstance);
1203}
1204
1205
1206/**
1207 * Records the asynchronous completition of a reset, suspend or power off.
1208 *
1209 * @param pThis The asynchronous notifification stats.
1210 * @param pszDrvName The driver name.
1211 * @param iDrvInstance The driver instance number.
1212 * @param pszDevName The device or USB device name.
1213 * @param iDevInstance The device or USB device instance number.
1214 * @param iLun The LUN.
1215 */
1216static void pdmR3NotifyAsyncAddDrv(PPDMNOTIFYASYNCSTATS pThis, const char *pszDrvName, uint32_t iDrvInstance,
1217 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1218{
1219 pThis->cAsync++;
1220 if (pThis->offList < sizeof(pThis->szList) - 8)
1221 pThis->offList += RTStrPrintf(&pThis->szList[pThis->offList], sizeof(pThis->szList) - pThis->offList,
1222 pThis->offList == 0 ? "%s/%u/%u/%s/%u" : ", %s/%u/%u/%s/%u",
1223 pszDevName, iDevInstance, iLun, pszDrvName, iDrvInstance);
1224}
1225
1226
1227/**
1228 * Log the stats.
1229 *
1230 * @param pThis The asynchronous notifification stats.
1231 */
1232static void pdmR3NotifyAsyncLog(PPDMNOTIFYASYNCSTATS pThis)
1233{
1234 /*
1235 * Return if we shouldn't log at this point.
1236 * We log with an internval increasing from 0 sec to 60 sec.
1237 */
1238 if (!pThis->cAsync)
1239 return;
1240
1241 uint64_t cNsElapsed = RTTimeNanoTS() - pThis->uStartNsTs;
1242 if (cNsElapsed < pThis->cNsElapsedNextLog)
1243 return;
1244
1245 if (pThis->cNsElapsedNextLog == 0)
1246 pThis->cNsElapsedNextLog = RT_NS_1SEC;
1247 else if (pThis->cNsElapsedNextLog >= RT_NS_1MIN / 2)
1248 pThis->cNsElapsedNextLog = RT_NS_1MIN;
1249 else
1250 pThis->cNsElapsedNextLog *= 2;
1251
1252 /*
1253 * Do the logging.
1254 */
1255 LogRel(("%s: after %5llu ms, %u loops: %u async tasks - %s\n",
1256 pThis->pszOp, cNsElapsed / RT_NS_1MS, pThis->cLoops, pThis->cAsync, pThis->szList));
1257}
1258
1259
1260/**
1261 * Wait for events and process pending requests.
1262 *
1263 * @param pThis The asynchronous notifification stats.
1264 * @param pVM Pointer to the VM.
1265 */
1266static void pdmR3NotifyAsyncWaitAndProcessRequests(PPDMNOTIFYASYNCSTATS pThis, PVM pVM)
1267{
1268 VM_ASSERT_EMT0(pVM);
1269 int rc = VMR3AsyncPdmNotificationWaitU(&pVM->pUVM->aCpus[0]);
1270 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc - %s - %s\n", rc, pThis->pszOp, pThis->szList));
1271
1272 rc = VMR3ReqProcessU(pVM->pUVM, VMCPUID_ANY, true /*fPriorityOnly*/);
1273 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc - %s - %s\n", rc, pThis->pszOp, pThis->szList));
1274 rc = VMR3ReqProcessU(pVM->pUVM, 0/*idDstCpu*/, true /*fPriorityOnly*/);
1275 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc - %s - %s\n", rc, pThis->pszOp, pThis->szList));
1276}
1277
1278
1279/**
1280 * Worker for PDMR3Reset that deals with one driver.
1281 *
1282 * @param pDrvIns The driver instance.
1283 * @param pAsync The structure for recording asynchronous
1284 * notification tasks.
1285 * @param pszDevName The parent device name.
1286 * @param iDevInstance The parent device instance number.
1287 * @param iLun The parent LUN number.
1288 */
1289DECLINLINE(bool) pdmR3ResetDrv(PPDMDRVINS pDrvIns, PPDMNOTIFYASYNCSTATS pAsync,
1290 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1291{
1292 if (!pDrvIns->Internal.s.fVMReset)
1293 {
1294 pDrvIns->Internal.s.fVMReset = true;
1295 if (pDrvIns->pReg->pfnReset)
1296 {
1297 if (!pDrvIns->Internal.s.pfnAsyncNotify)
1298 {
1299 LogFlow(("PDMR3Reset: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1300 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1301 pDrvIns->pReg->pfnReset(pDrvIns);
1302 if (pDrvIns->Internal.s.pfnAsyncNotify)
1303 LogFlow(("PDMR3Reset: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1304 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1305 }
1306 else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
1307 {
1308 LogFlow(("PDMR3Reset: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1309 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1310 pDrvIns->Internal.s.pfnAsyncNotify = NULL;
1311 }
1312 if (pDrvIns->Internal.s.pfnAsyncNotify)
1313 {
1314 pDrvIns->Internal.s.fVMReset = false;
1315 pdmR3NotifyAsyncAddDrv(pAsync, pDrvIns->Internal.s.pDrv->pReg->szName, pDrvIns->iInstance,
1316 pszDevName, iDevInstance, iLun);
1317 return false;
1318 }
1319 }
1320 }
1321 return true;
1322}
1323
1324
1325/**
1326 * Worker for PDMR3Reset that deals with one USB device instance.
1327 *
1328 * @param pUsbIns The USB device instance.
1329 * @param pAsync The structure for recording asynchronous
1330 * notification tasks.
1331 */
1332DECLINLINE(void) pdmR3ResetUsb(PPDMUSBINS pUsbIns, PPDMNOTIFYASYNCSTATS pAsync)
1333{
1334 if (!pUsbIns->Internal.s.fVMReset)
1335 {
1336 pUsbIns->Internal.s.fVMReset = true;
1337 if (pUsbIns->pReg->pfnVMReset)
1338 {
1339 if (!pUsbIns->Internal.s.pfnAsyncNotify)
1340 {
1341 LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1342 pUsbIns->pReg->pfnVMReset(pUsbIns);
1343 if (pUsbIns->Internal.s.pfnAsyncNotify)
1344 LogFlow(("PDMR3Reset: Async notification started - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1345 }
1346 else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
1347 {
1348 LogFlow(("PDMR3Reset: Async notification completed - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1349 pUsbIns->Internal.s.pfnAsyncNotify = NULL;
1350 }
1351 if (pUsbIns->Internal.s.pfnAsyncNotify)
1352 {
1353 pUsbIns->Internal.s.fVMReset = false;
1354 pdmR3NotifyAsyncAdd(pAsync, pUsbIns->Internal.s.pUsbDev->pReg->szName, pUsbIns->iInstance);
1355 }
1356 }
1357 }
1358}
1359
1360
1361/**
1362 * Worker for PDMR3Reset that deals with one device instance.
1363 *
1364 * @param pDevIns The device instance.
1365 * @param pAsync The structure for recording asynchronous
1366 * notification tasks.
1367 */
1368DECLINLINE(void) pdmR3ResetDev(PPDMDEVINS pDevIns, PPDMNOTIFYASYNCSTATS pAsync)
1369{
1370 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_RESET))
1371 {
1372 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_RESET;
1373 if (pDevIns->pReg->pfnReset)
1374 {
1375 uint64_t cNsElapsed = RTTimeNanoTS();
1376 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
1377
1378 if (!pDevIns->Internal.s.pfnAsyncNotify)
1379 {
1380 LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1381 pDevIns->pReg->pfnReset(pDevIns);
1382 if (pDevIns->Internal.s.pfnAsyncNotify)
1383 LogFlow(("PDMR3Reset: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1384 }
1385 else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
1386 {
1387 LogFlow(("PDMR3Reset: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1388 pDevIns->Internal.s.pfnAsyncNotify = NULL;
1389 }
1390 if (pDevIns->Internal.s.pfnAsyncNotify)
1391 {
1392 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_RESET;
1393 pdmR3NotifyAsyncAdd(pAsync, pDevIns->Internal.s.pDevR3->pReg->szName, pDevIns->iInstance);
1394 }
1395
1396 PDMCritSectLeave(pDevIns->pCritSectRoR3);
1397 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1398 if (cNsElapsed >= PDMSUSPEND_WARN_AT_NS)
1399 LogRel(("PDMR3Reset: device '%s'/%d took %'llu ns to reset\n",
1400 pDevIns->pReg->szName, pDevIns->iInstance, cNsElapsed));
1401 }
1402 }
1403}
1404
1405
1406/**
1407 * Resets a virtual CPU.
1408 *
1409 * Used by PDMR3Reset and CPU hot plugging.
1410 *
1411 * @param pVCpu Pointer to the VMCPU.
1412 */
1413VMMR3_INT_DECL(void) PDMR3ResetCpu(PVMCPU pVCpu)
1414{
1415 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
1416 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
1417 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
1418 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_SMI);
1419}
1420
1421
1422/**
1423 * This function will notify all the devices and their attached drivers about
1424 * the VM now being reset.
1425 *
1426 * @param pVM Pointer to the VM.
1427 */
1428VMMR3_INT_DECL(void) PDMR3Reset(PVM pVM)
1429{
1430 LogFlow(("PDMR3Reset:\n"));
1431
1432 /*
1433 * Clear all the reset flags.
1434 */
1435 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1436 {
1437 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_RESET;
1438 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1439 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1440 pDrvIns->Internal.s.fVMReset = false;
1441 }
1442#ifdef VBOX_WITH_USB
1443 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1444 {
1445 pUsbIns->Internal.s.fVMReset = false;
1446 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1447 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1448 pDrvIns->Internal.s.fVMReset = false;
1449 }
1450#endif
1451
1452 /*
1453 * The outer loop repeats until there are no more async requests.
1454 */
1455 PDMNOTIFYASYNCSTATS Async;
1456 pdmR3NotifyAsyncInit(&Async, "PDMR3Reset");
1457 for (;;)
1458 {
1459 pdmR3NotifyAsyncBeginLoop(&Async);
1460
1461 /*
1462 * Iterate thru the device instances and USB device instances,
1463 * processing the drivers associated with those.
1464 */
1465 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1466 {
1467 unsigned const cAsyncStart = Async.cAsync;
1468
1469 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_RESET_NOTIFICATION)
1470 pdmR3ResetDev(pDevIns, &Async);
1471
1472 if (Async.cAsync == cAsyncStart)
1473 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1474 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1475 if (!pdmR3ResetDrv(pDrvIns, &Async, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
1476 break;
1477
1478 if ( Async.cAsync == cAsyncStart
1479 && !(pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_RESET_NOTIFICATION))
1480 pdmR3ResetDev(pDevIns, &Async);
1481 }
1482
1483#ifdef VBOX_WITH_USB
1484 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1485 {
1486 unsigned const cAsyncStart = Async.cAsync;
1487
1488 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1489 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1490 if (!pdmR3ResetDrv(pDrvIns, &Async, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
1491 break;
1492
1493 if (Async.cAsync == cAsyncStart)
1494 pdmR3ResetUsb(pUsbIns, &Async);
1495 }
1496#endif
1497 if (!Async.cAsync)
1498 break;
1499 pdmR3NotifyAsyncLog(&Async);
1500 pdmR3NotifyAsyncWaitAndProcessRequests(&Async, pVM);
1501 }
1502
1503 /*
1504 * Clear all pending interrupts and DMA operations.
1505 */
1506 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1507 PDMR3ResetCpu(&pVM->aCpus[idCpu]);
1508 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
1509
1510 LogFlow(("PDMR3Reset: returns void\n"));
1511}
1512
1513
1514/**
1515 * This function will tell all the devices to setup up their memory structures
1516 * after VM construction and after VM reset.
1517 *
1518 * @param pVM Pointer to the VM.
1519 * @param fAtReset Indicates the context, after reset if @c true or after
1520 * construction if @c false.
1521 */
1522VMMR3_INT_DECL(void) PDMR3MemSetup(PVM pVM, bool fAtReset)
1523{
1524 LogFlow(("PDMR3MemSetup: fAtReset=%RTbool\n", fAtReset));
1525 PDMDEVMEMSETUPCTX const enmCtx = fAtReset ? PDMDEVMEMSETUPCTX_AFTER_RESET : PDMDEVMEMSETUPCTX_AFTER_CONSTRUCTION;
1526
1527 /*
1528 * Iterate thru the device instances and work the callback.
1529 */
1530 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1531 if (pDevIns->pReg->pfnMemSetup)
1532 {
1533 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
1534 pDevIns->pReg->pfnMemSetup(pDevIns, enmCtx);
1535 PDMCritSectLeave(pDevIns->pCritSectRoR3);
1536 }
1537
1538 LogFlow(("PDMR3MemSetup: returns void\n"));
1539}
1540
1541
1542/**
1543 * Worker for PDMR3Suspend that deals with one driver.
1544 *
1545 * @param pDrvIns The driver instance.
1546 * @param pAsync The structure for recording asynchronous
1547 * notification tasks.
1548 * @param pszDevName The parent device name.
1549 * @param iDevInstance The parent device instance number.
1550 * @param iLun The parent LUN number.
1551 */
1552DECLINLINE(bool) pdmR3SuspendDrv(PPDMDRVINS pDrvIns, PPDMNOTIFYASYNCSTATS pAsync,
1553 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1554{
1555 if (!pDrvIns->Internal.s.fVMSuspended)
1556 {
1557 pDrvIns->Internal.s.fVMSuspended = true;
1558 if (pDrvIns->pReg->pfnSuspend)
1559 {
1560 uint64_t cNsElapsed = RTTimeNanoTS();
1561
1562 if (!pDrvIns->Internal.s.pfnAsyncNotify)
1563 {
1564 LogFlow(("PDMR3Suspend: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1565 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1566 pDrvIns->pReg->pfnSuspend(pDrvIns);
1567 if (pDrvIns->Internal.s.pfnAsyncNotify)
1568 LogFlow(("PDMR3Suspend: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1569 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1570 }
1571 else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
1572 {
1573 LogFlow(("PDMR3Suspend: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1574 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1575 pDrvIns->Internal.s.pfnAsyncNotify = NULL;
1576 }
1577
1578 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1579 if (cNsElapsed >= PDMSUSPEND_WARN_AT_NS)
1580 LogRel(("PDMR3Suspend: Driver '%s'/%d on LUN#%d of device '%s'/%d took %'llu ns to suspend\n",
1581 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance, cNsElapsed));
1582
1583 if (pDrvIns->Internal.s.pfnAsyncNotify)
1584 {
1585 pDrvIns->Internal.s.fVMSuspended = false;
1586 pdmR3NotifyAsyncAddDrv(pAsync, pDrvIns->Internal.s.pDrv->pReg->szName, pDrvIns->iInstance, pszDevName, iDevInstance, iLun);
1587 return false;
1588 }
1589 }
1590 }
1591 return true;
1592}
1593
1594
1595/**
1596 * Worker for PDMR3Suspend that deals with one USB device instance.
1597 *
1598 * @param pUsbIns The USB device instance.
1599 * @param pAsync The structure for recording asynchronous
1600 * notification tasks.
1601 */
1602DECLINLINE(void) pdmR3SuspendUsb(PPDMUSBINS pUsbIns, PPDMNOTIFYASYNCSTATS pAsync)
1603{
1604 if (!pUsbIns->Internal.s.fVMSuspended)
1605 {
1606 pUsbIns->Internal.s.fVMSuspended = true;
1607 if (pUsbIns->pReg->pfnVMSuspend)
1608 {
1609 uint64_t cNsElapsed = RTTimeNanoTS();
1610
1611 if (!pUsbIns->Internal.s.pfnAsyncNotify)
1612 {
1613 LogFlow(("PDMR3Suspend: Notifying - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1614 pUsbIns->pReg->pfnVMSuspend(pUsbIns);
1615 if (pUsbIns->Internal.s.pfnAsyncNotify)
1616 LogFlow(("PDMR3Suspend: Async notification started - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1617 }
1618 else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
1619 {
1620 LogFlow(("PDMR3Suspend: Async notification completed - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1621 pUsbIns->Internal.s.pfnAsyncNotify = NULL;
1622 }
1623 if (pUsbIns->Internal.s.pfnAsyncNotify)
1624 {
1625 pUsbIns->Internal.s.fVMSuspended = false;
1626 pdmR3NotifyAsyncAdd(pAsync, pUsbIns->Internal.s.pUsbDev->pReg->szName, pUsbIns->iInstance);
1627 }
1628
1629 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1630 if (cNsElapsed >= PDMSUSPEND_WARN_AT_NS)
1631 LogRel(("PDMR3Suspend: USB device '%s'/%d took %'llu ns to suspend\n",
1632 pUsbIns->pReg->szName, pUsbIns->iInstance, cNsElapsed));
1633 }
1634 }
1635}
1636
1637
1638/**
1639 * Worker for PDMR3Suspend that deals with one device instance.
1640 *
1641 * @param pDevIns The device instance.
1642 * @param pAsync The structure for recording asynchronous
1643 * notification tasks.
1644 */
1645DECLINLINE(void) pdmR3SuspendDev(PPDMDEVINS pDevIns, PPDMNOTIFYASYNCSTATS pAsync)
1646{
1647 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED))
1648 {
1649 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_SUSPENDED;
1650 if (pDevIns->pReg->pfnSuspend)
1651 {
1652 uint64_t cNsElapsed = RTTimeNanoTS();
1653 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
1654
1655 if (!pDevIns->Internal.s.pfnAsyncNotify)
1656 {
1657 LogFlow(("PDMR3Suspend: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1658 pDevIns->pReg->pfnSuspend(pDevIns);
1659 if (pDevIns->Internal.s.pfnAsyncNotify)
1660 LogFlow(("PDMR3Suspend: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1661 }
1662 else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
1663 {
1664 LogFlow(("PDMR3Suspend: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1665 pDevIns->Internal.s.pfnAsyncNotify = NULL;
1666 }
1667 if (pDevIns->Internal.s.pfnAsyncNotify)
1668 {
1669 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1670 pdmR3NotifyAsyncAdd(pAsync, pDevIns->Internal.s.pDevR3->pReg->szName, pDevIns->iInstance);
1671 }
1672
1673 PDMCritSectLeave(pDevIns->pCritSectRoR3);
1674 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1675 if (cNsElapsed >= PDMSUSPEND_WARN_AT_NS)
1676 LogRel(("PDMR3Suspend: device '%s'/%d took %'llu ns to suspend\n",
1677 pDevIns->pReg->szName, pDevIns->iInstance, cNsElapsed));
1678 }
1679 }
1680}
1681
1682
1683/**
1684 * This function will notify all the devices and their attached drivers about
1685 * the VM now being suspended.
1686 *
1687 * @param pVM Pointer to the VM.
1688 * @thread EMT(0)
1689 */
1690VMMR3_INT_DECL(void) PDMR3Suspend(PVM pVM)
1691{
1692 LogFlow(("PDMR3Suspend:\n"));
1693 VM_ASSERT_EMT0(pVM);
1694 uint64_t cNsElapsed = RTTimeNanoTS();
1695
1696 /*
1697 * The outer loop repeats until there are no more async requests.
1698 *
1699 * Note! We depend on the suspended indicators to be in the desired state
1700 * and we do not reset them before starting because this allows
1701 * PDMR3PowerOn and PDMR3Resume to use PDMR3Suspend for cleaning up
1702 * on failure.
1703 */
1704 PDMNOTIFYASYNCSTATS Async;
1705 pdmR3NotifyAsyncInit(&Async, "PDMR3Suspend");
1706 for (;;)
1707 {
1708 pdmR3NotifyAsyncBeginLoop(&Async);
1709
1710 /*
1711 * Iterate thru the device instances and USB device instances,
1712 * processing the drivers associated with those.
1713 *
1714 * The attached drivers are normally processed first. Some devices
1715 * (like DevAHCI) though needs to be notified before the drivers so
1716 * that it doesn't kick off any new requests after the drivers stopped
1717 * taking any. (DrvVD changes to read-only in this particular case.)
1718 */
1719 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1720 {
1721 unsigned const cAsyncStart = Async.cAsync;
1722
1723 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION)
1724 pdmR3SuspendDev(pDevIns, &Async);
1725
1726 if (Async.cAsync == cAsyncStart)
1727 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1728 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1729 if (!pdmR3SuspendDrv(pDrvIns, &Async, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
1730 break;
1731
1732 if ( Async.cAsync == cAsyncStart
1733 && !(pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION))
1734 pdmR3SuspendDev(pDevIns, &Async);
1735 }
1736
1737#ifdef VBOX_WITH_USB
1738 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1739 {
1740 unsigned const cAsyncStart = Async.cAsync;
1741
1742 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1743 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1744 if (!pdmR3SuspendDrv(pDrvIns, &Async, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
1745 break;
1746
1747 if (Async.cAsync == cAsyncStart)
1748 pdmR3SuspendUsb(pUsbIns, &Async);
1749 }
1750#endif
1751 if (!Async.cAsync)
1752 break;
1753 pdmR3NotifyAsyncLog(&Async);
1754 pdmR3NotifyAsyncWaitAndProcessRequests(&Async, pVM);
1755 }
1756
1757 /*
1758 * Suspend all threads.
1759 */
1760 pdmR3ThreadSuspendAll(pVM);
1761
1762 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1763 LogRel(("PDMR3Suspend: %'llu ns run time\n", cNsElapsed));
1764}
1765
1766
1767/**
1768 * Worker for PDMR3Resume that deals with one driver.
1769 *
1770 * @param pDrvIns The driver instance.
1771 * @param pszDevName The parent device name.
1772 * @param iDevInstance The parent device instance number.
1773 * @param iLun The parent LUN number.
1774 */
1775DECLINLINE(int) pdmR3ResumeDrv(PPDMDRVINS pDrvIns, const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1776{
1777 Assert(pDrvIns->Internal.s.fVMSuspended);
1778 if (pDrvIns->pReg->pfnResume)
1779 {
1780 LogFlow(("PDMR3Resume: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1781 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1782 int rc = VINF_SUCCESS; pDrvIns->pReg->pfnResume(pDrvIns);
1783 if (RT_FAILURE(rc))
1784 {
1785 LogRel(("PDMR3Resume: driver '%s'/%d on LUN#%d of device '%s'/%d -> %Rrc\n",
1786 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance, rc));
1787 return rc;
1788 }
1789 }
1790 pDrvIns->Internal.s.fVMSuspended = false;
1791 return VINF_SUCCESS;
1792}
1793
1794
1795/**
1796 * Worker for PDMR3Resume that deals with one USB device instance.
1797 *
1798 * @returns VBox status code.
1799 * @param pUsbIns The USB device instance.
1800 */
1801DECLINLINE(int) pdmR3ResumeUsb(PPDMUSBINS pUsbIns)
1802{
1803 Assert(pUsbIns->Internal.s.fVMSuspended);
1804 if (pUsbIns->pReg->pfnVMResume)
1805 {
1806 LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1807 int rc = VINF_SUCCESS; pUsbIns->pReg->pfnVMResume(pUsbIns);
1808 if (RT_FAILURE(rc))
1809 {
1810 LogRel(("PDMR3Resume: device '%s'/%d -> %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1811 return rc;
1812 }
1813 }
1814 pUsbIns->Internal.s.fVMSuspended = false;
1815 return VINF_SUCCESS;
1816}
1817
1818
1819/**
1820 * Worker for PDMR3Resume that deals with one device instance.
1821 *
1822 * @returns VBox status code.
1823 * @param pDevIns The device instance.
1824 */
1825DECLINLINE(int) pdmR3ResumeDev(PPDMDEVINS pDevIns)
1826{
1827 Assert(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED);
1828 if (pDevIns->pReg->pfnResume)
1829 {
1830 LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1831 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
1832 int rc = VINF_SUCCESS; pDevIns->pReg->pfnResume(pDevIns);
1833 PDMCritSectLeave(pDevIns->pCritSectRoR3);
1834 if (RT_FAILURE(rc))
1835 {
1836 LogRel(("PDMR3Resume: device '%s'/%d -> %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
1837 return rc;
1838 }
1839 }
1840 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1841 return VINF_SUCCESS;
1842}
1843
1844
1845/**
1846 * This function will notify all the devices and their
1847 * attached drivers about the VM now being resumed.
1848 *
1849 * @param pVM Pointer to the VM.
1850 */
1851VMMR3_INT_DECL(void) PDMR3Resume(PVM pVM)
1852{
1853 LogFlow(("PDMR3Resume:\n"));
1854
1855 /*
1856 * Iterate thru the device instances and USB device instances,
1857 * processing the drivers associated with those.
1858 */
1859 int rc = VINF_SUCCESS;
1860 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns && RT_SUCCESS(rc); pDevIns = pDevIns->Internal.s.pNextR3)
1861 {
1862 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1863 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1864 rc = pdmR3ResumeDrv(pDrvIns, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun);
1865 if (RT_SUCCESS(rc))
1866 rc = pdmR3ResumeDev(pDevIns);
1867 }
1868
1869#ifdef VBOX_WITH_USB
1870 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns && RT_SUCCESS(rc); pUsbIns = pUsbIns->Internal.s.pNext)
1871 {
1872 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1873 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1874 rc = pdmR3ResumeDrv(pDrvIns, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun);
1875 if (RT_SUCCESS(rc))
1876 rc = pdmR3ResumeUsb(pUsbIns);
1877 }
1878#endif
1879
1880 /*
1881 * Resume all threads.
1882 */
1883 if (RT_SUCCESS(rc))
1884 pdmR3ThreadResumeAll(pVM);
1885
1886 /*
1887 * Resume the block cache.
1888 */
1889 if (RT_SUCCESS(rc))
1890 pdmR3BlkCacheResume(pVM);
1891
1892 /*
1893 * On failure, clean up via PDMR3Suspend.
1894 */
1895 if (RT_FAILURE(rc))
1896 PDMR3Suspend(pVM);
1897
1898 LogFlow(("PDMR3Resume: returns %Rrc\n", rc));
1899 return /*rc*/;
1900}
1901
1902
1903/**
1904 * Worker for PDMR3PowerOff that deals with one driver.
1905 *
1906 * @param pDrvIns The driver instance.
1907 * @param pAsync The structure for recording asynchronous
1908 * notification tasks.
1909 * @param pszDevName The parent device name.
1910 * @param iDevInstance The parent device instance number.
1911 * @param iLun The parent LUN number.
1912 */
1913DECLINLINE(bool) pdmR3PowerOffDrv(PPDMDRVINS pDrvIns, PPDMNOTIFYASYNCSTATS pAsync,
1914 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1915{
1916 if (!pDrvIns->Internal.s.fVMSuspended)
1917 {
1918 pDrvIns->Internal.s.fVMSuspended = true;
1919 if (pDrvIns->pReg->pfnPowerOff)
1920 {
1921 uint64_t cNsElapsed = RTTimeNanoTS();
1922
1923 if (!pDrvIns->Internal.s.pfnAsyncNotify)
1924 {
1925 LogFlow(("PDMR3PowerOff: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1926 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1927 pDrvIns->pReg->pfnPowerOff(pDrvIns);
1928 if (pDrvIns->Internal.s.pfnAsyncNotify)
1929 LogFlow(("PDMR3PowerOff: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1930 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1931 }
1932 else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
1933 {
1934 LogFlow(("PDMR3PowerOff: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1935 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1936 pDrvIns->Internal.s.pfnAsyncNotify = NULL;
1937 }
1938
1939 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1940 if (cNsElapsed >= PDMPOWEROFF_WARN_AT_NS)
1941 LogRel(("PDMR3PowerOff: Driver '%s'/%d on LUN#%d of device '%s'/%d took %'llu ns to power off\n",
1942 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance, cNsElapsed));
1943
1944 if (pDrvIns->Internal.s.pfnAsyncNotify)
1945 {
1946 pDrvIns->Internal.s.fVMSuspended = false;
1947 pdmR3NotifyAsyncAddDrv(pAsync, pDrvIns->Internal.s.pDrv->pReg->szName, pDrvIns->iInstance,
1948 pszDevName, iDevInstance, iLun);
1949 return false;
1950 }
1951 }
1952 }
1953 return true;
1954}
1955
1956
1957/**
1958 * Worker for PDMR3PowerOff that deals with one USB device instance.
1959 *
1960 * @param pUsbIns The USB device instance.
1961 * @param pAsync The structure for recording asynchronous
1962 * notification tasks.
1963 */
1964DECLINLINE(void) pdmR3PowerOffUsb(PPDMUSBINS pUsbIns, PPDMNOTIFYASYNCSTATS pAsync)
1965{
1966 if (!pUsbIns->Internal.s.fVMSuspended)
1967 {
1968 pUsbIns->Internal.s.fVMSuspended = true;
1969 if (pUsbIns->pReg->pfnVMPowerOff)
1970 {
1971 uint64_t cNsElapsed = RTTimeNanoTS();
1972
1973 if (!pUsbIns->Internal.s.pfnAsyncNotify)
1974 {
1975 LogFlow(("PDMR3PowerOff: Notifying - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1976 pUsbIns->pReg->pfnVMPowerOff(pUsbIns);
1977 if (pUsbIns->Internal.s.pfnAsyncNotify)
1978 LogFlow(("PDMR3PowerOff: Async notification started - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1979 }
1980 else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
1981 {
1982 LogFlow(("PDMR3PowerOff: Async notification completed - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1983 pUsbIns->Internal.s.pfnAsyncNotify = NULL;
1984 }
1985 if (pUsbIns->Internal.s.pfnAsyncNotify)
1986 {
1987 pUsbIns->Internal.s.fVMSuspended = false;
1988 pdmR3NotifyAsyncAdd(pAsync, pUsbIns->Internal.s.pUsbDev->pReg->szName, pUsbIns->iInstance);
1989 }
1990
1991 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1992 if (cNsElapsed >= PDMPOWEROFF_WARN_AT_NS)
1993 LogRel(("PDMR3PowerOff: USB device '%s'/%d took %'llu ns to power off\n",
1994 pUsbIns->pReg->szName, pUsbIns->iInstance, cNsElapsed));
1995
1996 }
1997 }
1998}
1999
2000
2001/**
2002 * Worker for PDMR3PowerOff that deals with one device instance.
2003 *
2004 * @param pDevIns The device instance.
2005 * @param pAsync The structure for recording asynchronous
2006 * notification tasks.
2007 */
2008DECLINLINE(void) pdmR3PowerOffDev(PPDMDEVINS pDevIns, PPDMNOTIFYASYNCSTATS pAsync)
2009{
2010 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED))
2011 {
2012 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_SUSPENDED;
2013 if (pDevIns->pReg->pfnPowerOff)
2014 {
2015 uint64_t cNsElapsed = RTTimeNanoTS();
2016 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
2017
2018 if (!pDevIns->Internal.s.pfnAsyncNotify)
2019 {
2020 LogFlow(("PDMR3PowerOff: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
2021 pDevIns->pReg->pfnPowerOff(pDevIns);
2022 if (pDevIns->Internal.s.pfnAsyncNotify)
2023 LogFlow(("PDMR3PowerOff: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
2024 }
2025 else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
2026 {
2027 LogFlow(("PDMR3PowerOff: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
2028 pDevIns->Internal.s.pfnAsyncNotify = NULL;
2029 }
2030 if (pDevIns->Internal.s.pfnAsyncNotify)
2031 {
2032 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
2033 pdmR3NotifyAsyncAdd(pAsync, pDevIns->Internal.s.pDevR3->pReg->szName, pDevIns->iInstance);
2034 }
2035
2036 PDMCritSectLeave(pDevIns->pCritSectRoR3);
2037 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
2038 if (cNsElapsed >= PDMPOWEROFF_WARN_AT_NS)
2039 LogFlow(("PDMR3PowerOff: Device '%s'/%d took %'llu ns to power off\n",
2040 pDevIns->pReg->szName, pDevIns->iInstance, cNsElapsed));
2041 }
2042 }
2043}
2044
2045
2046/**
2047 * This function will notify all the devices and their
2048 * attached drivers about the VM being powered off.
2049 *
2050 * @param pVM Pointer to the VM.
2051 */
2052VMMR3DECL(void) PDMR3PowerOff(PVM pVM)
2053{
2054 LogFlow(("PDMR3PowerOff:\n"));
2055 uint64_t cNsElapsed = RTTimeNanoTS();
2056
2057 /*
2058 * The outer loop repeats until there are no more async requests.
2059 */
2060 PDMNOTIFYASYNCSTATS Async;
2061 pdmR3NotifyAsyncInit(&Async, "PDMR3PowerOff");
2062 for (;;)
2063 {
2064 pdmR3NotifyAsyncBeginLoop(&Async);
2065
2066 /*
2067 * Iterate thru the device instances and USB device instances,
2068 * processing the drivers associated with those.
2069 *
2070 * The attached drivers are normally processed first. Some devices
2071 * (like DevAHCI) though needs to be notified before the drivers so
2072 * that it doesn't kick off any new requests after the drivers stopped
2073 * taking any. (DrvVD changes to read-only in this particular case.)
2074 */
2075 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2076 {
2077 unsigned const cAsyncStart = Async.cAsync;
2078
2079 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION)
2080 pdmR3PowerOffDev(pDevIns, &Async);
2081
2082 if (Async.cAsync == cAsyncStart)
2083 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
2084 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2085 if (!pdmR3PowerOffDrv(pDrvIns, &Async, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
2086 break;
2087
2088 if ( Async.cAsync == cAsyncStart
2089 && !(pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION))
2090 pdmR3PowerOffDev(pDevIns, &Async);
2091 }
2092
2093#ifdef VBOX_WITH_USB
2094 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2095 {
2096 unsigned const cAsyncStart = Async.cAsync;
2097
2098 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
2099 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2100 if (!pdmR3PowerOffDrv(pDrvIns, &Async, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
2101 break;
2102
2103 if (Async.cAsync == cAsyncStart)
2104 pdmR3PowerOffUsb(pUsbIns, &Async);
2105 }
2106#endif
2107 if (!Async.cAsync)
2108 break;
2109 pdmR3NotifyAsyncLog(&Async);
2110 pdmR3NotifyAsyncWaitAndProcessRequests(&Async, pVM);
2111 }
2112
2113 /*
2114 * Suspend all threads.
2115 */
2116 pdmR3ThreadSuspendAll(pVM);
2117
2118 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
2119 LogRel(("PDMR3PowerOff: %'llu ns run time\n", cNsElapsed));
2120}
2121
2122
2123/**
2124 * Queries the base interface of a device instance.
2125 *
2126 * The caller can use this to query other interfaces the device implements
2127 * and use them to talk to the device.
2128 *
2129 * @returns VBox status code.
2130 * @param pUVM The user mode VM handle.
2131 * @param pszDevice Device name.
2132 * @param iInstance Device instance.
2133 * @param ppBase Where to store the pointer to the base device interface on success.
2134 * @remark We're not doing any locking ATM, so don't try call this at times when the
2135 * device chain is known to be updated.
2136 */
2137VMMR3DECL(int) PDMR3QueryDevice(PUVM pUVM, const char *pszDevice, unsigned iInstance, PPDMIBASE *ppBase)
2138{
2139 LogFlow(("PDMR3DeviceQuery: pszDevice=%p:{%s} iInstance=%u ppBase=%p\n", pszDevice, pszDevice, iInstance, ppBase));
2140 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
2141 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
2142
2143 /*
2144 * Iterate registered devices looking for the device.
2145 */
2146 size_t cchDevice = strlen(pszDevice);
2147 for (PPDMDEV pDev = pUVM->pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
2148 {
2149 if ( pDev->cchName == cchDevice
2150 && !memcmp(pDev->pReg->szName, pszDevice, cchDevice))
2151 {
2152 /*
2153 * Iterate device instances.
2154 */
2155 for (PPDMDEVINS pDevIns = pDev->pInstances; pDevIns; pDevIns = pDevIns->Internal.s.pPerDeviceNextR3)
2156 {
2157 if (pDevIns->iInstance == iInstance)
2158 {
2159 if (pDevIns->IBase.pfnQueryInterface)
2160 {
2161 *ppBase = &pDevIns->IBase;
2162 LogFlow(("PDMR3DeviceQuery: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
2163 return VINF_SUCCESS;
2164 }
2165
2166 LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NO_IBASE\n"));
2167 return VERR_PDM_DEVICE_INSTANCE_NO_IBASE;
2168 }
2169 }
2170
2171 LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NOT_FOUND\n"));
2172 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND;
2173 }
2174 }
2175
2176 LogFlow(("PDMR3QueryDevice: returns VERR_PDM_DEVICE_NOT_FOUND\n"));
2177 return VERR_PDM_DEVICE_NOT_FOUND;
2178}
2179
2180
2181/**
2182 * Queries the base interface of a device LUN.
2183 *
2184 * This differs from PDMR3QueryLun by that it returns the interface on the
2185 * device and not the top level driver.
2186 *
2187 * @returns VBox status code.
2188 * @param pUVM The user mode VM handle.
2189 * @param pszDevice Device name.
2190 * @param iInstance Device instance.
2191 * @param iLun The Logical Unit to obtain the interface of.
2192 * @param ppBase Where to store the base interface pointer.
2193 * @remark We're not doing any locking ATM, so don't try call this at times when the
2194 * device chain is known to be updated.
2195 */
2196VMMR3DECL(int) PDMR3QueryDeviceLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
2197{
2198 LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
2199 pszDevice, pszDevice, iInstance, iLun, ppBase));
2200 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
2201 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
2202
2203 /*
2204 * Find the LUN.
2205 */
2206 PPDMLUN pLun;
2207 int rc = pdmR3DevFindLun(pUVM->pVM, pszDevice, iInstance, iLun, &pLun);
2208 if (RT_SUCCESS(rc))
2209 {
2210 *ppBase = pLun->pBase;
2211 LogFlow(("PDMR3QueryDeviceLun: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
2212 return VINF_SUCCESS;
2213 }
2214 LogFlow(("PDMR3QueryDeviceLun: returns %Rrc\n", rc));
2215 return rc;
2216}
2217
2218
2219/**
2220 * Query the interface of the top level driver on a LUN.
2221 *
2222 * @returns VBox status code.
2223 * @param pUVM The user mode VM handle.
2224 * @param pszDevice Device name.
2225 * @param iInstance Device instance.
2226 * @param iLun The Logical Unit to obtain the interface of.
2227 * @param ppBase Where to store the base interface pointer.
2228 * @remark We're not doing any locking ATM, so don't try call this at times when the
2229 * device chain is known to be updated.
2230 */
2231VMMR3DECL(int) PDMR3QueryLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
2232{
2233 LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
2234 pszDevice, pszDevice, iInstance, iLun, ppBase));
2235 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
2236 PVM pVM = pUVM->pVM;
2237 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
2238
2239 /*
2240 * Find the LUN.
2241 */
2242 PPDMLUN pLun;
2243 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
2244 if (RT_SUCCESS(rc))
2245 {
2246 if (pLun->pTop)
2247 {
2248 *ppBase = &pLun->pTop->IBase;
2249 LogFlow(("PDMR3QueryLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
2250 return VINF_SUCCESS;
2251 }
2252 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
2253 }
2254 LogFlow(("PDMR3QueryLun: returns %Rrc\n", rc));
2255 return rc;
2256}
2257
2258
2259/**
2260 * Query the interface of a named driver on a LUN.
2261 *
2262 * If the driver appears more than once in the driver chain, the first instance
2263 * is returned.
2264 *
2265 * @returns VBox status code.
2266 * @param pUVM The user mode VM handle.
2267 * @param pszDevice Device name.
2268 * @param iInstance Device instance.
2269 * @param iLun The Logical Unit to obtain the interface of.
2270 * @param pszDriver The driver name.
2271 * @param ppBase Where to store the base interface pointer.
2272 *
2273 * @remark We're not doing any locking ATM, so don't try call this at times when the
2274 * device chain is known to be updated.
2275 */
2276VMMR3DECL(int) PDMR3QueryDriverOnLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, const char *pszDriver, PPPDMIBASE ppBase)
2277{
2278 LogFlow(("PDMR3QueryDriverOnLun: pszDevice=%p:{%s} iInstance=%u iLun=%u pszDriver=%p:{%s} ppBase=%p\n",
2279 pszDevice, pszDevice, iInstance, iLun, pszDriver, pszDriver, ppBase));
2280 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
2281 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
2282
2283 /*
2284 * Find the LUN.
2285 */
2286 PPDMLUN pLun;
2287 int rc = pdmR3DevFindLun(pUVM->pVM, pszDevice, iInstance, iLun, &pLun);
2288 if (RT_SUCCESS(rc))
2289 {
2290 if (pLun->pTop)
2291 {
2292 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2293 if (!strcmp(pDrvIns->pReg->szName, pszDriver))
2294 {
2295 *ppBase = &pDrvIns->IBase;
2296 LogFlow(("PDMR3QueryDriverOnLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
2297 return VINF_SUCCESS;
2298
2299 }
2300 rc = VERR_PDM_DRIVER_NOT_FOUND;
2301 }
2302 else
2303 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
2304 }
2305 LogFlow(("PDMR3QueryDriverOnLun: returns %Rrc\n", rc));
2306 return rc;
2307}
2308
2309/**
2310 * Executes pending DMA transfers.
2311 * Forced Action handler.
2312 *
2313 * @param pVM Pointer to the VM.
2314 */
2315VMMR3DECL(void) PDMR3DmaRun(PVM pVM)
2316{
2317 /* Note! Not really SMP safe; restrict it to VCPU 0. */
2318 if (VMMGetCpuId(pVM) != 0)
2319 return;
2320
2321 if (VM_FF_TESTANDCLEAR(pVM, VM_FF_PDM_DMA))
2322 {
2323 if (pVM->pdm.s.pDmac)
2324 {
2325 bool fMore = pVM->pdm.s.pDmac->Reg.pfnRun(pVM->pdm.s.pDmac->pDevIns);
2326 if (fMore)
2327 VM_FF_SET(pVM, VM_FF_PDM_DMA);
2328 }
2329 }
2330}
2331
2332
2333/**
2334 * Service a VMMCALLRING3_PDM_LOCK call.
2335 *
2336 * @returns VBox status code.
2337 * @param pVM Pointer to the VM.
2338 */
2339VMMR3_INT_DECL(int) PDMR3LockCall(PVM pVM)
2340{
2341 return PDMR3CritSectEnterEx(&pVM->pdm.s.CritSect, true /* fHostCall */);
2342}
2343
2344
2345/**
2346 * Registers the VMM device heap
2347 *
2348 * @returns VBox status code.
2349 * @param pVM Pointer to the VM.
2350 * @param GCPhys The physical address.
2351 * @param pvHeap Ring-3 pointer.
2352 * @param cbSize Size of the heap.
2353 */
2354VMMR3_INT_DECL(int) PDMR3VmmDevHeapRegister(PVM pVM, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbSize)
2355{
2356 Assert(pVM->pdm.s.pvVMMDevHeap == NULL);
2357
2358 Log(("PDMR3VmmDevHeapRegister %RGp %RHv %x\n", GCPhys, pvHeap, cbSize));
2359 pVM->pdm.s.pvVMMDevHeap = pvHeap;
2360 pVM->pdm.s.GCPhysVMMDevHeap = GCPhys;
2361 pVM->pdm.s.cbVMMDevHeap = cbSize;
2362 pVM->pdm.s.cbVMMDevHeapLeft = cbSize;
2363 return VINF_SUCCESS;
2364}
2365
2366
2367/**
2368 * Unregisters the VMM device heap
2369 *
2370 * @returns VBox status code.
2371 * @param pVM Pointer to the VM.
2372 * @param GCPhys The physical address.
2373 */
2374VMMR3_INT_DECL(int) PDMR3VmmDevHeapUnregister(PVM pVM, RTGCPHYS GCPhys)
2375{
2376 Assert(pVM->pdm.s.GCPhysVMMDevHeap == GCPhys);
2377
2378 Log(("PDMR3VmmDevHeapUnregister %RGp\n", GCPhys));
2379 pVM->pdm.s.pvVMMDevHeap = NULL;
2380 pVM->pdm.s.GCPhysVMMDevHeap = NIL_RTGCPHYS;
2381 pVM->pdm.s.cbVMMDevHeap = 0;
2382 pVM->pdm.s.cbVMMDevHeapLeft = 0;
2383 return VINF_SUCCESS;
2384}
2385
2386
2387/**
2388 * Allocates memory from the VMM device heap
2389 *
2390 * @returns VBox status code.
2391 * @param pVM Pointer to the VM.
2392 * @param cbSize Allocation size.
2393 * @param pv Ring-3 pointer. (out)
2394 */
2395VMMR3_INT_DECL(int) PDMR3VmmDevHeapAlloc(PVM pVM, size_t cbSize, RTR3PTR *ppv)
2396{
2397#ifdef DEBUG_bird
2398 if (!cbSize || cbSize > pVM->pdm.s.cbVMMDevHeapLeft)
2399 return VERR_NO_MEMORY;
2400#else
2401 AssertReturn(cbSize && cbSize <= pVM->pdm.s.cbVMMDevHeapLeft, VERR_NO_MEMORY);
2402#endif
2403
2404 Log(("PDMR3VMMDevHeapAlloc: %#zx\n", cbSize));
2405
2406 /** @todo Not a real heap as there's currently only one user. */
2407 *ppv = pVM->pdm.s.pvVMMDevHeap;
2408 pVM->pdm.s.cbVMMDevHeapLeft = 0;
2409 return VINF_SUCCESS;
2410}
2411
2412
2413/**
2414 * Frees memory from the VMM device heap
2415 *
2416 * @returns VBox status code.
2417 * @param pVM Pointer to the VM.
2418 * @param pv Ring-3 pointer.
2419 */
2420VMMR3_INT_DECL(int) PDMR3VmmDevHeapFree(PVM pVM, RTR3PTR pv)
2421{
2422 Log(("PDMR3VmmDevHeapFree: %RHv\n", pv));
2423
2424 /** @todo not a real heap as there's currently only one user. */
2425 pVM->pdm.s.cbVMMDevHeapLeft = pVM->pdm.s.cbVMMDevHeap;
2426 return VINF_SUCCESS;
2427}
2428
2429
2430/**
2431 * Worker for DBGFR3TraceConfig that checks if the given tracing group name
2432 * matches a device or driver name and applies the tracing config change.
2433 *
2434 * @returns VINF_SUCCESS or VERR_NOT_FOUND.
2435 * @param pVM Pointer to the VM.
2436 * @param pszName The tracing config group name. This is NULL if
2437 * the operation applies to every device and
2438 * driver.
2439 * @param cchName The length to match.
2440 * @param fEnable Whether to enable or disable the corresponding
2441 * trace points.
2442 * @param fApply Whether to actually apply the changes or just do
2443 * existence checks.
2444 */
2445VMMR3_INT_DECL(int) PDMR3TracingConfig(PVM pVM, const char *pszName, size_t cchName, bool fEnable, bool fApply)
2446{
2447 /** @todo This code is potentially racing driver attaching and detaching. */
2448
2449 /*
2450 * Applies to all.
2451 */
2452 if (pszName == NULL)
2453 {
2454 AssertReturn(fApply, VINF_SUCCESS);
2455
2456 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2457 {
2458 pDevIns->fTracing = fEnable;
2459 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
2460 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2461 pDrvIns->fTracing = fEnable;
2462 }
2463
2464#ifdef VBOX_WITH_USB
2465 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2466 {
2467 pUsbIns->fTracing = fEnable;
2468 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
2469 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2470 pDrvIns->fTracing = fEnable;
2471
2472 }
2473#endif
2474 return VINF_SUCCESS;
2475 }
2476
2477 /*
2478 * Specific devices, USB devices or drivers.
2479 * Decode prefix to figure which of these it applies to.
2480 */
2481 if (cchName <= 3)
2482 return VERR_NOT_FOUND;
2483
2484 uint32_t cMatches = 0;
2485 if (!strncmp("dev", pszName, 3))
2486 {
2487 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2488 {
2489 const char *pszDevName = pDevIns->Internal.s.pDevR3->pReg->szName;
2490 size_t cchDevName = strlen(pszDevName);
2491 if ( ( cchDevName == cchName
2492 && RTStrNICmp(pszName, pszDevName, cchDevName))
2493 || ( cchDevName == cchName - 3
2494 && RTStrNICmp(pszName + 3, pszDevName, cchDevName)) )
2495 {
2496 cMatches++;
2497 if (fApply)
2498 pDevIns->fTracing = fEnable;
2499 }
2500 }
2501 }
2502 else if (!strncmp("usb", pszName, 3))
2503 {
2504 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2505 {
2506 const char *pszUsbName = pUsbIns->Internal.s.pUsbDev->pReg->szName;
2507 size_t cchUsbName = strlen(pszUsbName);
2508 if ( ( cchUsbName == cchName
2509 && RTStrNICmp(pszName, pszUsbName, cchUsbName))
2510 || ( cchUsbName == cchName - 3
2511 && RTStrNICmp(pszName + 3, pszUsbName, cchUsbName)) )
2512 {
2513 cMatches++;
2514 if (fApply)
2515 pUsbIns->fTracing = fEnable;
2516 }
2517 }
2518 }
2519 else if (!strncmp("drv", pszName, 3))
2520 {
2521 AssertReturn(fApply, VINF_SUCCESS);
2522
2523 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2524 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
2525 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2526 {
2527 const char *pszDrvName = pDrvIns->Internal.s.pDrv->pReg->szName;
2528 size_t cchDrvName = strlen(pszDrvName);
2529 if ( ( cchDrvName == cchName
2530 && RTStrNICmp(pszName, pszDrvName, cchDrvName))
2531 || ( cchDrvName == cchName - 3
2532 && RTStrNICmp(pszName + 3, pszDrvName, cchDrvName)) )
2533 {
2534 cMatches++;
2535 if (fApply)
2536 pDrvIns->fTracing = fEnable;
2537 }
2538 }
2539
2540#ifdef VBOX_WITH_USB
2541 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2542 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
2543 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2544 {
2545 const char *pszDrvName = pDrvIns->Internal.s.pDrv->pReg->szName;
2546 size_t cchDrvName = strlen(pszDrvName);
2547 if ( ( cchDrvName == cchName
2548 && RTStrNICmp(pszName, pszDrvName, cchDrvName))
2549 || ( cchDrvName == cchName - 3
2550 && RTStrNICmp(pszName + 3, pszDrvName, cchDrvName)) )
2551 {
2552 cMatches++;
2553 if (fApply)
2554 pDrvIns->fTracing = fEnable;
2555 }
2556 }
2557#endif
2558 }
2559 else
2560 return VERR_NOT_FOUND;
2561
2562 return cMatches > 0 ? VINF_SUCCESS : VERR_NOT_FOUND;
2563}
2564
2565
2566/**
2567 * Worker for DBGFR3TraceQueryConfig that checks whether all drivers, devices,
2568 * and USB device have the same tracing settings.
2569 *
2570 * @returns true / false.
2571 * @param pVM Pointer to the VM.
2572 * @param fEnabled The tracing setting to check for.
2573 */
2574VMMR3_INT_DECL(bool) PDMR3TracingAreAll(PVM pVM, bool fEnabled)
2575{
2576 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2577 {
2578 if (pDevIns->fTracing != (uint32_t)fEnabled)
2579 return false;
2580
2581 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
2582 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2583 if (pDrvIns->fTracing != (uint32_t)fEnabled)
2584 return false;
2585 }
2586
2587#ifdef VBOX_WITH_USB
2588 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2589 {
2590 if (pUsbIns->fTracing != (uint32_t)fEnabled)
2591 return false;
2592
2593 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
2594 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2595 if (pDrvIns->fTracing != (uint32_t)fEnabled)
2596 return false;
2597 }
2598#endif
2599
2600 return true;
2601}
2602
2603
2604/**
2605 * Worker for PDMR3TracingQueryConfig that adds a prefixed name to the output
2606 * string.
2607 *
2608 * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW
2609 * @param ppszDst The pointer to the output buffer pointer.
2610 * @param pcbDst The pointer to the output buffer size.
2611 * @param fSpace Whether to add a space before the name.
2612 * @param pszPrefix The name prefix.
2613 * @param pszName The name.
2614 */
2615static int pdmR3TracingAdd(char **ppszDst, size_t *pcbDst, bool fSpace, const char *pszPrefix, const char *pszName)
2616{
2617 size_t const cchPrefix = strlen(pszPrefix);
2618 if (!RTStrNICmp(pszPrefix, pszName, cchPrefix))
2619 pszName += cchPrefix;
2620 size_t const cchName = strlen(pszName);
2621
2622 size_t const cchThis = cchName + cchPrefix + fSpace;
2623 if (cchThis >= *pcbDst)
2624 return VERR_BUFFER_OVERFLOW;
2625 if (fSpace)
2626 {
2627 **ppszDst = ' ';
2628 memcpy(*ppszDst + 1, pszPrefix, cchPrefix);
2629 memcpy(*ppszDst + 1 + cchPrefix, pszName, cchName + 1);
2630 }
2631 else
2632 {
2633 memcpy(*ppszDst, pszPrefix, cchPrefix);
2634 memcpy(*ppszDst + cchPrefix, pszName, cchName + 1);
2635 }
2636 *ppszDst += cchThis;
2637 *pcbDst -= cchThis;
2638 return VINF_SUCCESS;
2639}
2640
2641
2642/**
2643 * Worker for DBGFR3TraceQueryConfig use when not everything is either enabled
2644 * or disabled.
2645 *
2646 * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW
2647 * @param pVM Pointer to the VM.
2648 * @param pszConfig Where to store the config spec.
2649 * @param cbConfig The size of the output buffer.
2650 */
2651VMMR3_INT_DECL(int) PDMR3TracingQueryConfig(PVM pVM, char *pszConfig, size_t cbConfig)
2652{
2653 int rc;
2654 char *pszDst = pszConfig;
2655 size_t cbDst = cbConfig;
2656
2657 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2658 {
2659 if (pDevIns->fTracing)
2660 {
2661 rc = pdmR3TracingAdd(&pszDst, &cbDst, pszDst != pszConfig, "dev", pDevIns->Internal.s.pDevR3->pReg->szName);
2662 if (RT_FAILURE(rc))
2663 return rc;
2664 }
2665
2666 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
2667 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2668 if (pDrvIns->fTracing)
2669 {
2670 rc = pdmR3TracingAdd(&pszDst, &cbDst, pszDst != pszConfig, "drv", pDrvIns->Internal.s.pDrv->pReg->szName);
2671 if (RT_FAILURE(rc))
2672 return rc;
2673 }
2674 }
2675
2676#ifdef VBOX_WITH_USB
2677 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2678 {
2679 if (pUsbIns->fTracing)
2680 {
2681 rc = pdmR3TracingAdd(&pszDst, &cbDst, pszDst != pszConfig, "usb", pUsbIns->Internal.s.pUsbDev->pReg->szName);
2682 if (RT_FAILURE(rc))
2683 return rc;
2684 }
2685
2686 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
2687 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2688 if (pDrvIns->fTracing)
2689 {
2690 rc = pdmR3TracingAdd(&pszDst, &cbDst, pszDst != pszConfig, "drv", pDrvIns->Internal.s.pDrv->pReg->szName);
2691 if (RT_FAILURE(rc))
2692 return rc;
2693 }
2694 }
2695#endif
2696
2697 return VINF_SUCCESS;
2698}
2699
2700
2701/**
2702 * Checks that a PDMDRVREG::szName, PDMDEVREG::szName or PDMUSBREG::szName
2703 * field contains only a limited set of ASCII characters.
2704 *
2705 * @returns true / false.
2706 * @param pszName The name to validate.
2707 */
2708bool pdmR3IsValidName(const char *pszName)
2709{
2710 char ch;
2711 while ( (ch = *pszName) != '\0'
2712 && ( RT_C_IS_ALNUM(ch)
2713 || ch == '-'
2714 || ch == ' ' /** @todo disallow this! */
2715 || ch == '_') )
2716 pszName++;
2717 return ch == '\0';
2718}
2719
2720
2721/**
2722 * Info handler for 'pdmtracingids'.
2723 *
2724 * @param pVM Pointer to the VM.
2725 * @param pHlp The output helpers.
2726 * @param pszArgs The optional user arguments.
2727 *
2728 * @remarks Can be called on most threads.
2729 */
2730static DECLCALLBACK(void) pdmR3InfoTracingIds(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
2731{
2732 /*
2733 * Parse the argument (optional).
2734 */
2735 if ( pszArgs
2736 && *pszArgs
2737 && strcmp(pszArgs, "all")
2738 && strcmp(pszArgs, "devices")
2739 && strcmp(pszArgs, "drivers")
2740 && strcmp(pszArgs, "usb"))
2741 {
2742 pHlp->pfnPrintf(pHlp, "Unable to grok '%s'\n", pszArgs);
2743 return;
2744 }
2745 bool fAll = !pszArgs || !*pszArgs || !strcmp(pszArgs, "all");
2746 bool fDevices = fAll || !strcmp(pszArgs, "devices");
2747 bool fUsbDevs = fAll || !strcmp(pszArgs, "usb");
2748 bool fDrivers = fAll || !strcmp(pszArgs, "drivers");
2749
2750 /*
2751 * Produce the requested output.
2752 */
2753/** @todo lock PDM lists! */
2754 /* devices */
2755 if (fDevices)
2756 {
2757 pHlp->pfnPrintf(pHlp, "Device tracing IDs:\n");
2758 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2759 pHlp->pfnPrintf(pHlp, "%05u %s\n", pDevIns->idTracing, pDevIns->Internal.s.pDevR3->pReg->szName);
2760 }
2761
2762 /* USB devices */
2763 if (fUsbDevs)
2764 {
2765 pHlp->pfnPrintf(pHlp, "USB device tracing IDs:\n");
2766 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2767 pHlp->pfnPrintf(pHlp, "%05u %s\n", pUsbIns->idTracing, pUsbIns->Internal.s.pUsbDev->pReg->szName);
2768 }
2769
2770 /* Drivers */
2771 if (fDrivers)
2772 {
2773 pHlp->pfnPrintf(pHlp, "Driver tracing IDs:\n");
2774 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2775 {
2776 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
2777 {
2778 uint32_t iLevel = 0;
2779 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown, iLevel++)
2780 pHlp->pfnPrintf(pHlp, "%05u %s (level %u, lun %u, dev %s)\n",
2781 pDrvIns->idTracing, pDrvIns->Internal.s.pDrv->pReg->szName,
2782 iLevel, pLun->iLun, pDevIns->Internal.s.pDevR3->pReg->szName);
2783 }
2784 }
2785
2786 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2787 {
2788 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
2789 {
2790 uint32_t iLevel = 0;
2791 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown, iLevel++)
2792 pHlp->pfnPrintf(pHlp, "%05u %s (level %u, lun %u, dev %s)\n",
2793 pDrvIns->idTracing, pDrvIns->Internal.s.pDrv->pReg->szName,
2794 iLevel, pLun->iLun, pUsbIns->Internal.s.pUsbDev->pReg->szName);
2795 }
2796 }
2797 }
2798}
2799
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