VirtualBox

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

Last change on this file since 3968 was 3852, checked in by vboxsync, 18 years ago

Finally splitting up pdm.h. Working on integrating USB into PDM (USBProxy needs CFGM stuff).

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