VirtualBox

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

Last change on this file since 50653 was 49814, checked in by vboxsync, 10 years ago

Devices/USB: First part of the rework, move most of the work to dedicated threads to improve performance

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

© 2023 Oracle
ContactPrivacy policyTerms of Use