VirtualBox

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

Last change on this file since 64396 was 64396, checked in by vboxsync, 8 years ago

PDMPCIDEV: some docs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 110.0 KB
Line 
1/* $Id: PDM.cpp 64396 2016-10-24 15:01:45Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device Manager.
4 */
5
6/*
7 * Copyright (C) 2006-2016 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 * The PDM handles devices and their drivers in a flexible and dynamic manner.
22 *
23 * VirtualBox is designed to be very configurable, i.e. the ability to select
24 * virtual devices and configure them uniquely for a VM. For this reason
25 * virtual devices are not statically linked with the VMM but loaded, linked and
26 * instantiated at runtime by PDM using the information found in the
27 * Configuration Manager (CFGM).
28 *
29 * While the chief purpose of PDM is to manager of devices their drivers, it
30 * also serves as somewhere to put usful things like cross context queues, cross
31 * context synchronization (like critsect), VM centric thread management,
32 * asynchronous I/O framework, and so on.
33 *
34 * @sa @ref grp_pdm
35 * @subpage pg_pdm_block_cache
36 *
37 *
38 * @section sec_pdm_dev The Pluggable Devices
39 *
40 * Devices register themselves when the module containing them is loaded. PDM
41 * will call the entry point 'VBoxDevicesRegister' when loading a device module.
42 * The device module will then use the supplied callback table to check the VMM
43 * version and to register its devices. Each device has an unique name (within
44 * the VM configuration anyway). The name is not only used in PDM, but also in
45 * CFGM to organize device and device instance settings, and by anyone who wants
46 * to talk to a specific device instance.
47 *
48 * When all device modules have been successfully loaded PDM will instantiate
49 * those devices which are configured for the VM. Note that a device may have
50 * more than one instance, take network adaptors as an example. When
51 * instantiating a device PDM provides device instance memory and a callback
52 * table (aka Device Helpers / DevHlp) with the VM APIs which the device
53 * instance is trusted with.
54 *
55 * Some devices are trusted devices, most are not. The trusted devices are an
56 * integrated part of the VM and can obtain the VM handle, thus enabling them to
57 * call any VM API. Untrusted devices can only use the callbacks provided
58 * during device instantiation.
59 *
60 * The main purpose in having DevHlps rather than just giving all the devices
61 * the VM handle and let them call the internal VM APIs directly, is both to
62 * create a binary interface that can be supported across releases and to
63 * create a barrier between devices and the VM. (The trusted / untrusted bit
64 * hasn't turned out to be of much use btw., but it's easy to maintain so there
65 * isn't any point in removing it.)
66 *
67 * A device can provide a ring-0 and/or a raw-mode context extension to improve
68 * the VM performance by handling exits and traps (respectively) without
69 * requiring context switches (to ring-3). Callbacks for MMIO and I/O ports
70 * need to be registered specifically for the additional contexts for this to
71 * make sense. Also, the device has to be trusted to be loaded into R0/RC
72 * because of the extra privilege it entails. Note that raw-mode code and data
73 * will be subject to relocation.
74 *
75 *
76 * @subsection sec_pdm_dev_pci PCI Devices
77 *
78 * A PDM device usually registers one a PCI device during it's instantiation,
79 * legacy devices may register zero, while a few (currently none) more
80 * complicated devices may register multiple PCI functions or devices.
81 *
82 * The bus, device and function assignments can either be done explictly via the
83 * configuration or the registration call, or it can be left up to the PCI bus.
84 * The typical VBox configuration construct (ConsoleImpl2.cpp) will do explict
85 * assignments for all devices it's BusAssignmentManager class knows about.
86 *
87 * For explict CFGM style configuration, the "PCIBusNo", "PCIDeviceNo", and
88 * "PCIFunctionNo" values in the PDM device instance configuration (not the
89 * "config" subkey, but the top level one) will be picked up for the primary PCI
90 * device. The primary PCI configuration is by default the first one, but this
91 * can be controlled using the @a idxDevCfg parameter of the
92 * PDMDEVHLPR3::pfnPCIRegister method. For subsequent configuration (@a
93 * idxDevCfg > 0) the values are taken from the "PciDevNN" subkey, where "NN" is
94 * replaced by the @a idxDevCfg value.
95 *
96 *
97 *
98 * @section sec_pdm_special_devs Special Devices
99 *
100 * Several kinds of devices interacts with the VMM and/or other device and PDM
101 * will work like a mediator for these. The typical pattern is that the device
102 * calls a special registration device helper with a set of callbacks, PDM
103 * responds by copying this and providing a pointer to a set helper callbacks
104 * for that particular kind of device. Unlike interfaces where the callback
105 * table pointer is used a 'this' pointer, these arrangements will use the
106 * device instance pointer (PPDMDEVINS) as a kind of 'this' pointer.
107 *
108 * For an example of this kind of setup, see the PIC. The PIC registers itself
109 * by calling PDMDEVHLPR3::pfnPICRegister. PDM saves the device instance,
110 * copies the callback tables (PDMPICREG), resolving the ring-0 and raw-mode
111 * addresses in the process, and hands back the pointer to a set of helper
112 * methods (PDMPICHLPR3). The PCI device then queries the ring-0 and raw-mode
113 * helpers using PDMPICHLPR3::pfnGetR0Helpers and PDMPICHLPR3::pfnGetRCHelpers.
114 * The PCI device repeats ths pfnGetRCHelpers call in it's relocation method
115 * since the address changes when RC is relocated.
116 *
117 * @see grp_pdm_device
118 *
119 *
120 * @section sec_pdm_usbdev The Pluggable USB Devices
121 *
122 * USB devices are handled a little bit differently than other devices. The
123 * general concepts wrt. pluggability are mostly the same, but the details
124 * varies. The registration entry point is 'VBoxUsbRegister', the device
125 * instance is PDMUSBINS and the callbacks helpers are different. Also, USB
126 * device are restricted to ring-3 and cannot have any ring-0 or raw-mode
127 * extensions (at least not yet).
128 *
129 * The way USB devices work differs greatly from other devices though since they
130 * aren't attaches directly to the PCI/ISA/whatever system buses but via a
131 * USB host control (OHCI, UHCI or EHCI). USB devices handle USB requests
132 * (URBs) and does not register I/O ports, MMIO ranges or PCI bus
133 * devices/functions.
134 *
135 * @see grp_pdm_usbdev
136 *
137 *
138 * @section sec_pdm_drv The Pluggable Drivers
139 *
140 * The VM devices are often accessing host hardware or OS facilities. For most
141 * devices these facilities can be abstracted in one or more levels. These
142 * abstractions are called drivers.
143 *
144 * For instance take a DVD/CD drive. This can be connected to a SCSI
145 * controller, an ATA controller or a SATA controller. The basics of the DVD/CD
146 * drive implementation remains the same - eject, insert, read, seek, and such.
147 * (For the scsi SCSCI, you might want to speak SCSI directly to, but that can of
148 * course be fixed - see SCSI passthru.) So, it
149 * makes much sense to have a generic CD/DVD driver which implements this.
150 *
151 * Then the media 'inserted' into the DVD/CD drive can be a ISO image, or it can
152 * be read from a real CD or DVD drive (there are probably other custom formats
153 * someone could desire to read or construct too). So, it would make sense to
154 * have abstracted interfaces for dealing with this in a generic way so the
155 * cdrom unit doesn't have to implement it all. Thus we have created the
156 * CDROM/DVD media driver family.
157 *
158 * So, for this example the IDE controller #1 (i.e. secondary) will have
159 * the DVD/CD Driver attached to it's LUN #0 (master). When a media is mounted
160 * the DVD/CD Driver will have a ISO, HostDVD or RAW (media) Driver attached.
161 *
162 * It is possible to configure many levels of drivers inserting filters, loggers,
163 * or whatever you desire into the chain. We're using this for network sniffing,
164 * for instance.
165 *
166 * The drivers are loaded in a similar manner to that of a device, namely by
167 * iterating a keyspace in CFGM, load the modules listed there and call
168 * 'VBoxDriversRegister' with a callback table.
169 *
170 * @see grp_pdm_driver
171 *
172 *
173 * @section sec_pdm_ifs Interfaces
174 *
175 * The pluggable drivers and devices expose one standard interface (callback
176 * table) which is used to construct, destruct, attach, detach,( ++,) and query
177 * other interfaces. A device will query the interfaces required for it's
178 * operation during init and hot-plug. PDM may query some interfaces during
179 * runtime mounting too.
180 *
181 * An interface here means a function table contained within the device or
182 * driver instance data. Its methods are invoked with the function table pointer
183 * as the first argument and they will calculate the address of the device or
184 * driver instance data from it. (This is one of the aspects which *might* have
185 * been better done in C++.)
186 *
187 * @see grp_pdm_interfaces
188 *
189 *
190 * @section sec_pdm_utils Utilities
191 *
192 * As mentioned earlier, PDM is the location of any usful constructs that doesn't
193 * quite fit into IPRT. The next subsections will discuss these.
194 *
195 * One thing these APIs all have in common is that resources will be associated
196 * with a device / driver and automatically freed after it has been destroyed if
197 * the destructor didn't do this.
198 *
199 *
200 * @subsection sec_pdm_async_completion Async I/O
201 *
202 * The PDM Async I/O API provides a somewhat platform agnostic interface for
203 * asynchronous I/O. For reasons of performance and complexity this does not
204 * build upon any IPRT API.
205 *
206 * @todo more details.
207 *
208 * @see grp_pdm_async_completion
209 *
210 *
211 * @subsection sec_pdm_async_task Async Task - not implemented
212 *
213 * @todo implement and describe
214 *
215 * @see grp_pdm_async_task
216 *
217 *
218 * @subsection sec_pdm_critsect Critical Section
219 *
220 * The PDM Critical Section API is currently building on the IPRT API with the
221 * same name. It adds the possibility to use critical sections in ring-0 and
222 * raw-mode as well as in ring-3. There are certain restrictions on the RC and
223 * R0 usage though since we're not able to wait on it, nor wake up anyone that
224 * is waiting on it. These restrictions origins with the use of a ring-3 event
225 * semaphore. In a later incarnation we plan to replace the ring-3 event
226 * semaphore with a ring-0 one, thus enabling us to wake up waiters while
227 * exectuing in ring-0 and making the hardware assisted execution mode more
228 * efficient. (Raw-mode won't benefit much from this, naturally.)
229 *
230 * @see grp_pdm_critsect
231 *
232 *
233 * @subsection sec_pdm_queue Queue
234 *
235 * The PDM Queue API is for queuing one or more tasks for later consumption in
236 * ring-3 by EMT, and optionally forcing a delayed or ASAP return to ring-3. The
237 * queues can also be run on a timer basis as an alternative to the ASAP thing.
238 * The queue will be flushed at forced action time.
239 *
240 * A queue can also be used by another thread (a I/O worker for instance) to
241 * send work / events over to the EMT.
242 *
243 * @see grp_pdm_queue
244 *
245 *
246 * @subsection sec_pdm_task Task - not implemented yet
247 *
248 * The PDM Task API is for flagging a task for execution at a later point when
249 * we're back in ring-3, optionally forcing the ring-3 return to happen ASAP.
250 * As you can see the concept is similar to queues only simpler.
251 *
252 * A task can also be scheduled by another thread (a I/O worker for instance) as
253 * a mean of getting something done in EMT.
254 *
255 * @see grp_pdm_task
256 *
257 *
258 * @subsection sec_pdm_thread Thread
259 *
260 * The PDM Thread API is there to help devices and drivers manage their threads
261 * correctly wrt. power on, suspend, resume, power off and destruction.
262 *
263 * The general usage pattern for threads in the employ of devices and drivers is
264 * that they shuffle data or requests while the VM is running and stop doing
265 * this when the VM is paused or powered down. Rogue threads running while the
266 * VM is paused can cause the state to change during saving or have other
267 * unwanted side effects. The PDM Threads API ensures that this won't happen.
268 *
269 * @see grp_pdm_thread
270 *
271 */
272
273
274/*********************************************************************************************************************************
275* Header Files *
276*********************************************************************************************************************************/
277#define LOG_GROUP LOG_GROUP_PDM
278#define PDMPCIDEV_INCLUDE_PRIVATE /* Hack to get pdmpcidevint.h included at the right point. */
279#include "PDMInternal.h"
280#include <VBox/vmm/pdm.h>
281#include <VBox/vmm/em.h>
282#include <VBox/vmm/mm.h>
283#include <VBox/vmm/pgm.h>
284#include <VBox/vmm/ssm.h>
285#include <VBox/vmm/hm.h>
286#include <VBox/vmm/vm.h>
287#include <VBox/vmm/uvm.h>
288#include <VBox/vmm/vmm.h>
289#include <VBox/param.h>
290#include <VBox/err.h>
291#include <VBox/sup.h>
292
293#include <VBox/log.h>
294#include <iprt/asm.h>
295#include <iprt/assert.h>
296#include <iprt/alloc.h>
297#include <iprt/ctype.h>
298#include <iprt/ldr.h>
299#include <iprt/path.h>
300#include <iprt/string.h>
301
302
303/*********************************************************************************************************************************
304* Defined Constants And Macros *
305*********************************************************************************************************************************/
306/** The PDM saved state version. */
307#define PDM_SAVED_STATE_VERSION 5
308/** Before the PDM audio architecture was introduced there was an "AudioSniffer"
309 * device which took care of multiplexing input/output audio data from/to various places.
310 * Thus this device is not needed/used anymore. */
311#define PDM_SAVED_STATE_VERSION_PRE_PDM_AUDIO 4
312#define PDM_SAVED_STATE_VERSION_PRE_NMI_FF 3
313
314/** The number of nanoseconds a suspend callback needs to take before
315 * PDMR3Suspend warns about it taking too long. */
316#define PDMSUSPEND_WARN_AT_NS UINT64_C(1200000000)
317
318/** The number of nanoseconds a suspend callback needs to take before
319 * PDMR3PowerOff warns about it taking too long. */
320#define PDMPOWEROFF_WARN_AT_NS UINT64_C( 900000000)
321
322
323/*********************************************************************************************************************************
324* Structures and Typedefs *
325*********************************************************************************************************************************/
326/**
327 * Statistics of asynchronous notification tasks - used by reset, suspend and
328 * power off.
329 */
330typedef struct PDMNOTIFYASYNCSTATS
331{
332 /** The start timestamp. */
333 uint64_t uStartNsTs;
334 /** When to log the next time. */
335 uint64_t cNsElapsedNextLog;
336 /** The loop counter. */
337 uint32_t cLoops;
338 /** The number of pending asynchronous notification tasks. */
339 uint32_t cAsync;
340 /** The name of the operation (log prefix). */
341 const char *pszOp;
342 /** The current list buffer position. */
343 size_t offList;
344 /** String containing a list of the pending tasks. */
345 char szList[1024];
346} PDMNOTIFYASYNCSTATS;
347/** Pointer to the stats of pending asynchronous notification tasks. */
348typedef PDMNOTIFYASYNCSTATS *PPDMNOTIFYASYNCSTATS;
349
350
351/*********************************************************************************************************************************
352* Internal Functions *
353*********************************************************************************************************************************/
354static DECLCALLBACK(int) pdmR3LiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass);
355static DECLCALLBACK(int) pdmR3SaveExec(PVM pVM, PSSMHANDLE pSSM);
356static DECLCALLBACK(int) pdmR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
357static DECLCALLBACK(int) pdmR3LoadPrep(PVM pVM, PSSMHANDLE pSSM);
358
359static FNDBGFHANDLERINT pdmR3InfoTracingIds;
360
361
362/**
363 * Initializes the PDM part of the UVM.
364 *
365 * This doesn't really do much right now but has to be here for the sake
366 * of completeness.
367 *
368 * @returns VBox status code.
369 * @param pUVM Pointer to the user mode VM structure.
370 */
371VMMR3_INT_DECL(int) PDMR3InitUVM(PUVM pUVM)
372{
373 AssertCompile(sizeof(pUVM->pdm.s) <= sizeof(pUVM->pdm.padding));
374 AssertRelease(sizeof(pUVM->pdm.s) <= sizeof(pUVM->pdm.padding));
375 pUVM->pdm.s.pModules = NULL;
376 pUVM->pdm.s.pCritSects = NULL;
377 pUVM->pdm.s.pRwCritSects = NULL;
378 return RTCritSectInit(&pUVM->pdm.s.ListCritSect);
379}
380
381
382/**
383 * Initializes the PDM.
384 *
385 * @returns VBox status code.
386 * @param pVM The cross context VM structure.
387 */
388VMMR3_INT_DECL(int) PDMR3Init(PVM pVM)
389{
390 LogFlow(("PDMR3Init\n"));
391
392 /*
393 * Assert alignment and sizes.
394 */
395 AssertRelease(!(RT_OFFSETOF(VM, pdm.s) & 31));
396 AssertRelease(sizeof(pVM->pdm.s) <= sizeof(pVM->pdm.padding));
397 AssertCompileMemberAlignment(PDM, CritSect, sizeof(uintptr_t));
398
399 /*
400 * Init the structure.
401 */
402 pVM->pdm.s.GCPhysVMMDevHeap = NIL_RTGCPHYS;
403 //pVM->pdm.s.idTracingDev = 0;
404 pVM->pdm.s.idTracingOther = 1024;
405
406 /*
407 * Initialize critical sections first.
408 */
409 int rc = pdmR3CritSectBothInitStats(pVM);
410 if (RT_SUCCESS(rc))
411 rc = PDMR3CritSectInit(pVM, &pVM->pdm.s.CritSect, RT_SRC_POS, "PDM");
412 if (RT_SUCCESS(rc))
413 {
414 rc = PDMR3CritSectInit(pVM, &pVM->pdm.s.NopCritSect, RT_SRC_POS, "NOP");
415 if (RT_SUCCESS(rc))
416 pVM->pdm.s.NopCritSect.s.Core.fFlags |= RTCRITSECT_FLAGS_NOP;
417 }
418
419 /*
420 * Initialize sub components.
421 */
422 if (RT_SUCCESS(rc))
423 rc = pdmR3LdrInitU(pVM->pUVM);
424#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
425 if (RT_SUCCESS(rc))
426 rc = pdmR3AsyncCompletionInit(pVM);
427#endif
428#ifdef VBOX_WITH_NETSHAPER
429 if (RT_SUCCESS(rc))
430 rc = pdmR3NetShaperInit(pVM);
431#endif
432 if (RT_SUCCESS(rc))
433 rc = pdmR3BlkCacheInit(pVM);
434 if (RT_SUCCESS(rc))
435 rc = pdmR3DrvInit(pVM);
436 if (RT_SUCCESS(rc))
437 rc = pdmR3DevInit(pVM);
438 if (RT_SUCCESS(rc))
439 {
440 /*
441 * Register the saved state data unit.
442 */
443 rc = SSMR3RegisterInternal(pVM, "pdm", 1, PDM_SAVED_STATE_VERSION, 128,
444 NULL, pdmR3LiveExec, NULL,
445 NULL, pdmR3SaveExec, NULL,
446 pdmR3LoadPrep, pdmR3LoadExec, NULL);
447 if (RT_SUCCESS(rc))
448 {
449 /*
450 * Register the info handlers.
451 */
452 DBGFR3InfoRegisterInternal(pVM, "pdmtracingids",
453 "Displays the tracing IDs assigned by PDM to devices, USB device, drivers and more.",
454 pdmR3InfoTracingIds);
455
456 LogFlow(("PDM: Successfully initialized\n"));
457 return rc;
458 }
459 }
460
461 /*
462 * Cleanup and return failure.
463 */
464 PDMR3Term(pVM);
465 LogFlow(("PDMR3Init: returns %Rrc\n", rc));
466 return rc;
467}
468
469
470/**
471 * Init phase completed callback.
472 *
473 * We use this for calling PDMDEVREG::pfnInitComplete callback after everything
474 * else has been initialized.
475 *
476 * @returns VBox status code.
477 * @param pVM The cross context VM structure.
478 * @param enmWhat The phase that was completed.
479 */
480VMMR3_INT_DECL(int) PDMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat)
481{
482#ifdef VBOX_WITH_RAW_MODE
483 if (enmWhat == VMINITCOMPLETED_RC)
484#else
485 if (enmWhat == VMINITCOMPLETED_RING0)
486#endif
487 return pdmR3DevInitComplete(pVM);
488 return VINF_SUCCESS;
489}
490
491
492/**
493 * Applies relocations to data and code managed by this
494 * component. This function will be called at init and
495 * whenever the VMM need to relocate it self inside the GC.
496 *
497 * @param pVM The cross context VM structure.
498 * @param offDelta Relocation delta relative to old location.
499 * @remark The loader subcomponent is relocated by PDMR3LdrRelocate() very
500 * early in the relocation phase.
501 */
502VMMR3_INT_DECL(void) PDMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
503{
504 LogFlow(("PDMR3Relocate\n"));
505
506 /*
507 * Queues.
508 */
509 pdmR3QueueRelocate(pVM, offDelta);
510 pVM->pdm.s.pDevHlpQueueRC = PDMQueueRCPtr(pVM->pdm.s.pDevHlpQueueR3);
511
512 /*
513 * Critical sections.
514 */
515 pdmR3CritSectBothRelocate(pVM);
516
517 /*
518 * The registered PIC.
519 */
520 if (pVM->pdm.s.Pic.pDevInsRC)
521 {
522 pVM->pdm.s.Pic.pDevInsRC += offDelta;
523 pVM->pdm.s.Pic.pfnSetIrqRC += offDelta;
524 pVM->pdm.s.Pic.pfnGetInterruptRC += offDelta;
525 }
526
527 /*
528 * The registered APIC.
529 */
530 if (pVM->pdm.s.Apic.pDevInsRC)
531 {
532 pVM->pdm.s.Apic.pDevInsRC += offDelta;
533 pVM->pdm.s.Apic.pfnGetInterruptRC += offDelta;
534 pVM->pdm.s.Apic.pfnSetBaseMsrRC += offDelta;
535 pVM->pdm.s.Apic.pfnGetBaseMsrRC += offDelta;
536 pVM->pdm.s.Apic.pfnSetTprRC += offDelta;
537 pVM->pdm.s.Apic.pfnGetTprRC += offDelta;
538 pVM->pdm.s.Apic.pfnWriteMsrRC += offDelta;
539 pVM->pdm.s.Apic.pfnReadMsrRC += offDelta;
540 pVM->pdm.s.Apic.pfnBusDeliverRC += offDelta;
541 if (pVM->pdm.s.Apic.pfnLocalInterruptRC)
542 pVM->pdm.s.Apic.pfnLocalInterruptRC += offDelta;
543 pVM->pdm.s.Apic.pfnGetTimerFreqRC += offDelta;
544 }
545
546 /*
547 * The registered I/O APIC.
548 */
549 if (pVM->pdm.s.IoApic.pDevInsRC)
550 {
551 pVM->pdm.s.IoApic.pDevInsRC += offDelta;
552 pVM->pdm.s.IoApic.pfnSetIrqRC += offDelta;
553 if (pVM->pdm.s.IoApic.pfnSendMsiRC)
554 pVM->pdm.s.IoApic.pfnSendMsiRC += offDelta;
555 if (pVM->pdm.s.IoApic.pfnSetEoiRC)
556 pVM->pdm.s.IoApic.pfnSetEoiRC += offDelta;
557 }
558
559 /*
560 * The register PCI Buses.
561 */
562 for (unsigned i = 0; i < RT_ELEMENTS(pVM->pdm.s.aPciBuses); i++)
563 {
564 if (pVM->pdm.s.aPciBuses[i].pDevInsRC)
565 {
566 pVM->pdm.s.aPciBuses[i].pDevInsRC += offDelta;
567 pVM->pdm.s.aPciBuses[i].pfnSetIrqRC += offDelta;
568 }
569 }
570
571 /*
572 * Devices & Drivers.
573 */
574 int rc;
575 PCPDMDEVHLPRC pDevHlpRC = NIL_RTRCPTR;
576 if (!HMIsEnabled(pVM))
577 {
578 rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDevHlp", &pDevHlpRC);
579 AssertReleaseMsgRC(rc, ("rc=%Rrc when resolving g_pdmRCDevHlp\n", rc));
580 }
581
582 PCPDMDRVHLPRC pDrvHlpRC = NIL_RTRCPTR;
583 if (!HMIsEnabled(pVM))
584 {
585 rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDevHlp", &pDrvHlpRC);
586 AssertReleaseMsgRC(rc, ("rc=%Rrc when resolving g_pdmRCDevHlp\n", rc));
587 }
588
589 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
590 {
591 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_RC)
592 {
593 pDevIns->pHlpRC = pDevHlpRC;
594 pDevIns->pvInstanceDataRC = MMHyperR3ToRC(pVM, pDevIns->pvInstanceDataR3);
595 if (pDevIns->pCritSectRoR3)
596 pDevIns->pCritSectRoRC = MMHyperR3ToRC(pVM, pDevIns->pCritSectRoR3);
597 pDevIns->Internal.s.pVMRC = pVM->pVMRC;
598
599 PPDMPCIDEV pPciDev = pDevIns->Internal.s.pHeadPciDevR3;
600 if (pPciDev)
601 {
602 pDevIns->Internal.s.pHeadPciDevRC = MMHyperR3ToRC(pVM, pPciDev);
603 do
604 {
605 pPciDev->Int.s.pDevInsRC = MMHyperR3ToRC(pVM, pPciDev->Int.s.pDevInsR3);
606 pPciDev->Int.s.pPdmBusRC = MMHyperR3ToRC(pVM, pPciDev->Int.s.pPdmBusR3);
607 if (pPciDev->Int.s.pNextR3)
608 pPciDev->Int.s.pNextRC = MMHyperR3ToRC(pVM, pPciDev->Int.s.pNextR3);
609 pPciDev = pPciDev->Int.s.pNextR3;
610 } while (pPciDev);
611 }
612
613 if (pDevIns->pReg->pfnRelocate)
614 {
615 LogFlow(("PDMR3Relocate: Relocating device '%s'/%d\n",
616 pDevIns->pReg->szName, pDevIns->iInstance));
617 pDevIns->pReg->pfnRelocate(pDevIns, offDelta);
618 }
619 }
620
621 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
622 {
623 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
624 {
625 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_RC)
626 {
627 pDrvIns->pHlpRC = pDrvHlpRC;
628 pDrvIns->pvInstanceDataRC = MMHyperR3ToRC(pVM, pDrvIns->pvInstanceDataR3);
629 pDrvIns->Internal.s.pVMRC = pVM->pVMRC;
630 if (pDrvIns->pReg->pfnRelocate)
631 {
632 LogFlow(("PDMR3Relocate: Relocating driver '%s'/%u attached to '%s'/%d/%u\n",
633 pDrvIns->pReg->szName, pDrvIns->iInstance,
634 pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun));
635 pDrvIns->pReg->pfnRelocate(pDrvIns, offDelta);
636 }
637 }
638 }
639 }
640
641 }
642}
643
644
645/**
646 * Worker for pdmR3Term that terminates a LUN chain.
647 *
648 * @param pVM The cross context VM structure.
649 * @param pLun The head of the chain.
650 * @param pszDevice The name of the device (for logging).
651 * @param iInstance The device instance number (for logging).
652 */
653static void pdmR3TermLuns(PVM pVM, PPDMLUN pLun, const char *pszDevice, unsigned iInstance)
654{
655 RT_NOREF2(pszDevice, iInstance);
656
657 for (; pLun; pLun = pLun->pNext)
658 {
659 /*
660 * Destroy them one at a time from the bottom up.
661 * (The serial device/drivers depends on this - bad.)
662 */
663 PPDMDRVINS pDrvIns = pLun->pBottom;
664 pLun->pBottom = pLun->pTop = NULL;
665 while (pDrvIns)
666 {
667 PPDMDRVINS pDrvNext = pDrvIns->Internal.s.pUp;
668
669 if (pDrvIns->pReg->pfnDestruct)
670 {
671 LogFlow(("pdmR3DevTerm: Destroying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
672 pDrvIns->pReg->szName, pDrvIns->iInstance, pLun->iLun, pszDevice, iInstance));
673 pDrvIns->pReg->pfnDestruct(pDrvIns);
674 }
675 pDrvIns->Internal.s.pDrv->cInstances--;
676
677 /* Order of resource freeing like in pdmR3DrvDestroyChain, but
678 * not all need to be done as they are done globally later. */
679 //PDMR3QueueDestroyDriver(pVM, pDrvIns);
680 TMR3TimerDestroyDriver(pVM, pDrvIns);
681 SSMR3DeregisterDriver(pVM, pDrvIns, NULL, 0);
682 //pdmR3ThreadDestroyDriver(pVM, pDrvIns);
683 //DBGFR3InfoDeregisterDriver(pVM, pDrvIns, NULL);
684 //pdmR3CritSectBothDeleteDriver(pVM, pDrvIns);
685 //PDMR3BlkCacheReleaseDriver(pVM, pDrvIns);
686#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
687 //pdmR3AsyncCompletionTemplateDestroyDriver(pVM, pDrvIns);
688#endif
689
690 /* Clear the driver struture to catch sloppy code. */
691 ASMMemFill32(pDrvIns, RT_OFFSETOF(PDMDRVINS, achInstanceData[pDrvIns->pReg->cbInstance]), 0xdeadd0d0);
692
693 pDrvIns = pDrvNext;
694 }
695 }
696}
697
698
699/**
700 * Terminates the PDM.
701 *
702 * Termination means cleaning up and freeing all resources,
703 * the VM it self is at this point powered off or suspended.
704 *
705 * @returns VBox status code.
706 * @param pVM The cross context VM structure.
707 */
708VMMR3_INT_DECL(int) PDMR3Term(PVM pVM)
709{
710 LogFlow(("PDMR3Term:\n"));
711 AssertMsg(PDMCritSectIsInitialized(&pVM->pdm.s.CritSect), ("bad init order!\n"));
712
713 /*
714 * Iterate the device instances and attach drivers, doing
715 * relevant destruction processing.
716 *
717 * N.B. There is no need to mess around freeing memory allocated
718 * from any MM heap since MM will do that in its Term function.
719 */
720 /* usb ones first. */
721 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
722 {
723 pdmR3TermLuns(pVM, pUsbIns->Internal.s.pLuns, pUsbIns->pReg->szName, pUsbIns->iInstance);
724
725 /*
726 * Detach it from the HUB (if it's actually attached to one) so the HUB has
727 * a chance to stop accessing any data.
728 */
729 PPDMUSBHUB pHub = pUsbIns->Internal.s.pHub;
730 if (pHub)
731 {
732 int rc = pHub->Reg.pfnDetachDevice(pHub->pDrvIns, pUsbIns, pUsbIns->Internal.s.iPort);
733 if (RT_FAILURE(rc))
734 {
735 LogRel(("PDM: Failed to detach USB device '%s' instance %d from %p: %Rrc\n",
736 pUsbIns->pReg->szName, pUsbIns->iInstance, pHub, rc));
737 }
738 else
739 {
740 pHub->cAvailablePorts++;
741 Assert(pHub->cAvailablePorts > 0 && pHub->cAvailablePorts <= pHub->cPorts);
742 pUsbIns->Internal.s.pHub = NULL;
743 }
744 }
745
746 if (pUsbIns->pReg->pfnDestruct)
747 {
748 LogFlow(("pdmR3DevTerm: Destroying - device '%s'/%d\n",
749 pUsbIns->pReg->szName, pUsbIns->iInstance));
750 pUsbIns->pReg->pfnDestruct(pUsbIns);
751 }
752
753 //TMR3TimerDestroyUsb(pVM, pUsbIns);
754 //SSMR3DeregisterUsb(pVM, pUsbIns, NULL, 0);
755 pdmR3ThreadDestroyUsb(pVM, pUsbIns);
756 }
757
758 /* then the 'normal' ones. */
759 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
760 {
761 pdmR3TermLuns(pVM, pDevIns->Internal.s.pLunsR3, pDevIns->pReg->szName, pDevIns->iInstance);
762
763 if (pDevIns->pReg->pfnDestruct)
764 {
765 LogFlow(("pdmR3DevTerm: Destroying - device '%s'/%d\n",
766 pDevIns->pReg->szName, pDevIns->iInstance));
767 pDevIns->pReg->pfnDestruct(pDevIns);
768 }
769
770 TMR3TimerDestroyDevice(pVM, pDevIns);
771 SSMR3DeregisterDevice(pVM, pDevIns, NULL, 0);
772 pdmR3CritSectBothDeleteDevice(pVM, pDevIns);
773 pdmR3ThreadDestroyDevice(pVM, pDevIns);
774 PDMR3QueueDestroyDevice(pVM, pDevIns);
775 PGMR3PhysMMIOExDeregister(pVM, pDevIns, UINT32_MAX, UINT32_MAX);
776#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
777 pdmR3AsyncCompletionTemplateDestroyDevice(pVM, pDevIns);
778#endif
779 DBGFR3InfoDeregisterDevice(pVM, pDevIns, NULL);
780 }
781
782 /*
783 * Destroy all threads.
784 */
785 pdmR3ThreadDestroyAll(pVM);
786
787 /*
788 * Destroy the block cache.
789 */
790 pdmR3BlkCacheTerm(pVM);
791
792#ifdef VBOX_WITH_NETSHAPER
793 /*
794 * Destroy network bandwidth groups.
795 */
796 pdmR3NetShaperTerm(pVM);
797#endif
798#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
799 /*
800 * Free async completion managers.
801 */
802 pdmR3AsyncCompletionTerm(pVM);
803#endif
804
805 /*
806 * Free modules.
807 */
808 pdmR3LdrTermU(pVM->pUVM);
809
810 /*
811 * Destroy the PDM lock.
812 */
813 PDMR3CritSectDelete(&pVM->pdm.s.CritSect);
814 /* The MiscCritSect is deleted by PDMR3CritSectBothTerm later. */
815
816 LogFlow(("PDMR3Term: returns %Rrc\n", VINF_SUCCESS));
817 return VINF_SUCCESS;
818}
819
820
821/**
822 * Terminates the PDM part of the UVM.
823 *
824 * This will unload any modules left behind.
825 *
826 * @param pUVM Pointer to the user mode VM structure.
827 */
828VMMR3_INT_DECL(void) PDMR3TermUVM(PUVM pUVM)
829{
830 /*
831 * In the normal cause of events we will now call pdmR3LdrTermU for
832 * the second time. In the case of init failure however, this might
833 * the first time, which is why we do it.
834 */
835 pdmR3LdrTermU(pUVM);
836
837 Assert(pUVM->pdm.s.pCritSects == NULL);
838 Assert(pUVM->pdm.s.pRwCritSects == NULL);
839 RTCritSectDelete(&pUVM->pdm.s.ListCritSect);
840}
841
842
843/**
844 * Bits that are saved in pass 0 and in the final pass.
845 *
846 * @param pVM The cross context VM structure.
847 * @param pSSM The saved state handle.
848 */
849static void pdmR3SaveBoth(PVM pVM, PSSMHANDLE pSSM)
850{
851 /*
852 * Save the list of device instances so we can check that they're all still
853 * there when we load the state and that nothing new has been added.
854 */
855 uint32_t i = 0;
856 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3, i++)
857 {
858 SSMR3PutU32(pSSM, i);
859 SSMR3PutStrZ(pSSM, pDevIns->pReg->szName);
860 SSMR3PutU32(pSSM, pDevIns->iInstance);
861 }
862 SSMR3PutU32(pSSM, UINT32_MAX); /* terminator */
863}
864
865
866/**
867 * Live save.
868 *
869 * @returns VBox status code.
870 * @param pVM The cross context VM structure.
871 * @param pSSM The saved state handle.
872 * @param uPass The pass.
873 */
874static DECLCALLBACK(int) pdmR3LiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass)
875{
876 LogFlow(("pdmR3LiveExec:\n"));
877 AssertReturn(uPass == 0, VERR_SSM_UNEXPECTED_PASS);
878 pdmR3SaveBoth(pVM, pSSM);
879 return VINF_SSM_DONT_CALL_AGAIN;
880}
881
882
883/**
884 * Execute state save operation.
885 *
886 * @returns VBox status code.
887 * @param pVM The cross context VM structure.
888 * @param pSSM The saved state handle.
889 */
890static DECLCALLBACK(int) pdmR3SaveExec(PVM pVM, PSSMHANDLE pSSM)
891{
892 LogFlow(("pdmR3SaveExec:\n"));
893
894 /*
895 * Save interrupt and DMA states.
896 */
897 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
898 {
899 PVMCPU pVCpu = &pVM->aCpus[idCpu];
900 SSMR3PutU32(pSSM, VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC));
901 SSMR3PutU32(pSSM, VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC));
902 SSMR3PutU32(pSSM, VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI));
903 SSMR3PutU32(pSSM, VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_SMI));
904 }
905 SSMR3PutU32(pSSM, VM_FF_IS_SET(pVM, VM_FF_PDM_DMA));
906
907 pdmR3SaveBoth(pVM, pSSM);
908 return VINF_SUCCESS;
909}
910
911
912/**
913 * Prepare state load operation.
914 *
915 * This will dispatch pending operations and clear the FFs governed by PDM and its devices.
916 *
917 * @returns VBox status code.
918 * @param pVM The cross context VM structure.
919 * @param pSSM The SSM handle.
920 */
921static DECLCALLBACK(int) pdmR3LoadPrep(PVM pVM, PSSMHANDLE pSSM)
922{
923 LogFlow(("pdmR3LoadPrep: %s%s\n",
924 VM_FF_IS_SET(pVM, VM_FF_PDM_QUEUES) ? " VM_FF_PDM_QUEUES" : "",
925 VM_FF_IS_SET(pVM, VM_FF_PDM_DMA) ? " VM_FF_PDM_DMA" : ""));
926#ifdef LOG_ENABLED
927 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
928 {
929 PVMCPU pVCpu = &pVM->aCpus[idCpu];
930 LogFlow(("pdmR3LoadPrep: VCPU %u %s%s\n", idCpu,
931 VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC) ? " VMCPU_FF_INTERRUPT_APIC" : "",
932 VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC) ? " VMCPU_FF_INTERRUPT_PIC" : ""));
933 }
934#endif
935 NOREF(pSSM);
936
937 /*
938 * In case there is work pending that will raise an interrupt,
939 * start a DMA transfer, or release a lock. (unlikely)
940 */
941 if (VM_FF_IS_SET(pVM, VM_FF_PDM_QUEUES))
942 PDMR3QueueFlushAll(pVM);
943
944 /* Clear the FFs. */
945 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
946 {
947 PVMCPU pVCpu = &pVM->aCpus[idCpu];
948 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
949 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
950 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
951 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_SMI);
952 }
953 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
954
955 return VINF_SUCCESS;
956}
957
958
959/**
960 * Execute state load operation.
961 *
962 * @returns VBox status code.
963 * @param pVM The cross context VM structure.
964 * @param pSSM SSM operation handle.
965 * @param uVersion Data layout version.
966 * @param uPass The data pass.
967 */
968static DECLCALLBACK(int) pdmR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
969{
970 int rc;
971
972 LogFlow(("pdmR3LoadExec: uPass=%#x\n", uPass));
973
974 /*
975 * Validate version.
976 */
977 if ( uVersion != PDM_SAVED_STATE_VERSION
978 && uVersion != PDM_SAVED_STATE_VERSION_PRE_NMI_FF
979 && uVersion != PDM_SAVED_STATE_VERSION_PRE_PDM_AUDIO)
980 {
981 AssertMsgFailed(("Invalid version uVersion=%d!\n", uVersion));
982 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
983 }
984
985 if (uPass == SSM_PASS_FINAL)
986 {
987 /*
988 * Load the interrupt and DMA states.
989 */
990 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
991 {
992 PVMCPU pVCpu = &pVM->aCpus[idCpu];
993
994 /* APIC interrupt */
995 uint32_t fInterruptPending = 0;
996 rc = SSMR3GetU32(pSSM, &fInterruptPending);
997 if (RT_FAILURE(rc))
998 return rc;
999 if (fInterruptPending & ~1)
1000 {
1001 AssertMsgFailed(("fInterruptPending=%#x (APIC)\n", fInterruptPending));
1002 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1003 }
1004 AssertRelease(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC));
1005 if (fInterruptPending)
1006 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC);
1007
1008 /* PIC interrupt */
1009 fInterruptPending = 0;
1010 rc = SSMR3GetU32(pSSM, &fInterruptPending);
1011 if (RT_FAILURE(rc))
1012 return rc;
1013 if (fInterruptPending & ~1)
1014 {
1015 AssertMsgFailed(("fInterruptPending=%#x (PIC)\n", fInterruptPending));
1016 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1017 }
1018 AssertRelease(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC));
1019 if (fInterruptPending)
1020 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC);
1021
1022 if (uVersion > PDM_SAVED_STATE_VERSION_PRE_NMI_FF)
1023 {
1024 /* NMI interrupt */
1025 fInterruptPending = 0;
1026 rc = SSMR3GetU32(pSSM, &fInterruptPending);
1027 if (RT_FAILURE(rc))
1028 return rc;
1029 if (fInterruptPending & ~1)
1030 {
1031 AssertMsgFailed(("fInterruptPending=%#x (NMI)\n", fInterruptPending));
1032 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1033 }
1034 AssertRelease(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI));
1035 if (fInterruptPending)
1036 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI);
1037
1038 /* SMI interrupt */
1039 fInterruptPending = 0;
1040 rc = SSMR3GetU32(pSSM, &fInterruptPending);
1041 if (RT_FAILURE(rc))
1042 return rc;
1043 if (fInterruptPending & ~1)
1044 {
1045 AssertMsgFailed(("fInterruptPending=%#x (SMI)\n", fInterruptPending));
1046 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1047 }
1048 AssertRelease(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_SMI));
1049 if (fInterruptPending)
1050 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_SMI);
1051 }
1052 }
1053
1054 /* DMA pending */
1055 uint32_t fDMAPending = 0;
1056 rc = SSMR3GetU32(pSSM, &fDMAPending);
1057 if (RT_FAILURE(rc))
1058 return rc;
1059 if (fDMAPending & ~1)
1060 {
1061 AssertMsgFailed(("fDMAPending=%#x\n", fDMAPending));
1062 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1063 }
1064 if (fDMAPending)
1065 VM_FF_SET(pVM, VM_FF_PDM_DMA);
1066 Log(("pdmR3LoadExec: VM_FF_PDM_DMA=%RTbool\n", VM_FF_IS_SET(pVM, VM_FF_PDM_DMA)));
1067 }
1068
1069 /*
1070 * Load the list of devices and verify that they are all there.
1071 */
1072 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1073 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_FOUND;
1074
1075 for (uint32_t i = 0; ; i++)
1076 {
1077 /* Get the sequence number / terminator. */
1078 uint32_t u32Sep;
1079 rc = SSMR3GetU32(pSSM, &u32Sep);
1080 if (RT_FAILURE(rc))
1081 return rc;
1082 if (u32Sep == UINT32_MAX)
1083 break;
1084 if (u32Sep != i)
1085 AssertMsgFailedReturn(("Out of sequence. u32Sep=%#x i=%#x\n", u32Sep, i), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
1086
1087 /* Get the name and instance number. */
1088 char szName[RT_SIZEOFMEMB(PDMDEVREG, szName)];
1089 rc = SSMR3GetStrZ(pSSM, szName, sizeof(szName));
1090 if (RT_FAILURE(rc))
1091 return rc;
1092 uint32_t iInstance;
1093 rc = SSMR3GetU32(pSSM, &iInstance);
1094 if (RT_FAILURE(rc))
1095 return rc;
1096
1097 /* Try locate it. */
1098 PPDMDEVINS pDevIns;
1099 for (pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1100 if ( !RTStrCmp(szName, pDevIns->pReg->szName)
1101 && pDevIns->iInstance == iInstance)
1102 {
1103 AssertLogRelMsgReturn(!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_FOUND),
1104 ("%s/#%u\n", pDevIns->pReg->szName, pDevIns->iInstance),
1105 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
1106 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_FOUND;
1107 break;
1108 }
1109
1110 if (!pDevIns)
1111 {
1112 bool fSkip = false;
1113
1114 /* Skip the non-existing (deprecated) "AudioSniffer" device stored in the saved state. */
1115 if ( uVersion <= PDM_SAVED_STATE_VERSION_PRE_PDM_AUDIO
1116 && !RTStrCmp(szName, "AudioSniffer"))
1117 fSkip = true;
1118
1119 if (!fSkip)
1120 {
1121 LogRel(("Device '%s'/%d not found in current config\n", szName, iInstance));
1122 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
1123 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device '%s'/%d not found in current config"), szName, iInstance);
1124 }
1125 }
1126 }
1127
1128 /*
1129 * Check that no additional devices were configured.
1130 */
1131 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1132 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_FOUND))
1133 {
1134 LogRel(("Device '%s'/%d not found in the saved state\n", pDevIns->pReg->szName, pDevIns->iInstance));
1135 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
1136 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device '%s'/%d not found in the saved state"),
1137 pDevIns->pReg->szName, pDevIns->iInstance);
1138 }
1139
1140 return VINF_SUCCESS;
1141}
1142
1143
1144/**
1145 * Worker for PDMR3PowerOn that deals with one driver.
1146 *
1147 * @param pDrvIns The driver instance.
1148 * @param pszDevName The parent device name.
1149 * @param iDevInstance The parent device instance number.
1150 * @param iLun The parent LUN number.
1151 */
1152DECLINLINE(int) pdmR3PowerOnDrv(PPDMDRVINS pDrvIns, const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1153{
1154 Assert(pDrvIns->Internal.s.fVMSuspended);
1155 if (pDrvIns->pReg->pfnPowerOn)
1156 {
1157 LogFlow(("PDMR3PowerOn: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1158 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1159 int rc = VINF_SUCCESS; pDrvIns->pReg->pfnPowerOn(pDrvIns);
1160 if (RT_FAILURE(rc))
1161 {
1162 LogRel(("PDMR3PowerOn: Driver '%s'/%d on LUN#%d of device '%s'/%d -> %Rrc\n",
1163 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance, rc));
1164 return rc;
1165 }
1166 }
1167 pDrvIns->Internal.s.fVMSuspended = false;
1168 return VINF_SUCCESS;
1169}
1170
1171
1172/**
1173 * Worker for PDMR3PowerOn that deals with one USB device instance.
1174 *
1175 * @returns VBox status code.
1176 * @param pUsbIns The USB device instance.
1177 */
1178DECLINLINE(int) pdmR3PowerOnUsb(PPDMUSBINS pUsbIns)
1179{
1180 Assert(pUsbIns->Internal.s.fVMSuspended);
1181 if (pUsbIns->pReg->pfnVMPowerOn)
1182 {
1183 LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1184 int rc = VINF_SUCCESS; pUsbIns->pReg->pfnVMPowerOn(pUsbIns);
1185 if (RT_FAILURE(rc))
1186 {
1187 LogRel(("PDMR3PowerOn: Device '%s'/%d -> %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1188 return rc;
1189 }
1190 }
1191 pUsbIns->Internal.s.fVMSuspended = false;
1192 return VINF_SUCCESS;
1193}
1194
1195
1196/**
1197 * Worker for PDMR3PowerOn that deals with one device instance.
1198 *
1199 * @returns VBox status code.
1200 * @param pDevIns The device instance.
1201 */
1202DECLINLINE(int) pdmR3PowerOnDev(PPDMDEVINS pDevIns)
1203{
1204 Assert(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED);
1205 if (pDevIns->pReg->pfnPowerOn)
1206 {
1207 LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1208 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
1209 int rc = VINF_SUCCESS; pDevIns->pReg->pfnPowerOn(pDevIns);
1210 PDMCritSectLeave(pDevIns->pCritSectRoR3);
1211 if (RT_FAILURE(rc))
1212 {
1213 LogRel(("PDMR3PowerOn: Device '%s'/%d -> %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
1214 return rc;
1215 }
1216 }
1217 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1218 return VINF_SUCCESS;
1219}
1220
1221
1222/**
1223 * This function will notify all the devices and their
1224 * attached drivers about the VM now being powered on.
1225 *
1226 * @param pVM The cross context VM structure.
1227 */
1228VMMR3DECL(void) PDMR3PowerOn(PVM pVM)
1229{
1230 LogFlow(("PDMR3PowerOn:\n"));
1231
1232 /*
1233 * Iterate thru the device instances and USB device instances,
1234 * processing the drivers associated with those.
1235 */
1236 int rc = VINF_SUCCESS;
1237 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns && RT_SUCCESS(rc); pDevIns = pDevIns->Internal.s.pNextR3)
1238 {
1239 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1240 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1241 rc = pdmR3PowerOnDrv(pDrvIns, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun);
1242 if (RT_SUCCESS(rc))
1243 rc = pdmR3PowerOnDev(pDevIns);
1244 }
1245
1246#ifdef VBOX_WITH_USB
1247 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns && RT_SUCCESS(rc); pUsbIns = pUsbIns->Internal.s.pNext)
1248 {
1249 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1250 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1251 rc = pdmR3PowerOnDrv(pDrvIns, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun);
1252 if (RT_SUCCESS(rc))
1253 rc = pdmR3PowerOnUsb(pUsbIns);
1254 }
1255#endif
1256
1257#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
1258 pdmR3AsyncCompletionResume(pVM);
1259#endif
1260
1261 /*
1262 * Resume all threads.
1263 */
1264 if (RT_SUCCESS(rc))
1265 pdmR3ThreadResumeAll(pVM);
1266
1267 /*
1268 * On failure, clean up via PDMR3Suspend.
1269 */
1270 if (RT_FAILURE(rc))
1271 PDMR3Suspend(pVM);
1272
1273 LogFlow(("PDMR3PowerOn: returns %Rrc\n", rc));
1274 return /*rc*/;
1275}
1276
1277
1278/**
1279 * Initializes the asynchronous notifi stats structure.
1280 *
1281 * @param pThis The asynchronous notifification stats.
1282 * @param pszOp The name of the operation.
1283 */
1284static void pdmR3NotifyAsyncInit(PPDMNOTIFYASYNCSTATS pThis, const char *pszOp)
1285{
1286 pThis->uStartNsTs = RTTimeNanoTS();
1287 pThis->cNsElapsedNextLog = 0;
1288 pThis->cLoops = 0;
1289 pThis->cAsync = 0;
1290 pThis->pszOp = pszOp;
1291 pThis->offList = 0;
1292 pThis->szList[0] = '\0';
1293}
1294
1295
1296/**
1297 * Begin a new loop, prepares to gather new stats.
1298 *
1299 * @param pThis The asynchronous notifification stats.
1300 */
1301static void pdmR3NotifyAsyncBeginLoop(PPDMNOTIFYASYNCSTATS pThis)
1302{
1303 pThis->cLoops++;
1304 pThis->cAsync = 0;
1305 pThis->offList = 0;
1306 pThis->szList[0] = '\0';
1307}
1308
1309
1310/**
1311 * Records a device or USB device with a pending asynchronous notification.
1312 *
1313 * @param pThis The asynchronous notifification stats.
1314 * @param pszName The name of the thing.
1315 * @param iInstance The instance number.
1316 */
1317static void pdmR3NotifyAsyncAdd(PPDMNOTIFYASYNCSTATS pThis, const char *pszName, uint32_t iInstance)
1318{
1319 pThis->cAsync++;
1320 if (pThis->offList < sizeof(pThis->szList) - 4)
1321 pThis->offList += RTStrPrintf(&pThis->szList[pThis->offList], sizeof(pThis->szList) - pThis->offList,
1322 pThis->offList == 0 ? "%s/%u" : ", %s/%u",
1323 pszName, iInstance);
1324}
1325
1326
1327/**
1328 * Records the asynchronous completition of a reset, suspend or power off.
1329 *
1330 * @param pThis The asynchronous notifification stats.
1331 * @param pszDrvName The driver name.
1332 * @param iDrvInstance The driver instance number.
1333 * @param pszDevName The device or USB device name.
1334 * @param iDevInstance The device or USB device instance number.
1335 * @param iLun The LUN.
1336 */
1337static void pdmR3NotifyAsyncAddDrv(PPDMNOTIFYASYNCSTATS pThis, const char *pszDrvName, uint32_t iDrvInstance,
1338 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1339{
1340 pThis->cAsync++;
1341 if (pThis->offList < sizeof(pThis->szList) - 8)
1342 pThis->offList += RTStrPrintf(&pThis->szList[pThis->offList], sizeof(pThis->szList) - pThis->offList,
1343 pThis->offList == 0 ? "%s/%u/%u/%s/%u" : ", %s/%u/%u/%s/%u",
1344 pszDevName, iDevInstance, iLun, pszDrvName, iDrvInstance);
1345}
1346
1347
1348/**
1349 * Log the stats.
1350 *
1351 * @param pThis The asynchronous notifification stats.
1352 */
1353static void pdmR3NotifyAsyncLog(PPDMNOTIFYASYNCSTATS pThis)
1354{
1355 /*
1356 * Return if we shouldn't log at this point.
1357 * We log with an internval increasing from 0 sec to 60 sec.
1358 */
1359 if (!pThis->cAsync)
1360 return;
1361
1362 uint64_t cNsElapsed = RTTimeNanoTS() - pThis->uStartNsTs;
1363 if (cNsElapsed < pThis->cNsElapsedNextLog)
1364 return;
1365
1366 if (pThis->cNsElapsedNextLog == 0)
1367 pThis->cNsElapsedNextLog = RT_NS_1SEC;
1368 else if (pThis->cNsElapsedNextLog >= RT_NS_1MIN / 2)
1369 pThis->cNsElapsedNextLog = RT_NS_1MIN;
1370 else
1371 pThis->cNsElapsedNextLog *= 2;
1372
1373 /*
1374 * Do the logging.
1375 */
1376 LogRel(("%s: after %5llu ms, %u loops: %u async tasks - %s\n",
1377 pThis->pszOp, cNsElapsed / RT_NS_1MS, pThis->cLoops, pThis->cAsync, pThis->szList));
1378}
1379
1380
1381/**
1382 * Wait for events and process pending requests.
1383 *
1384 * @param pThis The asynchronous notifification stats.
1385 * @param pVM The cross context VM structure.
1386 */
1387static void pdmR3NotifyAsyncWaitAndProcessRequests(PPDMNOTIFYASYNCSTATS pThis, PVM pVM)
1388{
1389 VM_ASSERT_EMT0(pVM);
1390 int rc = VMR3AsyncPdmNotificationWaitU(&pVM->pUVM->aCpus[0]);
1391 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc - %s - %s\n", rc, pThis->pszOp, pThis->szList));
1392
1393 rc = VMR3ReqProcessU(pVM->pUVM, VMCPUID_ANY, true /*fPriorityOnly*/);
1394 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc - %s - %s\n", rc, pThis->pszOp, pThis->szList));
1395 rc = VMR3ReqProcessU(pVM->pUVM, 0/*idDstCpu*/, true /*fPriorityOnly*/);
1396 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc - %s - %s\n", rc, pThis->pszOp, pThis->szList));
1397}
1398
1399
1400/**
1401 * Worker for PDMR3Reset that deals with one driver.
1402 *
1403 * @param pDrvIns The driver instance.
1404 * @param pAsync The structure for recording asynchronous
1405 * notification tasks.
1406 * @param pszDevName The parent device name.
1407 * @param iDevInstance The parent device instance number.
1408 * @param iLun The parent LUN number.
1409 */
1410DECLINLINE(bool) pdmR3ResetDrv(PPDMDRVINS pDrvIns, PPDMNOTIFYASYNCSTATS pAsync,
1411 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1412{
1413 if (!pDrvIns->Internal.s.fVMReset)
1414 {
1415 pDrvIns->Internal.s.fVMReset = true;
1416 if (pDrvIns->pReg->pfnReset)
1417 {
1418 if (!pDrvIns->Internal.s.pfnAsyncNotify)
1419 {
1420 LogFlow(("PDMR3Reset: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1421 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1422 pDrvIns->pReg->pfnReset(pDrvIns);
1423 if (pDrvIns->Internal.s.pfnAsyncNotify)
1424 LogFlow(("PDMR3Reset: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1425 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1426 }
1427 else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
1428 {
1429 LogFlow(("PDMR3Reset: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1430 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1431 pDrvIns->Internal.s.pfnAsyncNotify = NULL;
1432 }
1433 if (pDrvIns->Internal.s.pfnAsyncNotify)
1434 {
1435 pDrvIns->Internal.s.fVMReset = false;
1436 pdmR3NotifyAsyncAddDrv(pAsync, pDrvIns->Internal.s.pDrv->pReg->szName, pDrvIns->iInstance,
1437 pszDevName, iDevInstance, iLun);
1438 return false;
1439 }
1440 }
1441 }
1442 return true;
1443}
1444
1445
1446/**
1447 * Worker for PDMR3Reset that deals with one USB device instance.
1448 *
1449 * @param pUsbIns The USB device instance.
1450 * @param pAsync The structure for recording asynchronous
1451 * notification tasks.
1452 */
1453DECLINLINE(void) pdmR3ResetUsb(PPDMUSBINS pUsbIns, PPDMNOTIFYASYNCSTATS pAsync)
1454{
1455 if (!pUsbIns->Internal.s.fVMReset)
1456 {
1457 pUsbIns->Internal.s.fVMReset = true;
1458 if (pUsbIns->pReg->pfnVMReset)
1459 {
1460 if (!pUsbIns->Internal.s.pfnAsyncNotify)
1461 {
1462 LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1463 pUsbIns->pReg->pfnVMReset(pUsbIns);
1464 if (pUsbIns->Internal.s.pfnAsyncNotify)
1465 LogFlow(("PDMR3Reset: Async notification started - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1466 }
1467 else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
1468 {
1469 LogFlow(("PDMR3Reset: Async notification completed - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1470 pUsbIns->Internal.s.pfnAsyncNotify = NULL;
1471 }
1472 if (pUsbIns->Internal.s.pfnAsyncNotify)
1473 {
1474 pUsbIns->Internal.s.fVMReset = false;
1475 pdmR3NotifyAsyncAdd(pAsync, pUsbIns->Internal.s.pUsbDev->pReg->szName, pUsbIns->iInstance);
1476 }
1477 }
1478 }
1479}
1480
1481
1482/**
1483 * Worker for PDMR3Reset that deals with one device instance.
1484 *
1485 * @param pDevIns The device instance.
1486 * @param pAsync The structure for recording asynchronous
1487 * notification tasks.
1488 */
1489DECLINLINE(void) pdmR3ResetDev(PPDMDEVINS pDevIns, PPDMNOTIFYASYNCSTATS pAsync)
1490{
1491 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_RESET))
1492 {
1493 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_RESET;
1494 if (pDevIns->pReg->pfnReset)
1495 {
1496 uint64_t cNsElapsed = RTTimeNanoTS();
1497 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
1498
1499 if (!pDevIns->Internal.s.pfnAsyncNotify)
1500 {
1501 LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1502 pDevIns->pReg->pfnReset(pDevIns);
1503 if (pDevIns->Internal.s.pfnAsyncNotify)
1504 LogFlow(("PDMR3Reset: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1505 }
1506 else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
1507 {
1508 LogFlow(("PDMR3Reset: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1509 pDevIns->Internal.s.pfnAsyncNotify = NULL;
1510 }
1511 if (pDevIns->Internal.s.pfnAsyncNotify)
1512 {
1513 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_RESET;
1514 pdmR3NotifyAsyncAdd(pAsync, pDevIns->Internal.s.pDevR3->pReg->szName, pDevIns->iInstance);
1515 }
1516
1517 PDMCritSectLeave(pDevIns->pCritSectRoR3);
1518 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1519 if (cNsElapsed >= PDMSUSPEND_WARN_AT_NS)
1520 LogRel(("PDMR3Reset: Device '%s'/%d took %'llu ns to reset\n",
1521 pDevIns->pReg->szName, pDevIns->iInstance, cNsElapsed));
1522 }
1523 }
1524}
1525
1526
1527/**
1528 * Resets a virtual CPU.
1529 *
1530 * Used by PDMR3Reset and CPU hot plugging.
1531 *
1532 * @param pVCpu The cross context virtual CPU structure.
1533 */
1534VMMR3_INT_DECL(void) PDMR3ResetCpu(PVMCPU pVCpu)
1535{
1536 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
1537 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
1538 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
1539 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_SMI);
1540}
1541
1542
1543/**
1544 * This function will notify all the devices and their attached drivers about
1545 * the VM now being reset.
1546 *
1547 * @param pVM The cross context VM structure.
1548 */
1549VMMR3_INT_DECL(void) PDMR3Reset(PVM pVM)
1550{
1551 LogFlow(("PDMR3Reset:\n"));
1552
1553 /*
1554 * Clear all the reset flags.
1555 */
1556 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1557 {
1558 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_RESET;
1559 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1560 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1561 pDrvIns->Internal.s.fVMReset = false;
1562 }
1563#ifdef VBOX_WITH_USB
1564 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1565 {
1566 pUsbIns->Internal.s.fVMReset = false;
1567 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1568 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1569 pDrvIns->Internal.s.fVMReset = false;
1570 }
1571#endif
1572
1573 /*
1574 * The outer loop repeats until there are no more async requests.
1575 */
1576 PDMNOTIFYASYNCSTATS Async;
1577 pdmR3NotifyAsyncInit(&Async, "PDMR3Reset");
1578 for (;;)
1579 {
1580 pdmR3NotifyAsyncBeginLoop(&Async);
1581
1582 /*
1583 * Iterate thru the device instances and USB device instances,
1584 * processing the drivers associated with those.
1585 */
1586 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1587 {
1588 unsigned const cAsyncStart = Async.cAsync;
1589
1590 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_RESET_NOTIFICATION)
1591 pdmR3ResetDev(pDevIns, &Async);
1592
1593 if (Async.cAsync == cAsyncStart)
1594 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1595 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1596 if (!pdmR3ResetDrv(pDrvIns, &Async, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
1597 break;
1598
1599 if ( Async.cAsync == cAsyncStart
1600 && !(pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_RESET_NOTIFICATION))
1601 pdmR3ResetDev(pDevIns, &Async);
1602 }
1603
1604#ifdef VBOX_WITH_USB
1605 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1606 {
1607 unsigned const cAsyncStart = Async.cAsync;
1608
1609 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1610 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1611 if (!pdmR3ResetDrv(pDrvIns, &Async, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
1612 break;
1613
1614 if (Async.cAsync == cAsyncStart)
1615 pdmR3ResetUsb(pUsbIns, &Async);
1616 }
1617#endif
1618 if (!Async.cAsync)
1619 break;
1620 pdmR3NotifyAsyncLog(&Async);
1621 pdmR3NotifyAsyncWaitAndProcessRequests(&Async, pVM);
1622 }
1623
1624 /*
1625 * Clear all pending interrupts and DMA operations.
1626 */
1627 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1628 PDMR3ResetCpu(&pVM->aCpus[idCpu]);
1629 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
1630
1631 LogFlow(("PDMR3Reset: returns void\n"));
1632}
1633
1634
1635/**
1636 * This function will tell all the devices to setup up their memory structures
1637 * after VM construction and after VM reset.
1638 *
1639 * @param pVM The cross context VM structure.
1640 * @param fAtReset Indicates the context, after reset if @c true or after
1641 * construction if @c false.
1642 */
1643VMMR3_INT_DECL(void) PDMR3MemSetup(PVM pVM, bool fAtReset)
1644{
1645 LogFlow(("PDMR3MemSetup: fAtReset=%RTbool\n", fAtReset));
1646 PDMDEVMEMSETUPCTX const enmCtx = fAtReset ? PDMDEVMEMSETUPCTX_AFTER_RESET : PDMDEVMEMSETUPCTX_AFTER_CONSTRUCTION;
1647
1648 /*
1649 * Iterate thru the device instances and work the callback.
1650 */
1651 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1652 if (pDevIns->pReg->pfnMemSetup)
1653 {
1654 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
1655 pDevIns->pReg->pfnMemSetup(pDevIns, enmCtx);
1656 PDMCritSectLeave(pDevIns->pCritSectRoR3);
1657 }
1658
1659 LogFlow(("PDMR3MemSetup: returns void\n"));
1660}
1661
1662
1663/**
1664 * Retrieves and resets the info left behind by PDMDevHlpVMReset.
1665 *
1666 * @returns True if hard reset, false if soft reset.
1667 * @param pVM The cross context VM structure.
1668 * @param fOverride If non-zero, the override flags will be used instead
1669 * of the reset flags kept by PDM. (For triple faults.)
1670 * @param pfResetFlags Where to return the reset flags (PDMVMRESET_F_XXX).
1671 * @thread EMT
1672 */
1673VMMR3_INT_DECL(bool) PDMR3GetResetInfo(PVM pVM, uint32_t fOverride, uint32_t *pfResetFlags)
1674{
1675 VM_ASSERT_EMT(pVM);
1676
1677 /*
1678 * Get the reset flags.
1679 */
1680 uint32_t fResetFlags;
1681 fResetFlags = ASMAtomicXchgU32(&pVM->pdm.s.fResetFlags, 0);
1682 if (fOverride)
1683 fResetFlags = fOverride;
1684 *pfResetFlags = fResetFlags;
1685
1686 /*
1687 * To try avoid trouble, we never ever do soft/warm resets on SMP systems
1688 * with more than CPU #0 active. However, if only one CPU is active we
1689 * will ask the firmware what it wants us to do (because the firmware may
1690 * depend on the VMM doing a lot of what is normally its responsibility,
1691 * like clearing memory).
1692 */
1693 bool fOtherCpusActive = false;
1694 VMCPUID iCpu = pVM->cCpus;
1695 while (iCpu-- > 1)
1696 {
1697 EMSTATE enmState = EMGetState(&pVM->aCpus[iCpu]);
1698 if ( enmState != EMSTATE_WAIT_SIPI
1699 && enmState != EMSTATE_NONE)
1700 {
1701 fOtherCpusActive = true;
1702 break;
1703 }
1704 }
1705
1706 bool fHardReset = fOtherCpusActive
1707 || (fResetFlags & PDMVMRESET_F_SRC_MASK) < PDMVMRESET_F_LAST_ALWAYS_HARD
1708 || !pVM->pdm.s.pFirmware
1709 || pVM->pdm.s.pFirmware->Reg.pfnIsHardReset(pVM->pdm.s.pFirmware->pDevIns, fResetFlags);
1710
1711 Log(("PDMR3GetResetInfo: returns fHardReset=%RTbool fResetFlags=%#x\n", fHardReset, fResetFlags));
1712 return fHardReset;
1713}
1714
1715
1716/**
1717 * Performs a soft reset of devices.
1718 *
1719 * @param pVM The cross context VM structure.
1720 * @param fResetFlags PDMVMRESET_F_XXX.
1721 */
1722VMMR3_INT_DECL(void) PDMR3SoftReset(PVM pVM, uint32_t fResetFlags)
1723{
1724 LogFlow(("PDMR3SoftReset: fResetFlags=%#x\n", fResetFlags));
1725
1726 /*
1727 * Iterate thru the device instances and work the callback.
1728 */
1729 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1730 if (pDevIns->pReg->pfnSoftReset)
1731 {
1732 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
1733 pDevIns->pReg->pfnSoftReset(pDevIns, fResetFlags);
1734 PDMCritSectLeave(pDevIns->pCritSectRoR3);
1735 }
1736
1737 LogFlow(("PDMR3SoftReset: returns void\n"));
1738}
1739
1740
1741/**
1742 * Worker for PDMR3Suspend that deals with one driver.
1743 *
1744 * @param pDrvIns The driver instance.
1745 * @param pAsync The structure for recording asynchronous
1746 * notification tasks.
1747 * @param pszDevName The parent device name.
1748 * @param iDevInstance The parent device instance number.
1749 * @param iLun The parent LUN number.
1750 */
1751DECLINLINE(bool) pdmR3SuspendDrv(PPDMDRVINS pDrvIns, PPDMNOTIFYASYNCSTATS pAsync,
1752 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1753{
1754 if (!pDrvIns->Internal.s.fVMSuspended)
1755 {
1756 pDrvIns->Internal.s.fVMSuspended = true;
1757 if (pDrvIns->pReg->pfnSuspend)
1758 {
1759 uint64_t cNsElapsed = RTTimeNanoTS();
1760
1761 if (!pDrvIns->Internal.s.pfnAsyncNotify)
1762 {
1763 LogFlow(("PDMR3Suspend: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1764 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1765 pDrvIns->pReg->pfnSuspend(pDrvIns);
1766 if (pDrvIns->Internal.s.pfnAsyncNotify)
1767 LogFlow(("PDMR3Suspend: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1768 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1769 }
1770 else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
1771 {
1772 LogFlow(("PDMR3Suspend: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1773 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1774 pDrvIns->Internal.s.pfnAsyncNotify = NULL;
1775 }
1776
1777 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1778 if (cNsElapsed >= PDMSUSPEND_WARN_AT_NS)
1779 LogRel(("PDMR3Suspend: Driver '%s'/%d on LUN#%d of device '%s'/%d took %'llu ns to suspend\n",
1780 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance, cNsElapsed));
1781
1782 if (pDrvIns->Internal.s.pfnAsyncNotify)
1783 {
1784 pDrvIns->Internal.s.fVMSuspended = false;
1785 pdmR3NotifyAsyncAddDrv(pAsync, pDrvIns->Internal.s.pDrv->pReg->szName, pDrvIns->iInstance, pszDevName, iDevInstance, iLun);
1786 return false;
1787 }
1788 }
1789 }
1790 return true;
1791}
1792
1793
1794/**
1795 * Worker for PDMR3Suspend that deals with one USB device instance.
1796 *
1797 * @param pUsbIns The USB device instance.
1798 * @param pAsync The structure for recording asynchronous
1799 * notification tasks.
1800 */
1801DECLINLINE(void) pdmR3SuspendUsb(PPDMUSBINS pUsbIns, PPDMNOTIFYASYNCSTATS pAsync)
1802{
1803 if (!pUsbIns->Internal.s.fVMSuspended)
1804 {
1805 pUsbIns->Internal.s.fVMSuspended = true;
1806 if (pUsbIns->pReg->pfnVMSuspend)
1807 {
1808 uint64_t cNsElapsed = RTTimeNanoTS();
1809
1810 if (!pUsbIns->Internal.s.pfnAsyncNotify)
1811 {
1812 LogFlow(("PDMR3Suspend: Notifying - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1813 pUsbIns->pReg->pfnVMSuspend(pUsbIns);
1814 if (pUsbIns->Internal.s.pfnAsyncNotify)
1815 LogFlow(("PDMR3Suspend: Async notification started - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1816 }
1817 else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
1818 {
1819 LogFlow(("PDMR3Suspend: Async notification completed - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1820 pUsbIns->Internal.s.pfnAsyncNotify = NULL;
1821 }
1822 if (pUsbIns->Internal.s.pfnAsyncNotify)
1823 {
1824 pUsbIns->Internal.s.fVMSuspended = false;
1825 pdmR3NotifyAsyncAdd(pAsync, pUsbIns->Internal.s.pUsbDev->pReg->szName, pUsbIns->iInstance);
1826 }
1827
1828 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1829 if (cNsElapsed >= PDMSUSPEND_WARN_AT_NS)
1830 LogRel(("PDMR3Suspend: USB device '%s'/%d took %'llu ns to suspend\n",
1831 pUsbIns->pReg->szName, pUsbIns->iInstance, cNsElapsed));
1832 }
1833 }
1834}
1835
1836
1837/**
1838 * Worker for PDMR3Suspend that deals with one device instance.
1839 *
1840 * @param pDevIns The device instance.
1841 * @param pAsync The structure for recording asynchronous
1842 * notification tasks.
1843 */
1844DECLINLINE(void) pdmR3SuspendDev(PPDMDEVINS pDevIns, PPDMNOTIFYASYNCSTATS pAsync)
1845{
1846 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED))
1847 {
1848 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_SUSPENDED;
1849 if (pDevIns->pReg->pfnSuspend)
1850 {
1851 uint64_t cNsElapsed = RTTimeNanoTS();
1852 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
1853
1854 if (!pDevIns->Internal.s.pfnAsyncNotify)
1855 {
1856 LogFlow(("PDMR3Suspend: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1857 pDevIns->pReg->pfnSuspend(pDevIns);
1858 if (pDevIns->Internal.s.pfnAsyncNotify)
1859 LogFlow(("PDMR3Suspend: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1860 }
1861 else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
1862 {
1863 LogFlow(("PDMR3Suspend: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1864 pDevIns->Internal.s.pfnAsyncNotify = NULL;
1865 }
1866 if (pDevIns->Internal.s.pfnAsyncNotify)
1867 {
1868 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1869 pdmR3NotifyAsyncAdd(pAsync, pDevIns->Internal.s.pDevR3->pReg->szName, pDevIns->iInstance);
1870 }
1871
1872 PDMCritSectLeave(pDevIns->pCritSectRoR3);
1873 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1874 if (cNsElapsed >= PDMSUSPEND_WARN_AT_NS)
1875 LogRel(("PDMR3Suspend: Device '%s'/%d took %'llu ns to suspend\n",
1876 pDevIns->pReg->szName, pDevIns->iInstance, cNsElapsed));
1877 }
1878 }
1879}
1880
1881
1882/**
1883 * This function will notify all the devices and their attached drivers about
1884 * the VM now being suspended.
1885 *
1886 * @param pVM The cross context VM structure.
1887 * @thread EMT(0)
1888 */
1889VMMR3_INT_DECL(void) PDMR3Suspend(PVM pVM)
1890{
1891 LogFlow(("PDMR3Suspend:\n"));
1892 VM_ASSERT_EMT0(pVM);
1893 uint64_t cNsElapsed = RTTimeNanoTS();
1894
1895 /*
1896 * The outer loop repeats until there are no more async requests.
1897 *
1898 * Note! We depend on the suspended indicators to be in the desired state
1899 * and we do not reset them before starting because this allows
1900 * PDMR3PowerOn and PDMR3Resume to use PDMR3Suspend for cleaning up
1901 * on failure.
1902 */
1903 PDMNOTIFYASYNCSTATS Async;
1904 pdmR3NotifyAsyncInit(&Async, "PDMR3Suspend");
1905 for (;;)
1906 {
1907 pdmR3NotifyAsyncBeginLoop(&Async);
1908
1909 /*
1910 * Iterate thru the device instances and USB device instances,
1911 * processing the drivers associated with those.
1912 *
1913 * The attached drivers are normally processed first. Some devices
1914 * (like DevAHCI) though needs to be notified before the drivers so
1915 * that it doesn't kick off any new requests after the drivers stopped
1916 * taking any. (DrvVD changes to read-only in this particular case.)
1917 */
1918 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1919 {
1920 unsigned const cAsyncStart = Async.cAsync;
1921
1922 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION)
1923 pdmR3SuspendDev(pDevIns, &Async);
1924
1925 if (Async.cAsync == cAsyncStart)
1926 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1927 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1928 if (!pdmR3SuspendDrv(pDrvIns, &Async, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
1929 break;
1930
1931 if ( Async.cAsync == cAsyncStart
1932 && !(pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION))
1933 pdmR3SuspendDev(pDevIns, &Async);
1934 }
1935
1936#ifdef VBOX_WITH_USB
1937 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1938 {
1939 unsigned const cAsyncStart = Async.cAsync;
1940
1941 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1942 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1943 if (!pdmR3SuspendDrv(pDrvIns, &Async, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
1944 break;
1945
1946 if (Async.cAsync == cAsyncStart)
1947 pdmR3SuspendUsb(pUsbIns, &Async);
1948 }
1949#endif
1950 if (!Async.cAsync)
1951 break;
1952 pdmR3NotifyAsyncLog(&Async);
1953 pdmR3NotifyAsyncWaitAndProcessRequests(&Async, pVM);
1954 }
1955
1956 /*
1957 * Suspend all threads.
1958 */
1959 pdmR3ThreadSuspendAll(pVM);
1960
1961 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1962 LogRel(("PDMR3Suspend: %'llu ns run time\n", cNsElapsed));
1963}
1964
1965
1966/**
1967 * Worker for PDMR3Resume that deals with one driver.
1968 *
1969 * @param pDrvIns The driver instance.
1970 * @param pszDevName The parent device name.
1971 * @param iDevInstance The parent device instance number.
1972 * @param iLun The parent LUN number.
1973 */
1974DECLINLINE(int) pdmR3ResumeDrv(PPDMDRVINS pDrvIns, const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1975{
1976 Assert(pDrvIns->Internal.s.fVMSuspended);
1977 if (pDrvIns->pReg->pfnResume)
1978 {
1979 LogFlow(("PDMR3Resume: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1980 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1981 int rc = VINF_SUCCESS; pDrvIns->pReg->pfnResume(pDrvIns);
1982 if (RT_FAILURE(rc))
1983 {
1984 LogRel(("PDMR3Resume: Driver '%s'/%d on LUN#%d of device '%s'/%d -> %Rrc\n",
1985 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance, rc));
1986 return rc;
1987 }
1988 }
1989 pDrvIns->Internal.s.fVMSuspended = false;
1990 return VINF_SUCCESS;
1991}
1992
1993
1994/**
1995 * Worker for PDMR3Resume that deals with one USB device instance.
1996 *
1997 * @returns VBox status code.
1998 * @param pUsbIns The USB device instance.
1999 */
2000DECLINLINE(int) pdmR3ResumeUsb(PPDMUSBINS pUsbIns)
2001{
2002 Assert(pUsbIns->Internal.s.fVMSuspended);
2003 if (pUsbIns->pReg->pfnVMResume)
2004 {
2005 LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
2006 int rc = VINF_SUCCESS; pUsbIns->pReg->pfnVMResume(pUsbIns);
2007 if (RT_FAILURE(rc))
2008 {
2009 LogRel(("PDMR3Resume: Device '%s'/%d -> %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
2010 return rc;
2011 }
2012 }
2013 pUsbIns->Internal.s.fVMSuspended = false;
2014 return VINF_SUCCESS;
2015}
2016
2017
2018/**
2019 * Worker for PDMR3Resume that deals with one device instance.
2020 *
2021 * @returns VBox status code.
2022 * @param pDevIns The device instance.
2023 */
2024DECLINLINE(int) pdmR3ResumeDev(PPDMDEVINS pDevIns)
2025{
2026 Assert(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED);
2027 if (pDevIns->pReg->pfnResume)
2028 {
2029 LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
2030 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
2031 int rc = VINF_SUCCESS; pDevIns->pReg->pfnResume(pDevIns);
2032 PDMCritSectLeave(pDevIns->pCritSectRoR3);
2033 if (RT_FAILURE(rc))
2034 {
2035 LogRel(("PDMR3Resume: Device '%s'/%d -> %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
2036 return rc;
2037 }
2038 }
2039 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
2040 return VINF_SUCCESS;
2041}
2042
2043
2044/**
2045 * This function will notify all the devices and their
2046 * attached drivers about the VM now being resumed.
2047 *
2048 * @param pVM The cross context VM structure.
2049 */
2050VMMR3_INT_DECL(void) PDMR3Resume(PVM pVM)
2051{
2052 LogFlow(("PDMR3Resume:\n"));
2053
2054 /*
2055 * Iterate thru the device instances and USB device instances,
2056 * processing the drivers associated with those.
2057 */
2058 int rc = VINF_SUCCESS;
2059 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns && RT_SUCCESS(rc); pDevIns = pDevIns->Internal.s.pNextR3)
2060 {
2061 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
2062 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
2063 rc = pdmR3ResumeDrv(pDrvIns, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun);
2064 if (RT_SUCCESS(rc))
2065 rc = pdmR3ResumeDev(pDevIns);
2066 }
2067
2068#ifdef VBOX_WITH_USB
2069 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns && RT_SUCCESS(rc); pUsbIns = pUsbIns->Internal.s.pNext)
2070 {
2071 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
2072 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
2073 rc = pdmR3ResumeDrv(pDrvIns, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun);
2074 if (RT_SUCCESS(rc))
2075 rc = pdmR3ResumeUsb(pUsbIns);
2076 }
2077#endif
2078
2079 /*
2080 * Resume all threads.
2081 */
2082 if (RT_SUCCESS(rc))
2083 pdmR3ThreadResumeAll(pVM);
2084
2085 /*
2086 * Resume the block cache.
2087 */
2088 if (RT_SUCCESS(rc))
2089 pdmR3BlkCacheResume(pVM);
2090
2091 /*
2092 * On failure, clean up via PDMR3Suspend.
2093 */
2094 if (RT_FAILURE(rc))
2095 PDMR3Suspend(pVM);
2096
2097 LogFlow(("PDMR3Resume: returns %Rrc\n", rc));
2098 return /*rc*/;
2099}
2100
2101
2102/**
2103 * Worker for PDMR3PowerOff that deals with one driver.
2104 *
2105 * @param pDrvIns The driver instance.
2106 * @param pAsync The structure for recording asynchronous
2107 * notification tasks.
2108 * @param pszDevName The parent device name.
2109 * @param iDevInstance The parent device instance number.
2110 * @param iLun The parent LUN number.
2111 */
2112DECLINLINE(bool) pdmR3PowerOffDrv(PPDMDRVINS pDrvIns, PPDMNOTIFYASYNCSTATS pAsync,
2113 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
2114{
2115 if (!pDrvIns->Internal.s.fVMSuspended)
2116 {
2117 pDrvIns->Internal.s.fVMSuspended = true;
2118 if (pDrvIns->pReg->pfnPowerOff)
2119 {
2120 uint64_t cNsElapsed = RTTimeNanoTS();
2121
2122 if (!pDrvIns->Internal.s.pfnAsyncNotify)
2123 {
2124 LogFlow(("PDMR3PowerOff: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
2125 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
2126 pDrvIns->pReg->pfnPowerOff(pDrvIns);
2127 if (pDrvIns->Internal.s.pfnAsyncNotify)
2128 LogFlow(("PDMR3PowerOff: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
2129 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
2130 }
2131 else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
2132 {
2133 LogFlow(("PDMR3PowerOff: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
2134 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
2135 pDrvIns->Internal.s.pfnAsyncNotify = NULL;
2136 }
2137
2138 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
2139 if (cNsElapsed >= PDMPOWEROFF_WARN_AT_NS)
2140 LogRel(("PDMR3PowerOff: Driver '%s'/%d on LUN#%d of device '%s'/%d took %'llu ns to power off\n",
2141 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance, cNsElapsed));
2142
2143 if (pDrvIns->Internal.s.pfnAsyncNotify)
2144 {
2145 pDrvIns->Internal.s.fVMSuspended = false;
2146 pdmR3NotifyAsyncAddDrv(pAsync, pDrvIns->Internal.s.pDrv->pReg->szName, pDrvIns->iInstance,
2147 pszDevName, iDevInstance, iLun);
2148 return false;
2149 }
2150 }
2151 }
2152 return true;
2153}
2154
2155
2156/**
2157 * Worker for PDMR3PowerOff that deals with one USB device instance.
2158 *
2159 * @param pUsbIns The USB device instance.
2160 * @param pAsync The structure for recording asynchronous
2161 * notification tasks.
2162 */
2163DECLINLINE(void) pdmR3PowerOffUsb(PPDMUSBINS pUsbIns, PPDMNOTIFYASYNCSTATS pAsync)
2164{
2165 if (!pUsbIns->Internal.s.fVMSuspended)
2166 {
2167 pUsbIns->Internal.s.fVMSuspended = true;
2168 if (pUsbIns->pReg->pfnVMPowerOff)
2169 {
2170 uint64_t cNsElapsed = RTTimeNanoTS();
2171
2172 if (!pUsbIns->Internal.s.pfnAsyncNotify)
2173 {
2174 LogFlow(("PDMR3PowerOff: Notifying - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
2175 pUsbIns->pReg->pfnVMPowerOff(pUsbIns);
2176 if (pUsbIns->Internal.s.pfnAsyncNotify)
2177 LogFlow(("PDMR3PowerOff: Async notification started - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
2178 }
2179 else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
2180 {
2181 LogFlow(("PDMR3PowerOff: Async notification completed - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
2182 pUsbIns->Internal.s.pfnAsyncNotify = NULL;
2183 }
2184 if (pUsbIns->Internal.s.pfnAsyncNotify)
2185 {
2186 pUsbIns->Internal.s.fVMSuspended = false;
2187 pdmR3NotifyAsyncAdd(pAsync, pUsbIns->Internal.s.pUsbDev->pReg->szName, pUsbIns->iInstance);
2188 }
2189
2190 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
2191 if (cNsElapsed >= PDMPOWEROFF_WARN_AT_NS)
2192 LogRel(("PDMR3PowerOff: USB device '%s'/%d took %'llu ns to power off\n",
2193 pUsbIns->pReg->szName, pUsbIns->iInstance, cNsElapsed));
2194
2195 }
2196 }
2197}
2198
2199
2200/**
2201 * Worker for PDMR3PowerOff that deals with one device instance.
2202 *
2203 * @param pDevIns The device instance.
2204 * @param pAsync The structure for recording asynchronous
2205 * notification tasks.
2206 */
2207DECLINLINE(void) pdmR3PowerOffDev(PPDMDEVINS pDevIns, PPDMNOTIFYASYNCSTATS pAsync)
2208{
2209 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED))
2210 {
2211 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_SUSPENDED;
2212 if (pDevIns->pReg->pfnPowerOff)
2213 {
2214 uint64_t cNsElapsed = RTTimeNanoTS();
2215 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
2216
2217 if (!pDevIns->Internal.s.pfnAsyncNotify)
2218 {
2219 LogFlow(("PDMR3PowerOff: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
2220 pDevIns->pReg->pfnPowerOff(pDevIns);
2221 if (pDevIns->Internal.s.pfnAsyncNotify)
2222 LogFlow(("PDMR3PowerOff: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
2223 }
2224 else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
2225 {
2226 LogFlow(("PDMR3PowerOff: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
2227 pDevIns->Internal.s.pfnAsyncNotify = NULL;
2228 }
2229 if (pDevIns->Internal.s.pfnAsyncNotify)
2230 {
2231 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
2232 pdmR3NotifyAsyncAdd(pAsync, pDevIns->Internal.s.pDevR3->pReg->szName, pDevIns->iInstance);
2233 }
2234
2235 PDMCritSectLeave(pDevIns->pCritSectRoR3);
2236 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
2237 if (cNsElapsed >= PDMPOWEROFF_WARN_AT_NS)
2238 LogFlow(("PDMR3PowerOff: Device '%s'/%d took %'llu ns to power off\n",
2239 pDevIns->pReg->szName, pDevIns->iInstance, cNsElapsed));
2240 }
2241 }
2242}
2243
2244
2245/**
2246 * This function will notify all the devices and their
2247 * attached drivers about the VM being powered off.
2248 *
2249 * @param pVM The cross context VM structure.
2250 */
2251VMMR3DECL(void) PDMR3PowerOff(PVM pVM)
2252{
2253 LogFlow(("PDMR3PowerOff:\n"));
2254 uint64_t cNsElapsed = RTTimeNanoTS();
2255
2256 /*
2257 * Clear the suspended flags on all devices and drivers first because they
2258 * might have been set during a suspend but the power off callbacks should
2259 * be called in any case.
2260 */
2261 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2262 {
2263 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
2264
2265 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
2266 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2267 pDrvIns->Internal.s.fVMSuspended = false;
2268 }
2269
2270#ifdef VBOX_WITH_USB
2271 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2272 {
2273 pUsbIns->Internal.s.fVMSuspended = false;
2274
2275 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
2276 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2277 pDrvIns->Internal.s.fVMSuspended = false;
2278 }
2279#endif
2280
2281 /*
2282 * The outer loop repeats until there are no more async requests.
2283 */
2284 PDMNOTIFYASYNCSTATS Async;
2285 pdmR3NotifyAsyncInit(&Async, "PDMR3PowerOff");
2286 for (;;)
2287 {
2288 pdmR3NotifyAsyncBeginLoop(&Async);
2289
2290 /*
2291 * Iterate thru the device instances and USB device instances,
2292 * processing the drivers associated with those.
2293 *
2294 * The attached drivers are normally processed first. Some devices
2295 * (like DevAHCI) though needs to be notified before the drivers so
2296 * that it doesn't kick off any new requests after the drivers stopped
2297 * taking any. (DrvVD changes to read-only in this particular case.)
2298 */
2299 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2300 {
2301 unsigned const cAsyncStart = Async.cAsync;
2302
2303 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION)
2304 pdmR3PowerOffDev(pDevIns, &Async);
2305
2306 if (Async.cAsync == cAsyncStart)
2307 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
2308 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2309 if (!pdmR3PowerOffDrv(pDrvIns, &Async, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
2310 break;
2311
2312 if ( Async.cAsync == cAsyncStart
2313 && !(pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION))
2314 pdmR3PowerOffDev(pDevIns, &Async);
2315 }
2316
2317#ifdef VBOX_WITH_USB
2318 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2319 {
2320 unsigned const cAsyncStart = Async.cAsync;
2321
2322 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
2323 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2324 if (!pdmR3PowerOffDrv(pDrvIns, &Async, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
2325 break;
2326
2327 if (Async.cAsync == cAsyncStart)
2328 pdmR3PowerOffUsb(pUsbIns, &Async);
2329 }
2330#endif
2331 if (!Async.cAsync)
2332 break;
2333 pdmR3NotifyAsyncLog(&Async);
2334 pdmR3NotifyAsyncWaitAndProcessRequests(&Async, pVM);
2335 }
2336
2337 /*
2338 * Suspend all threads.
2339 */
2340 pdmR3ThreadSuspendAll(pVM);
2341
2342 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
2343 LogRel(("PDMR3PowerOff: %'llu ns run time\n", cNsElapsed));
2344}
2345
2346
2347/**
2348 * Queries the base interface of a device instance.
2349 *
2350 * The caller can use this to query other interfaces the device implements
2351 * and use them to talk to the device.
2352 *
2353 * @returns VBox status code.
2354 * @param pUVM The user mode VM handle.
2355 * @param pszDevice Device name.
2356 * @param iInstance Device instance.
2357 * @param ppBase Where to store the pointer to the base device interface on success.
2358 * @remark We're not doing any locking ATM, so don't try call this at times when the
2359 * device chain is known to be updated.
2360 */
2361VMMR3DECL(int) PDMR3QueryDevice(PUVM pUVM, const char *pszDevice, unsigned iInstance, PPDMIBASE *ppBase)
2362{
2363 LogFlow(("PDMR3DeviceQuery: pszDevice=%p:{%s} iInstance=%u ppBase=%p\n", pszDevice, pszDevice, iInstance, ppBase));
2364 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
2365 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
2366
2367 /*
2368 * Iterate registered devices looking for the device.
2369 */
2370 size_t cchDevice = strlen(pszDevice);
2371 for (PPDMDEV pDev = pUVM->pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
2372 {
2373 if ( pDev->cchName == cchDevice
2374 && !memcmp(pDev->pReg->szName, pszDevice, cchDevice))
2375 {
2376 /*
2377 * Iterate device instances.
2378 */
2379 for (PPDMDEVINS pDevIns = pDev->pInstances; pDevIns; pDevIns = pDevIns->Internal.s.pPerDeviceNextR3)
2380 {
2381 if (pDevIns->iInstance == iInstance)
2382 {
2383 if (pDevIns->IBase.pfnQueryInterface)
2384 {
2385 *ppBase = &pDevIns->IBase;
2386 LogFlow(("PDMR3DeviceQuery: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
2387 return VINF_SUCCESS;
2388 }
2389
2390 LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NO_IBASE\n"));
2391 return VERR_PDM_DEVICE_INSTANCE_NO_IBASE;
2392 }
2393 }
2394
2395 LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NOT_FOUND\n"));
2396 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND;
2397 }
2398 }
2399
2400 LogFlow(("PDMR3QueryDevice: returns VERR_PDM_DEVICE_NOT_FOUND\n"));
2401 return VERR_PDM_DEVICE_NOT_FOUND;
2402}
2403
2404
2405/**
2406 * Queries the base interface of a device LUN.
2407 *
2408 * This differs from PDMR3QueryLun by that it returns the interface on the
2409 * device and not the top level driver.
2410 *
2411 * @returns VBox status code.
2412 * @param pUVM The user mode VM handle.
2413 * @param pszDevice Device name.
2414 * @param iInstance Device instance.
2415 * @param iLun The Logical Unit to obtain the interface of.
2416 * @param ppBase Where to store the base interface pointer.
2417 * @remark We're not doing any locking ATM, so don't try call this at times when the
2418 * device chain is known to be updated.
2419 */
2420VMMR3DECL(int) PDMR3QueryDeviceLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
2421{
2422 LogFlow(("PDMR3QueryDeviceLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
2423 pszDevice, pszDevice, iInstance, iLun, ppBase));
2424 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
2425 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
2426
2427 /*
2428 * Find the LUN.
2429 */
2430 PPDMLUN pLun;
2431 int rc = pdmR3DevFindLun(pUVM->pVM, pszDevice, iInstance, iLun, &pLun);
2432 if (RT_SUCCESS(rc))
2433 {
2434 *ppBase = pLun->pBase;
2435 LogFlow(("PDMR3QueryDeviceLun: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
2436 return VINF_SUCCESS;
2437 }
2438 LogFlow(("PDMR3QueryDeviceLun: returns %Rrc\n", rc));
2439 return rc;
2440}
2441
2442
2443/**
2444 * Query the interface of the top level driver on a LUN.
2445 *
2446 * @returns VBox status code.
2447 * @param pUVM The user mode VM handle.
2448 * @param pszDevice Device name.
2449 * @param iInstance Device instance.
2450 * @param iLun The Logical Unit to obtain the interface of.
2451 * @param ppBase Where to store the base interface pointer.
2452 * @remark We're not doing any locking ATM, so don't try call this at times when the
2453 * device chain is known to be updated.
2454 */
2455VMMR3DECL(int) PDMR3QueryLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
2456{
2457 LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
2458 pszDevice, pszDevice, iInstance, iLun, ppBase));
2459 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
2460 PVM pVM = pUVM->pVM;
2461 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
2462
2463 /*
2464 * Find the LUN.
2465 */
2466 PPDMLUN pLun;
2467 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
2468 if (RT_SUCCESS(rc))
2469 {
2470 if (pLun->pTop)
2471 {
2472 *ppBase = &pLun->pTop->IBase;
2473 LogFlow(("PDMR3QueryLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
2474 return VINF_SUCCESS;
2475 }
2476 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
2477 }
2478 LogFlow(("PDMR3QueryLun: returns %Rrc\n", rc));
2479 return rc;
2480}
2481
2482
2483/**
2484 * Query the interface of a named driver on a LUN.
2485 *
2486 * If the driver appears more than once in the driver chain, the first instance
2487 * is returned.
2488 *
2489 * @returns VBox status code.
2490 * @param pUVM The user mode VM handle.
2491 * @param pszDevice Device name.
2492 * @param iInstance Device instance.
2493 * @param iLun The Logical Unit to obtain the interface of.
2494 * @param pszDriver The driver name.
2495 * @param ppBase Where to store the base interface pointer.
2496 *
2497 * @remark We're not doing any locking ATM, so don't try call this at times when the
2498 * device chain is known to be updated.
2499 */
2500VMMR3DECL(int) PDMR3QueryDriverOnLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, const char *pszDriver, PPPDMIBASE ppBase)
2501{
2502 LogFlow(("PDMR3QueryDriverOnLun: pszDevice=%p:{%s} iInstance=%u iLun=%u pszDriver=%p:{%s} ppBase=%p\n",
2503 pszDevice, pszDevice, iInstance, iLun, pszDriver, pszDriver, ppBase));
2504 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
2505 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
2506
2507 /*
2508 * Find the LUN.
2509 */
2510 PPDMLUN pLun;
2511 int rc = pdmR3DevFindLun(pUVM->pVM, pszDevice, iInstance, iLun, &pLun);
2512 if (RT_SUCCESS(rc))
2513 {
2514 if (pLun->pTop)
2515 {
2516 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2517 if (!strcmp(pDrvIns->pReg->szName, pszDriver))
2518 {
2519 *ppBase = &pDrvIns->IBase;
2520 LogFlow(("PDMR3QueryDriverOnLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
2521 return VINF_SUCCESS;
2522
2523 }
2524 rc = VERR_PDM_DRIVER_NOT_FOUND;
2525 }
2526 else
2527 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
2528 }
2529 LogFlow(("PDMR3QueryDriverOnLun: returns %Rrc\n", rc));
2530 return rc;
2531}
2532
2533/**
2534 * Executes pending DMA transfers.
2535 * Forced Action handler.
2536 *
2537 * @param pVM The cross context VM structure.
2538 */
2539VMMR3DECL(void) PDMR3DmaRun(PVM pVM)
2540{
2541 /* Note! Not really SMP safe; restrict it to VCPU 0. */
2542 if (VMMGetCpuId(pVM) != 0)
2543 return;
2544
2545 if (VM_FF_TEST_AND_CLEAR(pVM, VM_FF_PDM_DMA))
2546 {
2547 if (pVM->pdm.s.pDmac)
2548 {
2549 bool fMore = pVM->pdm.s.pDmac->Reg.pfnRun(pVM->pdm.s.pDmac->pDevIns);
2550 if (fMore)
2551 VM_FF_SET(pVM, VM_FF_PDM_DMA);
2552 }
2553 }
2554}
2555
2556
2557/**
2558 * Service a VMMCALLRING3_PDM_LOCK call.
2559 *
2560 * @returns VBox status code.
2561 * @param pVM The cross context VM structure.
2562 */
2563VMMR3_INT_DECL(int) PDMR3LockCall(PVM pVM)
2564{
2565 return PDMR3CritSectEnterEx(&pVM->pdm.s.CritSect, true /* fHostCall */);
2566}
2567
2568
2569/**
2570 * Allocates memory from the VMM device heap.
2571 *
2572 * @returns VBox status code.
2573 * @param pVM The cross context VM structure.
2574 * @param cbSize Allocation size.
2575 * @param pfnNotify Mapping/unmapping notification callback.
2576 * @param ppv Ring-3 pointer. (out)
2577 */
2578VMMR3_INT_DECL(int) PDMR3VmmDevHeapAlloc(PVM pVM, size_t cbSize, PFNPDMVMMDEVHEAPNOTIFY pfnNotify, RTR3PTR *ppv)
2579{
2580#ifdef DEBUG_bird
2581 if (!cbSize || cbSize > pVM->pdm.s.cbVMMDevHeapLeft)
2582 return VERR_NO_MEMORY;
2583#else
2584 AssertReturn(cbSize && cbSize <= pVM->pdm.s.cbVMMDevHeapLeft, VERR_NO_MEMORY);
2585#endif
2586
2587 Log(("PDMR3VMMDevHeapAlloc: %#zx\n", cbSize));
2588
2589 /** @todo Not a real heap as there's currently only one user. */
2590 *ppv = pVM->pdm.s.pvVMMDevHeap;
2591 pVM->pdm.s.cbVMMDevHeapLeft = 0;
2592 pVM->pdm.s.pfnVMMDevHeapNotify = pfnNotify;
2593 return VINF_SUCCESS;
2594}
2595
2596
2597/**
2598 * Frees memory from the VMM device heap
2599 *
2600 * @returns VBox status code.
2601 * @param pVM The cross context VM structure.
2602 * @param pv Ring-3 pointer.
2603 */
2604VMMR3_INT_DECL(int) PDMR3VmmDevHeapFree(PVM pVM, RTR3PTR pv)
2605{
2606 Log(("PDMR3VmmDevHeapFree: %RHv\n", pv)); RT_NOREF_PV(pv);
2607
2608 /** @todo not a real heap as there's currently only one user. */
2609 pVM->pdm.s.cbVMMDevHeapLeft = pVM->pdm.s.cbVMMDevHeap;
2610 pVM->pdm.s.pfnVMMDevHeapNotify = NULL;
2611 return VINF_SUCCESS;
2612}
2613
2614
2615/**
2616 * Worker for DBGFR3TraceConfig that checks if the given tracing group name
2617 * matches a device or driver name and applies the tracing config change.
2618 *
2619 * @returns VINF_SUCCESS or VERR_NOT_FOUND.
2620 * @param pVM The cross context VM structure.
2621 * @param pszName The tracing config group name. This is NULL if
2622 * the operation applies to every device and
2623 * driver.
2624 * @param cchName The length to match.
2625 * @param fEnable Whether to enable or disable the corresponding
2626 * trace points.
2627 * @param fApply Whether to actually apply the changes or just do
2628 * existence checks.
2629 */
2630VMMR3_INT_DECL(int) PDMR3TracingConfig(PVM pVM, const char *pszName, size_t cchName, bool fEnable, bool fApply)
2631{
2632 /** @todo This code is potentially racing driver attaching and detaching. */
2633
2634 /*
2635 * Applies to all.
2636 */
2637 if (pszName == NULL)
2638 {
2639 AssertReturn(fApply, VINF_SUCCESS);
2640
2641 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2642 {
2643 pDevIns->fTracing = fEnable;
2644 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
2645 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2646 pDrvIns->fTracing = fEnable;
2647 }
2648
2649#ifdef VBOX_WITH_USB
2650 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2651 {
2652 pUsbIns->fTracing = fEnable;
2653 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
2654 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2655 pDrvIns->fTracing = fEnable;
2656
2657 }
2658#endif
2659 return VINF_SUCCESS;
2660 }
2661
2662 /*
2663 * Specific devices, USB devices or drivers.
2664 * Decode prefix to figure which of these it applies to.
2665 */
2666 if (cchName <= 3)
2667 return VERR_NOT_FOUND;
2668
2669 uint32_t cMatches = 0;
2670 if (!strncmp("dev", pszName, 3))
2671 {
2672 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2673 {
2674 const char *pszDevName = pDevIns->Internal.s.pDevR3->pReg->szName;
2675 size_t cchDevName = strlen(pszDevName);
2676 if ( ( cchDevName == cchName
2677 && RTStrNICmp(pszName, pszDevName, cchDevName))
2678 || ( cchDevName == cchName - 3
2679 && RTStrNICmp(pszName + 3, pszDevName, cchDevName)) )
2680 {
2681 cMatches++;
2682 if (fApply)
2683 pDevIns->fTracing = fEnable;
2684 }
2685 }
2686 }
2687 else if (!strncmp("usb", pszName, 3))
2688 {
2689 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2690 {
2691 const char *pszUsbName = pUsbIns->Internal.s.pUsbDev->pReg->szName;
2692 size_t cchUsbName = strlen(pszUsbName);
2693 if ( ( cchUsbName == cchName
2694 && RTStrNICmp(pszName, pszUsbName, cchUsbName))
2695 || ( cchUsbName == cchName - 3
2696 && RTStrNICmp(pszName + 3, pszUsbName, cchUsbName)) )
2697 {
2698 cMatches++;
2699 if (fApply)
2700 pUsbIns->fTracing = fEnable;
2701 }
2702 }
2703 }
2704 else if (!strncmp("drv", pszName, 3))
2705 {
2706 AssertReturn(fApply, VINF_SUCCESS);
2707
2708 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2709 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
2710 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2711 {
2712 const char *pszDrvName = pDrvIns->Internal.s.pDrv->pReg->szName;
2713 size_t cchDrvName = strlen(pszDrvName);
2714 if ( ( cchDrvName == cchName
2715 && RTStrNICmp(pszName, pszDrvName, cchDrvName))
2716 || ( cchDrvName == cchName - 3
2717 && RTStrNICmp(pszName + 3, pszDrvName, cchDrvName)) )
2718 {
2719 cMatches++;
2720 if (fApply)
2721 pDrvIns->fTracing = fEnable;
2722 }
2723 }
2724
2725#ifdef VBOX_WITH_USB
2726 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2727 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
2728 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2729 {
2730 const char *pszDrvName = pDrvIns->Internal.s.pDrv->pReg->szName;
2731 size_t cchDrvName = strlen(pszDrvName);
2732 if ( ( cchDrvName == cchName
2733 && RTStrNICmp(pszName, pszDrvName, cchDrvName))
2734 || ( cchDrvName == cchName - 3
2735 && RTStrNICmp(pszName + 3, pszDrvName, cchDrvName)) )
2736 {
2737 cMatches++;
2738 if (fApply)
2739 pDrvIns->fTracing = fEnable;
2740 }
2741 }
2742#endif
2743 }
2744 else
2745 return VERR_NOT_FOUND;
2746
2747 return cMatches > 0 ? VINF_SUCCESS : VERR_NOT_FOUND;
2748}
2749
2750
2751/**
2752 * Worker for DBGFR3TraceQueryConfig that checks whether all drivers, devices,
2753 * and USB device have the same tracing settings.
2754 *
2755 * @returns true / false.
2756 * @param pVM The cross context VM structure.
2757 * @param fEnabled The tracing setting to check for.
2758 */
2759VMMR3_INT_DECL(bool) PDMR3TracingAreAll(PVM pVM, bool fEnabled)
2760{
2761 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2762 {
2763 if (pDevIns->fTracing != (uint32_t)fEnabled)
2764 return false;
2765
2766 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
2767 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2768 if (pDrvIns->fTracing != (uint32_t)fEnabled)
2769 return false;
2770 }
2771
2772#ifdef VBOX_WITH_USB
2773 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2774 {
2775 if (pUsbIns->fTracing != (uint32_t)fEnabled)
2776 return false;
2777
2778 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
2779 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2780 if (pDrvIns->fTracing != (uint32_t)fEnabled)
2781 return false;
2782 }
2783#endif
2784
2785 return true;
2786}
2787
2788
2789/**
2790 * Worker for PDMR3TracingQueryConfig that adds a prefixed name to the output
2791 * string.
2792 *
2793 * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW
2794 * @param ppszDst The pointer to the output buffer pointer.
2795 * @param pcbDst The pointer to the output buffer size.
2796 * @param fSpace Whether to add a space before the name.
2797 * @param pszPrefix The name prefix.
2798 * @param pszName The name.
2799 */
2800static int pdmR3TracingAdd(char **ppszDst, size_t *pcbDst, bool fSpace, const char *pszPrefix, const char *pszName)
2801{
2802 size_t const cchPrefix = strlen(pszPrefix);
2803 if (!RTStrNICmp(pszPrefix, pszName, cchPrefix))
2804 pszName += cchPrefix;
2805 size_t const cchName = strlen(pszName);
2806
2807 size_t const cchThis = cchName + cchPrefix + fSpace;
2808 if (cchThis >= *pcbDst)
2809 return VERR_BUFFER_OVERFLOW;
2810 if (fSpace)
2811 {
2812 **ppszDst = ' ';
2813 memcpy(*ppszDst + 1, pszPrefix, cchPrefix);
2814 memcpy(*ppszDst + 1 + cchPrefix, pszName, cchName + 1);
2815 }
2816 else
2817 {
2818 memcpy(*ppszDst, pszPrefix, cchPrefix);
2819 memcpy(*ppszDst + cchPrefix, pszName, cchName + 1);
2820 }
2821 *ppszDst += cchThis;
2822 *pcbDst -= cchThis;
2823 return VINF_SUCCESS;
2824}
2825
2826
2827/**
2828 * Worker for DBGFR3TraceQueryConfig use when not everything is either enabled
2829 * or disabled.
2830 *
2831 * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW
2832 * @param pVM The cross context VM structure.
2833 * @param pszConfig Where to store the config spec.
2834 * @param cbConfig The size of the output buffer.
2835 */
2836VMMR3_INT_DECL(int) PDMR3TracingQueryConfig(PVM pVM, char *pszConfig, size_t cbConfig)
2837{
2838 int rc;
2839 char *pszDst = pszConfig;
2840 size_t cbDst = cbConfig;
2841
2842 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2843 {
2844 if (pDevIns->fTracing)
2845 {
2846 rc = pdmR3TracingAdd(&pszDst, &cbDst, pszDst != pszConfig, "dev", pDevIns->Internal.s.pDevR3->pReg->szName);
2847 if (RT_FAILURE(rc))
2848 return rc;
2849 }
2850
2851 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
2852 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2853 if (pDrvIns->fTracing)
2854 {
2855 rc = pdmR3TracingAdd(&pszDst, &cbDst, pszDst != pszConfig, "drv", pDrvIns->Internal.s.pDrv->pReg->szName);
2856 if (RT_FAILURE(rc))
2857 return rc;
2858 }
2859 }
2860
2861#ifdef VBOX_WITH_USB
2862 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2863 {
2864 if (pUsbIns->fTracing)
2865 {
2866 rc = pdmR3TracingAdd(&pszDst, &cbDst, pszDst != pszConfig, "usb", pUsbIns->Internal.s.pUsbDev->pReg->szName);
2867 if (RT_FAILURE(rc))
2868 return rc;
2869 }
2870
2871 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
2872 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2873 if (pDrvIns->fTracing)
2874 {
2875 rc = pdmR3TracingAdd(&pszDst, &cbDst, pszDst != pszConfig, "drv", pDrvIns->Internal.s.pDrv->pReg->szName);
2876 if (RT_FAILURE(rc))
2877 return rc;
2878 }
2879 }
2880#endif
2881
2882 return VINF_SUCCESS;
2883}
2884
2885
2886/**
2887 * Checks that a PDMDRVREG::szName, PDMDEVREG::szName or PDMUSBREG::szName
2888 * field contains only a limited set of ASCII characters.
2889 *
2890 * @returns true / false.
2891 * @param pszName The name to validate.
2892 */
2893bool pdmR3IsValidName(const char *pszName)
2894{
2895 char ch;
2896 while ( (ch = *pszName) != '\0'
2897 && ( RT_C_IS_ALNUM(ch)
2898 || ch == '-'
2899 || ch == ' ' /** @todo disallow this! */
2900 || ch == '_') )
2901 pszName++;
2902 return ch == '\0';
2903}
2904
2905
2906/**
2907 * Info handler for 'pdmtracingids'.
2908 *
2909 * @param pVM The cross context VM structure.
2910 * @param pHlp The output helpers.
2911 * @param pszArgs The optional user arguments.
2912 *
2913 * @remarks Can be called on most threads.
2914 */
2915static DECLCALLBACK(void) pdmR3InfoTracingIds(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
2916{
2917 /*
2918 * Parse the argument (optional).
2919 */
2920 if ( pszArgs
2921 && *pszArgs
2922 && strcmp(pszArgs, "all")
2923 && strcmp(pszArgs, "devices")
2924 && strcmp(pszArgs, "drivers")
2925 && strcmp(pszArgs, "usb"))
2926 {
2927 pHlp->pfnPrintf(pHlp, "Unable to grok '%s'\n", pszArgs);
2928 return;
2929 }
2930 bool fAll = !pszArgs || !*pszArgs || !strcmp(pszArgs, "all");
2931 bool fDevices = fAll || !strcmp(pszArgs, "devices");
2932 bool fUsbDevs = fAll || !strcmp(pszArgs, "usb");
2933 bool fDrivers = fAll || !strcmp(pszArgs, "drivers");
2934
2935 /*
2936 * Produce the requested output.
2937 */
2938/** @todo lock PDM lists! */
2939 /* devices */
2940 if (fDevices)
2941 {
2942 pHlp->pfnPrintf(pHlp, "Device tracing IDs:\n");
2943 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2944 pHlp->pfnPrintf(pHlp, "%05u %s\n", pDevIns->idTracing, pDevIns->Internal.s.pDevR3->pReg->szName);
2945 }
2946
2947 /* USB devices */
2948 if (fUsbDevs)
2949 {
2950 pHlp->pfnPrintf(pHlp, "USB device tracing IDs:\n");
2951 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2952 pHlp->pfnPrintf(pHlp, "%05u %s\n", pUsbIns->idTracing, pUsbIns->Internal.s.pUsbDev->pReg->szName);
2953 }
2954
2955 /* Drivers */
2956 if (fDrivers)
2957 {
2958 pHlp->pfnPrintf(pHlp, "Driver tracing IDs:\n");
2959 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2960 {
2961 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
2962 {
2963 uint32_t iLevel = 0;
2964 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown, iLevel++)
2965 pHlp->pfnPrintf(pHlp, "%05u %s (level %u, lun %u, dev %s)\n",
2966 pDrvIns->idTracing, pDrvIns->Internal.s.pDrv->pReg->szName,
2967 iLevel, pLun->iLun, pDevIns->Internal.s.pDevR3->pReg->szName);
2968 }
2969 }
2970
2971 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2972 {
2973 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
2974 {
2975 uint32_t iLevel = 0;
2976 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown, iLevel++)
2977 pHlp->pfnPrintf(pHlp, "%05u %s (level %u, lun %u, dev %s)\n",
2978 pDrvIns->idTracing, pDrvIns->Internal.s.pDrv->pReg->szName,
2979 iLevel, pLun->iLun, pUsbIns->Internal.s.pUsbDev->pReg->szName);
2980 }
2981 }
2982 }
2983}
2984
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