VirtualBox

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

Last change on this file since 60682 was 60404, checked in by vboxsync, 9 years ago

VMM,Devices,Main: Implemented soft/warm reset for shutdown status codes 05h, 09h and 0Ah.

This is a shot at adjusting our VM reset handling to handle the ancient way of
getting a 286 out of protected mode and back to real mode. Our exiting reset
code (XXXR3Reset, PDMDEVREG::pfnReset, and so on) is doing a cold reset of the
system and then some additional device & memory initialization that the firmware
is usually responsible for doing. When the guest triggers a reset via the
keyboard controller, system control port A, CPU triple fault, and possibly ACPI,
only the CPU is supposed to be reset. The BIOS would then decide whether memory
and devices needed resetting as well, or if the resetter justed wanted to get out
protected mode and resume executing some real mode code pointed to by 467h.

  • New states SOFT_RESETTING and SOFT_RESETTING_LS. The latter returns to RUNNING_LS, not SUSPENDED_LS like for hard reset.
  • Added a firmware interface so the VMM/PDM can ask it whether we're supposed to do a hard reset or a soft(/warm) one.
  • Implemented firmware interface for the PC BIOS (but not EFI). It indicates soft(/warm) reset when CMOS[0xf] is 5, 9 or 10.
  • Moved the CMOS[0xf] resetting from the RTC device to the PC BIOS since it's firmware thing, not RTC.
  • Added a flag parameter to PDMDevHlpVMReset for specifying the source of the reset operation. One class of sources (GIM) will always trigger hard resets, whereas the others will check with the firmware first.
  • Added PDMR3GetResetInfo for query the flags passed to PDMDevHlpVMReset and for asking the firmware whether it's a hard or soft reset. The latter, however, is only done if only CPU 0 is active. Systems with more than one CPU in a state other than EMSTATE_WAIT_SIPI status will always be hard reset.
  • Added internal VMR3ResetFF and VMR3ResetTripleFault APIs for handling the VM_FF_RESET and VINF_EM_TRIPLE_FAULT conditions.
  • Added PMDR3ResetSoft and had it call pfnSoftReset (which is now defined).

Warning! Major PDM_DEVHLPR3_VERSION change, minor PDM_DEVREG_VERSION change.

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