1
/* $Id: PDM.cpp 35346 2010-12-27 16:13:13Z vboxsync $ */
3
* PDM - Pluggable Device Manager.
7
* Copyright (C) 2006-2007 Oracle Corporation
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.
19
/** @page pg_pdm PDM - The Pluggable Device & Driver Manager
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).
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.
35
* @section sec_pdm_dev The Pluggable Devices
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.
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.
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.
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.)
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.
73
* @section sec_pdm_special_devs Special Devices
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.
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.
95
* @section sec_pdm_usbdev The Pluggable USB Devices
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).
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
110
* @see grp_pdm_usbdev
113
* @section sec_pdm_drv The Pluggable Drivers
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.
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.
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.
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.
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
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.
145
* @see grp_pdm_driver
148
* @section sec_pdm_ifs Interfaces
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.
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++.)
162
* @see grp_pdm_interfaces
165
* @section sec_pdm_utils Utilities
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.
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.
175
* @subsection sec_pdm_async_completion Async I/O
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.
181
* @todo more details.
183
* @see grp_pdm_async_completion
186
* @subsection sec_pdm_async_task Async Task - not implemented
188
* @todo implement and describe
190
* @see grp_pdm_async_task
193
* @subsection sec_pdm_critsect Critical Section
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.)
205
* @see grp_pdm_critsect
208
* @subsection sec_pdm_queue Queue
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.
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.
221
* @subsection sec_pdm_task Task - not implemented yet
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.
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.
233
* @subsection sec_pdm_thread Thread
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.
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.
244
* @see grp_pdm_thread
249
/*******************************************************************************
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>
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>
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
282
/*******************************************************************************
283
* Internal Functions *
284
*******************************************************************************/
285
static DECLCALLBACK(int) pdmR3LiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass);
286
static DECLCALLBACK(int) pdmR3SaveExec(PVM pVM, PSSMHANDLE pSSM);
287
static DECLCALLBACK(int) pdmR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
288
static DECLCALLBACK(int) pdmR3LoadPrep(PVM pVM, PSSMHANDLE pSSM);
293
* Initializes the PDM part of the UVM.
295
* This doesn't really do much right now but has to be here for the sake
298
* @returns VBox status code.
299
* @param pUVM Pointer to the user mode VM structure.
301
VMMR3DECL(int) PDMR3InitUVM(PUVM pUVM)
303
AssertCompile(sizeof(pUVM->pdm.s) <= sizeof(pUVM->pdm.padding));
304
AssertRelease(sizeof(pUVM->pdm.s) <= sizeof(pUVM->pdm.padding));
305
pUVM->pdm.s.pModules = NULL;
306
pUVM->pdm.s.pCritSects = NULL;
307
return RTCritSectInit(&pUVM->pdm.s.ListCritSect);
312
* Initializes the PDM.
314
* @returns VBox status code.
315
* @param pVM The VM to operate on.
317
VMMR3DECL(int) PDMR3Init(PVM pVM)
319
LogFlow(("PDMR3Init\n"));
322
* Assert alignment and sizes.
324
AssertRelease(!(RT_OFFSETOF(VM, pdm.s) & 31));
325
AssertRelease(sizeof(pVM->pdm.s) <= sizeof(pVM->pdm.padding));
326
AssertCompileMemberAlignment(PDM, CritSect, sizeof(uintptr_t));
328
* Init the structure.
330
pVM->pdm.s.offVM = RT_OFFSETOF(VM, pdm.s);
331
pVM->pdm.s.GCPhysVMMDevHeap = NIL_RTGCPHYS;
334
* Initialize sub components.
336
int rc = pdmR3CritSectInitStats(pVM);
338
rc = PDMR3CritSectInit(pVM, &pVM->pdm.s.CritSect, RT_SRC_POS, "PDM");
340
rc = pdmR3LdrInitU(pVM->pUVM);
341
#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
343
rc = pdmR3AsyncCompletionInit(pVM);
346
rc = pdmR3BlkCacheInit(pVM);
348
rc = pdmR3DrvInit(pVM);
350
rc = pdmR3DevInit(pVM);
354
* Register the saved state data unit.
356
rc = SSMR3RegisterInternal(pVM, "pdm", 1, PDM_SAVED_STATE_VERSION, 128,
357
NULL, pdmR3LiveExec, NULL,
358
NULL, pdmR3SaveExec, NULL,
359
pdmR3LoadPrep, pdmR3LoadExec, NULL);
362
LogFlow(("PDM: Successfully initialized\n"));
368
* Cleanup and return failure.
371
LogFlow(("PDMR3Init: returns %Rrc\n", rc));
377
* Applies relocations to data and code managed by this
378
* component. This function will be called at init and
379
* whenever the VMM need to relocate it self inside the GC.
381
* @param pVM VM handle.
382
* @param offDelta Relocation delta relative to old location.
383
* @remark The loader subcomponent is relocated by PDMR3LdrRelocate() very
384
* early in the relocation phase.
386
VMMR3DECL(void) PDMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
388
LogFlow(("PDMR3Relocate\n"));
393
pdmR3QueueRelocate(pVM, offDelta);
394
pVM->pdm.s.pDevHlpQueueRC = PDMQueueRCPtr(pVM->pdm.s.pDevHlpQueueR3);
399
pdmR3CritSectRelocate(pVM);
402
* The registered PIC.
404
if (pVM->pdm.s.Pic.pDevInsRC)
406
pVM->pdm.s.Pic.pDevInsRC += offDelta;
407
pVM->pdm.s.Pic.pfnSetIrqRC += offDelta;
408
pVM->pdm.s.Pic.pfnGetInterruptRC += offDelta;
412
* The registered APIC.
414
if (pVM->pdm.s.Apic.pDevInsRC)
416
pVM->pdm.s.Apic.pDevInsRC += offDelta;
417
pVM->pdm.s.Apic.pfnGetInterruptRC += offDelta;
418
pVM->pdm.s.Apic.pfnSetBaseRC += offDelta;
419
pVM->pdm.s.Apic.pfnGetBaseRC += offDelta;
420
pVM->pdm.s.Apic.pfnSetTPRRC += offDelta;
421
pVM->pdm.s.Apic.pfnGetTPRRC += offDelta;
422
pVM->pdm.s.Apic.pfnBusDeliverRC += offDelta;
423
if (pVM->pdm.s.Apic.pfnLocalInterruptRC)
424
pVM->pdm.s.Apic.pfnLocalInterruptRC += offDelta;
425
pVM->pdm.s.Apic.pfnWriteMSRRC += offDelta;
426
pVM->pdm.s.Apic.pfnReadMSRRC += offDelta;
430
* The registered I/O APIC.
432
if (pVM->pdm.s.IoApic.pDevInsRC)
434
pVM->pdm.s.IoApic.pDevInsRC += offDelta;
435
pVM->pdm.s.IoApic.pfnSetIrqRC += offDelta;
436
if (pVM->pdm.s.IoApic.pfnSendMsiRC)
437
pVM->pdm.s.IoApic.pfnSendMsiRC += offDelta;
441
* The register PCI Buses.
443
for (unsigned i = 0; i < RT_ELEMENTS(pVM->pdm.s.aPciBuses); i++)
445
if (pVM->pdm.s.aPciBuses[i].pDevInsRC)
447
pVM->pdm.s.aPciBuses[i].pDevInsRC += offDelta;
448
pVM->pdm.s.aPciBuses[i].pfnSetIrqRC += offDelta;
455
PCPDMDEVHLPRC pDevHlpRC;
456
int rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDevHlp", &pDevHlpRC);
457
AssertReleaseMsgRC(rc, ("rc=%Rrc when resolving g_pdmRCDevHlp\n", rc));
459
PCPDMDRVHLPRC pDrvHlpRC;
460
rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDevHlp", &pDrvHlpRC);
461
AssertReleaseMsgRC(rc, ("rc=%Rrc when resolving g_pdmRCDevHlp\n", rc));
463
for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
465
if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_RC)
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)
478
LogFlow(("PDMR3Relocate: Relocating device '%s'/%d\n",
479
pDevIns->pReg->szName, pDevIns->iInstance));
480
pDevIns->pReg->pfnRelocate(pDevIns, offDelta);
484
for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
486
for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
488
if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_RC)
490
pDrvIns->pHlpRC = pDrvHlpRC;
491
pDrvIns->pvInstanceDataRC = MMHyperR3ToRC(pVM, pDrvIns->pvInstanceDataR3);
492
pDrvIns->Internal.s.pVMRC = pVM->pVMRC;
493
if (pDrvIns->pReg->pfnRelocate)
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);
509
* Worker for pdmR3Term that terminates a LUN chain.
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).
516
static void pdmR3TermLuns(PVM pVM, PPDMLUN pLun, const char *pszDevice, unsigned iInstance)
518
for (; pLun; pLun = pLun->pNext)
521
* Destroy them one at a time from the bottom up.
522
* (The serial device/drivers depends on this - bad.)
524
PPDMDRVINS pDrvIns = pLun->pBottom;
525
pLun->pBottom = pLun->pTop = NULL;
528
PPDMDRVINS pDrvNext = pDrvIns->Internal.s.pUp;
530
if (pDrvIns->pReg->pfnDestruct)
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);
536
pDrvIns->Internal.s.pDrv->cInstances--;
538
TMR3TimerDestroyDriver(pVM, pDrvIns);
539
//PDMR3QueueDestroyDriver(pVM, pDrvIns);
540
//pdmR3ThreadDestroyDriver(pVM, pDrvIns);
541
SSMR3DeregisterDriver(pVM, pDrvIns, NULL, 0);
550
* Terminates the PDM.
552
* Termination means cleaning up and freeing all resources,
553
* the VM it self is at this point powered off or suspended.
555
* @returns VBox status code.
556
* @param pVM The VM to operate on.
558
VMMR3DECL(int) PDMR3Term(PVM pVM)
560
LogFlow(("PDMR3Term:\n"));
561
AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
564
* Iterate the device instances and attach drivers, doing
565
* relevant destruction processing.
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.
570
/* usb ones first. */
571
for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
573
pdmR3TermLuns(pVM, pUsbIns->Internal.s.pLuns, pUsbIns->pReg->szName, pUsbIns->iInstance);
575
if (pUsbIns->pReg->pfnDestruct)
577
LogFlow(("pdmR3DevTerm: Destroying - device '%s'/%d\n",
578
pUsbIns->pReg->szName, pUsbIns->iInstance));
579
pUsbIns->pReg->pfnDestruct(pUsbIns);
582
//TMR3TimerDestroyUsb(pVM, pUsbIns);
583
//SSMR3DeregisterUsb(pVM, pUsbIns, NULL, 0);
584
pdmR3ThreadDestroyUsb(pVM, pUsbIns);
587
/* then the 'normal' ones. */
588
for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
590
pdmR3TermLuns(pVM, pDevIns->Internal.s.pLunsR3, pDevIns->pReg->szName, pDevIns->iInstance);
592
if (pDevIns->pReg->pfnDestruct)
594
LogFlow(("pdmR3DevTerm: Destroying - device '%s'/%d\n",
595
pDevIns->pReg->szName, pDevIns->iInstance));
596
pDevIns->pReg->pfnDestruct(pDevIns);
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);
608
* Destroy all threads.
610
pdmR3ThreadDestroyAll(pVM);
613
* Destroy the block cache.
615
pdmR3BlkCacheTerm(pVM);
617
#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
619
* Free async completion managers.
621
pdmR3AsyncCompletionTerm(pVM);
627
pdmR3LdrTermU(pVM->pUVM);
630
* Destroy the PDM lock.
632
PDMR3CritSectDelete(&pVM->pdm.s.CritSect);
633
/* The MiscCritSect is deleted by PDMR3CritSectTerm. */
635
LogFlow(("PDMR3Term: returns %Rrc\n", VINF_SUCCESS));
641
* Terminates the PDM part of the UVM.
643
* This will unload any modules left behind.
645
* @param pUVM Pointer to the user mode VM structure.
647
VMMR3DECL(void) PDMR3TermUVM(PUVM pUVM)
650
* In the normal cause of events we will now call pdmR3LdrTermU for
651
* the second time. In the case of init failure however, this might
652
* the first time, which is why we do it.
656
Assert(pUVM->pdm.s.pCritSects == NULL);
657
RTCritSectDelete(&pUVM->pdm.s.ListCritSect);
662
* Bits that are saved in pass 0 and in the final pass.
664
* @param pVM The VM handle.
665
* @param pSSM The saved state handle.
667
static void pdmR3SaveBoth(PVM pVM, PSSMHANDLE pSSM)
670
* Save the list of device instances so we can check that they're all still
671
* there when we load the state and that nothing new has been added.
674
for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3, i++)
676
SSMR3PutU32(pSSM, i);
677
SSMR3PutStrZ(pSSM, pDevIns->pReg->szName);
678
SSMR3PutU32(pSSM, pDevIns->iInstance);
680
SSMR3PutU32(pSSM, UINT32_MAX); /* terminator */
687
* @returns VBox status code.
688
* @param pVM The VM handle.
689
* @param pSSM The saved state handle.
690
* @param uPass The pass.
692
static DECLCALLBACK(int) pdmR3LiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass)
694
LogFlow(("pdmR3LiveExec:\n"));
695
AssertReturn(uPass == 0, VERR_INTERNAL_ERROR_4);
696
pdmR3SaveBoth(pVM, pSSM);
697
return VINF_SSM_DONT_CALL_AGAIN;
702
* Execute state save operation.
704
* @returns VBox status code.
705
* @param pVM The VM handle.
706
* @param pSSM The saved state handle.
708
static DECLCALLBACK(int) pdmR3SaveExec(PVM pVM, PSSMHANDLE pSSM)
710
LogFlow(("pdmR3SaveExec:\n"));
713
* Save interrupt and DMA states.
715
for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
717
PVMCPU pVCpu = &pVM->aCpus[idCpu];
718
SSMR3PutU32(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC));
719
SSMR3PutU32(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC));
720
SSMR3PutU32(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_NMI));
721
SSMR3PutU32(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_SMI));
723
SSMR3PutU32(pSSM, VM_FF_ISSET(pVM, VM_FF_PDM_DMA));
725
pdmR3SaveBoth(pVM, pSSM);
731
* Prepare state load operation.
733
* This will dispatch pending operations and clear the FFs governed by PDM and its devices.
735
* @returns VBox status code.
736
* @param pVM The VM handle.
737
* @param pSSM The SSM handle.
739
static DECLCALLBACK(int) pdmR3LoadPrep(PVM pVM, PSSMHANDLE pSSM)
741
LogFlow(("pdmR3LoadPrep: %s%s\n",
742
VM_FF_ISSET(pVM, VM_FF_PDM_QUEUES) ? " VM_FF_PDM_QUEUES" : "",
743
VM_FF_ISSET(pVM, VM_FF_PDM_DMA) ? " VM_FF_PDM_DMA" : ""));
745
for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
747
PVMCPU pVCpu = &pVM->aCpus[idCpu];
748
LogFlow(("pdmR3LoadPrep: VCPU %u %s%s\n", idCpu,
749
VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC) ? " VMCPU_FF_INTERRUPT_APIC" : "",
750
VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC) ? " VMCPU_FF_INTERRUPT_PIC" : ""));
755
* In case there is work pending that will raise an interrupt,
756
* start a DMA transfer, or release a lock. (unlikely)
758
if (VM_FF_ISSET(pVM, VM_FF_PDM_QUEUES))
759
PDMR3QueueFlushAll(pVM);
762
for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
764
PVMCPU pVCpu = &pVM->aCpus[idCpu];
765
VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
766
VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
767
VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
768
VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_SMI);
770
VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
777
* Execute state load operation.
779
* @returns VBox status code.
780
* @param pVM VM Handle.
781
* @param pSSM SSM operation handle.
782
* @param uVersion Data layout version.
783
* @param uPass The data pass.
785
static DECLCALLBACK(int) pdmR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
789
LogFlow(("pdmR3LoadExec: uPass=%#x\n", uPass));
794
if ( uVersion != PDM_SAVED_STATE_VERSION
795
&& uVersion != PDM_SAVED_STATE_VERSION_PRE_NMI_FF)
797
AssertMsgFailed(("Invalid version uVersion=%d!\n", uVersion));
798
return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
801
if (uPass == SSM_PASS_FINAL)
804
* Load the interrupt and DMA states.
806
for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
808
PVMCPU pVCpu = &pVM->aCpus[idCpu];
811
uint32_t fInterruptPending = 0;
812
rc = SSMR3GetU32(pSSM, &fInterruptPending);
815
if (fInterruptPending & ~1)
817
AssertMsgFailed(("fInterruptPending=%#x (APIC)\n", fInterruptPending));
818
return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
820
AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC));
821
if (fInterruptPending)
822
VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC);
825
fInterruptPending = 0;
826
rc = SSMR3GetU32(pSSM, &fInterruptPending);
829
if (fInterruptPending & ~1)
831
AssertMsgFailed(("fInterruptPending=%#x (PIC)\n", fInterruptPending));
832
return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
834
AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC));
835
if (fInterruptPending)
836
VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC);
838
if (uVersion > PDM_SAVED_STATE_VERSION_PRE_NMI_FF)
841
fInterruptPending = 0;
842
rc = SSMR3GetU32(pSSM, &fInterruptPending);
845
if (fInterruptPending & ~1)
847
AssertMsgFailed(("fInterruptPending=%#x (NMI)\n", fInterruptPending));
848
return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
850
AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_NMI));
851
if (fInterruptPending)
852
VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI);
855
fInterruptPending = 0;
856
rc = SSMR3GetU32(pSSM, &fInterruptPending);
859
if (fInterruptPending & ~1)
861
AssertMsgFailed(("fInterruptPending=%#x (SMI)\n", fInterruptPending));
862
return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
864
AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_SMI));
865
if (fInterruptPending)
866
VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_SMI);
871
uint32_t fDMAPending = 0;
872
rc = SSMR3GetU32(pSSM, &fDMAPending);
875
if (fDMAPending & ~1)
877
AssertMsgFailed(("fDMAPending=%#x\n", fDMAPending));
878
return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
881
VM_FF_SET(pVM, VM_FF_PDM_DMA);
882
Log(("pdmR3LoadExec: VM_FF_PDM_DMA=%RTbool\n", VM_FF_ISSET(pVM, VM_FF_PDM_DMA)));
886
* Load the list of devices and verify that they are all there.
888
for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
889
pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_FOUND;
891
for (uint32_t i = 0; ; i++)
893
/* Get the sequence number / terminator. */
895
rc = SSMR3GetU32(pSSM, &u32Sep);
898
if (u32Sep == UINT32_MAX)
901
AssertMsgFailedReturn(("Out of sequence. u32Sep=%#x i=%#x\n", u32Sep, i), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
903
/* Get the name and instance number. */
904
char szName[RT_SIZEOFMEMB(PDMDEVREG, szName)];
905
rc = SSMR3GetStrZ(pSSM, szName, sizeof(szName));
909
rc = SSMR3GetU32(pSSM, &iInstance);
915
for (pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
916
if ( !strcmp(szName, pDevIns->pReg->szName)
917
&& pDevIns->iInstance == iInstance)
919
AssertLogRelMsgReturn(!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_FOUND),
920
("%s/#%u\n", pDevIns->pReg->szName, pDevIns->iInstance),
921
VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
922
pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_FOUND;
927
LogRel(("Device '%s'/%d not found in current config\n", szName, iInstance));
928
if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
929
return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device '%s'/%d not found in current config"), szName, iInstance);
934
* Check that no additional devices were configured.
936
for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
937
if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_FOUND))
939
LogRel(("Device '%s'/%d not found in the saved state\n", pDevIns->pReg->szName, pDevIns->iInstance));
940
if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
941
return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device '%s'/%d not found in the saved state"),
942
pDevIns->pReg->szName, pDevIns->iInstance);
950
* Worker for PDMR3PowerOn that deals with one driver.
952
* @param pDrvIns The driver instance.
953
* @param pszDeviceName The parent device name.
954
* @param iDevInstance The parent device instance number.
955
* @param iLun The parent LUN number.
957
DECLINLINE(int) pdmR3PowerOnDrv(PPDMDRVINS pDrvIns, const char *pszDeviceName, uint32_t iDevInstance, uint32_t iLun)
959
Assert(pDrvIns->Internal.s.fVMSuspended);
960
if (pDrvIns->pReg->pfnPowerOn)
962
LogFlow(("PDMR3PowerOn: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
963
pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance));
964
int rc = VINF_SUCCESS; pDrvIns->pReg->pfnPowerOn(pDrvIns);
967
LogRel(("PDMR3PowerOn: driver '%s'/%d on LUN#%d of device '%s'/%d -> %Rrc\n",
968
pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance, rc));
972
pDrvIns->Internal.s.fVMSuspended = false;
978
* Worker for PDMR3PowerOn that deals with one USB device instance.
980
* @returns VBox status code.
981
* @param pUsbIns The USB device instance.
983
DECLINLINE(int) pdmR3PowerOnUsb(PPDMUSBINS pUsbIns)
985
Assert(pUsbIns->Internal.s.fVMSuspended);
986
if (pUsbIns->pReg->pfnVMPowerOn)
988
LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
989
int rc = VINF_SUCCESS; pUsbIns->pReg->pfnVMPowerOn(pUsbIns);
992
LogRel(("PDMR3PowerOn: device '%s'/%d -> %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
996
pUsbIns->Internal.s.fVMSuspended = false;
1002
* Worker for PDMR3PowerOn that deals with one device instance.
1004
* @returns VBox status code.
1005
* @param pDevIns The device instance.
1007
DECLINLINE(int) pdmR3PowerOnDev(PPDMDEVINS pDevIns)
1009
Assert(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED);
1010
if (pDevIns->pReg->pfnPowerOn)
1012
LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1013
int rc = VINF_SUCCESS; pDevIns->pReg->pfnPowerOn(pDevIns);
1016
LogRel(("PDMR3PowerOn: device '%s'/%d -> %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
1020
pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1021
return VINF_SUCCESS;
1026
* This function will notify all the devices and their
1027
* attached drivers about the VM now being powered on.
1029
* @param pVM VM Handle.
1031
VMMR3DECL(void) PDMR3PowerOn(PVM pVM)
1033
LogFlow(("PDMR3PowerOn:\n"));
1036
* Iterate thru the device instances and USB device instances,
1037
* processing the drivers associated with those.
1039
int rc = VINF_SUCCESS;
1040
for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns && RT_SUCCESS(rc); pDevIns = pDevIns->Internal.s.pNextR3)
1042
for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1043
for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1044
rc = pdmR3PowerOnDrv(pDrvIns, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun);
1046
rc = pdmR3PowerOnDev(pDevIns);
1049
#ifdef VBOX_WITH_USB
1050
for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns && RT_SUCCESS(rc); pUsbIns = pUsbIns->Internal.s.pNext)
1052
for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1053
for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1054
rc = pdmR3PowerOnDrv(pDrvIns, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun);
1056
rc = pdmR3PowerOnUsb(pUsbIns);
1060
#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
1061
pdmR3AsyncCompletionResume(pVM);
1065
* Resume all threads.
1068
pdmR3ThreadResumeAll(pVM);
1071
* On failure, clean up via PDMR3Suspend.
1076
LogFlow(("PDMR3PowerOn: returns %Rrc\n", rc));
1082
* Worker for PDMR3Reset that deals with one driver.
1084
* @param pDrvIns The driver instance.
1085
* @param pcAsync The asynchronous reset notification counter.
1086
* @param pszDeviceName The parent device name.
1087
* @param iDevInstance The parent device instance number.
1088
* @param iLun The parent LUN number.
1090
DECLINLINE(bool) pdmR3ResetDrv(PPDMDRVINS pDrvIns, unsigned *pcAsync,
1091
const char *pszDeviceName, uint32_t iDevInstance, uint32_t iLun)
1093
if (!pDrvIns->Internal.s.fVMReset)
1095
pDrvIns->Internal.s.fVMReset = true;
1096
if (pDrvIns->pReg->pfnReset)
1098
if (!pDrvIns->Internal.s.pfnAsyncNotify)
1100
LogFlow(("PDMR3Reset: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1101
pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance));
1102
pDrvIns->pReg->pfnReset(pDrvIns);
1103
if (pDrvIns->Internal.s.pfnAsyncNotify)
1104
LogFlow(("PDMR3Reset: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1105
pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance));
1107
else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
1109
pDrvIns->Internal.s.pfnAsyncNotify = false;
1110
LogFlow(("PDMR3Reset: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1111
pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance));
1113
if (pDrvIns->Internal.s.pfnAsyncNotify)
1115
pDrvIns->Internal.s.fVMReset = false;
1126
* Worker for PDMR3Reset that deals with one USB device instance.
1128
* @param pUsbIns The USB device instance.
1129
* @param pcAsync The asynchronous reset notification counter.
1131
DECLINLINE(void) pdmR3ResetUsb(PPDMUSBINS pUsbIns, unsigned *pcAsync)
1133
if (!pUsbIns->Internal.s.fVMReset)
1135
pUsbIns->Internal.s.fVMReset = true;
1136
if (pUsbIns->pReg->pfnVMReset)
1138
if (!pUsbIns->Internal.s.pfnAsyncNotify)
1140
LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1141
pUsbIns->pReg->pfnVMReset(pUsbIns);
1142
if (pUsbIns->Internal.s.pfnAsyncNotify)
1143
LogFlow(("PDMR3Reset: Async notification started - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1145
else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
1147
LogFlow(("PDMR3Reset: Async notification completed - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1148
pUsbIns->Internal.s.pfnAsyncNotify = NULL;
1150
if (pUsbIns->Internal.s.pfnAsyncNotify)
1152
pUsbIns->Internal.s.fVMReset = false;
1161
* Worker for PDMR3Reset that deals with one device instance.
1163
* @param pDevIns The device instance.
1164
* @param pcAsync The asynchronous reset notification counter.
1166
DECLINLINE(void) pdmR3ResetDev(PPDMDEVINS pDevIns, unsigned *pcAsync)
1168
if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_RESET))
1170
pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_RESET;
1171
if (pDevIns->pReg->pfnReset)
1173
if (!pDevIns->Internal.s.pfnAsyncNotify)
1175
LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1176
pDevIns->pReg->pfnReset(pDevIns);
1177
if (pDevIns->Internal.s.pfnAsyncNotify)
1178
LogFlow(("PDMR3Reset: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1180
else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
1182
LogFlow(("PDMR3Reset: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1183
pDevIns->Internal.s.pfnAsyncNotify = NULL;
1185
if (pDevIns->Internal.s.pfnAsyncNotify)
1187
pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_RESET;
1196
* Resets a virtual CPU.
1198
* Used by PDMR3Reset and CPU hot plugging.
1200
* @param pVCpu The virtual CPU handle.
1202
VMMR3DECL(void) PDMR3ResetCpu(PVMCPU pVCpu)
1204
VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
1205
VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
1206
VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
1207
VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_SMI);
1212
* This function will notify all the devices and their attached drivers about
1213
* the VM now being reset.
1215
* @param pVM VM Handle.
1217
VMMR3DECL(void) PDMR3Reset(PVM pVM)
1219
LogFlow(("PDMR3Reset:\n"));
1222
* Clear all the reset flags.
1224
for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1226
pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_RESET;
1227
for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1228
for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1229
pDrvIns->Internal.s.fVMReset = false;
1231
#ifdef VBOX_WITH_USB
1232
for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1234
pUsbIns->Internal.s.fVMReset = false;
1235
for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1236
for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1237
pDrvIns->Internal.s.fVMReset = false;
1242
* The outer loop repeats until there are no more async requests.
1245
for (unsigned iLoop = 0; ; iLoop++)
1248
* Iterate thru the device instances and USB device instances,
1249
* processing the drivers associated with those.
1252
for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1254
unsigned const cAsyncStart = cAsync;
1256
if (cAsync == cAsyncStart)
1257
for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1258
for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1259
if (!pdmR3ResetDrv(pDrvIns, &cAsync, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
1262
if (cAsync == cAsyncStart)
1263
pdmR3ResetDev(pDevIns, &cAsync);
1266
#ifdef VBOX_WITH_USB
1267
for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1269
unsigned const cAsyncStart = cAsync;
1271
for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1272
for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1273
if (!pdmR3ResetDrv(pDrvIns, &cAsync, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
1276
if (cAsync == cAsyncStart)
1277
pdmR3ResetUsb(pUsbIns, &cAsync);
1286
/** @todo This is utterly nuts and completely unsafe... will get back to it in a
1288
int rc = VMR3AsyncPdmNotificationWaitU(&pVM->pUVM->aCpus[0]);
1289
AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
1290
rc = VMR3ReqProcessU(pVM->pUVM, VMCPUID_ANY);
1291
AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
1292
rc = VMR3ReqProcessU(pVM->pUVM, 0/*idDstCpu*/);
1293
AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
1297
* Clear all pending interrupts and DMA operations.
1299
for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
1300
PDMR3ResetCpu(&pVM->aCpus[idCpu]);
1301
VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
1303
LogFlow(("PDMR3Reset: returns void\n"));
1308
* Worker for PDMR3Suspend that deals with one driver.
1310
* @param pDrvIns The driver instance.
1311
* @param pcAsync The asynchronous suspend notification counter.
1312
* @param pszDeviceName The parent device name.
1313
* @param iDevInstance The parent device instance number.
1314
* @param iLun The parent LUN number.
1316
DECLINLINE(bool) pdmR3SuspendDrv(PPDMDRVINS pDrvIns, unsigned *pcAsync,
1317
const char *pszDeviceName, uint32_t iDevInstance, uint32_t iLun)
1319
if (!pDrvIns->Internal.s.fVMSuspended)
1321
pDrvIns->Internal.s.fVMSuspended = true;
1322
if (pDrvIns->pReg->pfnSuspend)
1324
if (!pDrvIns->Internal.s.pfnAsyncNotify)
1326
LogFlow(("PDMR3Suspend: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1327
pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance));
1328
pDrvIns->pReg->pfnSuspend(pDrvIns);
1329
if (pDrvIns->Internal.s.pfnAsyncNotify)
1330
LogFlow(("PDMR3Suspend: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1331
pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance));
1333
else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
1335
pDrvIns->Internal.s.pfnAsyncNotify = false;
1336
LogFlow(("PDMR3Suspend: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1337
pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance));
1339
if (pDrvIns->Internal.s.pfnAsyncNotify)
1341
pDrvIns->Internal.s.fVMSuspended = false;
1352
* Worker for PDMR3Suspend that deals with one USB device instance.
1354
* @param pUsbIns The USB device instance.
1355
* @param pcAsync The asynchronous suspend notification counter.
1357
DECLINLINE(void) pdmR3SuspendUsb(PPDMUSBINS pUsbIns, unsigned *pcAsync)
1359
if (!pUsbIns->Internal.s.fVMSuspended)
1361
pUsbIns->Internal.s.fVMSuspended = true;
1362
if (pUsbIns->pReg->pfnVMSuspend)
1364
if (!pUsbIns->Internal.s.pfnAsyncNotify)
1366
LogFlow(("PDMR3Suspend: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1367
pUsbIns->pReg->pfnVMSuspend(pUsbIns);
1368
if (pUsbIns->Internal.s.pfnAsyncNotify)
1369
LogFlow(("PDMR3Suspend: Async notification started - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1371
else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
1373
LogFlow(("PDMR3Suspend: Async notification completed - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1374
pUsbIns->Internal.s.pfnAsyncNotify = NULL;
1376
if (pUsbIns->Internal.s.pfnAsyncNotify)
1378
pUsbIns->Internal.s.fVMSuspended = false;
1387
* Worker for PDMR3Suspend that deals with one device instance.
1389
* @param pDevIns The device instance.
1390
* @param pcAsync The asynchronous suspend notification counter.
1392
DECLINLINE(void) pdmR3SuspendDev(PPDMDEVINS pDevIns, unsigned *pcAsync)
1394
if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED))
1396
pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_SUSPENDED;
1397
if (pDevIns->pReg->pfnSuspend)
1399
if (!pDevIns->Internal.s.pfnAsyncNotify)
1401
LogFlow(("PDMR3Suspend: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1402
pDevIns->pReg->pfnSuspend(pDevIns);
1403
if (pDevIns->Internal.s.pfnAsyncNotify)
1404
LogFlow(("PDMR3Suspend: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1406
else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
1408
LogFlow(("PDMR3Suspend: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1409
pDevIns->Internal.s.pfnAsyncNotify = NULL;
1411
if (pDevIns->Internal.s.pfnAsyncNotify)
1413
pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1422
* This function will notify all the devices and their attached drivers about
1423
* the VM now being suspended.
1425
* @param pVM The VM Handle.
1428
VMMR3DECL(void) PDMR3Suspend(PVM pVM)
1430
LogFlow(("PDMR3Suspend:\n"));
1431
VM_ASSERT_EMT0(pVM);
1434
* The outer loop repeats until there are no more async requests.
1436
* Note! We depend on the suspended indicators to be in the desired state
1437
* and we do not reset them before starting because this allows
1438
* PDMR3PowerOn and PDMR3Resume to use PDMR3Suspend for cleaning up
1442
for (unsigned iLoop = 0; ; iLoop++)
1445
* Iterate thru the device instances and USB device instances,
1446
* processing the drivers associated with those.
1448
* The attached drivers are normally processed first. Some devices
1449
* (like DevAHCI) though needs to be notified before the drivers so
1450
* that it doesn't kick off any new requests after the drivers stopped
1451
* taking any. (DrvVD changes to read-only in this particular case.)
1454
for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1456
unsigned const cAsyncStart = cAsync;
1458
if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION)
1459
pdmR3SuspendDev(pDevIns, &cAsync);
1461
if (cAsync == cAsyncStart)
1462
for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1463
for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1464
if (!pdmR3SuspendDrv(pDrvIns, &cAsync, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
1467
if ( cAsync == cAsyncStart
1468
&& !(pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION))
1469
pdmR3SuspendDev(pDevIns, &cAsync);
1472
#ifdef VBOX_WITH_USB
1473
for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1475
unsigned const cAsyncStart = cAsync;
1477
for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1478
for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1479
if (!pdmR3SuspendDrv(pDrvIns, &cAsync, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
1482
if (cAsync == cAsyncStart)
1483
pdmR3SuspendUsb(pUsbIns, &cAsync);
1492
/** @todo This is utterly nuts and completely unsafe... will get back to it in a
1494
int rc = VMR3AsyncPdmNotificationWaitU(&pVM->pUVM->aCpus[0]);
1495
AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
1496
rc = VMR3ReqProcessU(pVM->pUVM, VMCPUID_ANY);
1497
AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
1498
rc = VMR3ReqProcessU(pVM->pUVM, 0/*idDstCpu*/);
1499
AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
1503
* Suspend all threads.
1505
pdmR3ThreadSuspendAll(pVM);
1507
LogFlow(("PDMR3Suspend: returns void\n"));
1512
* Worker for PDMR3Resume that deals with one driver.
1514
* @param pDrvIns The driver instance.
1515
* @param pszDeviceName The parent device name.
1516
* @param iDevInstance The parent device instance number.
1517
* @param iLun The parent LUN number.
1519
DECLINLINE(int) pdmR3ResumeDrv(PPDMDRVINS pDrvIns, const char *pszDeviceName, uint32_t iDevInstance, uint32_t iLun)
1521
Assert(pDrvIns->Internal.s.fVMSuspended);
1522
if (pDrvIns->pReg->pfnResume)
1524
LogFlow(("PDMR3Resume: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1525
pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance));
1526
int rc = VINF_SUCCESS; pDrvIns->pReg->pfnResume(pDrvIns);
1529
LogRel(("PDMR3Resume: driver '%s'/%d on LUN#%d of device '%s'/%d -> %Rrc\n",
1530
pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance, rc));
1534
pDrvIns->Internal.s.fVMSuspended = false;
1535
return VINF_SUCCESS;
1540
* Worker for PDMR3Resume that deals with one USB device instance.
1542
* @returns VBox status code.
1543
* @param pUsbIns The USB device instance.
1545
DECLINLINE(int) pdmR3ResumeUsb(PPDMUSBINS pUsbIns)
1547
Assert(pUsbIns->Internal.s.fVMSuspended);
1548
if (pUsbIns->pReg->pfnVMResume)
1550
LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1551
int rc = VINF_SUCCESS; pUsbIns->pReg->pfnVMResume(pUsbIns);
1554
LogRel(("PDMR3Resume: device '%s'/%d -> %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1558
pUsbIns->Internal.s.fVMSuspended = false;
1559
return VINF_SUCCESS;
1564
* Worker for PDMR3Resume that deals with one device instance.
1566
* @returns VBox status code.
1567
* @param pDevIns The device instance.
1569
DECLINLINE(int) pdmR3ResumeDev(PPDMDEVINS pDevIns)
1571
Assert(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED);
1572
if (pDevIns->pReg->pfnResume)
1574
LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1575
int rc = VINF_SUCCESS; pDevIns->pReg->pfnResume(pDevIns);
1578
LogRel(("PDMR3Resume: device '%s'/%d -> %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
1582
pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1583
return VINF_SUCCESS;
1588
* This function will notify all the devices and their
1589
* attached drivers about the VM now being resumed.
1591
* @param pVM VM Handle.
1593
VMMR3DECL(void) PDMR3Resume(PVM pVM)
1595
LogFlow(("PDMR3Resume:\n"));
1598
* Iterate thru the device instances and USB device instances,
1599
* processing the drivers associated with those.
1601
int rc = VINF_SUCCESS;
1602
for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns && RT_SUCCESS(rc); pDevIns = pDevIns->Internal.s.pNextR3)
1604
for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1605
for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1606
rc = pdmR3ResumeDrv(pDrvIns, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun);
1608
rc = pdmR3ResumeDev(pDevIns);
1611
#ifdef VBOX_WITH_USB
1612
for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns && RT_SUCCESS(rc); pUsbIns = pUsbIns->Internal.s.pNext)
1614
for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun && RT_SUCCESS(rc); pLun = pLun->pNext)
1615
for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns && RT_SUCCESS(rc); pDrvIns = pDrvIns->Internal.s.pDown)
1616
rc = pdmR3ResumeDrv(pDrvIns, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun);
1618
rc = pdmR3ResumeUsb(pUsbIns);
1623
* Resume all threads.
1626
pdmR3ThreadResumeAll(pVM);
1629
* Resume the block cache.
1632
pdmR3BlkCacheResume(pVM);
1635
* On failure, clean up via PDMR3Suspend.
1640
LogFlow(("PDMR3Resume: returns %Rrc\n", rc));
1646
* Worker for PDMR3PowerOff that deals with one driver.
1648
* @param pDrvIns The driver instance.
1649
* @param pcAsync The asynchronous power off notification counter.
1650
* @param pszDeviceName The parent device name.
1651
* @param iDevInstance The parent device instance number.
1652
* @param iLun The parent LUN number.
1654
DECLINLINE(bool) pdmR3PowerOffDrv(PPDMDRVINS pDrvIns, unsigned *pcAsync,
1655
const char *pszDeviceName, uint32_t iDevInstance, uint32_t iLun)
1657
if (!pDrvIns->Internal.s.fVMSuspended)
1659
pDrvIns->Internal.s.fVMSuspended = true;
1660
if (pDrvIns->pReg->pfnPowerOff)
1662
if (!pDrvIns->Internal.s.pfnAsyncNotify)
1664
LogFlow(("PDMR3PowerOff: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1665
pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance));
1666
pDrvIns->pReg->pfnPowerOff(pDrvIns);
1667
if (pDrvIns->Internal.s.pfnAsyncNotify)
1668
LogFlow(("PDMR3PowerOff: Async notification started - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1669
pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance));
1671
else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
1673
pDrvIns->Internal.s.pfnAsyncNotify = false;
1674
LogFlow(("PDMR3PowerOff: Async notification completed - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1675
pDrvIns->pReg->szName, pDrvIns->iInstance, iLun, pszDeviceName, iDevInstance));
1677
if (pDrvIns->Internal.s.pfnAsyncNotify)
1679
pDrvIns->Internal.s.fVMSuspended = false;
1690
* Worker for PDMR3PowerOff that deals with one USB device instance.
1692
* @param pUsbIns The USB device instance.
1693
* @param pcAsync The asynchronous power off notification counter.
1695
DECLINLINE(void) pdmR3PowerOffUsb(PPDMUSBINS pUsbIns, unsigned *pcAsync)
1697
if (!pUsbIns->Internal.s.fVMSuspended)
1699
pUsbIns->Internal.s.fVMSuspended = true;
1700
if (pUsbIns->pReg->pfnVMPowerOff)
1702
if (!pUsbIns->Internal.s.pfnAsyncNotify)
1704
LogFlow(("PDMR3PowerOff: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1705
pUsbIns->pReg->pfnVMPowerOff(pUsbIns);
1706
if (pUsbIns->Internal.s.pfnAsyncNotify)
1707
LogFlow(("PDMR3PowerOff: Async notification started - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1709
else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
1711
LogFlow(("PDMR3PowerOff: Async notification completed - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1712
pUsbIns->Internal.s.pfnAsyncNotify = NULL;
1714
if (pUsbIns->Internal.s.pfnAsyncNotify)
1716
pUsbIns->Internal.s.fVMSuspended = false;
1725
* Worker for PDMR3PowerOff that deals with one device instance.
1727
* @param pDevIns The device instance.
1728
* @param pcAsync The asynchronous power off notification counter.
1730
DECLINLINE(void) pdmR3PowerOffDev(PPDMDEVINS pDevIns, unsigned *pcAsync)
1732
if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED))
1734
pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_SUSPENDED;
1735
if (pDevIns->pReg->pfnPowerOff)
1737
if (!pDevIns->Internal.s.pfnAsyncNotify)
1739
LogFlow(("PDMR3PowerOff: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1740
pDevIns->pReg->pfnPowerOff(pDevIns);
1741
if (pDevIns->Internal.s.pfnAsyncNotify)
1742
LogFlow(("PDMR3PowerOff: Async notification started - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1744
else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
1746
LogFlow(("PDMR3PowerOff: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
1747
pDevIns->Internal.s.pfnAsyncNotify = NULL;
1749
if (pDevIns->Internal.s.pfnAsyncNotify)
1751
pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
1760
* This function will notify all the devices and their
1761
* attached drivers about the VM being powered off.
1763
* @param pVM VM Handle.
1765
VMMR3DECL(void) PDMR3PowerOff(PVM pVM)
1767
LogFlow(("PDMR3PowerOff:\n"));
1770
* The outer loop repeats until there are no more async requests.
1773
for (unsigned iLoop = 0; ; iLoop++)
1776
* Iterate thru the device instances and USB device instances,
1777
* processing the drivers associated with those.
1779
* The attached drivers are normally processed first. Some devices
1780
* (like DevAHCI) though needs to be notified before the drivers so
1781
* that it doesn't kick off any new requests after the drivers stopped
1782
* taking any. (DrvVD changes to read-only in this particular case.)
1785
for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1787
unsigned const cAsyncStart = cAsync;
1789
if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION)
1790
pdmR3PowerOffDev(pDevIns, &cAsync);
1792
if (cAsync == cAsyncStart)
1793
for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1794
for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1795
if (!pdmR3PowerOffDrv(pDrvIns, &cAsync, pDevIns->pReg->szName, pDevIns->iInstance, pLun->iLun))
1798
if ( cAsync == cAsyncStart
1799
&& !(pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION))
1800
pdmR3PowerOffDev(pDevIns, &cAsync);
1803
#ifdef VBOX_WITH_USB
1804
for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1806
unsigned const cAsyncStart = cAsync;
1808
for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1809
for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1810
if (!pdmR3PowerOffDrv(pDrvIns, &cAsync, pUsbIns->pReg->szName, pUsbIns->iInstance, pLun->iLun))
1813
if (cAsync == cAsyncStart)
1814
pdmR3PowerOffUsb(pUsbIns, &cAsync);
1823
/** @todo This is utterly nuts and completely unsafe... will get back to it in a
1825
int rc = VMR3AsyncPdmNotificationWaitU(&pVM->pUVM->aCpus[0]);
1826
AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
1827
rc = VMR3ReqProcessU(pVM->pUVM, VMCPUID_ANY);
1828
AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
1829
rc = VMR3ReqProcessU(pVM->pUVM, 0/*idDstCpu*/);
1830
AssertReleaseMsg(rc == VINF_SUCCESS, ("%Rrc\n", rc));
1834
* Suspend all threads.
1836
pdmR3ThreadSuspendAll(pVM);
1838
LogFlow(("PDMR3PowerOff: returns void\n"));
1843
* Queries the base interface of a device instance.
1845
* The caller can use this to query other interfaces the device implements
1846
* and use them to talk to the device.
1848
* @returns VBox status code.
1849
* @param pVM VM handle.
1850
* @param pszDevice Device name.
1851
* @param iInstance Device instance.
1852
* @param ppBase Where to store the pointer to the base device interface on success.
1853
* @remark We're not doing any locking ATM, so don't try call this at times when the
1854
* device chain is known to be updated.
1856
VMMR3DECL(int) PDMR3QueryDevice(PVM pVM, const char *pszDevice, unsigned iInstance, PPDMIBASE *ppBase)
1858
LogFlow(("PDMR3DeviceQuery: pszDevice=%p:{%s} iInstance=%u ppBase=%p\n", pszDevice, pszDevice, iInstance, ppBase));
1861
* Iterate registered devices looking for the device.
1863
size_t cchDevice = strlen(pszDevice);
1864
for (PPDMDEV pDev = pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
1866
if ( pDev->cchName == cchDevice
1867
&& !memcmp(pDev->pReg->szName, pszDevice, cchDevice))
1870
* Iterate device instances.
1872
for (PPDMDEVINS pDevIns = pDev->pInstances; pDevIns; pDevIns = pDevIns->Internal.s.pPerDeviceNextR3)
1874
if (pDevIns->iInstance == iInstance)
1876
if (pDevIns->IBase.pfnQueryInterface)
1878
*ppBase = &pDevIns->IBase;
1879
LogFlow(("PDMR3DeviceQuery: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
1880
return VINF_SUCCESS;
1883
LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NO_IBASE\n"));
1884
return VERR_PDM_DEVICE_INSTANCE_NO_IBASE;
1888
LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NOT_FOUND\n"));
1889
return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND;
1893
LogFlow(("PDMR3QueryDevice: returns VERR_PDM_DEVICE_NOT_FOUND\n"));
1894
return VERR_PDM_DEVICE_NOT_FOUND;
1899
* Queries the base interface of a device LUN.
1901
* This differs from PDMR3QueryLun by that it returns the interface on the
1902
* device and not the top level driver.
1904
* @returns VBox status code.
1905
* @param pVM VM Handle.
1906
* @param pszDevice Device name.
1907
* @param iInstance Device instance.
1908
* @param iLun The Logical Unit to obtain the interface of.
1909
* @param ppBase Where to store the base interface pointer.
1910
* @remark We're not doing any locking ATM, so don't try call this at times when the
1911
* device chain is known to be updated.
1913
VMMR3DECL(int) PDMR3QueryDeviceLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
1915
LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
1916
pszDevice, pszDevice, iInstance, iLun, ppBase));
1922
int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
1925
*ppBase = pLun->pBase;
1926
LogFlow(("PDMR3QueryDeviceLun: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
1927
return VINF_SUCCESS;
1929
LogFlow(("PDMR3QueryDeviceLun: returns %Rrc\n", rc));
1935
* Query the interface of the top level driver on a LUN.
1937
* @returns VBox status code.
1938
* @param pVM VM Handle.
1939
* @param pszDevice Device name.
1940
* @param iInstance Device instance.
1941
* @param iLun The Logical Unit to obtain the interface of.
1942
* @param ppBase Where to store the base interface pointer.
1943
* @remark We're not doing any locking ATM, so don't try call this at times when the
1944
* device chain is known to be updated.
1946
VMMR3DECL(int) PDMR3QueryLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
1948
LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
1949
pszDevice, pszDevice, iInstance, iLun, ppBase));
1955
int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
1960
*ppBase = &pLun->pTop->IBase;
1961
LogFlow(("PDMR3QueryLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
1962
return VINF_SUCCESS;
1964
rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
1966
LogFlow(("PDMR3QueryLun: returns %Rrc\n", rc));
1972
* Query the interface of a named driver on a LUN.
1974
* If the driver appears more than once in the driver chain, the first instance
1977
* @returns VBox status code.
1978
* @param pVM VM Handle.
1979
* @param pszDevice Device name.
1980
* @param iInstance Device instance.
1981
* @param iLun The Logical Unit to obtain the interface of.
1982
* @param pszDriver The driver name.
1983
* @param ppBase Where to store the base interface pointer.
1985
* @remark We're not doing any locking ATM, so don't try call this at times when the
1986
* device chain is known to be updated.
1988
VMMR3DECL(int) PDMR3QueryDriverOnLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, const char *pszDriver, PPPDMIBASE ppBase)
1990
LogFlow(("PDMR3QueryDriverOnLun: pszDevice=%p:{%s} iInstance=%u iLun=%u pszDriver=%p:{%s} ppBase=%p\n",
1991
pszDevice, pszDevice, iInstance, iLun, pszDriver, pszDriver, ppBase));
1997
int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
2002
for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
2003
if (!strcmp(pDrvIns->pReg->szName, pszDriver))
2005
*ppBase = &pDrvIns->IBase;
2006
LogFlow(("PDMR3QueryDriverOnLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
2007
return VINF_SUCCESS;
2010
rc = VERR_PDM_DRIVER_NOT_FOUND;
2013
rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
2015
LogFlow(("PDMR3QueryDriverOnLun: returns %Rrc\n", rc));
2020
* Executes pending DMA transfers.
2021
* Forced Action handler.
2023
* @param pVM VM handle.
2025
VMMR3DECL(void) PDMR3DmaRun(PVM pVM)
2027
/* Note! Not really SMP safe; restrict it to VCPU 0. */
2028
if (VMMGetCpuId(pVM) != 0)
2031
if (VM_FF_TESTANDCLEAR(pVM, VM_FF_PDM_DMA))
2033
if (pVM->pdm.s.pDmac)
2035
bool fMore = pVM->pdm.s.pDmac->Reg.pfnRun(pVM->pdm.s.pDmac->pDevIns);
2037
VM_FF_SET(pVM, VM_FF_PDM_DMA);
2044
* Service a VMMCALLRING3_PDM_LOCK call.
2046
* @returns VBox status code.
2047
* @param pVM The VM handle.
2049
VMMR3DECL(int) PDMR3LockCall(PVM pVM)
2051
return PDMR3CritSectEnterEx(&pVM->pdm.s.CritSect, true /* fHostCall */);
2056
* Registers the VMM device heap
2058
* @returns VBox status code.
2059
* @param pVM VM handle.
2060
* @param GCPhys The physical address.
2061
* @param pvHeap Ring-3 pointer.
2062
* @param cbSize Size of the heap.
2064
VMMR3DECL(int) PDMR3RegisterVMMDevHeap(PVM pVM, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbSize)
2066
Assert(pVM->pdm.s.pvVMMDevHeap == NULL);
2068
Log(("PDMR3RegisterVMMDevHeap %RGp %RHv %x\n", GCPhys, pvHeap, cbSize));
2069
pVM->pdm.s.pvVMMDevHeap = pvHeap;
2070
pVM->pdm.s.GCPhysVMMDevHeap = GCPhys;
2071
pVM->pdm.s.cbVMMDevHeap = cbSize;
2072
pVM->pdm.s.cbVMMDevHeapLeft = cbSize;
2073
return VINF_SUCCESS;
2078
* Unregisters the VMM device heap
2080
* @returns VBox status code.
2081
* @param pVM VM handle.
2082
* @param GCPhys The physical address.
2084
VMMR3DECL(int) PDMR3UnregisterVMMDevHeap(PVM pVM, RTGCPHYS GCPhys)
2086
Assert(pVM->pdm.s.GCPhysVMMDevHeap == GCPhys);
2088
Log(("PDMR3UnregisterVMMDevHeap %RGp\n", GCPhys));
2089
pVM->pdm.s.pvVMMDevHeap = NULL;
2090
pVM->pdm.s.GCPhysVMMDevHeap = NIL_RTGCPHYS;
2091
pVM->pdm.s.cbVMMDevHeap = 0;
2092
pVM->pdm.s.cbVMMDevHeapLeft = 0;
2093
return VINF_SUCCESS;
2098
* Allocates memory from the VMM device heap
2100
* @returns VBox status code.
2101
* @param pVM VM handle.
2102
* @param cbSize Allocation size.
2103
* @param pv Ring-3 pointer. (out)
2105
VMMR3DECL(int) PDMR3VMMDevHeapAlloc(PVM pVM, unsigned cbSize, RTR3PTR *ppv)
2108
if (!cbSize || cbSize > pVM->pdm.s.cbVMMDevHeapLeft)
2109
return VERR_NO_MEMORY;
2111
AssertReturn(cbSize && cbSize <= pVM->pdm.s.cbVMMDevHeapLeft, VERR_NO_MEMORY);
2114
Log(("PDMR3VMMDevHeapAlloc %x\n", cbSize));
2116
/** @todo not a real heap as there's currently only one user. */
2117
*ppv = pVM->pdm.s.pvVMMDevHeap;
2118
pVM->pdm.s.cbVMMDevHeapLeft = 0;
2119
return VINF_SUCCESS;
2124
* Frees memory from the VMM device heap
2126
* @returns VBox status code.
2127
* @param pVM VM handle.
2128
* @param pv Ring-3 pointer.
2130
VMMR3DECL(int) PDMR3VMMDevHeapFree(PVM pVM, RTR3PTR pv)
2132
Log(("PDMR3VMMDevHeapFree %RHv\n", pv));
2134
/** @todo not a real heap as there's currently only one user. */
2135
pVM->pdm.s.cbVMMDevHeapLeft = pVM->pdm.s.cbVMMDevHeap;
2136
return VINF_SUCCESS;