VirtualBox

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

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