VirtualBox

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

Last change on this file since 28549 was 28258, checked in by vboxsync, 15 years ago

PDM critsects for drivers. Fixed critsect cleanup in failure path. Started on new transmit locking scheme (required for intnet buffer serialization).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 74.2 KB
Line 
1/* $Id: PDM.cpp 28258 2010-04-13 14:51:16Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device Manager.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/** @page pg_pdm PDM - The Pluggable Device & Driver Manager
24 *
25 * VirtualBox is designed to be very configurable, i.e. the ability to select
26 * virtual devices and configure them uniquely for a VM. For this reason
27 * virtual devices are not statically linked with the VMM but loaded, linked and
28 * instantiated at runtime by PDM using the information found in the
29 * Configuration Manager (CFGM).
30 *
31 * While the chief purpose of PDM is to manager of devices their drivers, it
32 * also serves as somewhere to put usful things like cross context queues, cross
33 * context synchronization (like critsect), VM centric thread management,
34 * asynchronous I/O framework, and so on.
35 *
36 * @see grp_pdm
37 *
38 *
39 * @section sec_pdm_dev The Pluggable Devices
40 *
41 * Devices register themselves when the module containing them is loaded. PDM
42 * will call the entry point 'VBoxDevicesRegister' when loading a device module.
43 * The device module will then use the supplied callback table to check the VMM
44 * version and to register its devices. Each device have an unique (for the
45 * configured VM) name. The name is not only used in PDM but also in CFGM (to
46 * organize device and device instance settings) and by anyone who wants to talk
47 * to a specific device instance.
48 *
49 * When all device modules have been successfully loaded PDM will instantiate
50 * those devices which are configured for the VM. Note that a device may have
51 * more than one instance, see network adaptors for instance. When
52 * instantiating a device PDM provides device instance memory and a callback
53 * table (aka Device Helpers / DevHlp) with the VM APIs which the device
54 * instance is trusted with.
55 *
56 * Some devices are trusted devices, most are not. The trusted devices are an
57 * integrated part of the VM and can obtain the VM handle from their device
58 * instance handles, thus enabling them to call any VM api. Untrusted devices
59 * can only use the callbacks provided during device instantiation.
60 *
61 * The main purpose in having DevHlps rather than just giving all the devices
62 * the VM handle and let them call the internal VM APIs directly, is both to
63 * create a binary interface that can be supported accross releases and to
64 * create a barrier between devices and the VM. (The trusted / untrusted bit
65 * hasn't turned out to be of much use btw., but it's easy to maintain so there
66 * isn't any point in removing it.)
67 *
68 * A device can provide a ring-0 and/or a raw-mode context extension to improve
69 * the VM performance by handling exits and traps (respectively) without
70 * requiring context switches (to ring-3). Callbacks for MMIO and I/O ports can
71 * needs to be registered specifically for the additional contexts for this to
72 * make sense. Also, the device has to be trusted to be loaded into R0/RC
73 * because of the extra privilege it entails. Note that raw-mode code and data
74 * will be subject to relocation.
75 *
76 *
77 * @section sec_pdm_special_devs Special Devices
78 *
79 * Several kinds of devices interacts with the VMM and/or other device and PDM
80 * will work like a mediator for these. The typical pattern is that the device
81 * calls a special registration device helper with a set of callbacks, PDM
82 * responds by copying this and providing a pointer to a set helper callbacks
83 * for that particular kind of device. Unlike interfaces where the callback
84 * table pointer is used a 'this' pointer, these arrangements will use the
85 * device instance pointer (PPDMDEVINS) as a kind of 'this' pointer.
86 *
87 * For an example of this kind of setup, see the PIC. The PIC registers itself
88 * by calling PDMDEVHLPR3::pfnPICRegister. PDM saves the device instance,
89 * copies the callback tables (PDMPICREG), resolving the ring-0 and raw-mode
90 * addresses in the process, and hands back the pointer to a set of helper
91 * methods (PDMPICHLPR3). The PCI device then queries the ring-0 and raw-mode
92 * helpers using PDMPICHLPR3::pfnGetR0Helpers and PDMPICHLPR3::pfnGetRCHelpers.
93 * The PCI device repeates ths pfnGetRCHelpers call in it's relocation method
94 * since the address changes when RC is relocated.
95 *
96 * @see grp_pdm_device
97 *
98 *
99 * @section sec_pdm_usbdev The Pluggable USB Devices
100 *
101 * USB devices are handled a little bit differently than other devices. The
102 * general concepts wrt. pluggability are mostly the same, but the details
103 * varies. The registration entry point is 'VBoxUsbRegister', the device
104 * instance is PDMUSBINS and the callbacks helpers are different. Also, USB
105 * device are restricted to ring-3 and cannot have any ring-0 or raw-mode
106 * extensions (at least not yet).
107 *
108 * The way USB devices work differs greatly from other devices though since they
109 * aren't attaches directly to the PCI/ISA/whatever system buses but via a
110 * USB host control (OHCI, UHCI or EHCI). USB devices handles USB requests
111 * (URBs) and does not register I/O ports, MMIO ranges or PCI bus
112 * devices/functions.
113 *
114 * @see grp_pdm_usbdev
115 *
116 *
117 * @section sec_pdm_drv The Pluggable Drivers
118 *
119 * The VM devices are often accessing host hardware or OS facilities. For most
120 * devices these facilities can be abstracted in one or more levels. These
121 * abstractions are called drivers.
122 *
123 * For instance take a DVD/CD drive. This can be connected to a SCSI
124 * controller, an ATA controller or a SATA controller. The basics of the DVD/CD
125 * drive implementation remains the same - eject, insert, read, seek, and such.
126 * (For the scsi case, you might wanna speak SCSI directly to, but that can of
127 * course be fixed - see SCSI passthru.) So, it
128 * makes much sense to have a generic CD/DVD driver which implements this.
129 *
130 * Then the media 'inserted' into the DVD/CD drive can be a ISO image, or it can
131 * be read from a real CD or DVD drive (there are probably other custom formats
132 * someone could desire to read or construct too). So, it would make sense to
133 * have abstracted interfaces for dealing with this in a generic way so the
134 * cdrom unit doesn't have to implement it all. Thus we have created the
135 * CDROM/DVD media driver family.
136 *
137 * So, for this example the IDE controller #1 (i.e. secondary) will have
138 * the DVD/CD Driver attached to it's LUN #0 (master). When a media is mounted
139 * the DVD/CD Driver will have a ISO, HostDVD or RAW (media) Driver attached.
140 *
141 * It is possible to configure many levels of drivers inserting filters, loggers,
142 * or whatever you desire into the chain. We're using this for network sniffing
143 * for instance.
144 *
145 * The drivers are loaded in a similar manner to that of the device, namely by
146 * iterating a keyspace in CFGM, load the modules listed there and call
147 * 'VBoxDriversRegister' with a callback table.
148 *
149 * @see grp_pdm_driver
150 *
151 *
152 * @section sec_pdm_ifs Interfaces
153 *
154 * The pluggable drivers and devices exposes one standard interface (callback
155 * table) which is used to construct, destruct, attach, detach,( ++,) and query
156 * other interfaces. A device will query the interfaces required for it's
157 * operation during init and hot-plug. PDM may query some interfaces during
158 * runtime mounting too.
159 *
160 * An interface here means a function table contained within the device or
161 * driver instance data. Its method are invoked with the function table pointer
162 * as the first argument and they will calculate the address of the device or
163 * driver instance data from it. (This is one of the aspects which *might* have
164 * been better done in C++.)
165 *
166 * @see grp_pdm_interfaces
167 *
168 *
169 * @section sec_pdm_utils Utilities
170 *
171 * As mentioned earlier, PDM is the location of any usful constrcts that doesn't
172 * quite fit into IPRT. The next subsections will discuss these.
173 *
174 * One thing these APIs all have in common is that resources will be associated
175 * with a device / driver and automatically freed after it has been destroyed if
176 * the destructor didn't do this.
177 *
178 *
179 * @subsection sec_pdm_async_completion Async I/O
180 *
181 * The PDM Async I/O API provides a somewhat platform agnostic interface for
182 * asynchronous I/O. For reasons of performance and complexcity this does not
183 * build upon any IPRT API.
184 *
185 * @todo more details.
186 *
187 * @see grp_pdm_async_completion
188 *
189 *
190 * @subsection sec_pdm_async_task Async Task - not implemented
191 *
192 * @todo implement and describe
193 *
194 * @see grp_pdm_async_task
195 *
196 *
197 * @subsection sec_pdm_critsect Critical Section
198 *
199 * The PDM Critical Section API is currently building on the IPRT API with the
200 * same name. It adds the posibility to use critical sections in ring-0 and
201 * raw-mode as well as in ring-3. There are certain restrictions on the RC and
202 * R0 usage though since we're not able to wait on it, nor wake up anyone that
203 * is waiting on it. These restrictions origins with the use of a ring-3 event
204 * semaphore. In a later incarnation we plan to replace the ring-3 event
205 * semaphore with a ring-0 one, thus enabling us to wake up waiters while
206 * exectuing in ring-0 and making the hardware assisted execution mode more
207 * efficient. (Raw-mode won't benefit much from this, naturally.)
208 *
209 * @see grp_pdm_critsect
210 *
211 *
212 * @subsection sec_pdm_queue Queue
213 *
214 * The PDM Queue API is for queuing one or more tasks for later consumption in
215 * ring-3 by EMT, and optinally forcing a delayed or ASAP return to ring-3. The
216 * queues can also be run on a timer basis as an alternative to the ASAP thing.
217 * The queue will be flushed at forced action time.
218 *
219 * A queue can also be used by another thread (a I/O worker for instance) to
220 * send work / events over to the EMT.
221 *
222 * @see grp_pdm_queue
223 *
224 *
225 * @subsection sec_pdm_task Task - not implemented yet
226 *
227 * The PDM Task API is for flagging a task for execution at a later point when
228 * we're back in ring-3, optionally forcing the ring-3 return to happen ASAP.
229 * As you can see the concept is similar to queues only simpler.
230 *
231 * A task can also be scheduled by another thread (a I/O worker for instance) as
232 * a mean of getting something done in EMT.
233 *
234 * @see grp_pdm_task
235 *
236 *
237 * @subsection sec_pdm_thread Thread
238 *
239 * The PDM Thread API is there to help devices and drivers manage their threads
240 * correctly wrt. power on, suspend, resume, power off and destruction.
241 *
242 * The general usage pattern for threads in the employ of devices and drivers is
243 * that they shuffle data or requests while the VM is running and stop doing
244 * this when the VM is paused or powered down. Rogue threads running while the
245 * VM is paused can cause the state to change during saving or have other
246 * unwanted side effects. The PDM Threads API ensures that this won't happen.
247 *
248 * @see grp_pdm_thread
249 *
250 */
251
252
253/*******************************************************************************
254* Header Files *
255*******************************************************************************/
256#define LOG_GROUP LOG_GROUP_PDM
257#include "PDMInternal.h"
258#include <VBox/pdm.h>
259#include <VBox/mm.h>
260#include <VBox/pgm.h>
261#include <VBox/ssm.h>
262#include <VBox/vm.h>
263#include <VBox/uvm.h>
264#include <VBox/vmm.h>
265#include <VBox/param.h>
266#include <VBox/err.h>
267#include <VBox/sup.h>
268
269#include <VBox/log.h>
270#include <iprt/asm.h>
271#include <iprt/assert.h>
272#include <iprt/alloc.h>
273#include <iprt/ldr.h>
274#include <iprt/path.h>
275#include <iprt/string.h>
276
277
278/*******************************************************************************
279* Defined Constants And Macros *
280*******************************************************************************/
281/** The PDM saved state version. */
282#define PDM_SAVED_STATE_VERSION 4
283#define PDM_SAVED_STATE_VERSION_PRE_NMI_FF 3
284
285
286/*******************************************************************************
287* Internal Functions *
288*******************************************************************************/
289static DECLCALLBACK(int) pdmR3LiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass);
290static DECLCALLBACK(int) pdmR3SaveExec(PVM pVM, PSSMHANDLE pSSM);
291static DECLCALLBACK(int) pdmR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
292static DECLCALLBACK(int) pdmR3LoadPrep(PVM pVM, PSSMHANDLE pSSM);
293
294
295
296/**
297 * Initializes the PDM part of the UVM.
298 *
299 * This doesn't really do much right now but has to be here for the sake
300 * of completeness.
301 *
302 * @returns VBox status code.
303 * @param pUVM Pointer to the user mode VM structure.
304 */
305VMMR3DECL(int) PDMR3InitUVM(PUVM pUVM)
306{
307 AssertCompile(sizeof(pUVM->pdm.s) <= sizeof(pUVM->pdm.padding));
308 AssertRelease(sizeof(pUVM->pdm.s) <= sizeof(pUVM->pdm.padding));
309 pUVM->pdm.s.pModules = NULL;
310 pUVM->pdm.s.pCritSects = NULL;
311 return RTCritSectInit(&pUVM->pdm.s.ListCritSect);
312}
313
314
315/**
316 * Initializes the PDM.
317 *
318 * @returns VBox status code.
319 * @param pVM The VM to operate on.
320 */
321VMMR3DECL(int) PDMR3Init(PVM pVM)
322{
323 LogFlow(("PDMR3Init\n"));
324
325 /*
326 * Assert alignment and sizes.
327 */
328 AssertRelease(!(RT_OFFSETOF(VM, pdm.s) & 31));
329 AssertRelease(sizeof(pVM->pdm.s) <= sizeof(pVM->pdm.padding));
330 AssertCompileMemberAlignment(PDM, CritSect, sizeof(uintptr_t));
331 /*
332 * Init the structure.
333 */
334 pVM->pdm.s.offVM = RT_OFFSETOF(VM, pdm.s);
335 pVM->pdm.s.GCPhysVMMDevHeap = NIL_RTGCPHYS;
336
337 /*
338 * Initialize sub compontents.
339 */
340 int rc = pdmR3CritSectInitStats(pVM);
341 if (RT_SUCCESS(rc))
342 rc = PDMR3CritSectInit(pVM, &pVM->pdm.s.CritSect, RT_SRC_POS, "PDM");
343 if (RT_SUCCESS(rc))
344 rc = pdmR3LdrInitU(pVM->pUVM);
345#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
346 if (RT_SUCCESS(rc))
347 rc = pdmR3AsyncCompletionInit(pVM);
348#endif
349 if (RT_SUCCESS(rc))
350 rc = pdmR3DrvInit(pVM);
351 if (RT_SUCCESS(rc))
352 rc = pdmR3DevInit(pVM);
353 if (RT_SUCCESS(rc))
354 {
355 /*
356 * Register the saved state data unit.
357 */
358 rc = SSMR3RegisterInternal(pVM, "pdm", 1, PDM_SAVED_STATE_VERSION, 128,
359 NULL, pdmR3LiveExec, NULL,
360 NULL, pdmR3SaveExec, NULL,
361 pdmR3LoadPrep, pdmR3LoadExec, NULL);
362 if (RT_SUCCESS(rc))
363 {
364 LogFlow(("PDM: Successfully initialized\n"));
365 return rc;
366 }
367 }
368
369 /*
370 * Cleanup and return failure.
371 */
372 PDMR3Term(pVM);
373 LogFlow(("PDMR3Init: returns %Rrc\n", rc));
374 return rc;
375}
376
377
378/**
379 * Applies relocations to data and code managed by this
380 * component. This function will be called at init and
381 * whenever the VMM need to relocate it self inside the GC.
382 *
383 * @param pVM VM handle.
384 * @param offDelta Relocation delta relative to old location.
385 * @remark The loader subcomponent is relocated by PDMR3LdrRelocate() very
386 * early in the relocation phase.
387 */
388VMMR3DECL(void) PDMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
389{
390 LogFlow(("PDMR3Relocate\n"));
391
392 /*
393 * Queues.
394 */
395 pdmR3QueueRelocate(pVM, offDelta);
396 pVM->pdm.s.pDevHlpQueueRC = PDMQueueRCPtr(pVM->pdm.s.pDevHlpQueueR3);
397
398 /*
399 * Critical sections.
400 */
401 pdmR3CritSectRelocate(pVM);
402
403 /*
404 * The registered PIC.
405 */
406 if (pVM->pdm.s.Pic.pDevInsRC)
407 {
408 pVM->pdm.s.Pic.pDevInsRC += offDelta;
409 pVM->pdm.s.Pic.pfnSetIrqRC += offDelta;
410 pVM->pdm.s.Pic.pfnGetInterruptRC += offDelta;
411 }
412
413 /*
414 * The registered APIC.
415 */
416 if (pVM->pdm.s.Apic.pDevInsRC)
417 {
418 pVM->pdm.s.Apic.pDevInsRC += offDelta;
419 pVM->pdm.s.Apic.pfnGetInterruptRC += offDelta;
420 pVM->pdm.s.Apic.pfnSetBaseRC += offDelta;
421 pVM->pdm.s.Apic.pfnGetBaseRC += offDelta;
422 pVM->pdm.s.Apic.pfnSetTPRRC += offDelta;
423 pVM->pdm.s.Apic.pfnGetTPRRC += offDelta;
424 pVM->pdm.s.Apic.pfnBusDeliverRC += offDelta;
425 if (pVM->pdm.s.Apic.pfnLocalInterruptRC)
426 pVM->pdm.s.Apic.pfnLocalInterruptRC += offDelta;
427 pVM->pdm.s.Apic.pfnWriteMSRRC += offDelta;
428 pVM->pdm.s.Apic.pfnReadMSRRC += offDelta;
429 }
430
431 /*
432 * The registered I/O APIC.
433 */
434 if (pVM->pdm.s.IoApic.pDevInsRC)
435 {
436 pVM->pdm.s.IoApic.pDevInsRC += offDelta;
437 pVM->pdm.s.IoApic.pfnSetIrqRC += offDelta;
438 }
439
440 /*
441 * The register PCI Buses.
442 */
443 for (unsigned i = 0; i < RT_ELEMENTS(pVM->pdm.s.aPciBuses); i++)
444 {
445 if (pVM->pdm.s.aPciBuses[i].pDevInsRC)
446 {
447 pVM->pdm.s.aPciBuses[i].pDevInsRC += offDelta;
448 pVM->pdm.s.aPciBuses[i].pfnSetIrqRC += offDelta;
449 }
450 }
451
452 /*
453 * Devices & Drivers.
454 */
455 PCPDMDEVHLPRC pDevHlpRC;
456 int rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDevHlp", &pDevHlpRC);
457 AssertReleaseMsgRC(rc, ("rc=%Rrc when resolving g_pdmRCDevHlp\n", rc));
458
459 PCPDMDRVHLPRC pDrvHlpRC;
460 rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDevHlp", &pDrvHlpRC);
461 AssertReleaseMsgRC(rc, ("rc=%Rrc when resolving g_pdmRCDevHlp\n", rc));
462
463 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
464 {
465 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_RC)
466 {
467 pDevIns->pHlpRC = pDevHlpRC;
468 pDevIns->pvInstanceDataRC = MMHyperR3ToRC(pVM, pDevIns->pvInstanceDataR3);
469 if (pDevIns->pCritSectR3)
470 pDevIns->pCritSectRC = MMHyperR3ToRC(pVM, pDevIns->pCritSectR3);
471 pDevIns->Internal.s.pVMRC = pVM->pVMRC;
472 if (pDevIns->Internal.s.pPciBusR3)
473 pDevIns->Internal.s.pPciBusRC = MMHyperR3ToRC(pVM, pDevIns->Internal.s.pPciBusR3);
474 if (pDevIns->Internal.s.pPciDeviceR3)
475 pDevIns->Internal.s.pPciDeviceRC = MMHyperR3ToRC(pVM, pDevIns->Internal.s.pPciDeviceR3);
476 if (pDevIns->pReg->pfnRelocate)
477 {
478 LogFlow(("PDMR3Relocate: Relocating device '%s'/%d\n",
479 pDevIns->pReg->szName, pDevIns->iInstance));
480 pDevIns->pReg->pfnRelocate(pDevIns, offDelta);
481 }
482 }
483
484 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
485 {
486 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
487 {
488 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_RC)
489 {
490 pDrvIns->pHlpRC = pDrvHlpRC;
491 pDrvIns->pvInstanceDataRC = MMHyperR3ToRC(pVM, pDrvIns->pvInstanceDataR3);
492 pDrvIns->Internal.s.pVMRC = pVM->pVMRC;
493 if (pDrvIns->pReg->pfnRelocate)
494 {
495 LogFlow(("PDMR3Relocate: Relocating driver '%s'/%u attached to '%s'/%d/%u\n",
496 pDrvIns->pReg->szName, pDrvIns->iInstance,
497 pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun));
498 pDrvIns->pReg->pfnRelocate(pDrvIns, offDelta);
499 }
500 }
501 }
502 }
503
504 }
505}
506
507
508/**
509 * Worker for pdmR3Term that terminates a LUN chain.
510 *
511 * @param pVM Pointer to the shared VM structure.
512 * @param pLun The head of the chain.
513 * @param pszDevice The name of the device (for logging).
514 * @param iInstance The device instance number (for logging).
515 */
516static void pdmR3TermLuns(PVM pVM, PPDMLUN pLun, const char *pszDevice, unsigned iInstance)
517{
518 for (; pLun; pLun = pLun->pNext)
519 {
520 /*
521 * Destroy them one at a time from the bottom up.
522 * (The serial device/drivers depends on this - bad.)
523 */
524 PPDMDRVINS pDrvIns = pLun->pBottom;
525 pLun->pBottom = pLun->pTop = NULL;
526 while (pDrvIns)
527 {
528 PPDMDRVINS pDrvNext = pDrvIns->Internal.s.pUp;
529
530 if (pDrvIns->pReg->pfnDestruct)
531 {
532 LogFlow(("pdmR3DevTerm: Destroying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
533 pDrvIns->pReg->szName, pDrvIns->iInstance, pLun->iLun, pszDevice, iInstance));
534 pDrvIns->pReg->pfnDestruct(pDrvIns);
535 }
536 pDrvIns->Internal.s.pDrv->cInstances--;
537
538 TMR3TimerDestroyDriver(pVM, pDrvIns);
539 //PDMR3QueueDestroyDriver(pVM, pDrvIns);
540 //pdmR3ThreadDestroyDriver(pVM, pDrvIns);
541 SSMR3DeregisterDriver(pVM, pDrvIns, NULL, 0);
542
543 pDrvIns = pDrvNext;
544 }
545 }
546}
547
548
549/**
550 * Terminates the PDM.
551 *
552 * Termination means cleaning up and freeing all resources,
553 * the VM it self is at this point powered off or suspended.
554 *
555 * @returns VBox status code.
556 * @param pVM The VM to operate on.
557 */
558VMMR3DECL(int) PDMR3Term(PVM pVM)
559{
560 LogFlow(("PDMR3Term:\n"));
561 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
562
563 /*
564 * Iterate the device instances and attach drivers, doing
565 * relevant destruction processing.
566 *
567 * N.B. There is no need to mess around freeing memory allocated
568 * from any MM heap since MM will do that in its Term function.
569 */
570 /* usb ones first. */
571 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
572 {
573 pdmR3TermLuns(pVM, pUsbIns->Internal.s.pLuns, pUsbIns->pReg->szName, pUsbIns->iInstance);
574
575 if (pUsbIns->pReg->pfnDestruct)
576 {
577 LogFlow(("pdmR3DevTerm: Destroying - device '%s'/%d\n",
578 pUsbIns->pReg->szName, pUsbIns->iInstance));
579 pUsbIns->pReg->pfnDestruct(pUsbIns);
580 }
581
582 //TMR3TimerDestroyUsb(pVM, pUsbIns);
583 //SSMR3DeregisterUsb(pVM, pUsbIns, NULL, 0);
584 pdmR3ThreadDestroyUsb(pVM, pUsbIns);
585 }
586
587 /* then the 'normal' ones. */
588 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
589 {
590 pdmR3TermLuns(pVM, pDevIns->Internal.s.pLunsR3, pDevIns->pReg->szName, pDevIns->iInstance);
591
592 if (pDevIns->pReg->pfnDestruct)
593 {
594 LogFlow(("pdmR3DevTerm: Destroying - device '%s'/%d\n",
595 pDevIns->pReg->szName, pDevIns->iInstance));
596 pDevIns->pReg->pfnDestruct(pDevIns);
597 }
598
599 TMR3TimerDestroyDevice(pVM, pDevIns);
600 //SSMR3DeregisterDriver(pVM, pDevIns, NULL, 0);
601 pdmR3CritSectDeleteDevice(pVM, pDevIns);
602 //pdmR3ThreadDestroyDevice(pVM, pDevIns);
603 //PDMR3QueueDestroyDevice(pVM, pDevIns);
604 PGMR3PhysMMIO2Deregister(pVM, pDevIns, UINT32_MAX);
605 }
606
607 /*
608 * Destroy all threads.
609 */
610 pdmR3ThreadDestroyAll(pVM);
611
612#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
613 /*
614 * Free async completion managers.
615 */
616 pdmR3AsyncCompletionTerm(pVM);
617#endif
618
619 /*
620 * Free modules.
621 */
622 pdmR3LdrTermU(pVM->pUVM);
623
624 /*
625 * Destroy the PDM lock.
626 */
627 PDMR3CritSectDelete(&pVM->pdm.s.CritSect);
628 /* The MiscCritSect is deleted by PDMR3CritSectTerm. */
629
630 LogFlow(("PDMR3Term: returns %Rrc\n", VINF_SUCCESS));
631 return VINF_SUCCESS;
632}
633
634
635/**
636 * Terminates the PDM part of the UVM.
637 *
638 * This will unload any modules left behind.
639 *
640 * @param pUVM Pointer to the user mode VM structure.
641 */
642VMMR3DECL(void) PDMR3TermUVM(PUVM pUVM)
643{
644 /*
645 * In the normal cause of events we will now call pdmR3LdrTermU for
646 * the second time. In the case of init failure however, this might
647 * the first time, which is why we do it.
648 */
649 pdmR3LdrTermU(pUVM);
650
651 Assert(pUVM->pdm.s.pCritSects == NULL);
652 RTCritSectDelete(&pUVM->pdm.s.ListCritSect);
653}
654
655
656/**
657 * Bits that are saved in pass 0 and in the final pass.
658 *
659 * @param pVM The VM handle.
660 * @param pSSM The saved state handle.
661 */
662static void pdmR3SaveBoth(PVM pVM, PSSMHANDLE pSSM)
663{
664 /*
665 * Save the list of device instances so we can check that they're all still
666 * there when we load the state and that nothing new has been added.
667 */
668 uint32_t i = 0;
669 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3, i++)
670 {
671 SSMR3PutU32(pSSM, i);
672 SSMR3PutStrZ(pSSM, pDevIns->pReg->szName);
673 SSMR3PutU32(pSSM, pDevIns->iInstance);
674 }
675 SSMR3PutU32(pSSM, UINT32_MAX); /* terminator */
676}
677
678
679/**
680 * Live save.
681 *
682 * @returns VBox status code.
683 * @param pVM The VM handle.
684 * @param pSSM The saved state handle.
685 * @param uPass The pass.
686 */
687static DECLCALLBACK(int) pdmR3LiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass)
688{
689 LogFlow(("pdmR3LiveExec:\n"));
690 AssertReturn(uPass == 0, VERR_INTERNAL_ERROR_4);
691 pdmR3SaveBoth(pVM, pSSM);
692 return VINF_SSM_DONT_CALL_AGAIN;
693}
694
695
696/**
697 * Execute state save operation.
698 *
699 * @returns VBox status code.
700 * @param pVM The VM handle.
701 * @param pSSM The saved state handle.
702 */
703static DECLCALLBACK(int) pdmR3SaveExec(PVM pVM, PSSMHANDLE pSSM)
704{
705 LogFlow(("pdmR3SaveExec:\n"));
706
707 /*
708 * Save interrupt and DMA states.
709 */
710 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
711 {
712 PVMCPU pVCpu = &pVM->aCpus[idCpu];
713 SSMR3PutU32(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC));
714 SSMR3PutU32(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC));
715 SSMR3PutU32(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_NMI));
716 SSMR3PutU32(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_SMI));
717 }
718 SSMR3PutU32(pSSM, VM_FF_ISSET(pVM, VM_FF_PDM_DMA));
719
720 pdmR3SaveBoth(pVM, pSSM);
721 return VINF_SUCCESS;
722}
723
724
725/**
726 * Prepare state load operation.
727 *
728 * This will dispatch pending operations and clear the FFs governed by PDM and its devices.
729 *
730 * @returns VBox status code.
731 * @param pVM The VM handle.
732 * @param pSSM The SSM handle.
733 */
734static DECLCALLBACK(int) pdmR3LoadPrep(PVM pVM, PSSMHANDLE pSSM)
735{
736 LogFlow(("pdmR3LoadPrep: %s%s\n",
737 VM_FF_ISSET(pVM, VM_FF_PDM_QUEUES) ? " VM_FF_PDM_QUEUES" : "",
738 VM_FF_ISSET(pVM, VM_FF_PDM_DMA) ? " VM_FF_PDM_DMA" : ""));
739#ifdef LOG_ENABLED
740 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
741 {
742 PVMCPU pVCpu = &pVM->aCpus[idCpu];
743 LogFlow(("pdmR3LoadPrep: VCPU %u %s%s\n", idCpu,
744 VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC) ? " VMCPU_FF_INTERRUPT_APIC" : "",
745 VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC) ? " VMCPU_FF_INTERRUPT_PIC" : ""));
746 }
747#endif
748
749 /*
750 * In case there is work pending that will raise an interrupt,
751 * start a DMA transfer, or release a lock. (unlikely)
752 */
753 if (VM_FF_ISSET(pVM, VM_FF_PDM_QUEUES))
754 PDMR3QueueFlushAll(pVM);
755
756 /* Clear the FFs. */
757 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
758 {
759 PVMCPU pVCpu = &pVM->aCpus[idCpu];
760 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
761 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
762 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
763 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_SMI);
764 }
765 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
766
767 return VINF_SUCCESS;
768}
769
770
771/**
772 * Execute state load operation.
773 *
774 * @returns VBox status code.
775 * @param pVM VM Handle.
776 * @param pSSM SSM operation handle.
777 * @param uVersion Data layout version.
778 * @param uPass The data pass.
779 */
780static DECLCALLBACK(int) pdmR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
781{
782 int rc;
783
784 LogFlow(("pdmR3LoadExec: uPass=%#x\n", uPass));
785
786 /*
787 * Validate version.
788 */
789 if ( uVersion != PDM_SAVED_STATE_VERSION
790 && uVersion != PDM_SAVED_STATE_VERSION_PRE_NMI_FF)
791 {
792 AssertMsgFailed(("Invalid version uVersion=%d!\n", uVersion));
793 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
794 }
795
796 if (uPass == SSM_PASS_FINAL)
797 {
798 /*
799 * Load the interrupt and DMA states.
800 */
801 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
802 {
803 PVMCPU pVCpu = &pVM->aCpus[idCpu];
804
805 /* APIC interrupt */
806 uint32_t fInterruptPending = 0;
807 rc = SSMR3GetU32(pSSM, &fInterruptPending);
808 if (RT_FAILURE(rc))
809 return rc;
810 if (fInterruptPending & ~1)
811 {
812 AssertMsgFailed(("fInterruptPending=%#x (APIC)\n", fInterruptPending));
813 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
814 }
815 AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC));
816 if (fInterruptPending)
817 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC);
818
819 /* PIC interrupt */
820 fInterruptPending = 0;
821 rc = SSMR3GetU32(pSSM, &fInterruptPending);
822 if (RT_FAILURE(rc))
823 return rc;
824 if (fInterruptPending & ~1)
825 {
826 AssertMsgFailed(("fInterruptPending=%#x (PIC)\n", fInterruptPending));
827 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
828 }
829 AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC));
830 if (fInterruptPending)
831 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC);
832
833 if (uVersion > PDM_SAVED_STATE_VERSION_PRE_NMI_FF)
834 {
835 /* NMI interrupt */
836 fInterruptPending = 0;
837 rc = SSMR3GetU32(pSSM, &fInterruptPending);
838 if (RT_FAILURE(rc))
839 return rc;
840 if (fInterruptPending & ~1)
841 {
842 AssertMsgFailed(("fInterruptPending=%#x (NMI)\n", fInterruptPending));
843 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
844 }
845 AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_NMI));
846 if (fInterruptPending)
847 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI);
848
849 /* SMI interrupt */
850 fInterruptPending = 0;
851 rc = SSMR3GetU32(pSSM, &fInterruptPending);
852 if (RT_FAILURE(rc))
853 return rc;
854 if (fInterruptPending & ~1)
855 {
856 AssertMsgFailed(("fInterruptPending=%#x (SMI)\n", fInterruptPending));
857 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
858 }
859 AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_SMI));
860 if (fInterruptPending)
861 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_SMI);
862 }
863 }
864
865 /* DMA pending */
866 uint32_t fDMAPending = 0;
867 rc = SSMR3GetU32(pSSM, &fDMAPending);
868 if (RT_FAILURE(rc))
869 return rc;
870 if (fDMAPending & ~1)
871 {
872 AssertMsgFailed(("fDMAPending=%#x\n", fDMAPending));
873 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
874 }
875 if (fDMAPending)
876 VM_FF_SET(pVM, VM_FF_PDM_DMA);
877 Log(("pdmR3LoadExec: VM_FF_PDM_DMA=%RTbool\n", VM_FF_ISSET(pVM, VM_FF_PDM_DMA)));
878 }
879
880 /*
881 * Load the list of devices and verify that they are all there.
882 */
883 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
884 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_FOUND;
885
886 for (uint32_t i = 0; ; i++)
887 {
888 /* Get the sequence number / terminator. */
889 uint32_t u32Sep;
890 rc = SSMR3GetU32(pSSM, &u32Sep);
891 if (RT_FAILURE(rc))
892 return rc;
893 if (u32Sep == UINT32_MAX)
894 break;
895 if (u32Sep != i)
896 AssertMsgFailedReturn(("Out of seqence. u32Sep=%#x i=%#x\n", u32Sep, i), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
897
898 /* Get the name and instance number. */
899 char szName[RT_SIZEOFMEMB(PDMDEVREG, szName)];
900 rc = SSMR3GetStrZ(pSSM, szName, sizeof(szName));
901 if (RT_FAILURE(rc))
902 return rc;
903 uint32_t iInstance;
904 rc = SSMR3GetU32(pSSM, &iInstance);
905 if (RT_FAILURE(rc))
906 return rc;
907
908 /* Try locate it. */
909 PPDMDEVINS pDevIns;
910 for (pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
911 if ( !strcmp(szName, pDevIns->pReg->szName)
912 && pDevIns->iInstance == iInstance)
913 {
914 AssertLogRelMsgReturn(!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_FOUND),
915 ("%s/#%u\n", pDevIns->pReg->szName, pDevIns->iInstance),
916 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
917 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_FOUND;
918 break;
919 }
920 if (!pDevIns)
921 {
922 LogRel(("Device '%s'/%d not found in current config\n", szName, iInstance));
923 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
924 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device '%s'/%d not found in current config"), szName, iInstance);
925 }
926 }
927
928 /*
929 * Check that no additional devices were configured.
930 */
931 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
932 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_FOUND))
933 {
934 LogRel(("Device '%s'/%d not found in the saved state\n", pDevIns->pReg->szName, pDevIns->iInstance));
935 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
936 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device '%s'/%d not found in the saved state"),
937 pDevIns->pReg->szName, pDevIns->iInstance);
938 }
939
940 return VINF_SUCCESS;
941}
942
943
944/**
945 * Worker for PDMR3PowerOn that deals with one driver.
946 *
947 * @param pDrvIns The driver instance.
948 * @param pszDeviceName The parent device name.
949 * @param iDevInstance The parent device instance number.
950 * @param iLun The parent LUN number.
951 */
952DECLINLINE(int) pdmR3PowerOnDrv(PPDMDRVINS pDrvIns, const char *pszDeviceName, uint32_t iDevInstance, uint32_t iLun)
953{
954 Assert(pDrvIns->Internal.s.fVMSuspended);
955 if (pDrvIns->pReg->pfnPowerOn)
956 {
957 LogFlow(("PDMR3PowerOn: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
958 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance));
959 int rc = VINF_SUCCESS; pDrvIns->pReg->pfnPowerOn(pDrvIns);
960 if (RT_FAILURE(rc))
961 {
962 LogRel(("PDMR3PowerOn: driver '%s'/%d on LUN#%d of device '%s'/%d -> %Rrc\n",
963 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance, rc));
964 return rc;
965 }
966 }
967 pDrvIns->Internal.s.fVMSuspended = false;
968 return VINF_SUCCESS;
969}
970
971
972/**
973 * Worker for PDMR3PowerOn that deals with one USB device instance.
974 *
975 * @returns VBox status code.
976 * @param pUsbIns The USB device instance.
977 */
978DECLINLINE(int) pdmR3PowerOnUsb(PPDMUSBINS pUsbIns)
979{
980 Assert(pUsbIns->Internal.s.fVMSuspended);
981 if (pUsbIns->pReg->pfnVMPowerOn)
982 {
983 LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
984 int rc = VINF_SUCCESS; pUsbIns->pReg->pfnVMPowerOn(pUsbIns);
985 if (RT_FAILURE(rc))
986 {
987 LogRel(("PDMR3PowerOn: device '%s'/%d -> %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
988 return rc;
989 }
990 }
991 pUsbIns->Internal.s.fVMSuspended = false;
992 return VINF_SUCCESS;
993}
994
995
996/**
997 * Worker for PDMR3PowerOn that deals with one device instance.
998 *
999 * @returns VBox status code.
1000 * @param pDevIns The device instance.
1001 */
1002DECLINLINE(int) pdmR3PowerOnDev(PPDMDEVINS pDevIns)
1003{
1004 Assert(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED);
1005 if (pDevIns->pReg->pfnPowerOn)
1006 {
1007 LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1008 int rc = VINF_SUCCESS; pDevIns->pReg->pfnPowerOn(pDevIns);
1009 if (RT_FAILURE(rc))
1010 {
1011 LogRel(("PDMR3PowerOn: device '%s'/%d -> %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
1012 return rc;
1013 }
1014 }
1015 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1016 return VINF_SUCCESS;
1017}
1018
1019
1020/**
1021 * This function will notify all the devices and their
1022 * attached drivers about the VM now being powered on.
1023 *
1024 * @param pVM VM Handle.
1025 */
1026VMMR3DECL(void) PDMR3PowerOn(PVM pVM)
1027{
1028 LogFlow(("PDMR3PowerOn:\n"));
1029
1030 /*
1031 * Iterate thru the device instances and USB device instances,
1032 * processing the drivers associated with those.
1033 */
1034 int rc = VINF_SUCCESS;
1035 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns && RT_SUCCESS(rc); pDevIns = pDevIns->Internal.s.pNextR3)
1036 {
1037 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1038 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1039 rc = pdmR3PowerOnDrv(pDrvIns, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun);
1040 if (RT_SUCCESS(rc))
1041 rc = pdmR3PowerOnDev(pDevIns);
1042 }
1043
1044#ifdef VBOX_WITH_USB
1045 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns && RT_SUCCESS(rc); pUsbIns = pUsbIns->Internal.s.pNext)
1046 {
1047 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1048 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1049 rc = pdmR3PowerOnDrv(pDrvIns, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun);
1050 if (RT_SUCCESS(rc))
1051 rc = pdmR3PowerOnUsb(pUsbIns);
1052 }
1053#endif
1054
1055 /*
1056 * Resume all threads.
1057 */
1058 if (RT_SUCCESS(rc))
1059 pdmR3ThreadResumeAll(pVM);
1060
1061 /*
1062 * On failure, clean up via PDMR3Suspend.
1063 */
1064 if (RT_FAILURE(rc))
1065 PDMR3Suspend(pVM);
1066
1067 LogFlow(("PDMR3PowerOn: returns %Rrc\n", rc));
1068 return /*rc*/;
1069}
1070
1071
1072/**
1073 * Worker for PDMR3Reset that deals with one driver.
1074 *
1075 * @param pDrvIns The driver instance.
1076 * @param pcAsync The asynchronous reset notification counter.
1077 * @param pszDeviceName The parent device name.
1078 * @param iDevInstance The parent device instance number.
1079 * @param iLun The parent LUN number.
1080 */
1081DECLINLINE(bool) pdmR3ResetDrv(PPDMDRVINS pDrvIns, unsigned *pcAsync,
1082 const char *pszDeviceName, uint32_t iDevInstance, uint32_t iLun)
1083{
1084 if (!pDrvIns->Internal.s.fVMReset)
1085 {
1086 pDrvIns->Internal.s.fVMReset = true;
1087 if (pDrvIns->pReg->pfnReset)
1088 {
1089 if (!pDrvIns->Internal.s.pfnAsyncNotify)
1090 {
1091 LogFlow(("PDMR3Reset: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1092 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance));
1093 pDrvIns->pReg->pfnReset(pDrvIns);
1094 if (pDrvIns->Internal.s.pfnAsyncNotify)
1095 LogFlow(("PDMR3Reset: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1096 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance));
1097 }
1098 else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
1099 {
1100 pDrvIns->Internal.s.pfnAsyncNotify = false;
1101 LogFlow(("PDMR3Reset: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1102 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance));
1103 }
1104 if (pDrvIns->Internal.s.pfnAsyncNotify)
1105 {
1106 pDrvIns->Internal.s.fVMReset = false;
1107 (*pcAsync)++;
1108 return false;
1109 }
1110 }
1111 }
1112 return true;
1113}
1114
1115
1116/**
1117 * Worker for PDMR3Reset that deals with one USB device instance.
1118 *
1119 * @param pUsbIns The USB device instance.
1120 * @param pcAsync The asynchronous reset notification counter.
1121 */
1122DECLINLINE(void) pdmR3ResetUsb(PPDMUSBINS pUsbIns, unsigned *pcAsync)
1123{
1124 if (!pUsbIns->Internal.s.fVMReset)
1125 {
1126 pUsbIns->Internal.s.fVMReset = true;
1127 if (pUsbIns->pReg->pfnVMReset)
1128 {
1129 if (!pUsbIns->Internal.s.pfnAsyncNotify)
1130 {
1131 LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1132 pUsbIns->pReg->pfnVMReset(pUsbIns);
1133 if (pUsbIns->Internal.s.pfnAsyncNotify)
1134 LogFlow(("PDMR3Reset: Async notification started - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1135 }
1136 else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
1137 {
1138 LogFlow(("PDMR3Reset: Async notification completed - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1139 pUsbIns->Internal.s.pfnAsyncNotify = NULL;
1140 }
1141 if (pUsbIns->Internal.s.pfnAsyncNotify)
1142 {
1143 pUsbIns->Internal.s.fVMReset = false;
1144 (*pcAsync)++;
1145 }
1146 }
1147 }
1148}
1149
1150
1151/**
1152 * Worker for PDMR3Reset that deals with one device instance.
1153 *
1154 * @param pDevIns The device instance.
1155 * @param pcAsync The asynchronous reset notification counter.
1156 */
1157DECLINLINE(void) pdmR3ResetDev(PPDMDEVINS pDevIns, unsigned *pcAsync)
1158{
1159 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_RESET))
1160 {
1161 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_RESET;
1162 if (pDevIns->pReg->pfnReset)
1163 {
1164 if (!pDevIns->Internal.s.pfnAsyncNotify)
1165 {
1166 LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1167 pDevIns->pReg->pfnReset(pDevIns);
1168 if (pDevIns->Internal.s.pfnAsyncNotify)
1169 LogFlow(("PDMR3Reset: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1170 }
1171 else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
1172 {
1173 LogFlow(("PDMR3Reset: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1174 pDevIns->Internal.s.pfnAsyncNotify = NULL;
1175 }
1176 if (pDevIns->Internal.s.pfnAsyncNotify)
1177 {
1178 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_RESET;
1179 (*pcAsync)++;
1180 }
1181 }
1182 }
1183}
1184
1185
1186/**
1187 * Resets a virtual CPU.
1188 *
1189 * Used by PDMR3Reset and CPU hot plugging.
1190 *
1191 * @param pVCpu The virtual CPU handle.
1192 */
1193VMMR3DECL(void) PDMR3ResetCpu(PVMCPU pVCpu)
1194{
1195 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
1196 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
1197 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
1198 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_SMI);
1199}
1200
1201
1202/**
1203 * This function will notify all the devices and their attached drivers about
1204 * the VM now being reset.
1205 *
1206 * @param pVM VM Handle.
1207 */
1208VMMR3DECL(void) PDMR3Reset(PVM pVM)
1209{
1210 LogFlow(("PDMR3Reset:\n"));
1211
1212 /*
1213 * Clear all the reset flags.
1214 */
1215 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1216 {
1217 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_RESET;
1218 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1219 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1220 pDrvIns->Internal.s.fVMReset = false;
1221 }
1222#ifdef VBOX_WITH_USB
1223 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1224 {
1225 pUsbIns->Internal.s.fVMReset = false;
1226 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1227 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1228 pDrvIns->Internal.s.fVMReset = false;
1229 }
1230#endif
1231
1232 /*
1233 * The outer loop repeats until there are no more async requests.
1234 */
1235 unsigned cAsync;
1236 for (unsigned iLoop = 0; ; iLoop++)
1237 {
1238 /*
1239 * Iterate thru the device instances and USB device instances,
1240 * processing the drivers associated with those.
1241 */
1242 cAsync = 0;
1243 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1244 {
1245 unsigned const cAsyncStart = cAsync;
1246
1247 if (cAsync == cAsyncStart)
1248 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1249 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1250 if (!pdmR3ResetDrv(pDrvIns, &cAsync, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
1251 break;
1252
1253 if (cAsync == cAsyncStart)
1254 pdmR3ResetDev(pDevIns, &cAsync);
1255 }
1256
1257#ifdef VBOX_WITH_USB
1258 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1259 {
1260 unsigned const cAsyncStart = cAsync;
1261
1262 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1263 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1264 if (!pdmR3ResetDrv(pDrvIns, &cAsync, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
1265 break;
1266
1267 if (cAsync == cAsyncStart)
1268 pdmR3ResetUsb(pUsbIns, &cAsync);
1269 }
1270#endif
1271 if (!cAsync)
1272 break;
1273
1274 /*
1275 * Process requests.
1276 */
1277 /** @todo This is utterly nuts and completely unsafe... will get back to it in a
1278 * bit I hope... */
1279 int rc = VMR3AsyncPdmNotificationWaitU(&pVM->pUVM->aCpus[0]);
1280 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
1281 rc = VMR3ReqProcessU(pVM->pUVM, VMCPUID_ANY);
1282 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
1283 rc = VMR3ReqProcessU(pVM->pUVM, 0/*idDstCpu*/);
1284 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
1285 }
1286
1287 /*
1288 * Clear all pending interrupts and DMA operations.
1289 */
1290 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1291 PDMR3ResetCpu(&pVM->aCpus[idCpu]);
1292 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
1293
1294 LogFlow(("PDMR3Reset: returns void\n"));
1295}
1296
1297
1298/**
1299 * Worker for PDMR3Suspend that deals with one driver.
1300 *
1301 * @param pDrvIns The driver instance.
1302 * @param pcAsync The asynchronous suspend notification counter.
1303 * @param pszDeviceName The parent device name.
1304 * @param iDevInstance The parent device instance number.
1305 * @param iLun The parent LUN number.
1306 */
1307DECLINLINE(bool) pdmR3SuspendDrv(PPDMDRVINS pDrvIns, unsigned *pcAsync,
1308 const char *pszDeviceName, uint32_t iDevInstance, uint32_t iLun)
1309{
1310 if (!pDrvIns->Internal.s.fVMSuspended)
1311 {
1312 pDrvIns->Internal.s.fVMSuspended = true;
1313 if (pDrvIns->pReg->pfnSuspend)
1314 {
1315 if (!pDrvIns->Internal.s.pfnAsyncNotify)
1316 {
1317 LogFlow(("PDMR3Suspend: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1318 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance));
1319 pDrvIns->pReg->pfnSuspend(pDrvIns);
1320 if (pDrvIns->Internal.s.pfnAsyncNotify)
1321 LogFlow(("PDMR3Suspend: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1322 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance));
1323 }
1324 else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
1325 {
1326 pDrvIns->Internal.s.pfnAsyncNotify = false;
1327 LogFlow(("PDMR3Suspend: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1328 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance));
1329 }
1330 if (pDrvIns->Internal.s.pfnAsyncNotify)
1331 {
1332 pDrvIns->Internal.s.fVMSuspended = false;
1333 (*pcAsync)++;
1334 return false;
1335 }
1336 }
1337 }
1338 return true;
1339}
1340
1341
1342/**
1343 * Worker for PDMR3Suspend that deals with one USB device instance.
1344 *
1345 * @param pUsbIns The USB device instance.
1346 * @param pcAsync The asynchronous suspend notification counter.
1347 */
1348DECLINLINE(void) pdmR3SuspendUsb(PPDMUSBINS pUsbIns, unsigned *pcAsync)
1349{
1350 if (!pUsbIns->Internal.s.fVMSuspended)
1351 {
1352 pUsbIns->Internal.s.fVMSuspended = true;
1353 if (pUsbIns->pReg->pfnVMSuspend)
1354 {
1355 if (!pUsbIns->Internal.s.pfnAsyncNotify)
1356 {
1357 LogFlow(("PDMR3Suspend: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1358 pUsbIns->pReg->pfnVMSuspend(pUsbIns);
1359 if (pUsbIns->Internal.s.pfnAsyncNotify)
1360 LogFlow(("PDMR3Suspend: Async notification started - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1361 }
1362 else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
1363 {
1364 LogFlow(("PDMR3Suspend: Async notification completed - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1365 pUsbIns->Internal.s.pfnAsyncNotify = NULL;
1366 }
1367 if (pUsbIns->Internal.s.pfnAsyncNotify)
1368 {
1369 pUsbIns->Internal.s.fVMSuspended = false;
1370 (*pcAsync)++;
1371 }
1372 }
1373 }
1374}
1375
1376
1377/**
1378 * Worker for PDMR3Suspend that deals with one device instance.
1379 *
1380 * @param pDevIns The device instance.
1381 * @param pcAsync The asynchronous suspend notification counter.
1382 */
1383DECLINLINE(void) pdmR3SuspendDev(PPDMDEVINS pDevIns, unsigned *pcAsync)
1384{
1385 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED))
1386 {
1387 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_SUSPENDED;
1388 if (pDevIns->pReg->pfnSuspend)
1389 {
1390 if (!pDevIns->Internal.s.pfnAsyncNotify)
1391 {
1392 LogFlow(("PDMR3Suspend: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1393 pDevIns->pReg->pfnSuspend(pDevIns);
1394 if (pDevIns->Internal.s.pfnAsyncNotify)
1395 LogFlow(("PDMR3Suspend: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1396 }
1397 else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
1398 {
1399 LogFlow(("PDMR3Suspend: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1400 pDevIns->Internal.s.pfnAsyncNotify = NULL;
1401 }
1402 if (pDevIns->Internal.s.pfnAsyncNotify)
1403 {
1404 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1405 (*pcAsync)++;
1406 }
1407 }
1408 }
1409}
1410
1411
1412/**
1413 * This function will notify all the devices and their attached drivers about
1414 * the VM now being suspended.
1415 *
1416 * @param pVM The VM Handle.
1417 * @thread EMT(0)
1418 */
1419VMMR3DECL(void) PDMR3Suspend(PVM pVM)
1420{
1421 LogFlow(("PDMR3Suspend:\n"));
1422 VM_ASSERT_EMT0(pVM);
1423
1424 /*
1425 * The outer loop repeats until there are no more async requests.
1426 *
1427 * Note! We depend on the suspended indicators to be in the desired state
1428 * and we do not reset them before starting because this allows
1429 * PDMR3PowerOn and PDMR3Resume to use PDMR3Suspend for cleaning up
1430 * on failure.
1431 */
1432 unsigned cAsync;
1433 for (unsigned iLoop = 0; ; iLoop++)
1434 {
1435 /*
1436 * Iterate thru the device instances and USB device instances,
1437 * processing the drivers associated with those.
1438 *
1439 * The attached drivers are normally processed first. Some devices
1440 * (like DevAHCI) though needs to be notified before the drivers so
1441 * that it doesn't kick off any new requests after the drivers stopped
1442 * taking any. (DrvVD changes to read-only in this particular case.)
1443 */
1444 cAsync = 0;
1445 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1446 {
1447 unsigned const cAsyncStart = cAsync;
1448
1449 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION)
1450 pdmR3SuspendDev(pDevIns, &cAsync);
1451
1452 if (cAsync == cAsyncStart)
1453 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1454 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1455 if (!pdmR3SuspendDrv(pDrvIns, &cAsync, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
1456 break;
1457
1458 if ( cAsync == cAsyncStart
1459 && !(pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION))
1460 pdmR3SuspendDev(pDevIns, &cAsync);
1461 }
1462
1463#ifdef VBOX_WITH_USB
1464 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1465 {
1466 unsigned const cAsyncStart = cAsync;
1467
1468 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1469 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1470 if (!pdmR3SuspendDrv(pDrvIns, &cAsync, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
1471 break;
1472
1473 if (cAsync == cAsyncStart)
1474 pdmR3SuspendUsb(pUsbIns, &cAsync);
1475 }
1476#endif
1477 if (!cAsync)
1478 break;
1479
1480 /*
1481 * Process requests.
1482 */
1483 /** @todo This is utterly nuts and completely unsafe... will get back to it in a
1484 * bit I hope... */
1485 int rc = VMR3AsyncPdmNotificationWaitU(&pVM->pUVM->aCpus[0]);
1486 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
1487 rc = VMR3ReqProcessU(pVM->pUVM, VMCPUID_ANY);
1488 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
1489 rc = VMR3ReqProcessU(pVM->pUVM, 0/*idDstCpu*/);
1490 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
1491 }
1492
1493 /*
1494 * Suspend all threads.
1495 */
1496 pdmR3ThreadSuspendAll(pVM);
1497
1498 LogFlow(("PDMR3Suspend: returns void\n"));
1499}
1500
1501
1502/**
1503 * Worker for PDMR3Resume that deals with one driver.
1504 *
1505 * @param pDrvIns The driver instance.
1506 * @param pszDeviceName The parent device name.
1507 * @param iDevInstance The parent device instance number.
1508 * @param iLun The parent LUN number.
1509 */
1510DECLINLINE(int) pdmR3ResumeDrv(PPDMDRVINS pDrvIns, const char *pszDeviceName, uint32_t iDevInstance, uint32_t iLun)
1511{
1512 Assert(pDrvIns->Internal.s.fVMSuspended);
1513 if (pDrvIns->pReg->pfnResume)
1514 {
1515 LogFlow(("PDMR3Resume: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1516 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance));
1517 int rc = VINF_SUCCESS; pDrvIns->pReg->pfnResume(pDrvIns);
1518 if (RT_FAILURE(rc))
1519 {
1520 LogRel(("PDMR3Resume: driver '%s'/%d on LUN#%d of device '%s'/%d -> %Rrc\n",
1521 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance, rc));
1522 return rc;
1523 }
1524 }
1525 pDrvIns->Internal.s.fVMSuspended = false;
1526 return VINF_SUCCESS;
1527}
1528
1529
1530/**
1531 * Worker for PDMR3Resume that deals with one USB device instance.
1532 *
1533 * @returns VBox status code.
1534 * @param pUsbIns The USB device instance.
1535 */
1536DECLINLINE(int) pdmR3ResumeUsb(PPDMUSBINS pUsbIns)
1537{
1538 Assert(pUsbIns->Internal.s.fVMSuspended);
1539 if (pUsbIns->pReg->pfnVMResume)
1540 {
1541 LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1542 int rc = VINF_SUCCESS; pUsbIns->pReg->pfnVMResume(pUsbIns);
1543 if (RT_FAILURE(rc))
1544 {
1545 LogRel(("PDMR3Resume: device '%s'/%d -> %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1546 return rc;
1547 }
1548 }
1549 pUsbIns->Internal.s.fVMSuspended = false;
1550 return VINF_SUCCESS;
1551}
1552
1553
1554/**
1555 * Worker for PDMR3Resume that deals with one device instance.
1556 *
1557 * @returns VBox status code.
1558 * @param pDevIns The device instance.
1559 */
1560DECLINLINE(int) pdmR3ResumeDev(PPDMDEVINS pDevIns)
1561{
1562 Assert(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED);
1563 if (pDevIns->pReg->pfnResume)
1564 {
1565 LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1566 int rc = VINF_SUCCESS; pDevIns->pReg->pfnResume(pDevIns);
1567 if (RT_FAILURE(rc))
1568 {
1569 LogRel(("PDMR3Resume: device '%s'/%d -> %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
1570 return rc;
1571 }
1572 }
1573 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1574 return VINF_SUCCESS;
1575}
1576
1577
1578/**
1579 * This function will notify all the devices and their
1580 * attached drivers about the VM now being resumed.
1581 *
1582 * @param pVM VM Handle.
1583 */
1584VMMR3DECL(void) PDMR3Resume(PVM pVM)
1585{
1586 LogFlow(("PDMR3Resume:\n"));
1587
1588 /*
1589 * Iterate thru the device instances and USB device instances,
1590 * processing the drivers associated with those.
1591 */
1592 int rc = VINF_SUCCESS;
1593 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns && RT_SUCCESS(rc); pDevIns = pDevIns->Internal.s.pNextR3)
1594 {
1595 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1596 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1597 rc = pdmR3ResumeDrv(pDrvIns, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun);
1598 if (RT_SUCCESS(rc))
1599 rc = pdmR3ResumeDev(pDevIns);
1600 }
1601
1602#ifdef VBOX_WITH_USB
1603 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns && RT_SUCCESS(rc); pUsbIns = pUsbIns->Internal.s.pNext)
1604 {
1605 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1606 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1607 rc = pdmR3ResumeDrv(pDrvIns, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun);
1608 if (RT_SUCCESS(rc))
1609 rc = pdmR3ResumeUsb(pUsbIns);
1610 }
1611#endif
1612
1613 /*
1614 * Resume all threads.
1615 */
1616 if (RT_SUCCESS(rc))
1617 pdmR3ThreadResumeAll(pVM);
1618
1619 /*
1620 * On failure, clean up via PDMR3Suspend.
1621 */
1622 if (RT_FAILURE(rc))
1623 PDMR3Suspend(pVM);
1624
1625 LogFlow(("PDMR3Resume: returns %Rrc\n", rc));
1626 return /*rc*/;
1627}
1628
1629
1630/**
1631 * Worker for PDMR3PowerOff that deals with one driver.
1632 *
1633 * @param pDrvIns The driver instance.
1634 * @param pcAsync The asynchronous power off notification counter.
1635 * @param pszDeviceName The parent device name.
1636 * @param iDevInstance The parent device instance number.
1637 * @param iLun The parent LUN number.
1638 */
1639DECLINLINE(bool) pdmR3PowerOffDrv(PPDMDRVINS pDrvIns, unsigned *pcAsync,
1640 const char *pszDeviceName, uint32_t iDevInstance, uint32_t iLun)
1641{
1642 if (!pDrvIns->Internal.s.fVMSuspended)
1643 {
1644 pDrvIns->Internal.s.fVMSuspended = true;
1645 if (pDrvIns->pReg->pfnPowerOff)
1646 {
1647 if (!pDrvIns->Internal.s.pfnAsyncNotify)
1648 {
1649 LogFlow(("PDMR3PowerOff: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1650 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance));
1651 pDrvIns->pReg->pfnPowerOff(pDrvIns);
1652 if (pDrvIns->Internal.s.pfnAsyncNotify)
1653 LogFlow(("PDMR3PowerOff: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1654 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance));
1655 }
1656 else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
1657 {
1658 pDrvIns->Internal.s.pfnAsyncNotify = false;
1659 LogFlow(("PDMR3PowerOff: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1660 pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance));
1661 }
1662 if (pDrvIns->Internal.s.pfnAsyncNotify)
1663 {
1664 pDrvIns->Internal.s.fVMSuspended = false;
1665 (*pcAsync)++;
1666 return false;
1667 }
1668 }
1669 }
1670 return true;
1671}
1672
1673
1674/**
1675 * Worker for PDMR3PowerOff that deals with one USB device instance.
1676 *
1677 * @param pUsbIns The USB device instance.
1678 * @param pcAsync The asynchronous power off notification counter.
1679 */
1680DECLINLINE(void) pdmR3PowerOffUsb(PPDMUSBINS pUsbIns, unsigned *pcAsync)
1681{
1682 if (!pUsbIns->Internal.s.fVMSuspended)
1683 {
1684 pUsbIns->Internal.s.fVMSuspended = true;
1685 if (pUsbIns->pReg->pfnVMPowerOff)
1686 {
1687 if (!pUsbIns->Internal.s.pfnAsyncNotify)
1688 {
1689 LogFlow(("PDMR3PowerOff: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1690 pUsbIns->pReg->pfnVMPowerOff(pUsbIns);
1691 if (pUsbIns->Internal.s.pfnAsyncNotify)
1692 LogFlow(("PDMR3PowerOff: Async notification started - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1693 }
1694 else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
1695 {
1696 LogFlow(("PDMR3PowerOff: Async notification completed - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1697 pUsbIns->Internal.s.pfnAsyncNotify = NULL;
1698 }
1699 if (pUsbIns->Internal.s.pfnAsyncNotify)
1700 {
1701 pUsbIns->Internal.s.fVMSuspended = false;
1702 (*pcAsync)++;
1703 }
1704 }
1705 }
1706}
1707
1708
1709/**
1710 * Worker for PDMR3PowerOff that deals with one device instance.
1711 *
1712 * @param pDevIns The device instance.
1713 * @param pcAsync The asynchronous power off notification counter.
1714 */
1715DECLINLINE(void) pdmR3PowerOffDev(PPDMDEVINS pDevIns, unsigned *pcAsync)
1716{
1717 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED))
1718 {
1719 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_SUSPENDED;
1720 if (pDevIns->pReg->pfnPowerOff)
1721 {
1722 if (!pDevIns->Internal.s.pfnAsyncNotify)
1723 {
1724 LogFlow(("PDMR3PowerOff: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1725 pDevIns->pReg->pfnPowerOff(pDevIns);
1726 if (pDevIns->Internal.s.pfnAsyncNotify)
1727 LogFlow(("PDMR3PowerOff: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1728 }
1729 else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
1730 {
1731 LogFlow(("PDMR3PowerOff: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1732 pDevIns->Internal.s.pfnAsyncNotify = NULL;
1733 }
1734 if (pDevIns->Internal.s.pfnAsyncNotify)
1735 {
1736 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1737 (*pcAsync)++;
1738 }
1739 }
1740 }
1741}
1742
1743
1744/**
1745 * This function will notify all the devices and their
1746 * attached drivers about the VM being powered off.
1747 *
1748 * @param pVM VM Handle.
1749 */
1750VMMR3DECL(void) PDMR3PowerOff(PVM pVM)
1751{
1752 LogFlow(("PDMR3PowerOff:\n"));
1753
1754 /*
1755 * The outer loop repeats until there are no more async requests.
1756 */
1757 unsigned cAsync;
1758 for (unsigned iLoop = 0; ; iLoop++)
1759 {
1760 /*
1761 * Iterate thru the device instances and USB device instances,
1762 * processing the drivers associated with those.
1763 *
1764 * The attached drivers are normally processed first. Some devices
1765 * (like DevAHCI) though needs to be notified before the drivers so
1766 * that it doesn't kick off any new requests after the drivers stopped
1767 * taking any. (DrvVD changes to read-only in this particular case.)
1768 */
1769 cAsync = 0;
1770 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1771 {
1772 unsigned const cAsyncStart = cAsync;
1773
1774 if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION)
1775 pdmR3PowerOffDev(pDevIns, &cAsync);
1776
1777 if (cAsync == cAsyncStart)
1778 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1779 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1780 if (!pdmR3PowerOffDrv(pDrvIns, &cAsync, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
1781 break;
1782
1783 if ( cAsync == cAsyncStart
1784 && !(pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION))
1785 pdmR3PowerOffDev(pDevIns, &cAsync);
1786 }
1787
1788#ifdef VBOX_WITH_USB
1789 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1790 {
1791 unsigned const cAsyncStart = cAsync;
1792
1793 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1794 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1795 if (!pdmR3PowerOffDrv(pDrvIns, &cAsync, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
1796 break;
1797
1798 if (cAsync == cAsyncStart)
1799 pdmR3PowerOffUsb(pUsbIns, &cAsync);
1800 }
1801#endif
1802 if (!cAsync)
1803 break;
1804
1805 /*
1806 * Process requests.
1807 */
1808 /** @todo This is utterly nuts and completely unsafe... will get back to it in a
1809 * bit I hope... */
1810 int rc = VMR3AsyncPdmNotificationWaitU(&pVM->pUVM->aCpus[0]);
1811 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
1812 rc = VMR3ReqProcessU(pVM->pUVM, VMCPUID_ANY);
1813 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
1814 rc = VMR3ReqProcessU(pVM->pUVM, 0/*idDstCpu*/);
1815 AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
1816 }
1817
1818 /*
1819 * Suspend all threads.
1820 */
1821 pdmR3ThreadSuspendAll(pVM);
1822
1823 LogFlow(("PDMR3PowerOff: returns void\n"));
1824}
1825
1826
1827/**
1828 * Queries the base interace of a device instance.
1829 *
1830 * The caller can use this to query other interfaces the device implements
1831 * and use them to talk to the device.
1832 *
1833 * @returns VBox status code.
1834 * @param pVM VM handle.
1835 * @param pszDevice Device name.
1836 * @param iInstance Device instance.
1837 * @param ppBase Where to store the pointer to the base device interface on success.
1838 * @remark We're not doing any locking ATM, so don't try call this at times when the
1839 * device chain is known to be updated.
1840 */
1841VMMR3DECL(int) PDMR3QueryDevice(PVM pVM, const char *pszDevice, unsigned iInstance, PPDMIBASE *ppBase)
1842{
1843 LogFlow(("PDMR3DeviceQuery: pszDevice=%p:{%s} iInstance=%u ppBase=%p\n", pszDevice, pszDevice, iInstance, ppBase));
1844
1845 /*
1846 * Iterate registered devices looking for the device.
1847 */
1848 size_t cchDevice = strlen(pszDevice);
1849 for (PPDMDEV pDev = pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
1850 {
1851 if ( pDev->cchName == cchDevice
1852 && !memcmp(pDev->pReg->szName, pszDevice, cchDevice))
1853 {
1854 /*
1855 * Iterate device instances.
1856 */
1857 for (PPDMDEVINS pDevIns = pDev->pInstances; pDevIns; pDevIns = pDevIns->Internal.s.pPerDeviceNextR3)
1858 {
1859 if (pDevIns->iInstance == iInstance)
1860 {
1861 if (pDevIns->IBase.pfnQueryInterface)
1862 {
1863 *ppBase = &pDevIns->IBase;
1864 LogFlow(("PDMR3DeviceQuery: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
1865 return VINF_SUCCESS;
1866 }
1867
1868 LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NO_IBASE\n"));
1869 return VERR_PDM_DEVICE_INSTANCE_NO_IBASE;
1870 }
1871 }
1872
1873 LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NOT_FOUND\n"));
1874 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND;
1875 }
1876 }
1877
1878 LogFlow(("PDMR3QueryDevice: returns VERR_PDM_DEVICE_NOT_FOUND\n"));
1879 return VERR_PDM_DEVICE_NOT_FOUND;
1880}
1881
1882
1883/**
1884 * Queries the base interface of a device LUN.
1885 *
1886 * This differs from PDMR3QueryLun by that it returns the interface on the
1887 * device and not the top level driver.
1888 *
1889 * @returns VBox status code.
1890 * @param pVM VM Handle.
1891 * @param pszDevice Device name.
1892 * @param iInstance Device instance.
1893 * @param iLun The Logical Unit to obtain the interface of.
1894 * @param ppBase Where to store the base interface pointer.
1895 * @remark We're not doing any locking ATM, so don't try call this at times when the
1896 * device chain is known to be updated.
1897 */
1898VMMR3DECL(int) PDMR3QueryDeviceLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
1899{
1900 LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
1901 pszDevice, pszDevice, iInstance, iLun, ppBase));
1902
1903 /*
1904 * Find the LUN.
1905 */
1906 PPDMLUN pLun;
1907 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
1908 if (RT_SUCCESS(rc))
1909 {
1910 *ppBase = pLun->pBase;
1911 LogFlow(("PDMR3QueryDeviceLun: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
1912 return VINF_SUCCESS;
1913 }
1914 LogFlow(("PDMR3QueryDeviceLun: returns %Rrc\n", rc));
1915 return rc;
1916}
1917
1918
1919/**
1920 * Query the interface of the top level driver on a LUN.
1921 *
1922 * @returns VBox status code.
1923 * @param pVM VM Handle.
1924 * @param pszDevice Device name.
1925 * @param iInstance Device instance.
1926 * @param iLun The Logical Unit to obtain the interface of.
1927 * @param ppBase Where to store the base interface pointer.
1928 * @remark We're not doing any locking ATM, so don't try call this at times when the
1929 * device chain is known to be updated.
1930 */
1931VMMR3DECL(int) PDMR3QueryLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
1932{
1933 LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
1934 pszDevice, pszDevice, iInstance, iLun, ppBase));
1935
1936 /*
1937 * Find the LUN.
1938 */
1939 PPDMLUN pLun;
1940 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
1941 if (RT_SUCCESS(rc))
1942 {
1943 if (pLun->pTop)
1944 {
1945 *ppBase = &pLun->pTop->IBase;
1946 LogFlow(("PDMR3QueryLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
1947 return VINF_SUCCESS;
1948 }
1949 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
1950 }
1951 LogFlow(("PDMR3QueryLun: returns %Rrc\n", rc));
1952 return rc;
1953}
1954
1955/**
1956 * Executes pending DMA transfers.
1957 * Forced Action handler.
1958 *
1959 * @param pVM VM handle.
1960 */
1961VMMR3DECL(void) PDMR3DmaRun(PVM pVM)
1962{
1963 /* Note! Not really SMP safe; restrict it to VCPU 0. */
1964 if (VMMGetCpuId(pVM) != 0)
1965 return;
1966
1967 if (VM_FF_TESTANDCLEAR(pVM, VM_FF_PDM_DMA))
1968 {
1969 if (pVM->pdm.s.pDmac)
1970 {
1971 bool fMore = pVM->pdm.s.pDmac->Reg.pfnRun(pVM->pdm.s.pDmac->pDevIns);
1972 if (fMore)
1973 VM_FF_SET(pVM, VM_FF_PDM_DMA);
1974 }
1975 }
1976}
1977
1978
1979/**
1980 * Service a VMMCALLRING3_PDM_LOCK call.
1981 *
1982 * @returns VBox status code.
1983 * @param pVM The VM handle.
1984 */
1985VMMR3DECL(int) PDMR3LockCall(PVM pVM)
1986{
1987 return PDMR3CritSectEnterEx(&pVM->pdm.s.CritSect, true /* fHostCall */);
1988}
1989
1990
1991/**
1992 * Registers the VMM device heap
1993 *
1994 * @returns VBox status code.
1995 * @param pVM VM handle.
1996 * @param GCPhys The physical address.
1997 * @param pvHeap Ring-3 pointer.
1998 * @param cbSize Size of the heap.
1999 */
2000VMMR3DECL(int) PDMR3RegisterVMMDevHeap(PVM pVM, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbSize)
2001{
2002 Assert(pVM->pdm.s.pvVMMDevHeap == NULL);
2003
2004 Log(("PDMR3RegisterVMMDevHeap %RGp %RHv %x\n", GCPhys, pvHeap, cbSize));
2005 pVM->pdm.s.pvVMMDevHeap = pvHeap;
2006 pVM->pdm.s.GCPhysVMMDevHeap = GCPhys;
2007 pVM->pdm.s.cbVMMDevHeap = cbSize;
2008 pVM->pdm.s.cbVMMDevHeapLeft = cbSize;
2009 return VINF_SUCCESS;
2010}
2011
2012
2013/**
2014 * Unregisters the VMM device heap
2015 *
2016 * @returns VBox status code.
2017 * @param pVM VM handle.
2018 * @param GCPhys The physical address.
2019 */
2020VMMR3DECL(int) PDMR3UnregisterVMMDevHeap(PVM pVM, RTGCPHYS GCPhys)
2021{
2022 Assert(pVM->pdm.s.GCPhysVMMDevHeap == GCPhys);
2023
2024 Log(("PDMR3UnregisterVMMDevHeap %RGp\n", GCPhys));
2025 pVM->pdm.s.pvVMMDevHeap = NULL;
2026 pVM->pdm.s.GCPhysVMMDevHeap = NIL_RTGCPHYS;
2027 pVM->pdm.s.cbVMMDevHeap = 0;
2028 pVM->pdm.s.cbVMMDevHeapLeft = 0;
2029 return VINF_SUCCESS;
2030}
2031
2032
2033/**
2034 * Allocates memory from the VMM device heap
2035 *
2036 * @returns VBox status code.
2037 * @param pVM VM handle.
2038 * @param cbSize Allocation size.
2039 * @param pv Ring-3 pointer. (out)
2040 */
2041VMMR3DECL(int) PDMR3VMMDevHeapAlloc(PVM pVM, unsigned cbSize, RTR3PTR *ppv)
2042{
2043#ifdef DEBUG_bird
2044 if (!cbSize || cbSize > pVM->pdm.s.cbVMMDevHeapLeft)
2045 return VERR_NO_MEMORY;
2046#else
2047 AssertReturn(cbSize && cbSize <= pVM->pdm.s.cbVMMDevHeapLeft, VERR_NO_MEMORY);
2048#endif
2049
2050 Log(("PDMR3VMMDevHeapAlloc %x\n", cbSize));
2051
2052 /** @todo not a real heap as there's currently only one user. */
2053 *ppv = pVM->pdm.s.pvVMMDevHeap;
2054 pVM->pdm.s.cbVMMDevHeapLeft = 0;
2055 return VINF_SUCCESS;
2056}
2057
2058
2059/**
2060 * Frees memory from the VMM device heap
2061 *
2062 * @returns VBox status code.
2063 * @param pVM VM handle.
2064 * @param pv Ring-3 pointer.
2065 */
2066VMMR3DECL(int) PDMR3VMMDevHeapFree(PVM pVM, RTR3PTR pv)
2067{
2068 Log(("PDMR3VMMDevHeapFree %RHv\n", pv));
2069
2070 /** @todo not a real heap as there's currently only one user. */
2071 pVM->pdm.s.cbVMMDevHeapLeft = pVM->pdm.s.cbVMMDevHeap;
2072 return VINF_SUCCESS;
2073}
2074
2075/**
2076 * Release the PDM lock if owned by the current VCPU
2077 *
2078 * @param pVM The VM to operate on.
2079 */
2080VMMR3DECL(void) PDMR3ReleaseOwnedLocks(PVM pVM)
2081{
2082 while (PDMCritSectIsOwner(&pVM->pdm.s.CritSect))
2083 PDMCritSectLeave(&pVM->pdm.s.CritSect);
2084}
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