VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/PDMDevice.cpp@ 62478

Last change on this file since 62478 was 62478, checked in by vboxsync, 8 years ago

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 40.7 KB
Line 
1/* $Id: PDMDevice.cpp 62478 2016-07-22 18:29:06Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device and Driver Manager, Device parts.
4 */
5
6/*
7 * Copyright (C) 2006-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_PDM_DEVICE
23#include "PDMInternal.h"
24#include <VBox/vmm/pdm.h>
25#include <VBox/vmm/mm.h>
26#include <VBox/vmm/pgm.h>
27#include <VBox/vmm/iom.h>
28#include <VBox/vmm/hm.h>
29#include <VBox/vmm/cfgm.h>
30#ifdef VBOX_WITH_NEW_APIC
31# include <VBox/vmm/apic.h>
32#endif
33#ifdef VBOX_WITH_REM
34# include <VBox/vmm/rem.h>
35#endif
36#include <VBox/vmm/dbgf.h>
37#include <VBox/vmm/vm.h>
38#include <VBox/vmm/uvm.h>
39#include <VBox/vmm/vmm.h>
40
41#include <VBox/version.h>
42#include <VBox/log.h>
43#include <VBox/err.h>
44#include <iprt/alloc.h>
45#include <iprt/alloca.h>
46#include <iprt/asm.h>
47#include <iprt/assert.h>
48#include <iprt/path.h>
49#include <iprt/semaphore.h>
50#include <iprt/string.h>
51#include <iprt/thread.h>
52
53
54/*********************************************************************************************************************************
55* Structures and Typedefs *
56*********************************************************************************************************************************/
57/**
58 * Internal callback structure pointer.
59 * The main purpose is to define the extra data we associate
60 * with PDMDEVREGCB so we can find the VM instance and so on.
61 */
62typedef struct PDMDEVREGCBINT
63{
64 /** The callback structure. */
65 PDMDEVREGCB Core;
66 /** A bit of padding. */
67 uint32_t u32[4];
68 /** VM Handle. */
69 PVM pVM;
70 /** Pointer to the configuration node the registrations should be
71 * associated with. Can be NULL. */
72 PCFGMNODE pCfgNode;
73} PDMDEVREGCBINT;
74/** Pointer to a PDMDEVREGCBINT structure. */
75typedef PDMDEVREGCBINT *PPDMDEVREGCBINT;
76/** Pointer to a const PDMDEVREGCBINT structure. */
77typedef const PDMDEVREGCBINT *PCPDMDEVREGCBINT;
78
79
80/*********************************************************************************************************************************
81* Internal Functions *
82*********************************************************************************************************************************/
83static DECLCALLBACK(int) pdmR3DevReg_Register(PPDMDEVREGCB pCallbacks, PCPDMDEVREG pReg);
84static int pdmR3DevLoadModules(PVM pVM);
85static int pdmR3DevLoad(PVM pVM, PPDMDEVREGCBINT pRegCB, const char *pszFilename, const char *pszName);
86
87
88
89
90/**
91 * This function will initialize the devices for this VM instance.
92 *
93 *
94 * First of all this mean loading the builtin device and letting them
95 * register themselves. Beyond that any additional device modules are
96 * loaded and called for registration.
97 *
98 * Then the device configuration is enumerated, the instantiation order
99 * is determined, and finally they are instantiated.
100 *
101 * After all devices have been successfully instantiated the primary
102 * PCI Bus device is called to emulate the PCI BIOS, i.e. making the
103 * resource assignments. If there is no PCI device, this step is of course
104 * skipped.
105 *
106 * Finally the init completion routines of the instantiated devices
107 * are called.
108 *
109 * @returns VBox status code.
110 * @param pVM The cross context VM structure.
111 */
112int pdmR3DevInit(PVM pVM)
113{
114 LogFlow(("pdmR3DevInit:\n"));
115
116 AssertRelease(!(RT_OFFSETOF(PDMDEVINS, achInstanceData) & 15));
117 AssertRelease(sizeof(pVM->pdm.s.pDevInstances->Internal.s) <= sizeof(pVM->pdm.s.pDevInstances->Internal.padding));
118
119 /*
120 * Load device modules.
121 */
122 int rc = pdmR3DevLoadModules(pVM);
123 if (RT_FAILURE(rc))
124 return rc;
125
126#ifdef VBOX_WITH_USB
127 /* ditto for USB Devices. */
128 rc = pdmR3UsbLoadModules(pVM);
129 if (RT_FAILURE(rc))
130 return rc;
131#endif
132
133 /*
134 * Get the RC & R0 devhlps and create the devhlp R3 task queue.
135 */
136 PCPDMDEVHLPRC pHlpRC = NIL_RTRCPTR;
137 if (!HMIsEnabled(pVM))
138 {
139 rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDevHlp", &pHlpRC);
140 AssertReleaseRCReturn(rc, rc);
141 }
142
143 PCPDMDEVHLPR0 pHlpR0;
144 rc = PDMR3LdrGetSymbolR0(pVM, NULL, "g_pdmR0DevHlp", &pHlpR0);
145 AssertReleaseRCReturn(rc, rc);
146
147 rc = PDMR3QueueCreateInternal(pVM, sizeof(PDMDEVHLPTASK), 8, 0, pdmR3DevHlpQueueConsumer, true, "DevHlp",
148 &pVM->pdm.s.pDevHlpQueueR3);
149 AssertRCReturn(rc, rc);
150 pVM->pdm.s.pDevHlpQueueR0 = PDMQueueR0Ptr(pVM->pdm.s.pDevHlpQueueR3);
151 pVM->pdm.s.pDevHlpQueueRC = PDMQueueRCPtr(pVM->pdm.s.pDevHlpQueueR3);
152
153
154 /*
155 *
156 * Enumerate the device instance configurations
157 * and come up with a instantiation order.
158 *
159 */
160 /* Switch to /Devices, which contains the device instantiations. */
161 PCFGMNODE pDevicesNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "Devices");
162
163 /*
164 * Count the device instances.
165 */
166 PCFGMNODE pCur;
167 PCFGMNODE pInstanceNode;
168 unsigned cDevs = 0;
169 for (pCur = CFGMR3GetFirstChild(pDevicesNode); pCur; pCur = CFGMR3GetNextChild(pCur))
170 for (pInstanceNode = CFGMR3GetFirstChild(pCur); pInstanceNode; pInstanceNode = CFGMR3GetNextChild(pInstanceNode))
171 cDevs++;
172 if (!cDevs)
173 {
174 Log(("PDM: No devices were configured!\n"));
175 return VINF_SUCCESS;
176 }
177 Log2(("PDM: cDevs=%u\n", cDevs));
178
179 /*
180 * Collect info on each device instance.
181 */
182 struct DEVORDER
183 {
184 /** Configuration node. */
185 PCFGMNODE pNode;
186 /** Pointer to device. */
187 PPDMDEV pDev;
188 /** Init order. */
189 uint32_t u32Order;
190 /** VBox instance number. */
191 uint32_t iInstance;
192 } *paDevs = (struct DEVORDER *)alloca(sizeof(paDevs[0]) * (cDevs + 1)); /* (One extra for swapping) */
193 Assert(paDevs);
194 unsigned i = 0;
195 for (pCur = CFGMR3GetFirstChild(pDevicesNode); pCur; pCur = CFGMR3GetNextChild(pCur))
196 {
197 /* Get the device name. */
198 char szName[sizeof(paDevs[0].pDev->pReg->szName)];
199 rc = CFGMR3GetName(pCur, szName, sizeof(szName));
200 AssertMsgRCReturn(rc, ("Configuration error: device name is too long (or something)! rc=%Rrc\n", rc), rc);
201
202 /* Find the device. */
203 PPDMDEV pDev = pdmR3DevLookup(pVM, szName);
204 AssertLogRelMsgReturn(pDev, ("Configuration error: device '%s' not found!\n", szName), VERR_PDM_DEVICE_NOT_FOUND);
205
206 /* Configured priority or use default based on device class? */
207 uint32_t u32Order;
208 rc = CFGMR3QueryU32(pCur, "Priority", &u32Order);
209 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
210 {
211 uint32_t u32 = pDev->pReg->fClass;
212 for (u32Order = 1; !(u32 & u32Order); u32Order <<= 1)
213 /* nop */;
214 }
215 else
216 AssertMsgRCReturn(rc, ("Configuration error: reading \"Priority\" for the '%s' device failed rc=%Rrc!\n", szName, rc), rc);
217
218 /* Enumerate the device instances. */
219 uint32_t const iStart = i;
220 for (pInstanceNode = CFGMR3GetFirstChild(pCur); pInstanceNode; pInstanceNode = CFGMR3GetNextChild(pInstanceNode))
221 {
222 paDevs[i].pNode = pInstanceNode;
223 paDevs[i].pDev = pDev;
224 paDevs[i].u32Order = u32Order;
225
226 /* Get the instance number. */
227 char szInstance[32];
228 rc = CFGMR3GetName(pInstanceNode, szInstance, sizeof(szInstance));
229 AssertMsgRCReturn(rc, ("Configuration error: instance name is too long (or something)! rc=%Rrc\n", rc), rc);
230 char *pszNext = NULL;
231 rc = RTStrToUInt32Ex(szInstance, &pszNext, 0, &paDevs[i].iInstance);
232 AssertMsgRCReturn(rc, ("Configuration error: RTStrToInt32Ex failed on the instance name '%s'! rc=%Rrc\n", szInstance, rc), rc);
233 AssertMsgReturn(!*pszNext, ("Configuration error: the instance name '%s' isn't all digits. (%s)\n", szInstance, pszNext), VERR_INVALID_PARAMETER);
234
235 /* next instance */
236 i++;
237 }
238
239 /* check the number of instances */
240 if (i - iStart > pDev->pReg->cMaxInstances)
241 AssertLogRelMsgFailedReturn(("Configuration error: Too many instances of %s was configured: %u, max %u\n",
242 szName, i - iStart, pDev->pReg->cMaxInstances),
243 VERR_PDM_TOO_MANY_DEVICE_INSTANCES);
244 } /* devices */
245 Assert(i == cDevs);
246
247 /*
248 * Sort the device array ascending on u32Order. (bubble)
249 */
250 unsigned c = cDevs - 1;
251 while (c)
252 {
253 unsigned j = 0;
254 for (i = 0; i < c; i++)
255 if (paDevs[i].u32Order > paDevs[i + 1].u32Order)
256 {
257 paDevs[cDevs] = paDevs[i + 1];
258 paDevs[i + 1] = paDevs[i];
259 paDevs[i] = paDevs[cDevs];
260 j = i;
261 }
262 c = j;
263 }
264
265
266 /*
267 *
268 * Instantiate the devices.
269 *
270 */
271 for (i = 0; i < cDevs; i++)
272 {
273 /*
274 * Gather a bit of config.
275 */
276 /* trusted */
277 bool fTrusted;
278 rc = CFGMR3QueryBool(paDevs[i].pNode, "Trusted", &fTrusted);
279 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
280 fTrusted = false;
281 else if (RT_FAILURE(rc))
282 {
283 AssertMsgFailed(("configuration error: failed to query boolean \"Trusted\", rc=%Rrc\n", rc));
284 return rc;
285 }
286 /* config node */
287 PCFGMNODE pConfigNode = CFGMR3GetChild(paDevs[i].pNode, "Config");
288 if (!pConfigNode)
289 {
290 rc = CFGMR3InsertNode(paDevs[i].pNode, "Config", &pConfigNode);
291 if (RT_FAILURE(rc))
292 {
293 AssertMsgFailed(("Failed to create Config node! rc=%Rrc\n", rc));
294 return rc;
295 }
296 }
297 CFGMR3SetRestrictedRoot(pConfigNode);
298
299 /*
300 * Allocate the device instance and critical section.
301 */
302 AssertReturn(paDevs[i].pDev->cInstances < paDevs[i].pDev->pReg->cMaxInstances, VERR_PDM_TOO_MANY_DEVICE_INSTANCES);
303 size_t cb = RT_OFFSETOF(PDMDEVINS, achInstanceData[paDevs[i].pDev->pReg->cbInstance]);
304 cb = RT_ALIGN_Z(cb, 16);
305 PPDMDEVINS pDevIns;
306 if (paDevs[i].pDev->pReg->fFlags & (PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0))
307 rc = MMR3HyperAllocOnceNoRel(pVM, cb, 0, MM_TAG_PDM_DEVICE, (void **)&pDevIns);
308 else
309 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_DEVICE, cb, (void **)&pDevIns);
310 AssertLogRelMsgRCReturn(rc,
311 ("Failed to allocate %d bytes of instance data for device '%s'. rc=%Rrc\n",
312 cb, paDevs[i].pDev->pReg->szName, rc),
313 rc);
314 PPDMCRITSECT pCritSect;
315 if (paDevs[i].pDev->pReg->fFlags & (PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0))
316 rc = MMHyperAlloc(pVM, sizeof(*pCritSect), 0, MM_TAG_PDM_DEVICE, (void **)&pCritSect);
317 else
318 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_DEVICE, sizeof(*pCritSect), (void **)&pCritSect);
319 AssertLogRelMsgRCReturn(rc, ("Failed to allocate a critical section for the device (%Rrc)\n", rc), rc);
320
321 /*
322 * Initialize it.
323 */
324 pDevIns->u32Version = PDM_DEVINS_VERSION;
325 pDevIns->iInstance = paDevs[i].iInstance;
326 //pDevIns->Internal.s.pNextR3 = NULL;
327 //pDevIns->Internal.s.pPerDeviceNextR3 = NULL;
328 pDevIns->Internal.s.pDevR3 = paDevs[i].pDev;
329 pDevIns->Internal.s.pVMR3 = pVM;
330 pDevIns->Internal.s.pVMR0 = pVM->pVMR0;
331 pDevIns->Internal.s.pVMRC = pVM->pVMRC;
332 //pDevIns->Internal.s.pLunsR3 = NULL;
333 pDevIns->Internal.s.pCfgHandle = paDevs[i].pNode;
334 //pDevIns->Internal.s.pPciDeviceR3 = NULL;
335 //pDevIns->Internal.s.pPciBusR3 = NULL;
336 //pDevIns->Internal.s.pPciDeviceR0 = 0;
337 //pDevIns->Internal.s.pPciBusR0 = 0;
338 //pDevIns->Internal.s.pPciDeviceRC = 0;
339 //pDevIns->Internal.s.pPciBusRC = 0;
340 pDevIns->Internal.s.fIntFlags = PDMDEVINSINT_FLAGS_SUSPENDED;
341 //pDevIns->Internal.s.uLastIrqTag = 0;
342 pDevIns->pHlpR3 = fTrusted ? &g_pdmR3DevHlpTrusted : &g_pdmR3DevHlpUnTrusted;
343 pDevIns->pHlpRC = pHlpRC;
344 pDevIns->pHlpR0 = pHlpR0;
345 pDevIns->pReg = paDevs[i].pDev->pReg;
346 pDevIns->pCfg = pConfigNode;
347 //pDevIns->IBase.pfnQueryInterface = NULL;
348 //pDevIns->fTracing = 0;
349 pDevIns->idTracing = ++pVM->pdm.s.idTracingDev;
350 pDevIns->pvInstanceDataR3 = &pDevIns->achInstanceData[0];
351 pDevIns->pvInstanceDataRC = pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_RC
352 ? MMHyperR3ToRC(pVM, pDevIns->pvInstanceDataR3) : NIL_RTRCPTR;
353 pDevIns->pvInstanceDataR0 = pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_R0
354 ? MMHyperR3ToR0(pVM, pDevIns->pvInstanceDataR3) : NIL_RTR0PTR;
355
356 pDevIns->pCritSectRoR3 = pCritSect;
357 pDevIns->pCritSectRoRC = pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_RC
358 ? MMHyperR3ToRC(pVM, pCritSect) : NIL_RTRCPTR;
359 pDevIns->pCritSectRoR0 = pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_R0
360 ? MMHyperR3ToR0(pVM, pCritSect) : NIL_RTR0PTR;
361
362 rc = pdmR3CritSectInitDeviceAuto(pVM, pDevIns, pCritSect, RT_SRC_POS,
363 "%s#%uAuto", pDevIns->pReg->szName, pDevIns->iInstance);
364 AssertLogRelRCReturn(rc, rc);
365
366 /*
367 * Link it into all the lists.
368 */
369 /* The global instance FIFO. */
370 PPDMDEVINS pPrev1 = pVM->pdm.s.pDevInstances;
371 if (!pPrev1)
372 pVM->pdm.s.pDevInstances = pDevIns;
373 else
374 {
375 while (pPrev1->Internal.s.pNextR3)
376 pPrev1 = pPrev1->Internal.s.pNextR3;
377 pPrev1->Internal.s.pNextR3 = pDevIns;
378 }
379
380 /* The per device instance FIFO. */
381 PPDMDEVINS pPrev2 = paDevs[i].pDev->pInstances;
382 if (!pPrev2)
383 paDevs[i].pDev->pInstances = pDevIns;
384 else
385 {
386 while (pPrev2->Internal.s.pPerDeviceNextR3)
387 pPrev2 = pPrev2->Internal.s.pPerDeviceNextR3;
388 pPrev2->Internal.s.pPerDeviceNextR3 = pDevIns;
389 }
390
391 /*
392 * Call the constructor.
393 */
394 paDevs[i].pDev->cInstances++;
395 Log(("PDM: Constructing device '%s' instance %d...\n", pDevIns->pReg->szName, pDevIns->iInstance));
396 rc = pDevIns->pReg->pfnConstruct(pDevIns, pDevIns->iInstance, pDevIns->pCfg);
397 if (RT_FAILURE(rc))
398 {
399 LogRel(("PDM: Failed to construct '%s'/%d! %Rra\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
400 paDevs[i].pDev->cInstances--;
401 /* Because we're damn lazy, the destructor will be called even if
402 the constructor fails. So, no unlinking. */
403 return rc == VERR_VERSION_MISMATCH ? VERR_PDM_DEVICE_VERSION_MISMATCH : rc;
404 }
405 } /* for device instances */
406
407#ifdef VBOX_WITH_USB
408 /* ditto for USB Devices. */
409 rc = pdmR3UsbInstantiateDevices(pVM);
410 if (RT_FAILURE(rc))
411 return rc;
412#endif
413
414 LogFlow(("pdmR3DevInit: returns %Rrc\n", VINF_SUCCESS));
415 return VINF_SUCCESS;
416}
417
418
419/**
420 * Performs the init complete callback after ring-0 and raw-mode has been
421 * initialized.
422 *
423 * @returns VBox status code.
424 * @param pVM The cross context VM structure.
425 */
426int pdmR3DevInitComplete(PVM pVM)
427{
428 int rc;
429
430 /*
431 *
432 * PCI BIOS Fake and Init Complete.
433 *
434 */
435 if (pVM->pdm.s.aPciBuses[0].pDevInsR3)
436 {
437 pdmLock(pVM);
438 rc = pVM->pdm.s.aPciBuses[0].pfnFakePCIBIOSR3(pVM->pdm.s.aPciBuses[0].pDevInsR3);
439 pdmUnlock(pVM);
440 if (RT_FAILURE(rc))
441 {
442 AssertMsgFailed(("PCI BIOS fake failed rc=%Rrc\n", rc));
443 return rc;
444 }
445 }
446
447 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
448 {
449 if (pDevIns->pReg->pfnInitComplete)
450 {
451 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
452 rc = pDevIns->pReg->pfnInitComplete(pDevIns);
453 PDMCritSectLeave(pDevIns->pCritSectRoR3);
454 if (RT_FAILURE(rc))
455 {
456 AssertMsgFailed(("InitComplete on device '%s'/%d failed with rc=%Rrc\n",
457 pDevIns->pReg->szName, pDevIns->iInstance, rc));
458 return rc;
459 }
460 }
461 }
462
463#ifdef VBOX_WITH_USB
464 rc = pdmR3UsbVMInitComplete(pVM);
465 if (RT_FAILURE(rc))
466 {
467 Log(("pdmR3DevInit: returns %Rrc\n", rc));
468 return rc;
469 }
470#endif
471
472 LogFlow(("pdmR3DevInit: returns %Rrc\n", VINF_SUCCESS));
473 return VINF_SUCCESS;
474}
475
476
477/**
478 * Lookups a device structure by name.
479 * @internal
480 */
481PPDMDEV pdmR3DevLookup(PVM pVM, const char *pszName)
482{
483 size_t cchName = strlen(pszName);
484 for (PPDMDEV pDev = pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
485 if ( pDev->cchName == cchName
486 && !strcmp(pDev->pReg->szName, pszName))
487 return pDev;
488 return NULL;
489}
490
491
492/**
493 * Loads the device modules.
494 *
495 * @returns VBox status code.
496 * @param pVM The cross context VM structure.
497 */
498static int pdmR3DevLoadModules(PVM pVM)
499{
500 /*
501 * Initialize the callback structure.
502 */
503 PDMDEVREGCBINT RegCB;
504 RegCB.Core.u32Version = PDM_DEVREG_CB_VERSION;
505 RegCB.Core.pfnRegister = pdmR3DevReg_Register;
506 RegCB.pVM = pVM;
507 RegCB.pCfgNode = NULL;
508
509#ifdef VBOX_WITH_NEW_APIC
510 /*
511 * Load the internal VMM APIC device.
512 */
513 int rc2 = pdmR3DevReg_Register(&RegCB.Core, &g_DeviceAPIC);
514 AssertRCReturn(rc2, rc2);
515#endif
516
517 /*
518 * Load the builtin module.
519 */
520 PCFGMNODE pDevicesNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "PDM/Devices");
521 bool fLoadBuiltin;
522 int rc = CFGMR3QueryBool(pDevicesNode, "LoadBuiltin", &fLoadBuiltin);
523 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
524 fLoadBuiltin = true;
525 else if (RT_FAILURE(rc))
526 {
527 AssertMsgFailed(("Configuration error: Querying boolean \"LoadBuiltin\" failed with %Rrc\n", rc));
528 return rc;
529 }
530 if (fLoadBuiltin)
531 {
532 /* make filename */
533 char *pszFilename = pdmR3FileR3("VBoxDD", true /*fShared*/);
534 if (!pszFilename)
535 return VERR_NO_TMP_MEMORY;
536 rc = pdmR3DevLoad(pVM, &RegCB, pszFilename, "VBoxDD");
537 RTMemTmpFree(pszFilename);
538 if (RT_FAILURE(rc))
539 return rc;
540
541 /* make filename */
542 pszFilename = pdmR3FileR3("VBoxDD2", true /*fShared*/);
543 if (!pszFilename)
544 return VERR_NO_TMP_MEMORY;
545 rc = pdmR3DevLoad(pVM, &RegCB, pszFilename, "VBoxDD2");
546 RTMemTmpFree(pszFilename);
547 if (RT_FAILURE(rc))
548 return rc;
549 }
550
551 /*
552 * Load additional device modules.
553 */
554 PCFGMNODE pCur;
555 for (pCur = CFGMR3GetFirstChild(pDevicesNode); pCur; pCur = CFGMR3GetNextChild(pCur))
556 {
557 /*
558 * Get the name and path.
559 */
560 char szName[PDMMOD_NAME_LEN];
561 rc = CFGMR3GetName(pCur, &szName[0], sizeof(szName));
562 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
563 {
564 AssertMsgFailed(("configuration error: The module name is too long, cchName=%zu.\n", CFGMR3GetNameLen(pCur)));
565 return VERR_PDM_MODULE_NAME_TOO_LONG;
566 }
567 else if (RT_FAILURE(rc))
568 {
569 AssertMsgFailed(("CFGMR3GetName -> %Rrc.\n", rc));
570 return rc;
571 }
572
573 /* the path is optional, if no path the module name + path is used. */
574 char szFilename[RTPATH_MAX];
575 rc = CFGMR3QueryString(pCur, "Path", &szFilename[0], sizeof(szFilename));
576 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
577 strcpy(szFilename, szName);
578 else if (RT_FAILURE(rc))
579 {
580 AssertMsgFailed(("configuration error: Failure to query the module path, rc=%Rrc.\n", rc));
581 return rc;
582 }
583
584 /* prepend path? */
585 if (!RTPathHavePath(szFilename))
586 {
587 char *psz = pdmR3FileR3(szFilename, false /*fShared*/);
588 if (!psz)
589 return VERR_NO_TMP_MEMORY;
590 size_t cch = strlen(psz) + 1;
591 if (cch > sizeof(szFilename))
592 {
593 RTMemTmpFree(psz);
594 AssertMsgFailed(("Filename too long! cch=%d '%s'\n", cch, psz));
595 return VERR_FILENAME_TOO_LONG;
596 }
597 memcpy(szFilename, psz, cch);
598 RTMemTmpFree(psz);
599 }
600
601 /*
602 * Load the module and register it's devices.
603 */
604 RegCB.pCfgNode = pCur;
605 rc = pdmR3DevLoad(pVM, &RegCB, szFilename, szName);
606 if (RT_FAILURE(rc))
607 return rc;
608 }
609
610 return VINF_SUCCESS;
611}
612
613
614/**
615 * Loads one device module and call the registration entry point.
616 *
617 * @returns VBox status code.
618 * @param pVM The cross context VM structure.
619 * @param pRegCB The registration callback stuff.
620 * @param pszFilename Module filename.
621 * @param pszName Module name.
622 */
623static int pdmR3DevLoad(PVM pVM, PPDMDEVREGCBINT pRegCB, const char *pszFilename, const char *pszName)
624{
625 /*
626 * Load it.
627 */
628 int rc = pdmR3LoadR3U(pVM->pUVM, pszFilename, pszName);
629 if (RT_SUCCESS(rc))
630 {
631 /*
632 * Get the registration export and call it.
633 */
634 FNPDMVBOXDEVICESREGISTER *pfnVBoxDevicesRegister;
635 rc = PDMR3LdrGetSymbolR3(pVM, pszName, "VBoxDevicesRegister", (void **)&pfnVBoxDevicesRegister);
636 if (RT_SUCCESS(rc))
637 {
638 Log(("PDM: Calling VBoxDevicesRegister (%p) of %s (%s)\n", pfnVBoxDevicesRegister, pszName, pszFilename));
639 rc = pfnVBoxDevicesRegister(&pRegCB->Core, VBOX_VERSION);
640 if (RT_SUCCESS(rc))
641 Log(("PDM: Successfully loaded device module %s (%s).\n", pszName, pszFilename));
642 else
643 AssertMsgFailed(("VBoxDevicesRegister failed with rc=%Rrc for module %s (%s)\n", rc, pszName, pszFilename));
644 }
645 else
646 {
647 AssertMsgFailed(("Failed to locate 'VBoxDevicesRegister' in %s (%s) rc=%Rrc\n", pszName, pszFilename, rc));
648 if (rc == VERR_SYMBOL_NOT_FOUND)
649 rc = VERR_PDM_NO_REGISTRATION_EXPORT;
650 }
651 }
652 else
653 AssertMsgFailed(("Failed to load %s %s!\n", pszFilename, pszName));
654 return rc;
655}
656
657
658/**
659 * @interface_method_impl{PDMDEVREGCB,pfnRegister}
660 */
661static DECLCALLBACK(int) pdmR3DevReg_Register(PPDMDEVREGCB pCallbacks, PCPDMDEVREG pReg)
662{
663 /*
664 * Validate the registration structure.
665 */
666 Assert(pReg);
667 AssertMsgReturn(pReg->u32Version == PDM_DEVREG_VERSION,
668 ("Unknown struct version %#x!\n", pReg->u32Version),
669 VERR_PDM_UNKNOWN_DEVREG_VERSION);
670
671 AssertMsgReturn( pReg->szName[0]
672 && strlen(pReg->szName) < sizeof(pReg->szName)
673 && pdmR3IsValidName(pReg->szName),
674 ("Invalid name '%.*s'\n", sizeof(pReg->szName), pReg->szName),
675 VERR_PDM_INVALID_DEVICE_REGISTRATION);
676 AssertMsgReturn( !(pReg->fFlags & PDM_DEVREG_FLAGS_RC)
677 || ( pReg->szRCMod[0]
678 && strlen(pReg->szRCMod) < sizeof(pReg->szRCMod)),
679 ("Invalid GC module name '%s' - (Device %s)\n", pReg->szRCMod, pReg->szName),
680 VERR_PDM_INVALID_DEVICE_REGISTRATION);
681 AssertMsgReturn( !(pReg->fFlags & PDM_DEVREG_FLAGS_R0)
682 || ( pReg->szR0Mod[0]
683 && strlen(pReg->szR0Mod) < sizeof(pReg->szR0Mod)),
684 ("Invalid R0 module name '%s' - (Device %s)\n", pReg->szR0Mod, pReg->szName),
685 VERR_PDM_INVALID_DEVICE_REGISTRATION);
686 AssertMsgReturn((pReg->fFlags & PDM_DEVREG_FLAGS_HOST_BITS_MASK) == PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT,
687 ("Invalid host bits flags! fFlags=%#x (Device %s)\n", pReg->fFlags, pReg->szName),
688 VERR_PDM_INVALID_DEVICE_HOST_BITS);
689 AssertMsgReturn((pReg->fFlags & PDM_DEVREG_FLAGS_GUEST_BITS_MASK),
690 ("Invalid guest bits flags! fFlags=%#x (Device %s)\n", pReg->fFlags, pReg->szName),
691 VERR_PDM_INVALID_DEVICE_REGISTRATION);
692 AssertMsgReturn(pReg->fClass,
693 ("No class! (Device %s)\n", pReg->szName),
694 VERR_PDM_INVALID_DEVICE_REGISTRATION);
695 AssertMsgReturn(pReg->cMaxInstances > 0,
696 ("Max instances %u! (Device %s)\n", pReg->cMaxInstances, pReg->szName),
697 VERR_PDM_INVALID_DEVICE_REGISTRATION);
698 AssertMsgReturn(pReg->cbInstance <= (uint32_t)(pReg->fFlags & (PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0) ? 96 * _1K : _1M),
699 ("Instance size %d bytes! (Device %s)\n", pReg->cbInstance, pReg->szName),
700 VERR_PDM_INVALID_DEVICE_REGISTRATION);
701 AssertMsgReturn(pReg->pfnConstruct,
702 ("No constructor! (Device %s)\n", pReg->szName),
703 VERR_PDM_INVALID_DEVICE_REGISTRATION);
704 AssertLogRelMsgReturn((pReg->fFlags & PDM_DEVREG_FLAGS_GUEST_BITS_MASK) == PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT,
705 ("PDM: Rejected device '%s' because it didn't match the guest bits.\n", pReg->szName),
706 VERR_PDM_INVALID_DEVICE_GUEST_BITS);
707 AssertLogRelMsg(pReg->u32VersionEnd == PDM_DEVREG_VERSION,
708 ("u32VersionEnd=%#x, expected %#x. (szName=%s)\n",
709 pReg->u32VersionEnd, PDM_DEVREG_VERSION, pReg->szName));
710
711 /*
712 * Check for duplicate and find FIFO entry at the same time.
713 */
714 PCPDMDEVREGCBINT pRegCB = (PCPDMDEVREGCBINT)pCallbacks;
715 PPDMDEV pDevPrev = NULL;
716 PPDMDEV pDev = pRegCB->pVM->pdm.s.pDevs;
717 for (; pDev; pDevPrev = pDev, pDev = pDev->pNext)
718 AssertMsgReturn(strcmp(pDev->pReg->szName, pReg->szName),
719 ("Device '%s' already exists\n", pReg->szName),
720 VERR_PDM_DEVICE_NAME_CLASH);
721
722 /*
723 * Allocate new device structure, initialize and insert it into the list.
724 */
725 int rc;
726 pDev = (PPDMDEV)MMR3HeapAlloc(pRegCB->pVM, MM_TAG_PDM_DEVICE, sizeof(*pDev));
727 if (pDev)
728 {
729 pDev->pNext = NULL;
730 pDev->cInstances = 0;
731 pDev->pInstances = NULL;
732 pDev->pReg = pReg;
733 pDev->cchName = (uint32_t)strlen(pReg->szName);
734 rc = CFGMR3QueryStringAllocDef( pRegCB->pCfgNode, "RCSearchPath", &pDev->pszRCSearchPath, NULL);
735 if (RT_SUCCESS(rc))
736 rc = CFGMR3QueryStringAllocDef(pRegCB->pCfgNode, "R0SearchPath", &pDev->pszR0SearchPath, NULL);
737 if (RT_SUCCESS(rc))
738 {
739 if (pDevPrev)
740 pDevPrev->pNext = pDev;
741 else
742 pRegCB->pVM->pdm.s.pDevs = pDev;
743 Log(("PDM: Registered device '%s'\n", pReg->szName));
744 return VINF_SUCCESS;
745 }
746
747 MMR3HeapFree(pDev);
748 }
749 else
750 rc = VERR_NO_MEMORY;
751 return rc;
752}
753
754
755/**
756 * Locates a LUN.
757 *
758 * @returns VBox status code.
759 * @param pVM The cross context VM structure.
760 * @param pszDevice Device name.
761 * @param iInstance Device instance.
762 * @param iLun The Logical Unit to obtain the interface of.
763 * @param ppLun Where to store the pointer to the LUN if found.
764 * @thread Try only do this in EMT...
765 */
766int pdmR3DevFindLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPPDMLUN ppLun)
767{
768 /*
769 * Iterate registered devices looking for the device.
770 */
771 size_t cchDevice = strlen(pszDevice);
772 for (PPDMDEV pDev = pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
773 {
774 if ( pDev->cchName == cchDevice
775 && !memcmp(pDev->pReg->szName, pszDevice, cchDevice))
776 {
777 /*
778 * Iterate device instances.
779 */
780 for (PPDMDEVINS pDevIns = pDev->pInstances; pDevIns; pDevIns = pDevIns->Internal.s.pPerDeviceNextR3)
781 {
782 if (pDevIns->iInstance == iInstance)
783 {
784 /*
785 * Iterate luns.
786 */
787 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
788 {
789 if (pLun->iLun == iLun)
790 {
791 *ppLun = pLun;
792 return VINF_SUCCESS;
793 }
794 }
795 return VERR_PDM_LUN_NOT_FOUND;
796 }
797 }
798 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND;
799 }
800 }
801 return VERR_PDM_DEVICE_NOT_FOUND;
802}
803
804
805/**
806 * Attaches a preconfigured driver to an existing device instance.
807 *
808 * This is used to change drivers and suchlike at runtime.
809 *
810 * @returns VBox status code.
811 * @param pUVM The user mode VM handle.
812 * @param pszDevice Device name.
813 * @param iInstance Device instance.
814 * @param iLun The Logical Unit to obtain the interface of.
815 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
816 * @param ppBase Where to store the base interface pointer. Optional.
817 * @thread EMT
818 */
819VMMR3DECL(int) PDMR3DeviceAttach(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, uint32_t fFlags, PPPDMIBASE ppBase)
820{
821 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
822 PVM pVM = pUVM->pVM;
823 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
824 VM_ASSERT_EMT(pVM);
825 LogFlow(("PDMR3DeviceAttach: pszDevice=%p:{%s} iInstance=%d iLun=%d fFlags=%#x ppBase=%p\n",
826 pszDevice, pszDevice, iInstance, iLun, fFlags, ppBase));
827
828 /*
829 * Find the LUN in question.
830 */
831 PPDMLUN pLun;
832 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
833 if (RT_SUCCESS(rc))
834 {
835 /*
836 * Can we attach anything at runtime?
837 */
838 PPDMDEVINS pDevIns = pLun->pDevIns;
839 if (pDevIns->pReg->pfnAttach)
840 {
841 if (!pLun->pTop)
842 {
843 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
844 rc = pDevIns->pReg->pfnAttach(pDevIns, iLun, fFlags);
845 PDMCritSectLeave(pDevIns->pCritSectRoR3);
846 }
847 else
848 rc = VERR_PDM_DRIVER_ALREADY_ATTACHED;
849 }
850 else
851 rc = VERR_PDM_DEVICE_NO_RT_ATTACH;
852
853 if (ppBase)
854 *ppBase = pLun->pTop ? &pLun->pTop->IBase : NULL;
855 }
856 else if (ppBase)
857 *ppBase = NULL;
858
859 if (ppBase)
860 LogFlow(("PDMR3DeviceAttach: returns %Rrc *ppBase=%p\n", rc, *ppBase));
861 else
862 LogFlow(("PDMR3DeviceAttach: returns %Rrc\n", rc));
863 return rc;
864}
865
866
867/**
868 * Detaches a driver chain from an existing device instance.
869 *
870 * This is used to change drivers and suchlike at runtime.
871 *
872 * @returns VBox status code.
873 * @param pUVM The user mode VM handle.
874 * @param pszDevice Device name.
875 * @param iInstance Device instance.
876 * @param iLun The Logical Unit to obtain the interface of.
877 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
878 * @thread EMT
879 */
880VMMR3DECL(int) PDMR3DeviceDetach(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, uint32_t fFlags)
881{
882 return PDMR3DriverDetach(pUVM, pszDevice, iInstance, iLun, NULL, 0, fFlags);
883}
884
885
886/**
887 * References the critical section associated with a device for the use by a
888 * timer or similar created by the device.
889 *
890 * @returns Pointer to the critical section.
891 * @param pVM The cross context VM structure.
892 * @param pDevIns The device instance in question.
893 *
894 * @internal
895 */
896VMMR3_INT_DECL(PPDMCRITSECT) PDMR3DevGetCritSect(PVM pVM, PPDMDEVINS pDevIns)
897{
898 VM_ASSERT_EMT(pVM);
899 VM_ASSERT_STATE(pVM, VMSTATE_CREATING);
900 AssertPtr(pDevIns);
901
902 PPDMCRITSECT pCritSect = pDevIns->pCritSectRoR3;
903 AssertPtr(pCritSect);
904 pCritSect->s.fUsedByTimerOrSimilar = true;
905
906 return pCritSect;
907}
908
909
910/**
911 * Attaches a preconfigured driver to an existing device or driver instance.
912 *
913 * This is used to change drivers and suchlike at runtime. The driver or device
914 * at the end of the chain will be told to attach to whatever is configured
915 * below it.
916 *
917 * @returns VBox status code.
918 * @param pUVM The user mode VM handle.
919 * @param pszDevice Device name.
920 * @param iInstance Device instance.
921 * @param iLun The Logical Unit to obtain the interface of.
922 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
923 * @param ppBase Where to store the base interface pointer. Optional.
924 *
925 * @thread EMT
926 */
927VMMR3DECL(int) PDMR3DriverAttach(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, uint32_t fFlags, PPPDMIBASE ppBase)
928{
929 LogFlow(("PDMR3DriverAttach: pszDevice=%p:{%s} iInstance=%d iLun=%d fFlags=%#x ppBase=%p\n",
930 pszDevice, pszDevice, iInstance, iLun, fFlags, ppBase));
931 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
932 PVM pVM = pUVM->pVM;
933 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
934 VM_ASSERT_EMT(pVM);
935
936 if (ppBase)
937 *ppBase = NULL;
938
939 /*
940 * Find the LUN in question.
941 */
942 PPDMLUN pLun;
943 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
944 if (RT_SUCCESS(rc))
945 {
946 /*
947 * Anything attached to the LUN?
948 */
949 PPDMDRVINS pDrvIns = pLun->pTop;
950 if (!pDrvIns)
951 {
952 /* No, ask the device to attach to the new stuff. */
953 PPDMDEVINS pDevIns = pLun->pDevIns;
954 if (pDevIns->pReg->pfnAttach)
955 {
956 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
957 rc = pDevIns->pReg->pfnAttach(pDevIns, iLun, fFlags);
958 if (RT_SUCCESS(rc) && ppBase)
959 *ppBase = pLun->pTop ? &pLun->pTop->IBase : NULL;
960 PDMCritSectLeave(pDevIns->pCritSectRoR3);
961 }
962 else
963 rc = VERR_PDM_DEVICE_NO_RT_ATTACH;
964 }
965 else
966 {
967 /* Yes, find the bottom most driver and ask it to attach to the new stuff. */
968 while (pDrvIns->Internal.s.pDown)
969 pDrvIns = pDrvIns->Internal.s.pDown;
970 if (pDrvIns->pReg->pfnAttach)
971 {
972 rc = pDrvIns->pReg->pfnAttach(pDrvIns, fFlags);
973 if (RT_SUCCESS(rc) && ppBase)
974 *ppBase = pDrvIns->Internal.s.pDown
975 ? &pDrvIns->Internal.s.pDown->IBase
976 : NULL;
977 }
978 else
979 rc = VERR_PDM_DRIVER_NO_RT_ATTACH;
980 }
981 }
982
983 if (ppBase)
984 LogFlow(("PDMR3DriverAttach: returns %Rrc *ppBase=%p\n", rc, *ppBase));
985 else
986 LogFlow(("PDMR3DriverAttach: returns %Rrc\n", rc));
987 return rc;
988}
989
990
991/**
992 * Detaches the specified driver instance.
993 *
994 * This is used to replumb drivers at runtime for simulating hot plugging and
995 * media changes.
996 *
997 * This is a superset of PDMR3DeviceDetach. It allows detaching drivers from
998 * any driver or device by specifying the driver to start detaching at. The
999 * only prerequisite is that the driver or device above implements the
1000 * pfnDetach callback (PDMDRVREG / PDMDEVREG).
1001 *
1002 * @returns VBox status code.
1003 * @param pUVM The user mode VM handle.
1004 * @param pszDevice Device name.
1005 * @param iDevIns Device instance.
1006 * @param iLun The Logical Unit in which to look for the driver.
1007 * @param pszDriver The name of the driver which to detach. If NULL
1008 * then the entire driver chain is detatched.
1009 * @param iOccurance The occurrence of that driver in the chain. This is
1010 * usually 0.
1011 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1012 * @thread EMT
1013 */
1014VMMR3DECL(int) PDMR3DriverDetach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun,
1015 const char *pszDriver, unsigned iOccurance, uint32_t fFlags)
1016{
1017 LogFlow(("PDMR3DriverDetach: pszDevice=%p:{%s} iDevIns=%u iLun=%u pszDriver=%p:{%s} iOccurance=%u fFlags=%#x\n",
1018 pszDevice, pszDevice, iDevIns, iLun, pszDriver, pszDriver, iOccurance, fFlags));
1019 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1020 PVM pVM = pUVM->pVM;
1021 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1022 VM_ASSERT_EMT(pVM);
1023 AssertPtr(pszDevice);
1024 AssertPtrNull(pszDriver);
1025 Assert(iOccurance == 0 || pszDriver);
1026 Assert(!(fFlags & ~(PDM_TACH_FLAGS_NOT_HOT_PLUG)));
1027
1028 /*
1029 * Find the LUN in question.
1030 */
1031 PPDMLUN pLun;
1032 int rc = pdmR3DevFindLun(pVM, pszDevice, iDevIns, iLun, &pLun);
1033 if (RT_SUCCESS(rc))
1034 {
1035 /*
1036 * Locate the driver.
1037 */
1038 PPDMDRVINS pDrvIns = pLun->pTop;
1039 if (pDrvIns)
1040 {
1041 if (pszDriver)
1042 {
1043 while (pDrvIns)
1044 {
1045 if (!strcmp(pDrvIns->pReg->szName, pszDriver))
1046 {
1047 if (iOccurance == 0)
1048 break;
1049 iOccurance--;
1050 }
1051 pDrvIns = pDrvIns->Internal.s.pDown;
1052 }
1053 }
1054 if (pDrvIns)
1055 rc = pdmR3DrvDetach(pDrvIns, fFlags);
1056 else
1057 rc = VERR_PDM_DRIVER_INSTANCE_NOT_FOUND;
1058 }
1059 else
1060 rc = VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN;
1061 }
1062
1063 LogFlow(("PDMR3DriverDetach: returns %Rrc\n", rc));
1064 return rc;
1065}
1066
1067
1068/**
1069 * Runtime detach and reattach of a new driver chain or sub chain.
1070 *
1071 * This is intended to be called on a non-EMT thread, this will instantiate the
1072 * new driver (sub-)chain, and then the EMTs will do the actual replumbing. The
1073 * destruction of the old driver chain will be taken care of on the calling
1074 * thread.
1075 *
1076 * @returns VBox status code.
1077 * @param pUVM The user mode VM handle.
1078 * @param pszDevice Device name.
1079 * @param iDevIns Device instance.
1080 * @param iLun The Logical Unit in which to look for the driver.
1081 * @param pszDriver The name of the driver which to detach and replace.
1082 * If NULL then the entire driver chain is to be
1083 * reattached.
1084 * @param iOccurance The occurrence of that driver in the chain. This is
1085 * usually 0.
1086 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1087 * @param pCfg The configuration of the new driver chain that is
1088 * going to be attached. The subtree starts with the
1089 * node containing a Driver key, a Config subtree and
1090 * optionally an AttachedDriver subtree.
1091 * If this parameter is NULL, then this call will work
1092 * like at a non-pause version of PDMR3DriverDetach.
1093 * @param ppBase Where to store the base interface pointer to the new
1094 * driver. Optional.
1095 *
1096 * @thread Any thread. The EMTs will be involved at some point though.
1097 */
1098VMMR3DECL(int) PDMR3DriverReattach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun,
1099 const char *pszDriver, unsigned iOccurance, uint32_t fFlags,
1100 PCFGMNODE pCfg, PPPDMIBASE ppBase)
1101{
1102 NOREF(pUVM); NOREF(pszDevice); NOREF(iDevIns); NOREF(iLun); NOREF(pszDriver); NOREF(iOccurance);
1103 NOREF(fFlags); NOREF(pCfg); NOREF(ppBase);
1104 return VERR_NOT_IMPLEMENTED;
1105}
1106
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