VirtualBox

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

Last change on this file since 46548 was 46420, checked in by vboxsync, 11 years ago

VMM, recompiler: Purge deprecated macros.

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

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