VirtualBox

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

Last change on this file since 5999 was 5999, checked in by vboxsync, 17 years ago

The Giant CDDL Dual-License Header Change.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 38.7 KB
Line 
1/* $Id: PDM.cpp 5999 2007-12-07 15:05:06Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device Manager.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/** @page pg_pdm PDM - The Pluggable Device Manager
20 *
21 * VBox is designed to be very configurable, i.e. the ability to select
22 * virtual devices and configure them uniquely for a VM. For this reason
23 * virtual devices are not statically linked with the VMM but loaded and
24 * linked at runtime thru the Configuration Manager (CFGM). PDM will use
25 * CFGM to enumerate devices which needs loading and instantiation.
26 *
27 *
28 * @section sec_pdm_dev The Pluggable Device
29 *
30 * Devices register themselves when the module containing them is loaded.
31 * PDM will call an entry point 'VBoxDevicesRegister' when loading a device
32 * module. The device module will then use the supplied callback table to
33 * check the VMM version and to register its devices. Each device have an
34 * unique (for the configured VM) name (string). The name is not only used
35 * in PDM but in CFGM - to organize device and device instance settings - and
36 * by anyone who wants to do ioctls to the device.
37 *
38 * When all device modules have been successfully loaded PDM will instantiate
39 * those devices which are configured for the VM. Mark that this might mean
40 * creating several instances of some devices. When instantiating a device
41 * PDM provides device instance memory and a callback table with the VM APIs
42 * which the device instance is trusted with.
43 *
44 * Some devices are trusted devices, most are not. The trusted devices are
45 * an integrated part of the VM and can obtain the VM handle from their
46 * device instance handles, thus enabling them to call any VM api. Untrusted
47 * devices are can only use the callbacks provided during device
48 * instantiation.
49 *
50 * The guest context extention (optional) of a device is initialized as part
51 * of the GC init. A device marks in it's registration structure that it have
52 * a GC part, in which module and which name the entry point have. PDM will
53 * use its loader facilities to load this module into GC and to find the
54 * specified entry point.
55 *
56 * When writing a GC extention the programmer must keep in mind that this
57 * code will be relocated, so that using global/static pointer variables
58 * won't work.
59 *
60 *
61 * @section sec_pdm_drv The Pluggable Drivers
62 *
63 * The VM devices are often accessing host hardware or OS facilities. For
64 * most devices these facilities can be abstracted in one or more levels.
65 * These abstractions are called drivers.
66 *
67 * For instance take a DVD/CD drive. This can be connected to a SCSI
68 * controller, EIDE controller or SATA controller. The basics of the
69 * DVD/CD drive implementation remains the same - eject, insert,
70 * read, seek, and such. (For the scsi case, you might wanna speak SCSI
71 * directly to, but that can of course be fixed.) So, it makes much sense to
72 * have a generic CD/DVD driver which implements this.
73 *
74 * Then the media 'inserted' into the DVD/CD drive can be a ISO image, or
75 * it can be read from a real CD or DVD drive (there are probably other
76 * custom formats someone could desire to read or construct too). So, it
77 * would make sense to have abstracted interfaces for dealing with this
78 * in a generic way so the cdrom unit doesn't have to implement it all.
79 * Thus we have created the CDROM/DVD media driver family.
80 *
81 * So, for this example the IDE controller #1 (i.e. secondary) will have
82 * the DVD/CD Driver attached to it's LUN #0 (master). When a media is mounted
83 * the DVD/CD Driver will have a ISO, NativeCD, NativeDVD or RAW (media) Driver
84 * attached.
85 *
86 * It is possible to configure many levels of drivers inserting filters, loggers,
87 * or whatever you desire into the chain.
88 *
89 *
90 * @subsection sec_pdm_drv_interfaces Interfaces
91 *
92 * The pluggable drivers exposes one standard interface (callback table) which
93 * is used to construct, destruct, attach, detach, and query other interfaces.
94 * A device will query the interfaces required for it's operation during init
95 * and hotplug. PDM will query some interfaces during runtime mounting too.
96 *
97 * ... list interfaces ...
98 *
99 */
100
101
102/*******************************************************************************
103* Header Files *
104*******************************************************************************/
105#define LOG_GROUP LOG_GROUP_PDM
106#include "PDMInternal.h"
107#include <VBox/pdm.h>
108#include <VBox/mm.h>
109#include <VBox/ssm.h>
110#include <VBox/vm.h>
111#include <VBox/vmm.h>
112#include <VBox/param.h>
113#include <VBox/err.h>
114#include <VBox/sup.h>
115
116#include <VBox/log.h>
117#include <iprt/asm.h>
118#include <iprt/assert.h>
119#include <iprt/alloc.h>
120#include <iprt/ldr.h>
121#include <iprt/path.h>
122#include <iprt/string.h>
123
124
125/*******************************************************************************
126* Defined Constants And Macros *
127*******************************************************************************/
128/** The PDM saved state version. */
129#define PDM_SAVED_STATE_VERSION 3
130
131
132/*******************************************************************************
133* Internal Functions *
134*******************************************************************************/
135static DECLCALLBACK(int) pdmR3Save(PVM pVM, PSSMHANDLE pSSM);
136static DECLCALLBACK(int) pdmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version);
137static DECLCALLBACK(int) pdmR3LoadPrep(PVM pVM, PSSMHANDLE pSSM);
138static DECLCALLBACK(void) pdmR3PollerTimer(PVM pVM, PTMTIMER pTimer, void *pvUser);
139
140
141
142/**
143 * Initializes the PDM.
144 *
145 * @returns VBox status code.
146 * @param pVM The VM to operate on.
147 */
148PDMR3DECL(int) PDMR3Init(PVM pVM)
149{
150 LogFlow(("PDMR3Init\n"));
151
152 /*
153 * Assert alignment and sizes.
154 */
155 AssertRelease(!(RT_OFFSETOF(VM, pdm.s) & 31));
156 AssertRelease(sizeof(pVM->pdm.s) <= sizeof(pVM->pdm.padding));
157
158 /*
159 * Init the structure.
160 */
161 pVM->pdm.s.offVM = RT_OFFSETOF(VM, pdm.s);
162
163 int rc = TMR3TimerCreateInternal(pVM, TMCLOCK_VIRTUAL, pdmR3PollerTimer, NULL, "PDM Poller", &pVM->pdm.s.pTimerPollers);
164 AssertRC(rc);
165
166 /*
167 * Initialize sub compontents.
168 */
169 rc = pdmR3CritSectInit(pVM);
170 if (VBOX_SUCCESS(rc))
171 {
172#ifdef VBOX_WITH_PDM_LOCK
173 rc = PDMR3CritSectInit(pVM, &pVM->pdm.s.CritSect, "PDM");
174 if (VBOX_SUCCESS(rc))
175#endif
176 rc = pdmR3LdrInit(pVM);
177 if (VBOX_SUCCESS(rc))
178 {
179 rc = pdmR3DrvInit(pVM);
180 if (VBOX_SUCCESS(rc))
181 {
182 rc = pdmR3DevInit(pVM);
183 if (VBOX_SUCCESS(rc))
184 {
185#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
186 rc = pdmR3AsyncCompletionInit(pVM);
187 if (VBOX_SUCCESS(rc))
188#endif
189 {
190 /*
191 * Register the saved state data unit.
192 */
193 rc = SSMR3RegisterInternal(pVM, "pdm", 1, PDM_SAVED_STATE_VERSION, 128,
194 NULL, pdmR3Save, NULL,
195 pdmR3LoadPrep, pdmR3Load, NULL);
196 if (VBOX_SUCCESS(rc))
197 {
198 LogFlow(("PDM: Successfully initialized\n"));
199 return rc;
200 }
201
202 }
203 }
204 }
205 }
206 }
207
208 /*
209 * Cleanup and return failure.
210 */
211 PDMR3Term(pVM);
212 LogFlow(("PDMR3Init: returns %Vrc\n", rc));
213 return rc;
214}
215
216
217/**
218 * Applies relocations to data and code managed by this
219 * component. This function will be called at init and
220 * whenever the VMM need to relocate it self inside the GC.
221 *
222 * @param pVM VM handle.
223 * @param offDelta Relocation delta relative to old location.
224 * @remark The loader subcomponent is relocated by PDMR3LdrRelocate() very
225 * early in the relocation phase.
226 */
227PDMR3DECL(void) PDMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
228{
229 LogFlow(("PDMR3Relocate\n"));
230
231 /*
232 * Queues.
233 */
234 pdmR3QueueRelocate(pVM, offDelta);
235 pVM->pdm.s.pDevHlpQueueGC = PDMQueueGCPtr(pVM->pdm.s.pDevHlpQueueHC);
236
237 /*
238 * Critical sections.
239 */
240 pdmR3CritSectRelocate(pVM);
241
242 /*
243 * The registered PIC.
244 */
245 if (pVM->pdm.s.Pic.pDevInsGC)
246 {
247 pVM->pdm.s.Pic.pDevInsGC += offDelta;
248 pVM->pdm.s.Pic.pfnSetIrqGC += offDelta;
249 pVM->pdm.s.Pic.pfnGetInterruptGC += offDelta;
250 }
251
252 /*
253 * The registered APIC.
254 */
255 if (pVM->pdm.s.Apic.pDevInsGC)
256 {
257 pVM->pdm.s.Apic.pDevInsGC += offDelta;
258 pVM->pdm.s.Apic.pfnGetInterruptGC += offDelta;
259 pVM->pdm.s.Apic.pfnSetBaseGC += offDelta;
260 pVM->pdm.s.Apic.pfnGetBaseGC += offDelta;
261 pVM->pdm.s.Apic.pfnSetTPRGC += offDelta;
262 pVM->pdm.s.Apic.pfnGetTPRGC += offDelta;
263 pVM->pdm.s.Apic.pfnBusDeliverGC += offDelta;
264 }
265
266 /*
267 * The registered I/O APIC.
268 */
269 if (pVM->pdm.s.IoApic.pDevInsGC)
270 {
271 pVM->pdm.s.IoApic.pDevInsGC += offDelta;
272 pVM->pdm.s.IoApic.pfnSetIrqGC += offDelta;
273 }
274
275 /*
276 * The register PCI Buses.
277 */
278 for (unsigned i = 0; i < ELEMENTS(pVM->pdm.s.aPciBuses); i++)
279 {
280 if (pVM->pdm.s.aPciBuses[i].pDevInsGC)
281 {
282 pVM->pdm.s.aPciBuses[i].pDevInsGC += offDelta;
283 pVM->pdm.s.aPciBuses[i].pfnSetIrqGC += offDelta;
284 }
285 }
286
287 /*
288 * Devices.
289 */
290 GCPTRTYPE(PCPDMDEVHLPGC) pDevHlpGC;
291 int rc = PDMR3GetSymbolGC(pVM, NULL, "g_pdmGCDevHlp", &pDevHlpGC);
292 AssertReleaseMsgRC(rc, ("rc=%Vrc when resolving g_pdmGCDevHlp\n", rc));
293 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextHC)
294 {
295 if (pDevIns->pDevReg->fFlags & PDM_DEVREG_FLAGS_GC)
296 {
297 pDevIns->pDevHlpGC = pDevHlpGC;
298 pDevIns->pvInstanceDataGC = MMHyperR3ToGC(pVM, pDevIns->pvInstanceDataR3);
299 pDevIns->pvInstanceDataR0 = MMHyperR3ToR0(pVM, pDevIns->pvInstanceDataR3);
300 pDevIns->Internal.s.pVMGC = pVM->pVMGC;
301 if (pDevIns->Internal.s.pPciBusHC)
302 pDevIns->Internal.s.pPciBusGC = MMHyperR3ToGC(pVM, pDevIns->Internal.s.pPciBusHC);
303 if (pDevIns->Internal.s.pPciDeviceHC)
304 pDevIns->Internal.s.pPciDeviceGC = MMHyperR3ToGC(pVM, pDevIns->Internal.s.pPciDeviceHC);
305 if (pDevIns->pDevReg->pfnRelocate)
306 {
307 LogFlow(("PDMR3Relocate: Relocating device '%s'/%d\n",
308 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
309 pDevIns->pDevReg->pfnRelocate(pDevIns, offDelta);
310 }
311 }
312 }
313}
314
315
316/**
317 * Worker for pdmR3Term that terminates a LUN chain.
318 *
319 * @param pVM Pointer to the shared VM structure.
320 * @param pLun The head of the chain.
321 * @param pszDevice The name of the device (for logging).
322 * @param iInstance The device instance number (for logging).
323 */
324static void pdmR3TermLuns(PVM pVM, PPDMLUN pLun, const char *pszDevice, unsigned iInstance)
325{
326 for (; pLun; pLun = pLun->pNext)
327 {
328 /*
329 * Destroy them one at a time from the bottom up.
330 * (The serial device/drivers depends on this - bad.)
331 */
332 PPDMDRVINS pDrvIns = pLun->pBottom;
333 pLun->pBottom = pLun->pTop = NULL;
334 while (pDrvIns)
335 {
336 PPDMDRVINS pDrvNext = pDrvIns->Internal.s.pUp;
337
338 if (pDrvIns->pDrvReg->pfnDestruct)
339 {
340 LogFlow(("pdmR3DevTerm: Destroying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
341 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pszDevice, iInstance));
342 pDrvIns->pDrvReg->pfnDestruct(pDrvIns);
343 }
344
345 TMR3TimerDestroyDriver(pVM, pDrvIns);
346 //PDMR3QueueDestroyDriver(pVM, pDrvIns);
347 //pdmR3ThreadDestroyDriver(pVM, pDrvIns);
348 SSMR3DeregisterDriver(pVM, pDrvIns, NULL, 0);
349
350 pDrvIns = pDrvNext;
351 }
352 }
353}
354
355
356/**
357 * Terminates the PDM.
358 *
359 * Termination means cleaning up and freeing all resources,
360 * the VM it self is at this point powered off or suspended.
361 *
362 * @returns VBox status code.
363 * @param pVM The VM to operate on.
364 */
365PDMR3DECL(int) PDMR3Term(PVM pVM)
366{
367 LogFlow(("PDMR3Term:\n"));
368 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
369
370 /*
371 * Iterate the device instances and attach drivers, doing
372 * relevant destruction processing.
373 *
374 * N.B. There is no need to mess around freeing memory allocated
375 * from any MM heap since MM will do that in its Term function.
376 */
377 /* usb ones first. */
378 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
379 {
380 pdmR3TermLuns(pVM, pUsbIns->Internal.s.pLuns, pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance);
381
382 if (pUsbIns->pUsbReg->pfnDestruct)
383 {
384 LogFlow(("pdmR3DevTerm: Destroying - device '%s'/%d\n",
385 pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
386 pUsbIns->pUsbReg->pfnDestruct(pUsbIns);
387 }
388
389 //TMR3TimerDestroyUsb(pVM, pUsbIns);
390 //SSMR3DeregisterUsb(pVM, pUsbIns, NULL, 0);
391 pdmR3ThreadDestroyUsb(pVM, pUsbIns);
392 }
393
394 /* then the 'normal' ones. */
395 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextHC)
396 {
397 pdmR3TermLuns(pVM, pDevIns->Internal.s.pLunsHC, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance);
398
399 if (pDevIns->pDevReg->pfnDestruct)
400 {
401 LogFlow(("pdmR3DevTerm: Destroying - device '%s'/%d\n",
402 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
403 pDevIns->pDevReg->pfnDestruct(pDevIns);
404 }
405
406 TMR3TimerDestroyDevice(pVM, pDevIns);
407 //SSMR3DeregisterDriver(pVM, pDevIns, NULL, 0);
408 pdmR3CritSectDeleteDevice(pVM, pDevIns);
409 //pdmR3ThreadDestroyDevice(pVM, pDevIns);
410 //PDMR3QueueDestroyDevice(pVM, pDevIns);
411 }
412
413 /*
414 * Destroy all threads.
415 */
416 pdmR3ThreadDestroyAll(pVM);
417
418#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
419 /*
420 * Free async completion managers.
421 */
422 pdmR3AsyncCompletionTerm(pVM);
423#endif
424
425 /*
426 * Free modules.
427 */
428 pdmR3LdrTerm(pVM);
429
430#ifdef VBOX_WITH_PDM_LOCK
431 /*
432 * Destroy the PDM lock.
433 */
434 PDMR3CritSectDelete(&pVM->pdm.s.CritSect);
435#endif
436
437 LogFlow(("PDMR3Term: returns %Vrc\n", VINF_SUCCESS));
438 return VINF_SUCCESS;
439}
440
441
442/**
443 * Execute state save operation.
444 *
445 * @returns VBox status code.
446 * @param pVM VM Handle.
447 * @param pSSM SSM operation handle.
448 */
449static DECLCALLBACK(int) pdmR3Save(PVM pVM, PSSMHANDLE pSSM)
450{
451 LogFlow(("pdmR3Save:\n"));
452
453 /*
454 * Save interrupt and DMA states.
455 */
456 SSMR3PutUInt(pSSM, VM_FF_ISSET(pVM, VM_FF_INTERRUPT_APIC));
457 SSMR3PutUInt(pSSM, VM_FF_ISSET(pVM, VM_FF_INTERRUPT_PIC));
458 SSMR3PutUInt(pSSM, VM_FF_ISSET(pVM, VM_FF_PDM_DMA));
459
460 /*
461 * Save the list of device instances so we can check that
462 * they're all still there when we load the state and that
463 * nothing new have been added.
464 */
465 /** @todo We might have to filter out some device classes, like USB attached devices. */
466 uint32_t i = 0;
467 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextHC, i++)
468 {
469 SSMR3PutU32(pSSM, i);
470 SSMR3PutStrZ(pSSM, pDevIns->pDevReg->szDeviceName);
471 SSMR3PutU32(pSSM, pDevIns->iInstance);
472 }
473 return SSMR3PutU32(pSSM, ~0); /* terminator */
474}
475
476
477/**
478 * Prepare state load operation.
479 *
480 * This will dispatch pending operations and clear the FFs governed by PDM and its devices.
481 *
482 * @returns VBox status code.
483 * @param pVM The VM handle.
484 * @param pSSM The SSM handle.
485 */
486static DECLCALLBACK(int) pdmR3LoadPrep(PVM pVM, PSSMHANDLE pSSM)
487{
488 LogFlow(("pdmR3LoadPrep: %s%s%s%s\n",
489 VM_FF_ISSET(pVM, VM_FF_PDM_QUEUES) ? " VM_FF_PDM_QUEUES" : "",
490 VM_FF_ISSET(pVM, VM_FF_PDM_DMA) ? " VM_FF_PDM_DMA" : "",
491 VM_FF_ISSET(pVM, VM_FF_INTERRUPT_APIC) ? " VM_FF_INTERRUPT_APIC" : "",
492 VM_FF_ISSET(pVM, VM_FF_INTERRUPT_PIC) ? " VM_FF_INTERRUPT_PIC" : ""
493 ));
494
495 /*
496 * In case there is work pending that will raise an interrupt,
497 * start a DMA transfer, or release a lock. (unlikely)
498 */
499 if (VM_FF_ISSET(pVM, VM_FF_PDM_QUEUES))
500 PDMR3QueueFlushAll(pVM);
501
502 /* Clear the FFs. */
503 VM_FF_CLEAR(pVM, VM_FF_INTERRUPT_APIC);
504 VM_FF_CLEAR(pVM, VM_FF_INTERRUPT_PIC);
505 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
506
507 return VINF_SUCCESS;
508}
509
510
511/**
512 * Execute state load operation.
513 *
514 * @returns VBox status code.
515 * @param pVM VM Handle.
516 * @param pSSM SSM operation handle.
517 * @param u32Version Data layout version.
518 */
519static DECLCALLBACK(int) pdmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version)
520{
521 LogFlow(("pdmR3Load:\n"));
522
523 /*
524 * Validate version.
525 */
526 if (u32Version != PDM_SAVED_STATE_VERSION)
527 {
528 Log(("pdmR3Load: Invalid version u32Version=%d!\n", u32Version));
529 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
530 }
531
532 /*
533 * Load the interrupt and DMA states.
534 */
535 /* APIC interrupt */
536 RTUINT fInterruptPending = 0;
537 int rc = SSMR3GetUInt(pSSM, &fInterruptPending);
538 if (VBOX_FAILURE(rc))
539 return rc;
540 if (fInterruptPending & ~1)
541 {
542 AssertMsgFailed(("fInterruptPending=%#x (APIC)\n", fInterruptPending));
543 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
544 }
545 AssertRelease(!VM_FF_ISSET(pVM, VM_FF_INTERRUPT_APIC));
546 if (fInterruptPending)
547 VM_FF_SET(pVM, VM_FF_INTERRUPT_APIC);
548
549 /* PIC interrupt */
550 fInterruptPending = 0;
551 rc = SSMR3GetUInt(pSSM, &fInterruptPending);
552 if (VBOX_FAILURE(rc))
553 return rc;
554 if (fInterruptPending & ~1)
555 {
556 AssertMsgFailed(("fInterruptPending=%#x (PIC)\n", fInterruptPending));
557 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
558 }
559 AssertRelease(!VM_FF_ISSET(pVM, VM_FF_INTERRUPT_PIC));
560 if (fInterruptPending)
561 VM_FF_SET(pVM, VM_FF_INTERRUPT_PIC);
562
563 /* DMA pending */
564 RTUINT fDMAPending = 0;
565 rc = SSMR3GetUInt(pSSM, &fDMAPending);
566 if (VBOX_FAILURE(rc))
567 return rc;
568 if (fDMAPending & ~1)
569 {
570 AssertMsgFailed(("fDMAPending=%#x\n", fDMAPending));
571 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
572 }
573 AssertRelease(!VM_FF_ISSET(pVM, VM_FF_PDM_DMA));
574 if (fDMAPending)
575 VM_FF_SET(pVM, VM_FF_PDM_DMA);
576
577 /*
578 * Load the list of devices and verify that they are all there.
579 *
580 * We boldly ASSUME that the order is fixed and that it's a good, this
581 * makes it way easier to validate...
582 */
583 uint32_t i = 0;
584 PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances;
585 for (;;pDevIns = pDevIns->Internal.s.pNextHC, i++)
586 {
587 /* Get the separator / terminator. */
588 uint32_t u32Sep;
589 int rc = SSMR3GetU32(pSSM, &u32Sep);
590 if (VBOX_FAILURE(rc))
591 return rc;
592 if (u32Sep == (uint32_t)~0)
593 break;
594 if (u32Sep != i)
595 AssertMsgFailedReturn(("Out of seqence. u32Sep=%#x i=%#x\n", u32Sep, i), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
596
597 /* get the name and instance number. */
598 char szDeviceName[sizeof(pDevIns->pDevReg->szDeviceName)];
599 rc = SSMR3GetStrZ(pSSM, szDeviceName, sizeof(szDeviceName));
600 if (VBOX_FAILURE(rc))
601 return rc;
602 RTUINT iInstance;
603 rc = SSMR3GetUInt(pSSM, &iInstance);
604 if (VBOX_FAILURE(rc))
605 return rc;
606
607 /* compare */
608 if (!pDevIns)
609 {
610 LogRel(("Device '%s'/%d not found in current config\n", szDeviceName, iInstance));
611 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
612 AssertFailedReturn(VERR_SSM_LOAD_CONFIG_MISMATCH);
613 break;
614 }
615 if ( strcmp(szDeviceName, pDevIns->pDevReg->szDeviceName)
616 || pDevIns->iInstance != iInstance)
617 {
618 LogRel(("u32Sep=%d loaded '%s'/%d configured '%s'/%d\n",
619 u32Sep, szDeviceName, iInstance, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
620 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
621 AssertFailedReturn(VERR_SSM_LOAD_CONFIG_MISMATCH);
622 }
623 }
624
625 /*
626 * Too many devices?
627 */
628 if (pDevIns)
629 {
630 LogRel(("Device '%s'/%d not found in saved state\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
631 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
632 AssertFailedReturn(VERR_SSM_LOAD_CONFIG_MISMATCH);
633 }
634
635 return VINF_SUCCESS;
636}
637
638
639/**
640 * This function will notify all the devices and their
641 * attached drivers about the VM now being powered on.
642 *
643 * @param pVM VM Handle.
644 */
645PDMR3DECL(void) PDMR3PowerOn(PVM pVM)
646{
647 LogFlow(("PDMR3PowerOn:\n"));
648
649 /*
650 * Iterate the device instances.
651 * The attached drivers are processed first.
652 */
653 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextHC)
654 {
655 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsHC; pLun; pLun = pLun->pNext)
656 /** @todo Inverse the order here? */
657 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
658 if (pDrvIns->pDrvReg->pfnPowerOn)
659 {
660 LogFlow(("PDMR3PowerOn: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
661 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
662 pDrvIns->pDrvReg->pfnPowerOn(pDrvIns);
663 }
664
665 if (pDevIns->pDevReg->pfnPowerOn)
666 {
667 LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n",
668 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
669 pDevIns->pDevReg->pfnPowerOn(pDevIns);
670 }
671 }
672
673#ifdef VBOX_WITH_USB
674 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
675 {
676 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
677 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
678 if (pDrvIns->pDrvReg->pfnPowerOn)
679 {
680 LogFlow(("PDMR3PowerOn: Notifying - driver '%s'/%d on LUN#%d of usb device '%s'/%d\n",
681 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
682 pDrvIns->pDrvReg->pfnPowerOn(pDrvIns);
683 }
684
685 if (pUsbIns->pUsbReg->pfnVMPowerOn)
686 {
687 LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n",
688 pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
689 pUsbIns->pUsbReg->pfnVMPowerOn(pUsbIns);
690 }
691 }
692#endif
693
694 /*
695 * Resume all threads.
696 */
697 pdmR3ThreadResumeAll(pVM);
698
699 LogFlow(("PDMR3PowerOn: returns void\n"));
700}
701
702
703
704
705/**
706 * This function will notify all the devices and their
707 * attached drivers about the VM now being reset.
708 *
709 * @param pVM VM Handle.
710 */
711PDMR3DECL(void) PDMR3Reset(PVM pVM)
712{
713 LogFlow(("PDMR3Reset:\n"));
714
715 /*
716 * Clear all pending interrupts and DMA operations.
717 */
718 VM_FF_CLEAR(pVM, VM_FF_INTERRUPT_APIC);
719 VM_FF_CLEAR(pVM, VM_FF_INTERRUPT_PIC);
720 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
721
722 /*
723 * Iterate the device instances.
724 * The attached drivers are processed first.
725 */
726 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextHC)
727 {
728 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsHC; pLun; pLun = pLun->pNext)
729 /** @todo Inverse the order here? */
730 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
731 if (pDrvIns->pDrvReg->pfnReset)
732 {
733 LogFlow(("PDMR3Reset: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
734 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
735 pDrvIns->pDrvReg->pfnReset(pDrvIns);
736 }
737
738 if (pDevIns->pDevReg->pfnReset)
739 {
740 LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n",
741 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
742 pDevIns->pDevReg->pfnReset(pDevIns);
743 }
744 }
745
746#ifdef VBOX_WITH_USB
747 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
748 {
749 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
750 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
751 if (pDrvIns->pDrvReg->pfnReset)
752 {
753 LogFlow(("PDMR3Reset: Notifying - driver '%s'/%d on LUN#%d of usb device '%s'/%d\n",
754 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
755 pDrvIns->pDrvReg->pfnReset(pDrvIns);
756 }
757
758 if (pUsbIns->pUsbReg->pfnVMReset)
759 {
760 LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n",
761 pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
762 pUsbIns->pUsbReg->pfnVMReset(pUsbIns);
763 }
764 }
765#endif
766
767 LogFlow(("PDMR3Reset: returns void\n"));
768}
769
770
771/**
772 * This function will notify all the devices and their
773 * attached drivers about the VM now being reset.
774 *
775 * @param pVM VM Handle.
776 */
777PDMR3DECL(void) PDMR3Suspend(PVM pVM)
778{
779 LogFlow(("PDMR3Suspend:\n"));
780
781 /*
782 * Iterate the device instances.
783 * The attached drivers are processed first.
784 */
785 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextHC)
786 {
787 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsHC; pLun; pLun = pLun->pNext)
788 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
789 if (pDrvIns->pDrvReg->pfnSuspend)
790 {
791 LogFlow(("PDMR3Suspend: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
792 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
793 pDrvIns->pDrvReg->pfnSuspend(pDrvIns);
794 }
795
796 if (pDevIns->pDevReg->pfnSuspend)
797 {
798 LogFlow(("PDMR3Suspend: Notifying - device '%s'/%d\n",
799 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
800 pDevIns->pDevReg->pfnSuspend(pDevIns);
801 }
802 }
803
804#ifdef VBOX_WITH_USB
805 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
806 {
807 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
808 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
809 if (pDrvIns->pDrvReg->pfnSuspend)
810 {
811 LogFlow(("PDMR3Suspend: Notifying - driver '%s'/%d on LUN#%d of usb device '%s'/%d\n",
812 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
813 pDrvIns->pDrvReg->pfnSuspend(pDrvIns);
814 }
815
816 if (pUsbIns->pUsbReg->pfnVMSuspend)
817 {
818 LogFlow(("PDMR3Suspend: Notifying - device '%s'/%d\n",
819 pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
820 pUsbIns->pUsbReg->pfnVMSuspend(pUsbIns);
821 }
822 }
823#endif
824
825 /*
826 * Suspend all threads.
827 */
828 pdmR3ThreadSuspendAll(pVM);
829
830 LogFlow(("PDMR3Suspend: returns void\n"));
831}
832
833
834/**
835 * This function will notify all the devices and their
836 * attached drivers about the VM now being resumed.
837 *
838 * @param pVM VM Handle.
839 */
840PDMR3DECL(void) PDMR3Resume(PVM pVM)
841{
842 LogFlow(("PDMR3Resume:\n"));
843
844 /*
845 * Iterate the device instances.
846 * The attached drivers are processed first.
847 */
848 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextHC)
849 {
850 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsHC; pLun; pLun = pLun->pNext)
851 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
852 if (pDrvIns->pDrvReg->pfnResume)
853 {
854 LogFlow(("PDMR3Resume: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
855 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
856 pDrvIns->pDrvReg->pfnResume(pDrvIns);
857 }
858
859 if (pDevIns->pDevReg->pfnResume)
860 {
861 LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n",
862 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
863 pDevIns->pDevReg->pfnResume(pDevIns);
864 }
865 }
866
867#ifdef VBOX_WITH_USB
868 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
869 {
870 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
871 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
872 if (pDrvIns->pDrvReg->pfnResume)
873 {
874 LogFlow(("PDMR3Resume: Notifying - driver '%s'/%d on LUN#%d of usb device '%s'/%d\n",
875 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
876 pDrvIns->pDrvReg->pfnResume(pDrvIns);
877 }
878
879 if (pUsbIns->pUsbReg->pfnVMResume)
880 {
881 LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n",
882 pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
883 pUsbIns->pUsbReg->pfnVMResume(pUsbIns);
884 }
885 }
886#endif
887
888 /*
889 * Resume all threads.
890 */
891 pdmR3ThreadResumeAll(pVM);
892
893 LogFlow(("PDMR3Resume: returns void\n"));
894}
895
896
897/**
898 * This function will notify all the devices and their
899 * attached drivers about the VM being powered off.
900 *
901 * @param pVM VM Handle.
902 */
903PDMR3DECL(void) PDMR3PowerOff(PVM pVM)
904{
905 LogFlow(("PDMR3PowerOff:\n"));
906
907 /*
908 * Iterate the device instances.
909 * The attached drivers are processed first.
910 */
911 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextHC)
912 {
913 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsHC; pLun; pLun = pLun->pNext)
914 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
915 if (pDrvIns->pDrvReg->pfnPowerOff)
916 {
917 LogFlow(("PDMR3PowerOff: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
918 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
919 pDrvIns->pDrvReg->pfnPowerOff(pDrvIns);
920 }
921
922 if (pDevIns->pDevReg->pfnPowerOff)
923 {
924 LogFlow(("PDMR3PowerOff: Notifying - device '%s'/%d\n",
925 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
926 pDevIns->pDevReg->pfnPowerOff(pDevIns);
927 }
928 }
929
930#ifdef VBOX_WITH_USB
931 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
932 {
933 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
934 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
935 if (pDrvIns->pDrvReg->pfnPowerOff)
936 {
937 LogFlow(("PDMR3PowerOff: Notifying - driver '%s'/%d on LUN#%d of usb device '%s'/%d\n",
938 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
939 pDrvIns->pDrvReg->pfnPowerOff(pDrvIns);
940 }
941
942 if (pUsbIns->pUsbReg->pfnVMPowerOff)
943 {
944 LogFlow(("PDMR3PowerOff: Notifying - device '%s'/%d\n",
945 pUsbIns->pUsbReg->szDeviceName, pUsbIns->iInstance));
946 pUsbIns->pUsbReg->pfnVMPowerOff(pUsbIns);
947 }
948 }
949#endif
950
951 /*
952 * Suspend all threads.
953 */
954 pdmR3ThreadSuspendAll(pVM);
955
956 LogFlow(("PDMR3PowerOff: returns void\n"));
957}
958
959
960/**
961 * Queries the base interace of a device instance.
962 *
963 * The caller can use this to query other interfaces the device implements
964 * and use them to talk to the device.
965 *
966 * @returns VBox status code.
967 * @param pVM VM handle.
968 * @param pszDevice Device name.
969 * @param iInstance Device instance.
970 * @param ppBase Where to store the pointer to the base device interface on success.
971 * @remark We're not doing any locking ATM, so don't try call this at times when the
972 * device chain is known to be updated.
973 */
974PDMR3DECL(int) PDMR3QueryDevice(PVM pVM, const char *pszDevice, unsigned iInstance, PPDMIBASE *ppBase)
975{
976 LogFlow(("PDMR3DeviceQuery: pszDevice=%p:{%s} iInstance=%u ppBase=%p\n", pszDevice, pszDevice, iInstance, ppBase));
977
978 /*
979 * Iterate registered devices looking for the device.
980 */
981 RTUINT cchDevice = strlen(pszDevice);
982 for (PPDMDEV pDev = pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
983 {
984 if ( pDev->cchName == cchDevice
985 && !memcmp(pDev->pDevReg->szDeviceName, pszDevice, cchDevice))
986 {
987 /*
988 * Iterate device instances.
989 */
990 for (PPDMDEVINS pDevIns = pDev->pInstances; pDevIns; pDevIns = pDevIns->Internal.s.pPerDeviceNextHC)
991 {
992 if (pDevIns->iInstance == iInstance)
993 {
994 if (pDevIns->IBase.pfnQueryInterface)
995 {
996 *ppBase = &pDevIns->IBase;
997 LogFlow(("PDMR3DeviceQuery: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
998 return VINF_SUCCESS;
999 }
1000
1001 LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NO_IBASE\n"));
1002 return VERR_PDM_DEVICE_INSTANCE_NO_IBASE;
1003 }
1004 }
1005
1006 LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NOT_FOUND\n"));
1007 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND;
1008 }
1009 }
1010
1011 LogFlow(("PDMR3QueryDevice: returns VERR_PDM_DEVICE_NOT_FOUND\n"));
1012 return VERR_PDM_DEVICE_NOT_FOUND;
1013}
1014
1015
1016/**
1017 * Queries the base interface of a device LUN.
1018 *
1019 * This differs from PDMR3QueryLun by that it returns the interface on the
1020 * device and not the top level driver.
1021 *
1022 * @returns VBox status code.
1023 * @param pVM VM Handle.
1024 * @param pszDevice Device name.
1025 * @param iInstance Device instance.
1026 * @param iLun The Logical Unit to obtain the interface of.
1027 * @param ppBase Where to store the base interface pointer.
1028 * @remark We're not doing any locking ATM, so don't try call this at times when the
1029 * device chain is known to be updated.
1030 */
1031PDMR3DECL(int) PDMR3QueryDeviceLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
1032{
1033 LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
1034 pszDevice, pszDevice, iInstance, iLun, ppBase));
1035
1036 /*
1037 * Find the LUN.
1038 */
1039 PPDMLUN pLun;
1040 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
1041 if (VBOX_SUCCESS(rc))
1042 {
1043 *ppBase = pLun->pBase;
1044 LogFlow(("PDMR3QueryDeviceLun: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
1045 return VINF_SUCCESS;
1046 }
1047 LogFlow(("PDMR3QueryDeviceLun: returns %Vrc\n", rc));
1048 return rc;
1049}
1050
1051
1052/**
1053 * Query the interface of the top level driver on a LUN.
1054 *
1055 * @returns VBox status code.
1056 * @param pVM VM Handle.
1057 * @param pszDevice Device name.
1058 * @param iInstance Device instance.
1059 * @param iLun The Logical Unit to obtain the interface of.
1060 * @param ppBase Where to store the base interface pointer.
1061 * @remark We're not doing any locking ATM, so don't try call this at times when the
1062 * device chain is known to be updated.
1063 */
1064PDMR3DECL(int) PDMR3QueryLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
1065{
1066 LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
1067 pszDevice, pszDevice, iInstance, iLun, ppBase));
1068
1069 /*
1070 * Find the LUN.
1071 */
1072 PPDMLUN pLun;
1073 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
1074 if (VBOX_SUCCESS(rc))
1075 {
1076 if (pLun->pTop)
1077 {
1078 *ppBase = &pLun->pTop->IBase;
1079 LogFlow(("PDMR3QueryLun: return %Vrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
1080 return VINF_SUCCESS;
1081 }
1082 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
1083 }
1084 LogFlow(("PDMR3QueryLun: returns %Vrc\n", rc));
1085 return rc;
1086}
1087
1088/**
1089 * Executes pending DMA transfers.
1090 * Forced Action handler.
1091 *
1092 * @param pVM VM handle.
1093 */
1094PDMR3DECL(void) PDMR3DmaRun(PVM pVM)
1095{
1096 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
1097 if (pVM->pdm.s.pDmac)
1098 {
1099 bool fMore = pVM->pdm.s.pDmac->Reg.pfnRun(pVM->pdm.s.pDmac->pDevIns);
1100 if (fMore)
1101 VM_FF_SET(pVM, VM_FF_PDM_DMA);
1102 }
1103}
1104
1105
1106/**
1107 * Call polling function.
1108 *
1109 * @param pVM VM handle.
1110 */
1111PDMR3DECL(void) PDMR3Poll(PVM pVM)
1112{
1113 /* This is temporary hack and shall be removed ASAP! */
1114 unsigned iPoller = pVM->pdm.s.cPollers;
1115 if (iPoller)
1116 {
1117 while (iPoller-- > 0)
1118 pVM->pdm.s.apfnPollers[iPoller](pVM->pdm.s.aDrvInsPollers[iPoller]);
1119 TMTimerSetMillies(pVM->pdm.s.pTimerPollers, 3);
1120 }
1121}
1122
1123
1124/**
1125 * Internal timer callback function.
1126 *
1127 * @param pVM The VM.
1128 * @param pTimer The timer handle.
1129 * @param pvUser User argument specified upon timer creation.
1130 */
1131static DECLCALLBACK(void) pdmR3PollerTimer(PVM pVM, PTMTIMER pTimer, void *pvUser)
1132{
1133 PDMR3Poll(pVM);
1134}
1135
1136
1137/**
1138 * Serivce a VMMCALLHOST_PDM_LOCK call.
1139 *
1140 * @returns VBox status code.
1141 * @param pVM The VM handle.
1142 */
1143PDMR3DECL(int) PDMR3LockCall(PVM pVM)
1144{
1145 return pdmLockEx(pVM, VERR_INTERNAL_ERROR);
1146}
1147
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