VirtualBox

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

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

Fix crash in async completion code when an error occurs during init before the PDM async completion module was initialized. Move the initialization before the drivers as they may use the API during init

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