VirtualBox

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

Last change on this file since 80572 was 80542, checked in by vboxsync, 6 years ago

VMM: Fix for problem loading VBoxEhciR0.r0 after PDM device refactoring. bugref:9218

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette