VirtualBox

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

Last change on this file since 19297 was 19141, checked in by vboxsync, 16 years ago

Action flags breakup.
Fixed PGM saved state loading of 2.2.2 images.
Reduced hacks in PATM state loading (fixups).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 49.9 KB
Line 
1/* $Id: PDM.cpp 19141 2009-04-23 13:52:18Z 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 3
283
284
285/*******************************************************************************
286* Internal Functions *
287*******************************************************************************/
288static DECLCALLBACK(int) pdmR3Save(PVM pVM, PSSMHANDLE pSSM);
289static DECLCALLBACK(int) pdmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version);
290static DECLCALLBACK(int) pdmR3LoadPrep(PVM pVM, PSSMHANDLE pSSM);
291
292
293
294/**
295 * Initializes the PDM part of the UVM.
296 *
297 * This doesn't really do much right now but has to be here for the sake
298 * of completeness.
299 *
300 * @returns VBox status code.
301 * @param pUVM Pointer to the user mode VM structure.
302 */
303VMMR3DECL(int) PDMR3InitUVM(PUVM pUVM)
304{
305 AssertCompile(sizeof(pUVM->pdm.s) <= sizeof(pUVM->pdm.padding));
306 AssertRelease(sizeof(pUVM->pdm.s) <= sizeof(pUVM->pdm.padding));
307 pUVM->pdm.s.pModules = NULL;
308 return VINF_SUCCESS;
309}
310
311
312/**
313 * Initializes the PDM.
314 *
315 * @returns VBox status code.
316 * @param pVM The VM to operate on.
317 */
318VMMR3DECL(int) PDMR3Init(PVM pVM)
319{
320 LogFlow(("PDMR3Init\n"));
321
322 /*
323 * Assert alignment and sizes.
324 */
325 AssertRelease(!(RT_OFFSETOF(VM, pdm.s) & 31));
326 AssertRelease(sizeof(pVM->pdm.s) <= sizeof(pVM->pdm.padding));
327
328 /*
329 * Init the structure.
330 */
331 pVM->pdm.s.offVM = RT_OFFSETOF(VM, pdm.s);
332 pVM->pdm.s.GCPhysVMMDevHeap = NIL_RTGCPHYS;
333
334 /*
335 * Initialize sub compontents.
336 */
337 int rc = pdmR3CritSectInit(pVM);
338 if (RT_SUCCESS(rc))
339 {
340 rc = PDMR3CritSectInit(pVM, &pVM->pdm.s.CritSect, "PDM");
341 if (RT_SUCCESS(rc))
342 rc = pdmR3LdrInitU(pVM->pUVM);
343 if (RT_SUCCESS(rc))
344 {
345 rc = pdmR3DrvInit(pVM);
346 if (RT_SUCCESS(rc))
347 {
348 rc = pdmR3DevInit(pVM);
349 if (RT_SUCCESS(rc))
350 {
351#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
352 rc = pdmR3AsyncCompletionInit(pVM);
353 if (RT_SUCCESS(rc))
354#endif
355 {
356 /*
357 * Register the saved state data unit.
358 */
359 rc = SSMR3RegisterInternal(pVM, "pdm", 1, PDM_SAVED_STATE_VERSION, 128,
360 NULL, pdmR3Save, NULL,
361 pdmR3LoadPrep, pdmR3Load, NULL);
362 if (RT_SUCCESS(rc))
363 {
364 LogFlow(("PDM: Successfully initialized\n"));
365 return rc;
366 }
367
368 }
369 }
370 }
371 }
372 }
373
374 /*
375 * Cleanup and return failure.
376 */
377 PDMR3Term(pVM);
378 LogFlow(("PDMR3Init: returns %Rrc\n", rc));
379 return rc;
380}
381
382
383/**
384 * Applies relocations to data and code managed by this
385 * component. This function will be called at init and
386 * whenever the VMM need to relocate it self inside the GC.
387 *
388 * @param pVM VM handle.
389 * @param offDelta Relocation delta relative to old location.
390 * @remark The loader subcomponent is relocated by PDMR3LdrRelocate() very
391 * early in the relocation phase.
392 */
393VMMR3DECL(void) PDMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
394{
395 LogFlow(("PDMR3Relocate\n"));
396
397 /*
398 * Queues.
399 */
400 pdmR3QueueRelocate(pVM, offDelta);
401 pVM->pdm.s.pDevHlpQueueRC = PDMQueueRCPtr(pVM->pdm.s.pDevHlpQueueR3);
402
403 /*
404 * Critical sections.
405 */
406 pdmR3CritSectRelocate(pVM);
407
408 /*
409 * The registered PIC.
410 */
411 if (pVM->pdm.s.Pic.pDevInsRC)
412 {
413 pVM->pdm.s.Pic.pDevInsRC += offDelta;
414 pVM->pdm.s.Pic.pfnSetIrqRC += offDelta;
415 pVM->pdm.s.Pic.pfnGetInterruptRC += offDelta;
416 }
417
418 /*
419 * The registered APIC.
420 */
421 if (pVM->pdm.s.Apic.pDevInsRC)
422 {
423 pVM->pdm.s.Apic.pDevInsRC += offDelta;
424 pVM->pdm.s.Apic.pfnGetInterruptRC += offDelta;
425 pVM->pdm.s.Apic.pfnSetBaseRC += offDelta;
426 pVM->pdm.s.Apic.pfnGetBaseRC += offDelta;
427 pVM->pdm.s.Apic.pfnSetTPRRC += offDelta;
428 pVM->pdm.s.Apic.pfnGetTPRRC += offDelta;
429 pVM->pdm.s.Apic.pfnBusDeliverRC += offDelta;
430 pVM->pdm.s.Apic.pfnWriteMSRRC += offDelta;
431 pVM->pdm.s.Apic.pfnReadMSRRC += offDelta;
432 }
433
434 /*
435 * The registered I/O APIC.
436 */
437 if (pVM->pdm.s.IoApic.pDevInsRC)
438 {
439 pVM->pdm.s.IoApic.pDevInsRC += offDelta;
440 pVM->pdm.s.IoApic.pfnSetIrqRC += offDelta;
441 }
442
443 /*
444 * The register PCI Buses.
445 */
446 for (unsigned i = 0; i < RT_ELEMENTS(pVM->pdm.s.aPciBuses); i++)
447 {
448 if (pVM->pdm.s.aPciBuses[i].pDevInsRC)
449 {
450 pVM->pdm.s.aPciBuses[i].pDevInsRC += offDelta;
451 pVM->pdm.s.aPciBuses[i].pfnSetIrqRC += offDelta;
452 }
453 }
454
455 /*
456 * Devices.
457 */
458 PCPDMDEVHLPRC pDevHlpRC;
459 int rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDevHlp", &pDevHlpRC);
460 AssertReleaseMsgRC(rc, ("rc=%Rrc when resolving g_pdmRCDevHlp\n", rc));
461 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
462 {
463 if (pDevIns->pDevReg->fFlags & PDM_DEVREG_FLAGS_RC)
464 {
465 pDevIns->pDevHlpRC = pDevHlpRC;
466 pDevIns->pvInstanceDataRC = MMHyperR3ToRC(pVM, pDevIns->pvInstanceDataR3);
467 pDevIns->Internal.s.pVMRC = pVM->pVMRC;
468 if (pDevIns->Internal.s.pPciBusR3)
469 pDevIns->Internal.s.pPciBusRC = MMHyperR3ToRC(pVM, pDevIns->Internal.s.pPciBusR3);
470 if (pDevIns->Internal.s.pPciDeviceR3)
471 pDevIns->Internal.s.pPciDeviceRC = MMHyperR3ToRC(pVM, pDevIns->Internal.s.pPciDeviceR3);
472 if (pDevIns->pDevReg->pfnRelocate)
473 {
474 LogFlow(("PDMR3Relocate: Relocating device '%s'/%d\n",
475 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
476 pDevIns->pDevReg->pfnRelocate(pDevIns, offDelta);
477 }
478 }
479 }
480}
481
482
483/**
484 * Worker for pdmR3Term that terminates a LUN chain.
485 *
486 * @param pVM Pointer to the shared VM structure.
487 * @param pLun The head of the chain.
488 * @param pszDevice The name of the device (for logging).
489 * @param iInstance The device instance number (for logging).
490 */
491static void pdmR3TermLuns(PVM pVM, PPDMLUN pLun, const char *pszDevice, unsigned iInstance)
492{
493 for (; pLun; pLun = pLun->pNext)
494 {
495 /*
496 * Destroy them one at a time from the bottom up.
497 * (The serial device/drivers depends on this - bad.)
498 */
499 PPDMDRVINS pDrvIns = pLun->pBottom;
500 pLun->pBottom = pLun->pTop = NULL;
501 while (pDrvIns)
502 {
503 PPDMDRVINS pDrvNext = pDrvIns->Internal.s.pUp;
504
505 if (pDrvIns->pDrvReg->pfnDestruct)
506 {
507 LogFlow(("pdmR3DevTerm: Destroying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
508 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pszDevice, iInstance));
509 pDrvIns->pDrvReg->pfnDestruct(pDrvIns);
510 }
511
512 TMR3TimerDestroyDriver(pVM, pDrvIns);
513 //PDMR3QueueDestroyDriver(pVM, pDrvIns);
514 //pdmR3ThreadDestroyDriver(pVM, pDrvIns);
515 SSMR3DeregisterDriver(pVM, pDrvIns, NULL, 0);
516
517 pDrvIns = pDrvNext;
518 }
519 }
520}
521
522
523/**
524 * Terminates the PDM.
525 *
526 * Termination means cleaning up and freeing all resources,
527 * the VM it self is at this point powered off or suspended.
528 *
529 * @returns VBox status code.
530 * @param pVM The VM to operate on.
531 */
532VMMR3DECL(int) PDMR3Term(PVM pVM)
533{
534 LogFlow(("PDMR3Term:\n"));
535 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
536
537 /*
538 * Iterate the device instances and attach drivers, doing
539 * relevant destruction processing.
540 *
541 * N.B. There is no need to mess around freeing memory allocated
542 * from any MM heap since MM will do that in its Term function.
543 */
544 /* usb ones first. */
545 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
546 {
547 pdmR3TermLuns(pVM, pUsbIns->Internal.s.pLuns, pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance);
548
549 if (pUsbIns->pUsbReg->pfnDestruct)
550 {
551 LogFlow(("pdmR3DevTerm: Destroying - device '%s'/%d\n",
552 pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
553 pUsbIns->pUsbReg->pfnDestruct(pUsbIns);
554 }
555
556 //TMR3TimerDestroyUsb(pVM, pUsbIns);
557 //SSMR3DeregisterUsb(pVM, pUsbIns, NULL, 0);
558 pdmR3ThreadDestroyUsb(pVM, pUsbIns);
559 }
560
561 /* then the 'normal' ones. */
562 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
563 {
564 pdmR3TermLuns(pVM, pDevIns->Internal.s.pLunsR3, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance);
565
566 if (pDevIns->pDevReg->pfnDestruct)
567 {
568 LogFlow(("pdmR3DevTerm: Destroying - device '%s'/%d\n",
569 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
570 pDevIns->pDevReg->pfnDestruct(pDevIns);
571 }
572
573 TMR3TimerDestroyDevice(pVM, pDevIns);
574 //SSMR3DeregisterDriver(pVM, pDevIns, NULL, 0);
575 pdmR3CritSectDeleteDevice(pVM, pDevIns);
576 //pdmR3ThreadDestroyDevice(pVM, pDevIns);
577 //PDMR3QueueDestroyDevice(pVM, pDevIns);
578 PGMR3PhysMMIO2Deregister(pVM, pDevIns, UINT32_MAX);
579 }
580
581 /*
582 * Destroy all threads.
583 */
584 pdmR3ThreadDestroyAll(pVM);
585
586#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
587 /*
588 * Free async completion managers.
589 */
590 pdmR3AsyncCompletionTerm(pVM);
591#endif
592
593 /*
594 * Free modules.
595 */
596 pdmR3LdrTermU(pVM->pUVM);
597
598 /*
599 * Destroy the PDM lock.
600 */
601 PDMR3CritSectDelete(&pVM->pdm.s.CritSect);
602
603 LogFlow(("PDMR3Term: returns %Rrc\n", VINF_SUCCESS));
604 return VINF_SUCCESS;
605}
606
607
608/**
609 * Terminates the PDM part of the UVM.
610 *
611 * This will unload any modules left behind.
612 *
613 * @param pUVM Pointer to the user mode VM structure.
614 */
615VMMR3DECL(void) PDMR3TermUVM(PUVM pUVM)
616{
617 /*
618 * In the normal cause of events we will now call pdmR3LdrTermU for
619 * the second time. In the case of init failure however, this might
620 * the first time, which is why we do it.
621 */
622 pdmR3LdrTermU(pUVM);
623}
624
625
626
627
628
629/**
630 * Execute state save operation.
631 *
632 * @returns VBox status code.
633 * @param pVM VM Handle.
634 * @param pSSM SSM operation handle.
635 */
636static DECLCALLBACK(int) pdmR3Save(PVM pVM, PSSMHANDLE pSSM)
637{
638 LogFlow(("pdmR3Save:\n"));
639
640 /*
641 * Save interrupt and DMA states.
642 */
643 for (unsigned idCpu=0;idCpu<pVM->cCPUs;idCpu++)
644 {
645 PVMCPU pVCpu = &pVM->aCpus[idCpu];
646 SSMR3PutUInt(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC));
647 SSMR3PutUInt(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC));
648 }
649 SSMR3PutUInt(pSSM, VM_FF_ISSET(pVM, VM_FF_PDM_DMA));
650
651 /*
652 * Save the list of device instances so we can check that
653 * they're all still there when we load the state and that
654 * nothing new have been added.
655 */
656 /** @todo We might have to filter out some device classes, like USB attached devices. */
657 uint32_t i = 0;
658 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3, i++)
659 {
660 SSMR3PutU32(pSSM, i);
661 SSMR3PutStrZ(pSSM, pDevIns->pDevReg->szDeviceName);
662 SSMR3PutU32(pSSM, pDevIns->iInstance);
663 }
664 return SSMR3PutU32(pSSM, ~0); /* terminator */
665}
666
667
668/**
669 * Prepare state load operation.
670 *
671 * This will dispatch pending operations and clear the FFs governed by PDM and its devices.
672 *
673 * @returns VBox status code.
674 * @param pVM The VM handle.
675 * @param pSSM The SSM handle.
676 */
677static DECLCALLBACK(int) pdmR3LoadPrep(PVM pVM, PSSMHANDLE pSSM)
678{
679 LogFlow(("pdmR3LoadPrep: %s%s%s%s\n",
680 VM_FF_ISSET(pVM, VM_FF_PDM_QUEUES) ? " VM_FF_PDM_QUEUES" : "",
681 VM_FF_ISSET(pVM, VM_FF_PDM_DMA) ? " VM_FF_PDM_DMA" : ""
682 ));
683#ifdef LOG_ENABLED
684 for (unsigned idCpu=0;idCpu<pVM->cCPUs;idCpu++)
685 {
686 PVMCPU pVCpu = &pVM->aCpus[idCpu];
687 LogFlow(("pdmR3LoadPrep: VCPU %d %s%s%s%s\n", idCpu,
688 VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC) ? " VMCPU_FF_INTERRUPT_APIC" : "",
689 VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC) ? " VMCPU_FF_INTERRUPT_PIC" : ""
690 ));
691 }
692#endif
693
694 /*
695 * In case there is work pending that will raise an interrupt,
696 * start a DMA transfer, or release a lock. (unlikely)
697 */
698 if (VM_FF_ISSET(pVM, VM_FF_PDM_QUEUES))
699 PDMR3QueueFlushAll(pVM);
700
701 /* Clear the FFs. */
702 for (unsigned idCpu=0;idCpu<pVM->cCPUs;idCpu++)
703 {
704 PVMCPU pVCpu = &pVM->aCpus[idCpu];
705 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
706 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
707 }
708 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
709
710 return VINF_SUCCESS;
711}
712
713
714/**
715 * Execute state load operation.
716 *
717 * @returns VBox status code.
718 * @param pVM VM Handle.
719 * @param pSSM SSM operation handle.
720 * @param u32Version Data layout version.
721 */
722static DECLCALLBACK(int) pdmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version)
723{
724 int rc;
725
726 LogFlow(("pdmR3Load:\n"));
727
728 /*
729 * Validate version.
730 */
731 if (u32Version != PDM_SAVED_STATE_VERSION)
732 {
733 AssertMsgFailed(("pdmR3Load: Invalid version u32Version=%d!\n", u32Version));
734 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
735 }
736
737 /*
738 * Load the interrupt and DMA states.
739 */
740 for (unsigned idCpu=0;idCpu<pVM->cCPUs;idCpu++)
741 {
742 PVMCPU pVCpu = &pVM->aCpus[idCpu];
743
744 /* APIC interrupt */
745 RTUINT fInterruptPending = 0;
746 rc = SSMR3GetUInt(pSSM, &fInterruptPending);
747 if (RT_FAILURE(rc))
748 return rc;
749 if (fInterruptPending & ~1)
750 {
751 AssertMsgFailed(("fInterruptPending=%#x (APIC)\n", fInterruptPending));
752 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
753 }
754 AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_APIC));
755 if (fInterruptPending)
756 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC);
757
758 /* PIC interrupt */
759 fInterruptPending = 0;
760 rc = SSMR3GetUInt(pSSM, &fInterruptPending);
761 if (RT_FAILURE(rc))
762 return rc;
763 if (fInterruptPending & ~1)
764 {
765 AssertMsgFailed(("fInterruptPending=%#x (PIC)\n", fInterruptPending));
766 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
767 }
768 AssertRelease(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INTERRUPT_PIC));
769 if (fInterruptPending)
770 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC);
771 }
772
773 /* DMA pending */
774 RTUINT fDMAPending = 0;
775 rc = SSMR3GetUInt(pSSM, &fDMAPending);
776 if (RT_FAILURE(rc))
777 return rc;
778 if (fDMAPending & ~1)
779 {
780 AssertMsgFailed(("fDMAPending=%#x\n", fDMAPending));
781 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
782 }
783 AssertRelease(!VM_FF_ISSET(pVM, VM_FF_PDM_DMA));
784 if (fDMAPending)
785 VM_FF_SET(pVM, VM_FF_PDM_DMA);
786
787 /*
788 * Load the list of devices and verify that they are all there.
789 *
790 * We boldly ASSUME that the order is fixed and that it's a good, this
791 * makes it way easier to validate...
792 */
793 uint32_t i = 0;
794 PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances;
795 for (;;pDevIns = pDevIns->Internal.s.pNextR3, i++)
796 {
797 /* Get the separator / terminator. */
798 uint32_t u32Sep;
799 int rc = SSMR3GetU32(pSSM, &u32Sep);
800 if (RT_FAILURE(rc))
801 return rc;
802 if (u32Sep == (uint32_t)~0)
803 break;
804 if (u32Sep != i)
805 AssertMsgFailedReturn(("Out of seqence. u32Sep=%#x i=%#x\n", u32Sep, i), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
806
807 /* get the name and instance number. */
808 char szDeviceName[sizeof(pDevIns->pDevReg->szDeviceName)];
809 rc = SSMR3GetStrZ(pSSM, szDeviceName, sizeof(szDeviceName));
810 if (RT_FAILURE(rc))
811 return rc;
812 RTUINT iInstance;
813 rc = SSMR3GetUInt(pSSM, &iInstance);
814 if (RT_FAILURE(rc))
815 return rc;
816
817 /* compare */
818 if (!pDevIns)
819 {
820 LogRel(("Device '%s'/%d not found in current config\n", szDeviceName, iInstance));
821 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
822 AssertFailedReturn(VERR_SSM_LOAD_CONFIG_MISMATCH);
823 break;
824 }
825 if ( strcmp(szDeviceName, pDevIns->pDevReg->szDeviceName)
826 || pDevIns->iInstance != iInstance)
827 {
828 LogRel(("u32Sep=%d loaded '%s'/%d configured '%s'/%d\n",
829 u32Sep, szDeviceName, iInstance, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
830 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
831 AssertFailedReturn(VERR_SSM_LOAD_CONFIG_MISMATCH);
832 }
833 }
834
835 /*
836 * Too many devices?
837 */
838 if (pDevIns)
839 {
840 LogRel(("Device '%s'/%d not found in saved state\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
841 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
842 AssertFailedReturn(VERR_SSM_LOAD_CONFIG_MISMATCH);
843 }
844
845 return VINF_SUCCESS;
846}
847
848
849/**
850 * This function will notify all the devices and their
851 * attached drivers about the VM now being powered on.
852 *
853 * @param pVM VM Handle.
854 */
855VMMR3DECL(void) PDMR3PowerOn(PVM pVM)
856{
857 LogFlow(("PDMR3PowerOn:\n"));
858
859 /*
860 * Iterate the device instances.
861 * The attached drivers are processed first.
862 */
863 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
864 {
865 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
866 /** @todo Inverse the order here? */
867 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
868 if (pDrvIns->pDrvReg->pfnPowerOn)
869 {
870 LogFlow(("PDMR3PowerOn: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
871 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
872 pDrvIns->pDrvReg->pfnPowerOn(pDrvIns);
873 }
874
875 if (pDevIns->pDevReg->pfnPowerOn)
876 {
877 LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n",
878 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
879 pDevIns->pDevReg->pfnPowerOn(pDevIns);
880 }
881 }
882
883#ifdef VBOX_WITH_USB
884 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
885 {
886 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
887 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
888 if (pDrvIns->pDrvReg->pfnPowerOn)
889 {
890 LogFlow(("PDMR3PowerOn: Notifying - driver '%s'/%d on LUN#%d of usb device '%s'/%d\n",
891 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
892 pDrvIns->pDrvReg->pfnPowerOn(pDrvIns);
893 }
894
895 if (pUsbIns->pUsbReg->pfnVMPowerOn)
896 {
897 LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n",
898 pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
899 pUsbIns->pUsbReg->pfnVMPowerOn(pUsbIns);
900 }
901 }
902#endif
903
904 /*
905 * Resume all threads.
906 */
907 pdmR3ThreadResumeAll(pVM);
908
909 LogFlow(("PDMR3PowerOn: returns void\n"));
910}
911
912
913
914
915/**
916 * This function will notify all the devices and their
917 * attached drivers about the VM now being reset.
918 *
919 * @param pVM VM Handle.
920 */
921VMMR3DECL(void) PDMR3Reset(PVM pVM)
922{
923 LogFlow(("PDMR3Reset:\n"));
924
925 /*
926 * Clear all pending interrupts and DMA operations.
927 */
928 for (unsigned idCpu=0;idCpu<pVM->cCPUs;idCpu++)
929 {
930 PVMCPU pVCpu = &pVM->aCpus[idCpu];
931 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_APIC);
932 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_PIC);
933 }
934 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
935
936 /*
937 * Iterate the device instances.
938 * The attached drivers are processed first.
939 */
940 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
941 {
942 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
943 /** @todo Inverse the order here? */
944 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
945 if (pDrvIns->pDrvReg->pfnReset)
946 {
947 LogFlow(("PDMR3Reset: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
948 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
949 pDrvIns->pDrvReg->pfnReset(pDrvIns);
950 }
951
952 if (pDevIns->pDevReg->pfnReset)
953 {
954 LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n",
955 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
956 pDevIns->pDevReg->pfnReset(pDevIns);
957 }
958 }
959
960#ifdef VBOX_WITH_USB
961 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
962 {
963 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
964 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
965 if (pDrvIns->pDrvReg->pfnReset)
966 {
967 LogFlow(("PDMR3Reset: Notifying - driver '%s'/%d on LUN#%d of usb device '%s'/%d\n",
968 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
969 pDrvIns->pDrvReg->pfnReset(pDrvIns);
970 }
971
972 if (pUsbIns->pUsbReg->pfnVMReset)
973 {
974 LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n",
975 pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
976 pUsbIns->pUsbReg->pfnVMReset(pUsbIns);
977 }
978 }
979#endif
980
981 LogFlow(("PDMR3Reset: returns void\n"));
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) PDMR3Suspend(PVM pVM)
992{
993 LogFlow(("PDMR3Suspend:\n"));
994
995 /*
996 * Iterate the device instances.
997 * The attached drivers are processed first.
998 */
999 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1000 {
1001 /*
1002 * Some devices need to be notified first that the VM is suspended to ensure that that there are no pending
1003 * requests from the guest which are still processed. Calling the drivers before these requests are finished
1004 * might lead to errors otherwise. One example is the SATA controller which might still have I/O requests
1005 * pending. But DrvVD sets the files into readonly mode and every request will fail then.
1006 */
1007 if (pDevIns->pDevReg->pfnSuspend && (pDevIns->pDevReg->fFlags & PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION))
1008 {
1009 LogFlow(("PDMR3Suspend: Notifying - device '%s'/%d\n",
1010 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1011 pDevIns->pDevReg->pfnSuspend(pDevIns);
1012 }
1013
1014 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1015 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1016 if (pDrvIns->pDrvReg->pfnSuspend)
1017 {
1018 LogFlow(("PDMR3Suspend: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1019 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1020 pDrvIns->pDrvReg->pfnSuspend(pDrvIns);
1021 }
1022
1023 /* Don't call the suspend notification again if it was already called. */
1024 if (pDevIns->pDevReg->pfnSuspend && !(pDevIns->pDevReg->fFlags & PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION))
1025 {
1026 LogFlow(("PDMR3Suspend: Notifying - device '%s'/%d\n",
1027 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1028 pDevIns->pDevReg->pfnSuspend(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->pfnSuspend)
1038 {
1039 LogFlow(("PDMR3Suspend: 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->pfnSuspend(pDrvIns);
1042 }
1043
1044 if (pUsbIns->pUsbReg->pfnVMSuspend)
1045 {
1046 LogFlow(("PDMR3Suspend: Notifying - device '%s'/%d\n",
1047 pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
1048 pUsbIns->pUsbReg->pfnVMSuspend(pUsbIns);
1049 }
1050 }
1051#endif
1052
1053 /*
1054 * Suspend all threads.
1055 */
1056 pdmR3ThreadSuspendAll(pVM);
1057
1058 LogFlow(("PDMR3Suspend: returns void\n"));
1059}
1060
1061
1062/**
1063 * This function will notify all the devices and their
1064 * attached drivers about the VM now being resumed.
1065 *
1066 * @param pVM VM Handle.
1067 */
1068VMMR3DECL(void) PDMR3Resume(PVM pVM)
1069{
1070 LogFlow(("PDMR3Resume:\n"));
1071
1072 /*
1073 * Iterate the device instances.
1074 * The attached drivers are processed first.
1075 */
1076 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1077 {
1078 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1079 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1080 if (pDrvIns->pDrvReg->pfnResume)
1081 {
1082 LogFlow(("PDMR3Resume: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1083 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1084 pDrvIns->pDrvReg->pfnResume(pDrvIns);
1085 }
1086
1087 if (pDevIns->pDevReg->pfnResume)
1088 {
1089 LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n",
1090 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1091 pDevIns->pDevReg->pfnResume(pDevIns);
1092 }
1093 }
1094
1095#ifdef VBOX_WITH_USB
1096 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1097 {
1098 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1099 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1100 if (pDrvIns->pDrvReg->pfnResume)
1101 {
1102 LogFlow(("PDMR3Resume: Notifying - driver '%s'/%d on LUN#%d of usb device '%s'/%d\n",
1103 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
1104 pDrvIns->pDrvReg->pfnResume(pDrvIns);
1105 }
1106
1107 if (pUsbIns->pUsbReg->pfnVMResume)
1108 {
1109 LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n",
1110 pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
1111 pUsbIns->pUsbReg->pfnVMResume(pUsbIns);
1112 }
1113 }
1114#endif
1115
1116 /*
1117 * Resume all threads.
1118 */
1119 pdmR3ThreadResumeAll(pVM);
1120
1121 LogFlow(("PDMR3Resume: returns void\n"));
1122}
1123
1124
1125/**
1126 * This function will notify all the devices and their
1127 * attached drivers about the VM being powered off.
1128 *
1129 * @param pVM VM Handle.
1130 */
1131VMMR3DECL(void) PDMR3PowerOff(PVM pVM)
1132{
1133 LogFlow(("PDMR3PowerOff:\n"));
1134
1135 /*
1136 * Iterate the device instances.
1137 * The attached drivers are processed first.
1138 */
1139 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
1140 {
1141
1142 if (pDevIns->pDevReg->pfnPowerOff && (pDevIns->pDevReg->fFlags & PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION))
1143 {
1144 LogFlow(("PDMR3PowerOff: Notifying - device '%s'/%d\n",
1145 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1146 pDevIns->pDevReg->pfnPowerOff(pDevIns);
1147 }
1148
1149 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
1150 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1151 if (pDrvIns->pDrvReg->pfnPowerOff)
1152 {
1153 LogFlow(("PDMR3PowerOff: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
1154 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1155 pDrvIns->pDrvReg->pfnPowerOff(pDrvIns);
1156 }
1157
1158 if (pDevIns->pDevReg->pfnPowerOff && !(pDevIns->pDevReg->fFlags & PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION))
1159 {
1160 LogFlow(("PDMR3PowerOff: Notifying - device '%s'/%d\n",
1161 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1162 pDevIns->pDevReg->pfnPowerOff(pDevIns);
1163 }
1164 }
1165
1166#ifdef VBOX_WITH_USB
1167 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1168 {
1169 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1170 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1171 if (pDrvIns->pDrvReg->pfnPowerOff)
1172 {
1173 LogFlow(("PDMR3PowerOff: Notifying - driver '%s'/%d on LUN#%d of usb device '%s'/%d\n",
1174 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
1175 pDrvIns->pDrvReg->pfnPowerOff(pDrvIns);
1176 }
1177
1178 if (pUsbIns->pUsbReg->pfnVMPowerOff)
1179 {
1180 LogFlow(("PDMR3PowerOff: Notifying - device '%s'/%d\n",
1181 pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
1182 pUsbIns->pUsbReg->pfnVMPowerOff(pUsbIns);
1183 }
1184 }
1185#endif
1186
1187 /*
1188 * Suspend all threads.
1189 */
1190 pdmR3ThreadSuspendAll(pVM);
1191
1192 LogFlow(("PDMR3PowerOff: returns void\n"));
1193}
1194
1195
1196/**
1197 * Queries the base interace of a device instance.
1198 *
1199 * The caller can use this to query other interfaces the device implements
1200 * and use them to talk to the device.
1201 *
1202 * @returns VBox status code.
1203 * @param pVM VM handle.
1204 * @param pszDevice Device name.
1205 * @param iInstance Device instance.
1206 * @param ppBase Where to store the pointer to the base device interface on success.
1207 * @remark We're not doing any locking ATM, so don't try call this at times when the
1208 * device chain is known to be updated.
1209 */
1210VMMR3DECL(int) PDMR3QueryDevice(PVM pVM, const char *pszDevice, unsigned iInstance, PPDMIBASE *ppBase)
1211{
1212 LogFlow(("PDMR3DeviceQuery: pszDevice=%p:{%s} iInstance=%u ppBase=%p\n", pszDevice, pszDevice, iInstance, ppBase));
1213
1214 /*
1215 * Iterate registered devices looking for the device.
1216 */
1217 size_t cchDevice = strlen(pszDevice);
1218 for (PPDMDEV pDev = pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
1219 {
1220 if ( pDev->cchName == cchDevice
1221 && !memcmp(pDev->pDevReg->szDeviceName, pszDevice, cchDevice))
1222 {
1223 /*
1224 * Iterate device instances.
1225 */
1226 for (PPDMDEVINS pDevIns = pDev->pInstances; pDevIns; pDevIns = pDevIns->Internal.s.pPerDeviceNextR3)
1227 {
1228 if (pDevIns->iInstance == iInstance)
1229 {
1230 if (pDevIns->IBase.pfnQueryInterface)
1231 {
1232 *ppBase = &pDevIns->IBase;
1233 LogFlow(("PDMR3DeviceQuery: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
1234 return VINF_SUCCESS;
1235 }
1236
1237 LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NO_IBASE\n"));
1238 return VERR_PDM_DEVICE_INSTANCE_NO_IBASE;
1239 }
1240 }
1241
1242 LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NOT_FOUND\n"));
1243 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND;
1244 }
1245 }
1246
1247 LogFlow(("PDMR3QueryDevice: returns VERR_PDM_DEVICE_NOT_FOUND\n"));
1248 return VERR_PDM_DEVICE_NOT_FOUND;
1249}
1250
1251
1252/**
1253 * Queries the base interface of a device LUN.
1254 *
1255 * This differs from PDMR3QueryLun by that it returns the interface on the
1256 * device and not the top level driver.
1257 *
1258 * @returns VBox status code.
1259 * @param pVM VM Handle.
1260 * @param pszDevice Device name.
1261 * @param iInstance Device instance.
1262 * @param iLun The Logical Unit to obtain the interface of.
1263 * @param ppBase Where to store the base interface pointer.
1264 * @remark We're not doing any locking ATM, so don't try call this at times when the
1265 * device chain is known to be updated.
1266 */
1267VMMR3DECL(int) PDMR3QueryDeviceLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
1268{
1269 LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
1270 pszDevice, pszDevice, iInstance, iLun, ppBase));
1271
1272 /*
1273 * Find the LUN.
1274 */
1275 PPDMLUN pLun;
1276 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
1277 if (RT_SUCCESS(rc))
1278 {
1279 *ppBase = pLun->pBase;
1280 LogFlow(("PDMR3QueryDeviceLun: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
1281 return VINF_SUCCESS;
1282 }
1283 LogFlow(("PDMR3QueryDeviceLun: returns %Rrc\n", rc));
1284 return rc;
1285}
1286
1287
1288/**
1289 * Query the interface of the top level driver on a LUN.
1290 *
1291 * @returns VBox status code.
1292 * @param pVM VM Handle.
1293 * @param pszDevice Device name.
1294 * @param iInstance Device instance.
1295 * @param iLun The Logical Unit to obtain the interface of.
1296 * @param ppBase Where to store the base interface pointer.
1297 * @remark We're not doing any locking ATM, so don't try call this at times when the
1298 * device chain is known to be updated.
1299 */
1300VMMR3DECL(int) PDMR3QueryLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
1301{
1302 LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
1303 pszDevice, pszDevice, iInstance, iLun, ppBase));
1304
1305 /*
1306 * Find the LUN.
1307 */
1308 PPDMLUN pLun;
1309 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
1310 if (RT_SUCCESS(rc))
1311 {
1312 if (pLun->pTop)
1313 {
1314 *ppBase = &pLun->pTop->IBase;
1315 LogFlow(("PDMR3QueryLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
1316 return VINF_SUCCESS;
1317 }
1318 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
1319 }
1320 LogFlow(("PDMR3QueryLun: returns %Rrc\n", rc));
1321 return rc;
1322}
1323
1324/**
1325 * Executes pending DMA transfers.
1326 * Forced Action handler.
1327 *
1328 * @param pVM VM handle.
1329 */
1330VMMR3DECL(void) PDMR3DmaRun(PVM pVM)
1331{
1332 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
1333 if (pVM->pdm.s.pDmac)
1334 {
1335 bool fMore = pVM->pdm.s.pDmac->Reg.pfnRun(pVM->pdm.s.pDmac->pDevIns);
1336 if (fMore)
1337 VM_FF_SET(pVM, VM_FF_PDM_DMA);
1338 }
1339}
1340
1341
1342/**
1343 * Service a VMMCALLHOST_PDM_LOCK call.
1344 *
1345 * @returns VBox status code.
1346 * @param pVM The VM handle.
1347 */
1348VMMR3DECL(int) PDMR3LockCall(PVM pVM)
1349{
1350 return PDMR3CritSectEnterEx(&pVM->pdm.s.CritSect, true /* fHostCall */);
1351}
1352
1353
1354/**
1355 * Registers the VMM device heap
1356 *
1357 * @returns VBox status code.
1358 * @param pVM VM handle.
1359 * @param GCPhys The physical address.
1360 * @param pvHeap Ring-3 pointer.
1361 * @param cbSize Size of the heap.
1362 */
1363VMMR3DECL(int) PDMR3RegisterVMMDevHeap(PVM pVM, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbSize)
1364{
1365 Assert(pVM->pdm.s.pvVMMDevHeap == NULL);
1366
1367 Log(("PDMR3RegisterVMMDevHeap %RGp %RHv %x\n", GCPhys, pvHeap, cbSize));
1368 pVM->pdm.s.pvVMMDevHeap = pvHeap;
1369 pVM->pdm.s.GCPhysVMMDevHeap = GCPhys;
1370 pVM->pdm.s.cbVMMDevHeap = cbSize;
1371 pVM->pdm.s.cbVMMDevHeapLeft = cbSize;
1372 return VINF_SUCCESS;
1373}
1374
1375
1376/**
1377 * Unregisters the VMM device heap
1378 *
1379 * @returns VBox status code.
1380 * @param pVM VM handle.
1381 * @param GCPhys The physical address.
1382 */
1383VMMR3DECL(int) PDMR3UnregisterVMMDevHeap(PVM pVM, RTGCPHYS GCPhys)
1384{
1385 Assert(pVM->pdm.s.GCPhysVMMDevHeap == GCPhys);
1386
1387 Log(("PDMR3UnregisterVMMDevHeap %RGp\n", GCPhys));
1388 pVM->pdm.s.pvVMMDevHeap = NULL;
1389 pVM->pdm.s.GCPhysVMMDevHeap = NIL_RTGCPHYS;
1390 pVM->pdm.s.cbVMMDevHeap = 0;
1391 pVM->pdm.s.cbVMMDevHeapLeft = 0;
1392 return VINF_SUCCESS;
1393}
1394
1395
1396/**
1397 * Allocates memory from the VMM device heap
1398 *
1399 * @returns VBox status code.
1400 * @param pVM VM handle.
1401 * @param cbSize Allocation size.
1402 * @param pv Ring-3 pointer. (out)
1403 */
1404VMMR3DECL(int) PDMR3VMMDevHeapAlloc(PVM pVM, unsigned cbSize, RTR3PTR *ppv)
1405{
1406 AssertReturn(cbSize && cbSize <= pVM->pdm.s.cbVMMDevHeapLeft, VERR_NO_MEMORY);
1407
1408 Log(("PDMR3VMMDevHeapAlloc %x\n", cbSize));
1409
1410 /** @todo not a real heap as there's currently only one user. */
1411 *ppv = pVM->pdm.s.pvVMMDevHeap;
1412 pVM->pdm.s.cbVMMDevHeapLeft = 0;
1413 return VINF_SUCCESS;
1414}
1415
1416
1417/**
1418 * Frees memory from the VMM device heap
1419 *
1420 * @returns VBox status code.
1421 * @param pVM VM handle.
1422 * @param pv Ring-3 pointer.
1423 */
1424VMMR3DECL(int) PDMR3VMMDevHeapFree(PVM pVM, RTR3PTR pv)
1425{
1426 Log(("PDMR3VMMDevHeapFree %RHv\n", pv));
1427
1428 /** @todo not a real heap as there's currently only one user. */
1429 pVM->pdm.s.cbVMMDevHeapLeft = pVM->pdm.s.cbVMMDevHeap;
1430 return VINF_SUCCESS;
1431}
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