VirtualBox

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

Last change on this file since 99576 was 99576, checked in by vboxsync, 19 months ago

VMM: Preparations for getting interrupts injected into the guest. With ARMv8 there are two types of interrupts (normal interrupts and fast interrupts) which need to be mapped to forced action flags. Because the PIC and APIC flags are not needed those are mapped to IRQs and FIQs on ARM respectively, bugref:10389

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