VirtualBox

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

Last change on this file since 93115 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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