VirtualBox

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

Last change on this file since 93612 was 93609, checked in by vboxsync, 3 years ago

VMM/PDMQueue: Rewrote the queue code to not use the hyper heap and be a bit safer. Added a testcase (driverless). bugref:10093

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