VirtualBox

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

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

Recompiler, VMM, Devices: Purge the old APIC and the VBOX_WITH_NEW_APIC define.

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