VirtualBox

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

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

PDM: docs update.

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