VirtualBox

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

Last change on this file since 90346 was 90346, checked in by vboxsync, 3 years ago
  • VMM: Pass pVM to PDMCritSect APIs. bugref:9218 bugref:10074
  • DrvNetShaper: Do bandwidth allocation via PDMDrvHlp. bugref:10074
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 115.1 KB
Line 
1/* $Id: PDM.cpp 90346 2021-07-26 19:55:53Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device Manager.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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 = pdmR3CritSectBothInitStats(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 * Queues.
582 */
583 pdmR3QueueRelocate(pVM, offDelta);
584 pVM->pdm.s.pDevHlpQueueRC = PDMQueueRCPtr(pVM->pdm.s.pDevHlpQueueR3);
585
586 /*
587 * Critical sections.
588 */
589 pdmR3CritSectBothRelocate(pVM);
590
591 /*
592 * The registered PIC.
593 */
594 if (pVM->pdm.s.Pic.pDevInsRC)
595 {
596 pVM->pdm.s.Pic.pDevInsRC += offDelta;
597 pVM->pdm.s.Pic.pfnSetIrqRC += offDelta;
598 pVM->pdm.s.Pic.pfnGetInterruptRC += offDelta;
599 }
600
601 /*
602 * The registered APIC.
603 */
604 if (pVM->pdm.s.Apic.pDevInsRC)
605 pVM->pdm.s.Apic.pDevInsRC += offDelta;
606
607 /*
608 * The registered I/O APIC.
609 */
610 if (pVM->pdm.s.IoApic.pDevInsRC)
611 {
612 pVM->pdm.s.IoApic.pDevInsRC += offDelta;
613 pVM->pdm.s.IoApic.pfnSetIrqRC += offDelta;
614 if (pVM->pdm.s.IoApic.pfnSendMsiRC)
615 pVM->pdm.s.IoApic.pfnSendMsiRC += offDelta;
616 if (pVM->pdm.s.IoApic.pfnSetEoiRC)
617 pVM->pdm.s.IoApic.pfnSetEoiRC += offDelta;
618 }
619
620 /*
621 * Devices & Drivers.
622 */
623#ifdef VBOX_WITH_RAW_MODE_KEEP /* needs fixing */
624 int rc;
625 PCPDMDEVHLPRC pDevHlpRC = NIL_RTRCPTR;
626 if (VM_IS_RAW_MODE_ENABLED(pVM))
627 {
628 rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDevHlp", &pDevHlpRC);
629 AssertReleaseMsgRC(rc, ("rc=%Rrc when resolving g_pdmRCDevHlp\n", rc));
630 }
631
632 PCPDMDRVHLPRC pDrvHlpRC = NIL_RTRCPTR;
633 if (VM_IS_RAW_MODE_ENABLED(pVM))
634 {
635 rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDevHlp", &pDrvHlpRC);
636 AssertReleaseMsgRC(rc, ("rc=%Rrc when resolving g_pdmRCDevHlp\n", rc));
637 }
638
639 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
640 {
641 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_RC)
642 {
643 pDevIns->pHlpRC = pDevHlpRC;
644 pDevIns->pvInstanceDataRC = MMHyperR3ToRC(pVM, pDevIns->pvInstanceDataR3);
645 if (pDevIns->pCritSectRoR3)
646 pDevIns->pCritSectRoRC = MMHyperR3ToRC(pVM, pDevIns->pCritSectRoR3);
647 pDevIns->Internal.s.pVMRC = pVM->pVMRC;
648
649 PPDMPCIDEV pPciDev = pDevIns->Internal.s.pHeadPciDevR3;
650 if (pPciDev)
651 {
652 pDevIns->Internal.s.pHeadPciDevRC = MMHyperR3ToRC(pVM, pPciDev);
653 do
654 {
655 pPciDev->Int.s.pDevInsRC = MMHyperR3ToRC(pVM, pPciDev->Int.s.pDevInsR3);
656 pPciDev->Int.s.pPdmBusRC = MMHyperR3ToRC(pVM, pPciDev->Int.s.pPdmBusR3);
657 if (pPciDev->Int.s.pNextR3)
658 pPciDev->Int.s.pNextRC = MMHyperR3ToRC(pVM, pPciDev->Int.s.pNextR3);
659 pPciDev = pPciDev->Int.s.pNextR3;
660 } while (pPciDev);
661 }
662
663 if (pDevIns->pReg->pfnRelocate)
664 {
665 LogFlow(("PDMR3Relocate: Relocating device '%s'/%d\n",
666 pDevIns->pReg->szName, pDevIns->iInstance));
667 pDevIns->pReg->pfnRelocate(pDevIns, offDelta);
668 }
669 }
670
671 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
672 {
673 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
674 {
675 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_RC)
676 {
677 pDrvIns->pHlpRC = pDrvHlpRC;
678 pDrvIns->pvInstanceDataRC = MMHyperR3ToRC(pVM, pDrvIns->pvInstanceDataR3);
679 pDrvIns->Internal.s.pVMRC = pVM->pVMRC;
680 if (pDrvIns->pReg->pfnRelocate)
681 {
682 LogFlow(("PDMR3Relocate: Relocating driver '%s'/%u attached to '%s'/%d/%u\n",
683 pDrvIns->pReg->szName, pDrvIns->iInstance,
684 pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun));
685 pDrvIns->pReg->pfnRelocate(pDrvIns, offDelta);
686 }
687 }
688 }
689 }
690
691 }
692#endif
693}
694
695
696/**
697 * Worker for pdmR3Term that terminates a LUN chain.
698 *
699 * @param pVM The cross context VM structure.
700 * @param pLun The head of the chain.
701 * @param pszDevice The name of the device (for logging).
702 * @param iInstance The device instance number (for logging).
703 */
704static void pdmR3TermLuns(PVM pVM, PPDMLUN pLun, const char *pszDevice, unsigned iInstance)
705{
706 RT_NOREF2(pszDevice, iInstance);
707
708 for (; pLun; pLun = pLun->pNext)
709 {
710 /*
711 * Destroy them one at a time from the bottom up.
712 * (The serial device/drivers depends on this - bad.)
713 */
714 PPDMDRVINS pDrvIns = pLun->pBottom;
715 pLun->pBottom = pLun->pTop = NULL;
716 while (pDrvIns)
717 {
718 PPDMDRVINS pDrvNext = pDrvIns->Internal.s.pUp;
719
720 if (pDrvIns->pReg->pfnDestruct)
721 {
722 LogFlow(("pdmR3DevTerm: Destroying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
723 pDrvIns->pReg->szName, pDrvIns->iInstance, pLun->iLun, pszDevice, iInstance));
724 pDrvIns->pReg->pfnDestruct(pDrvIns);
725 }
726 pDrvIns->Internal.s.pDrv->cInstances--;
727
728 /* Order of resource freeing like in pdmR3DrvDestroyChain, but
729 * not all need to be done as they are done globally later. */
730 //PDMR3QueueDestroyDriver(pVM, pDrvIns);
731 TMR3TimerDestroyDriver(pVM, pDrvIns);
732 SSMR3DeregisterDriver(pVM, pDrvIns, NULL, 0);
733 //pdmR3ThreadDestroyDriver(pVM, pDrvIns);
734 //DBGFR3InfoDeregisterDriver(pVM, pDrvIns, NULL);
735 //pdmR3CritSectBothDeleteDriver(pVM, pDrvIns);
736 //PDMR3BlkCacheReleaseDriver(pVM, pDrvIns);
737#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
738 //pdmR3AsyncCompletionTemplateDestroyDriver(pVM, pDrvIns);
739#endif
740
741 /* Clear the driver struture to catch sloppy code. */
742 ASMMemFill32(pDrvIns, RT_UOFFSETOF_DYN(PDMDRVINS, achInstanceData[pDrvIns->pReg->cbInstance]), 0xdeadd0d0);
743
744 pDrvIns = pDrvNext;
745 }
746 }
747}
748
749
750/**
751 * Terminates the PDM.
752 *
753 * Termination means cleaning up and freeing all resources,
754 * the VM it self is at this point powered off or suspended.
755 *
756 * @returns VBox status code.
757 * @param pVM The cross context VM structure.
758 */
759VMMR3_INT_DECL(int) PDMR3Term(PVM pVM)
760{
761 LogFlow(("PDMR3Term:\n"));
762 AssertMsg(PDMCritSectIsInitialized(&pVM->pdm.s.CritSect), ("bad init order!\n"));
763
764 /*
765 * Iterate the device instances and attach drivers, doing
766 * relevant destruction processing.
767 *
768 * N.B. There is no need to mess around freeing memory allocated
769 * from any MM heap since MM will do that in its Term function.
770 */
771 /* usb ones first. */
772 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
773 {
774 pdmR3TermLuns(pVM, pUsbIns->Internal.s.pLuns, pUsbIns->pReg->szName, pUsbIns->iInstance);
775
776 /*
777 * Detach it from the HUB (if it's actually attached to one) so the HUB has
778 * a chance to stop accessing any data.
779 */
780 PPDMUSBHUB pHub = pUsbIns->Internal.s.pHub;
781 if (pHub)
782 {
783 int rc = pHub->Reg.pfnDetachDevice(pHub->pDrvIns, pUsbIns, pUsbIns->Internal.s.iPort);
784 if (RT_FAILURE(rc))
785 {
786 LogRel(("PDM: Failed to detach USB device '%s' instance %d from %p: %Rrc\n",
787 pUsbIns->pReg->szName, pUsbIns->iInstance, pHub, rc));
788 }
789 else
790 {
791 pHub->cAvailablePorts++;
792 Assert(pHub->cAvailablePorts > 0 && pHub->cAvailablePorts <= pHub->cPorts);
793 pUsbIns->Internal.s.pHub = NULL;
794 }
795 }
796
797 if (pUsbIns->pReg->pfnDestruct)
798 {
799 LogFlow(("pdmR3DevTerm: Destroying - device '%s'/%d\n",
800 pUsbIns->pReg->szName, pUsbIns->iInstance));
801 pUsbIns->pReg->pfnDestruct(pUsbIns);
802 }
803
804 //TMR3TimerDestroyUsb(pVM, pUsbIns);
805 //SSMR3DeregisterUsb(pVM, pUsbIns, NULL, 0);
806 pdmR3ThreadDestroyUsb(pVM, pUsbIns);
807 }
808
809 /* then the 'normal' ones. */
810 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
811 {
812 pdmR3TermLuns(pVM, pDevIns->Internal.s.pLunsR3, pDevIns->pReg->szName, pDevIns->iInstance);
813
814 if (pDevIns->pReg->pfnDestruct)
815 {
816 LogFlow(("pdmR3DevTerm: Destroying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
817 pDevIns->pReg->pfnDestruct(pDevIns);
818 }
819
820 if (pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_R0_CONTRUCT)
821 {
822 LogFlow(("pdmR3DevTerm: Destroying (ring-0) - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
823 PDMDEVICEGENCALLREQ Req;
824 RT_ZERO(Req.Params);
825 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
826 Req.Hdr.cbReq = sizeof(Req);
827 Req.enmCall = PDMDEVICEGENCALL_DESTRUCT;
828 Req.idxR0Device = pDevIns->Internal.s.idxR0Device;
829 Req.pDevInsR3 = pDevIns;
830 int rc2 = VMMR3CallR0(pVM, VMMR0_DO_PDM_DEVICE_GEN_CALL, 0, &Req.Hdr);
831 AssertRC(rc2);
832 }
833
834 if (pDevIns->Internal.s.paDbgfTraceTrack)
835 {
836 RTMemFree(pDevIns->Internal.s.paDbgfTraceTrack);
837 pDevIns->Internal.s.paDbgfTraceTrack = NULL;
838 }
839
840#ifdef VBOX_WITH_DBGF_TRACING
841 if (pDevIns->Internal.s.hDbgfTraceEvtSrc != NIL_DBGFTRACEREVTSRC)
842 {
843 DBGFR3TracerDeregisterEvtSrc(pVM, pDevIns->Internal.s.hDbgfTraceEvtSrc);
844 pDevIns->Internal.s.hDbgfTraceEvtSrc = NIL_DBGFTRACEREVTSRC;
845 }
846#endif
847
848 TMR3TimerDestroyDevice(pVM, pDevIns);
849 SSMR3DeregisterDevice(pVM, pDevIns, NULL, 0);
850 pdmR3CritSectBothDeleteDevice(pVM, pDevIns);
851 pdmR3ThreadDestroyDevice(pVM, pDevIns);
852 PDMR3QueueDestroyDevice(pVM, pDevIns);
853 PGMR3PhysMmio2Deregister(pVM, pDevIns, NIL_PGMMMIO2HANDLE);
854#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
855 pdmR3AsyncCompletionTemplateDestroyDevice(pVM, pDevIns);
856#endif
857 DBGFR3InfoDeregisterDevice(pVM, pDevIns, NULL);
858 }
859
860 /*
861 * Destroy all threads.
862 */
863 pdmR3ThreadDestroyAll(pVM);
864
865 /*
866 * Destroy the block cache.
867 */
868 pdmR3BlkCacheTerm(pVM);
869
870#ifdef VBOX_WITH_NETSHAPER
871 /*
872 * Destroy network bandwidth groups.
873 */
874 pdmR3NetShaperTerm(pVM);
875#endif
876#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
877 /*
878 * Free async completion managers.
879 */
880 pdmR3AsyncCompletionTerm(pVM);
881#endif
882
883 /*
884 * Free modules.
885 */
886 pdmR3LdrTermU(pVM->pUVM, false /*fFinal*/);
887
888 /*
889 * Stop task threads.
890 */
891 pdmR3TaskTerm(pVM);
892
893 /*
894 * Destroy the PDM lock.
895 */
896 PDMR3CritSectDelete(&pVM->pdm.s.CritSect);
897 /* The MiscCritSect is deleted by PDMR3CritSectBothTerm later. */
898
899 LogFlow(("PDMR3Term: returns %Rrc\n", VINF_SUCCESS));
900 return VINF_SUCCESS;
901}
902
903
904/**
905 * Terminates the PDM part of the UVM.
906 *
907 * This will unload any modules left behind.
908 *
909 * @param pUVM Pointer to the user mode VM structure.
910 */
911VMMR3_INT_DECL(void) PDMR3TermUVM(PUVM pUVM)
912{
913 /*
914 * In the normal cause of events we will now call pdmR3LdrTermU for
915 * the second time. In the case of init failure however, this might
916 * the first time, which is why we do it.
917 */
918 pdmR3LdrTermU(pUVM, true /*fFinal*/);
919
920 Assert(pUVM->pdm.s.pCritSects == NULL);
921 Assert(pUVM->pdm.s.pRwCritSects == NULL);
922 RTCritSectDelete(&pUVM->pdm.s.ListCritSect);
923}
924
925
926/**
927 * For APIC assertions.
928 *
929 * @returns true if we've loaded state.
930 * @param pVM The cross context VM structure.
931 */
932VMMR3_INT_DECL(bool) PDMR3HasLoadedState(PVM pVM)
933{
934 return pVM->pdm.s.fStateLoaded;
935}
936
937
938/**
939 * Bits that are saved in pass 0 and in the final pass.
940 *
941 * @param pVM The cross context VM structure.
942 * @param pSSM The saved state handle.
943 */
944static void pdmR3SaveBoth(PVM pVM, PSSMHANDLE pSSM)
945{
946 /*
947 * Save the list of device instances so we can check that they're all still
948 * there when we load the state and that nothing new has been added.
949 */
950 uint32_t i = 0;
951 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3, i++)
952 {
953 SSMR3PutU32(pSSM, i);
954 SSMR3PutStrZ(pSSM, pDevIns->pReg->szName);
955 SSMR3PutU32(pSSM, pDevIns->iInstance);
956 }
957 SSMR3PutU32(pSSM, UINT32_MAX); /* terminator */
958}
959
960
961/**
962 * Live save.
963 *
964 * @returns VBox status code.
965 * @param pVM The cross context VM structure.
966 * @param pSSM The saved state handle.
967 * @param uPass The pass.
968 */
969static DECLCALLBACK(int) pdmR3LiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass)
970{
971 LogFlow(("pdmR3LiveExec:\n"));
972 AssertReturn(uPass == 0, VERR_SSM_UNEXPECTED_PASS);
973 pdmR3SaveBoth(pVM, pSSM);
974 return VINF_SSM_DONT_CALL_AGAIN;
975}
976
977
978/**
979 * Execute state save operation.
980 *
981 * @returns VBox status code.
982 * @param pVM The cross context VM structure.
983 * @param pSSM The saved state handle.
984 */
985static DECLCALLBACK(int) pdmR3SaveExec(PVM pVM, PSSMHANDLE pSSM)
986{
987 LogFlow(("pdmR3SaveExec:\n"));
988
989 /*
990 * Save interrupt and DMA states.
991 */
992 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
993 {
994 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
995 SSMR3PutU32(pSSM, VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC));
996 SSMR3PutU32(pSSM, VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC));
997 SSMR3PutU32(pSSM, VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI));
998 SSMR3PutU32(pSSM, VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_SMI));
999 }
1000 SSMR3PutU32(pSSM, VM_FF_IS_SET(pVM, VM_FF_PDM_DMA));
1001
1002 pdmR3SaveBoth(pVM, pSSM);
1003 return VINF_SUCCESS;
1004}
1005
1006
1007/**
1008 * Prepare state load operation.
1009 *
1010 * This will dispatch pending operations and clear the FFs governed by PDM and its devices.
1011 *
1012 * @returns VBox status code.
1013 * @param pVM The cross context VM structure.
1014 * @param pSSM The SSM handle.
1015 */
1016static DECLCALLBACK(int) pdmR3LoadPrep(PVM pVM, PSSMHANDLE pSSM)
1017{
1018 LogFlow(("pdmR3LoadPrep: %s%s\n",
1019 VM_FF_IS_SET(pVM, VM_FF_PDM_QUEUES) ? " VM_FF_PDM_QUEUES" : "",
1020 VM_FF_IS_SET(pVM, VM_FF_PDM_DMA) ? " VM_FF_PDM_DMA" : ""));
1021#ifdef LOG_ENABLED
1022 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1023 {
1024 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
1025 LogFlow(("pdmR3LoadPrep: VCPU %u %s%s\n", idCpu,
1026 VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC) ? " VMCPU_FF_INTERRUPT_APIC" : "",
1027 VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC) ? " VMCPU_FF_INTERRUPT_PIC" : ""));
1028 }
1029#endif
1030 NOREF(pSSM);
1031
1032 /*
1033 * In case there is work pending that will raise an interrupt,
1034 * start a DMA transfer, or release a lock. (unlikely)
1035 */
1036 if (VM_FF_IS_SET(pVM, VM_FF_PDM_QUEUES))
1037 PDMR3QueueFlushAll(pVM);
1038
1039 /* Clear the FFs. */
1040 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1041 {
1042 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
1043 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
1044 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
1045 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
1046 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_SMI);
1047 }
1048 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
1049
1050 return VINF_SUCCESS;
1051}
1052
1053
1054/**
1055 * Execute state load operation.
1056 *
1057 * @returns VBox status code.
1058 * @param pVM The cross context VM structure.
1059 * @param pSSM SSM operation handle.
1060 * @param uVersion Data layout version.
1061 * @param uPass The data pass.
1062 */
1063static DECLCALLBACK(int) pdmR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1064{
1065 int rc;
1066
1067 LogFlow(("pdmR3LoadExec: uPass=%#x\n", uPass));
1068
1069 /*
1070 * Validate version.
1071 */
1072 if ( uVersion != PDM_SAVED_STATE_VERSION
1073 && uVersion != PDM_SAVED_STATE_VERSION_PRE_NMI_FF
1074 && uVersion != PDM_SAVED_STATE_VERSION_PRE_PDM_AUDIO)
1075 {
1076 AssertMsgFailed(("Invalid version uVersion=%d!\n", uVersion));
1077 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1078 }
1079
1080 if (uPass == SSM_PASS_FINAL)
1081 {
1082 /*
1083 * Load the interrupt and DMA states.
1084 *
1085 * The APIC, PIC and DMA devices does not restore these, we do. In the
1086 * APIC and PIC cases, it is possible that some devices is incorrectly
1087 * setting IRQs during restore. We'll warn when this happens. (There
1088 * are debug assertions in PDMDevMiscHlp.cpp and APICAll.cpp for
1089 * catching the buggy device.)
1090 */
1091 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1092 {
1093 PVMCPU pVCpu = pVM->apCpusR3[idCpu];
1094
1095 /* APIC interrupt */
1096 uint32_t fInterruptPending = 0;
1097 rc = SSMR3GetU32(pSSM, &fInterruptPending);
1098 if (RT_FAILURE(rc))
1099 return rc;
1100 if (fInterruptPending & ~1)
1101 {
1102 AssertMsgFailed(("fInterruptPending=%#x (APIC)\n", fInterruptPending));
1103 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1104 }
1105 AssertLogRelMsg(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC),
1106 ("VCPU%03u: VMCPU_FF_INTERRUPT_APIC set! Devices shouldn't set interrupts during state restore...\n", idCpu));
1107 if (fInterruptPending)
1108 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC);
1109
1110 /* PIC interrupt */
1111 fInterruptPending = 0;
1112 rc = SSMR3GetU32(pSSM, &fInterruptPending);
1113 if (RT_FAILURE(rc))
1114 return rc;
1115 if (fInterruptPending & ~1)
1116 {
1117 AssertMsgFailed(("fInterruptPending=%#x (PIC)\n", fInterruptPending));
1118 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1119 }
1120 AssertLogRelMsg(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC),
1121 ("VCPU%03u: VMCPU_FF_INTERRUPT_PIC set! Devices shouldn't set interrupts during state restore...\n", idCpu));
1122 if (fInterruptPending)
1123 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC);
1124
1125 if (uVersion > PDM_SAVED_STATE_VERSION_PRE_NMI_FF)
1126 {
1127 /* NMI interrupt */
1128 fInterruptPending = 0;
1129 rc = SSMR3GetU32(pSSM, &fInterruptPending);
1130 if (RT_FAILURE(rc))
1131 return rc;
1132 if (fInterruptPending & ~1)
1133 {
1134 AssertMsgFailed(("fInterruptPending=%#x (NMI)\n", fInterruptPending));
1135 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1136 }
1137 AssertLogRelMsg(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI), ("VCPU%3u: VMCPU_FF_INTERRUPT_NMI set!\n", idCpu));
1138 if (fInterruptPending)
1139 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI);
1140
1141 /* SMI interrupt */
1142 fInterruptPending = 0;
1143 rc = SSMR3GetU32(pSSM, &fInterruptPending);
1144 if (RT_FAILURE(rc))
1145 return rc;
1146 if (fInterruptPending & ~1)
1147 {
1148 AssertMsgFailed(("fInterruptPending=%#x (SMI)\n", fInterruptPending));
1149 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1150 }
1151 AssertLogRelMsg(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_SMI), ("VCPU%3u: VMCPU_FF_INTERRUPT_SMI set!\n", idCpu));
1152 if (fInterruptPending)
1153 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_SMI);
1154 }
1155 }
1156
1157 /* DMA pending */
1158 uint32_t fDMAPending = 0;
1159 rc = SSMR3GetU32(pSSM, &fDMAPending);
1160 if (RT_FAILURE(rc))
1161 return rc;
1162 if (fDMAPending & ~1)
1163 {
1164 AssertMsgFailed(("fDMAPending=%#x\n", fDMAPending));
1165 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1166 }
1167 if (fDMAPending)
1168 VM_FF_SET(pVM, VM_FF_PDM_DMA);
1169 Log(("pdmR3LoadExec: VM_FF_PDM_DMA=%RTbool\n", VM_FF_IS_SET(pVM, VM_FF_PDM_DMA)));
1170 }
1171
1172 /*
1173 * Load the list of devices and verify that they are all there.
1174 */
1175 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1176 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_FOUND;
1177
1178 for (uint32_t i = 0; ; i++)
1179 {
1180 /* Get the sequence number / terminator. */
1181 uint32_t u32Sep;
1182 rc = SSMR3GetU32(pSSM, &u32Sep);
1183 if (RT_FAILURE(rc))
1184 return rc;
1185 if (u32Sep == UINT32_MAX)
1186 break;
1187 if (u32Sep != i)
1188 AssertMsgFailedReturn(("Out of sequence. u32Sep=%#x i=%#x\n", u32Sep, i), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
1189
1190 /* Get the name and instance number. */
1191 char szName[RT_SIZEOFMEMB(PDMDEVREG, szName)];
1192 rc = SSMR3GetStrZ(pSSM, szName, sizeof(szName));
1193 if (RT_FAILURE(rc))
1194 return rc;
1195 uint32_t iInstance;
1196 rc = SSMR3GetU32(pSSM, &iInstance);
1197 if (RT_FAILURE(rc))
1198 return rc;
1199
1200 /* Try locate it. */
1201 PPDMDEVINS pDevIns;
1202 for (pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1203 if ( !RTStrCmp(szName, pDevIns->pReg->szName)
1204 && pDevIns->iInstance == iInstance)
1205 {
1206 AssertLogRelMsgReturn(!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_FOUND),
1207 ("%s/#%u\n", pDevIns->pReg->szName, pDevIns->iInstance),
1208 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
1209 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_FOUND;
1210 break;
1211 }
1212
1213 if (!pDevIns)
1214 {
1215 bool fSkip = false;
1216
1217 /* Skip the non-existing (deprecated) "AudioSniffer" device stored in the saved state. */
1218 if ( uVersion <= PDM_SAVED_STATE_VERSION_PRE_PDM_AUDIO
1219 && !RTStrCmp(szName, "AudioSniffer"))
1220 fSkip = true;
1221
1222 if (!fSkip)
1223 {
1224 LogRel(("Device '%s'/%d not found in current config\n", szName, iInstance));
1225 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
1226 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device '%s'/%d not found in current config"), szName, iInstance);
1227 }
1228 }
1229 }
1230
1231 /*
1232 * Check that no additional devices were configured.
1233 */
1234 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1235 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_FOUND))
1236 {
1237 LogRel(("Device '%s'/%d not found in the saved state\n", pDevIns->pReg->szName, pDevIns->iInstance));
1238 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
1239 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device '%s'/%d not found in the saved state"),
1240 pDevIns->pReg->szName, pDevIns->iInstance);
1241 }
1242
1243
1244 /*
1245 * Indicate that we've been called (for assertions).
1246 */
1247 pVM->pdm.s.fStateLoaded = true;
1248
1249 return VINF_SUCCESS;
1250}
1251
1252
1253/**
1254 * Worker for PDMR3PowerOn that deals with one driver.
1255 *
1256 * @param pDrvIns The driver instance.
1257 * @param pszDevName The parent device name.
1258 * @param iDevInstance The parent device instance number.
1259 * @param iLun The parent LUN number.
1260 */
1261DECLINLINE(int) pdmR3PowerOnDrv(PPDMDRVINS pDrvIns, const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1262{
1263 Assert(pDrvIns->Internal.s.fVMSuspended);
1264 if (pDrvIns->pReg->pfnPowerOn)
1265 {
1266 LogFlow(("PDMR3PowerOn: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1267 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1268 int rc = VINF_SUCCESS; pDrvIns->pReg->pfnPowerOn(pDrvIns);
1269 if (RT_FAILURE(rc))
1270 {
1271 LogRel(("PDMR3PowerOn: Driver '%s'/%d on LUN#%d of device '%s'/%d -> %Rrc\n",
1272 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance, rc));
1273 return rc;
1274 }
1275 }
1276 pDrvIns->Internal.s.fVMSuspended = false;
1277 return VINF_SUCCESS;
1278}
1279
1280
1281/**
1282 * Worker for PDMR3PowerOn that deals with one USB device instance.
1283 *
1284 * @returns VBox status code.
1285 * @param pUsbIns The USB device instance.
1286 */
1287DECLINLINE(int) pdmR3PowerOnUsb(PPDMUSBINS pUsbIns)
1288{
1289 Assert(pUsbIns->Internal.s.fVMSuspended);
1290 if (pUsbIns->pReg->pfnVMPowerOn)
1291 {
1292 LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1293 int rc = VINF_SUCCESS; pUsbIns->pReg->pfnVMPowerOn(pUsbIns);
1294 if (RT_FAILURE(rc))
1295 {
1296 LogRel(("PDMR3PowerOn: Device '%s'/%d -> %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1297 return rc;
1298 }
1299 }
1300 pUsbIns->Internal.s.fVMSuspended = false;
1301 return VINF_SUCCESS;
1302}
1303
1304
1305/**
1306 * Worker for PDMR3PowerOn that deals with one device instance.
1307 *
1308 * @returns VBox status code.
1309 * @param pVM The cross context VM structure.
1310 * @param pDevIns The device instance.
1311 */
1312DECLINLINE(int) pdmR3PowerOnDev(PVM pVM, PPDMDEVINS pDevIns)
1313{
1314 Assert(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED);
1315 if (pDevIns->pReg->pfnPowerOn)
1316 {
1317 LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1318 PDMCritSectEnter(pVM, pDevIns->pCritSectRoR3, VERR_IGNORED);
1319 int rc = VINF_SUCCESS; pDevIns->pReg->pfnPowerOn(pDevIns);
1320 PDMCritSectLeave(pVM, pDevIns->pCritSectRoR3);
1321 if (RT_FAILURE(rc))
1322 {
1323 LogRel(("PDMR3PowerOn: Device '%s'/%d -> %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
1324 return rc;
1325 }
1326 }
1327 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1328 return VINF_SUCCESS;
1329}
1330
1331
1332/**
1333 * This function will notify all the devices and their
1334 * attached drivers about the VM now being powered on.
1335 *
1336 * @param pVM The cross context VM structure.
1337 */
1338VMMR3DECL(void) PDMR3PowerOn(PVM pVM)
1339{
1340 LogFlow(("PDMR3PowerOn:\n"));
1341
1342 /*
1343 * Iterate thru the device instances and USB device instances,
1344 * processing the drivers associated with those.
1345 */
1346 int rc = VINF_SUCCESS;
1347 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns && RT_SUCCESS(rc); pDevIns = pDevIns->Internal.s.pNextR3)
1348 {
1349 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1350 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1351 rc = pdmR3PowerOnDrv(pDrvIns, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun);
1352 if (RT_SUCCESS(rc))
1353 rc = pdmR3PowerOnDev(pVM, pDevIns);
1354 }
1355
1356#ifdef VBOX_WITH_USB
1357 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns && RT_SUCCESS(rc); pUsbIns = pUsbIns->Internal.s.pNext)
1358 {
1359 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1360 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1361 rc = pdmR3PowerOnDrv(pDrvIns, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun);
1362 if (RT_SUCCESS(rc))
1363 rc = pdmR3PowerOnUsb(pUsbIns);
1364 }
1365#endif
1366
1367#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
1368 pdmR3AsyncCompletionResume(pVM);
1369#endif
1370
1371 /*
1372 * Resume all threads.
1373 */
1374 if (RT_SUCCESS(rc))
1375 pdmR3ThreadResumeAll(pVM);
1376
1377 /*
1378 * On failure, clean up via PDMR3Suspend.
1379 */
1380 if (RT_FAILURE(rc))
1381 PDMR3Suspend(pVM);
1382
1383 LogFlow(("PDMR3PowerOn: returns %Rrc\n", rc));
1384 return /*rc*/;
1385}
1386
1387
1388/**
1389 * Initializes the asynchronous notifi stats structure.
1390 *
1391 * @param pThis The asynchronous notifification stats.
1392 * @param pszOp The name of the operation.
1393 */
1394static void pdmR3NotifyAsyncInit(PPDMNOTIFYASYNCSTATS pThis, const char *pszOp)
1395{
1396 pThis->uStartNsTs = RTTimeNanoTS();
1397 pThis->cNsElapsedNextLog = 0;
1398 pThis->cLoops = 0;
1399 pThis->cAsync = 0;
1400 pThis->pszOp = pszOp;
1401 pThis->offList = 0;
1402 pThis->szList[0] = '\0';
1403}
1404
1405
1406/**
1407 * Begin a new loop, prepares to gather new stats.
1408 *
1409 * @param pThis The asynchronous notifification stats.
1410 */
1411static void pdmR3NotifyAsyncBeginLoop(PPDMNOTIFYASYNCSTATS pThis)
1412{
1413 pThis->cLoops++;
1414 pThis->cAsync = 0;
1415 pThis->offList = 0;
1416 pThis->szList[0] = '\0';
1417}
1418
1419
1420/**
1421 * Records a device or USB device with a pending asynchronous notification.
1422 *
1423 * @param pThis The asynchronous notifification stats.
1424 * @param pszName The name of the thing.
1425 * @param iInstance The instance number.
1426 */
1427static void pdmR3NotifyAsyncAdd(PPDMNOTIFYASYNCSTATS pThis, const char *pszName, uint32_t iInstance)
1428{
1429 pThis->cAsync++;
1430 if (pThis->offList < sizeof(pThis->szList) - 4)
1431 pThis->offList += RTStrPrintf(&pThis->szList[pThis->offList], sizeof(pThis->szList) - pThis->offList,
1432 pThis->offList == 0 ? "%s/%u" : ", %s/%u",
1433 pszName, iInstance);
1434}
1435
1436
1437/**
1438 * Records the asynchronous completition of a reset, suspend or power off.
1439 *
1440 * @param pThis The asynchronous notifification stats.
1441 * @param pszDrvName The driver name.
1442 * @param iDrvInstance The driver instance number.
1443 * @param pszDevName The device or USB device name.
1444 * @param iDevInstance The device or USB device instance number.
1445 * @param iLun The LUN.
1446 */
1447static void pdmR3NotifyAsyncAddDrv(PPDMNOTIFYASYNCSTATS pThis, const char *pszDrvName, uint32_t iDrvInstance,
1448 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1449{
1450 pThis->cAsync++;
1451 if (pThis->offList < sizeof(pThis->szList) - 8)
1452 pThis->offList += RTStrPrintf(&pThis->szList[pThis->offList], sizeof(pThis->szList) - pThis->offList,
1453 pThis->offList == 0 ? "%s/%u/%u/%s/%u" : ", %s/%u/%u/%s/%u",
1454 pszDevName, iDevInstance, iLun, pszDrvName, iDrvInstance);
1455}
1456
1457
1458/**
1459 * Log the stats.
1460 *
1461 * @param pThis The asynchronous notifification stats.
1462 */
1463static void pdmR3NotifyAsyncLog(PPDMNOTIFYASYNCSTATS pThis)
1464{
1465 /*
1466 * Return if we shouldn't log at this point.
1467 * We log with an internval increasing from 0 sec to 60 sec.
1468 */
1469 if (!pThis->cAsync)
1470 return;
1471
1472 uint64_t cNsElapsed = RTTimeNanoTS() - pThis->uStartNsTs;
1473 if (cNsElapsed < pThis->cNsElapsedNextLog)
1474 return;
1475
1476 if (pThis->cNsElapsedNextLog == 0)
1477 pThis->cNsElapsedNextLog = RT_NS_1SEC;
1478 else if (pThis->cNsElapsedNextLog >= RT_NS_1MIN / 2)
1479 pThis->cNsElapsedNextLog = RT_NS_1MIN;
1480 else
1481 pThis->cNsElapsedNextLog *= 2;
1482
1483 /*
1484 * Do the logging.
1485 */
1486 LogRel(("%s: after %5llu ms, %u loops: %u async tasks - %s\n",
1487 pThis->pszOp, cNsElapsed / RT_NS_1MS, pThis->cLoops, pThis->cAsync, pThis->szList));
1488}
1489
1490
1491/**
1492 * Wait for events and process pending requests.
1493 *
1494 * @param pThis The asynchronous notifification stats.
1495 * @param pVM The cross context VM structure.
1496 */
1497static void pdmR3NotifyAsyncWaitAndProcessRequests(PPDMNOTIFYASYNCSTATS pThis, PVM pVM)
1498{
1499 VM_ASSERT_EMT0(pVM);
1500 int rc = VMR3AsyncPdmNotificationWaitU(&pVM->pUVM->aCpus[0]);
1501 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc - %s - %s\n", rc, pThis->pszOp, pThis->szList));
1502
1503 rc = VMR3ReqProcessU(pVM->pUVM, VMCPUID_ANY, true /*fPriorityOnly*/);
1504 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc - %s - %s\n", rc, pThis->pszOp, pThis->szList));
1505 rc = VMR3ReqProcessU(pVM->pUVM, 0/*idDstCpu*/, true /*fPriorityOnly*/);
1506 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc - %s - %s\n", rc, pThis->pszOp, pThis->szList));
1507}
1508
1509
1510/**
1511 * Worker for PDMR3Reset that deals with one driver.
1512 *
1513 * @param pDrvIns The driver instance.
1514 * @param pAsync The structure for recording asynchronous
1515 * notification tasks.
1516 * @param pszDevName The parent device name.
1517 * @param iDevInstance The parent device instance number.
1518 * @param iLun The parent LUN number.
1519 */
1520DECLINLINE(bool) pdmR3ResetDrv(PPDMDRVINS pDrvIns, PPDMNOTIFYASYNCSTATS pAsync,
1521 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1522{
1523 if (!pDrvIns->Internal.s.fVMReset)
1524 {
1525 pDrvIns->Internal.s.fVMReset = true;
1526 if (pDrvIns->pReg->pfnReset)
1527 {
1528 if (!pDrvIns->Internal.s.pfnAsyncNotify)
1529 {
1530 LogFlow(("PDMR3Reset: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1531 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1532 pDrvIns->pReg->pfnReset(pDrvIns);
1533 if (pDrvIns->Internal.s.pfnAsyncNotify)
1534 LogFlow(("PDMR3Reset: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1535 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1536 }
1537 else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
1538 {
1539 LogFlow(("PDMR3Reset: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1540 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1541 pDrvIns->Internal.s.pfnAsyncNotify = NULL;
1542 }
1543 if (pDrvIns->Internal.s.pfnAsyncNotify)
1544 {
1545 pDrvIns->Internal.s.fVMReset = false;
1546 pdmR3NotifyAsyncAddDrv(pAsync, pDrvIns->Internal.s.pDrv->pReg->szName, pDrvIns->iInstance,
1547 pszDevName, iDevInstance, iLun);
1548 return false;
1549 }
1550 }
1551 }
1552 return true;
1553}
1554
1555
1556/**
1557 * Worker for PDMR3Reset that deals with one USB device instance.
1558 *
1559 * @param pUsbIns The USB device instance.
1560 * @param pAsync The structure for recording asynchronous
1561 * notification tasks.
1562 */
1563DECLINLINE(void) pdmR3ResetUsb(PPDMUSBINS pUsbIns, PPDMNOTIFYASYNCSTATS pAsync)
1564{
1565 if (!pUsbIns->Internal.s.fVMReset)
1566 {
1567 pUsbIns->Internal.s.fVMReset = true;
1568 if (pUsbIns->pReg->pfnVMReset)
1569 {
1570 if (!pUsbIns->Internal.s.pfnAsyncNotify)
1571 {
1572 LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1573 pUsbIns->pReg->pfnVMReset(pUsbIns);
1574 if (pUsbIns->Internal.s.pfnAsyncNotify)
1575 LogFlow(("PDMR3Reset: Async notification started - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1576 }
1577 else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
1578 {
1579 LogFlow(("PDMR3Reset: Async notification completed - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1580 pUsbIns->Internal.s.pfnAsyncNotify = NULL;
1581 }
1582 if (pUsbIns->Internal.s.pfnAsyncNotify)
1583 {
1584 pUsbIns->Internal.s.fVMReset = false;
1585 pdmR3NotifyAsyncAdd(pAsync, pUsbIns->Internal.s.pUsbDev->pReg->szName, pUsbIns->iInstance);
1586 }
1587 }
1588 }
1589}
1590
1591
1592/**
1593 * Worker for PDMR3Reset that deals with one device instance.
1594 *
1595 * @param pVM The cross context VM structure.
1596 * @param pDevIns The device instance.
1597 * @param pAsync The structure for recording asynchronous notification tasks.
1598 */
1599DECLINLINE(void) pdmR3ResetDev(PVM pVM, PPDMDEVINS pDevIns, PPDMNOTIFYASYNCSTATS pAsync)
1600{
1601 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_RESET))
1602 {
1603 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_RESET;
1604 if (pDevIns->pReg->pfnReset)
1605 {
1606 uint64_t cNsElapsed = RTTimeNanoTS();
1607 PDMCritSectEnter(pVM, pDevIns->pCritSectRoR3, VERR_IGNORED);
1608
1609 if (!pDevIns->Internal.s.pfnAsyncNotify)
1610 {
1611 LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1612 pDevIns->pReg->pfnReset(pDevIns);
1613 if (pDevIns->Internal.s.pfnAsyncNotify)
1614 LogFlow(("PDMR3Reset: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1615 }
1616 else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
1617 {
1618 LogFlow(("PDMR3Reset: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1619 pDevIns->Internal.s.pfnAsyncNotify = NULL;
1620 }
1621 if (pDevIns->Internal.s.pfnAsyncNotify)
1622 {
1623 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_RESET;
1624 pdmR3NotifyAsyncAdd(pAsync, pDevIns->Internal.s.pDevR3->pReg->szName, pDevIns->iInstance);
1625 }
1626
1627 PDMCritSectLeave(pVM, pDevIns->pCritSectRoR3);
1628 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1629 if (cNsElapsed >= PDMSUSPEND_WARN_AT_NS)
1630 LogRel(("PDMR3Reset: Device '%s'/%d took %'llu ns to reset\n",
1631 pDevIns->pReg->szName, pDevIns->iInstance, cNsElapsed));
1632 }
1633 }
1634}
1635
1636
1637/**
1638 * Resets a virtual CPU.
1639 *
1640 * Used by PDMR3Reset and CPU hot plugging.
1641 *
1642 * @param pVCpu The cross context virtual CPU structure.
1643 */
1644VMMR3_INT_DECL(void) PDMR3ResetCpu(PVMCPU pVCpu)
1645{
1646 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
1647 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
1648 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
1649 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_SMI);
1650}
1651
1652
1653/**
1654 * This function will notify all the devices and their attached drivers about
1655 * the VM now being reset.
1656 *
1657 * @param pVM The cross context VM structure.
1658 */
1659VMMR3_INT_DECL(void) PDMR3Reset(PVM pVM)
1660{
1661 LogFlow(("PDMR3Reset:\n"));
1662
1663 /*
1664 * Clear all the reset flags.
1665 */
1666 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1667 {
1668 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_RESET;
1669 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1670 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1671 pDrvIns->Internal.s.fVMReset = false;
1672 }
1673#ifdef VBOX_WITH_USB
1674 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1675 {
1676 pUsbIns->Internal.s.fVMReset = false;
1677 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1678 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1679 pDrvIns->Internal.s.fVMReset = false;
1680 }
1681#endif
1682
1683 /*
1684 * The outer loop repeats until there are no more async requests.
1685 */
1686 PDMNOTIFYASYNCSTATS Async;
1687 pdmR3NotifyAsyncInit(&Async, "PDMR3Reset");
1688 for (;;)
1689 {
1690 pdmR3NotifyAsyncBeginLoop(&Async);
1691
1692 /*
1693 * Iterate thru the device instances and USB device instances,
1694 * processing the drivers associated with those.
1695 */
1696 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1697 {
1698 unsigned const cAsyncStart = Async.cAsync;
1699
1700 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_RESET_NOTIFICATION)
1701 pdmR3ResetDev(pVM, pDevIns, &Async);
1702
1703 if (Async.cAsync == cAsyncStart)
1704 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1705 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1706 if (!pdmR3ResetDrv(pDrvIns, &Async, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
1707 break;
1708
1709 if ( Async.cAsync == cAsyncStart
1710 && !(pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_RESET_NOTIFICATION))
1711 pdmR3ResetDev(pVM, pDevIns, &Async);
1712 }
1713
1714#ifdef VBOX_WITH_USB
1715 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1716 {
1717 unsigned const cAsyncStart = Async.cAsync;
1718
1719 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1720 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1721 if (!pdmR3ResetDrv(pDrvIns, &Async, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
1722 break;
1723
1724 if (Async.cAsync == cAsyncStart)
1725 pdmR3ResetUsb(pUsbIns, &Async);
1726 }
1727#endif
1728 if (!Async.cAsync)
1729 break;
1730 pdmR3NotifyAsyncLog(&Async);
1731 pdmR3NotifyAsyncWaitAndProcessRequests(&Async, pVM);
1732 }
1733
1734 /*
1735 * Clear all pending interrupts and DMA operations.
1736 */
1737 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1738 PDMR3ResetCpu(pVM->apCpusR3[idCpu]);
1739 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
1740
1741 LogFlow(("PDMR3Reset: returns void\n"));
1742}
1743
1744
1745/**
1746 * This function will tell all the devices to setup up their memory structures
1747 * after VM construction and after VM reset.
1748 *
1749 * @param pVM The cross context VM structure.
1750 * @param fAtReset Indicates the context, after reset if @c true or after
1751 * construction if @c false.
1752 */
1753VMMR3_INT_DECL(void) PDMR3MemSetup(PVM pVM, bool fAtReset)
1754{
1755 LogFlow(("PDMR3MemSetup: fAtReset=%RTbool\n", fAtReset));
1756 PDMDEVMEMSETUPCTX const enmCtx = fAtReset ? PDMDEVMEMSETUPCTX_AFTER_RESET : PDMDEVMEMSETUPCTX_AFTER_CONSTRUCTION;
1757
1758 /*
1759 * Iterate thru the device instances and work the callback.
1760 */
1761 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1762 if (pDevIns->pReg->pfnMemSetup)
1763 {
1764 PDMCritSectEnter(pVM, pDevIns->pCritSectRoR3, VERR_IGNORED);
1765 pDevIns->pReg->pfnMemSetup(pDevIns, enmCtx);
1766 PDMCritSectLeave(pVM, pDevIns->pCritSectRoR3);
1767 }
1768
1769 LogFlow(("PDMR3MemSetup: returns void\n"));
1770}
1771
1772
1773/**
1774 * Retrieves and resets the info left behind by PDMDevHlpVMReset.
1775 *
1776 * @returns True if hard reset, false if soft reset.
1777 * @param pVM The cross context VM structure.
1778 * @param fOverride If non-zero, the override flags will be used instead
1779 * of the reset flags kept by PDM. (For triple faults.)
1780 * @param pfResetFlags Where to return the reset flags (PDMVMRESET_F_XXX).
1781 * @thread EMT
1782 */
1783VMMR3_INT_DECL(bool) PDMR3GetResetInfo(PVM pVM, uint32_t fOverride, uint32_t *pfResetFlags)
1784{
1785 VM_ASSERT_EMT(pVM);
1786
1787 /*
1788 * Get the reset flags.
1789 */
1790 uint32_t fResetFlags;
1791 fResetFlags = ASMAtomicXchgU32(&pVM->pdm.s.fResetFlags, 0);
1792 if (fOverride)
1793 fResetFlags = fOverride;
1794 *pfResetFlags = fResetFlags;
1795
1796 /*
1797 * To try avoid trouble, we never ever do soft/warm resets on SMP systems
1798 * with more than CPU #0 active. However, if only one CPU is active we
1799 * will ask the firmware what it wants us to do (because the firmware may
1800 * depend on the VMM doing a lot of what is normally its responsibility,
1801 * like clearing memory).
1802 */
1803 bool fOtherCpusActive = false;
1804 VMCPUID idCpu = pVM->cCpus;
1805 while (idCpu-- > 1)
1806 {
1807 EMSTATE enmState = EMGetState(pVM->apCpusR3[idCpu]);
1808 if ( enmState != EMSTATE_WAIT_SIPI
1809 && enmState != EMSTATE_NONE)
1810 {
1811 fOtherCpusActive = true;
1812 break;
1813 }
1814 }
1815
1816 bool fHardReset = fOtherCpusActive
1817 || (fResetFlags & PDMVMRESET_F_SRC_MASK) < PDMVMRESET_F_LAST_ALWAYS_HARD
1818 || !pVM->pdm.s.pFirmware
1819 || pVM->pdm.s.pFirmware->Reg.pfnIsHardReset(pVM->pdm.s.pFirmware->pDevIns, fResetFlags);
1820
1821 Log(("PDMR3GetResetInfo: returns fHardReset=%RTbool fResetFlags=%#x\n", fHardReset, fResetFlags));
1822 return fHardReset;
1823}
1824
1825
1826/**
1827 * Performs a soft reset of devices.
1828 *
1829 * @param pVM The cross context VM structure.
1830 * @param fResetFlags PDMVMRESET_F_XXX.
1831 */
1832VMMR3_INT_DECL(void) PDMR3SoftReset(PVM pVM, uint32_t fResetFlags)
1833{
1834 LogFlow(("PDMR3SoftReset: fResetFlags=%#x\n", fResetFlags));
1835
1836 /*
1837 * Iterate thru the device instances and work the callback.
1838 */
1839 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1840 if (pDevIns->pReg->pfnSoftReset)
1841 {
1842 PDMCritSectEnter(pVM, pDevIns->pCritSectRoR3, VERR_IGNORED);
1843 pDevIns->pReg->pfnSoftReset(pDevIns, fResetFlags);
1844 PDMCritSectLeave(pVM, pDevIns->pCritSectRoR3);
1845 }
1846
1847 LogFlow(("PDMR3SoftReset: returns void\n"));
1848}
1849
1850
1851/**
1852 * Worker for PDMR3Suspend that deals with one driver.
1853 *
1854 * @param pDrvIns The driver instance.
1855 * @param pAsync The structure for recording asynchronous
1856 * notification tasks.
1857 * @param pszDevName The parent device name.
1858 * @param iDevInstance The parent device instance number.
1859 * @param iLun The parent LUN number.
1860 */
1861DECLINLINE(bool) pdmR3SuspendDrv(PPDMDRVINS pDrvIns, PPDMNOTIFYASYNCSTATS pAsync,
1862 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1863{
1864 if (!pDrvIns->Internal.s.fVMSuspended)
1865 {
1866 pDrvIns->Internal.s.fVMSuspended = true;
1867 if (pDrvIns->pReg->pfnSuspend)
1868 {
1869 uint64_t cNsElapsed = RTTimeNanoTS();
1870
1871 if (!pDrvIns->Internal.s.pfnAsyncNotify)
1872 {
1873 LogFlow(("PDMR3Suspend: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1874 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1875 pDrvIns->pReg->pfnSuspend(pDrvIns);
1876 if (pDrvIns->Internal.s.pfnAsyncNotify)
1877 LogFlow(("PDMR3Suspend: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1878 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1879 }
1880 else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
1881 {
1882 LogFlow(("PDMR3Suspend: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1883 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1884 pDrvIns->Internal.s.pfnAsyncNotify = NULL;
1885 }
1886
1887 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1888 if (cNsElapsed >= PDMSUSPEND_WARN_AT_NS)
1889 LogRel(("PDMR3Suspend: Driver '%s'/%d on LUN#%d of device '%s'/%d took %'llu ns to suspend\n",
1890 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance, cNsElapsed));
1891
1892 if (pDrvIns->Internal.s.pfnAsyncNotify)
1893 {
1894 pDrvIns->Internal.s.fVMSuspended = false;
1895 pdmR3NotifyAsyncAddDrv(pAsync, pDrvIns->Internal.s.pDrv->pReg->szName, pDrvIns->iInstance, pszDevName, iDevInstance, iLun);
1896 return false;
1897 }
1898 }
1899 }
1900 return true;
1901}
1902
1903
1904/**
1905 * Worker for PDMR3Suspend that deals with one USB device instance.
1906 *
1907 * @param pUsbIns The USB device instance.
1908 * @param pAsync The structure for recording asynchronous
1909 * notification tasks.
1910 */
1911DECLINLINE(void) pdmR3SuspendUsb(PPDMUSBINS pUsbIns, PPDMNOTIFYASYNCSTATS pAsync)
1912{
1913 if (!pUsbIns->Internal.s.fVMSuspended)
1914 {
1915 pUsbIns->Internal.s.fVMSuspended = true;
1916 if (pUsbIns->pReg->pfnVMSuspend)
1917 {
1918 uint64_t cNsElapsed = RTTimeNanoTS();
1919
1920 if (!pUsbIns->Internal.s.pfnAsyncNotify)
1921 {
1922 LogFlow(("PDMR3Suspend: Notifying - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1923 pUsbIns->pReg->pfnVMSuspend(pUsbIns);
1924 if (pUsbIns->Internal.s.pfnAsyncNotify)
1925 LogFlow(("PDMR3Suspend: Async notification started - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1926 }
1927 else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
1928 {
1929 LogFlow(("PDMR3Suspend: Async notification completed - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1930 pUsbIns->Internal.s.pfnAsyncNotify = NULL;
1931 }
1932 if (pUsbIns->Internal.s.pfnAsyncNotify)
1933 {
1934 pUsbIns->Internal.s.fVMSuspended = false;
1935 pdmR3NotifyAsyncAdd(pAsync, pUsbIns->Internal.s.pUsbDev->pReg->szName, pUsbIns->iInstance);
1936 }
1937
1938 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1939 if (cNsElapsed >= PDMSUSPEND_WARN_AT_NS)
1940 LogRel(("PDMR3Suspend: USB device '%s'/%d took %'llu ns to suspend\n",
1941 pUsbIns->pReg->szName, pUsbIns->iInstance, cNsElapsed));
1942 }
1943 }
1944}
1945
1946
1947/**
1948 * Worker for PDMR3Suspend that deals with one device instance.
1949 *
1950 * @param pVM The cross context VM structure.
1951 * @param pDevIns The device instance.
1952 * @param pAsync The structure for recording asynchronous notification tasks.
1953 */
1954DECLINLINE(void) pdmR3SuspendDev(PVM pVM, PPDMDEVINS pDevIns, PPDMNOTIFYASYNCSTATS pAsync)
1955{
1956 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED))
1957 {
1958 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_SUSPENDED;
1959 if (pDevIns->pReg->pfnSuspend)
1960 {
1961 uint64_t cNsElapsed = RTTimeNanoTS();
1962 PDMCritSectEnter(pVM, pDevIns->pCritSectRoR3, VERR_IGNORED);
1963
1964 if (!pDevIns->Internal.s.pfnAsyncNotify)
1965 {
1966 LogFlow(("PDMR3Suspend: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1967 pDevIns->pReg->pfnSuspend(pDevIns);
1968 if (pDevIns->Internal.s.pfnAsyncNotify)
1969 LogFlow(("PDMR3Suspend: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1970 }
1971 else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
1972 {
1973 LogFlow(("PDMR3Suspend: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1974 pDevIns->Internal.s.pfnAsyncNotify = NULL;
1975 }
1976 if (pDevIns->Internal.s.pfnAsyncNotify)
1977 {
1978 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1979 pdmR3NotifyAsyncAdd(pAsync, pDevIns->Internal.s.pDevR3->pReg->szName, pDevIns->iInstance);
1980 }
1981
1982 PDMCritSectLeave(pVM, pDevIns->pCritSectRoR3);
1983 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
1984 if (cNsElapsed >= PDMSUSPEND_WARN_AT_NS)
1985 LogRel(("PDMR3Suspend: Device '%s'/%d took %'llu ns to suspend\n",
1986 pDevIns->pReg->szName, pDevIns->iInstance, cNsElapsed));
1987 }
1988 }
1989}
1990
1991
1992/**
1993 * This function will notify all the devices and their attached drivers about
1994 * the VM now being suspended.
1995 *
1996 * @param pVM The cross context VM structure.
1997 * @thread EMT(0)
1998 */
1999VMMR3_INT_DECL(void) PDMR3Suspend(PVM pVM)
2000{
2001 LogFlow(("PDMR3Suspend:\n"));
2002 VM_ASSERT_EMT0(pVM);
2003 uint64_t cNsElapsed = RTTimeNanoTS();
2004
2005 /*
2006 * The outer loop repeats until there are no more async requests.
2007 *
2008 * Note! We depend on the suspended indicators to be in the desired state
2009 * and we do not reset them before starting because this allows
2010 * PDMR3PowerOn and PDMR3Resume to use PDMR3Suspend for cleaning up
2011 * on failure.
2012 */
2013 PDMNOTIFYASYNCSTATS Async;
2014 pdmR3NotifyAsyncInit(&Async, "PDMR3Suspend");
2015 for (;;)
2016 {
2017 pdmR3NotifyAsyncBeginLoop(&Async);
2018
2019 /*
2020 * Iterate thru the device instances and USB device instances,
2021 * processing the drivers associated with those.
2022 *
2023 * The attached drivers are normally processed first. Some devices
2024 * (like DevAHCI) though needs to be notified before the drivers so
2025 * that it doesn't kick off any new requests after the drivers stopped
2026 * taking any. (DrvVD changes to read-only in this particular case.)
2027 */
2028 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2029 {
2030 unsigned const cAsyncStart = Async.cAsync;
2031
2032 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION)
2033 pdmR3SuspendDev(pVM, pDevIns, &Async);
2034
2035 if (Async.cAsync == cAsyncStart)
2036 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
2037 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2038 if (!pdmR3SuspendDrv(pDrvIns, &Async, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
2039 break;
2040
2041 if ( Async.cAsync == cAsyncStart
2042 && !(pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION))
2043 pdmR3SuspendDev(pVM, pDevIns, &Async);
2044 }
2045
2046#ifdef VBOX_WITH_USB
2047 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2048 {
2049 unsigned const cAsyncStart = Async.cAsync;
2050
2051 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
2052 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2053 if (!pdmR3SuspendDrv(pDrvIns, &Async, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
2054 break;
2055
2056 if (Async.cAsync == cAsyncStart)
2057 pdmR3SuspendUsb(pUsbIns, &Async);
2058 }
2059#endif
2060 if (!Async.cAsync)
2061 break;
2062 pdmR3NotifyAsyncLog(&Async);
2063 pdmR3NotifyAsyncWaitAndProcessRequests(&Async, pVM);
2064 }
2065
2066 /*
2067 * Suspend all threads.
2068 */
2069 pdmR3ThreadSuspendAll(pVM);
2070
2071 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
2072 LogRel(("PDMR3Suspend: %'llu ns run time\n", cNsElapsed));
2073}
2074
2075
2076/**
2077 * Worker for PDMR3Resume that deals with one driver.
2078 *
2079 * @param pDrvIns The driver instance.
2080 * @param pszDevName The parent device name.
2081 * @param iDevInstance The parent device instance number.
2082 * @param iLun The parent LUN number.
2083 */
2084DECLINLINE(int) pdmR3ResumeDrv(PPDMDRVINS pDrvIns, const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
2085{
2086 Assert(pDrvIns->Internal.s.fVMSuspended);
2087 if (pDrvIns->pReg->pfnResume)
2088 {
2089 LogFlow(("PDMR3Resume: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
2090 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
2091 int rc = VINF_SUCCESS; pDrvIns->pReg->pfnResume(pDrvIns);
2092 if (RT_FAILURE(rc))
2093 {
2094 LogRel(("PDMR3Resume: Driver '%s'/%d on LUN#%d of device '%s'/%d -> %Rrc\n",
2095 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance, rc));
2096 return rc;
2097 }
2098 }
2099 pDrvIns->Internal.s.fVMSuspended = false;
2100 return VINF_SUCCESS;
2101}
2102
2103
2104/**
2105 * Worker for PDMR3Resume that deals with one USB device instance.
2106 *
2107 * @returns VBox status code.
2108 * @param pUsbIns The USB device instance.
2109 */
2110DECLINLINE(int) pdmR3ResumeUsb(PPDMUSBINS pUsbIns)
2111{
2112 Assert(pUsbIns->Internal.s.fVMSuspended);
2113 if (pUsbIns->pReg->pfnVMResume)
2114 {
2115 LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
2116 int rc = VINF_SUCCESS; pUsbIns->pReg->pfnVMResume(pUsbIns);
2117 if (RT_FAILURE(rc))
2118 {
2119 LogRel(("PDMR3Resume: Device '%s'/%d -> %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
2120 return rc;
2121 }
2122 }
2123 pUsbIns->Internal.s.fVMSuspended = false;
2124 return VINF_SUCCESS;
2125}
2126
2127
2128/**
2129 * Worker for PDMR3Resume that deals with one device instance.
2130 *
2131 * @returns VBox status code.
2132 * @param pVM The cross context VM structure.
2133 * @param pDevIns The device instance.
2134 */
2135DECLINLINE(int) pdmR3ResumeDev(PVM pVM, PPDMDEVINS pDevIns)
2136{
2137 Assert(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED);
2138 if (pDevIns->pReg->pfnResume)
2139 {
2140 LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
2141 PDMCritSectEnter(pVM, pDevIns->pCritSectRoR3, VERR_IGNORED);
2142 int rc = VINF_SUCCESS; pDevIns->pReg->pfnResume(pDevIns);
2143 PDMCritSectLeave(pVM, pDevIns->pCritSectRoR3);
2144 if (RT_FAILURE(rc))
2145 {
2146 LogRel(("PDMR3Resume: Device '%s'/%d -> %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
2147 return rc;
2148 }
2149 }
2150 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
2151 return VINF_SUCCESS;
2152}
2153
2154
2155/**
2156 * This function will notify all the devices and their
2157 * attached drivers about the VM now being resumed.
2158 *
2159 * @param pVM The cross context VM structure.
2160 */
2161VMMR3_INT_DECL(void) PDMR3Resume(PVM pVM)
2162{
2163 LogFlow(("PDMR3Resume:\n"));
2164
2165 /*
2166 * Iterate thru the device instances and USB device instances,
2167 * processing the drivers associated with those.
2168 */
2169 int rc = VINF_SUCCESS;
2170 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns && RT_SUCCESS(rc); pDevIns = pDevIns->Internal.s.pNextR3)
2171 {
2172 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
2173 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
2174 rc = pdmR3ResumeDrv(pDrvIns, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun);
2175 if (RT_SUCCESS(rc))
2176 rc = pdmR3ResumeDev(pVM, pDevIns);
2177 }
2178
2179#ifdef VBOX_WITH_USB
2180 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns && RT_SUCCESS(rc); pUsbIns = pUsbIns->Internal.s.pNext)
2181 {
2182 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
2183 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
2184 rc = pdmR3ResumeDrv(pDrvIns, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun);
2185 if (RT_SUCCESS(rc))
2186 rc = pdmR3ResumeUsb(pUsbIns);
2187 }
2188#endif
2189
2190 /*
2191 * Resume all threads.
2192 */
2193 if (RT_SUCCESS(rc))
2194 pdmR3ThreadResumeAll(pVM);
2195
2196 /*
2197 * Resume the block cache.
2198 */
2199 if (RT_SUCCESS(rc))
2200 pdmR3BlkCacheResume(pVM);
2201
2202 /*
2203 * On failure, clean up via PDMR3Suspend.
2204 */
2205 if (RT_FAILURE(rc))
2206 PDMR3Suspend(pVM);
2207
2208 LogFlow(("PDMR3Resume: returns %Rrc\n", rc));
2209 return /*rc*/;
2210}
2211
2212
2213/**
2214 * Worker for PDMR3PowerOff that deals with one driver.
2215 *
2216 * @param pDrvIns The driver instance.
2217 * @param pAsync The structure for recording asynchronous
2218 * notification tasks.
2219 * @param pszDevName The parent device name.
2220 * @param iDevInstance The parent device instance number.
2221 * @param iLun The parent LUN number.
2222 */
2223DECLINLINE(bool) pdmR3PowerOffDrv(PPDMDRVINS pDrvIns, PPDMNOTIFYASYNCSTATS pAsync,
2224 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
2225{
2226 if (!pDrvIns->Internal.s.fVMSuspended)
2227 {
2228 pDrvIns->Internal.s.fVMSuspended = true;
2229 if (pDrvIns->pReg->pfnPowerOff)
2230 {
2231 uint64_t cNsElapsed = RTTimeNanoTS();
2232
2233 if (!pDrvIns->Internal.s.pfnAsyncNotify)
2234 {
2235 LogFlow(("PDMR3PowerOff: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
2236 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
2237 pDrvIns->pReg->pfnPowerOff(pDrvIns);
2238 if (pDrvIns->Internal.s.pfnAsyncNotify)
2239 LogFlow(("PDMR3PowerOff: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
2240 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
2241 }
2242 else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
2243 {
2244 LogFlow(("PDMR3PowerOff: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
2245 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
2246 pDrvIns->Internal.s.pfnAsyncNotify = NULL;
2247 }
2248
2249 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
2250 if (cNsElapsed >= PDMPOWEROFF_WARN_AT_NS)
2251 LogRel(("PDMR3PowerOff: Driver '%s'/%d on LUN#%d of device '%s'/%d took %'llu ns to power off\n",
2252 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance, cNsElapsed));
2253
2254 if (pDrvIns->Internal.s.pfnAsyncNotify)
2255 {
2256 pDrvIns->Internal.s.fVMSuspended = false;
2257 pdmR3NotifyAsyncAddDrv(pAsync, pDrvIns->Internal.s.pDrv->pReg->szName, pDrvIns->iInstance,
2258 pszDevName, iDevInstance, iLun);
2259 return false;
2260 }
2261 }
2262 }
2263 return true;
2264}
2265
2266
2267/**
2268 * Worker for PDMR3PowerOff that deals with one USB device instance.
2269 *
2270 * @param pUsbIns The USB device instance.
2271 * @param pAsync The structure for recording asynchronous
2272 * notification tasks.
2273 */
2274DECLINLINE(void) pdmR3PowerOffUsb(PPDMUSBINS pUsbIns, PPDMNOTIFYASYNCSTATS pAsync)
2275{
2276 if (!pUsbIns->Internal.s.fVMSuspended)
2277 {
2278 pUsbIns->Internal.s.fVMSuspended = true;
2279 if (pUsbIns->pReg->pfnVMPowerOff)
2280 {
2281 uint64_t cNsElapsed = RTTimeNanoTS();
2282
2283 if (!pUsbIns->Internal.s.pfnAsyncNotify)
2284 {
2285 LogFlow(("PDMR3PowerOff: Notifying - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
2286 pUsbIns->pReg->pfnVMPowerOff(pUsbIns);
2287 if (pUsbIns->Internal.s.pfnAsyncNotify)
2288 LogFlow(("PDMR3PowerOff: Async notification started - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
2289 }
2290 else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
2291 {
2292 LogFlow(("PDMR3PowerOff: Async notification completed - USB device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
2293 pUsbIns->Internal.s.pfnAsyncNotify = NULL;
2294 }
2295 if (pUsbIns->Internal.s.pfnAsyncNotify)
2296 {
2297 pUsbIns->Internal.s.fVMSuspended = false;
2298 pdmR3NotifyAsyncAdd(pAsync, pUsbIns->Internal.s.pUsbDev->pReg->szName, pUsbIns->iInstance);
2299 }
2300
2301 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
2302 if (cNsElapsed >= PDMPOWEROFF_WARN_AT_NS)
2303 LogRel(("PDMR3PowerOff: USB device '%s'/%d took %'llu ns to power off\n",
2304 pUsbIns->pReg->szName, pUsbIns->iInstance, cNsElapsed));
2305
2306 }
2307 }
2308}
2309
2310
2311/**
2312 * Worker for PDMR3PowerOff that deals with one device instance.
2313 *
2314 * @param pVM The cross context VM structure.
2315 * @param pDevIns The device instance.
2316 * @param pAsync The structure for recording asynchronous notification tasks.
2317 */
2318DECLINLINE(void) pdmR3PowerOffDev(PVM pVM, PPDMDEVINS pDevIns, PPDMNOTIFYASYNCSTATS pAsync)
2319{
2320 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED))
2321 {
2322 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_SUSPENDED;
2323 if (pDevIns->pReg->pfnPowerOff)
2324 {
2325 uint64_t cNsElapsed = RTTimeNanoTS();
2326 PDMCritSectEnter(pVM, pDevIns->pCritSectRoR3, VERR_IGNORED);
2327
2328 if (!pDevIns->Internal.s.pfnAsyncNotify)
2329 {
2330 LogFlow(("PDMR3PowerOff: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
2331 pDevIns->pReg->pfnPowerOff(pDevIns);
2332 if (pDevIns->Internal.s.pfnAsyncNotify)
2333 LogFlow(("PDMR3PowerOff: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
2334 }
2335 else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
2336 {
2337 LogFlow(("PDMR3PowerOff: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
2338 pDevIns->Internal.s.pfnAsyncNotify = NULL;
2339 }
2340 if (pDevIns->Internal.s.pfnAsyncNotify)
2341 {
2342 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
2343 pdmR3NotifyAsyncAdd(pAsync, pDevIns->Internal.s.pDevR3->pReg->szName, pDevIns->iInstance);
2344 }
2345
2346 PDMCritSectLeave(pVM, pDevIns->pCritSectRoR3);
2347 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
2348 if (cNsElapsed >= PDMPOWEROFF_WARN_AT_NS)
2349 LogFlow(("PDMR3PowerOff: Device '%s'/%d took %'llu ns to power off\n",
2350 pDevIns->pReg->szName, pDevIns->iInstance, cNsElapsed));
2351 }
2352 }
2353}
2354
2355
2356/**
2357 * This function will notify all the devices and their
2358 * attached drivers about the VM being powered off.
2359 *
2360 * @param pVM The cross context VM structure.
2361 */
2362VMMR3DECL(void) PDMR3PowerOff(PVM pVM)
2363{
2364 LogFlow(("PDMR3PowerOff:\n"));
2365 uint64_t cNsElapsed = RTTimeNanoTS();
2366
2367 /*
2368 * Clear the suspended flags on all devices and drivers first because they
2369 * might have been set during a suspend but the power off callbacks should
2370 * be called in any case.
2371 */
2372 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2373 {
2374 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
2375
2376 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
2377 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2378 pDrvIns->Internal.s.fVMSuspended = false;
2379 }
2380
2381#ifdef VBOX_WITH_USB
2382 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2383 {
2384 pUsbIns->Internal.s.fVMSuspended = false;
2385
2386 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
2387 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2388 pDrvIns->Internal.s.fVMSuspended = false;
2389 }
2390#endif
2391
2392 /*
2393 * The outer loop repeats until there are no more async requests.
2394 */
2395 PDMNOTIFYASYNCSTATS Async;
2396 pdmR3NotifyAsyncInit(&Async, "PDMR3PowerOff");
2397 for (;;)
2398 {
2399 pdmR3NotifyAsyncBeginLoop(&Async);
2400
2401 /*
2402 * Iterate thru the device instances and USB device instances,
2403 * processing the drivers associated with those.
2404 *
2405 * The attached drivers are normally processed first. Some devices
2406 * (like DevAHCI) though needs to be notified before the drivers so
2407 * that it doesn't kick off any new requests after the drivers stopped
2408 * taking any. (DrvVD changes to read-only in this particular case.)
2409 */
2410 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2411 {
2412 unsigned const cAsyncStart = Async.cAsync;
2413
2414 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION)
2415 pdmR3PowerOffDev(pVM, pDevIns, &Async);
2416
2417 if (Async.cAsync == cAsyncStart)
2418 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
2419 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2420 if (!pdmR3PowerOffDrv(pDrvIns, &Async, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
2421 break;
2422
2423 if ( Async.cAsync == cAsyncStart
2424 && !(pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION))
2425 pdmR3PowerOffDev(pVM, pDevIns, &Async);
2426 }
2427
2428#ifdef VBOX_WITH_USB
2429 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2430 {
2431 unsigned const cAsyncStart = Async.cAsync;
2432
2433 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
2434 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2435 if (!pdmR3PowerOffDrv(pDrvIns, &Async, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
2436 break;
2437
2438 if (Async.cAsync == cAsyncStart)
2439 pdmR3PowerOffUsb(pUsbIns, &Async);
2440 }
2441#endif
2442 if (!Async.cAsync)
2443 break;
2444 pdmR3NotifyAsyncLog(&Async);
2445 pdmR3NotifyAsyncWaitAndProcessRequests(&Async, pVM);
2446 }
2447
2448 /*
2449 * Suspend all threads.
2450 */
2451 pdmR3ThreadSuspendAll(pVM);
2452
2453 cNsElapsed = RTTimeNanoTS() - cNsElapsed;
2454 LogRel(("PDMR3PowerOff: %'llu ns run time\n", cNsElapsed));
2455}
2456
2457
2458/**
2459 * Queries the base interface of a device instance.
2460 *
2461 * The caller can use this to query other interfaces the device implements
2462 * and use them to talk to the device.
2463 *
2464 * @returns VBox status code.
2465 * @param pUVM The user mode VM handle.
2466 * @param pszDevice Device name.
2467 * @param iInstance Device instance.
2468 * @param ppBase Where to store the pointer to the base device interface on success.
2469 * @remark We're not doing any locking ATM, so don't try call this at times when the
2470 * device chain is known to be updated.
2471 */
2472VMMR3DECL(int) PDMR3QueryDevice(PUVM pUVM, const char *pszDevice, unsigned iInstance, PPDMIBASE *ppBase)
2473{
2474 LogFlow(("PDMR3DeviceQuery: pszDevice=%p:{%s} iInstance=%u ppBase=%p\n", pszDevice, pszDevice, iInstance, ppBase));
2475 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
2476 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
2477
2478 /*
2479 * Iterate registered devices looking for the device.
2480 */
2481 size_t cchDevice = strlen(pszDevice);
2482 for (PPDMDEV pDev = pUVM->pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
2483 {
2484 if ( pDev->cchName == cchDevice
2485 && !memcmp(pDev->pReg->szName, pszDevice, cchDevice))
2486 {
2487 /*
2488 * Iterate device instances.
2489 */
2490 for (PPDMDEVINS pDevIns = pDev->pInstances; pDevIns; pDevIns = pDevIns->Internal.s.pPerDeviceNextR3)
2491 {
2492 if (pDevIns->iInstance == iInstance)
2493 {
2494 if (pDevIns->IBase.pfnQueryInterface)
2495 {
2496 *ppBase = &pDevIns->IBase;
2497 LogFlow(("PDMR3DeviceQuery: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
2498 return VINF_SUCCESS;
2499 }
2500
2501 LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NO_IBASE\n"));
2502 return VERR_PDM_DEVICE_INSTANCE_NO_IBASE;
2503 }
2504 }
2505
2506 LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NOT_FOUND\n"));
2507 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND;
2508 }
2509 }
2510
2511 LogFlow(("PDMR3QueryDevice: returns VERR_PDM_DEVICE_NOT_FOUND\n"));
2512 return VERR_PDM_DEVICE_NOT_FOUND;
2513}
2514
2515
2516/**
2517 * Queries the base interface of a device LUN.
2518 *
2519 * This differs from PDMR3QueryLun by that it returns the interface on the
2520 * device and not the top level driver.
2521 *
2522 * @returns VBox status code.
2523 * @param pUVM The user mode VM handle.
2524 * @param pszDevice Device name.
2525 * @param iInstance Device instance.
2526 * @param iLun The Logical Unit to obtain the interface of.
2527 * @param ppBase Where to store the base interface pointer.
2528 * @remark We're not doing any locking ATM, so don't try call this at times when the
2529 * device chain is known to be updated.
2530 */
2531VMMR3DECL(int) PDMR3QueryDeviceLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
2532{
2533 LogFlow(("PDMR3QueryDeviceLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
2534 pszDevice, pszDevice, iInstance, iLun, ppBase));
2535 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
2536 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
2537
2538 /*
2539 * Find the LUN.
2540 */
2541 PPDMLUN pLun;
2542 int rc = pdmR3DevFindLun(pUVM->pVM, pszDevice, iInstance, iLun, &pLun);
2543 if (RT_SUCCESS(rc))
2544 {
2545 *ppBase = pLun->pBase;
2546 LogFlow(("PDMR3QueryDeviceLun: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
2547 return VINF_SUCCESS;
2548 }
2549 LogFlow(("PDMR3QueryDeviceLun: returns %Rrc\n", rc));
2550 return rc;
2551}
2552
2553
2554/**
2555 * Query the interface of the top level driver on a LUN.
2556 *
2557 * @returns VBox status code.
2558 * @param pUVM The user mode VM handle.
2559 * @param pszDevice Device name.
2560 * @param iInstance Device instance.
2561 * @param iLun The Logical Unit to obtain the interface of.
2562 * @param ppBase Where to store the base interface pointer.
2563 * @remark We're not doing any locking ATM, so don't try call this at times when the
2564 * device chain is known to be updated.
2565 */
2566VMMR3DECL(int) PDMR3QueryLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
2567{
2568 LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
2569 pszDevice, pszDevice, iInstance, iLun, ppBase));
2570 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
2571 PVM pVM = pUVM->pVM;
2572 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
2573
2574 /*
2575 * Find the LUN.
2576 */
2577 PPDMLUN pLun;
2578 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
2579 if (RT_SUCCESS(rc))
2580 {
2581 if (pLun->pTop)
2582 {
2583 *ppBase = &pLun->pTop->IBase;
2584 LogFlow(("PDMR3QueryLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
2585 return VINF_SUCCESS;
2586 }
2587 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
2588 }
2589 LogFlow(("PDMR3QueryLun: returns %Rrc\n", rc));
2590 return rc;
2591}
2592
2593
2594/**
2595 * Query the interface of a named driver on a LUN.
2596 *
2597 * If the driver appears more than once in the driver chain, the first instance
2598 * is returned.
2599 *
2600 * @returns VBox status code.
2601 * @param pUVM The user mode VM handle.
2602 * @param pszDevice Device name.
2603 * @param iInstance Device instance.
2604 * @param iLun The Logical Unit to obtain the interface of.
2605 * @param pszDriver The driver name.
2606 * @param ppBase Where to store the base interface pointer.
2607 *
2608 * @remark We're not doing any locking ATM, so don't try call this at times when the
2609 * device chain is known to be updated.
2610 */
2611VMMR3DECL(int) PDMR3QueryDriverOnLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, const char *pszDriver, PPPDMIBASE ppBase)
2612{
2613 LogFlow(("PDMR3QueryDriverOnLun: pszDevice=%p:{%s} iInstance=%u iLun=%u pszDriver=%p:{%s} ppBase=%p\n",
2614 pszDevice, pszDevice, iInstance, iLun, pszDriver, pszDriver, ppBase));
2615 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
2616 VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
2617
2618 /*
2619 * Find the LUN.
2620 */
2621 PPDMLUN pLun;
2622 int rc = pdmR3DevFindLun(pUVM->pVM, pszDevice, iInstance, iLun, &pLun);
2623 if (RT_SUCCESS(rc))
2624 {
2625 if (pLun->pTop)
2626 {
2627 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2628 if (!strcmp(pDrvIns->pReg->szName, pszDriver))
2629 {
2630 *ppBase = &pDrvIns->IBase;
2631 LogFlow(("PDMR3QueryDriverOnLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
2632 return VINF_SUCCESS;
2633
2634 }
2635 rc = VERR_PDM_DRIVER_NOT_FOUND;
2636 }
2637 else
2638 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
2639 }
2640 LogFlow(("PDMR3QueryDriverOnLun: returns %Rrc\n", rc));
2641 return rc;
2642}
2643
2644/**
2645 * Executes pending DMA transfers.
2646 * Forced Action handler.
2647 *
2648 * @param pVM The cross context VM structure.
2649 */
2650VMMR3DECL(void) PDMR3DmaRun(PVM pVM)
2651{
2652 /* Note! Not really SMP safe; restrict it to VCPU 0. */
2653 if (VMMGetCpuId(pVM) != 0)
2654 return;
2655
2656 if (VM_FF_TEST_AND_CLEAR(pVM, VM_FF_PDM_DMA))
2657 {
2658 if (pVM->pdm.s.pDmac)
2659 {
2660 bool fMore = pVM->pdm.s.pDmac->Reg.pfnRun(pVM->pdm.s.pDmac->pDevIns);
2661 if (fMore)
2662 VM_FF_SET(pVM, VM_FF_PDM_DMA);
2663 }
2664 }
2665}
2666
2667
2668/**
2669 * Service a VMMCALLRING3_PDM_LOCK call.
2670 *
2671 * @returns VBox status code.
2672 * @param pVM The cross context VM structure.
2673 */
2674VMMR3_INT_DECL(int) PDMR3LockCall(PVM pVM)
2675{
2676 return PDMR3CritSectEnterEx(pVM, &pVM->pdm.s.CritSect, true /* fHostCall */);
2677}
2678
2679
2680/**
2681 * Allocates memory from the VMM device heap.
2682 *
2683 * @returns VBox status code.
2684 * @param pVM The cross context VM structure.
2685 * @param cbSize Allocation size.
2686 * @param pfnNotify Mapping/unmapping notification callback.
2687 * @param ppv Ring-3 pointer. (out)
2688 */
2689VMMR3_INT_DECL(int) PDMR3VmmDevHeapAlloc(PVM pVM, size_t cbSize, PFNPDMVMMDEVHEAPNOTIFY pfnNotify, RTR3PTR *ppv)
2690{
2691#ifdef DEBUG_bird
2692 if (!cbSize || cbSize > pVM->pdm.s.cbVMMDevHeapLeft)
2693 return VERR_NO_MEMORY;
2694#else
2695 AssertReturn(cbSize && cbSize <= pVM->pdm.s.cbVMMDevHeapLeft, VERR_NO_MEMORY);
2696#endif
2697
2698 Log(("PDMR3VMMDevHeapAlloc: %#zx\n", cbSize));
2699
2700 /** @todo Not a real heap as there's currently only one user. */
2701 *ppv = pVM->pdm.s.pvVMMDevHeap;
2702 pVM->pdm.s.cbVMMDevHeapLeft = 0;
2703 pVM->pdm.s.pfnVMMDevHeapNotify = pfnNotify;
2704 return VINF_SUCCESS;
2705}
2706
2707
2708/**
2709 * Frees memory from the VMM device heap
2710 *
2711 * @returns VBox status code.
2712 * @param pVM The cross context VM structure.
2713 * @param pv Ring-3 pointer.
2714 */
2715VMMR3_INT_DECL(int) PDMR3VmmDevHeapFree(PVM pVM, RTR3PTR pv)
2716{
2717 Log(("PDMR3VmmDevHeapFree: %RHv\n", pv)); RT_NOREF_PV(pv);
2718
2719 /** @todo not a real heap as there's currently only one user. */
2720 pVM->pdm.s.cbVMMDevHeapLeft = pVM->pdm.s.cbVMMDevHeap;
2721 pVM->pdm.s.pfnVMMDevHeapNotify = NULL;
2722 return VINF_SUCCESS;
2723}
2724
2725
2726/**
2727 * Worker for DBGFR3TraceConfig that checks if the given tracing group name
2728 * matches a device or driver name and applies the tracing config change.
2729 *
2730 * @returns VINF_SUCCESS or VERR_NOT_FOUND.
2731 * @param pVM The cross context VM structure.
2732 * @param pszName The tracing config group name. This is NULL if
2733 * the operation applies to every device and
2734 * driver.
2735 * @param cchName The length to match.
2736 * @param fEnable Whether to enable or disable the corresponding
2737 * trace points.
2738 * @param fApply Whether to actually apply the changes or just do
2739 * existence checks.
2740 */
2741VMMR3_INT_DECL(int) PDMR3TracingConfig(PVM pVM, const char *pszName, size_t cchName, bool fEnable, bool fApply)
2742{
2743 /** @todo This code is potentially racing driver attaching and detaching. */
2744
2745 /*
2746 * Applies to all.
2747 */
2748 if (pszName == NULL)
2749 {
2750 AssertReturn(fApply, VINF_SUCCESS);
2751
2752 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2753 {
2754 pDevIns->fTracing = fEnable;
2755 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
2756 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2757 pDrvIns->fTracing = fEnable;
2758 }
2759
2760#ifdef VBOX_WITH_USB
2761 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2762 {
2763 pUsbIns->fTracing = fEnable;
2764 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
2765 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2766 pDrvIns->fTracing = fEnable;
2767
2768 }
2769#endif
2770 return VINF_SUCCESS;
2771 }
2772
2773 /*
2774 * Specific devices, USB devices or drivers.
2775 * Decode prefix to figure which of these it applies to.
2776 */
2777 if (cchName <= 3)
2778 return VERR_NOT_FOUND;
2779
2780 uint32_t cMatches = 0;
2781 if (!strncmp("dev", pszName, 3))
2782 {
2783 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2784 {
2785 const char *pszDevName = pDevIns->Internal.s.pDevR3->pReg->szName;
2786 size_t cchDevName = strlen(pszDevName);
2787 if ( ( cchDevName == cchName
2788 && RTStrNICmp(pszName, pszDevName, cchDevName))
2789 || ( cchDevName == cchName - 3
2790 && RTStrNICmp(pszName + 3, pszDevName, cchDevName)) )
2791 {
2792 cMatches++;
2793 if (fApply)
2794 pDevIns->fTracing = fEnable;
2795 }
2796 }
2797 }
2798 else if (!strncmp("usb", pszName, 3))
2799 {
2800 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2801 {
2802 const char *pszUsbName = pUsbIns->Internal.s.pUsbDev->pReg->szName;
2803 size_t cchUsbName = strlen(pszUsbName);
2804 if ( ( cchUsbName == cchName
2805 && RTStrNICmp(pszName, pszUsbName, cchUsbName))
2806 || ( cchUsbName == cchName - 3
2807 && RTStrNICmp(pszName + 3, pszUsbName, cchUsbName)) )
2808 {
2809 cMatches++;
2810 if (fApply)
2811 pUsbIns->fTracing = fEnable;
2812 }
2813 }
2814 }
2815 else if (!strncmp("drv", pszName, 3))
2816 {
2817 AssertReturn(fApply, VINF_SUCCESS);
2818
2819 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2820 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
2821 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2822 {
2823 const char *pszDrvName = pDrvIns->Internal.s.pDrv->pReg->szName;
2824 size_t cchDrvName = strlen(pszDrvName);
2825 if ( ( cchDrvName == cchName
2826 && RTStrNICmp(pszName, pszDrvName, cchDrvName))
2827 || ( cchDrvName == cchName - 3
2828 && RTStrNICmp(pszName + 3, pszDrvName, cchDrvName)) )
2829 {
2830 cMatches++;
2831 if (fApply)
2832 pDrvIns->fTracing = fEnable;
2833 }
2834 }
2835
2836#ifdef VBOX_WITH_USB
2837 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2838 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
2839 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2840 {
2841 const char *pszDrvName = pDrvIns->Internal.s.pDrv->pReg->szName;
2842 size_t cchDrvName = strlen(pszDrvName);
2843 if ( ( cchDrvName == cchName
2844 && RTStrNICmp(pszName, pszDrvName, cchDrvName))
2845 || ( cchDrvName == cchName - 3
2846 && RTStrNICmp(pszName + 3, pszDrvName, cchDrvName)) )
2847 {
2848 cMatches++;
2849 if (fApply)
2850 pDrvIns->fTracing = fEnable;
2851 }
2852 }
2853#endif
2854 }
2855 else
2856 return VERR_NOT_FOUND;
2857
2858 return cMatches > 0 ? VINF_SUCCESS : VERR_NOT_FOUND;
2859}
2860
2861
2862/**
2863 * Worker for DBGFR3TraceQueryConfig that checks whether all drivers, devices,
2864 * and USB device have the same tracing settings.
2865 *
2866 * @returns true / false.
2867 * @param pVM The cross context VM structure.
2868 * @param fEnabled The tracing setting to check for.
2869 */
2870VMMR3_INT_DECL(bool) PDMR3TracingAreAll(PVM pVM, bool fEnabled)
2871{
2872 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2873 {
2874 if (pDevIns->fTracing != (uint32_t)fEnabled)
2875 return false;
2876
2877 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
2878 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2879 if (pDrvIns->fTracing != (uint32_t)fEnabled)
2880 return false;
2881 }
2882
2883#ifdef VBOX_WITH_USB
2884 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2885 {
2886 if (pUsbIns->fTracing != (uint32_t)fEnabled)
2887 return false;
2888
2889 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
2890 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2891 if (pDrvIns->fTracing != (uint32_t)fEnabled)
2892 return false;
2893 }
2894#endif
2895
2896 return true;
2897}
2898
2899
2900/**
2901 * Worker for PDMR3TracingQueryConfig that adds a prefixed name to the output
2902 * string.
2903 *
2904 * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW
2905 * @param ppszDst The pointer to the output buffer pointer.
2906 * @param pcbDst The pointer to the output buffer size.
2907 * @param fSpace Whether to add a space before the name.
2908 * @param pszPrefix The name prefix.
2909 * @param pszName The name.
2910 */
2911static int pdmR3TracingAdd(char **ppszDst, size_t *pcbDst, bool fSpace, const char *pszPrefix, const char *pszName)
2912{
2913 size_t const cchPrefix = strlen(pszPrefix);
2914 if (!RTStrNICmp(pszPrefix, pszName, cchPrefix))
2915 pszName += cchPrefix;
2916 size_t const cchName = strlen(pszName);
2917
2918 size_t const cchThis = cchName + cchPrefix + fSpace;
2919 if (cchThis >= *pcbDst)
2920 return VERR_BUFFER_OVERFLOW;
2921 if (fSpace)
2922 {
2923 **ppszDst = ' ';
2924 memcpy(*ppszDst + 1, pszPrefix, cchPrefix);
2925 memcpy(*ppszDst + 1 + cchPrefix, pszName, cchName + 1);
2926 }
2927 else
2928 {
2929 memcpy(*ppszDst, pszPrefix, cchPrefix);
2930 memcpy(*ppszDst + cchPrefix, pszName, cchName + 1);
2931 }
2932 *ppszDst += cchThis;
2933 *pcbDst -= cchThis;
2934 return VINF_SUCCESS;
2935}
2936
2937
2938/**
2939 * Worker for DBGFR3TraceQueryConfig use when not everything is either enabled
2940 * or disabled.
2941 *
2942 * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW
2943 * @param pVM The cross context VM structure.
2944 * @param pszConfig Where to store the config spec.
2945 * @param cbConfig The size of the output buffer.
2946 */
2947VMMR3_INT_DECL(int) PDMR3TracingQueryConfig(PVM pVM, char *pszConfig, size_t cbConfig)
2948{
2949 int rc;
2950 char *pszDst = pszConfig;
2951 size_t cbDst = cbConfig;
2952
2953 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
2954 {
2955 if (pDevIns->fTracing)
2956 {
2957 rc = pdmR3TracingAdd(&pszDst, &cbDst, pszDst != pszConfig, "dev", pDevIns->Internal.s.pDevR3->pReg->szName);
2958 if (RT_FAILURE(rc))
2959 return rc;
2960 }
2961
2962 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
2963 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2964 if (pDrvIns->fTracing)
2965 {
2966 rc = pdmR3TracingAdd(&pszDst, &cbDst, pszDst != pszConfig, "drv", pDrvIns->Internal.s.pDrv->pReg->szName);
2967 if (RT_FAILURE(rc))
2968 return rc;
2969 }
2970 }
2971
2972#ifdef VBOX_WITH_USB
2973 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
2974 {
2975 if (pUsbIns->fTracing)
2976 {
2977 rc = pdmR3TracingAdd(&pszDst, &cbDst, pszDst != pszConfig, "usb", pUsbIns->Internal.s.pUsbDev->pReg->szName);
2978 if (RT_FAILURE(rc))
2979 return rc;
2980 }
2981
2982 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
2983 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2984 if (pDrvIns->fTracing)
2985 {
2986 rc = pdmR3TracingAdd(&pszDst, &cbDst, pszDst != pszConfig, "drv", pDrvIns->Internal.s.pDrv->pReg->szName);
2987 if (RT_FAILURE(rc))
2988 return rc;
2989 }
2990 }
2991#endif
2992
2993 return VINF_SUCCESS;
2994}
2995
2996
2997/**
2998 * Checks that a PDMDRVREG::szName, PDMDEVREG::szName or PDMUSBREG::szName
2999 * field contains only a limited set of ASCII characters.
3000 *
3001 * @returns true / false.
3002 * @param pszName The name to validate.
3003 */
3004bool pdmR3IsValidName(const char *pszName)
3005{
3006 char ch;
3007 while ( (ch = *pszName) != '\0'
3008 && ( RT_C_IS_ALNUM(ch)
3009 || ch == '-'
3010 || ch == ' ' /** @todo disallow this! */
3011 || ch == '_') )
3012 pszName++;
3013 return ch == '\0';
3014}
3015
3016
3017/**
3018 * Info handler for 'pdmtracingids'.
3019 *
3020 * @param pVM The cross context VM structure.
3021 * @param pHlp The output helpers.
3022 * @param pszArgs The optional user arguments.
3023 *
3024 * @remarks Can be called on most threads.
3025 */
3026static DECLCALLBACK(void) pdmR3InfoTracingIds(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
3027{
3028 /*
3029 * Parse the argument (optional).
3030 */
3031 if ( pszArgs
3032 && *pszArgs
3033 && strcmp(pszArgs, "all")
3034 && strcmp(pszArgs, "devices")
3035 && strcmp(pszArgs, "drivers")
3036 && strcmp(pszArgs, "usb"))
3037 {
3038 pHlp->pfnPrintf(pHlp, "Unable to grok '%s'\n", pszArgs);
3039 return;
3040 }
3041 bool fAll = !pszArgs || !*pszArgs || !strcmp(pszArgs, "all");
3042 bool fDevices = fAll || !strcmp(pszArgs, "devices");
3043 bool fUsbDevs = fAll || !strcmp(pszArgs, "usb");
3044 bool fDrivers = fAll || !strcmp(pszArgs, "drivers");
3045
3046 /*
3047 * Produce the requested output.
3048 */
3049/** @todo lock PDM lists! */
3050 /* devices */
3051 if (fDevices)
3052 {
3053 pHlp->pfnPrintf(pHlp, "Device tracing IDs:\n");
3054 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
3055 pHlp->pfnPrintf(pHlp, "%05u %s\n", pDevIns->idTracing, pDevIns->Internal.s.pDevR3->pReg->szName);
3056 }
3057
3058 /* USB devices */
3059 if (fUsbDevs)
3060 {
3061 pHlp->pfnPrintf(pHlp, "USB device tracing IDs:\n");
3062 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
3063 pHlp->pfnPrintf(pHlp, "%05u %s\n", pUsbIns->idTracing, pUsbIns->Internal.s.pUsbDev->pReg->szName);
3064 }
3065
3066 /* Drivers */
3067 if (fDrivers)
3068 {
3069 pHlp->pfnPrintf(pHlp, "Driver tracing IDs:\n");
3070 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
3071 {
3072 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
3073 {
3074 uint32_t iLevel = 0;
3075 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown, iLevel++)
3076 pHlp->pfnPrintf(pHlp, "%05u %s (level %u, lun %u, dev %s)\n",
3077 pDrvIns->idTracing, pDrvIns->Internal.s.pDrv->pReg->szName,
3078 iLevel, pLun->iLun, pDevIns->Internal.s.pDevR3->pReg->szName);
3079 }
3080 }
3081
3082 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
3083 {
3084 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
3085 {
3086 uint32_t iLevel = 0;
3087 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown, iLevel++)
3088 pHlp->pfnPrintf(pHlp, "%05u %s (level %u, lun %u, dev %s)\n",
3089 pDrvIns->idTracing, pDrvIns->Internal.s.pDrv->pReg->szName,
3090 iLevel, pLun->iLun, pUsbIns->Internal.s.pUsbDev->pReg->szName);
3091 }
3092 }
3093 }
3094}
3095
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