VirtualBox

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

Last change on this file since 80943 was 80943, checked in by vboxsync, 5 years ago

Devices/PCI: Device model refactoring, part I. bugref:9218

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