VirtualBox

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

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

Clear the flags so they don't get saved and trigger the release assertions in pdmR3LoadExec.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 54.1 KB
Line 
1/* $Id: PDM.cpp 24629 2009-11-13 10:06:48Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device Manager.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/** @page pg_pdm PDM - The Pluggable Device & Driver Manager
24 *
25 * VirtualBox is designed to be very configurable, i.e. the ability to select
26 * virtual devices and configure them uniquely for a VM. For this reason
27 * virtual devices are not statically linked with the VMM but loaded, linked and
28 * instantiated at runtime by PDM using the information found in the
29 * Configuration Manager (CFGM).
30 *
31 * While the chief purpose of PDM is to manager of devices their drivers, it
32 * also serves as somewhere to put usful things like cross context queues, cross
33 * context synchronization (like critsect), VM centric thread management,
34 * asynchronous I/O framework, and so on.
35 *
36 * @see grp_pdm
37 *
38 *
39 * @section sec_pdm_dev The Pluggable Devices
40 *
41 * Devices register themselves when the module containing them is loaded. PDM
42 * will call the entry point 'VBoxDevicesRegister' when loading a device module.
43 * The device module will then use the supplied callback table to check the VMM
44 * version and to register its devices. Each device have an unique (for the
45 * configured VM) name. The name is not only used in PDM but also in CFGM (to
46 * organize device and device instance settings) and by anyone who wants to talk
47 * to a specific device instance.
48 *
49 * When all device modules have been successfully loaded PDM will instantiate
50 * those devices which are configured for the VM. Note that a device may have
51 * more than one instance, see network adaptors for instance. When
52 * instantiating a device PDM provides device instance memory and a callback
53 * table (aka Device Helpers / DevHlp) with the VM APIs which the device
54 * instance is trusted with.
55 *
56 * Some devices are trusted devices, most are not. The trusted devices are an
57 * integrated part of the VM and can obtain the VM handle from their device
58 * instance handles, thus enabling them to call any VM api. Untrusted devices
59 * can only use the callbacks provided during device instantiation.
60 *
61 * The main purpose in having DevHlps rather than just giving all the devices
62 * the VM handle and let them call the internal VM APIs directly, is both to
63 * create a binary interface that can be supported accross releases and to
64 * create a barrier between devices and the VM. (The trusted / untrusted bit
65 * hasn't turned out to be of much use btw., but it's easy to maintain so there
66 * isn't any point in removing it.)
67 *
68 * A device can provide a ring-0 and/or a raw-mode context extension to improve
69 * the VM performance by handling exits and traps (respectively) without
70 * requiring context switches (to ring-3). Callbacks for MMIO and I/O ports can
71 * needs to be registered specifically for the additional contexts for this to
72 * make sense. Also, the device has to be trusted to be loaded into R0/RC
73 * because of the extra privilege it entails. Note that raw-mode code and data
74 * will be subject to relocation.
75 *
76 *
77 * @section sec_pdm_special_devs Special Devices
78 *
79 * Several kinds of devices interacts with the VMM and/or other device and PDM
80 * will work like a mediator for these. The typical pattern is that the device
81 * calls a special registration device helper with a set of callbacks, PDM
82 * responds by copying this and providing a pointer to a set helper callbacks
83 * for that particular kind of device. Unlike interfaces where the callback
84 * table pointer is used a 'this' pointer, these arrangements will use the
85 * device instance pointer (PPDMDEVINS) as a kind of 'this' pointer.
86 *
87 * For an example of this kind of setup, see the PIC. The PIC registers itself
88 * by calling PDMDEVHLPR3::pfnPICRegister. PDM saves the device instance,
89 * copies the callback tables (PDMPICREG), resolving the ring-0 and raw-mode
90 * addresses in the process, and hands back the pointer to a set of helper
91 * methods (PDMPICHLPR3). The PCI device then queries the ring-0 and raw-mode
92 * helpers using PDMPICHLPR3::pfnGetR0Helpers and PDMPICHLPR3::pfnGetRCHelpers.
93 * The PCI device repeates ths pfnGetRCHelpers call in it's relocation method
94 * since the address changes when RC is relocated.
95 *
96 * @see grp_pdm_device
97 *
98 *
99 * @section sec_pdm_usbdev The Pluggable USB Devices
100 *
101 * USB devices are handled a little bit differently than other devices. The
102 * general concepts wrt. pluggability are mostly the same, but the details
103 * varies. The registration entry point is 'VBoxUsbRegister', the device
104 * instance is PDMUSBINS and the callbacks helpers are different. Also, USB
105 * device are restricted to ring-3 and cannot have any ring-0 or raw-mode
106 * extensions (at least not yet).
107 *
108 * The way USB devices work differs greatly from other devices though since they
109 * aren't attaches directly to the PCI/ISA/whatever system buses but via a
110 * USB host control (OHCI, UHCI or EHCI). USB devices handles USB requests
111 * (URBs) and does not register I/O ports, MMIO ranges or PCI bus
112 * devices/functions.
113 *
114 * @see grp_pdm_usbdev
115 *
116 *
117 * @section sec_pdm_drv The Pluggable Drivers
118 *
119 * The VM devices are often accessing host hardware or OS facilities. For most
120 * devices these facilities can be abstracted in one or more levels. These
121 * abstractions are called drivers.
122 *
123 * For instance take a DVD/CD drive. This can be connected to a SCSI
124 * controller, an ATA controller or a SATA controller. The basics of the DVD/CD
125 * drive implementation remains the same - eject, insert, read, seek, and such.
126 * (For the scsi case, you might wanna speak SCSI directly to, but that can of
127 * course be fixed - see SCSI passthru.) So, it
128 * makes much sense to have a generic CD/DVD driver which implements this.
129 *
130 * Then the media 'inserted' into the DVD/CD drive can be a ISO image, or it can
131 * be read from a real CD or DVD drive (there are probably other custom formats
132 * someone could desire to read or construct too). So, it would make sense to
133 * have abstracted interfaces for dealing with this in a generic way so the
134 * cdrom unit doesn't have to implement it all. Thus we have created the
135 * CDROM/DVD media driver family.
136 *
137 * So, for this example the IDE controller #1 (i.e. secondary) will have
138 * the DVD/CD Driver attached to it's LUN #0 (master). When a media is mounted
139 * the DVD/CD Driver will have a ISO, HostDVD or RAW (media) Driver attached.
140 *
141 * It is possible to configure many levels of drivers inserting filters, loggers,
142 * or whatever you desire into the chain. We're using this for network sniffing
143 * for instance.
144 *
145 * The drivers are loaded in a similar manner to that of the device, namely by
146 * iterating a keyspace in CFGM, load the modules listed there and call
147 * 'VBoxDriversRegister' with a callback table.
148 *
149 * @see grp_pdm_driver
150 *
151 *
152 * @section sec_pdm_ifs Interfaces
153 *
154 * The pluggable drivers and devices exposes one standard interface (callback
155 * table) which is used to construct, destruct, attach, detach,( ++,) and query
156 * other interfaces. A device will query the interfaces required for it's
157 * operation during init and hotplug. PDM may query some interfaces during
158 * runtime mounting too.
159 *
160 * An interface here means a function table contained within the device or
161 * driver instance data. Its method are invoked with the function table pointer
162 * as the first argument and they will calculate the address of the device or
163 * driver instance data from it. (This is one of the aspects which *might* have
164 * been better done in C++.)
165 *
166 * @see grp_pdm_interfaces
167 *
168 *
169 * @section sec_pdm_utils Utilities
170 *
171 * As mentioned earlier, PDM is the location of any usful constrcts that doesn't
172 * quite fit into IPRT. The next subsections will discuss these.
173 *
174 * One thing these APIs all have in common is that resources will be associated
175 * with a device / driver and automatically freed after it has been destroyed if
176 * the destructor didn't do this.
177 *
178 *
179 * @subsection sec_pdm_async_completion Async I/O
180 *
181 * The PDM Async I/O API provides a somewhat platform agnostic interface for
182 * asynchronous I/O. For reasons of performance and complexcity this does not
183 * build upon any IPRT API.
184 *
185 * @todo more details.
186 *
187 * @see grp_pdm_async_completion
188 *
189 *
190 * @subsection sec_pdm_async_task Async Task - not implemented
191 *
192 * @todo implement and describe
193 *
194 * @see grp_pdm_async_task
195 *
196 *
197 * @subsection sec_pdm_critsect Critical Section
198 *
199 * The PDM Critical Section API is currently building on the IPRT API with the
200 * same name. It adds the posibility to use critical sections in ring-0 and
201 * raw-mode as well as in ring-3. There are certain restrictions on the RC and
202 * R0 usage though since we're not able to wait on it, nor wake up anyone that
203 * is waiting on it. These restrictions origins with the use of a ring-3 event
204 * semaphore. In a later incarnation we plan to replace the ring-3 event
205 * semaphore with a ring-0 one, thus enabling us to wake up waiters while
206 * exectuing in ring-0 and making the hardware assisted execution mode more
207 * efficient. (Raw-mode won't benefit much from this, naturally.)
208 *
209 * @see grp_pdm_critsect
210 *
211 *
212 * @subsection sec_pdm_queue Queue
213 *
214 * The PDM Queue API is for queuing one or more tasks for later consumption in
215 * ring-3 by EMT, and optinally forcing a delayed or ASAP return to ring-3. The
216 * queues can also be run on a timer basis as an alternative to the ASAP thing.
217 * The queue will be flushed at forced action time.
218 *
219 * A queue can also be used by another thread (a I/O worker for instance) to
220 * send work / events over to the EMT.
221 *
222 * @see grp_pdm_queue
223 *
224 *
225 * @subsection sec_pdm_task Task - not implemented yet
226 *
227 * The PDM Task API is for flagging a task for execution at a later point when
228 * we're back in ring-3, optionally forcing the ring-3 return to happen ASAP.
229 * As you can see the concept is similar to queues only simpler.
230 *
231 * A task can also be scheduled by another thread (a I/O worker for instance) as
232 * a mean of getting something done in EMT.
233 *
234 * @see grp_pdm_task
235 *
236 *
237 * @subsection sec_pdm_thread Thread
238 *
239 * The PDM Thread API is there to help devices and drivers manage their threads
240 * correctly wrt. power on, suspend, resume, power off and destruction.
241 *
242 * The general usage pattern for threads in the employ of devices and drivers is
243 * that they shuffle data or requests while the VM is running and stop doing
244 * this when the VM is paused or powered down. Rogue threads running while the
245 * VM is paused can cause the state to change during saving or have other
246 * unwanted side effects. The PDM Threads API ensures that this won't happen.
247 *
248 * @see grp_pdm_thread
249 *
250 */
251
252
253/*******************************************************************************
254* Header Files *
255*******************************************************************************/
256#define LOG_GROUP LOG_GROUP_PDM
257#include "PDMInternal.h"
258#include <VBox/pdm.h>
259#include <VBox/mm.h>
260#include <VBox/pgm.h>
261#include <VBox/ssm.h>
262#include <VBox/vm.h>
263#include <VBox/uvm.h>
264#include <VBox/vmm.h>
265#include <VBox/param.h>
266#include <VBox/err.h>
267#include <VBox/sup.h>
268
269#include <VBox/log.h>
270#include <iprt/asm.h>
271#include <iprt/assert.h>
272#include <iprt/alloc.h>
273#include <iprt/ldr.h>
274#include <iprt/path.h>
275#include <iprt/string.h>
276
277
278/*******************************************************************************
279* Defined Constants And Macros *
280*******************************************************************************/
281/** The PDM saved state version. */
282#define PDM_SAVED_STATE_VERSION 4
283#define PDM_SAVED_STATE_VERSION_PRE_NMI_FF 3
284
285
286/*******************************************************************************
287* Internal Functions *
288*******************************************************************************/
289static DECLCALLBACK(int) pdmR3LiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass);
290static DECLCALLBACK(int) pdmR3SaveExec(PVM pVM, PSSMHANDLE pSSM);
291static DECLCALLBACK(int) pdmR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
292static DECLCALLBACK(int) pdmR3LoadPrep(PVM pVM, PSSMHANDLE pSSM);
293
294
295
296/**
297 * Initializes the PDM part of the UVM.
298 *
299 * This doesn't really do much right now but has to be here for the sake
300 * of completeness.
301 *
302 * @returns VBox status code.
303 * @param pUVM Pointer to the user mode VM structure.
304 */
305VMMR3DECL(int) PDMR3InitUVM(PUVM pUVM)
306{
307 AssertCompile(sizeof(pUVM->pdm.s) <= sizeof(pUVM->pdm.padding));
308 AssertRelease(sizeof(pUVM->pdm.s) <= sizeof(pUVM->pdm.padding));
309 pUVM->pdm.s.pModules = NULL;
310 return VINF_SUCCESS;
311}
312
313
314/**
315 * Initializes the PDM.
316 *
317 * @returns VBox status code.
318 * @param pVM The VM to operate on.
319 */
320VMMR3DECL(int) PDMR3Init(PVM pVM)
321{
322 LogFlow(("PDMR3Init\n"));
323
324 /*
325 * Assert alignment and sizes.
326 */
327 AssertRelease(!(RT_OFFSETOF(VM, pdm.s) & 31));
328 AssertRelease(sizeof(pVM->pdm.s) <= sizeof(pVM->pdm.padding));
329 AssertCompileMemberAlignment(PDM, CritSect, sizeof(uintptr_t));
330 /*
331 * Init the structure.
332 */
333 pVM->pdm.s.offVM = RT_OFFSETOF(VM, pdm.s);
334 pVM->pdm.s.GCPhysVMMDevHeap = NIL_RTGCPHYS;
335
336 /*
337 * Initialize sub compontents.
338 */
339 int rc = RTCritSectInit(&pVM->pdm.s.MiscCritSect);
340 if (RT_SUCCESS(rc))
341 rc = pdmR3CritSectInit(pVM);
342 if (RT_SUCCESS(rc))
343 rc = PDMR3CritSectInit(pVM, &pVM->pdm.s.CritSect, "PDM");
344 if (RT_SUCCESS(rc))
345 rc = pdmR3LdrInitU(pVM->pUVM);
346#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
347 if (RT_SUCCESS(rc))
348 rc = pdmR3AsyncCompletionInit(pVM);
349#endif
350 if (RT_SUCCESS(rc))
351 rc = pdmR3DrvInit(pVM);
352 if (RT_SUCCESS(rc))
353 rc = pdmR3DevInit(pVM);
354 if (RT_SUCCESS(rc))
355 {
356 /*
357 * Register the saved state data unit.
358 */
359 rc = SSMR3RegisterInternal(pVM, "pdm", 1, PDM_SAVED_STATE_VERSION, 128,
360 NULL, pdmR3LiveExec, NULL,
361 NULL, pdmR3SaveExec, NULL,
362 pdmR3LoadPrep, pdmR3LoadExec, NULL);
363 if (RT_SUCCESS(rc))
364 {
365 LogFlow(("PDM: Successfully initialized\n"));
366 return rc;
367 }
368 }
369
370 /*
371 * Cleanup and return failure.
372 */
373 PDMR3Term(pVM);
374 LogFlow(("PDMR3Init: returns %Rrc\n", rc));
375 return rc;
376}
377
378
379/**
380 * Applies relocations to data and code managed by this
381 * component. This function will be called at init and
382 * whenever the VMM need to relocate it self inside the GC.
383 *
384 * @param pVM VM handle.
385 * @param offDelta Relocation delta relative to old location.
386 * @remark The loader subcomponent is relocated by PDMR3LdrRelocate() very
387 * early in the relocation phase.
388 */
389VMMR3DECL(void) PDMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
390{
391 LogFlow(("PDMR3Relocate\n"));
392
393 /*
394 * Queues.
395 */
396 pdmR3QueueRelocate(pVM, offDelta);
397 pVM->pdm.s.pDevHlpQueueRC = PDMQueueRCPtr(pVM->pdm.s.pDevHlpQueueR3);
398
399 /*
400 * Critical sections.
401 */
402 pdmR3CritSectRelocate(pVM);
403
404 /*
405 * The registered PIC.
406 */
407 if (pVM->pdm.s.Pic.pDevInsRC)
408 {
409 pVM->pdm.s.Pic.pDevInsRC += offDelta;
410 pVM->pdm.s.Pic.pfnSetIrqRC += offDelta;
411 pVM->pdm.s.Pic.pfnGetInterruptRC += offDelta;
412 }
413
414 /*
415 * The registered APIC.
416 */
417 if (pVM->pdm.s.Apic.pDevInsRC)
418 {
419 pVM->pdm.s.Apic.pDevInsRC += offDelta;
420 pVM->pdm.s.Apic.pfnGetInterruptRC += offDelta;
421 pVM->pdm.s.Apic.pfnSetBaseRC += offDelta;
422 pVM->pdm.s.Apic.pfnGetBaseRC += offDelta;
423 pVM->pdm.s.Apic.pfnSetTPRRC += offDelta;
424 pVM->pdm.s.Apic.pfnGetTPRRC += offDelta;
425 pVM->pdm.s.Apic.pfnBusDeliverRC += offDelta;
426 if (pVM->pdm.s.Apic.pfnLocalInterruptRC)
427 pVM->pdm.s.Apic.pfnLocalInterruptRC += offDelta;
428 pVM->pdm.s.Apic.pfnWriteMSRRC += offDelta;
429 pVM->pdm.s.Apic.pfnReadMSRRC += offDelta;
430 }
431
432 /*
433 * The registered I/O APIC.
434 */
435 if (pVM->pdm.s.IoApic.pDevInsRC)
436 {
437 pVM->pdm.s.IoApic.pDevInsRC += offDelta;
438 pVM->pdm.s.IoApic.pfnSetIrqRC += offDelta;
439 }
440
441 /*
442 * The register PCI Buses.
443 */
444 for (unsigned i = 0; i < RT_ELEMENTS(pVM->pdm.s.aPciBuses); i++)
445 {
446 if (pVM->pdm.s.aPciBuses[i].pDevInsRC)
447 {
448 pVM->pdm.s.aPciBuses[i].pDevInsRC += offDelta;
449 pVM->pdm.s.aPciBuses[i].pfnSetIrqRC += offDelta;
450 }
451 }
452
453 /*
454 * Devices.
455 */
456 PCPDMDEVHLPRC pDevHlpRC;
457 int rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDevHlp", &pDevHlpRC);
458 AssertReleaseMsgRC(rc, ("rc=%Rrc when resolving g_pdmRCDevHlp\n", rc));
459 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
460 {
461 if (pDevIns->pDevReg->fFlags & PDM_DEVREG_FLAGS_RC)
462 {
463 pDevIns->pDevHlpRC = pDevHlpRC;
464 pDevIns->pvInstanceDataRC = MMHyperR3ToRC(pVM, pDevIns->pvInstanceDataR3);
465 pDevIns->Internal.s.pVMRC = pVM->pVMRC;
466 if (pDevIns->Internal.s.pPciBusR3)
467 pDevIns->Internal.s.pPciBusRC = MMHyperR3ToRC(pVM, pDevIns->Internal.s.pPciBusR3);
468 if (pDevIns->Internal.s.pPciDeviceR3)
469 pDevIns->Internal.s.pPciDeviceRC = MMHyperR3ToRC(pVM, pDevIns->Internal.s.pPciDeviceR3);
470 if (pDevIns->pDevReg->pfnRelocate)
471 {
472 LogFlow(("PDMR3Relocate: Relocating device '%s'/%d\n",
473 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
474 pDevIns->pDevReg->pfnRelocate(pDevIns, offDelta);
475 }
476 }
477 }
478}
479
480
481/**
482 * Worker for pdmR3Term that terminates a LUN chain.
483 *
484 * @param pVM Pointer to the shared VM structure.
485 * @param pLun The head of the chain.
486 * @param pszDevice The name of the device (for logging).
487 * @param iInstance The device instance number (for logging).
488 */
489static void pdmR3TermLuns(PVM pVM, PPDMLUN pLun, const char *pszDevice, unsigned iInstance)
490{
491 for (; pLun; pLun = pLun->pNext)
492 {
493 /*
494 * Destroy them one at a time from the bottom up.
495 * (The serial device/drivers depends on this - bad.)
496 */
497 PPDMDRVINS pDrvIns = pLun->pBottom;
498 pLun->pBottom = pLun->pTop = NULL;
499 while (pDrvIns)
500 {
501 PPDMDRVINS pDrvNext = pDrvIns->Internal.s.pUp;
502
503 if (pDrvIns->pDrvReg->pfnDestruct)
504 {
505 LogFlow(("pdmR3DevTerm: Destroying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
506 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pszDevice, iInstance));
507 pDrvIns->pDrvReg->pfnDestruct(pDrvIns);
508 }
509
510 TMR3TimerDestroyDriver(pVM, pDrvIns);
511 //PDMR3QueueDestroyDriver(pVM, pDrvIns);
512 //pdmR3ThreadDestroyDriver(pVM, pDrvIns);
513 SSMR3DeregisterDriver(pVM, pDrvIns, NULL, 0);
514
515 pDrvIns = pDrvNext;
516 }
517 }
518}
519
520
521/**
522 * Terminates the PDM.
523 *
524 * Termination means cleaning up and freeing all resources,
525 * the VM it self is at this point powered off or suspended.
526 *
527 * @returns VBox status code.
528 * @param pVM The VM to operate on.
529 */
530VMMR3DECL(int) PDMR3Term(PVM pVM)
531{
532 LogFlow(("PDMR3Term:\n"));
533 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
534
535 /*
536 * Iterate the device instances and attach drivers, doing
537 * relevant destruction processing.
538 *
539 * N.B. There is no need to mess around freeing memory allocated
540 * from any MM heap since MM will do that in its Term function.
541 */
542 /* usb ones first. */
543 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
544 {
545 pdmR3TermLuns(pVM, pUsbIns->Internal.s.pLuns, pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance);
546
547 if (pUsbIns->pUsbReg->pfnDestruct)
548 {
549 LogFlow(("pdmR3DevTerm: Destroying - device '%s'/%d\n",
550 pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
551 pUsbIns->pUsbReg->pfnDestruct(pUsbIns);
552 }
553
554 //TMR3TimerDestroyUsb(pVM, pUsbIns);
555 //SSMR3DeregisterUsb(pVM, pUsbIns, NULL, 0);
556 pdmR3ThreadDestroyUsb(pVM, pUsbIns);
557 }
558
559 /* then the 'normal' ones. */
560 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
561 {
562 pdmR3TermLuns(pVM, pDevIns->Internal.s.pLunsR3, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance);
563
564 if (pDevIns->pDevReg->pfnDestruct)
565 {
566 LogFlow(("pdmR3DevTerm: Destroying - device '%s'/%d\n",
567 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
568 pDevIns->pDevReg->pfnDestruct(pDevIns);
569 }
570
571 TMR3TimerDestroyDevice(pVM, pDevIns);
572 //SSMR3DeregisterDriver(pVM, pDevIns, NULL, 0);
573 pdmR3CritSectDeleteDevice(pVM, pDevIns);
574 //pdmR3ThreadDestroyDevice(pVM, pDevIns);
575 //PDMR3QueueDestroyDevice(pVM, pDevIns);
576 PGMR3PhysMMIO2Deregister(pVM, pDevIns, UINT32_MAX);
577 }
578
579 /*
580 * Destroy all threads.
581 */
582 pdmR3ThreadDestroyAll(pVM);
583
584#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
585 /*
586 * Free async completion managers.
587 */
588 pdmR3AsyncCompletionTerm(pVM);
589#endif
590
591 /*
592 * Free modules.
593 */
594 pdmR3LdrTermU(pVM->pUVM);
595
596 /*
597 * Destroy the PDM lock.
598 */
599 PDMR3CritSectDelete(&pVM->pdm.s.CritSect);
600 /* The MiscCritSect is deleted by PDMR3CritSectTerm. */
601
602 LogFlow(("PDMR3Term: returns %Rrc\n", VINF_SUCCESS));
603 return VINF_SUCCESS;
604}
605
606
607/**
608 * Terminates the PDM part of the UVM.
609 *
610 * This will unload any modules left behind.
611 *
612 * @param pUVM Pointer to the user mode VM structure.
613 */
614VMMR3DECL(void) PDMR3TermUVM(PUVM pUVM)
615{
616 /*
617 * In the normal cause of events we will now call pdmR3LdrTermU for
618 * the second time. In the case of init failure however, this might
619 * the first time, which is why we do it.
620 */
621 pdmR3LdrTermU(pUVM);
622}
623
624
625/**
626 * Bits that are saved in pass 0 and in the final pass.
627 *
628 * @param pVM The VM handle.
629 * @param pSSM The saved state handle.
630 */
631static void pdmR3SaveBoth(PVM pVM, PSSMHANDLE pSSM)
632{
633 /*
634 * Save the list of device instances so we can check that they're all still
635 * there when we load the state and that nothing new has been added.
636 */
637 uint32_t i = 0;
638 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3, i++)
639 {
640 SSMR3PutU32(pSSM, i);
641 SSMR3PutStrZ(pSSM, pDevIns->pDevReg->szDeviceName);
642 SSMR3PutU32(pSSM, pDevIns->iInstance);
643 }
644 SSMR3PutU32(pSSM, UINT32_MAX); /* terminator */
645}
646
647
648/**
649 * Live save.
650 *
651 * @returns VBox status code.
652 * @param pVM The VM handle.
653 * @param pSSM The saved state handle.
654 * @param uPass The pass.
655 */
656static DECLCALLBACK(int) pdmR3LiveExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass)
657{
658 LogFlow(("pdmR3LiveExec:\n"));
659 AssertReturn(uPass == 0, VERR_INTERNAL_ERROR_4);
660 pdmR3SaveBoth(pVM, pSSM);
661 return VINF_SSM_DONT_CALL_AGAIN;
662}
663
664
665/**
666 * Execute state save operation.
667 *
668 * @returns VBox status code.
669 * @param pVM The VM handle.
670 * @param pSSM The saved state handle.
671 */
672static DECLCALLBACK(int) pdmR3SaveExec(PVM pVM, PSSMHANDLE pSSM)
673{
674 LogFlow(("pdmR3SaveExec:\n"));
675
676 /*
677 * Save interrupt and DMA states.
678 */
679 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
680 {
681 PVMCPU pVCpu = &pVM->aCpus[idCpu];
682 SSMR3PutUInt(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC));
683 SSMR3PutUInt(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC));
684 SSMR3PutUInt(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_NMI));
685 SSMR3PutUInt(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_SMI));
686
687 /* Clear the flags so they don't get saved and trigger the release assertions in pdmR3LoadExec. */
688 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
689 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
690 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
691 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_SMI);
692 }
693 SSMR3PutUInt(pSSM, VM_FF_ISSET(pVM, VM_FF_PDM_DMA));
694
695 pdmR3SaveBoth(pVM, pSSM);
696 return VINF_SUCCESS;
697}
698
699
700/**
701 * Prepare state load operation.
702 *
703 * This will dispatch pending operations and clear the FFs governed by PDM and its devices.
704 *
705 * @returns VBox status code.
706 * @param pVM The VM handle.
707 * @param pSSM The SSM handle.
708 */
709static DECLCALLBACK(int) pdmR3LoadPrep(PVM pVM, PSSMHANDLE pSSM)
710{
711 LogFlow(("pdmR3LoadPrep: %s%s\n",
712 VM_FF_ISSET(pVM, VM_FF_PDM_QUEUES) ? " VM_FF_PDM_QUEUES" : "",
713 VM_FF_ISSET(pVM, VM_FF_PDM_DMA) ? " VM_FF_PDM_DMA" : ""));
714#ifdef LOG_ENABLED
715 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
716 {
717 PVMCPU pVCpu = &pVM->aCpus[idCpu];
718 LogFlow(("pdmR3LoadPrep: VCPU %u %s%s\n", idCpu,
719 VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC) ? " VMCPU_FF_INTERRUPT_APIC" : "",
720 VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC) ? " VMCPU_FF_INTERRUPT_PIC" : ""));
721 }
722#endif
723
724 /*
725 * In case there is work pending that will raise an interrupt,
726 * start a DMA transfer, or release a lock. (unlikely)
727 */
728 if (VM_FF_ISSET(pVM, VM_FF_PDM_QUEUES))
729 PDMR3QueueFlushAll(pVM);
730
731 /* Clear the FFs. */
732 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
733 {
734 PVMCPU pVCpu = &pVM->aCpus[idCpu];
735 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
736 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
737 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
738 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_SMI);
739 }
740 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
741
742 return VINF_SUCCESS;
743}
744
745
746/**
747 * Execute state load operation.
748 *
749 * @returns VBox status code.
750 * @param pVM VM Handle.
751 * @param pSSM SSM operation handle.
752 * @param uVersion Data layout version.
753 * @param uPass The data pass.
754 */
755static DECLCALLBACK(int) pdmR3LoadExec(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
756{
757 int rc;
758
759 LogFlow(("pdmR3LoadExec: uPass=%#x\n", uPass));
760
761 /*
762 * Validate version.
763 */
764 if ( uVersion != PDM_SAVED_STATE_VERSION
765 && uVersion != PDM_SAVED_STATE_VERSION_PRE_NMI_FF)
766 {
767 AssertMsgFailed(("Invalid version uVersion=%d!\n", uVersion));
768 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
769 }
770
771 if (uPass == SSM_PASS_FINAL)
772 {
773 /*
774 * Load the interrupt and DMA states.
775 */
776 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
777 {
778 PVMCPU pVCpu = &pVM->aCpus[idCpu];
779
780 /* APIC interrupt */
781 RTUINT fInterruptPending = 0;
782 rc = SSMR3GetUInt(pSSM, &fInterruptPending);
783 if (RT_FAILURE(rc))
784 return rc;
785 if (fInterruptPending & ~1)
786 {
787 AssertMsgFailed(("fInterruptPending=%#x (APIC)\n", fInterruptPending));
788 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
789 }
790 AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC));
791 if (fInterruptPending)
792 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC);
793
794 /* PIC interrupt */
795 fInterruptPending = 0;
796 rc = SSMR3GetUInt(pSSM, &fInterruptPending);
797 if (RT_FAILURE(rc))
798 return rc;
799 if (fInterruptPending & ~1)
800 {
801 AssertMsgFailed(("fInterruptPending=%#x (PIC)\n", fInterruptPending));
802 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
803 }
804 AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC));
805 if (fInterruptPending)
806 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC);
807
808 if (uVersion > PDM_SAVED_STATE_VERSION_PRE_NMI_FF)
809 {
810 /* NMI interrupt */
811 RTUINT fInterruptPending = 0;
812 rc = SSMR3GetUInt(pSSM, &fInterruptPending);
813 if (RT_FAILURE(rc))
814 return rc;
815 if (fInterruptPending & ~1)
816 {
817 AssertMsgFailed(("fInterruptPending=%#x (NMI)\n", fInterruptPending));
818 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
819 }
820 AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_NMI));
821 if (fInterruptPending)
822 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI);
823
824 /* SMI interrupt */
825 fInterruptPending = 0;
826 rc = SSMR3GetUInt(pSSM, &fInterruptPending);
827 if (RT_FAILURE(rc))
828 return rc;
829 if (fInterruptPending & ~1)
830 {
831 AssertMsgFailed(("fInterruptPending=%#x (SMI)\n", fInterruptPending));
832 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
833 }
834 AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_SMI));
835 if (fInterruptPending)
836 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_SMI);
837 }
838 }
839
840 /* DMA pending */
841 RTUINT fDMAPending = 0;
842 rc = SSMR3GetUInt(pSSM, &fDMAPending);
843 if (RT_FAILURE(rc))
844 return rc;
845 if (fDMAPending & ~1)
846 {
847 AssertMsgFailed(("fDMAPending=%#x\n", fDMAPending));
848 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
849 }
850 if (fDMAPending)
851 VM_FF_SET(pVM, VM_FF_PDM_DMA);
852 Log(("pdmR3LoadExec: VM_FF_PDM_DMA=%RTbool\n", VM_FF_ISSET(pVM, VM_FF_PDM_DMA)));
853 }
854
855 /*
856 * Load the list of devices and verify that they are all there.
857 */
858 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
859 pDevIns->Internal.s.fIntFlags &= ~PDMDEVINSINT_FLAGS_FOUND;
860
861 for (uint32_t i = 0; ; i++)
862 {
863 /* Get the sequence number / terminator. */
864 uint32_t u32Sep;
865 int rc = SSMR3GetU32(pSSM, &u32Sep);
866 if (RT_FAILURE(rc))
867 return rc;
868 if (u32Sep == UINT32_MAX)
869 break;
870 if (u32Sep != i)
871 AssertMsgFailedReturn(("Out of seqence. u32Sep=%#x i=%#x\n", u32Sep, i), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
872
873 /* Get the name and instance number. */
874 char szDeviceName[RT_SIZEOFMEMB(PDMDEVREG, szDeviceName)];
875 rc = SSMR3GetStrZ(pSSM, szDeviceName, sizeof(szDeviceName));
876 if (RT_FAILURE(rc))
877 return rc;
878 RTUINT iInstance;
879 rc = SSMR3GetUInt(pSSM, &iInstance);
880 if (RT_FAILURE(rc))
881 return rc;
882
883 /* Try locate it. */
884 PPDMDEVINS pDevIns;
885 for (pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
886 if ( !strcmp(szDeviceName, pDevIns->pDevReg->szDeviceName)
887 && pDevIns->iInstance == iInstance)
888 {
889 AssertLogRelMsgReturn(!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_FOUND),
890 ("%s/#%u\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance),
891 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
892 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_FOUND;
893 break;
894 }
895 if (!pDevIns)
896 {
897 LogRel(("Device '%s'/%d not found in current config\n", szDeviceName, iInstance));
898 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
899 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device '%s'/%d not found in current config"), szDeviceName, iInstance);
900 }
901 }
902
903 /*
904 * Check that no additional devices were configured.
905 */
906 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
907 if (!(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_FOUND))
908 {
909 LogRel(("Device '%s'/%d not found in the saved state\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
910 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
911 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device '%s'/%d not found in the saved state"),
912 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance);
913 }
914
915 return VINF_SUCCESS;
916}
917
918
919/**
920 * This function will notify all the devices and their
921 * attached drivers about the VM now being powered on.
922 *
923 * @param pVM VM Handle.
924 */
925VMMR3DECL(void) PDMR3PowerOn(PVM pVM)
926{
927 LogFlow(("PDMR3PowerOn:\n"));
928
929 /*
930 * Iterate the device instances.
931 * The attached drivers are processed first.
932 */
933 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
934 {
935 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
936 /** @todo Inverse the order here? */
937 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
938 if (pDrvIns->pDrvReg->pfnPowerOn)
939 {
940 LogFlow(("PDMR3PowerOn: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
941 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
942 pDrvIns->pDrvReg->pfnPowerOn(pDrvIns);
943 }
944
945 if (pDevIns->pDevReg->pfnPowerOn)
946 {
947 LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n",
948 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
949 pDevIns->pDevReg->pfnPowerOn(pDevIns);
950 }
951 }
952
953#ifdef VBOX_WITH_USB
954 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
955 {
956 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
957 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
958 if (pDrvIns->pDrvReg->pfnPowerOn)
959 {
960 LogFlow(("PDMR3PowerOn: Notifying - driver '%s'/%d on LUN#%d of usb device '%s'/%d\n",
961 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
962 pDrvIns->pDrvReg->pfnPowerOn(pDrvIns);
963 }
964
965 if (pUsbIns->pUsbReg->pfnVMPowerOn)
966 {
967 LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n",
968 pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
969 pUsbIns->pUsbReg->pfnVMPowerOn(pUsbIns);
970 }
971 }
972#endif
973
974 /*
975 * Resume all threads.
976 */
977 pdmR3ThreadResumeAll(pVM);
978
979 LogFlow(("PDMR3PowerOn: returns void\n"));
980}
981
982
983
984
985/**
986 * This function will notify all the devices and their
987 * attached drivers about the VM now being reset.
988 *
989 * @param pVM VM Handle.
990 */
991VMMR3DECL(void) PDMR3Reset(PVM pVM)
992{
993 LogFlow(("PDMR3Reset:\n"));
994
995 /*
996 * Clear all pending interrupts and DMA operations.
997 */
998 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
999 {
1000 PVMCPU pVCpu = &pVM->aCpus[idCpu];
1001 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
1002 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
1003 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
1004 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_SMI);
1005 }
1006 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
1007
1008 /*
1009 * Iterate the device instances.
1010 * The attached drivers are processed first.
1011 */
1012 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1013 {
1014 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1015 /** @todo Inverse the order here? */
1016 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1017 if (pDrvIns->pDrvReg->pfnReset)
1018 {
1019 LogFlow(("PDMR3Reset: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1020 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1021 pDrvIns->pDrvReg->pfnReset(pDrvIns);
1022 }
1023
1024 if (pDevIns->pDevReg->pfnReset)
1025 {
1026 LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n",
1027 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1028 pDevIns->pDevReg->pfnReset(pDevIns);
1029 }
1030 }
1031
1032#ifdef VBOX_WITH_USB
1033 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1034 {
1035 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1036 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1037 if (pDrvIns->pDrvReg->pfnReset)
1038 {
1039 LogFlow(("PDMR3Reset: Notifying - driver '%s'/%d on LUN#%d of usb device '%s'/%d\n",
1040 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
1041 pDrvIns->pDrvReg->pfnReset(pDrvIns);
1042 }
1043
1044 if (pUsbIns->pUsbReg->pfnVMReset)
1045 {
1046 LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n",
1047 pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
1048 pUsbIns->pUsbReg->pfnVMReset(pUsbIns);
1049 }
1050 }
1051#endif
1052
1053 LogFlow(("PDMR3Reset: returns void\n"));
1054}
1055
1056
1057/**
1058 * This function will notify all the devices and their
1059 * attached drivers about the VM now being reset.
1060 *
1061 * @param pVM VM Handle.
1062 * @thread EMT(0)
1063 */
1064VMMR3DECL(void) PDMR3Suspend(PVM pVM)
1065{
1066 LogFlow(("PDMR3Suspend:\n"));
1067 VM_ASSERT_EMT0(pVM);
1068
1069 /*
1070 * Iterate the device instances.
1071 * The attached drivers are processed first.
1072 */
1073 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1074 {
1075 /*
1076 * Some devices need to be notified first that the VM is suspended to ensure that that there are no pending
1077 * requests from the guest which are still processed. Calling the drivers before these requests are finished
1078 * might lead to errors otherwise. One example is the SATA controller which might still have I/O requests
1079 * pending. But DrvVD sets the files into readonly mode and every request will fail then.
1080 */
1081 if (pDevIns->pDevReg->pfnSuspend && (pDevIns->pDevReg->fFlags & PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION))
1082 {
1083 LogFlow(("PDMR3Suspend: Notifying - device '%s'/%d\n",
1084 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1085 pDevIns->pDevReg->pfnSuspend(pDevIns);
1086 }
1087
1088 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1089 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1090 if (pDrvIns->pDrvReg->pfnSuspend)
1091 {
1092 LogFlow(("PDMR3Suspend: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1093 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1094 pDrvIns->pDrvReg->pfnSuspend(pDrvIns);
1095 }
1096
1097 /* Don't call the suspend notification again if it was already called. */
1098 if (pDevIns->pDevReg->pfnSuspend && !(pDevIns->pDevReg->fFlags & PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION))
1099 {
1100 LogFlow(("PDMR3Suspend: Notifying - device '%s'/%d\n",
1101 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1102 pDevIns->pDevReg->pfnSuspend(pDevIns);
1103 }
1104 }
1105
1106#ifdef VBOX_WITH_USB
1107 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1108 {
1109 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1110 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1111 if (pDrvIns->pDrvReg->pfnSuspend)
1112 {
1113 LogFlow(("PDMR3Suspend: Notifying - driver '%s'/%d on LUN#%d of usb device '%s'/%d\n",
1114 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
1115 pDrvIns->pDrvReg->pfnSuspend(pDrvIns);
1116 }
1117
1118 if (pUsbIns->pUsbReg->pfnVMSuspend)
1119 {
1120 LogFlow(("PDMR3Suspend: Notifying - device '%s'/%d\n",
1121 pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
1122 pUsbIns->pUsbReg->pfnVMSuspend(pUsbIns);
1123 }
1124 }
1125#endif
1126
1127 /*
1128 * Suspend all threads.
1129 */
1130 pdmR3ThreadSuspendAll(pVM);
1131
1132 LogFlow(("PDMR3Suspend: returns void\n"));
1133}
1134
1135
1136/**
1137 * This function will notify all the devices and their
1138 * attached drivers about the VM now being resumed.
1139 *
1140 * @param pVM VM Handle.
1141 */
1142VMMR3DECL(void) PDMR3Resume(PVM pVM)
1143{
1144 LogFlow(("PDMR3Resume:\n"));
1145
1146 /*
1147 * Iterate the device instances.
1148 * The attached drivers are processed first.
1149 */
1150 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1151 {
1152 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1153 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1154 if (pDrvIns->pDrvReg->pfnResume)
1155 {
1156 LogFlow(("PDMR3Resume: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1157 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1158 pDrvIns->pDrvReg->pfnResume(pDrvIns);
1159 }
1160
1161 if (pDevIns->pDevReg->pfnResume)
1162 {
1163 LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n",
1164 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1165 pDevIns->pDevReg->pfnResume(pDevIns);
1166 }
1167 }
1168
1169#ifdef VBOX_WITH_USB
1170 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1171 {
1172 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1173 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1174 if (pDrvIns->pDrvReg->pfnResume)
1175 {
1176 LogFlow(("PDMR3Resume: Notifying - driver '%s'/%d on LUN#%d of usb device '%s'/%d\n",
1177 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
1178 pDrvIns->pDrvReg->pfnResume(pDrvIns);
1179 }
1180
1181 if (pUsbIns->pUsbReg->pfnVMResume)
1182 {
1183 LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n",
1184 pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
1185 pUsbIns->pUsbReg->pfnVMResume(pUsbIns);
1186 }
1187 }
1188#endif
1189
1190 /*
1191 * Resume all threads.
1192 */
1193 pdmR3ThreadResumeAll(pVM);
1194
1195 LogFlow(("PDMR3Resume: returns void\n"));
1196}
1197
1198
1199/**
1200 * This function will notify all the devices and their
1201 * attached drivers about the VM being powered off.
1202 *
1203 * @param pVM VM Handle.
1204 */
1205VMMR3DECL(void) PDMR3PowerOff(PVM pVM)
1206{
1207 LogFlow(("PDMR3PowerOff:\n"));
1208
1209 /*
1210 * Iterate the device instances.
1211 * The attached drivers are processed first.
1212 */
1213 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1214 {
1215
1216 if (pDevIns->pDevReg->pfnPowerOff && (pDevIns->pDevReg->fFlags & PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION))
1217 {
1218 LogFlow(("PDMR3PowerOff: Notifying - device '%s'/%d\n",
1219 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1220 pDevIns->pDevReg->pfnPowerOff(pDevIns);
1221 }
1222
1223 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1224 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1225 if (pDrvIns->pDrvReg->pfnPowerOff)
1226 {
1227 LogFlow(("PDMR3PowerOff: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1228 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1229 pDrvIns->pDrvReg->pfnPowerOff(pDrvIns);
1230 }
1231
1232 if (pDevIns->pDevReg->pfnPowerOff && !(pDevIns->pDevReg->fFlags & PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION))
1233 {
1234 LogFlow(("PDMR3PowerOff: Notifying - device '%s'/%d\n",
1235 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1236 pDevIns->pDevReg->pfnPowerOff(pDevIns);
1237 }
1238 }
1239
1240#ifdef VBOX_WITH_USB
1241 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1242 {
1243 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1244 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1245 if (pDrvIns->pDrvReg->pfnPowerOff)
1246 {
1247 LogFlow(("PDMR3PowerOff: Notifying - driver '%s'/%d on LUN#%d of usb device '%s'/%d\n",
1248 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
1249 pDrvIns->pDrvReg->pfnPowerOff(pDrvIns);
1250 }
1251
1252 if (pUsbIns->pUsbReg->pfnVMPowerOff)
1253 {
1254 LogFlow(("PDMR3PowerOff: Notifying - device '%s'/%d\n",
1255 pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
1256 pUsbIns->pUsbReg->pfnVMPowerOff(pUsbIns);
1257 }
1258 }
1259#endif
1260
1261 /*
1262 * Suspend all threads.
1263 */
1264 pdmR3ThreadSuspendAll(pVM);
1265
1266 LogFlow(("PDMR3PowerOff: returns void\n"));
1267}
1268
1269
1270/**
1271 * Queries the base interace of a device instance.
1272 *
1273 * The caller can use this to query other interfaces the device implements
1274 * and use them to talk to the device.
1275 *
1276 * @returns VBox status code.
1277 * @param pVM VM handle.
1278 * @param pszDevice Device name.
1279 * @param iInstance Device instance.
1280 * @param ppBase Where to store the pointer to the base device interface on success.
1281 * @remark We're not doing any locking ATM, so don't try call this at times when the
1282 * device chain is known to be updated.
1283 */
1284VMMR3DECL(int) PDMR3QueryDevice(PVM pVM, const char *pszDevice, unsigned iInstance, PPDMIBASE *ppBase)
1285{
1286 LogFlow(("PDMR3DeviceQuery: pszDevice=%p:{%s} iInstance=%u ppBase=%p\n", pszDevice, pszDevice, iInstance, ppBase));
1287
1288 /*
1289 * Iterate registered devices looking for the device.
1290 */
1291 size_t cchDevice = strlen(pszDevice);
1292 for (PPDMDEV pDev = pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
1293 {
1294 if ( pDev->cchName == cchDevice
1295 && !memcmp(pDev->pDevReg->szDeviceName, pszDevice, cchDevice))
1296 {
1297 /*
1298 * Iterate device instances.
1299 */
1300 for (PPDMDEVINS pDevIns = pDev->pInstances; pDevIns; pDevIns = pDevIns->Internal.s.pPerDeviceNextR3)
1301 {
1302 if (pDevIns->iInstance == iInstance)
1303 {
1304 if (pDevIns->IBase.pfnQueryInterface)
1305 {
1306 *ppBase = &pDevIns->IBase;
1307 LogFlow(("PDMR3DeviceQuery: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
1308 return VINF_SUCCESS;
1309 }
1310
1311 LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NO_IBASE\n"));
1312 return VERR_PDM_DEVICE_INSTANCE_NO_IBASE;
1313 }
1314 }
1315
1316 LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NOT_FOUND\n"));
1317 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND;
1318 }
1319 }
1320
1321 LogFlow(("PDMR3QueryDevice: returns VERR_PDM_DEVICE_NOT_FOUND\n"));
1322 return VERR_PDM_DEVICE_NOT_FOUND;
1323}
1324
1325
1326/**
1327 * Queries the base interface of a device LUN.
1328 *
1329 * This differs from PDMR3QueryLun by that it returns the interface on the
1330 * device and not the top level driver.
1331 *
1332 * @returns VBox status code.
1333 * @param pVM VM Handle.
1334 * @param pszDevice Device name.
1335 * @param iInstance Device instance.
1336 * @param iLun The Logical Unit to obtain the interface of.
1337 * @param ppBase Where to store the base interface pointer.
1338 * @remark We're not doing any locking ATM, so don't try call this at times when the
1339 * device chain is known to be updated.
1340 */
1341VMMR3DECL(int) PDMR3QueryDeviceLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
1342{
1343 LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
1344 pszDevice, pszDevice, iInstance, iLun, ppBase));
1345
1346 /*
1347 * Find the LUN.
1348 */
1349 PPDMLUN pLun;
1350 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
1351 if (RT_SUCCESS(rc))
1352 {
1353 *ppBase = pLun->pBase;
1354 LogFlow(("PDMR3QueryDeviceLun: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
1355 return VINF_SUCCESS;
1356 }
1357 LogFlow(("PDMR3QueryDeviceLun: returns %Rrc\n", rc));
1358 return rc;
1359}
1360
1361
1362/**
1363 * Query the interface of the top level driver on a LUN.
1364 *
1365 * @returns VBox status code.
1366 * @param pVM VM Handle.
1367 * @param pszDevice Device name.
1368 * @param iInstance Device instance.
1369 * @param iLun The Logical Unit to obtain the interface of.
1370 * @param ppBase Where to store the base interface pointer.
1371 * @remark We're not doing any locking ATM, so don't try call this at times when the
1372 * device chain is known to be updated.
1373 */
1374VMMR3DECL(int) PDMR3QueryLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
1375{
1376 LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
1377 pszDevice, pszDevice, iInstance, iLun, ppBase));
1378
1379 /*
1380 * Find the LUN.
1381 */
1382 PPDMLUN pLun;
1383 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
1384 if (RT_SUCCESS(rc))
1385 {
1386 if (pLun->pTop)
1387 {
1388 *ppBase = &pLun->pTop->IBase;
1389 LogFlow(("PDMR3QueryLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
1390 return VINF_SUCCESS;
1391 }
1392 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
1393 }
1394 LogFlow(("PDMR3QueryLun: returns %Rrc\n", rc));
1395 return rc;
1396}
1397
1398/**
1399 * Executes pending DMA transfers.
1400 * Forced Action handler.
1401 *
1402 * @param pVM VM handle.
1403 */
1404VMMR3DECL(void) PDMR3DmaRun(PVM pVM)
1405{
1406 /* Note! Not really SMP safe; restrict it to VCPU 0. */
1407 if (VMMGetCpuId(pVM) != 0)
1408 return;
1409
1410 if (VM_FF_TESTANDCLEAR(pVM, VM_FF_PDM_DMA))
1411 {
1412 if (pVM->pdm.s.pDmac)
1413 {
1414 bool fMore = pVM->pdm.s.pDmac->Reg.pfnRun(pVM->pdm.s.pDmac->pDevIns);
1415 if (fMore)
1416 VM_FF_SET(pVM, VM_FF_PDM_DMA);
1417 }
1418 }
1419}
1420
1421
1422/**
1423 * Service a VMMCALLRING3_PDM_LOCK call.
1424 *
1425 * @returns VBox status code.
1426 * @param pVM The VM handle.
1427 */
1428VMMR3DECL(int) PDMR3LockCall(PVM pVM)
1429{
1430 return PDMR3CritSectEnterEx(&pVM->pdm.s.CritSect, true /* fHostCall */);
1431}
1432
1433
1434/**
1435 * Registers the VMM device heap
1436 *
1437 * @returns VBox status code.
1438 * @param pVM VM handle.
1439 * @param GCPhys The physical address.
1440 * @param pvHeap Ring-3 pointer.
1441 * @param cbSize Size of the heap.
1442 */
1443VMMR3DECL(int) PDMR3RegisterVMMDevHeap(PVM pVM, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbSize)
1444{
1445 Assert(pVM->pdm.s.pvVMMDevHeap == NULL);
1446
1447 Log(("PDMR3RegisterVMMDevHeap %RGp %RHv %x\n", GCPhys, pvHeap, cbSize));
1448 pVM->pdm.s.pvVMMDevHeap = pvHeap;
1449 pVM->pdm.s.GCPhysVMMDevHeap = GCPhys;
1450 pVM->pdm.s.cbVMMDevHeap = cbSize;
1451 pVM->pdm.s.cbVMMDevHeapLeft = cbSize;
1452 return VINF_SUCCESS;
1453}
1454
1455
1456/**
1457 * Unregisters the VMM device heap
1458 *
1459 * @returns VBox status code.
1460 * @param pVM VM handle.
1461 * @param GCPhys The physical address.
1462 */
1463VMMR3DECL(int) PDMR3UnregisterVMMDevHeap(PVM pVM, RTGCPHYS GCPhys)
1464{
1465 Assert(pVM->pdm.s.GCPhysVMMDevHeap == GCPhys);
1466
1467 Log(("PDMR3UnregisterVMMDevHeap %RGp\n", GCPhys));
1468 pVM->pdm.s.pvVMMDevHeap = NULL;
1469 pVM->pdm.s.GCPhysVMMDevHeap = NIL_RTGCPHYS;
1470 pVM->pdm.s.cbVMMDevHeap = 0;
1471 pVM->pdm.s.cbVMMDevHeapLeft = 0;
1472 return VINF_SUCCESS;
1473}
1474
1475
1476/**
1477 * Allocates memory from the VMM device heap
1478 *
1479 * @returns VBox status code.
1480 * @param pVM VM handle.
1481 * @param cbSize Allocation size.
1482 * @param pv Ring-3 pointer. (out)
1483 */
1484VMMR3DECL(int) PDMR3VMMDevHeapAlloc(PVM pVM, unsigned cbSize, RTR3PTR *ppv)
1485{
1486#ifdef DEBUG_bird
1487 if (!cbSize || cbSize > pVM->pdm.s.cbVMMDevHeapLeft)
1488 return VERR_NO_MEMORY;
1489#else
1490 AssertReturn(cbSize && cbSize <= pVM->pdm.s.cbVMMDevHeapLeft, VERR_NO_MEMORY);
1491#endif
1492
1493 Log(("PDMR3VMMDevHeapAlloc %x\n", cbSize));
1494
1495 /** @todo not a real heap as there's currently only one user. */
1496 *ppv = pVM->pdm.s.pvVMMDevHeap;
1497 pVM->pdm.s.cbVMMDevHeapLeft = 0;
1498 return VINF_SUCCESS;
1499}
1500
1501
1502/**
1503 * Frees memory from the VMM device heap
1504 *
1505 * @returns VBox status code.
1506 * @param pVM VM handle.
1507 * @param pv Ring-3 pointer.
1508 */
1509VMMR3DECL(int) PDMR3VMMDevHeapFree(PVM pVM, RTR3PTR pv)
1510{
1511 Log(("PDMR3VMMDevHeapFree %RHv\n", pv));
1512
1513 /** @todo not a real heap as there's currently only one user. */
1514 pVM->pdm.s.cbVMMDevHeapLeft = pVM->pdm.s.cbVMMDevHeap;
1515 return VINF_SUCCESS;
1516}
1517
1518/**
1519 * Release the PDM lock if owned by the current VCPU
1520 *
1521 * @param pVM The VM to operate on.
1522 */
1523VMMR3DECL(void) PDMR3ReleaseOwnedLocks(PVM pVM)
1524{
1525 while (PDMCritSectIsOwner(&pVM->pdm.s.CritSect))
1526 PDMCritSectLeave(&pVM->pdm.s.CritSect);
1527}
Note: See TracBrowser for help on using the repository browser.

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