VirtualBox

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

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

Copyright year updates by scm.

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