VirtualBox

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

Last change on this file since 81031 was 81031, checked in by vboxsync, 5 years ago

PDM,Devices: Moving the PDMPCIDEV structures into the PDMDEVINS allocation. Preps for extending the config space to 4KB. bugref:9218

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