~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/VMM/VMMR3/PDM.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: PDM.cpp 35346 2010-12-27 16:13:13Z vboxsync $ */
 
2
/** @file
 
3
 * PDM - Pluggable Device Manager.
 
4
 */
 
5
 
 
6
/*
 
7
 * Copyright (C) 2006-2007 Oracle Corporation
 
8
 *
 
9
 * This file is part of VirtualBox Open Source Edition (OSE), as
 
10
 * available from http://www.virtualbox.org. This file is free software;
 
11
 * you can redistribute it and/or modify it under the terms of the GNU
 
12
 * General Public License (GPL) as published by the Free Software
 
13
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 
14
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 
15
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 
16
 */
 
17
 
 
18
 
 
19
/** @page   pg_pdm      PDM - The Pluggable Device & Driver Manager
 
20
 *
 
21
 * VirtualBox is designed to be very configurable, i.e. the ability to select
 
22
 * virtual devices and configure them uniquely for a VM.  For this reason
 
23
 * virtual devices are not statically linked with the VMM but loaded, linked and
 
24
 * instantiated at runtime by PDM using the information found in the
 
25
 * Configuration Manager (CFGM).
 
26
 *
 
27
 * While the chief purpose of PDM is to manager of devices their drivers, it
 
28
 * also serves as somewhere to put usful things like cross context queues, cross
 
29
 * context synchronization (like critsect), VM centric thread management,
 
30
 * asynchronous I/O framework, and so on.
 
31
 *
 
32
 * @see grp_pdm
 
33
 *
 
34
 *
 
35
 * @section sec_pdm_dev     The Pluggable Devices
 
36
 *
 
37
 * Devices register themselves when the module containing them is loaded.  PDM
 
38
 * will call the entry point 'VBoxDevicesRegister' when loading a device module.
 
39
 * The device module will then use the supplied callback table to check the VMM
 
40
 * version and to register its devices.  Each device have an unique (for the
 
41
 * configured VM) name.  The name is not only used in PDM but also in CFGM (to
 
42
 * organize device and device instance settings) and by anyone who wants to talk
 
43
 * to a specific device instance.
 
44
 *
 
45
 * When all device modules have been successfully loaded PDM will instantiate
 
46
 * those devices which are configured for the VM.  Note that a device may have
 
47
 * more than one instance, see network adaptors for instance.  When
 
48
 * instantiating a device PDM provides device instance memory and a callback
 
49
 * table (aka Device Helpers / DevHlp) with the VM APIs which the device
 
50
 * instance is trusted with.
 
51
 *
 
52
 * Some devices are trusted devices, most are not.  The trusted devices are an
 
53
 * integrated part of the VM and can obtain the VM handle from their device
 
54
 * instance handles, thus enabling them to call any VM api.  Untrusted devices
 
55
 * can only use the callbacks provided during device instantiation.
 
56
 *
 
57
 * The main purpose in having DevHlps rather than just giving all the devices
 
58
 * the VM handle and let them call the internal VM APIs directly, is both to
 
59
 * create a binary interface that can be supported across releases and to
 
60
 * create a barrier between devices and the VM.  (The trusted / untrusted bit
 
61
 * hasn't turned out to be of much use btw., but it's easy to maintain so there
 
62
 * isn't any point in removing it.)
 
63
 *
 
64
 * A device can provide a ring-0 and/or a raw-mode context extension to improve
 
65
 * the VM performance by handling exits and traps (respectively) without
 
66
 * requiring context switches (to ring-3).  Callbacks for MMIO and I/O ports can
 
67
 * needs to be registered specifically for the additional contexts for this to
 
68
 * make sense.  Also, the device has to be trusted to be loaded into R0/RC
 
69
 * because of the extra privilege it entails.  Note that raw-mode code and data
 
70
 * will be subject to relocation.
 
71
 *
 
72
 *
 
73
 * @section sec_pdm_special_devs    Special Devices
 
74
 *
 
75
 * Several kinds of devices interacts with the VMM and/or other device and PDM
 
76
 * will work like a mediator for these. The typical pattern is that the device
 
77
 * calls a special registration device helper with a set of callbacks, PDM
 
78
 * responds by copying this and providing a pointer to a set helper callbacks
 
79
 * for that particular kind of device. Unlike interfaces where the callback
 
80
 * table pointer is used a 'this' pointer, these arrangements will use the
 
81
 * device instance pointer (PPDMDEVINS) as a kind of 'this' pointer.
 
82
 *
 
83
 * For an example of this kind of setup, see the PIC. The PIC registers itself
 
84
 * by calling PDMDEVHLPR3::pfnPICRegister.  PDM saves the device instance,
 
85
 * copies the callback tables (PDMPICREG), resolving the ring-0 and raw-mode
 
86
 * addresses in the process, and hands back the pointer to a set of helper
 
87
 * methods (PDMPICHLPR3).  The PCI device then queries the ring-0 and raw-mode
 
88
 * helpers using PDMPICHLPR3::pfnGetR0Helpers and PDMPICHLPR3::pfnGetRCHelpers.
 
89
 * The PCI device repeats ths pfnGetRCHelpers call in it's relocation method
 
90
 * since the address changes when RC is relocated.
 
91
 *
 
92
 * @see grp_pdm_device
 
93
 *
 
94
 *
 
95
 * @section sec_pdm_usbdev  The Pluggable USB Devices
 
96
 *
 
97
 * USB devices are handled a little bit differently than other devices.  The
 
98
 * general concepts wrt. pluggability are mostly the same, but the details
 
99
 * varies.  The registration entry point is 'VBoxUsbRegister', the device
 
100
 * instance is PDMUSBINS and the callbacks helpers are different.  Also, USB
 
101
 * device are restricted to ring-3 and cannot have any ring-0 or raw-mode
 
102
 * extensions (at least not yet).
 
103
 *
 
104
 * The way USB devices work differs greatly from other devices though since they
 
105
 * aren't attaches directly to the PCI/ISA/whatever system buses but via a
 
106
 * USB host control (OHCI, UHCI or EHCI).  USB devices handles USB requests
 
107
 * (URBs) and does not register I/O ports, MMIO ranges or PCI bus
 
108
 * devices/functions.
 
109
 *
 
110
 * @see grp_pdm_usbdev
 
111
 *
 
112
 *
 
113
 * @section sec_pdm_drv     The Pluggable Drivers
 
114
 *
 
115
 * The VM devices are often accessing host hardware or OS facilities.  For most
 
116
 * devices these facilities can be abstracted in one or more levels.  These
 
117
 * abstractions are called drivers.
 
118
 *
 
119
 * For instance take a DVD/CD drive.  This can be connected to a SCSI
 
120
 * controller, an ATA controller or a SATA controller.  The basics of the DVD/CD
 
121
 * drive implementation remains the same - eject, insert, read, seek, and such.
 
122
 * (For the scsi case, you might wanna speak SCSI directly to, but that can of
 
123
 * course be fixed - see SCSI passthru.)  So, it
 
124
 * makes much sense to have a generic CD/DVD driver which implements this.
 
125
 *
 
126
 * Then the media 'inserted' into the DVD/CD drive can be a ISO image, or it can
 
127
 * be read from a real CD or DVD drive (there are probably other custom formats
 
128
 * someone could desire to read or construct too).  So, it would make sense to
 
129
 * have abstracted interfaces for dealing with this in a generic way so the
 
130
 * cdrom unit doesn't have to implement it all.  Thus we have created the
 
131
 * CDROM/DVD media driver family.
 
132
 *
 
133
 * So, for this example the IDE controller #1 (i.e. secondary) will have
 
134
 * the DVD/CD Driver attached to it's LUN #0 (master).  When a media is mounted
 
135
 * the DVD/CD Driver will have a ISO, HostDVD or RAW (media) Driver attached.
 
136
 *
 
137
 * It is possible to configure many levels of drivers inserting filters, loggers,
 
138
 * or whatever you desire into the chain.  We're using this for network sniffing
 
139
 * for instance.
 
140
 *
 
141
 * The drivers are loaded in a similar manner to that of the device, namely by
 
142
 * iterating a keyspace in CFGM, load the modules listed there and call
 
143
 * 'VBoxDriversRegister' with a callback table.
 
144
 *
 
145
 * @see grp_pdm_driver
 
146
 *
 
147
 *
 
148
 * @section sec_pdm_ifs     Interfaces
 
149
 *
 
150
 * The pluggable drivers and devices exposes one standard interface (callback
 
151
 * table) which is used to construct, destruct, attach, detach,( ++,) and query
 
152
 * other interfaces. A device will query the interfaces required for it's
 
153
 * operation during init and hot-plug.  PDM may query some interfaces during
 
154
 * runtime mounting too.
 
155
 *
 
156
 * An interface here means a function table contained within the device or
 
157
 * driver instance data. Its method are invoked with the function table pointer
 
158
 * as the first argument and they will calculate the address of the device or
 
159
 * driver instance data from it. (This is one of the aspects which *might* have
 
160
 * been better done in C++.)
 
161
 *
 
162
 * @see grp_pdm_interfaces
 
163
 *
 
164
 *
 
165
 * @section sec_pdm_utils   Utilities
 
166
 *
 
167
 * As mentioned earlier, PDM is the location of any usful constructs that doesn't
 
168
 * quite fit into IPRT. The next subsections will discuss these.
 
169
 *
 
170
 * One thing these APIs all have in common is that resources will be associated
 
171
 * with a device / driver and automatically freed after it has been destroyed if
 
172
 * the destructor didn't do this.
 
173
 *
 
174
 *
 
175
 * @subsection sec_pdm_async_completion     Async I/O
 
176
 *
 
177
 * The PDM Async I/O API provides a somewhat platform agnostic interface for
 
178
 * asynchronous I/O.  For reasons of performance and complexity this does not
 
179
 * build upon any IPRT API.
 
180
 *
 
181
 * @todo more details.
 
182
 *
 
183
 * @see grp_pdm_async_completion
 
184
 *
 
185
 *
 
186
 * @subsection sec_pdm_async_task   Async Task - not implemented
 
187
 *
 
188
 * @todo implement and describe
 
189
 *
 
190
 * @see grp_pdm_async_task
 
191
 *
 
192
 *
 
193
 * @subsection sec_pdm_critsect     Critical Section
 
194
 *
 
195
 * The PDM Critical Section API is currently building on the IPRT API with the
 
196
 * same name.  It adds the possibility to use critical sections in ring-0 and
 
197
 * raw-mode as well as in ring-3.  There are certain restrictions on the RC and
 
198
 * R0 usage though since we're not able to wait on it, nor wake up anyone that
 
199
 * is waiting on it.  These restrictions origins with the use of a ring-3 event
 
200
 * semaphore.  In a later incarnation we plan to replace the ring-3 event
 
201
 * semaphore with a ring-0 one, thus enabling us to wake up waiters while
 
202
 * exectuing in ring-0 and making the hardware assisted execution mode more
 
203
 * efficient. (Raw-mode won't benefit much from this, naturally.)
 
204
 *
 
205
 * @see grp_pdm_critsect
 
206
 *
 
207
 *
 
208
 * @subsection sec_pdm_queue        Queue
 
209
 *
 
210
 * The PDM Queue API is for queuing one or more tasks for later consumption in
 
211
 * ring-3 by EMT, and optionally forcing a delayed or ASAP return to ring-3.  The
 
212
 * queues can also be run on a timer basis as an alternative to the ASAP thing.
 
213
 * The queue will be flushed at forced action time.
 
214
 *
 
215
 * A queue can also be used by another thread (a I/O worker for instance) to
 
216
 * send work / events over to the EMT.
 
217
 *
 
218
 * @see grp_pdm_queue
 
219
 *
 
220
 *
 
221
 * @subsection sec_pdm_task        Task - not implemented yet
 
222
 *
 
223
 * The PDM Task API is for flagging a task for execution at a later point when
 
224
 * we're back in ring-3, optionally forcing the ring-3 return to happen ASAP.
 
225
 * As you can see the concept is similar to queues only simpler.
 
226
 *
 
227
 * A task can also be scheduled by another thread (a I/O worker for instance) as
 
228
 * a mean of getting something done in EMT.
 
229
 *
 
230
 * @see grp_pdm_task
 
231
 *
 
232
 *
 
233
 * @subsection sec_pdm_thread       Thread
 
234
 *
 
235
 * The PDM Thread API is there to help devices and drivers manage their threads
 
236
 * correctly wrt. power on, suspend, resume, power off and destruction.
 
237
 *
 
238
 * The general usage pattern for threads in the employ of devices and drivers is
 
239
 * that they shuffle data or requests while the VM is running and stop doing
 
240
 * this when the VM is paused or powered down. Rogue threads running while the
 
241
 * VM is paused can cause the state to change during saving or have other
 
242
 * unwanted side effects. The PDM Threads API ensures that this won't happen.
 
243
 *
 
244
 * @see grp_pdm_thread
 
245
 *
 
246
 */
 
247
 
 
248
 
 
249
/*******************************************************************************
 
250
*   Header Files                                                               *
 
251
*******************************************************************************/
 
252
#define LOG_GROUP LOG_GROUP_PDM
 
253
#include "PDMInternal.h"
 
254
#include <VBox/vmm/pdm.h>
 
255
#include <VBox/vmm/mm.h>
 
256
#include <VBox/vmm/pgm.h>
 
257
#include <VBox/vmm/ssm.h>
 
258
#include <VBox/vmm/vm.h>
 
259
#include <VBox/vmm/uvm.h>
 
260
#include <VBox/vmm/vmm.h>
 
261
#include <VBox/param.h>
 
262
#include <VBox/err.h>
 
263
#include <VBox/sup.h>
 
264
 
 
265
#include <VBox/log.h>
 
266
#include <iprt/asm.h>
 
267
#include <iprt/assert.h>
 
268
#include <iprt/alloc.h>
 
269
#include <iprt/ldr.h>
 
270
#include <iprt/path.h>
 
271
#include <iprt/string.h>
 
272
 
 
273
 
 
274
/*******************************************************************************
 
275
*   Defined Constants And Macros                                               *
 
276
*******************************************************************************/
 
277
/** The PDM saved state version. */
 
278
#define PDM_SAVED_STATE_VERSION             4
 
279
#define PDM_SAVED_STATE_VERSION_PRE_NMI_FF  3
 
280
 
 
281
 
 
282
/*******************************************************************************
 
283
*   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);
 
289
 
 
290
 
 
291
 
 
292
/**
 
293
 * Initializes the PDM part of the UVM.
 
294
 *
 
295
 * This doesn't really do much right now but has to be here for the sake
 
296
 * of completeness.
 
297
 *
 
298
 * @returns VBox status code.
 
299
 * @param   pUVM        Pointer to the user mode VM structure.
 
300
 */
 
301
VMMR3DECL(int) PDMR3InitUVM(PUVM pUVM)
 
302
{
 
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);
 
308
}
 
309
 
 
310
 
 
311
/**
 
312
 * Initializes the PDM.
 
313
 *
 
314
 * @returns VBox status code.
 
315
 * @param   pVM         The VM to operate on.
 
316
 */
 
317
VMMR3DECL(int) PDMR3Init(PVM pVM)
 
318
{
 
319
    LogFlow(("PDMR3Init\n"));
 
320
 
 
321
    /*
 
322
     * Assert alignment and sizes.
 
323
     */
 
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));
 
327
    /*
 
328
     * Init the structure.
 
329
     */
 
330
    pVM->pdm.s.offVM = RT_OFFSETOF(VM, pdm.s);
 
331
    pVM->pdm.s.GCPhysVMMDevHeap = NIL_RTGCPHYS;
 
332
 
 
333
    /*
 
334
     * Initialize sub components.
 
335
     */
 
336
    int rc = pdmR3CritSectInitStats(pVM);
 
337
    if (RT_SUCCESS(rc))
 
338
        rc = PDMR3CritSectInit(pVM, &pVM->pdm.s.CritSect, RT_SRC_POS, "PDM");
 
339
    if (RT_SUCCESS(rc))
 
340
        rc = pdmR3LdrInitU(pVM->pUVM);
 
341
#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
 
342
    if (RT_SUCCESS(rc))
 
343
        rc = pdmR3AsyncCompletionInit(pVM);
 
344
#endif
 
345
    if (RT_SUCCESS(rc))
 
346
        rc = pdmR3BlkCacheInit(pVM);
 
347
    if (RT_SUCCESS(rc))
 
348
        rc = pdmR3DrvInit(pVM);
 
349
    if (RT_SUCCESS(rc))
 
350
        rc = pdmR3DevInit(pVM);
 
351
    if (RT_SUCCESS(rc))
 
352
    {
 
353
        /*
 
354
         * Register the saved state data unit.
 
355
         */
 
356
        rc = SSMR3RegisterInternal(pVM, "pdm", 1, PDM_SAVED_STATE_VERSION, 128,
 
357
                                   NULL, pdmR3LiveExec, NULL,
 
358
                                   NULL, pdmR3SaveExec, NULL,
 
359
                                   pdmR3LoadPrep, pdmR3LoadExec, NULL);
 
360
        if (RT_SUCCESS(rc))
 
361
        {
 
362
            LogFlow(("PDM: Successfully initialized\n"));
 
363
            return rc;
 
364
        }
 
365
    }
 
366
 
 
367
    /*
 
368
     * Cleanup and return failure.
 
369
     */
 
370
    PDMR3Term(pVM);
 
371
    LogFlow(("PDMR3Init: returns %Rrc\n", rc));
 
372
    return rc;
 
373
}
 
374
 
 
375
 
 
376
/**
 
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.
 
380
 *
 
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.
 
385
 */
 
386
VMMR3DECL(void) PDMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
 
387
{
 
388
    LogFlow(("PDMR3Relocate\n"));
 
389
 
 
390
    /*
 
391
     * Queues.
 
392
     */
 
393
    pdmR3QueueRelocate(pVM, offDelta);
 
394
    pVM->pdm.s.pDevHlpQueueRC = PDMQueueRCPtr(pVM->pdm.s.pDevHlpQueueR3);
 
395
 
 
396
    /*
 
397
     * Critical sections.
 
398
     */
 
399
    pdmR3CritSectRelocate(pVM);
 
400
 
 
401
    /*
 
402
     * The registered PIC.
 
403
     */
 
404
    if (pVM->pdm.s.Pic.pDevInsRC)
 
405
    {
 
406
        pVM->pdm.s.Pic.pDevInsRC            += offDelta;
 
407
        pVM->pdm.s.Pic.pfnSetIrqRC          += offDelta;
 
408
        pVM->pdm.s.Pic.pfnGetInterruptRC    += offDelta;
 
409
    }
 
410
 
 
411
    /*
 
412
     * The registered APIC.
 
413
     */
 
414
    if (pVM->pdm.s.Apic.pDevInsRC)
 
415
    {
 
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;
 
427
    }
 
428
 
 
429
    /*
 
430
     * The registered I/O APIC.
 
431
     */
 
432
    if (pVM->pdm.s.IoApic.pDevInsRC)
 
433
    {
 
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;
 
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
 */
 
516
static 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
 */
 
558
VMMR3DECL(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
    /*
 
613
     * Destroy the block cache.
 
614
     */
 
615
    pdmR3BlkCacheTerm(pVM);
 
616
 
 
617
#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
 
618
    /*
 
619
     * Free async completion managers.
 
620
     */
 
621
    pdmR3AsyncCompletionTerm(pVM);
 
622
#endif
 
623
 
 
624
    /*
 
625
     * Free modules.
 
626
     */
 
627
    pdmR3LdrTermU(pVM->pUVM);
 
628
 
 
629
    /*
 
630
     * Destroy the PDM lock.
 
631
     */
 
632
    PDMR3CritSectDelete(&pVM->pdm.s.CritSect);
 
633
    /* The MiscCritSect is deleted by PDMR3CritSectTerm. */
 
634
 
 
635
    LogFlow(("PDMR3Term: returns %Rrc\n", VINF_SUCCESS));
 
636
    return VINF_SUCCESS;
 
637
}
 
638
 
 
639
 
 
640
/**
 
641
 * Terminates the PDM part of the UVM.
 
642
 *
 
643
 * This will unload any modules left behind.
 
644
 *
 
645
 * @param   pUVM        Pointer to the user mode VM structure.
 
646
 */
 
647
VMMR3DECL(void) PDMR3TermUVM(PUVM pUVM)
 
648
{
 
649
    /*
 
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.
 
653
     */
 
654
    pdmR3LdrTermU(pUVM);
 
655
 
 
656
    Assert(pUVM->pdm.s.pCritSects == NULL);
 
657
    RTCritSectDelete(&pUVM->pdm.s.ListCritSect);
 
658
}
 
659
 
 
660
 
 
661
/**
 
662
 * Bits that are saved in pass 0 and in the final pass.
 
663
 *
 
664
 * @param   pVM             The VM handle.
 
665
 * @param   pSSM            The saved state handle.
 
666
 */
 
667
static void pdmR3SaveBoth(PVM pVM, PSSMHANDLE pSSM)
 
668
{
 
669
    /*
 
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.
 
672
     */
 
673
    uint32_t i = 0;
 
674
    for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3, i++)
 
675
    {
 
676
        SSMR3PutU32(pSSM, i);
 
677
        SSMR3PutStrZ(pSSM, pDevIns->pReg->szName);
 
678
        SSMR3PutU32(pSSM, pDevIns->iInstance);
 
679
    }
 
680
    SSMR3PutU32(pSSM, UINT32_MAX); /* terminator */
 
681
}
 
682
 
 
683
 
 
684
/**
 
685
 * Live save.
 
686
 *
 
687
 * @returns VBox status code.
 
688
 * @param   pVM             The VM handle.
 
689
 * @param   pSSM            The saved state handle.
 
690
 * @param   uPass           The pass.
 
691
 */
 
692
static DECLCALLBACK(int) pdmR3LiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass)
 
693
{
 
694
    LogFlow(("pdmR3LiveExec:\n"));
 
695
    AssertReturn(uPass == 0, VERR_INTERNAL_ERROR_4);
 
696
    pdmR3SaveBoth(pVM, pSSM);
 
697
    return VINF_SSM_DONT_CALL_AGAIN;
 
698
}
 
699
 
 
700
 
 
701
/**
 
702
 * Execute state save operation.
 
703
 *
 
704
 * @returns VBox status code.
 
705
 * @param   pVM             The VM handle.
 
706
 * @param   pSSM            The saved state handle.
 
707
 */
 
708
static DECLCALLBACK(int) pdmR3SaveExec(PVM pVM, PSSMHANDLE pSSM)
 
709
{
 
710
    LogFlow(("pdmR3SaveExec:\n"));
 
711
 
 
712
    /*
 
713
     * Save interrupt and DMA states.
 
714
     */
 
715
    for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
 
716
    {
 
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));
 
722
    }
 
723
    SSMR3PutU32(pSSM, VM_FF_ISSET(pVM, VM_FF_PDM_DMA));
 
724
 
 
725
    pdmR3SaveBoth(pVM, pSSM);
 
726
    return VINF_SUCCESS;
 
727
}
 
728
 
 
729
 
 
730
/**
 
731
 * Prepare state load operation.
 
732
 *
 
733
 * This will dispatch pending operations and clear the FFs governed by PDM and its devices.
 
734
 *
 
735
 * @returns VBox status code.
 
736
 * @param   pVM         The VM handle.
 
737
 * @param   pSSM        The SSM handle.
 
738
 */
 
739
static DECLCALLBACK(int) pdmR3LoadPrep(PVM pVM, PSSMHANDLE pSSM)
 
740
{
 
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" : ""));
 
744
#ifdef LOG_ENABLED
 
745
    for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
 
746
    {
 
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" : ""));
 
751
    }
 
752
#endif
 
753
 
 
754
    /*
 
755
     * In case there is work pending that will raise an interrupt,
 
756
     * start a DMA transfer, or release a lock. (unlikely)
 
757
     */
 
758
    if (VM_FF_ISSET(pVM, VM_FF_PDM_QUEUES))
 
759
        PDMR3QueueFlushAll(pVM);
 
760
 
 
761
    /* Clear the FFs. */
 
762
    for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
 
763
    {
 
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);
 
769
    }
 
770
    VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
 
771
 
 
772
    return VINF_SUCCESS;
 
773
}
 
774
 
 
775
 
 
776
/**
 
777
 * Execute state load operation.
 
778
 *
 
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.
 
784
 */
 
785
static DECLCALLBACK(int) pdmR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
 
786
{
 
787
    int rc;
 
788
 
 
789
    LogFlow(("pdmR3LoadExec: uPass=%#x\n", uPass));
 
790
 
 
791
    /*
 
792
     * Validate version.
 
793
     */
 
794
    if (    uVersion != PDM_SAVED_STATE_VERSION
 
795
        &&  uVersion != PDM_SAVED_STATE_VERSION_PRE_NMI_FF)
 
796
    {
 
797
        AssertMsgFailed(("Invalid version uVersion=%d!\n", uVersion));
 
798
        return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
 
799
    }
 
800
 
 
801
    if (uPass == SSM_PASS_FINAL)
 
802
    {
 
803
        /*
 
804
         * Load the interrupt and DMA states.
 
805
         */
 
806
        for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
 
807
        {
 
808
            PVMCPU pVCpu = &pVM->aCpus[idCpu];
 
809
 
 
810
            /* APIC interrupt */
 
811
            uint32_t fInterruptPending = 0;
 
812
            rc = SSMR3GetU32(pSSM, &fInterruptPending);
 
813
            if (RT_FAILURE(rc))
 
814
                return rc;
 
815
            if (fInterruptPending & ~1)
 
816
            {
 
817
                AssertMsgFailed(("fInterruptPending=%#x (APIC)\n", fInterruptPending));
 
818
                return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
 
819
            }
 
820
            AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC));
 
821
            if (fInterruptPending)
 
822
                VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC);
 
823
 
 
824
            /* PIC interrupt */
 
825
            fInterruptPending = 0;
 
826
            rc = SSMR3GetU32(pSSM, &fInterruptPending);
 
827
            if (RT_FAILURE(rc))
 
828
                return rc;
 
829
            if (fInterruptPending & ~1)
 
830
            {
 
831
                AssertMsgFailed(("fInterruptPending=%#x (PIC)\n", fInterruptPending));
 
832
                return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
 
833
            }
 
834
            AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC));
 
835
            if (fInterruptPending)
 
836
                VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC);
 
837
 
 
838
            if (uVersion > PDM_SAVED_STATE_VERSION_PRE_NMI_FF)
 
839
            {
 
840
                /* NMI interrupt */
 
841
                fInterruptPending = 0;
 
842
                rc = SSMR3GetU32(pSSM, &fInterruptPending);
 
843
                if (RT_FAILURE(rc))
 
844
                    return rc;
 
845
                if (fInterruptPending & ~1)
 
846
                {
 
847
                    AssertMsgFailed(("fInterruptPending=%#x (NMI)\n", fInterruptPending));
 
848
                    return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
 
849
                }
 
850
                AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_NMI));
 
851
                if (fInterruptPending)
 
852
                    VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI);
 
853
 
 
854
                /* SMI interrupt */
 
855
                fInterruptPending = 0;
 
856
                rc = SSMR3GetU32(pSSM, &fInterruptPending);
 
857
                if (RT_FAILURE(rc))
 
858
                    return rc;
 
859
                if (fInterruptPending & ~1)
 
860
                {
 
861
                    AssertMsgFailed(("fInterruptPending=%#x (SMI)\n", fInterruptPending));
 
862
                    return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
 
863
                }
 
864
                AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_SMI));
 
865
                if (fInterruptPending)
 
866
                    VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_SMI);
 
867
            }
 
868
        }
 
869
 
 
870
        /* DMA pending */
 
871
        uint32_t fDMAPending = 0;
 
872
        rc = SSMR3GetU32(pSSM, &fDMAPending);
 
873
        if (RT_FAILURE(rc))
 
874
            return rc;
 
875
        if (fDMAPending & ~1)
 
876
        {
 
877
            AssertMsgFailed(("fDMAPending=%#x\n", fDMAPending));
 
878
            return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
 
879
        }
 
880
        if (fDMAPending)
 
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)));
 
883
    }
 
884
 
 
885
    /*
 
886
     * Load the list of devices and verify that they are all there.
 
887
     */
 
888
    for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
 
889
        pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_FOUND;
 
890
 
 
891
    for (uint32_t i = 0; ; i++)
 
892
    {
 
893
        /* Get the sequence number / terminator. */
 
894
        uint32_t    u32Sep;
 
895
        rc = SSMR3GetU32(pSSM, &u32Sep);
 
896
        if (RT_FAILURE(rc))
 
897
            return rc;
 
898
        if (u32Sep == UINT32_MAX)
 
899
            break;
 
900
        if (u32Sep != i)
 
901
            AssertMsgFailedReturn(("Out of sequence. u32Sep=%#x i=%#x\n", u32Sep, i), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
 
902
 
 
903
        /* Get the name and instance number. */
 
904
        char szName[RT_SIZEOFMEMB(PDMDEVREG, szName)];
 
905
        rc = SSMR3GetStrZ(pSSM, szName, sizeof(szName));
 
906
        if (RT_FAILURE(rc))
 
907
            return rc;
 
908
        uint32_t iInstance;
 
909
        rc = SSMR3GetU32(pSSM, &iInstance);
 
910
        if (RT_FAILURE(rc))
 
911
            return rc;
 
912
 
 
913
        /* Try locate it. */
 
914
        PPDMDEVINS pDevIns;
 
915
        for (pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
 
916
            if (   !strcmp(szName, pDevIns->pReg->szName)
 
917
                && pDevIns->iInstance == iInstance)
 
918
            {
 
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;
 
923
                break;
 
924
            }
 
925
        if (!pDevIns)
 
926
        {
 
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);
 
930
        }
 
931
    }
 
932
 
 
933
    /*
 
934
     * Check that no additional devices were configured.
 
935
     */
 
936
    for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
 
937
        if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_FOUND))
 
938
        {
 
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);
 
943
        }
 
944
 
 
945
    return VINF_SUCCESS;
 
946
}
 
947
 
 
948
 
 
949
/**
 
950
 * Worker for PDMR3PowerOn that deals with one driver.
 
951
 *
 
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.
 
956
 */
 
957
DECLINLINE(int) pdmR3PowerOnDrv(PPDMDRVINS pDrvIns, const char *pszDeviceName, uint32_t iDevInstance, uint32_t iLun)
 
958
{
 
959
    Assert(pDrvIns->Internal.s.fVMSuspended);
 
960
    if (pDrvIns->pReg->pfnPowerOn)
 
961
    {
 
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);
 
965
        if (RT_FAILURE(rc))
 
966
        {
 
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));
 
969
            return rc;
 
970
        }
 
971
    }
 
972
    pDrvIns->Internal.s.fVMSuspended = false;
 
973
    return VINF_SUCCESS;
 
974
}
 
975
 
 
976
 
 
977
/**
 
978
 * Worker for PDMR3PowerOn that deals with one USB device instance.
 
979
 *
 
980
 * @returns VBox status code.
 
981
 * @param   pUsbIns             The USB device instance.
 
982
 */
 
983
DECLINLINE(int) pdmR3PowerOnUsb(PPDMUSBINS pUsbIns)
 
984
{
 
985
    Assert(pUsbIns->Internal.s.fVMSuspended);
 
986
    if (pUsbIns->pReg->pfnVMPowerOn)
 
987
    {
 
988
        LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
 
989
        int rc = VINF_SUCCESS; pUsbIns->pReg->pfnVMPowerOn(pUsbIns);
 
990
        if (RT_FAILURE(rc))
 
991
        {
 
992
            LogRel(("PDMR3PowerOn: device '%s'/%d -> %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
 
993
            return rc;
 
994
        }
 
995
    }
 
996
    pUsbIns->Internal.s.fVMSuspended = false;
 
997
    return VINF_SUCCESS;
 
998
}
 
999
 
 
1000
 
 
1001
/**
 
1002
 * Worker for PDMR3PowerOn that deals with one device instance.
 
1003
 *
 
1004
 * @returns VBox status code.
 
1005
 * @param   pDevIns             The device instance.
 
1006
 */
 
1007
DECLINLINE(int) pdmR3PowerOnDev(PPDMDEVINS pDevIns)
 
1008
{
 
1009
    Assert(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED);
 
1010
    if (pDevIns->pReg->pfnPowerOn)
 
1011
    {
 
1012
        LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
 
1013
        int rc = VINF_SUCCESS; pDevIns->pReg->pfnPowerOn(pDevIns);
 
1014
        if (RT_FAILURE(rc))
 
1015
        {
 
1016
            LogRel(("PDMR3PowerOn: device '%s'/%d -> %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
 
1017
            return rc;
 
1018
        }
 
1019
    }
 
1020
    pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
 
1021
    return VINF_SUCCESS;
 
1022
}
 
1023
 
 
1024
 
 
1025
/**
 
1026
 * This function will notify all the devices and their
 
1027
 * attached drivers about the VM now being powered on.
 
1028
 *
 
1029
 * @param   pVM     VM Handle.
 
1030
 */
 
1031
VMMR3DECL(void) PDMR3PowerOn(PVM pVM)
 
1032
{
 
1033
    LogFlow(("PDMR3PowerOn:\n"));
 
1034
 
 
1035
    /*
 
1036
     * Iterate thru the device instances and USB device instances,
 
1037
     * processing the drivers associated with those.
 
1038
     */
 
1039
    int rc = VINF_SUCCESS;
 
1040
    for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances;  pDevIns && RT_SUCCESS(rc);  pDevIns = pDevIns->Internal.s.pNextR3)
 
1041
    {
 
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);
 
1045
        if (RT_SUCCESS(rc))
 
1046
            rc = pdmR3PowerOnDev(pDevIns);
 
1047
    }
 
1048
 
 
1049
#ifdef VBOX_WITH_USB
 
1050
    for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances;  pUsbIns && RT_SUCCESS(rc);  pUsbIns = pUsbIns->Internal.s.pNext)
 
1051
    {
 
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);
 
1055
        if (RT_SUCCESS(rc))
 
1056
            rc = pdmR3PowerOnUsb(pUsbIns);
 
1057
    }
 
1058
#endif
 
1059
 
 
1060
#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
 
1061
    pdmR3AsyncCompletionResume(pVM);
 
1062
#endif
 
1063
 
 
1064
    /*
 
1065
     * Resume all threads.
 
1066
     */
 
1067
    if (RT_SUCCESS(rc))
 
1068
        pdmR3ThreadResumeAll(pVM);
 
1069
 
 
1070
    /*
 
1071
     * On failure, clean up via PDMR3Suspend.
 
1072
     */
 
1073
    if (RT_FAILURE(rc))
 
1074
        PDMR3Suspend(pVM);
 
1075
 
 
1076
    LogFlow(("PDMR3PowerOn: returns %Rrc\n", rc));
 
1077
    return /*rc*/;
 
1078
}
 
1079
 
 
1080
 
 
1081
/**
 
1082
 * Worker for PDMR3Reset that deals with one driver.
 
1083
 *
 
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.
 
1089
 */
 
1090
DECLINLINE(bool) pdmR3ResetDrv(PPDMDRVINS pDrvIns, unsigned *pcAsync,
 
1091
                               const char *pszDeviceName, uint32_t iDevInstance, uint32_t iLun)
 
1092
{
 
1093
    if (!pDrvIns->Internal.s.fVMReset)
 
1094
    {
 
1095
        pDrvIns->Internal.s.fVMReset = true;
 
1096
        if (pDrvIns->pReg->pfnReset)
 
1097
        {
 
1098
            if (!pDrvIns->Internal.s.pfnAsyncNotify)
 
1099
            {
 
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));
 
1106
            }
 
1107
            else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
 
1108
            {
 
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));
 
1112
            }
 
1113
            if (pDrvIns->Internal.s.pfnAsyncNotify)
 
1114
            {
 
1115
                pDrvIns->Internal.s.fVMReset = false;
 
1116
                (*pcAsync)++;
 
1117
                return false;
 
1118
            }
 
1119
        }
 
1120
    }
 
1121
    return true;
 
1122
}
 
1123
 
 
1124
 
 
1125
/**
 
1126
 * Worker for PDMR3Reset that deals with one USB device instance.
 
1127
 *
 
1128
 * @param   pUsbIns             The USB device instance.
 
1129
 * @param   pcAsync             The asynchronous reset notification counter.
 
1130
 */
 
1131
DECLINLINE(void) pdmR3ResetUsb(PPDMUSBINS pUsbIns, unsigned *pcAsync)
 
1132
{
 
1133
    if (!pUsbIns->Internal.s.fVMReset)
 
1134
    {
 
1135
        pUsbIns->Internal.s.fVMReset = true;
 
1136
        if (pUsbIns->pReg->pfnVMReset)
 
1137
        {
 
1138
            if (!pUsbIns->Internal.s.pfnAsyncNotify)
 
1139
            {
 
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));
 
1144
            }
 
1145
            else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
 
1146
            {
 
1147
                LogFlow(("PDMR3Reset: Async notification completed - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
 
1148
                pUsbIns->Internal.s.pfnAsyncNotify = NULL;
 
1149
            }
 
1150
            if (pUsbIns->Internal.s.pfnAsyncNotify)
 
1151
            {
 
1152
                pUsbIns->Internal.s.fVMReset = false;
 
1153
                (*pcAsync)++;
 
1154
            }
 
1155
        }
 
1156
    }
 
1157
}
 
1158
 
 
1159
 
 
1160
/**
 
1161
 * Worker for PDMR3Reset that deals with one device instance.
 
1162
 *
 
1163
 * @param   pDevIns             The device instance.
 
1164
 * @param   pcAsync             The asynchronous reset notification counter.
 
1165
 */
 
1166
DECLINLINE(void) pdmR3ResetDev(PPDMDEVINS pDevIns, unsigned *pcAsync)
 
1167
{
 
1168
    if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_RESET))
 
1169
    {
 
1170
        pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_RESET;
 
1171
        if (pDevIns->pReg->pfnReset)
 
1172
        {
 
1173
            if (!pDevIns->Internal.s.pfnAsyncNotify)
 
1174
            {
 
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));
 
1179
            }
 
1180
            else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
 
1181
            {
 
1182
                LogFlow(("PDMR3Reset: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
 
1183
                pDevIns->Internal.s.pfnAsyncNotify = NULL;
 
1184
            }
 
1185
            if (pDevIns->Internal.s.pfnAsyncNotify)
 
1186
            {
 
1187
                pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_RESET;
 
1188
                (*pcAsync)++;
 
1189
            }
 
1190
        }
 
1191
    }
 
1192
}
 
1193
 
 
1194
 
 
1195
/**
 
1196
 * Resets a virtual CPU.
 
1197
 *
 
1198
 * Used by PDMR3Reset and CPU hot plugging.
 
1199
 *
 
1200
 * @param   pVCpu               The virtual CPU handle.
 
1201
 */
 
1202
VMMR3DECL(void) PDMR3ResetCpu(PVMCPU pVCpu)
 
1203
{
 
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);
 
1208
}
 
1209
 
 
1210
 
 
1211
/**
 
1212
 * This function will notify all the devices and their attached drivers about
 
1213
 * the VM now being reset.
 
1214
 *
 
1215
 * @param   pVM     VM Handle.
 
1216
 */
 
1217
VMMR3DECL(void) PDMR3Reset(PVM pVM)
 
1218
{
 
1219
    LogFlow(("PDMR3Reset:\n"));
 
1220
 
 
1221
    /*
 
1222
     * Clear all the reset flags.
 
1223
     */
 
1224
    for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
 
1225
    {
 
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;
 
1230
    }
 
1231
#ifdef VBOX_WITH_USB
 
1232
    for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
 
1233
    {
 
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;
 
1238
    }
 
1239
#endif
 
1240
 
 
1241
    /*
 
1242
     * The outer loop repeats until there are no more async requests.
 
1243
     */
 
1244
    unsigned cAsync;
 
1245
    for (unsigned iLoop = 0; ; iLoop++)
 
1246
    {
 
1247
        /*
 
1248
         * Iterate thru the device instances and USB device instances,
 
1249
         * processing the drivers associated with those.
 
1250
         */
 
1251
        cAsync = 0;
 
1252
        for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
 
1253
        {
 
1254
            unsigned const cAsyncStart = cAsync;
 
1255
 
 
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))
 
1260
                            break;
 
1261
 
 
1262
                        if (cAsync == cAsyncStart)
 
1263
                pdmR3ResetDev(pDevIns, &cAsync);
 
1264
        }
 
1265
 
 
1266
#ifdef VBOX_WITH_USB
 
1267
        for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
 
1268
        {
 
1269
            unsigned const cAsyncStart = cAsync;
 
1270
 
 
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))
 
1274
                        break;
 
1275
 
 
1276
            if (cAsync == cAsyncStart)
 
1277
                pdmR3ResetUsb(pUsbIns, &cAsync);
 
1278
        }
 
1279
#endif
 
1280
        if (!cAsync)
 
1281
            break;
 
1282
 
 
1283
        /*
 
1284
         * Process requests.
 
1285
         */
 
1286
        /** @todo This is utterly nuts and completely unsafe... will get back to it in a
 
1287
         *        bit I hope... */
 
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));
 
1294
    }
 
1295
 
 
1296
    /*
 
1297
     * Clear all pending interrupts and DMA operations.
 
1298
     */
 
1299
    for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
 
1300
        PDMR3ResetCpu(&pVM->aCpus[idCpu]);
 
1301
    VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
 
1302
 
 
1303
    LogFlow(("PDMR3Reset: returns void\n"));
 
1304
}
 
1305
 
 
1306
 
 
1307
/**
 
1308
 * Worker for PDMR3Suspend that deals with one driver.
 
1309
 *
 
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.
 
1315
 */
 
1316
DECLINLINE(bool) pdmR3SuspendDrv(PPDMDRVINS pDrvIns, unsigned *pcAsync,
 
1317
                                 const char *pszDeviceName, uint32_t iDevInstance, uint32_t iLun)
 
1318
{
 
1319
    if (!pDrvIns->Internal.s.fVMSuspended)
 
1320
    {
 
1321
        pDrvIns->Internal.s.fVMSuspended = true;
 
1322
        if (pDrvIns->pReg->pfnSuspend)
 
1323
        {
 
1324
            if (!pDrvIns->Internal.s.pfnAsyncNotify)
 
1325
            {
 
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));
 
1332
            }
 
1333
            else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
 
1334
            {
 
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));
 
1338
            }
 
1339
            if (pDrvIns->Internal.s.pfnAsyncNotify)
 
1340
            {
 
1341
                pDrvIns->Internal.s.fVMSuspended = false;
 
1342
                (*pcAsync)++;
 
1343
                return false;
 
1344
            }
 
1345
        }
 
1346
    }
 
1347
    return true;
 
1348
}
 
1349
 
 
1350
 
 
1351
/**
 
1352
 * Worker for PDMR3Suspend that deals with one USB device instance.
 
1353
 *
 
1354
 * @param   pUsbIns             The USB device instance.
 
1355
 * @param   pcAsync             The asynchronous suspend notification counter.
 
1356
 */
 
1357
DECLINLINE(void) pdmR3SuspendUsb(PPDMUSBINS pUsbIns, unsigned *pcAsync)
 
1358
{
 
1359
    if (!pUsbIns->Internal.s.fVMSuspended)
 
1360
    {
 
1361
        pUsbIns->Internal.s.fVMSuspended = true;
 
1362
        if (pUsbIns->pReg->pfnVMSuspend)
 
1363
        {
 
1364
            if (!pUsbIns->Internal.s.pfnAsyncNotify)
 
1365
            {
 
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));
 
1370
            }
 
1371
            else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
 
1372
            {
 
1373
                LogFlow(("PDMR3Suspend: Async notification completed - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
 
1374
                pUsbIns->Internal.s.pfnAsyncNotify = NULL;
 
1375
            }
 
1376
            if (pUsbIns->Internal.s.pfnAsyncNotify)
 
1377
            {
 
1378
                pUsbIns->Internal.s.fVMSuspended = false;
 
1379
                (*pcAsync)++;
 
1380
            }
 
1381
        }
 
1382
    }
 
1383
}
 
1384
 
 
1385
 
 
1386
/**
 
1387
 * Worker for PDMR3Suspend that deals with one device instance.
 
1388
 *
 
1389
 * @param   pDevIns             The device instance.
 
1390
 * @param   pcAsync             The asynchronous suspend notification counter.
 
1391
 */
 
1392
DECLINLINE(void) pdmR3SuspendDev(PPDMDEVINS pDevIns, unsigned *pcAsync)
 
1393
{
 
1394
    if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED))
 
1395
    {
 
1396
        pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_SUSPENDED;
 
1397
        if (pDevIns->pReg->pfnSuspend)
 
1398
        {
 
1399
            if (!pDevIns->Internal.s.pfnAsyncNotify)
 
1400
            {
 
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));
 
1405
            }
 
1406
            else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
 
1407
            {
 
1408
                LogFlow(("PDMR3Suspend: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
 
1409
                pDevIns->Internal.s.pfnAsyncNotify = NULL;
 
1410
            }
 
1411
            if (pDevIns->Internal.s.pfnAsyncNotify)
 
1412
            {
 
1413
                pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
 
1414
                (*pcAsync)++;
 
1415
            }
 
1416
        }
 
1417
    }
 
1418
}
 
1419
 
 
1420
 
 
1421
/**
 
1422
 * This function will notify all the devices and their attached drivers about
 
1423
 * the VM now being suspended.
 
1424
 *
 
1425
 * @param   pVM     The VM Handle.
 
1426
 * @thread  EMT(0)
 
1427
 */
 
1428
VMMR3DECL(void) PDMR3Suspend(PVM pVM)
 
1429
{
 
1430
    LogFlow(("PDMR3Suspend:\n"));
 
1431
    VM_ASSERT_EMT0(pVM);
 
1432
 
 
1433
    /*
 
1434
     * The outer loop repeats until there are no more async requests.
 
1435
     *
 
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
 
1439
     *       on failure.
 
1440
     */
 
1441
    unsigned cAsync;
 
1442
    for (unsigned iLoop = 0; ; iLoop++)
 
1443
    {
 
1444
        /*
 
1445
         * Iterate thru the device instances and USB device instances,
 
1446
         * processing the drivers associated with those.
 
1447
         *
 
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.)
 
1452
         */
 
1453
        cAsync = 0;
 
1454
        for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
 
1455
        {
 
1456
            unsigned const cAsyncStart = cAsync;
 
1457
 
 
1458
            if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION)
 
1459
                pdmR3SuspendDev(pDevIns, &cAsync);
 
1460
 
 
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))
 
1465
                            break;
 
1466
 
 
1467
            if (    cAsync == cAsyncStart
 
1468
                && !(pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION))
 
1469
                pdmR3SuspendDev(pDevIns, &cAsync);
 
1470
        }
 
1471
 
 
1472
#ifdef VBOX_WITH_USB
 
1473
        for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
 
1474
        {
 
1475
            unsigned const cAsyncStart = cAsync;
 
1476
 
 
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))
 
1480
                        break;
 
1481
 
 
1482
            if (cAsync == cAsyncStart)
 
1483
                pdmR3SuspendUsb(pUsbIns, &cAsync);
 
1484
        }
 
1485
#endif
 
1486
        if (!cAsync)
 
1487
            break;
 
1488
 
 
1489
        /*
 
1490
         * Process requests.
 
1491
         */
 
1492
        /** @todo This is utterly nuts and completely unsafe... will get back to it in a
 
1493
         *        bit I hope... */
 
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));
 
1500
    }
 
1501
 
 
1502
    /*
 
1503
     * Suspend all threads.
 
1504
     */
 
1505
    pdmR3ThreadSuspendAll(pVM);
 
1506
 
 
1507
    LogFlow(("PDMR3Suspend: returns void\n"));
 
1508
}
 
1509
 
 
1510
 
 
1511
/**
 
1512
 * Worker for PDMR3Resume that deals with one driver.
 
1513
 *
 
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.
 
1518
 */
 
1519
DECLINLINE(int) pdmR3ResumeDrv(PPDMDRVINS pDrvIns, const char *pszDeviceName, uint32_t iDevInstance, uint32_t iLun)
 
1520
{
 
1521
    Assert(pDrvIns->Internal.s.fVMSuspended);
 
1522
    if (pDrvIns->pReg->pfnResume)
 
1523
    {
 
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);
 
1527
        if (RT_FAILURE(rc))
 
1528
        {
 
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));
 
1531
            return rc;
 
1532
        }
 
1533
    }
 
1534
    pDrvIns->Internal.s.fVMSuspended = false;
 
1535
    return VINF_SUCCESS;
 
1536
}
 
1537
 
 
1538
 
 
1539
/**
 
1540
 * Worker for PDMR3Resume that deals with one USB device instance.
 
1541
 *
 
1542
 * @returns VBox status code.
 
1543
 * @param   pUsbIns             The USB device instance.
 
1544
 */
 
1545
DECLINLINE(int) pdmR3ResumeUsb(PPDMUSBINS pUsbIns)
 
1546
{
 
1547
    Assert(pUsbIns->Internal.s.fVMSuspended);
 
1548
    if (pUsbIns->pReg->pfnVMResume)
 
1549
    {
 
1550
        LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
 
1551
        int rc = VINF_SUCCESS; pUsbIns->pReg->pfnVMResume(pUsbIns);
 
1552
        if (RT_FAILURE(rc))
 
1553
        {
 
1554
            LogRel(("PDMR3Resume: device '%s'/%d -> %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
 
1555
            return rc;
 
1556
        }
 
1557
    }
 
1558
    pUsbIns->Internal.s.fVMSuspended = false;
 
1559
    return VINF_SUCCESS;
 
1560
}
 
1561
 
 
1562
 
 
1563
/**
 
1564
 * Worker for PDMR3Resume that deals with one device instance.
 
1565
 *
 
1566
 * @returns VBox status code.
 
1567
 * @param   pDevIns             The device instance.
 
1568
 */
 
1569
DECLINLINE(int) pdmR3ResumeDev(PPDMDEVINS pDevIns)
 
1570
{
 
1571
    Assert(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED);
 
1572
    if (pDevIns->pReg->pfnResume)
 
1573
    {
 
1574
        LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
 
1575
        int rc = VINF_SUCCESS; pDevIns->pReg->pfnResume(pDevIns);
 
1576
        if (RT_FAILURE(rc))
 
1577
        {
 
1578
            LogRel(("PDMR3Resume: device '%s'/%d -> %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
 
1579
            return rc;
 
1580
        }
 
1581
    }
 
1582
    pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
 
1583
    return VINF_SUCCESS;
 
1584
}
 
1585
 
 
1586
 
 
1587
/**
 
1588
 * This function will notify all the devices and their
 
1589
 * attached drivers about the VM now being resumed.
 
1590
 *
 
1591
 * @param   pVM     VM Handle.
 
1592
 */
 
1593
VMMR3DECL(void) PDMR3Resume(PVM pVM)
 
1594
{
 
1595
    LogFlow(("PDMR3Resume:\n"));
 
1596
 
 
1597
    /*
 
1598
     * Iterate thru the device instances and USB device instances,
 
1599
     * processing the drivers associated with those.
 
1600
     */
 
1601
    int rc = VINF_SUCCESS;
 
1602
    for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances;  pDevIns && RT_SUCCESS(rc);  pDevIns = pDevIns->Internal.s.pNextR3)
 
1603
    {
 
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);
 
1607
        if (RT_SUCCESS(rc))
 
1608
            rc = pdmR3ResumeDev(pDevIns);
 
1609
    }
 
1610
 
 
1611
#ifdef VBOX_WITH_USB
 
1612
    for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances;  pUsbIns && RT_SUCCESS(rc);  pUsbIns = pUsbIns->Internal.s.pNext)
 
1613
    {
 
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);
 
1617
        if (RT_SUCCESS(rc))
 
1618
            rc = pdmR3ResumeUsb(pUsbIns);
 
1619
    }
 
1620
#endif
 
1621
 
 
1622
    /*
 
1623
     * Resume all threads.
 
1624
     */
 
1625
    if (RT_SUCCESS(rc))
 
1626
        pdmR3ThreadResumeAll(pVM);
 
1627
 
 
1628
    /*
 
1629
     * Resume the block cache.
 
1630
     */
 
1631
    if (RT_SUCCESS(rc))
 
1632
        pdmR3BlkCacheResume(pVM);
 
1633
 
 
1634
    /*
 
1635
     * On failure, clean up via PDMR3Suspend.
 
1636
     */
 
1637
    if (RT_FAILURE(rc))
 
1638
        PDMR3Suspend(pVM);
 
1639
 
 
1640
    LogFlow(("PDMR3Resume: returns %Rrc\n", rc));
 
1641
    return /*rc*/;
 
1642
}
 
1643
 
 
1644
 
 
1645
/**
 
1646
 * Worker for PDMR3PowerOff that deals with one driver.
 
1647
 *
 
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.
 
1653
 */
 
1654
DECLINLINE(bool) pdmR3PowerOffDrv(PPDMDRVINS pDrvIns, unsigned *pcAsync,
 
1655
                                  const char *pszDeviceName, uint32_t iDevInstance, uint32_t iLun)
 
1656
{
 
1657
    if (!pDrvIns->Internal.s.fVMSuspended)
 
1658
    {
 
1659
        pDrvIns->Internal.s.fVMSuspended = true;
 
1660
        if (pDrvIns->pReg->pfnPowerOff)
 
1661
        {
 
1662
            if (!pDrvIns->Internal.s.pfnAsyncNotify)
 
1663
            {
 
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));
 
1670
            }
 
1671
            else if (pDrvIns->Internal.s.pfnAsyncNotify(pDrvIns))
 
1672
            {
 
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));
 
1676
            }
 
1677
            if (pDrvIns->Internal.s.pfnAsyncNotify)
 
1678
            {
 
1679
                pDrvIns->Internal.s.fVMSuspended = false;
 
1680
                (*pcAsync)++;
 
1681
                return false;
 
1682
            }
 
1683
        }
 
1684
    }
 
1685
    return true;
 
1686
}
 
1687
 
 
1688
 
 
1689
/**
 
1690
 * Worker for PDMR3PowerOff that deals with one USB device instance.
 
1691
 *
 
1692
 * @param   pUsbIns             The USB device instance.
 
1693
 * @param   pcAsync             The asynchronous power off notification counter.
 
1694
 */
 
1695
DECLINLINE(void) pdmR3PowerOffUsb(PPDMUSBINS pUsbIns, unsigned *pcAsync)
 
1696
{
 
1697
    if (!pUsbIns->Internal.s.fVMSuspended)
 
1698
    {
 
1699
        pUsbIns->Internal.s.fVMSuspended = true;
 
1700
        if (pUsbIns->pReg->pfnVMPowerOff)
 
1701
        {
 
1702
            if (!pUsbIns->Internal.s.pfnAsyncNotify)
 
1703
            {
 
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));
 
1708
            }
 
1709
            else if (pUsbIns->Internal.s.pfnAsyncNotify(pUsbIns))
 
1710
            {
 
1711
                LogFlow(("PDMR3PowerOff: Async notification completed - device '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
 
1712
                pUsbIns->Internal.s.pfnAsyncNotify = NULL;
 
1713
            }
 
1714
            if (pUsbIns->Internal.s.pfnAsyncNotify)
 
1715
            {
 
1716
                pUsbIns->Internal.s.fVMSuspended = false;
 
1717
                (*pcAsync)++;
 
1718
            }
 
1719
        }
 
1720
    }
 
1721
}
 
1722
 
 
1723
 
 
1724
/**
 
1725
 * Worker for PDMR3PowerOff that deals with one device instance.
 
1726
 *
 
1727
 * @param   pDevIns             The device instance.
 
1728
 * @param   pcAsync             The asynchronous power off notification counter.
 
1729
 */
 
1730
DECLINLINE(void) pdmR3PowerOffDev(PPDMDEVINS pDevIns, unsigned *pcAsync)
 
1731
{
 
1732
    if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_SUSPENDED))
 
1733
    {
 
1734
        pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_SUSPENDED;
 
1735
        if (pDevIns->pReg->pfnPowerOff)
 
1736
        {
 
1737
            if (!pDevIns->Internal.s.pfnAsyncNotify)
 
1738
            {
 
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));
 
1743
            }
 
1744
            else if (pDevIns->Internal.s.pfnAsyncNotify(pDevIns))
 
1745
            {
 
1746
                LogFlow(("PDMR3PowerOff: Async notification completed - device '%s'/%d\n", pDevIns->pReg->szName, pDevIns->iInstance));
 
1747
                pDevIns->Internal.s.pfnAsyncNotify = NULL;
 
1748
            }
 
1749
            if (pDevIns->Internal.s.pfnAsyncNotify)
 
1750
            {
 
1751
                pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_SUSPENDED;
 
1752
                (*pcAsync)++;
 
1753
            }
 
1754
        }
 
1755
    }
 
1756
}
 
1757
 
 
1758
 
 
1759
/**
 
1760
 * This function will notify all the devices and their
 
1761
 * attached drivers about the VM being powered off.
 
1762
 *
 
1763
 * @param   pVM     VM Handle.
 
1764
 */
 
1765
VMMR3DECL(void) PDMR3PowerOff(PVM pVM)
 
1766
{
 
1767
    LogFlow(("PDMR3PowerOff:\n"));
 
1768
 
 
1769
    /*
 
1770
     * The outer loop repeats until there are no more async requests.
 
1771
     */
 
1772
    unsigned cAsync;
 
1773
    for (unsigned iLoop = 0; ; iLoop++)
 
1774
    {
 
1775
        /*
 
1776
         * Iterate thru the device instances and USB device instances,
 
1777
         * processing the drivers associated with those.
 
1778
         *
 
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.)
 
1783
         */
 
1784
        cAsync = 0;
 
1785
        for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
 
1786
        {
 
1787
            unsigned const cAsyncStart = cAsync;
 
1788
 
 
1789
            if (pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION)
 
1790
                pdmR3PowerOffDev(pDevIns, &cAsync);
 
1791
 
 
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))
 
1796
                            break;
 
1797
 
 
1798
            if (    cAsync == cAsyncStart
 
1799
                && !(pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION))
 
1800
                pdmR3PowerOffDev(pDevIns, &cAsync);
 
1801
        }
 
1802
 
 
1803
#ifdef VBOX_WITH_USB
 
1804
        for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
 
1805
        {
 
1806
            unsigned const cAsyncStart = cAsync;
 
1807
 
 
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))
 
1811
                        break;
 
1812
 
 
1813
            if (cAsync == cAsyncStart)
 
1814
                pdmR3PowerOffUsb(pUsbIns, &cAsync);
 
1815
        }
 
1816
#endif
 
1817
        if (!cAsync)
 
1818
            break;
 
1819
 
 
1820
        /*
 
1821
         * Process requests.
 
1822
         */
 
1823
        /** @todo This is utterly nuts and completely unsafe... will get back to it in a
 
1824
         *        bit I hope... */
 
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));
 
1831
    }
 
1832
 
 
1833
    /*
 
1834
     * Suspend all threads.
 
1835
     */
 
1836
    pdmR3ThreadSuspendAll(pVM);
 
1837
 
 
1838
    LogFlow(("PDMR3PowerOff: returns void\n"));
 
1839
}
 
1840
 
 
1841
 
 
1842
/**
 
1843
 * Queries the base interface of a device instance.
 
1844
 *
 
1845
 * The caller can use this to query other interfaces the device implements
 
1846
 * and use them to talk to the device.
 
1847
 *
 
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.
 
1855
 */
 
1856
VMMR3DECL(int) PDMR3QueryDevice(PVM pVM, const char *pszDevice, unsigned iInstance, PPDMIBASE *ppBase)
 
1857
{
 
1858
    LogFlow(("PDMR3DeviceQuery: pszDevice=%p:{%s} iInstance=%u ppBase=%p\n", pszDevice, pszDevice, iInstance, ppBase));
 
1859
 
 
1860
    /*
 
1861
     * Iterate registered devices looking for the device.
 
1862
     */
 
1863
    size_t cchDevice = strlen(pszDevice);
 
1864
    for (PPDMDEV pDev = pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
 
1865
    {
 
1866
        if (    pDev->cchName == cchDevice
 
1867
            &&  !memcmp(pDev->pReg->szName, pszDevice, cchDevice))
 
1868
        {
 
1869
            /*
 
1870
             * Iterate device instances.
 
1871
             */
 
1872
            for (PPDMDEVINS pDevIns = pDev->pInstances; pDevIns; pDevIns = pDevIns->Internal.s.pPerDeviceNextR3)
 
1873
            {
 
1874
                if (pDevIns->iInstance == iInstance)
 
1875
                {
 
1876
                    if (pDevIns->IBase.pfnQueryInterface)
 
1877
                    {
 
1878
                        *ppBase = &pDevIns->IBase;
 
1879
                        LogFlow(("PDMR3DeviceQuery: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
 
1880
                        return VINF_SUCCESS;
 
1881
                    }
 
1882
 
 
1883
                    LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NO_IBASE\n"));
 
1884
                    return VERR_PDM_DEVICE_INSTANCE_NO_IBASE;
 
1885
                }
 
1886
            }
 
1887
 
 
1888
            LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NOT_FOUND\n"));
 
1889
            return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND;
 
1890
        }
 
1891
    }
 
1892
 
 
1893
    LogFlow(("PDMR3QueryDevice: returns VERR_PDM_DEVICE_NOT_FOUND\n"));
 
1894
    return VERR_PDM_DEVICE_NOT_FOUND;
 
1895
}
 
1896
 
 
1897
 
 
1898
/**
 
1899
 * Queries the base interface of a device LUN.
 
1900
 *
 
1901
 * This differs from PDMR3QueryLun by that it returns the interface on the
 
1902
 * device and not the top level driver.
 
1903
 *
 
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.
 
1912
 */
 
1913
VMMR3DECL(int) PDMR3QueryDeviceLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
 
1914
{
 
1915
    LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
 
1916
             pszDevice, pszDevice, iInstance, iLun, ppBase));
 
1917
 
 
1918
    /*
 
1919
     * Find the LUN.
 
1920
     */
 
1921
    PPDMLUN pLun;
 
1922
    int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
 
1923
    if (RT_SUCCESS(rc))
 
1924
    {
 
1925
        *ppBase = pLun->pBase;
 
1926
        LogFlow(("PDMR3QueryDeviceLun: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
 
1927
        return VINF_SUCCESS;
 
1928
    }
 
1929
    LogFlow(("PDMR3QueryDeviceLun: returns %Rrc\n", rc));
 
1930
    return rc;
 
1931
}
 
1932
 
 
1933
 
 
1934
/**
 
1935
 * Query the interface of the top level driver on a LUN.
 
1936
 *
 
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.
 
1945
 */
 
1946
VMMR3DECL(int) PDMR3QueryLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
 
1947
{
 
1948
    LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
 
1949
             pszDevice, pszDevice, iInstance, iLun, ppBase));
 
1950
 
 
1951
    /*
 
1952
     * Find the LUN.
 
1953
     */
 
1954
    PPDMLUN pLun;
 
1955
    int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
 
1956
    if (RT_SUCCESS(rc))
 
1957
    {
 
1958
        if (pLun->pTop)
 
1959
        {
 
1960
            *ppBase = &pLun->pTop->IBase;
 
1961
            LogFlow(("PDMR3QueryLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
 
1962
            return VINF_SUCCESS;
 
1963
        }
 
1964
        rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
 
1965
    }
 
1966
    LogFlow(("PDMR3QueryLun: returns %Rrc\n", rc));
 
1967
    return rc;
 
1968
}
 
1969
 
 
1970
 
 
1971
/**
 
1972
 * Query the interface of a named driver on a LUN.
 
1973
 *
 
1974
 * If the driver appears more than once in the driver chain, the first instance
 
1975
 * is returned.
 
1976
 *
 
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.
 
1984
 *
 
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.
 
1987
 */
 
1988
VMMR3DECL(int) PDMR3QueryDriverOnLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, const char *pszDriver, PPPDMIBASE ppBase)
 
1989
{
 
1990
    LogFlow(("PDMR3QueryDriverOnLun: pszDevice=%p:{%s} iInstance=%u iLun=%u pszDriver=%p:{%s} ppBase=%p\n",
 
1991
             pszDevice, pszDevice, iInstance, iLun, pszDriver, pszDriver, ppBase));
 
1992
 
 
1993
    /*
 
1994
     * Find the LUN.
 
1995
     */
 
1996
    PPDMLUN pLun;
 
1997
    int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
 
1998
    if (RT_SUCCESS(rc))
 
1999
    {
 
2000
        if (pLun->pTop)
 
2001
        {
 
2002
            for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
 
2003
                if (!strcmp(pDrvIns->pReg->szName, pszDriver))
 
2004
                {
 
2005
                    *ppBase = &pDrvIns->IBase;
 
2006
                    LogFlow(("PDMR3QueryDriverOnLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
 
2007
                    return VINF_SUCCESS;
 
2008
 
 
2009
                }
 
2010
            rc = VERR_PDM_DRIVER_NOT_FOUND;
 
2011
        }
 
2012
        else
 
2013
            rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
 
2014
    }
 
2015
    LogFlow(("PDMR3QueryDriverOnLun: returns %Rrc\n", rc));
 
2016
    return rc;
 
2017
}
 
2018
 
 
2019
/**
 
2020
 * Executes pending DMA transfers.
 
2021
 * Forced Action handler.
 
2022
 *
 
2023
 * @param   pVM             VM handle.
 
2024
 */
 
2025
VMMR3DECL(void) PDMR3DmaRun(PVM pVM)
 
2026
{
 
2027
    /* Note! Not really SMP safe; restrict it to VCPU 0. */
 
2028
    if (VMMGetCpuId(pVM) != 0)
 
2029
        return;
 
2030
 
 
2031
    if (VM_FF_TESTANDCLEAR(pVM, VM_FF_PDM_DMA))
 
2032
    {
 
2033
        if (pVM->pdm.s.pDmac)
 
2034
        {
 
2035
            bool fMore = pVM->pdm.s.pDmac->Reg.pfnRun(pVM->pdm.s.pDmac->pDevIns);
 
2036
            if (fMore)
 
2037
                VM_FF_SET(pVM, VM_FF_PDM_DMA);
 
2038
        }
 
2039
    }
 
2040
}
 
2041
 
 
2042
 
 
2043
/**
 
2044
 * Service a VMMCALLRING3_PDM_LOCK call.
 
2045
 *
 
2046
 * @returns VBox status code.
 
2047
 * @param   pVM     The VM handle.
 
2048
 */
 
2049
VMMR3DECL(int) PDMR3LockCall(PVM pVM)
 
2050
{
 
2051
    return PDMR3CritSectEnterEx(&pVM->pdm.s.CritSect, true /* fHostCall */);
 
2052
}
 
2053
 
 
2054
 
 
2055
/**
 
2056
 * Registers the VMM device heap
 
2057
 *
 
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.
 
2063
 */
 
2064
VMMR3DECL(int) PDMR3RegisterVMMDevHeap(PVM pVM, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbSize)
 
2065
{
 
2066
    Assert(pVM->pdm.s.pvVMMDevHeap == NULL);
 
2067
 
 
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;
 
2074
}
 
2075
 
 
2076
 
 
2077
/**
 
2078
 * Unregisters the VMM device heap
 
2079
 *
 
2080
 * @returns VBox status code.
 
2081
 * @param   pVM             VM handle.
 
2082
 * @param   GCPhys          The physical address.
 
2083
 */
 
2084
VMMR3DECL(int) PDMR3UnregisterVMMDevHeap(PVM pVM, RTGCPHYS GCPhys)
 
2085
{
 
2086
    Assert(pVM->pdm.s.GCPhysVMMDevHeap == GCPhys);
 
2087
 
 
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;
 
2094
}
 
2095
 
 
2096
 
 
2097
/**
 
2098
 * Allocates memory from the VMM device heap
 
2099
 *
 
2100
 * @returns VBox status code.
 
2101
 * @param   pVM             VM handle.
 
2102
 * @param   cbSize          Allocation size.
 
2103
 * @param   pv              Ring-3 pointer. (out)
 
2104
 */
 
2105
VMMR3DECL(int) PDMR3VMMDevHeapAlloc(PVM pVM, unsigned cbSize, RTR3PTR *ppv)
 
2106
{
 
2107
#ifdef DEBUG_bird
 
2108
    if (!cbSize || cbSize > pVM->pdm.s.cbVMMDevHeapLeft)
 
2109
        return VERR_NO_MEMORY;
 
2110
#else
 
2111
    AssertReturn(cbSize && cbSize <= pVM->pdm.s.cbVMMDevHeapLeft, VERR_NO_MEMORY);
 
2112
#endif
 
2113
 
 
2114
    Log(("PDMR3VMMDevHeapAlloc %x\n", cbSize));
 
2115
 
 
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;
 
2120
}
 
2121
 
 
2122
 
 
2123
/**
 
2124
 * Frees memory from the VMM device heap
 
2125
 *
 
2126
 * @returns VBox status code.
 
2127
 * @param   pVM             VM handle.
 
2128
 * @param   pv              Ring-3 pointer.
 
2129
 */
 
2130
VMMR3DECL(int) PDMR3VMMDevHeapFree(PVM pVM, RTR3PTR pv)
 
2131
{
 
2132
    Log(("PDMR3VMMDevHeapFree %RHv\n", pv));
 
2133
 
 
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;
 
2137
}
 
2138