VirtualBox

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

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

Use GVMMR3CreateVM. the new GVM structure is a ring-0 only VM structure. the old VM structure is the shared ring-0, ring-3 and GC VM structure.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 32.6 KB
Line 
1/* $Id: PDM.cpp 5031 2007-09-25 22:27:37Z 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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * 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 /*
186 * Register the saved state data unit.
187 */
188 rc = SSMR3RegisterInternal(pVM, "pdm", 1, PDM_SAVED_STATE_VERSION, 128,
189 NULL, pdmR3Save, NULL,
190 pdmR3LoadPrep, pdmR3Load, NULL);
191 if (VBOX_SUCCESS(rc))
192 {
193 LogFlow(("PDM: Successfully initialized\n"));
194 return rc;
195 }
196
197 }
198 }
199 }
200 }
201
202 /*
203 * Cleanup and return failure.
204 */
205 PDMR3Term(pVM);
206 LogFlow(("PDMR3Init: returns %Vrc\n", rc));
207 return rc;
208}
209
210
211/**
212 * Applies relocations to data and code managed by this
213 * component. This function will be called at init and
214 * whenever the VMM need to relocate it self inside the GC.
215 *
216 * @param pVM VM handle.
217 * @param offDelta Relocation delta relative to old location.
218 * @remark The loader subcomponent is relocated by PDMR3LdrRelocate() very
219 * early in the relocation phase.
220 */
221PDMR3DECL(void) PDMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
222{
223 LogFlow(("PDMR3Relocate\n"));
224
225 /*
226 * Queues.
227 */
228 pdmR3QueueRelocate(pVM, offDelta);
229 pVM->pdm.s.pDevHlpQueueGC = PDMQueueGCPtr(pVM->pdm.s.pDevHlpQueueHC);
230
231 /*
232 * Critical sections.
233 */
234 pdmR3CritSectRelocate(pVM);
235
236 /*
237 * The registered PIC.
238 */
239 if (pVM->pdm.s.Pic.pDevInsGC)
240 {
241 pVM->pdm.s.Pic.pDevInsGC += offDelta;
242 pVM->pdm.s.Pic.pfnSetIrqGC += offDelta;
243 pVM->pdm.s.Pic.pfnGetInterruptGC += offDelta;
244 }
245
246 /*
247 * The registered APIC.
248 */
249 if (pVM->pdm.s.Apic.pDevInsGC)
250 {
251 pVM->pdm.s.Apic.pDevInsGC += offDelta;
252 pVM->pdm.s.Apic.pfnGetInterruptGC += offDelta;
253 pVM->pdm.s.Apic.pfnSetBaseGC += offDelta;
254 pVM->pdm.s.Apic.pfnGetBaseGC += offDelta;
255 pVM->pdm.s.Apic.pfnSetTPRGC += offDelta;
256 pVM->pdm.s.Apic.pfnGetTPRGC += offDelta;
257 pVM->pdm.s.Apic.pfnBusDeliverGC += offDelta;
258 }
259
260 /*
261 * The registered I/O APIC.
262 */
263 if (pVM->pdm.s.IoApic.pDevInsGC)
264 {
265 pVM->pdm.s.IoApic.pDevInsGC += offDelta;
266 pVM->pdm.s.IoApic.pfnSetIrqGC += offDelta;
267 }
268
269 /*
270 * The register PCI Buses.
271 */
272 for (unsigned i = 0; i < ELEMENTS(pVM->pdm.s.aPciBuses); i++)
273 {
274 if (pVM->pdm.s.aPciBuses[i].pDevInsGC)
275 {
276 pVM->pdm.s.aPciBuses[i].pDevInsGC += offDelta;
277 pVM->pdm.s.aPciBuses[i].pfnSetIrqGC += offDelta;
278 }
279 }
280
281 /*
282 * Devices.
283 */
284 GCPTRTYPE(PCPDMDEVHLPGC) pDevHlpGC;
285 int rc = PDMR3GetSymbolGC(pVM, NULL, "g_pdmGCDevHlp", &pDevHlpGC);
286 AssertReleaseMsgRC(rc, ("rc=%Vrc when resolving g_pdmGCDevHlp\n", rc));
287 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextHC)
288 {
289 if (pDevIns->pDevReg->fFlags & PDM_DEVREG_FLAGS_GC)
290 {
291 pDevIns->pDevHlpGC = pDevHlpGC;
292 pDevIns->pvInstanceDataGC = MMHyperR3ToGC(pVM, pDevIns->pvInstanceDataR3);
293 pDevIns->pvInstanceDataR0 = MMHyperR3ToR0(pVM, pDevIns->pvInstanceDataR3);
294 pDevIns->Internal.s.pVMGC = pVM->pVMGC;
295 if (pDevIns->Internal.s.pPciBusHC)
296 pDevIns->Internal.s.pPciBusGC = MMHyperR3ToGC(pVM, pDevIns->Internal.s.pPciBusHC);
297 if (pDevIns->Internal.s.pPciDeviceHC)
298 pDevIns->Internal.s.pPciDeviceGC = MMHyperR3ToGC(pVM, pDevIns->Internal.s.pPciDeviceHC);
299 if (pDevIns->pDevReg->pfnRelocate)
300 {
301 LogFlow(("PDMR3Relocate: Relocating device '%s'/%d\n",
302 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
303 pDevIns->pDevReg->pfnRelocate(pDevIns, offDelta);
304 }
305 }
306 }
307}
308
309
310/**
311 * Terminates the PDM.
312 *
313 * Termination means cleaning up and freeing all resources,
314 * the VM it self is at this point powered off or suspended.
315 *
316 * @returns VBox status code.
317 * @param pVM The VM to operate on.
318 */
319PDMR3DECL(int) PDMR3Term(PVM pVM)
320{
321 LogFlow(("PDMR3Term:\n"));
322 AssertMsg(pVM->pdm.s.offVM, ("bad init order!\n"));
323
324 /*
325 * Iterate the device instances.
326 * The attached drivers are processed first.
327 * N.B. There is no need to mess around freeing memory allocated
328 * from any MM heap since MM will do that in its Term function.
329 */
330 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextHC)
331 {
332 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsHC; pLun; pLun = pLun->pNext)
333 {
334 /* Find the bottom driver. */
335 /** @todo Add pBottom to PDMLUN, this might not be the only place we will have to work it from the bottom up. */
336 PPDMDRVINS pDrvIns = pLun->pTop;
337 while (pDrvIns && pDrvIns->Internal.s.pDown)
338 pDrvIns = pDrvIns->Internal.s.pDown;
339
340 /* And destroy them one at a time from the bottom up. */
341 while (pDrvIns)
342 {
343 PPDMDRVINS pDrvNext = pDrvIns->Internal.s.pUp;
344
345 if (pDrvIns->pDrvReg->pfnDestruct)
346 {
347 LogFlow(("pdmR3DevTerm: Destroying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
348 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
349 pDrvIns->pDrvReg->pfnDestruct(pDrvIns);
350 TMR3TimerDestroyDriver(pVM, pDrvIns);
351 }
352
353 pDrvIns = pDrvNext;
354 }
355 }
356
357 if (pDevIns->pDevReg->pfnDestruct)
358 {
359 LogFlow(("pdmR3DevTerm: Destroying - device '%s'/%d\n",
360 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
361 pDevIns->pDevReg->pfnDestruct(pDevIns);
362 TMR3TimerDestroyDevice(pVM, pDevIns);
363 pdmR3CritSectDeleteDevice(pVM, pDevIns);
364 }
365 }
366
367 /*
368 * Destroy all threads.
369 */
370 pdmR3ThreadDestroyAll(pVM);
371
372 /*
373 * Free modules.
374 */
375 pdmR3LdrTerm(pVM);
376
377#ifdef VBOX_WITH_PDM_LOCK
378 /*
379 * Destroy the PDM lock.
380 */
381 PDMR3CritSectDelete(&pVM->pdm.s.CritSect);
382#endif
383
384 LogFlow(("PDMR3Term: returns %Vrc\n", VINF_SUCCESS));
385 return VINF_SUCCESS;
386}
387
388
389/**
390 * Execute state save operation.
391 *
392 * @returns VBox status code.
393 * @param pVM VM Handle.
394 * @param pSSM SSM operation handle.
395 */
396static DECLCALLBACK(int) pdmR3Save(PVM pVM, PSSMHANDLE pSSM)
397{
398 LogFlow(("pdmR3Save:\n"));
399
400 /*
401 * Save interrupt and DMA states.
402 */
403 SSMR3PutUInt(pSSM, VM_FF_ISSET(pVM, VM_FF_INTERRUPT_APIC));
404 SSMR3PutUInt(pSSM, VM_FF_ISSET(pVM, VM_FF_INTERRUPT_PIC));
405 SSMR3PutUInt(pSSM, VM_FF_ISSET(pVM, VM_FF_PDM_DMA));
406
407 /*
408 * Save the list of device instances so we can check that
409 * they're all still there when we load the state and that
410 * nothing new have been added.
411 */
412 /** @todo We might have to filter out some device classes, like USB attached devices. */
413 uint32_t i = 0;
414 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextHC, i++)
415 {
416 SSMR3PutU32(pSSM, i);
417 SSMR3PutStrZ(pSSM, pDevIns->pDevReg->szDeviceName);
418 SSMR3PutU32(pSSM, pDevIns->iInstance);
419 }
420 return SSMR3PutU32(pSSM, ~0); /* terminator */
421}
422
423
424/**
425 * Prepare state load operation.
426 *
427 * This will dispatch pending operations and clear the FFs governed by PDM and its devices.
428 *
429 * @returns VBox status code.
430 * @param pVM The VM handle.
431 * @param pSSM The SSM handle.
432 */
433static DECLCALLBACK(int) pdmR3LoadPrep(PVM pVM, PSSMHANDLE pSSM)
434{
435 LogFlow(("pdmR3LoadPrep: %s%s%s%s\n",
436 VM_FF_ISSET(pVM, VM_FF_PDM_QUEUES) ? " VM_FF_PDM_QUEUES" : "",
437 VM_FF_ISSET(pVM, VM_FF_PDM_DMA) ? " VM_FF_PDM_DMA" : "",
438 VM_FF_ISSET(pVM, VM_FF_INTERRUPT_APIC) ? " VM_FF_INTERRUPT_APIC" : "",
439 VM_FF_ISSET(pVM, VM_FF_INTERRUPT_PIC) ? " VM_FF_INTERRUPT_PIC" : ""
440 ));
441
442 /*
443 * In case there is work pending that will raise an interrupt,
444 * start a DMA transfer, or release a lock. (unlikely)
445 */
446 if (VM_FF_ISSET(pVM, VM_FF_PDM_QUEUES))
447 PDMR3QueueFlushAll(pVM);
448
449 /* Clear the FFs. */
450 VM_FF_CLEAR(pVM, VM_FF_INTERRUPT_APIC);
451 VM_FF_CLEAR(pVM, VM_FF_INTERRUPT_PIC);
452 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
453
454 return VINF_SUCCESS;
455}
456
457
458/**
459 * Execute state load operation.
460 *
461 * @returns VBox status code.
462 * @param pVM VM Handle.
463 * @param pSSM SSM operation handle.
464 * @param u32Version Data layout version.
465 */
466static DECLCALLBACK(int) pdmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version)
467{
468 LogFlow(("pdmR3Load:\n"));
469
470 /*
471 * Validate version.
472 */
473 if (u32Version != PDM_SAVED_STATE_VERSION)
474 {
475 Log(("pdmR3Load: Invalid version u32Version=%d!\n", u32Version));
476 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
477 }
478
479 /*
480 * Load the interrupt and DMA states.
481 */
482 /* APIC interrupt */
483 RTUINT fInterruptPending = 0;
484 int rc = SSMR3GetUInt(pSSM, &fInterruptPending);
485 if (VBOX_FAILURE(rc))
486 return rc;
487 if (fInterruptPending & ~1)
488 {
489 AssertMsgFailed(("fInterruptPending=%#x (APIC)\n", fInterruptPending));
490 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
491 }
492 AssertRelease(!VM_FF_ISSET(pVM, VM_FF_INTERRUPT_APIC));
493 if (fInterruptPending)
494 VM_FF_SET(pVM, VM_FF_INTERRUPT_APIC);
495
496 /* PIC interrupt */
497 fInterruptPending = 0;
498 rc = SSMR3GetUInt(pSSM, &fInterruptPending);
499 if (VBOX_FAILURE(rc))
500 return rc;
501 if (fInterruptPending & ~1)
502 {
503 AssertMsgFailed(("fInterruptPending=%#x (PIC)\n", fInterruptPending));
504 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
505 }
506 AssertRelease(!VM_FF_ISSET(pVM, VM_FF_INTERRUPT_PIC));
507 if (fInterruptPending)
508 VM_FF_SET(pVM, VM_FF_INTERRUPT_PIC);
509
510 /* DMA pending */
511 RTUINT fDMAPending = 0;
512 rc = SSMR3GetUInt(pSSM, &fDMAPending);
513 if (VBOX_FAILURE(rc))
514 return rc;
515 if (fDMAPending & ~1)
516 {
517 AssertMsgFailed(("fDMAPending=%#x\n", fDMAPending));
518 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
519 }
520 AssertRelease(!VM_FF_ISSET(pVM, VM_FF_PDM_DMA));
521 if (fDMAPending)
522 VM_FF_SET(pVM, VM_FF_PDM_DMA);
523
524 /*
525 * Load the list of devices and verify that they are all there.
526 *
527 * We boldly ASSUME that the order is fixed and that it's a good, this
528 * makes it way easier to validate...
529 */
530 uint32_t i = 0;
531 PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances;
532 for (;;pDevIns = pDevIns->Internal.s.pNextHC, i++)
533 {
534 /* Get the separator / terminator. */
535 uint32_t u32Sep;
536 int rc = SSMR3GetU32(pSSM, &u32Sep);
537 if (VBOX_FAILURE(rc))
538 return rc;
539 if (u32Sep == (uint32_t)~0)
540 break;
541 if (u32Sep != i)
542 AssertMsgFailedReturn(("Out of seqence. u32Sep=%#x i=%#x\n", u32Sep, i), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
543
544 /* get the name and instance number. */
545 char szDeviceName[sizeof(pDevIns->pDevReg->szDeviceName)];
546 rc = SSMR3GetStrZ(pSSM, szDeviceName, sizeof(szDeviceName));
547 if (VBOX_FAILURE(rc))
548 return rc;
549 RTUINT iInstance;
550 rc = SSMR3GetUInt(pSSM, &iInstance);
551 if (VBOX_FAILURE(rc))
552 return rc;
553
554 /* compare */
555 if (!pDevIns)
556 {
557 LogRel(("Device '%s'/%d not found in current config\n", szDeviceName, iInstance));
558 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
559 AssertFailedReturn(VERR_SSM_LOAD_CONFIG_MISMATCH);
560 break;
561 }
562 if ( strcmp(szDeviceName, pDevIns->pDevReg->szDeviceName)
563 || pDevIns->iInstance != iInstance)
564 {
565 LogRel(("u32Sep=%d loaded '%s'/%d configured '%s'/%d\n",
566 u32Sep, szDeviceName, iInstance, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
567 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
568 AssertFailedReturn(VERR_SSM_LOAD_CONFIG_MISMATCH);
569 }
570 }
571
572 /*
573 * Too many devices?
574 */
575 if (pDevIns)
576 {
577 LogRel(("Device '%s'/%d not found in saved state\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
578 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
579 AssertFailedReturn(VERR_SSM_LOAD_CONFIG_MISMATCH);
580 }
581
582 return VINF_SUCCESS;
583}
584
585
586/**
587 * This function will notify all the devices and their
588 * attached drivers about the VM now being powered on.
589 *
590 * @param pVM VM Handle.
591 */
592PDMR3DECL(void) PDMR3PowerOn(PVM pVM)
593{
594 LogFlow(("PDMR3PowerOn:\n"));
595
596 /*
597 * Iterate the device instances.
598 * The attached drivers are processed first.
599 */
600 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextHC)
601 {
602 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsHC; pLun; pLun = pLun->pNext)
603 /** @todo Inverse the order here? */
604 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
605 if (pDrvIns->pDrvReg->pfnPowerOn)
606 {
607 LogFlow(("PDMR3PowerOn: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
608 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
609 pDrvIns->pDrvReg->pfnPowerOn(pDrvIns);
610 }
611
612 if (pDevIns->pDevReg->pfnPowerOn)
613 {
614 LogFlow(("PDMR3PowerOn: Notifying - device '%s'/%d\n",
615 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
616 pDevIns->pDevReg->pfnPowerOn(pDevIns);
617 }
618 }
619
620 /*
621 * Resume all threads.
622 */
623 pdmR3ThreadResumeAll(pVM);
624
625 LogFlow(("PDMR3PowerOn: returns void\n"));
626}
627
628
629
630
631/**
632 * This function will notify all the devices and their
633 * attached drivers about the VM now being reset.
634 *
635 * @param pVM VM Handle.
636 */
637PDMR3DECL(void) PDMR3Reset(PVM pVM)
638{
639 LogFlow(("PDMR3Reset:\n"));
640
641 /*
642 * Clear all pending interrupts and DMA operations.
643 */
644 VM_FF_CLEAR(pVM, VM_FF_INTERRUPT_APIC);
645 VM_FF_CLEAR(pVM, VM_FF_INTERRUPT_PIC);
646 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
647
648 /*
649 * Iterate the device instances.
650 * The attached drivers are processed first.
651 */
652 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextHC)
653 {
654 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsHC; pLun; pLun = pLun->pNext)
655 /** @todo Inverse the order here? */
656 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
657 if (pDrvIns->pDrvReg->pfnReset)
658 {
659 LogFlow(("PDMR3Reset: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
660 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
661 pDrvIns->pDrvReg->pfnReset(pDrvIns);
662 }
663
664 if (pDevIns->pDevReg->pfnReset)
665 {
666 LogFlow(("PDMR3Reset: Notifying - device '%s'/%d\n",
667 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
668 pDevIns->pDevReg->pfnReset(pDevIns);
669 }
670 }
671
672 LogFlow(("PDMR3Reset: returns void\n"));
673}
674
675
676/**
677 * This function will notify all the devices and their
678 * attached drivers about the VM now being reset.
679 *
680 * @param pVM VM Handle.
681 */
682PDMR3DECL(void) PDMR3Suspend(PVM pVM)
683{
684 LogFlow(("PDMR3Suspend:\n"));
685
686 /*
687 * Iterate the device instances.
688 * The attached drivers are processed first.
689 */
690 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextHC)
691 {
692 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsHC; pLun; pLun = pLun->pNext)
693 /** @todo Inverse the order here? */
694 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
695 if (pDrvIns->pDrvReg->pfnSuspend)
696 {
697 LogFlow(("PDMR3Suspend: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
698 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
699 pDrvIns->pDrvReg->pfnSuspend(pDrvIns);
700 }
701
702 if (pDevIns->pDevReg->pfnSuspend)
703 {
704 LogFlow(("PDMR3Suspend: Notifying - device '%s'/%d\n",
705 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
706 pDevIns->pDevReg->pfnSuspend(pDevIns);
707 }
708 }
709
710 /*
711 * Suspend all threads.
712 */
713 pdmR3ThreadSuspendAll(pVM);
714
715 LogFlow(("PDMR3Suspend: returns void\n"));
716}
717
718
719/**
720 * This function will notify all the devices and their
721 * attached drivers about the VM now being resumed.
722 *
723 * @param pVM VM Handle.
724 */
725PDMR3DECL(void) PDMR3Resume(PVM pVM)
726{
727 LogFlow(("PDMR3Resume:\n"));
728
729 /*
730 * Iterate the device instances.
731 * The attached drivers are processed first.
732 */
733 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextHC)
734 {
735 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsHC; pLun; pLun = pLun->pNext)
736 /** @todo Inverse the order here? */
737 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
738 if (pDrvIns->pDrvReg->pfnResume)
739 {
740 LogFlow(("PDMR3Resume: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
741 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
742 pDrvIns->pDrvReg->pfnResume(pDrvIns);
743 }
744
745 if (pDevIns->pDevReg->pfnResume)
746 {
747 LogFlow(("PDMR3Resume: Notifying - device '%s'/%d\n",
748 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
749 pDevIns->pDevReg->pfnResume(pDevIns);
750 }
751 }
752
753 /*
754 * Resume all threads.
755 */
756 pdmR3ThreadResumeAll(pVM);
757
758 LogFlow(("PDMR3Resume: returns void\n"));
759}
760
761
762/**
763 * This function will notify all the devices and their
764 * attached drivers about the VM being powered off.
765 *
766 * @param pVM VM Handle.
767 */
768PDMR3DECL(void) PDMR3PowerOff(PVM pVM)
769{
770 LogFlow(("PDMR3PowerOff:\n"));
771
772 /*
773 * Iterate the device instances.
774 * The attached drivers are processed first.
775 */
776 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextHC)
777 {
778 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsHC; pLun; pLun = pLun->pNext)
779 /** @todo Inverse the order here? */
780 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
781 if (pDrvIns->pDrvReg->pfnPowerOff)
782 {
783 LogFlow(("PDMR3PowerOff: Notifying - driver '%s'/%d on LUN#%d of device '%s'/%d\n",
784 pDrvIns->pDrvReg->szDriverName, pDrvIns->iInstance, pLun->iLun, pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
785 pDrvIns->pDrvReg->pfnPowerOff(pDrvIns);
786 }
787
788 if (pDevIns->pDevReg->pfnPowerOff)
789 {
790 LogFlow(("PDMR3PowerOff: Notifying - device '%s'/%d\n",
791 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
792 pDevIns->pDevReg->pfnPowerOff(pDevIns);
793 }
794 }
795
796 /*
797 * Suspend all threads.
798 */
799 pdmR3ThreadSuspendAll(pVM);
800
801 LogFlow(("PDMR3PowerOff: returns void\n"));
802}
803
804
805/**
806 * Queries the base interace of a device instance.
807 *
808 * The caller can use this to query other interfaces the device implements
809 * and use them to talk to the device.
810 *
811 * @returns VBox status code.
812 * @param pVM VM handle.
813 * @param pszDevice Device name.
814 * @param iInstance Device instance.
815 * @param ppBase Where to store the pointer to the base device interface on success.
816 * @remark We're not doing any locking ATM, so don't try call this at times when the
817 * device chain is known to be updated.
818 */
819PDMR3DECL(int) PDMR3QueryDevice(PVM pVM, const char *pszDevice, unsigned iInstance, PPDMIBASE *ppBase)
820{
821 LogFlow(("PDMR3DeviceQuery: pszDevice=%p:{%s} iInstance=%u ppBase=%p\n", pszDevice, pszDevice, iInstance, ppBase));
822
823 /*
824 * Iterate registered devices looking for the device.
825 */
826 RTUINT cchDevice = strlen(pszDevice);
827 for (PPDMDEV pDev = pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
828 {
829 if ( pDev->cchName == cchDevice
830 && !memcmp(pDev->pDevReg->szDeviceName, pszDevice, cchDevice))
831 {
832 /*
833 * Iterate device instances.
834 */
835 for (PPDMDEVINS pDevIns = pDev->pInstances; pDevIns; pDevIns = pDevIns->Internal.s.pPerDeviceNextHC)
836 {
837 if (pDevIns->iInstance == iInstance)
838 {
839 if (pDevIns->IBase.pfnQueryInterface)
840 {
841 *ppBase = &pDevIns->IBase;
842 LogFlow(("PDMR3DeviceQuery: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
843 return VINF_SUCCESS;
844 }
845
846 LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NO_IBASE\n"));
847 return VERR_PDM_DEVICE_INSTANCE_NO_IBASE;
848 }
849 }
850
851 LogFlow(("PDMR3DeviceQuery: returns VERR_PDM_DEVICE_INSTANCE_NOT_FOUND\n"));
852 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND;
853 }
854 }
855
856 LogFlow(("PDMR3QueryDevice: returns VERR_PDM_DEVICE_NOT_FOUND\n"));
857 return VERR_PDM_DEVICE_NOT_FOUND;
858}
859
860
861/**
862 * Queries the base interface of a device LUN.
863 *
864 * This differs from PDMR3QueryLun by that it returns the interface on the
865 * device and not the top level driver.
866 *
867 * @returns VBox status code.
868 * @param pVM VM Handle.
869 * @param pszDevice Device name.
870 * @param iInstance Device instance.
871 * @param iLun The Logical Unit to obtain the interface of.
872 * @param ppBase Where to store the base interface pointer.
873 * @remark We're not doing any locking ATM, so don't try call this at times when the
874 * device chain is known to be updated.
875 */
876PDMR3DECL(int) PDMR3QueryDeviceLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
877{
878 LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
879 pszDevice, pszDevice, iInstance, iLun, ppBase));
880
881 /*
882 * Find the LUN.
883 */
884 PPDMLUN pLun;
885 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
886 if (VBOX_SUCCESS(rc))
887 {
888 *ppBase = pLun->pBase;
889 LogFlow(("PDMR3QueryDeviceLun: return VINF_SUCCESS and *ppBase=%p\n", *ppBase));
890 return VINF_SUCCESS;
891 }
892 LogFlow(("PDMR3QueryDeviceLun: returns %Vrc\n", rc));
893 return rc;
894}
895
896
897/**
898 * Query the interface of the top level driver on a LUN.
899 *
900 * @returns VBox status code.
901 * @param pVM VM Handle.
902 * @param pszDevice Device name.
903 * @param iInstance Device instance.
904 * @param iLun The Logical Unit to obtain the interface of.
905 * @param ppBase Where to store the base interface pointer.
906 * @remark We're not doing any locking ATM, so don't try call this at times when the
907 * device chain is known to be updated.
908 */
909PDMR3DECL(int) PDMR3QueryLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
910{
911 LogFlow(("PDMR3QueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
912 pszDevice, pszDevice, iInstance, iLun, ppBase));
913
914 /*
915 * Find the LUN.
916 */
917 PPDMLUN pLun;
918 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
919 if (VBOX_SUCCESS(rc))
920 {
921 if (pLun->pTop)
922 {
923 *ppBase = &pLun->pTop->IBase;
924 LogFlow(("PDMR3QueryLun: return %Vrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
925 return VINF_SUCCESS;
926 }
927 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
928 }
929 LogFlow(("PDMR3QueryLun: returns %Vrc\n", rc));
930 return rc;
931}
932
933/**
934 * Executes pending DMA transfers.
935 * Forced Action handler.
936 *
937 * @param pVM VM handle.
938 */
939PDMR3DECL(void) PDMR3DmaRun(PVM pVM)
940{
941 VM_FF_CLEAR(pVM, VM_FF_PDM_DMA);
942 if (pVM->pdm.s.pDmac)
943 {
944 bool fMore = pVM->pdm.s.pDmac->Reg.pfnRun(pVM->pdm.s.pDmac->pDevIns);
945 if (fMore)
946 VM_FF_SET(pVM, VM_FF_PDM_DMA);
947 }
948}
949
950
951/**
952 * Call polling function.
953 *
954 * @param pVM VM handle.
955 */
956PDMR3DECL(void) PDMR3Poll(PVM pVM)
957{
958 /* This is temporary hack and shall be removed ASAP! */
959 unsigned iPoller = pVM->pdm.s.cPollers;
960 if (iPoller)
961 {
962 while (iPoller-- > 0)
963 pVM->pdm.s.apfnPollers[iPoller](pVM->pdm.s.aDrvInsPollers[iPoller]);
964 TMTimerSetMillies(pVM->pdm.s.pTimerPollers, 3);
965 }
966}
967
968
969/**
970 * Internal timer callback function.
971 *
972 * @param pVM The VM.
973 * @param pTimer The timer handle.
974 * @param pvUser User argument specified upon timer creation.
975 */
976static DECLCALLBACK(void) pdmR3PollerTimer(PVM pVM, PTMTIMER pTimer, void *pvUser)
977{
978 PDMR3Poll(pVM);
979}
980
981
982/**
983 * Serivce a VMMCALLHOST_PDM_LOCK call.
984 *
985 * @returns VBox status code.
986 * @param pVM The VM handle.
987 */
988PDMR3DECL(int) PDMR3LockCall(PVM pVM)
989{
990 return pdmLockEx(pVM, VERR_INTERNAL_ERROR);
991}
992
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