VirtualBox

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

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

PDM Audio: Branch -> trunk.

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