VirtualBox

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

Last change on this file since 12998 was 12989, checked in by vboxsync, 16 years ago

VMM + VBox/cdefs.h: consolidated all the XYZ*DECLS of the VMM into VMM*DECL. Removed dead DECL and IN_XYZ* macros.

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