VirtualBox

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

Last change on this file since 50653 was 49814, checked in by vboxsync, 10 years ago

Devices/USB: First part of the rework, move most of the work to dedicated threads to improve performance

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

© 2023 Oracle
ContactPrivacy policyTerms of Use