VirtualBox

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

Last change on this file since 37503 was 37466, checked in by vboxsync, 14 years ago

VMM,Devices: Automatically use a per-device lock instead of the giant IOM lock. With exception of the PIC, APIC, IOAPIC and PCI buses which are all using the PDM crit sect, there should be no calls between devices. So, this change should be relatively safe.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 81.8 KB
Line 
1/* $Id: PDM.cpp 37466 2011-06-15 12:44:16Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device Manager.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/** @page pg_pdm PDM - The Pluggable Device & Driver Manager
20 *
21 * VirtualBox is designed to be very configurable, i.e. the ability to select
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
24 * instantiated at runtime by PDM using the information found in the
25 * Configuration Manager (CFGM).
26 *
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.
31 *
32 * @see grp_pdm
33 *
34 *
35 * @section sec_pdm_dev The Pluggable Devices
36 *
37 * Devices register themselves when the module containing them is loaded. PDM
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
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
42 * organize device and device instance settings) and by anyone who wants to talk
43 * to a specific device instance.
44 *
45 * When all device modules have been successfully loaded PDM will instantiate
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.
51 *
52 * Some devices are trusted devices, most are not. The trusted devices are an
53 * integrated part of the VM and can obtain the VM handle from their device
54 * instance handles, thus enabling them to call any VM api. Untrusted devices
55 * can only use the callbacks provided during device instantiation.
56 *
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
59 * create a binary interface that can be supported across releases and to
60 * create a barrier between devices and the VM. (The trusted / untrusted bit
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.)
63 *
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
66 * requiring context switches (to ring-3). Callbacks for MMIO and I/O ports can
67 * needs to be registered specifically for the additional contexts for this to
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
70 * will be subject to relocation.
71 *
72 *
73 * @section sec_pdm_special_devs Special Devices
74 *
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.
89 * The PCI device repeats ths pfnGetRCHelpers call in it's relocation method
90 * since the address changes when RC is relocated.
91 *
92 * @see grp_pdm_device
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 *
110 * @see grp_pdm_usbdev
111 *
112 *
113 * @section sec_pdm_drv The Pluggable Drivers
114 *
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.
118 *
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.
125 *
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.
132 *
133 * So, for this example the IDE controller #1 (i.e. secondary) will have
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.
136 *
137 * It is possible to configure many levels of drivers inserting filters, loggers,
138 * or whatever you desire into the chain. We're using this for network sniffing
139 * for instance.
140 *
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.
144 *
145 * @see grp_pdm_driver
146 *
147 *
148 * @section sec_pdm_ifs Interfaces
149 *
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
153 * operation during init and hot-plug. PDM may query some interfaces during
154 * runtime mounting too.
155 *
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++.)
161 *
162 * @see grp_pdm_interfaces
163 *
164 *
165 * @section sec_pdm_utils Utilities
166 *
167 * As mentioned earlier, PDM is the location of any usful constructs that doesn't
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 *
175 * @subsection sec_pdm_async_completion Async I/O
176 *
177 * The PDM Async I/O API provides a somewhat platform agnostic interface for
178 * asynchronous I/O. For reasons of performance and complexity this does not
179 * build upon any IPRT API.
180 *
181 * @todo more details.
182 *
183 * @see grp_pdm_async_completion
184 *
185 *
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 *
195 * The PDM Critical Section API is currently building on the IPRT API with the
196 * same name. It adds the possibility to use critical sections in ring-0 and
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.)
204 *
205 * @see grp_pdm_critsect
206 *
207 *
208 * @subsection sec_pdm_queue Queue
209 *
210 * The PDM Queue API is for queuing one or more tasks for later consumption in
211 * ring-3 by EMT, and optionally forcing a delayed or ASAP return to ring-3. The
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.
214 *
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.
217 *
218 * @see grp_pdm_queue
219 *
220 *
221 * @subsection sec_pdm_task Task - not implemented yet
222 *
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.
226 *
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 *
230 * @see grp_pdm_task
231 *
232 *
233 * @subsection sec_pdm_thread Thread
234 *
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 *
244 * @see grp_pdm_thread
245 *
246 */
247
248
249/*******************************************************************************
250* Header Files *
251*******************************************************************************/
252#define LOG_GROUP LOG_GROUP_PDM
253#include "PDMInternal.h"
254#include <VBox/vmm/pdm.h>
255#include <VBox/vmm/mm.h>
256#include <VBox/vmm/pgm.h>
257#include <VBox/vmm/ssm.h>
258#include <VBox/vmm/vm.h>
259#include <VBox/vmm/uvm.h>
260#include <VBox/vmm/vmm.h>
261#include <VBox/param.h>
262#include <VBox/err.h>
263#include <VBox/sup.h>
264
265#include <VBox/log.h>
266#include <iprt/asm.h>
267#include <iprt/assert.h>
268#include <iprt/alloc.h>
269#include <iprt/ldr.h>
270#include <iprt/path.h>
271#include <iprt/string.h>
272
273
274/*******************************************************************************
275* Defined Constants And Macros *
276*******************************************************************************/
277/** The PDM saved state version. */
278#define PDM_SAVED_STATE_VERSION 4
279#define PDM_SAVED_STATE_VERSION_PRE_NMI_FF 3
280
281
282/*******************************************************************************
283* Structures and Typedefs *
284*******************************************************************************/
285/**
286 * Statistics of asynchronous notification tasks - used by reset, suspend and
287 * power off.
288 */
289typedef struct PDMNOTIFYASYNCSTATS
290{
291 /** The the start timestamp. */
292 uint64_t uStartNsTs;
293 /** When to log the next time. */
294 uint64_t cNsElapsedNextLog;
295 /** The loop counter. */
296 uint32_t cLoops;
297 /** The number of pending asynchronous notification tasks. */
298 uint32_t cAsync;
299 /** The name of the operation (log prefix). */
300 const char *pszOp;
301 /** The current list buffer position. */
302 size_t offList;
303 /** String containing a list of the pending tasks. */
304 char szList[1024];
305} PDMNOTIFYASYNCSTATS;
306/** Pointer to the stats of pending asynchronous notification tasks. */
307typedef PDMNOTIFYASYNCSTATS *PPDMNOTIFYASYNCSTATS;
308
309
310/*******************************************************************************
311* Internal Functions *
312*******************************************************************************/
313static DECLCALLBACK(int) pdmR3LiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass);
314static DECLCALLBACK(int) pdmR3SaveExec(PVM pVM, PSSMHANDLE pSSM);
315static DECLCALLBACK(int) pdmR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
316static DECLCALLBACK(int) pdmR3LoadPrep(PVM pVM, PSSMHANDLE pSSM);
317
318
319
320/**
321 * Initializes the PDM part of the UVM.
322 *
323 * This doesn't really do much right now but has to be here for the sake
324 * of completeness.
325 *
326 * @returns VBox status code.
327 * @param pUVM Pointer to the user mode VM structure.
328 */
329VMMR3DECL(int) PDMR3InitUVM(PUVM pUVM)
330{
331 AssertCompile(sizeof(pUVM->pdm.s) <= sizeof(pUVM->pdm.padding));
332 AssertRelease(sizeof(pUVM->pdm.s) <= sizeof(pUVM->pdm.padding));
333 pUVM->pdm.s.pModules = NULL;
334 pUVM->pdm.s.pCritSects = NULL;
335 return RTCritSectInit(&pUVM->pdm.s.ListCritSect);
336}
337
338
339/**
340 * Initializes the PDM.
341 *
342 * @returns VBox status code.
343 * @param pVM The VM to operate on.
344 */
345VMMR3DECL(int) PDMR3Init(PVM pVM)
346{
347 LogFlow(("PDMR3Init\n"));
348
349 /*
350 * Assert alignment and sizes.
351 */
352 AssertRelease(!(RT_OFFSETOF(VM, pdm.s) & 31));
353 AssertRelease(sizeof(pVM->pdm.s) <= sizeof(pVM->pdm.padding));
354 AssertCompileMemberAlignment(PDM, CritSect, sizeof(uintptr_t));
355
356 /*
357 * Init the structure.
358 */
359 pVM->pdm.s.GCPhysVMMDevHeap = NIL_RTGCPHYS;
360
361 /*
362 * Initialize critical sections first.
363 */
364 int rc = pdmR3CritSectInitStats(pVM);
365 if (RT_SUCCESS(rc))
366 rc = PDMR3CritSectInit(pVM, &pVM->pdm.s.CritSect, RT_SRC_POS, "PDM");
367 if (RT_SUCCESS(rc))
368 {
369 rc = PDMR3CritSectInit(pVM, &pVM->pdm.s.NopCritSect, RT_SRC_POS, "NOP");
370 if (RT_SUCCESS(rc))
371 pVM->pdm.s.NopCritSect.s.Core.fFlags |= RTCRITSECT_FLAGS_NOP;
372 }
373
374 /*
375 * Initialize sub components.
376 */
377 if (RT_SUCCESS(rc))
378 rc = pdmR3LdrInitU(pVM->pUVM);
379#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
380 if (RT_SUCCESS(rc))
381 rc = pdmR3AsyncCompletionInit(pVM);
382#endif
383 if (RT_SUCCESS(rc))
384 rc = pdmR3BlkCacheInit(pVM);
385 if (RT_SUCCESS(rc))
386 rc = pdmR3DrvInit(pVM);
387 if (RT_SUCCESS(rc))
388 rc = pdmR3DevInit(pVM);
389 if (RT_SUCCESS(rc))
390 {
391 /*
392 * Register the saved state data unit.
393 */
394 rc = SSMR3RegisterInternal(pVM, "pdm", 1, PDM_SAVED_STATE_VERSION, 128,
395 NULL, pdmR3LiveExec, NULL,
396 NULL, pdmR3SaveExec, NULL,
397 pdmR3LoadPrep, pdmR3LoadExec, NULL);
398 if (RT_SUCCESS(rc))
399 {
400 LogFlow(("PDM: Successfully initialized\n"));
401 return rc;
402 }
403 }
404
405 /*
406 * Cleanup and return failure.
407 */
408 PDMR3Term(pVM);
409 LogFlow(("PDMR3Init: returns %Rrc\n", rc));
410 return rc;
411}
412
413
414/**
415 * Applies relocations to data and code managed by this
416 * component. This function will be called at init and
417 * whenever the VMM need to relocate it self inside the GC.
418 *
419 * @param pVM VM handle.
420 * @param offDelta Relocation delta relative to old location.
421 * @remark The loader subcomponent is relocated by PDMR3LdrRelocate() very
422 * early in the relocation phase.
423 */
424VMMR3DECL(void) PDMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
425{
426 LogFlow(("PDMR3Relocate\n"));
427
428 /*
429 * Queues.
430 */
431 pdmR3QueueRelocate(pVM, offDelta);
432 pVM->pdm.s.pDevHlpQueueRC = PDMQueueRCPtr(pVM->pdm.s.pDevHlpQueueR3);
433
434 /*
435 * Critical sections.
436 */
437 pdmR3CritSectRelocate(pVM);
438
439 /*
440 * The registered PIC.
441 */
442 if (pVM->pdm.s.Pic.pDevInsRC)
443 {
444 pVM->pdm.s.Pic.pDevInsRC += offDelta;
445 pVM->pdm.s.Pic.pfnSetIrqRC += offDelta;
446 pVM->pdm.s.Pic.pfnGetInterruptRC += offDelta;
447 }
448
449 /*
450 * The registered APIC.
451 */
452 if (pVM->pdm.s.Apic.pDevInsRC)
453 {
454 pVM->pdm.s.Apic.pDevInsRC += offDelta;
455 pVM->pdm.s.Apic.pfnGetInterruptRC += offDelta;
456 pVM->pdm.s.Apic.pfnSetBaseRC += offDelta;
457 pVM->pdm.s.Apic.pfnGetBaseRC += offDelta;
458 pVM->pdm.s.Apic.pfnSetTPRRC += offDelta;
459 pVM->pdm.s.Apic.pfnGetTPRRC += offDelta;
460 pVM->pdm.s.Apic.pfnBusDeliverRC += offDelta;
461 if (pVM->pdm.s.Apic.pfnLocalInterruptRC)
462 pVM->pdm.s.Apic.pfnLocalInterruptRC += offDelta;
463 pVM->pdm.s.Apic.pfnWriteMSRRC += offDelta;
464 pVM->pdm.s.Apic.pfnReadMSRRC += offDelta;
465 }
466
467 /*
468 * The registered I/O APIC.
469 */
470 if (pVM->pdm.s.IoApic.pDevInsRC)
471 {
472 pVM->pdm.s.IoApic.pDevInsRC += offDelta;
473 pVM->pdm.s.IoApic.pfnSetIrqRC += offDelta;
474 if (pVM->pdm.s.IoApic.pfnSendMsiRC)
475 pVM->pdm.s.IoApic.pfnSendMsiRC += offDelta;
476 }
477
478 /*
479 * The register PCI Buses.
480 */
481 for (unsigned i = 0; i < RT_ELEMENTS(pVM->pdm.s.aPciBuses); i++)
482 {
483 if (pVM->pdm.s.aPciBuses[i].pDevInsRC)
484 {
485 pVM->pdm.s.aPciBuses[i].pDevInsRC += offDelta;
486 pVM->pdm.s.aPciBuses[i].pfnSetIrqRC += offDelta;
487 }
488 }
489
490 /*
491 * Devices & Drivers.
492 */
493 PCPDMDEVHLPRC pDevHlpRC;
494 int rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDevHlp", &pDevHlpRC);
495 AssertReleaseMsgRC(rc, ("rc=%Rrc when resolving g_pdmRCDevHlp\n", rc));
496
497 PCPDMDRVHLPRC pDrvHlpRC;
498 rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDevHlp", &pDrvHlpRC);
499 AssertReleaseMsgRC(rc, ("rc=%Rrc when resolving g_pdmRCDevHlp\n", rc));
500
501 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
502 {
503 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_RC)
504 {
505 pDevIns->pHlpRC = pDevHlpRC;
506 pDevIns->pvInstanceDataRC = MMHyperR3ToRC(pVM, pDevIns->pvInstanceDataR3);
507 if (pDevIns->pCritSectRoR3)
508 pDevIns->pCritSectRoRC = MMHyperR3ToRC(pVM, pDevIns->pCritSectRoR3);
509 pDevIns->Internal.s.pVMRC = pVM->pVMRC;
510 if (pDevIns->Internal.s.pPciBusR3)
511 pDevIns->Internal.s.pPciBusRC = MMHyperR3ToRC(pVM, pDevIns->Internal.s.pPciBusR3);
512 if (pDevIns->Internal.s.pPciDeviceR3)
513 pDevIns->Internal.s.pPciDeviceRC = MMHyperR3ToRC(pVM, pDevIns->Internal.s.pPciDeviceR3);
514 if (pDevIns->pReg->pfnRelocate)
515 {
516 LogFlow(("PDMR3Relocate: Relocating device '%s'/%d\n",
517 pDevIns->pReg->szName, pDevIns->iInstance));
518 pDevIns->pReg->pfnRelocate(pDevIns, offDelta);
519 }
520 }
521
522 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
523 {
524 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
525 {
526 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_RC)
527 {
528 pDrvIns->pHlpRC = pDrvHlpRC;
529 pDrvIns->pvInstanceDataRC = MMHyperR3ToRC(pVM, pDrvIns->pvInstanceDataR3);
530 pDrvIns->Internal.s.pVMRC = pVM->pVMRC;
531 if (pDrvIns->pReg->pfnRelocate)
532 {
533 LogFlow(("PDMR3Relocate: Relocating driver '%s'/%u attached to '%s'/%d/%u\n",
534 pDrvIns->pReg->szName, pDrvIns->iInstance,
535 pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun));
536 pDrvIns->pReg->pfnRelocate(pDrvIns, offDelta);
537 }
538 }
539 }
540 }
541
542 }
543}
544
545
546/**
547 * Worker for pdmR3Term that terminates a LUN chain.
548 *
549 * @param pVM Pointer to the shared VM structure.
550 * @param pLun The head of the chain.
551 * @param pszDevice The name of the device (for logging).
552 * @param iInstance The device instance number (for logging).
553 */
554static void pdmR3TermLuns(PVM pVM, PPDMLUN pLun, const char *pszDevice, unsigned iInstance)
555{
556 for (; pLun; pLun = pLun->pNext)
557 {
558 /*
559 * Destroy them one at a time from the bottom up.
560 * (The serial device/drivers depends on this - bad.)
561 */
562 PPDMDRVINS pDrvIns = pLun->pBottom;
563 pLun->pBottom = pLun->pTop = NULL;
564 while (pDrvIns)
565 {
566 PPDMDRVINS pDrvNext = pDrvIns->Internal.s.pUp;
567
568 if (pDrvIns->pReg->pfnDestruct)
569 {
570 LogFlow(("pdmR3DevTerm: Destroying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
571 pDrvIns->pReg->szName, pDrvIns->iInstance, pLun->iLun, pszDevice, iInstance));
572 pDrvIns->pReg->pfnDestruct(pDrvIns);
573 }
574 pDrvIns->Internal.s.pDrv->cInstances--;
575
576 TMR3TimerDestroyDriver(pVM, pDrvIns);
577 //PDMR3QueueDestroyDriver(pVM, pDrvIns);
578 //pdmR3ThreadDestroyDriver(pVM, pDrvIns);
579 SSMR3DeregisterDriver(pVM, pDrvIns, NULL, 0);
580
581 pDrvIns = pDrvNext;
582 }
583 }
584}
585
586
587/**
588 * Terminates the PDM.
589 *
590 * Termination means cleaning up and freeing all resources,
591 * the VM it self is at this point powered off or suspended.
592 *
593 * @returns VBox status code.
594 * @param pVM The VM to operate on.
595 */
596VMMR3DECL(int) PDMR3Term(PVM pVM)
597{
598 LogFlow(("PDMR3Term:\n"));
599 AssertMsg(PDMCritSectIsInitialized(&pVM->pdm.s.CritSect), ("bad init order!\n"));
600
601 /*
602 * Iterate the device instances and attach drivers, doing
603 * relevant destruction processing.
604 *
605 * N.B. There is no need to mess around freeing memory allocated
606 * from any MM heap since MM will do that in its Term function.
607 */
608 /* usb ones first. */
609 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
610 {
611 pdmR3TermLuns(pVM, pUsbIns->Internal.s.pLuns, pUsbIns->pReg->szName, pUsbIns->iInstance);
612
613 if (pUsbIns->pReg->pfnDestruct)
614 {
615 LogFlow(("pdmR3DevTerm: Destroying - device '%s'/%d\n",
616 pUsbIns->pReg->szName, pUsbIns->iInstance));
617 pUsbIns->pReg->pfnDestruct(pUsbIns);
618 }
619
620 //TMR3TimerDestroyUsb(pVM, pUsbIns);
621 //SSMR3DeregisterUsb(pVM, pUsbIns, NULL, 0);
622 pdmR3ThreadDestroyUsb(pVM, pUsbIns);
623 }
624
625 /* then the 'normal' ones. */
626 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
627 {
628 pdmR3TermLuns(pVM, pDevIns->Internal.s.pLunsR3, pDevIns->pReg->szName, pDevIns->iInstance);
629
630 if (pDevIns->pReg->pfnDestruct)
631 {
632 LogFlow(("pdmR3DevTerm: Destroying - device '%s'/%d\n",
633 pDevIns->pReg->szName, pDevIns->iInstance));
634 pDevIns->pReg->pfnDestruct(pDevIns);
635 }
636
637 TMR3TimerDestroyDevice(pVM, pDevIns);
638 //SSMR3DeregisterDriver(pVM, pDevIns, NULL, 0);
639 pdmR3CritSectDeleteDevice(pVM, pDevIns);
640 //pdmR3ThreadDestroyDevice(pVM, pDevIns);
641 //PDMR3QueueDestroyDevice(pVM, pDevIns);
642 PGMR3PhysMMIO2Deregister(pVM, pDevIns, UINT32_MAX);
643 }
644
645 /*
646 * Destroy all threads.
647 */
648 pdmR3ThreadDestroyAll(pVM);
649
650 /*
651 * Destroy the block cache.
652 */
653 pdmR3BlkCacheTerm(pVM);
654
655#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
656 /*
657 * Free async completion managers.
658 */
659 pdmR3AsyncCompletionTerm(pVM);
660#endif
661
662 /*
663 * Free modules.
664 */
665 pdmR3LdrTermU(pVM->pUVM);
666
667 /*
668 * Destroy the PDM lock.
669 */
670 PDMR3CritSectDelete(&pVM->pdm.s.CritSect);
671 /* The MiscCritSect is deleted by PDMR3CritSectTerm. */
672
673 LogFlow(("PDMR3Term: returns %Rrc\n", VINF_SUCCESS));
674 return VINF_SUCCESS;
675}
676
677
678/**
679 * Terminates the PDM part of the UVM.
680 *
681 * This will unload any modules left behind.
682 *
683 * @param pUVM Pointer to the user mode VM structure.
684 */
685VMMR3DECL(void) PDMR3TermUVM(PUVM pUVM)
686{
687 /*
688 * In the normal cause of events we will now call pdmR3LdrTermU for
689 * the second time. In the case of init failure however, this might
690 * the first time, which is why we do it.
691 */
692 pdmR3LdrTermU(pUVM);
693
694 Assert(pUVM->pdm.s.pCritSects == NULL);
695 RTCritSectDelete(&pUVM->pdm.s.ListCritSect);
696}
697
698
699/**
700 * Bits that are saved in pass 0 and in the final pass.
701 *
702 * @param pVM The VM handle.
703 * @param pSSM The saved state handle.
704 */
705static void pdmR3SaveBoth(PVM pVM, PSSMHANDLE pSSM)
706{
707 /*
708 * Save the list of device instances so we can check that they're all still
709 * there when we load the state and that nothing new has been added.
710 */
711 uint32_t i = 0;
712 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3, i++)
713 {
714 SSMR3PutU32(pSSM, i);
715 SSMR3PutStrZ(pSSM, pDevIns->pReg->szName);
716 SSMR3PutU32(pSSM, pDevIns->iInstance);
717 }
718 SSMR3PutU32(pSSM, UINT32_MAX); /* terminator */
719}
720
721
722/**
723 * Live save.
724 *
725 * @returns VBox status code.
726 * @param pVM The VM handle.
727 * @param pSSM The saved state handle.
728 * @param uPass The pass.
729 */
730static DECLCALLBACK(int) pdmR3LiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass)
731{
732 LogFlow(("pdmR3LiveExec:\n"));
733 AssertReturn(uPass == 0, VERR_INTERNAL_ERROR_4);
734 pdmR3SaveBoth(pVM, pSSM);
735 return VINF_SSM_DONT_CALL_AGAIN;
736}
737
738
739/**
740 * Execute state save operation.
741 *
742 * @returns VBox status code.
743 * @param pVM The VM handle.
744 * @param pSSM The saved state handle.
745 */
746static DECLCALLBACK(int) pdmR3SaveExec(PVM pVM, PSSMHANDLE pSSM)
747{
748 LogFlow(("pdmR3SaveExec:\n"));
749
750 /*
751 * Save interrupt and DMA states.
752 */
753 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
754 {
755 PVMCPU pVCpu = &pVM->aCpus[idCpu];
756 SSMR3PutU32(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC));
757 SSMR3PutU32(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC));
758 SSMR3PutU32(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_NMI));
759 SSMR3PutU32(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_SMI));
760 }
761 SSMR3PutU32(pSSM, VM_FF_ISSET(pVM, VM_FF_PDM_DMA));
762
763 pdmR3SaveBoth(pVM, pSSM);
764 return VINF_SUCCESS;
765}
766
767
768/**
769 * Prepare state load operation.
770 *
771 * This will dispatch pending operations and clear the FFs governed by PDM and its devices.
772 *
773 * @returns VBox status code.
774 * @param pVM The VM handle.
775 * @param pSSM The SSM handle.
776 */
777static DECLCALLBACK(int) pdmR3LoadPrep(PVM pVM, PSSMHANDLE pSSM)
778{
779 LogFlow(("pdmR3LoadPrep: %s%s\n",
780 VM_FF_ISSET(pVM, VM_FF_PDM_QUEUES) ? " VM_FF_PDM_QUEUES" : "",
781 VM_FF_ISSET(pVM, VM_FF_PDM_DMA) ? " VM_FF_PDM_DMA" : ""));
782#ifdef LOG_ENABLED
783 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
784 {
785 PVMCPU pVCpu = &pVM->aCpus[idCpu];
786 LogFlow(("pdmR3LoadPrep: VCPU %u %s%s\n", idCpu,
787 VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC) ? " VMCPU_FF_INTERRUPT_APIC" : "",
788 VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC) ? " VMCPU_FF_INTERRUPT_PIC" : ""));
789 }
790#endif
791
792 /*
793 * In case there is work pending that will raise an interrupt,
794 * start a DMA transfer, or release a lock. (unlikely)
795 */
796 if (VM_FF_ISSET(pVM, VM_FF_PDM_QUEUES))
797 PDMR3QueueFlushAll(pVM);
798
799 /* Clear the FFs. */
800 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
801 {
802 PVMCPU pVCpu = &pVM->aCpus[idCpu];
803 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
804 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
805 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
806 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_SMI);
807 }
808 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
809
810 return VINF_SUCCESS;
811}
812
813
814/**
815 * Execute state load operation.
816 *
817 * @returns VBox status code.
818 * @param pVM VM Handle.
819 * @param pSSM SSM operation handle.
820 * @param uVersion Data layout version.
821 * @param uPass The data pass.
822 */
823static DECLCALLBACK(int) pdmR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
824{
825 int rc;
826
827 LogFlow(("pdmR3LoadExec: uPass=%#x\n", uPass));
828
829 /*
830 * Validate version.
831 */
832 if ( uVersion != PDM_SAVED_STATE_VERSION
833 && uVersion != PDM_SAVED_STATE_VERSION_PRE_NMI_FF)
834 {
835 AssertMsgFailed(("Invalid version uVersion=%d!\n", uVersion));
836 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
837 }
838
839 if (uPass == SSM_PASS_FINAL)
840 {
841 /*
842 * Load the interrupt and DMA states.
843 */
844 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
845 {
846 PVMCPU pVCpu = &pVM->aCpus[idCpu];
847
848 /* APIC interrupt */
849 uint32_t fInterruptPending = 0;
850 rc = SSMR3GetU32(pSSM, &fInterruptPending);
851 if (RT_FAILURE(rc))
852 return rc;
853 if (fInterruptPending & ~1)
854 {
855 AssertMsgFailed(("fInterruptPending=%#x (APIC)\n", fInterruptPending));
856 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
857 }
858 AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC));
859 if (fInterruptPending)
860 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC);
861
862 /* PIC interrupt */
863 fInterruptPending = 0;
864 rc = SSMR3GetU32(pSSM, &fInterruptPending);
865 if (RT_FAILURE(rc))
866 return rc;
867 if (fInterruptPending & ~1)
868 {
869 AssertMsgFailed(("fInterruptPending=%#x (PIC)\n", fInterruptPending));
870 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
871 }
872 AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC));
873 if (fInterruptPending)
874 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC);
875
876 if (uVersion > PDM_SAVED_STATE_VERSION_PRE_NMI_FF)
877 {
878 /* NMI interrupt */
879 fInterruptPending = 0;
880 rc = SSMR3GetU32(pSSM, &fInterruptPending);
881 if (RT_FAILURE(rc))
882 return rc;
883 if (fInterruptPending & ~1)
884 {
885 AssertMsgFailed(("fInterruptPending=%#x (NMI)\n", fInterruptPending));
886 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
887 }
888 AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_NMI));
889 if (fInterruptPending)
890 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI);
891
892 /* SMI interrupt */
893 fInterruptPending = 0;
894 rc = SSMR3GetU32(pSSM, &fInterruptPending);
895 if (RT_FAILURE(rc))
896 return rc;
897 if (fInterruptPending & ~1)
898 {
899 AssertMsgFailed(("fInterruptPending=%#x (SMI)\n", fInterruptPending));
900 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
901 }
902 AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_SMI));
903 if (fInterruptPending)
904 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_SMI);
905 }
906 }
907
908 /* DMA pending */
909 uint32_t fDMAPending = 0;
910 rc = SSMR3GetU32(pSSM, &fDMAPending);
911 if (RT_FAILURE(rc))
912 return rc;
913 if (fDMAPending & ~1)
914 {
915 AssertMsgFailed(("fDMAPending=%#x\n", fDMAPending));
916 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
917 }
918 if (fDMAPending)
919 VM_FF_SET(pVM, VM_FF_PDM_DMA);
920 Log(("pdmR3LoadExec: VM_FF_PDM_DMA=%RTbool\n", VM_FF_ISSET(pVM, VM_FF_PDM_DMA)));
921 }
922
923 /*
924 * Load the list of devices and verify that they are all there.
925 */
926 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
927 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_FOUND;
928
929 for (uint32_t i = 0; ; i++)
930 {
931 /* Get the sequence number / terminator. */
932 uint32_t u32Sep;
933 rc = SSMR3GetU32(pSSM, &u32Sep);
934 if (RT_FAILURE(rc))
935 return rc;
936 if (u32Sep == UINT32_MAX)
937 break;
938 if (u32Sep != i)
939 AssertMsgFailedReturn(("Out of sequence. u32Sep=%#x i=%#x\n", u32Sep, i), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
940
941 /* Get the name and instance number. */
942 char szName[RT_SIZEOFMEMB(PDMDEVREG, szName)];
943 rc = SSMR3GetStrZ(pSSM, szName, sizeof(szName));
944 if (RT_FAILURE(rc))
945 return rc;
946 uint32_t iInstance;
947 rc = SSMR3GetU32(pSSM, &iInstance);
948 if (RT_FAILURE(rc))
949 return rc;
950
951 /* Try locate it. */
952 PPDMDEVINS pDevIns;
953 for (pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
954 if ( !strcmp(szName, pDevIns->pReg->szName)
955 && pDevIns->iInstance == iInstance)
956 {
957 AssertLogRelMsgReturn(!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_FOUND),
958 ("%s/#%u\n", pDevIns->pReg->szName, pDevIns->iInstance),
959 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
960 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_FOUND;
961 break;
962 }
963 if (!pDevIns)
964 {
965 LogRel(("Device '%s'/%d not found in current config\n", szName, iInstance));
966 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
967 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device '%s'/%d not found in current config"), szName, iInstance);
968 }
969 }
970
971 /*
972 * Check that no additional devices were configured.
973 */
974 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
975 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_FOUND))
976 {
977 LogRel(("Device '%s'/%d not found in the saved state\n", pDevIns->pReg->szName, pDevIns->iInstance));
978 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
979 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device '%s'/%d not found in the saved state"),
980 pDevIns->pReg->szName, pDevIns->iInstance);
981 }
982
983 return VINF_SUCCESS;
984}
985
986
987/**
988 * Worker for PDMR3PowerOn that deals with one driver.
989 *
990 * @param pDrvIns The driver instance.
991 * @param pszDevName The parent device name.
992 * @param iDevInstance The parent device instance number.
993 * @param iLun The parent LUN number.
994 */
995DECLINLINE(int) pdmR3PowerOnDrv(PPDMDRVINS pDrvIns, const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
996{
997 Assert(pDrvIns->Internal.s.fVMSuspended);
998 if (pDrvIns->pReg->pfnPowerOn)
999 {
1000 LogFlow(("PDMR3PowerOn: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1001 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1002 int rc = VINF_SUCCESS; pDrvIns->pReg->pfnPowerOn(pDrvIns);
1003 if (RT_FAILURE(rc))
1004 {
1005 LogRel(("PDMR3PowerOn: driver '%s'/%d on LUN#%d of device '%s'/%d -> %Rrc\n",
1006 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance, rc));
1007 return rc;
1008 }
1009 }
1010 pDrvIns->Internal.s.fVMSuspended = false;
1011 return VINF_SUCCESS;
1012}
1013
1014
1015/**
1016 * Worker for PDMR3PowerOn that deals with one USB device instance.
1017 *
1018 * @returns VBox status code.
1019 * @param pUsbIns The USB device instance.
1020 */
1021DECLINLINE(int) pdmR3PowerOnUsb(PPDMUSBINS pUsbIns)
1022{
1023 Assert(pUsbIns->Internal.s.fVMSuspended);
1024 if (pUsbIns->pReg->pfnVMPowerOn)
1025 {
1026 LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1027 int rc = VINF_SUCCESS; pUsbIns->pReg->pfnVMPowerOn(pUsbIns);
1028 if (RT_FAILURE(rc))
1029 {
1030 LogRel(("PDMR3PowerOn: device '%s'/%d -> %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1031 return rc;
1032 }
1033 }
1034 pUsbIns->Internal.s.fVMSuspended = false;
1035 return VINF_SUCCESS;
1036}
1037
1038
1039/**
1040 * Worker for PDMR3PowerOn that deals with one device instance.
1041 *
1042 * @returns VBox status code.
1043 * @param pDevIns The device instance.
1044 */
1045DECLINLINE(int) pdmR3PowerOnDev(PPDMDEVINS pDevIns)
1046{
1047 Assert(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED);
1048 if (pDevIns->pReg->pfnPowerOn)
1049 {
1050 LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1051 int rc = VINF_SUCCESS; pDevIns->pReg->pfnPowerOn(pDevIns);
1052 if (RT_FAILURE(rc))
1053 {
1054 LogRel(("PDMR3PowerOn: device '%s'/%d -> %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
1055 return rc;
1056 }
1057 }
1058 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1059 return VINF_SUCCESS;
1060}
1061
1062
1063/**
1064 * This function will notify all the devices and their
1065 * attached drivers about the VM now being powered on.
1066 *
1067 * @param pVM VM Handle.
1068 */
1069VMMR3DECL(void) PDMR3PowerOn(PVM pVM)
1070{
1071 LogFlow(("PDMR3PowerOn:\n"));
1072
1073 /*
1074 * Iterate thru the device instances and USB device instances,
1075 * processing the drivers associated with those.
1076 */
1077 int rc = VINF_SUCCESS;
1078 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns && RT_SUCCESS(rc); pDevIns = pDevIns->Internal.s.pNextR3)
1079 {
1080 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1081 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1082 rc = pdmR3PowerOnDrv(pDrvIns, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun);
1083 if (RT_SUCCESS(rc))
1084 rc = pdmR3PowerOnDev(pDevIns);
1085 }
1086
1087#ifdef VBOX_WITH_USB
1088 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns && RT_SUCCESS(rc); pUsbIns = pUsbIns->Internal.s.pNext)
1089 {
1090 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1091 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1092 rc = pdmR3PowerOnDrv(pDrvIns, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun);
1093 if (RT_SUCCESS(rc))
1094 rc = pdmR3PowerOnUsb(pUsbIns);
1095 }
1096#endif
1097
1098#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
1099 pdmR3AsyncCompletionResume(pVM);
1100#endif
1101
1102 /*
1103 * Resume all threads.
1104 */
1105 if (RT_SUCCESS(rc))
1106 pdmR3ThreadResumeAll(pVM);
1107
1108 /*
1109 * On failure, clean up via PDMR3Suspend.
1110 */
1111 if (RT_FAILURE(rc))
1112 PDMR3Suspend(pVM);
1113
1114 LogFlow(("PDMR3PowerOn: returns %Rrc\n", rc));
1115 return /*rc*/;
1116}
1117
1118
1119/**
1120 * Initializes the asynchronous notifi stats structure.
1121 *
1122 * @param pThis The asynchronous notifification stats.
1123 * @param pszOp The name of the operation.
1124 */
1125static void pdmR3NotifyAsyncInit(PPDMNOTIFYASYNCSTATS pThis, const char *pszOp)
1126{
1127 pThis->uStartNsTs = RTTimeNanoTS();
1128 pThis->cNsElapsedNextLog = 0;
1129 pThis->cLoops = 0;
1130 pThis->cAsync = 0;
1131 pThis->pszOp = pszOp;
1132 pThis->offList = 0;
1133 pThis->szList[0] = '\0';
1134}
1135
1136
1137/**
1138 * Begin a new loop, prepares to gather new stats.
1139 *
1140 * @param pThis The asynchronous notifification stats.
1141 */
1142static void pdmR3NotifyAsyncBeginLoop(PPDMNOTIFYASYNCSTATS pThis)
1143{
1144 pThis->cLoops++;
1145 pThis->cAsync = 0;
1146 pThis->offList = 0;
1147 pThis->szList[0] = '\0';
1148}
1149
1150
1151/**
1152 * Records a device or USB device with a pending asynchronous notification.
1153 *
1154 * @param pThis The asynchronous notifification stats.
1155 * @param pszName The name of the thing.
1156 * @param iInstance The instance number.
1157 */
1158static void pdmR3NotifyAsyncAdd(PPDMNOTIFYASYNCSTATS pThis, const char *pszName, uint32_t iInstance)
1159{
1160 pThis->cAsync++;
1161 if (pThis->offList < sizeof(pThis->szList) - 4)
1162 pThis->offList += RTStrPrintf(&pThis->szList[pThis->offList], sizeof(pThis->szList) - pThis->offList,
1163 pThis->offList == 0 ? "%s/%u" : ", %s/%u",
1164 pszName, iInstance);
1165}
1166
1167
1168/**
1169 * Records the asynchronous completition of a reset, suspend or power off.
1170 *
1171 * @param pThis The asynchronous notifification stats.
1172 * @param pszDrvName The driver name.
1173 * @param iDrvInstance The driver instance number.
1174 * @param pszDevName The device or USB device name.
1175 * @param iDevInstance The device or USB device instance number.
1176 * @param iLun The LUN.
1177 */
1178static void pdmR3NotifyAsyncAddDrv(PPDMNOTIFYASYNCSTATS pThis, const char *pszDrvName, uint32_t iDrvInstance,
1179 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1180{
1181 pThis->cAsync++;
1182 if (pThis->offList < sizeof(pThis->szList) - 8)
1183 pThis->offList += RTStrPrintf(&pThis->szList[pThis->offList], sizeof(pThis->szList) - pThis->offList,
1184 pThis->offList == 0 ? "%s/%u/%u/%s/%u" : ", %s/%u/%u/%s/%u",
1185 pszDevName, iDevInstance, iLun, pszDrvName, iDrvInstance);
1186}
1187
1188
1189/**
1190 * Log the stats.
1191 *
1192 * @param pThis The asynchronous notifification stats.
1193 */
1194static void pdmR3NotifyAsyncLog(PPDMNOTIFYASYNCSTATS pThis)
1195{
1196 /*
1197 * Return if we shouldn't log at this point.
1198 * We log with an internval increasing from 0 sec to 60 sec.
1199 */
1200 if (!pThis->cAsync)
1201 return;
1202
1203 uint64_t cNsElapsed = RTTimeNanoTS() - pThis->uStartNsTs;
1204 if (cNsElapsed < pThis->cNsElapsedNextLog)
1205 return;
1206
1207 if (pThis->cNsElapsedNextLog == 0)
1208 pThis->cNsElapsedNextLog = RT_NS_1SEC;
1209 else if (pThis->cNsElapsedNextLog >= RT_NS_1MIN / 2)
1210 pThis->cNsElapsedNextLog = RT_NS_1MIN;
1211 else
1212 pThis->cNsElapsedNextLog *= 2;
1213
1214 /*
1215 * Do the logging.
1216 */
1217 LogRel(("%s: after %5llu ms, %u loops: %u async tasks - %s\n",
1218 pThis->pszOp, cNsElapsed / RT_NS_1MS, pThis->cLoops, pThis->cAsync, pThis->szList));
1219}
1220
1221
1222/**
1223 * Wait for events and process pending requests.
1224 *
1225 * @param pThis The asynchronous notifification stats.
1226 * @param pVM The VM handle.
1227 */
1228static void pdmR3NotifyAsyncWaitAndProcessRequests(PPDMNOTIFYASYNCSTATS pThis, PVM pVM)
1229{
1230 /** @todo This is utterly nuts and completely unsafe... will get back to it in a
1231 * bit I hope... */
1232 VM_ASSERT_EMT0(pVM);
1233 int rc = VMR3AsyncPdmNotificationWaitU(&pVM->pUVM->aCpus[0]);
1234 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc - %s - %s\n", rc, pThis->pszOp, pThis->szList));
1235
1236 rc = VMR3ReqProcessU(pVM->pUVM, VMCPUID_ANY);
1237 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc - %s - %s\n", rc, pThis->pszOp, pThis->szList));
1238 rc = VMR3ReqProcessU(pVM->pUVM, 0/*idDstCpu*/);
1239 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc - %s - %s\n", rc, pThis->pszOp, pThis->szList));
1240}
1241
1242
1243/**
1244 * Worker for PDMR3Reset that deals with one driver.
1245 *
1246 * @param pDrvIns The driver instance.
1247 * @param pAsync The structure for recording asynchronous
1248 * notification tasks.
1249 * @param pszDevName The parent device name.
1250 * @param iDevInstance The parent device instance number.
1251 * @param iLun The parent LUN number.
1252 */
1253DECLINLINE(bool) pdmR3ResetDrv(PPDMDRVINS pDrvIns, PPDMNOTIFYASYNCSTATS pAsync,
1254 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1255{
1256 if (!pDrvIns->Internal.s.fVMReset)
1257 {
1258 pDrvIns->Internal.s.fVMReset = true;
1259 if (pDrvIns->pReg->pfnReset)
1260 {
1261 if (!pDrvIns->Internal.s.pfnAsyncNotify)
1262 {
1263 LogFlow(("PDMR3Reset: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1264 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1265 pDrvIns->pReg->pfnReset(pDrvIns);
1266 if (pDrvIns->Internal.s.pfnAsyncNotify)
1267 LogFlow(("PDMR3Reset: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1268 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1269 }
1270 else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
1271 {
1272 pDrvIns->Internal.s.pfnAsyncNotify = false;
1273 LogFlow(("PDMR3Reset: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1274 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1275 }
1276 if (pDrvIns->Internal.s.pfnAsyncNotify)
1277 {
1278 pDrvIns->Internal.s.fVMReset = false;
1279 pdmR3NotifyAsyncAddDrv(pAsync, pDrvIns->Internal.s.pDrv->pReg->szName, pDrvIns->iInstance,
1280 pszDevName, iDevInstance, iLun);
1281 return false;
1282 }
1283 }
1284 }
1285 return true;
1286}
1287
1288
1289/**
1290 * Worker for PDMR3Reset that deals with one USB device instance.
1291 *
1292 * @param pUsbIns The USB device instance.
1293 * @param pAsync The structure for recording asynchronous
1294 * notification tasks.
1295 */
1296DECLINLINE(void) pdmR3ResetUsb(PPDMUSBINS pUsbIns, PPDMNOTIFYASYNCSTATS pAsync)
1297{
1298 if (!pUsbIns->Internal.s.fVMReset)
1299 {
1300 pUsbIns->Internal.s.fVMReset = true;
1301 if (pUsbIns->pReg->pfnVMReset)
1302 {
1303 if (!pUsbIns->Internal.s.pfnAsyncNotify)
1304 {
1305 LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1306 pUsbIns->pReg->pfnVMReset(pUsbIns);
1307 if (pUsbIns->Internal.s.pfnAsyncNotify)
1308 LogFlow(("PDMR3Reset: Async notification started - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1309 }
1310 else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
1311 {
1312 LogFlow(("PDMR3Reset: Async notification completed - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1313 pUsbIns->Internal.s.pfnAsyncNotify = NULL;
1314 }
1315 if (pUsbIns->Internal.s.pfnAsyncNotify)
1316 {
1317 pUsbIns->Internal.s.fVMReset = false;
1318 pdmR3NotifyAsyncAdd(pAsync, pUsbIns->Internal.s.pUsbDev->pReg->szName, pUsbIns->iInstance);
1319 }
1320 }
1321 }
1322}
1323
1324
1325/**
1326 * Worker for PDMR3Reset that deals with one device instance.
1327 *
1328 * @param pDevIns The device instance.
1329 * @param pAsync The structure for recording asynchronous
1330 * notification tasks.
1331 */
1332DECLINLINE(void) pdmR3ResetDev(PPDMDEVINS pDevIns, PPDMNOTIFYASYNCSTATS pAsync)
1333{
1334 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_RESET))
1335 {
1336 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_RESET;
1337 if (pDevIns->pReg->pfnReset)
1338 {
1339 if (!pDevIns->Internal.s.pfnAsyncNotify)
1340 {
1341 LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1342 pDevIns->pReg->pfnReset(pDevIns);
1343 if (pDevIns->Internal.s.pfnAsyncNotify)
1344 LogFlow(("PDMR3Reset: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1345 }
1346 else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
1347 {
1348 LogFlow(("PDMR3Reset: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1349 pDevIns->Internal.s.pfnAsyncNotify = NULL;
1350 }
1351 if (pDevIns->Internal.s.pfnAsyncNotify)
1352 {
1353 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_RESET;
1354 pdmR3NotifyAsyncAdd(pAsync, pDevIns->Internal.s.pDevR3->pReg->szName, pDevIns->iInstance);
1355 }
1356 }
1357 }
1358}
1359
1360
1361/**
1362 * Resets a virtual CPU.
1363 *
1364 * Used by PDMR3Reset and CPU hot plugging.
1365 *
1366 * @param pVCpu The virtual CPU handle.
1367 */
1368VMMR3DECL(void) PDMR3ResetCpu(PVMCPU pVCpu)
1369{
1370 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
1371 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
1372 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
1373 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_SMI);
1374}
1375
1376
1377/**
1378 * This function will notify all the devices and their attached drivers about
1379 * the VM now being reset.
1380 *
1381 * @param pVM VM Handle.
1382 */
1383VMMR3DECL(void) PDMR3Reset(PVM pVM)
1384{
1385 LogFlow(("PDMR3Reset:\n"));
1386
1387 /*
1388 * Clear all the reset flags.
1389 */
1390 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1391 {
1392 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_RESET;
1393 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1394 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1395 pDrvIns->Internal.s.fVMReset = false;
1396 }
1397#ifdef VBOX_WITH_USB
1398 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1399 {
1400 pUsbIns->Internal.s.fVMReset = false;
1401 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1402 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1403 pDrvIns->Internal.s.fVMReset = false;
1404 }
1405#endif
1406
1407 /*
1408 * The outer loop repeats until there are no more async requests.
1409 */
1410 PDMNOTIFYASYNCSTATS Async;
1411 pdmR3NotifyAsyncInit(&Async, "PDMR3Reset");
1412 for (;;)
1413 {
1414 pdmR3NotifyAsyncBeginLoop(&Async);
1415
1416 /*
1417 * Iterate thru the device instances and USB device instances,
1418 * processing the drivers associated with those.
1419 */
1420 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1421 {
1422 unsigned const cAsyncStart = Async.cAsync;
1423
1424 if (Async.cAsync == cAsyncStart)
1425 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1426 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1427 if (!pdmR3ResetDrv(pDrvIns, &Async, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
1428 break;
1429
1430 if (Async.cAsync == cAsyncStart)
1431 pdmR3ResetDev(pDevIns, &Async);
1432 }
1433
1434#ifdef VBOX_WITH_USB
1435 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1436 {
1437 unsigned const cAsyncStart = Async.cAsync;
1438
1439 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1440 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1441 if (!pdmR3ResetDrv(pDrvIns, &Async, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
1442 break;
1443
1444 if (Async.cAsync == cAsyncStart)
1445 pdmR3ResetUsb(pUsbIns, &Async);
1446 }
1447#endif
1448 if (!Async.cAsync)
1449 break;
1450 pdmR3NotifyAsyncLog(&Async);
1451 pdmR3NotifyAsyncWaitAndProcessRequests(&Async, pVM);
1452 }
1453
1454 /*
1455 * Clear all pending interrupts and DMA operations.
1456 */
1457 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1458 PDMR3ResetCpu(&pVM->aCpus[idCpu]);
1459 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
1460
1461 LogFlow(("PDMR3Reset: returns void\n"));
1462}
1463
1464
1465/**
1466 * Worker for PDMR3Suspend that deals with one driver.
1467 *
1468 * @param pDrvIns The driver instance.
1469 * @param pAsync The structure for recording asynchronous
1470 * notification tasks.
1471 * @param pszDevName The parent device name.
1472 * @param iDevInstance The parent device instance number.
1473 * @param iLun The parent LUN number.
1474 */
1475DECLINLINE(bool) pdmR3SuspendDrv(PPDMDRVINS pDrvIns, PPDMNOTIFYASYNCSTATS pAsync,
1476 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1477{
1478 if (!pDrvIns->Internal.s.fVMSuspended)
1479 {
1480 pDrvIns->Internal.s.fVMSuspended = true;
1481 if (pDrvIns->pReg->pfnSuspend)
1482 {
1483 if (!pDrvIns->Internal.s.pfnAsyncNotify)
1484 {
1485 LogFlow(("PDMR3Suspend: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1486 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1487 pDrvIns->pReg->pfnSuspend(pDrvIns);
1488 if (pDrvIns->Internal.s.pfnAsyncNotify)
1489 LogFlow(("PDMR3Suspend: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1490 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1491 }
1492 else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
1493 {
1494 pDrvIns->Internal.s.pfnAsyncNotify = NULL;
1495 LogFlow(("PDMR3Suspend: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1496 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1497 }
1498 if (pDrvIns->Internal.s.pfnAsyncNotify)
1499 {
1500 pDrvIns->Internal.s.fVMSuspended = false;
1501 pdmR3NotifyAsyncAddDrv(pAsync, pDrvIns->Internal.s.pDrv->pReg->szName, pDrvIns->iInstance, pszDevName, iDevInstance, iLun);
1502 return false;
1503 }
1504 }
1505 }
1506 return true;
1507}
1508
1509
1510/**
1511 * Worker for PDMR3Suspend that deals with one USB device instance.
1512 *
1513 * @param pUsbIns The USB device instance.
1514 * @param pAsync The structure for recording asynchronous
1515 * notification tasks.
1516 */
1517DECLINLINE(void) pdmR3SuspendUsb(PPDMUSBINS pUsbIns, PPDMNOTIFYASYNCSTATS pAsync)
1518{
1519 if (!pUsbIns->Internal.s.fVMSuspended)
1520 {
1521 pUsbIns->Internal.s.fVMSuspended = true;
1522 if (pUsbIns->pReg->pfnVMSuspend)
1523 {
1524 if (!pUsbIns->Internal.s.pfnAsyncNotify)
1525 {
1526 LogFlow(("PDMR3Suspend: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1527 pUsbIns->pReg->pfnVMSuspend(pUsbIns);
1528 if (pUsbIns->Internal.s.pfnAsyncNotify)
1529 LogFlow(("PDMR3Suspend: Async notification started - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1530 }
1531 else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
1532 {
1533 LogFlow(("PDMR3Suspend: Async notification completed - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1534 pUsbIns->Internal.s.pfnAsyncNotify = NULL;
1535 }
1536 if (pUsbIns->Internal.s.pfnAsyncNotify)
1537 {
1538 pUsbIns->Internal.s.fVMSuspended = false;
1539 pdmR3NotifyAsyncAdd(pAsync, pUsbIns->Internal.s.pUsbDev->pReg->szName, pUsbIns->iInstance);
1540 }
1541 }
1542 }
1543}
1544
1545
1546/**
1547 * Worker for PDMR3Suspend that deals with one device instance.
1548 *
1549 * @param pDevIns The device instance.
1550 * @param pAsync The structure for recording asynchronous
1551 * notification tasks.
1552 */
1553DECLINLINE(void) pdmR3SuspendDev(PPDMDEVINS pDevIns, PPDMNOTIFYASYNCSTATS pAsync)
1554{
1555 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED))
1556 {
1557 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_SUSPENDED;
1558 if (pDevIns->pReg->pfnSuspend)
1559 {
1560 if (!pDevIns->Internal.s.pfnAsyncNotify)
1561 {
1562 LogFlow(("PDMR3Suspend: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1563 pDevIns->pReg->pfnSuspend(pDevIns);
1564 if (pDevIns->Internal.s.pfnAsyncNotify)
1565 LogFlow(("PDMR3Suspend: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1566 }
1567 else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
1568 {
1569 LogFlow(("PDMR3Suspend: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1570 pDevIns->Internal.s.pfnAsyncNotify = NULL;
1571 }
1572 if (pDevIns->Internal.s.pfnAsyncNotify)
1573 {
1574 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1575 pdmR3NotifyAsyncAdd(pAsync, pDevIns->Internal.s.pDevR3->pReg->szName, pDevIns->iInstance);
1576 }
1577 }
1578 }
1579}
1580
1581
1582/**
1583 * This function will notify all the devices and their attached drivers about
1584 * the VM now being suspended.
1585 *
1586 * @param pVM The VM Handle.
1587 * @thread EMT(0)
1588 */
1589VMMR3DECL(void) PDMR3Suspend(PVM pVM)
1590{
1591 LogFlow(("PDMR3Suspend:\n"));
1592 VM_ASSERT_EMT0(pVM);
1593
1594 /*
1595 * The outer loop repeats until there are no more async requests.
1596 *
1597 * Note! We depend on the suspended indicators to be in the desired state
1598 * and we do not reset them before starting because this allows
1599 * PDMR3PowerOn and PDMR3Resume to use PDMR3Suspend for cleaning up
1600 * on failure.
1601 */
1602 PDMNOTIFYASYNCSTATS Async;
1603 pdmR3NotifyAsyncInit(&Async, "PDMR3Suspend");
1604 for (;;)
1605 {
1606 pdmR3NotifyAsyncBeginLoop(&Async);
1607
1608 /*
1609 * Iterate thru the device instances and USB device instances,
1610 * processing the drivers associated with those.
1611 *
1612 * The attached drivers are normally processed first. Some devices
1613 * (like DevAHCI) though needs to be notified before the drivers so
1614 * that it doesn't kick off any new requests after the drivers stopped
1615 * taking any. (DrvVD changes to read-only in this particular case.)
1616 */
1617 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1618 {
1619 unsigned const cAsyncStart = Async.cAsync;
1620
1621 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION)
1622 pdmR3SuspendDev(pDevIns, &Async);
1623
1624 if (Async.cAsync == cAsyncStart)
1625 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1626 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1627 if (!pdmR3SuspendDrv(pDrvIns, &Async, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
1628 break;
1629
1630 if ( Async.cAsync == cAsyncStart
1631 && !(pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION))
1632 pdmR3SuspendDev(pDevIns, &Async);
1633 }
1634
1635#ifdef VBOX_WITH_USB
1636 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1637 {
1638 unsigned const cAsyncStart = Async.cAsync;
1639
1640 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1641 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1642 if (!pdmR3SuspendDrv(pDrvIns, &Async, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
1643 break;
1644
1645 if (Async.cAsync == cAsyncStart)
1646 pdmR3SuspendUsb(pUsbIns, &Async);
1647 }
1648#endif
1649 if (!Async.cAsync)
1650 break;
1651 pdmR3NotifyAsyncLog(&Async);
1652 pdmR3NotifyAsyncWaitAndProcessRequests(&Async, pVM);
1653 }
1654
1655 /*
1656 * Suspend all threads.
1657 */
1658 pdmR3ThreadSuspendAll(pVM);
1659
1660 LogFlow(("PDMR3Suspend: returns void\n"));
1661}
1662
1663
1664/**
1665 * Worker for PDMR3Resume that deals with one driver.
1666 *
1667 * @param pDrvIns The driver instance.
1668 * @param pszDevName The parent device name.
1669 * @param iDevInstance The parent device instance number.
1670 * @param iLun The parent LUN number.
1671 */
1672DECLINLINE(int) pdmR3ResumeDrv(PPDMDRVINS pDrvIns, const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1673{
1674 Assert(pDrvIns->Internal.s.fVMSuspended);
1675 if (pDrvIns->pReg->pfnResume)
1676 {
1677 LogFlow(("PDMR3Resume: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1678 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1679 int rc = VINF_SUCCESS; pDrvIns->pReg->pfnResume(pDrvIns);
1680 if (RT_FAILURE(rc))
1681 {
1682 LogRel(("PDMR3Resume: driver '%s'/%d on LUN#%d of device '%s'/%d -> %Rrc\n",
1683 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance, rc));
1684 return rc;
1685 }
1686 }
1687 pDrvIns->Internal.s.fVMSuspended = false;
1688 return VINF_SUCCESS;
1689}
1690
1691
1692/**
1693 * Worker for PDMR3Resume that deals with one USB device instance.
1694 *
1695 * @returns VBox status code.
1696 * @param pUsbIns The USB device instance.
1697 */
1698DECLINLINE(int) pdmR3ResumeUsb(PPDMUSBINS pUsbIns)
1699{
1700 Assert(pUsbIns->Internal.s.fVMSuspended);
1701 if (pUsbIns->pReg->pfnVMResume)
1702 {
1703 LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1704 int rc = VINF_SUCCESS; pUsbIns->pReg->pfnVMResume(pUsbIns);
1705 if (RT_FAILURE(rc))
1706 {
1707 LogRel(("PDMR3Resume: device '%s'/%d -> %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1708 return rc;
1709 }
1710 }
1711 pUsbIns->Internal.s.fVMSuspended = false;
1712 return VINF_SUCCESS;
1713}
1714
1715
1716/**
1717 * Worker for PDMR3Resume that deals with one device instance.
1718 *
1719 * @returns VBox status code.
1720 * @param pDevIns The device instance.
1721 */
1722DECLINLINE(int) pdmR3ResumeDev(PPDMDEVINS pDevIns)
1723{
1724 Assert(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED);
1725 if (pDevIns->pReg->pfnResume)
1726 {
1727 LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1728 int rc = VINF_SUCCESS; pDevIns->pReg->pfnResume(pDevIns);
1729 if (RT_FAILURE(rc))
1730 {
1731 LogRel(("PDMR3Resume: device '%s'/%d -> %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
1732 return rc;
1733 }
1734 }
1735 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1736 return VINF_SUCCESS;
1737}
1738
1739
1740/**
1741 * This function will notify all the devices and their
1742 * attached drivers about the VM now being resumed.
1743 *
1744 * @param pVM VM Handle.
1745 */
1746VMMR3DECL(void) PDMR3Resume(PVM pVM)
1747{
1748 LogFlow(("PDMR3Resume:\n"));
1749
1750 /*
1751 * Iterate thru the device instances and USB device instances,
1752 * processing the drivers associated with those.
1753 */
1754 int rc = VINF_SUCCESS;
1755 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns && RT_SUCCESS(rc); pDevIns = pDevIns->Internal.s.pNextR3)
1756 {
1757 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1758 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1759 rc = pdmR3ResumeDrv(pDrvIns, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun);
1760 if (RT_SUCCESS(rc))
1761 rc = pdmR3ResumeDev(pDevIns);
1762 }
1763
1764#ifdef VBOX_WITH_USB
1765 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns && RT_SUCCESS(rc); pUsbIns = pUsbIns->Internal.s.pNext)
1766 {
1767 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1768 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1769 rc = pdmR3ResumeDrv(pDrvIns, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun);
1770 if (RT_SUCCESS(rc))
1771 rc = pdmR3ResumeUsb(pUsbIns);
1772 }
1773#endif
1774
1775 /*
1776 * Resume all threads.
1777 */
1778 if (RT_SUCCESS(rc))
1779 pdmR3ThreadResumeAll(pVM);
1780
1781 /*
1782 * Resume the block cache.
1783 */
1784 if (RT_SUCCESS(rc))
1785 pdmR3BlkCacheResume(pVM);
1786
1787 /*
1788 * On failure, clean up via PDMR3Suspend.
1789 */
1790 if (RT_FAILURE(rc))
1791 PDMR3Suspend(pVM);
1792
1793 LogFlow(("PDMR3Resume: returns %Rrc\n", rc));
1794 return /*rc*/;
1795}
1796
1797
1798/**
1799 * Worker for PDMR3PowerOff that deals with one driver.
1800 *
1801 * @param pDrvIns The driver instance.
1802 * @param pAsync The structure for recording asynchronous
1803 * notification tasks.
1804 * @param pszDevName The parent device name.
1805 * @param iDevInstance The parent device instance number.
1806 * @param iLun The parent LUN number.
1807 */
1808DECLINLINE(bool) pdmR3PowerOffDrv(PPDMDRVINS pDrvIns, PPDMNOTIFYASYNCSTATS pAsync,
1809 const char *pszDevName, uint32_t iDevInstance, uint32_t iLun)
1810{
1811 if (!pDrvIns->Internal.s.fVMSuspended)
1812 {
1813 pDrvIns->Internal.s.fVMSuspended = true;
1814 if (pDrvIns->pReg->pfnPowerOff)
1815 {
1816 if (!pDrvIns->Internal.s.pfnAsyncNotify)
1817 {
1818 LogFlow(("PDMR3PowerOff: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1819 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1820 pDrvIns->pReg->pfnPowerOff(pDrvIns);
1821 if (pDrvIns->Internal.s.pfnAsyncNotify)
1822 LogFlow(("PDMR3PowerOff: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1823 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1824 }
1825 else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
1826 {
1827 pDrvIns->Internal.s.pfnAsyncNotify = false;
1828 LogFlow(("PDMR3PowerOff: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1829 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDevName, iDevInstance));
1830 }
1831 if (pDrvIns->Internal.s.pfnAsyncNotify)
1832 {
1833 pDrvIns->Internal.s.fVMSuspended = false;
1834 pdmR3NotifyAsyncAddDrv(pAsync, pDrvIns->Internal.s.pDrv->pReg->szName, pDrvIns->iInstance,
1835 pszDevName, iDevInstance, iLun);
1836 return false;
1837 }
1838 }
1839 }
1840 return true;
1841}
1842
1843
1844/**
1845 * Worker for PDMR3PowerOff that deals with one USB device instance.
1846 *
1847 * @param pUsbIns The USB device instance.
1848 * @param pAsync The structure for recording asynchronous
1849 * notification tasks.
1850 */
1851DECLINLINE(void) pdmR3PowerOffUsb(PPDMUSBINS pUsbIns, PPDMNOTIFYASYNCSTATS pAsync)
1852{
1853 if (!pUsbIns->Internal.s.fVMSuspended)
1854 {
1855 pUsbIns->Internal.s.fVMSuspended = true;
1856 if (pUsbIns->pReg->pfnVMPowerOff)
1857 {
1858 if (!pUsbIns->Internal.s.pfnAsyncNotify)
1859 {
1860 LogFlow(("PDMR3PowerOff: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1861 pUsbIns->pReg->pfnVMPowerOff(pUsbIns);
1862 if (pUsbIns->Internal.s.pfnAsyncNotify)
1863 LogFlow(("PDMR3PowerOff: Async notification started - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1864 }
1865 else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
1866 {
1867 LogFlow(("PDMR3PowerOff: Async notification completed - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1868 pUsbIns->Internal.s.pfnAsyncNotify = NULL;
1869 }
1870 if (pUsbIns->Internal.s.pfnAsyncNotify)
1871 {
1872 pUsbIns->Internal.s.fVMSuspended = false;
1873 pdmR3NotifyAsyncAdd(pAsync, pUsbIns->Internal.s.pUsbDev->pReg->szName, pUsbIns->iInstance);
1874 }
1875 }
1876 }
1877}
1878
1879
1880/**
1881 * Worker for PDMR3PowerOff that deals with one device instance.
1882 *
1883 * @param pDevIns The device instance.
1884 * @param pAsync The structure for recording asynchronous
1885 * notification tasks.
1886 */
1887DECLINLINE(void) pdmR3PowerOffDev(PPDMDEVINS pDevIns, PPDMNOTIFYASYNCSTATS pAsync)
1888{
1889 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED))
1890 {
1891 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_SUSPENDED;
1892 if (pDevIns->pReg->pfnPowerOff)
1893 {
1894 if (!pDevIns->Internal.s.pfnAsyncNotify)
1895 {
1896 LogFlow(("PDMR3PowerOff: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1897 pDevIns->pReg->pfnPowerOff(pDevIns);
1898 if (pDevIns->Internal.s.pfnAsyncNotify)
1899 LogFlow(("PDMR3PowerOff: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1900 }
1901 else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
1902 {
1903 LogFlow(("PDMR3PowerOff: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1904 pDevIns->Internal.s.pfnAsyncNotify = NULL;
1905 }
1906 if (pDevIns->Internal.s.pfnAsyncNotify)
1907 {
1908 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1909 pdmR3NotifyAsyncAdd(pAsync, pDevIns->Internal.s.pDevR3->pReg->szName, pDevIns->iInstance);
1910 }
1911 }
1912 }
1913}
1914
1915
1916/**
1917 * This function will notify all the devices and their
1918 * attached drivers about the VM being powered off.
1919 *
1920 * @param pVM VM Handle.
1921 */
1922VMMR3DECL(void) PDMR3PowerOff(PVM pVM)
1923{
1924 LogFlow(("PDMR3PowerOff:\n"));
1925
1926 /*
1927 * The outer loop repeats until there are no more async requests.
1928 */
1929 PDMNOTIFYASYNCSTATS Async;
1930 pdmR3NotifyAsyncInit(&Async, "PDMR3PowerOff");
1931 for (;;)
1932 {
1933 pdmR3NotifyAsyncBeginLoop(&Async);
1934
1935 /*
1936 * Iterate thru the device instances and USB device instances,
1937 * processing the drivers associated with those.
1938 *
1939 * The attached drivers are normally processed first. Some devices
1940 * (like DevAHCI) though needs to be notified before the drivers so
1941 * that it doesn't kick off any new requests after the drivers stopped
1942 * taking any. (DrvVD changes to read-only in this particular case.)
1943 */
1944 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1945 {
1946 unsigned const cAsyncStart = Async.cAsync;
1947
1948 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION)
1949 pdmR3PowerOffDev(pDevIns, &Async);
1950
1951 if (Async.cAsync == cAsyncStart)
1952 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1953 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1954 if (!pdmR3PowerOffDrv(pDrvIns, &Async, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
1955 break;
1956
1957 if ( Async.cAsync == cAsyncStart
1958 && !(pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION))
1959 pdmR3PowerOffDev(pDevIns, &Async);
1960 }
1961
1962#ifdef VBOX_WITH_USB
1963 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1964 {
1965 unsigned const cAsyncStart = Async.cAsync;
1966
1967 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1968 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1969 if (!pdmR3PowerOffDrv(pDrvIns, &Async, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
1970 break;
1971
1972 if (Async.cAsync == cAsyncStart)
1973 pdmR3PowerOffUsb(pUsbIns, &Async);
1974 }
1975#endif
1976 if (!Async.cAsync)
1977 break;
1978 pdmR3NotifyAsyncLog(&Async);
1979 pdmR3NotifyAsyncWaitAndProcessRequests(&Async, pVM);
1980 }
1981
1982 /*
1983 * Suspend all threads.
1984 */
1985 pdmR3ThreadSuspendAll(pVM);
1986
1987 LogFlow(("PDMR3PowerOff: returns void\n"));
1988}
1989
1990
1991/**
1992 * Queries the base interface of a device instance.
1993 *
1994 * The caller can use this to query other interfaces the device implements
1995 * and use them to talk to the device.
1996 *
1997 * @returns VBox status code.
1998 * @param pVM VM handle.
1999 * @param pszDevice Device name.
2000 * @param iInstance Device instance.
2001 * @param ppBase Where to store the pointer to the base device interface on success.
2002 * @remark We're not doing any locking ATM, so don't try call this at times when the
2003 * device chain is known to be updated.
2004 */
2005VMMR3DECL(int) PDMR3QueryDevice(PVM pVM, const char *pszDevice, unsigned iInstance, PPDMIBASE *ppBase)
2006{
2007 LogFlow(("PDMR3DeviceQuery: pszDevice=%p:{%s} iInstance=%u ppBase=%p\n", pszDevice, pszDevice, iInstance, ppBase));
2008
2009 /*
2010 * Iterate registered devices looking for the device.
2011 */
2012 size_t cchDevice = strlen(pszDevice);
2013 for (PPDMDEV pDev = pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
2014 {
2015 if ( pDev->cchName == cchDevice
2016 && !memcmp(pDev->pReg->szName, pszDevice, cchDevice))
2017 {
2018 /*
2019 * Iterate device instances.
2020 */
2021 for (PPDMDEVINS pDevIns = pDev->pInstances; pDevIns; pDevIns = pDevIns->Internal.s.pPerDeviceNextR3)
2022 {
2023 if (pDevIns->iInstance == iInstance)
2024 {
2025 if (pDevIns->IBase.pfnQueryInterface)
2026 {
2027 *ppBase = &pDevIns->IBase;
2028 LogFlow(("PDMR3DeviceQuery: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
2029 return VINF_SUCCESS;
2030 }
2031
2032 LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NO_IBASE\n"));
2033 return VERR_PDM_DEVICE_INSTANCE_NO_IBASE;
2034 }
2035 }
2036
2037 LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NOT_FOUND\n"));
2038 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND;
2039 }
2040 }
2041
2042 LogFlow(("PDMR3QueryDevice: returns VERR_PDM_DEVICE_NOT_FOUND\n"));
2043 return VERR_PDM_DEVICE_NOT_FOUND;
2044}
2045
2046
2047/**
2048 * Queries the base interface of a device LUN.
2049 *
2050 * This differs from PDMR3QueryLun by that it returns the interface on the
2051 * device and not the top level driver.
2052 *
2053 * @returns VBox status code.
2054 * @param pVM VM Handle.
2055 * @param pszDevice Device name.
2056 * @param iInstance Device instance.
2057 * @param iLun The Logical Unit to obtain the interface of.
2058 * @param ppBase Where to store the base interface pointer.
2059 * @remark We're not doing any locking ATM, so don't try call this at times when the
2060 * device chain is known to be updated.
2061 */
2062VMMR3DECL(int) PDMR3QueryDeviceLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
2063{
2064 LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
2065 pszDevice, pszDevice, iInstance, iLun, ppBase));
2066
2067 /*
2068 * Find the LUN.
2069 */
2070 PPDMLUN pLun;
2071 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
2072 if (RT_SUCCESS(rc))
2073 {
2074 *ppBase = pLun->pBase;
2075 LogFlow(("PDMR3QueryDeviceLun: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
2076 return VINF_SUCCESS;
2077 }
2078 LogFlow(("PDMR3QueryDeviceLun: returns %Rrc\n", rc));
2079 return rc;
2080}
2081
2082
2083/**
2084 * Query the interface of the top level driver on a LUN.
2085 *
2086 * @returns VBox status code.
2087 * @param pVM VM Handle.
2088 * @param pszDevice Device name.
2089 * @param iInstance Device instance.
2090 * @param iLun The Logical Unit to obtain the interface of.
2091 * @param ppBase Where to store the base interface pointer.
2092 * @remark We're not doing any locking ATM, so don't try call this at times when the
2093 * device chain is known to be updated.
2094 */
2095VMMR3DECL(int) PDMR3QueryLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
2096{
2097 LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
2098 pszDevice, pszDevice, iInstance, iLun, ppBase));
2099 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
2100
2101 /*
2102 * Find the LUN.
2103 */
2104 PPDMLUN pLun;
2105 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
2106 if (RT_SUCCESS(rc))
2107 {
2108 if (pLun->pTop)
2109 {
2110 *ppBase = &pLun->pTop->IBase;
2111 LogFlow(("PDMR3QueryLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
2112 return VINF_SUCCESS;
2113 }
2114 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
2115 }
2116 LogFlow(("PDMR3QueryLun: returns %Rrc\n", rc));
2117 return rc;
2118}
2119
2120
2121/**
2122 * Query the interface of a named driver on a LUN.
2123 *
2124 * If the driver appears more than once in the driver chain, the first instance
2125 * is returned.
2126 *
2127 * @returns VBox status code.
2128 * @param pVM VM Handle.
2129 * @param pszDevice Device name.
2130 * @param iInstance Device instance.
2131 * @param iLun The Logical Unit to obtain the interface of.
2132 * @param pszDriver The driver name.
2133 * @param ppBase Where to store the base interface pointer.
2134 *
2135 * @remark We're not doing any locking ATM, so don't try call this at times when the
2136 * device chain is known to be updated.
2137 */
2138VMMR3DECL(int) PDMR3QueryDriverOnLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, const char *pszDriver, PPPDMIBASE ppBase)
2139{
2140 LogFlow(("PDMR3QueryDriverOnLun: pszDevice=%p:{%s} iInstance=%u iLun=%u pszDriver=%p:{%s} ppBase=%p\n",
2141 pszDevice, pszDevice, iInstance, iLun, pszDriver, pszDriver, ppBase));
2142
2143 /*
2144 * Find the LUN.
2145 */
2146 PPDMLUN pLun;
2147 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
2148 if (RT_SUCCESS(rc))
2149 {
2150 if (pLun->pTop)
2151 {
2152 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2153 if (!strcmp(pDrvIns->pReg->szName, pszDriver))
2154 {
2155 *ppBase = &pDrvIns->IBase;
2156 LogFlow(("PDMR3QueryDriverOnLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
2157 return VINF_SUCCESS;
2158
2159 }
2160 rc = VERR_PDM_DRIVER_NOT_FOUND;
2161 }
2162 else
2163 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
2164 }
2165 LogFlow(("PDMR3QueryDriverOnLun: returns %Rrc\n", rc));
2166 return rc;
2167}
2168
2169/**
2170 * Executes pending DMA transfers.
2171 * Forced Action handler.
2172 *
2173 * @param pVM VM handle.
2174 */
2175VMMR3DECL(void) PDMR3DmaRun(PVM pVM)
2176{
2177 /* Note! Not really SMP safe; restrict it to VCPU 0. */
2178 if (VMMGetCpuId(pVM) != 0)
2179 return;
2180
2181 if (VM_FF_TESTANDCLEAR(pVM, VM_FF_PDM_DMA))
2182 {
2183 if (pVM->pdm.s.pDmac)
2184 {
2185 bool fMore = pVM->pdm.s.pDmac->Reg.pfnRun(pVM->pdm.s.pDmac->pDevIns);
2186 if (fMore)
2187 VM_FF_SET(pVM, VM_FF_PDM_DMA);
2188 }
2189 }
2190}
2191
2192
2193/**
2194 * Service a VMMCALLRING3_PDM_LOCK call.
2195 *
2196 * @returns VBox status code.
2197 * @param pVM The VM handle.
2198 */
2199VMMR3DECL(int) PDMR3LockCall(PVM pVM)
2200{
2201 return PDMR3CritSectEnterEx(&pVM->pdm.s.CritSect, true /* fHostCall */);
2202}
2203
2204
2205/**
2206 * Registers the VMM device heap
2207 *
2208 * @returns VBox status code.
2209 * @param pVM VM handle.
2210 * @param GCPhys The physical address.
2211 * @param pvHeap Ring-3 pointer.
2212 * @param cbSize Size of the heap.
2213 */
2214VMMR3DECL(int) PDMR3RegisterVMMDevHeap(PVM pVM, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbSize)
2215{
2216 Assert(pVM->pdm.s.pvVMMDevHeap == NULL);
2217
2218 Log(("PDMR3RegisterVMMDevHeap %RGp %RHv %x\n", GCPhys, pvHeap, cbSize));
2219 pVM->pdm.s.pvVMMDevHeap = pvHeap;
2220 pVM->pdm.s.GCPhysVMMDevHeap = GCPhys;
2221 pVM->pdm.s.cbVMMDevHeap = cbSize;
2222 pVM->pdm.s.cbVMMDevHeapLeft = cbSize;
2223 return VINF_SUCCESS;
2224}
2225
2226
2227/**
2228 * Unregisters the VMM device heap
2229 *
2230 * @returns VBox status code.
2231 * @param pVM VM handle.
2232 * @param GCPhys The physical address.
2233 */
2234VMMR3DECL(int) PDMR3UnregisterVMMDevHeap(PVM pVM, RTGCPHYS GCPhys)
2235{
2236 Assert(pVM->pdm.s.GCPhysVMMDevHeap == GCPhys);
2237
2238 Log(("PDMR3UnregisterVMMDevHeap %RGp\n", GCPhys));
2239 pVM->pdm.s.pvVMMDevHeap = NULL;
2240 pVM->pdm.s.GCPhysVMMDevHeap = NIL_RTGCPHYS;
2241 pVM->pdm.s.cbVMMDevHeap = 0;
2242 pVM->pdm.s.cbVMMDevHeapLeft = 0;
2243 return VINF_SUCCESS;
2244}
2245
2246
2247/**
2248 * Allocates memory from the VMM device heap
2249 *
2250 * @returns VBox status code.
2251 * @param pVM VM handle.
2252 * @param cbSize Allocation size.
2253 * @param pv Ring-3 pointer. (out)
2254 */
2255VMMR3DECL(int) PDMR3VMMDevHeapAlloc(PVM pVM, unsigned cbSize, RTR3PTR *ppv)
2256{
2257#ifdef DEBUG_bird
2258 if (!cbSize || cbSize > pVM->pdm.s.cbVMMDevHeapLeft)
2259 return VERR_NO_MEMORY;
2260#else
2261 AssertReturn(cbSize && cbSize <= pVM->pdm.s.cbVMMDevHeapLeft, VERR_NO_MEMORY);
2262#endif
2263
2264 Log(("PDMR3VMMDevHeapAlloc %x\n", cbSize));
2265
2266 /** @todo not a real heap as there's currently only one user. */
2267 *ppv = pVM->pdm.s.pvVMMDevHeap;
2268 pVM->pdm.s.cbVMMDevHeapLeft = 0;
2269 return VINF_SUCCESS;
2270}
2271
2272
2273/**
2274 * Frees memory from the VMM device heap
2275 *
2276 * @returns VBox status code.
2277 * @param pVM VM handle.
2278 * @param pv Ring-3 pointer.
2279 */
2280VMMR3DECL(int) PDMR3VMMDevHeapFree(PVM pVM, RTR3PTR pv)
2281{
2282 Log(("PDMR3VMMDevHeapFree %RHv\n", pv));
2283
2284 /** @todo not a real heap as there's currently only one user. */
2285 pVM->pdm.s.cbVMMDevHeapLeft = pVM->pdm.s.cbVMMDevHeap;
2286 return VINF_SUCCESS;
2287}
2288
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette