VirtualBox

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

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

VMMR3: warnings

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