VirtualBox

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

Last change on this file since 95638 was 93635, checked in by vboxsync, 3 years ago

VMM/PGM,VMM/PDM,VGA: Consolidate the user parameters of the physical access handlers into a single uint64_t value that shouldn't be a pointer, at least not for ring-0 callbacks. Special hack for devices where it's translated from a ring-0 device instance index into a current context PPDMDEVINS (not really tested yet). bugref:10094

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 49.7 KB
Line 
1/* $Id: PDMDevice.cpp 93635 2022-02-07 10:43:45Z 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
393 rc = VMMR3CallR0Emt(pVM, pVM->apCpusR3[0], VMMR0_DO_PDM_DEVICE_CREATE, 0, &Req.Hdr);
394 AssertLogRelMsgRCReturn(rc, ("VMMR0_DO_PDM_DEVICE_CREATE for %s failed: %Rrc\n", pReg->szName, rc), rc);
395
396 pDevIns = Req.pDevInsR3;
397 pCritSect = pDevIns->pCritSectRoR3;
398
399 Assert(pDevIns->Internal.s.fIntFlags & PDMDEVINSINT_FLAGS_R0_ENABLED);
400 AssertLogRelReturn(pDevIns->Internal.s.idxR0Device < PDM_MAX_RING0_DEVICE_INSTANCES, VERR_PDM_DEV_IPE_1);
401 AssertLogRelReturn(pVM->pdm.s.apDevRing0Instances[pDevIns->Internal.s.idxR0Device] == pDevIns, VERR_PDM_DEV_IPE_1);
402 }
403 else
404 {
405 /* The code in this else branch works by the same rules as the PDMR0Device.cpp
406 code, except there is only the ring-3 components of the device instance.
407 Changes here may need to be reflected in PDMR0DEvice.cpp and vice versa! */
408 uint32_t cb = RT_UOFFSETOF_DYN(PDMDEVINS, achInstanceData[pReg->cbInstanceCC]);
409 cb = RT_ALIGN_32(cb, 64);
410 uint32_t const offShared = cb;
411 cb += RT_ALIGN_32(pReg->cbInstanceShared, 64);
412 uint32_t const cbCritSect = RT_ALIGN_32(sizeof(*pCritSect), 64);
413 cb += cbCritSect;
414 uint32_t const cbMsixState = RT_ALIGN_32(pReg->cMaxMsixVectors * 16 + (pReg->cMaxMsixVectors + 7) / 8, _4K);
415 uint32_t const cbPciDev = RT_ALIGN_32(RT_UOFFSETOF_DYN(PDMPCIDEV, abMsixState[cbMsixState]), 64);
416 uint32_t const cPciDevs = RT_MIN(pReg->cMaxPciDevices, 1024);
417 uint32_t const cbPciDevs = cbPciDev * cPciDevs;
418 cb += cbPciDevs;
419 AssertLogRelMsgReturn(cb <= PDM_MAX_DEVICE_INSTANCE_SIZE_R3,
420 ("Device %s total instance size is to big: %u, max %u\n",
421 pReg->szName, cb, PDM_MAX_DEVICE_INSTANCE_SIZE_R3),
422 VERR_ALLOCATION_TOO_BIG);
423
424#if 0 /* Several devices demands cacheline aligned data, if not page aligned. Real problem in NEM mode. */
425 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_DEVICE, cb, (void **)&pDevIns);
426 AssertLogRelMsgRCReturn(rc, ("Failed to allocate %zu bytes of instance data for device '%s'. rc=%Rrc\n",
427 cb, pReg->szName, rc), rc);
428#else
429 pDevIns = (PPDMDEVINS)RTMemPageAllocZ(cb);
430 AssertLogRelMsgReturn(pDevIns, ("Failed to allocate %zu bytes of instance data for device '%s'\n", cb, pReg->szName),
431 VERR_NO_PAGE_MEMORY);
432#endif
433
434 /* Initialize it: */
435 pDevIns->u32Version = PDM_DEVINSR3_VERSION;
436 pDevIns->iInstance = paDevs[i].iInstance;
437 pDevIns->cbRing3 = cb;
438 //pDevIns->fR0Enabled = false;
439 //pDevIns->fRCEnabled = false;
440 pDevIns->pvInstanceDataR3 = (uint8_t *)pDevIns + offShared;
441 pDevIns->pvInstanceDataForR3 = &pDevIns->achInstanceData[0];
442 pCritSect = (PPDMCRITSECT)((uint8_t *)pDevIns + offShared + RT_ALIGN_32(pReg->cbInstanceShared, 64));
443 pDevIns->pCritSectRoR3 = pCritSect;
444 pDevIns->cbPciDev = cbPciDev;
445 pDevIns->cPciDevs = cPciDevs;
446 for (uint32_t iPciDev = 0; iPciDev < cPciDevs; iPciDev++)
447 {
448 PPDMPCIDEV pPciDev = (PPDMPCIDEV)((uint8_t *)pDevIns->pCritSectRoR3 + cbCritSect + cbPciDev * iPciDev);
449 if (iPciDev < RT_ELEMENTS(pDevIns->apPciDevs))
450 pDevIns->apPciDevs[iPciDev] = pPciDev;
451 pPciDev->cbConfig = _4K;
452 pPciDev->cbMsixState = cbMsixState;
453 pPciDev->idxSubDev = (uint16_t)iPciDev;
454 pPciDev->Int.s.idxSubDev = (uint16_t)iPciDev;
455 pPciDev->u32Magic = PDMPCIDEV_MAGIC;
456 }
457 }
458
459 pDevIns->pHlpR3 = fTrusted ? &g_pdmR3DevHlpTrusted : &g_pdmR3DevHlpUnTrusted;
460 pDevIns->pReg = pReg;
461 pDevIns->pCfg = pConfigNode;
462 //pDevIns->IBase.pfnQueryInterface = NULL;
463 //pDevIns->fTracing = 0;
464 pDevIns->idTracing = ++pVM->pdm.s.idTracingDev;
465
466 //pDevIns->Internal.s.pNextR3 = NULL;
467 //pDevIns->Internal.s.pPerDeviceNextR3 = NULL;
468 pDevIns->Internal.s.pDevR3 = paDevs[i].pDev;
469 //pDevIns->Internal.s.pLunsR3 = NULL;
470 //pDevIns->Internal.s.pfnAsyncNotify = NULL;
471 pDevIns->Internal.s.pCfgHandle = paDevs[i].pNode;
472 pDevIns->Internal.s.pVMR3 = pVM;
473#ifdef VBOX_WITH_DBGF_TRACING
474 pDevIns->Internal.s.hDbgfTraceEvtSrc = hDbgfTraceEvtSrc;
475#else
476 pDevIns->Internal.s.hDbgfTraceEvtSrc = NIL_DBGFTRACEREVTSRC;
477#endif
478 //pDevIns->Internal.s.pHeadPciDevR3 = NULL;
479 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_SUSPENDED;
480 //pDevIns->Internal.s.uLastIrqTag = 0;
481
482 rc = pdmR3CritSectInitDeviceAuto(pVM, pDevIns, pCritSect, RT_SRC_POS,
483 "%s#%uAuto", pDevIns->pReg->szName, pDevIns->iInstance);
484 AssertLogRelRCReturn(rc, rc);
485
486 /*
487 * Link it into all the lists.
488 */
489 /* The global instance FIFO. */
490 PPDMDEVINS pPrev1 = pVM->pdm.s.pDevInstances;
491 if (!pPrev1)
492 pVM->pdm.s.pDevInstances = pDevIns;
493 else
494 {
495 while (pPrev1->Internal.s.pNextR3)
496 pPrev1 = pPrev1->Internal.s.pNextR3;
497 pPrev1->Internal.s.pNextR3 = pDevIns;
498 }
499
500 /* The per device instance FIFO. */
501 PPDMDEVINS pPrev2 = paDevs[i].pDev->pInstances;
502 if (!pPrev2)
503 paDevs[i].pDev->pInstances = pDevIns;
504 else
505 {
506 while (pPrev2->Internal.s.pPerDeviceNextR3)
507 pPrev2 = pPrev2->Internal.s.pPerDeviceNextR3;
508 pPrev2->Internal.s.pPerDeviceNextR3 = pDevIns;
509 }
510
511#ifdef VBOX_WITH_DBGF_TRACING
512 /*
513 * Allocate memory for the MMIO/IO port registration tracking if DBGF tracing is enabled.
514 */
515 if (hDbgfTraceEvtSrc != NIL_DBGFTRACEREVTSRC)
516 {
517 pDevIns->Internal.s.paDbgfTraceTrack = (PPDMDEVINSDBGFTRACK)RTMemAllocZ(PDM_MAX_DEVICE_DBGF_TRACING_TRACK);
518 if (!pDevIns->Internal.s.paDbgfTraceTrack)
519 {
520 LogRel(("PDM: Failed to construct '%s'/%d! %Rra\n", pDevIns->pReg->szName, pDevIns->iInstance, VERR_NO_MEMORY));
521 if (VMR3GetErrorCount(pVM->pUVM) == 0)
522 VMSetError(pVM, rc, RT_SRC_POS, "Failed to construct device '%s' instance #%u",
523 pDevIns->pReg->szName, pDevIns->iInstance);
524 paDevs[i].pDev->cInstances--;
525 return VERR_NO_MEMORY;
526 }
527
528 pDevIns->Internal.s.idxDbgfTraceTrackNext = 0;
529 pDevIns->Internal.s.cDbgfTraceTrackMax = PDM_MAX_DEVICE_DBGF_TRACING_TRACK / sizeof(PDMDEVINSDBGFTRACK);
530 pDevIns->pHlpR3 = &g_pdmR3DevHlpTracing;
531 }
532#endif
533
534 /*
535 * Call the constructor.
536 */
537 paDevs[i].pDev->cInstances++;
538 Log(("PDM: Constructing device '%s' instance %d...\n", pDevIns->pReg->szName, pDevIns->iInstance));
539 rc = pDevIns->pReg->pfnConstruct(pDevIns, pDevIns->iInstance, pDevIns->pCfg);
540 if (RT_FAILURE(rc))
541 {
542 LogRel(("PDM: Failed to construct '%s'/%d! %Rra\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
543 if (VMR3GetErrorCount(pVM->pUVM) == 0)
544 VMSetError(pVM, rc, RT_SRC_POS, "Failed to construct device '%s' instance #%u",
545 pDevIns->pReg->szName, pDevIns->iInstance);
546 /* Because we're damn lazy, the destructor will be called even if
547 the constructor fails. So, no unlinking. */
548 paDevs[i].pDev->cInstances--;
549 return rc == VERR_VERSION_MISMATCH ? VERR_PDM_DEVICE_VERSION_MISMATCH : rc;
550 }
551
552 /*
553 * Call the ring-0 constructor if applicable.
554 */
555 if (fR0Enabled)
556 {
557 PDMDEVICEGENCALLREQ Req;
558 RT_ZERO(Req.Params);
559 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
560 Req.Hdr.cbReq = sizeof(Req);
561 Req.enmCall = PDMDEVICEGENCALL_CONSTRUCT;
562 Req.idxR0Device = pDevIns->Internal.s.idxR0Device;
563 Req.pDevInsR3 = pDevIns;
564 rc = VMMR3CallR0Emt(pVM, pVM->apCpusR3[0], VMMR0_DO_PDM_DEVICE_GEN_CALL, 0, &Req.Hdr);
565 pDevIns->Internal.s.fIntFlags |= PDMDEVINSINT_FLAGS_R0_CONTRUCT;
566 if (RT_FAILURE(rc))
567 {
568 LogRel(("PDM: Failed to construct (ring-0) '%s'/%d! %Rra\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
569 if (VMR3GetErrorCount(pVM->pUVM) == 0)
570 VMSetError(pVM, rc, RT_SRC_POS, "The ring-0 constructor of device '%s' instance #%u failed",
571 pDevIns->pReg->szName, pDevIns->iInstance);
572 paDevs[i].pDev->cInstances--;
573 return rc == VERR_VERSION_MISMATCH ? VERR_PDM_DEVICE_VERSION_MISMATCH : rc;
574 }
575 }
576
577 } /* for device instances */
578
579#ifdef VBOX_WITH_USB
580 /* ditto for USB Devices. */
581 rc = pdmR3UsbInstantiateDevices(pVM);
582 if (RT_FAILURE(rc))
583 return rc;
584#endif
585
586 LogFlow(("pdmR3DevInit: returns %Rrc\n", VINF_SUCCESS));
587 return VINF_SUCCESS;
588}
589
590
591/**
592 * Performs the init complete callback after ring-0 and raw-mode has been
593 * initialized.
594 *
595 * @returns VBox status code.
596 * @param pVM The cross context VM structure.
597 */
598int pdmR3DevInitComplete(PVM pVM)
599{
600 int rc;
601
602 /*
603 * Iterate thru the device instances and work the callback.
604 */
605 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
606 {
607 if (pDevIns->pReg->pfnInitComplete)
608 {
609 PDMCritSectEnter(pVM, pDevIns->pCritSectRoR3, VERR_IGNORED);
610 rc = pDevIns->pReg->pfnInitComplete(pDevIns);
611 PDMCritSectLeave(pVM, pDevIns->pCritSectRoR3);
612 if (RT_FAILURE(rc))
613 {
614 AssertMsgFailed(("InitComplete on device '%s'/%d failed with rc=%Rrc\n",
615 pDevIns->pReg->szName, pDevIns->iInstance, rc));
616 return rc;
617 }
618 }
619 }
620
621#ifdef VBOX_WITH_USB
622 rc = pdmR3UsbVMInitComplete(pVM);
623 if (RT_FAILURE(rc))
624 {
625 Log(("pdmR3DevInit: returns %Rrc\n", rc));
626 return rc;
627 }
628#endif
629
630 LogFlow(("pdmR3DevInit: returns %Rrc\n", VINF_SUCCESS));
631 return VINF_SUCCESS;
632}
633
634
635/**
636 * Lookups a device structure by name.
637 * @internal
638 */
639PPDMDEV pdmR3DevLookup(PVM pVM, const char *pszName)
640{
641 size_t cchName = strlen(pszName);
642 for (PPDMDEV pDev = pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
643 if ( pDev->cchName == cchName
644 && !strcmp(pDev->pReg->szName, pszName))
645 return pDev;
646 return NULL;
647}
648
649
650/**
651 * Loads the device modules.
652 *
653 * @returns VBox status code.
654 * @param pVM The cross context VM structure.
655 */
656static int pdmR3DevLoadModules(PVM pVM)
657{
658 /*
659 * Initialize the callback structure.
660 */
661 PDMDEVREGCBINT RegCB;
662 RegCB.Core.u32Version = PDM_DEVREG_CB_VERSION;
663 RegCB.Core.pfnRegister = pdmR3DevReg_Register;
664 RegCB.pVM = pVM;
665 RegCB.pCfgNode = NULL;
666
667 /*
668 * Register the internal VMM APIC device.
669 */
670 int rc = pdmR3DevReg_Register(&RegCB.Core, &g_DeviceAPIC);
671 AssertRCReturn(rc, rc);
672
673 /*
674 * Load the builtin module.
675 */
676 PCFGMNODE pDevicesNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "PDM/Devices");
677 bool fLoadBuiltin;
678 rc = CFGMR3QueryBool(pDevicesNode, "LoadBuiltin", &fLoadBuiltin);
679 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
680 fLoadBuiltin = true;
681 else if (RT_FAILURE(rc))
682 {
683 AssertMsgFailed(("Configuration error: Querying boolean \"LoadBuiltin\" failed with %Rrc\n", rc));
684 return rc;
685 }
686 if (fLoadBuiltin)
687 {
688 /* make filename */
689 char *pszFilename = pdmR3FileR3("VBoxDD", true /*fShared*/);
690 if (!pszFilename)
691 return VERR_NO_TMP_MEMORY;
692 rc = pdmR3DevLoad(pVM, &RegCB, pszFilename, "VBoxDD");
693 RTMemTmpFree(pszFilename);
694 if (RT_FAILURE(rc))
695 return rc;
696
697 /* make filename */
698 pszFilename = pdmR3FileR3("VBoxDD2", true /*fShared*/);
699 if (!pszFilename)
700 return VERR_NO_TMP_MEMORY;
701 rc = pdmR3DevLoad(pVM, &RegCB, pszFilename, "VBoxDD2");
702 RTMemTmpFree(pszFilename);
703 if (RT_FAILURE(rc))
704 return rc;
705 }
706
707 /*
708 * Load additional device modules.
709 */
710 PCFGMNODE pCur;
711 for (pCur = CFGMR3GetFirstChild(pDevicesNode); pCur; pCur = CFGMR3GetNextChild(pCur))
712 {
713 /*
714 * Get the name and path.
715 */
716 char szName[PDMMOD_NAME_LEN];
717 rc = CFGMR3GetName(pCur, &szName[0], sizeof(szName));
718 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
719 {
720 AssertMsgFailed(("configuration error: The module name is too long, cchName=%zu.\n", CFGMR3GetNameLen(pCur)));
721 return VERR_PDM_MODULE_NAME_TOO_LONG;
722 }
723 else if (RT_FAILURE(rc))
724 {
725 AssertMsgFailed(("CFGMR3GetName -> %Rrc.\n", rc));
726 return rc;
727 }
728
729 /* the path is optional, if no path the module name + path is used. */
730 char szFilename[RTPATH_MAX];
731 rc = CFGMR3QueryString(pCur, "Path", &szFilename[0], sizeof(szFilename));
732 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
733 strcpy(szFilename, szName);
734 else if (RT_FAILURE(rc))
735 {
736 AssertMsgFailed(("configuration error: Failure to query the module path, rc=%Rrc.\n", rc));
737 return rc;
738 }
739
740 /* prepend path? */
741 if (!RTPathHavePath(szFilename))
742 {
743 char *psz = pdmR3FileR3(szFilename, false /*fShared*/);
744 if (!psz)
745 return VERR_NO_TMP_MEMORY;
746 size_t cch = strlen(psz) + 1;
747 if (cch > sizeof(szFilename))
748 {
749 RTMemTmpFree(psz);
750 AssertMsgFailed(("Filename too long! cch=%d '%s'\n", cch, psz));
751 return VERR_FILENAME_TOO_LONG;
752 }
753 memcpy(szFilename, psz, cch);
754 RTMemTmpFree(psz);
755 }
756
757 /*
758 * Load the module and register it's devices.
759 */
760 RegCB.pCfgNode = pCur;
761 rc = pdmR3DevLoad(pVM, &RegCB, szFilename, szName);
762 if (RT_FAILURE(rc))
763 return rc;
764 }
765
766 return VINF_SUCCESS;
767}
768
769
770/**
771 * Loads one device module and call the registration entry point.
772 *
773 * @returns VBox status code.
774 * @param pVM The cross context VM structure.
775 * @param pRegCB The registration callback stuff.
776 * @param pszFilename Module filename.
777 * @param pszName Module name.
778 */
779static int pdmR3DevLoad(PVM pVM, PPDMDEVREGCBINT pRegCB, const char *pszFilename, const char *pszName)
780{
781 /*
782 * Load it.
783 */
784 int rc = pdmR3LoadR3U(pVM->pUVM, pszFilename, pszName);
785 if (RT_SUCCESS(rc))
786 {
787 /*
788 * Get the registration export and call it.
789 */
790 FNPDMVBOXDEVICESREGISTER *pfnVBoxDevicesRegister;
791 rc = PDMR3LdrGetSymbolR3(pVM, pszName, "VBoxDevicesRegister", (void **)&pfnVBoxDevicesRegister);
792 if (RT_SUCCESS(rc))
793 {
794 Log(("PDM: Calling VBoxDevicesRegister (%p) of %s (%s)\n", pfnVBoxDevicesRegister, pszName, pszFilename));
795 rc = pfnVBoxDevicesRegister(&pRegCB->Core, VBOX_VERSION);
796 if (RT_SUCCESS(rc))
797 Log(("PDM: Successfully loaded device module %s (%s).\n", pszName, pszFilename));
798 else
799 {
800 VMR3SetError(pVM->pUVM, rc, RT_SRC_POS, "VBoxDevicesRegister failed with rc=%Rrc for module %s (%s)",
801 rc, pszName, pszFilename);
802 AssertMsgFailed(("VBoxDevicesRegister failed with rc=%Rrc for module %s (%s)\n", rc, pszName, pszFilename));
803 }
804 }
805 else
806 {
807 AssertMsgFailed(("Failed to locate 'VBoxDevicesRegister' in %s (%s) rc=%Rrc\n", pszName, pszFilename, rc));
808 if (rc == VERR_SYMBOL_NOT_FOUND)
809 rc = VERR_PDM_NO_REGISTRATION_EXPORT;
810 VMR3SetError(pVM->pUVM, rc, RT_SRC_POS, "Failed to locate 'VBoxDevicesRegister' in %s (%s) rc=%Rrc",
811 pszName, pszFilename, rc);
812 }
813 }
814 else
815 AssertMsgFailed(("Failed to load %s %s!\n", pszFilename, pszName));
816 return rc;
817}
818
819
820/**
821 * @interface_method_impl{PDMDEVREGCB,pfnRegister}
822 */
823static DECLCALLBACK(int) pdmR3DevReg_Register(PPDMDEVREGCB pCallbacks, PCPDMDEVREG pReg)
824{
825 /*
826 * Validate the registration structure.
827 */
828 Assert(pReg);
829 AssertMsgReturn(pReg->u32Version == PDM_DEVREG_VERSION,
830 ("Unknown struct version %#x!\n", pReg->u32Version),
831 VERR_PDM_UNKNOWN_DEVREG_VERSION);
832
833 AssertMsgReturn( pReg->szName[0]
834 && strlen(pReg->szName) < sizeof(pReg->szName)
835 && pdmR3IsValidName(pReg->szName),
836 ("Invalid name '%.*s'\n", sizeof(pReg->szName), pReg->szName),
837 VERR_PDM_INVALID_DEVICE_REGISTRATION);
838 AssertMsgReturn( !(pReg->fFlags & PDM_DEVREG_FLAGS_RC)
839 || ( pReg->pszRCMod[0]
840 && strlen(pReg->pszRCMod) < RT_SIZEOFMEMB(PDMDEVICECREATEREQ, szModName)),
841 ("Invalid GC module name '%s' - (Device %s)\n", pReg->pszRCMod, pReg->szName),
842 VERR_PDM_INVALID_DEVICE_REGISTRATION);
843 AssertMsgReturn( !(pReg->fFlags & PDM_DEVREG_FLAGS_R0)
844 || ( pReg->pszR0Mod[0]
845 && strlen(pReg->pszR0Mod) < RT_SIZEOFMEMB(PDMDEVICECREATEREQ, szModName)),
846 ("Invalid R0 module name '%s' - (Device %s)\n", pReg->pszR0Mod, pReg->szName),
847 VERR_PDM_INVALID_DEVICE_REGISTRATION);
848 AssertMsgReturn((pReg->fFlags & PDM_DEVREG_FLAGS_HOST_BITS_MASK) == PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT,
849 ("Invalid host bits flags! fFlags=%#x (Device %s)\n", pReg->fFlags, pReg->szName),
850 VERR_PDM_INVALID_DEVICE_HOST_BITS);
851 AssertMsgReturn((pReg->fFlags & PDM_DEVREG_FLAGS_GUEST_BITS_MASK),
852 ("Invalid guest bits flags! fFlags=%#x (Device %s)\n", pReg->fFlags, pReg->szName),
853 VERR_PDM_INVALID_DEVICE_REGISTRATION);
854 AssertMsgReturn(pReg->fClass,
855 ("No class! (Device %s)\n", pReg->szName),
856 VERR_PDM_INVALID_DEVICE_REGISTRATION);
857 AssertMsgReturn(pReg->cMaxInstances > 0,
858 ("Max instances %u! (Device %s)\n", pReg->cMaxInstances, pReg->szName),
859 VERR_PDM_INVALID_DEVICE_REGISTRATION);
860 uint32_t const cbMaxInstance = pReg->fFlags & (PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0)
861 ? PDM_MAX_DEVICE_INSTANCE_SIZE : PDM_MAX_DEVICE_INSTANCE_SIZE_R3;
862 AssertMsgReturn(pReg->cbInstanceShared <= cbMaxInstance,
863 ("Instance size %u bytes! (Max %u; Device %s)\n", pReg->cbInstanceShared, cbMaxInstance, pReg->szName),
864 VERR_PDM_INVALID_DEVICE_REGISTRATION);
865 AssertMsgReturn(pReg->cbInstanceCC <= cbMaxInstance,
866 ("Instance size %d bytes! (Max %u; Device %s)\n", pReg->cbInstanceCC, cbMaxInstance, pReg->szName),
867 VERR_PDM_INVALID_DEVICE_REGISTRATION);
868 AssertMsgReturn(pReg->pfnConstruct,
869 ("No constructor! (Device %s)\n", pReg->szName),
870 VERR_PDM_INVALID_DEVICE_REGISTRATION);
871 AssertLogRelMsgReturn((pReg->fFlags & PDM_DEVREG_FLAGS_GUEST_BITS_MASK) == PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT,
872 ("PDM: Rejected device '%s' because it didn't match the guest bits.\n", pReg->szName),
873 VERR_PDM_INVALID_DEVICE_GUEST_BITS);
874 AssertLogRelMsg(pReg->u32VersionEnd == PDM_DEVREG_VERSION,
875 ("u32VersionEnd=%#x, expected %#x. (szName=%s)\n",
876 pReg->u32VersionEnd, PDM_DEVREG_VERSION, pReg->szName));
877 AssertLogRelMsgReturn(pReg->cMaxPciDevices <= 8, ("%#x (szName=%s)\n", pReg->cMaxPciDevices, pReg->szName),
878 VERR_PDM_INVALID_DEVICE_REGISTRATION);
879 AssertLogRelMsgReturn(pReg->cMaxMsixVectors <= VBOX_MSIX_MAX_ENTRIES,
880 ("%#x (szName=%s)\n", pReg->cMaxMsixVectors, pReg->szName),
881 VERR_PDM_INVALID_DEVICE_REGISTRATION);
882 AssertLogRelMsgReturn(pReg->fFlags & PDM_DEVREG_FLAGS_NEW_STYLE /* the flag is required now */,
883 ("PDM_DEVREG_FLAGS_NEW_STYLE not set for szName=%s!\n", pReg->szName),
884 VERR_PDM_INVALID_DEVICE_REGISTRATION);
885
886 /*
887 * Check for duplicate and find FIFO entry at the same time.
888 */
889 PCPDMDEVREGCBINT pRegCB = (PCPDMDEVREGCBINT)pCallbacks;
890 PPDMDEV pDevPrev = NULL;
891 PPDMDEV pDev = pRegCB->pVM->pdm.s.pDevs;
892 for (; pDev; pDevPrev = pDev, pDev = pDev->pNext)
893 AssertMsgReturn(strcmp(pDev->pReg->szName, pReg->szName),
894 ("Device '%s' already exists\n", pReg->szName),
895 VERR_PDM_DEVICE_NAME_CLASH);
896
897 /*
898 * Allocate new device structure, initialize and insert it into the list.
899 */
900 int rc;
901 pDev = (PPDMDEV)MMR3HeapAlloc(pRegCB->pVM, MM_TAG_PDM_DEVICE, sizeof(*pDev));
902 if (pDev)
903 {
904 pDev->pNext = NULL;
905 pDev->cInstances = 0;
906 pDev->pInstances = NULL;
907 pDev->pReg = pReg;
908 pDev->cchName = (uint32_t)strlen(pReg->szName);
909 rc = CFGMR3QueryStringAllocDef( pRegCB->pCfgNode, "RCSearchPath", &pDev->pszRCSearchPath, NULL);
910 if (RT_SUCCESS(rc))
911 rc = CFGMR3QueryStringAllocDef(pRegCB->pCfgNode, "R0SearchPath", &pDev->pszR0SearchPath, NULL);
912 if (RT_SUCCESS(rc))
913 {
914 if (pDevPrev)
915 pDevPrev->pNext = pDev;
916 else
917 pRegCB->pVM->pdm.s.pDevs = pDev;
918 Log(("PDM: Registered device '%s'\n", pReg->szName));
919 return VINF_SUCCESS;
920 }
921
922 MMR3HeapFree(pDev);
923 }
924 else
925 rc = VERR_NO_MEMORY;
926 return rc;
927}
928
929
930/**
931 * Locates a LUN.
932 *
933 * @returns VBox status code.
934 * @param pVM The cross context VM structure.
935 * @param pszDevice Device name.
936 * @param iInstance Device instance.
937 * @param iLun The Logical Unit to obtain the interface of.
938 * @param ppLun Where to store the pointer to the LUN if found.
939 * @thread Try only do this in EMT...
940 */
941int pdmR3DevFindLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPPDMLUN ppLun)
942{
943 /*
944 * Iterate registered devices looking for the device.
945 */
946 size_t cchDevice = strlen(pszDevice);
947 for (PPDMDEV pDev = pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
948 {
949 if ( pDev->cchName == cchDevice
950 && !memcmp(pDev->pReg->szName, pszDevice, cchDevice))
951 {
952 /*
953 * Iterate device instances.
954 */
955 for (PPDMDEVINS pDevIns = pDev->pInstances; pDevIns; pDevIns = pDevIns->Internal.s.pPerDeviceNextR3)
956 {
957 if (pDevIns->iInstance == iInstance)
958 {
959 /*
960 * Iterate luns.
961 */
962 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
963 {
964 if (pLun->iLun == iLun)
965 {
966 *ppLun = pLun;
967 return VINF_SUCCESS;
968 }
969 }
970 return VERR_PDM_LUN_NOT_FOUND;
971 }
972 }
973 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND;
974 }
975 }
976 return VERR_PDM_DEVICE_NOT_FOUND;
977}
978
979
980/**
981 * Attaches a preconfigured driver to an existing device instance.
982 *
983 * This is used to change drivers and suchlike at runtime.
984 *
985 * @returns VBox status code.
986 * @param pUVM The user mode VM handle.
987 * @param pszDevice Device name.
988 * @param iInstance Device instance.
989 * @param iLun The Logical Unit to obtain the interface of.
990 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
991 * @param ppBase Where to store the base interface pointer. Optional.
992 * @thread EMT
993 */
994VMMR3DECL(int) PDMR3DeviceAttach(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, uint32_t fFlags, PPPDMIBASE ppBase)
995{
996 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
997 PVM pVM = pUVM->pVM;
998 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
999 VM_ASSERT_EMT(pVM);
1000 LogFlow(("PDMR3DeviceAttach: pszDevice=%p:{%s} iInstance=%d iLun=%d fFlags=%#x ppBase=%p\n",
1001 pszDevice, pszDevice, iInstance, iLun, fFlags, ppBase));
1002
1003 /*
1004 * Find the LUN in question.
1005 */
1006 PPDMLUN pLun;
1007 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
1008 if (RT_SUCCESS(rc))
1009 {
1010 /*
1011 * Can we attach anything at runtime?
1012 */
1013 PPDMDEVINS pDevIns = pLun->pDevIns;
1014 if (pDevIns->pReg->pfnAttach)
1015 {
1016 if (!pLun->pTop)
1017 {
1018 PDMCritSectEnter(pVM, pDevIns->pCritSectRoR3, VERR_IGNORED);
1019 rc = pDevIns->pReg->pfnAttach(pDevIns, iLun, fFlags);
1020 PDMCritSectLeave(pVM, pDevIns->pCritSectRoR3);
1021 }
1022 else
1023 rc = VERR_PDM_DRIVER_ALREADY_ATTACHED;
1024 }
1025 else
1026 rc = VERR_PDM_DEVICE_NO_RT_ATTACH;
1027
1028 if (ppBase)
1029 *ppBase = pLun->pTop ? &pLun->pTop->IBase : NULL;
1030 }
1031 else if (ppBase)
1032 *ppBase = NULL;
1033
1034 if (ppBase)
1035 LogFlow(("PDMR3DeviceAttach: returns %Rrc *ppBase=%p\n", rc, *ppBase));
1036 else
1037 LogFlow(("PDMR3DeviceAttach: returns %Rrc\n", rc));
1038 return rc;
1039}
1040
1041
1042/**
1043 * Detaches a driver chain from an existing device instance.
1044 *
1045 * This is used to change drivers and suchlike at runtime.
1046 *
1047 * @returns VBox status code.
1048 * @param pUVM The user mode VM handle.
1049 * @param pszDevice Device name.
1050 * @param iInstance Device instance.
1051 * @param iLun The Logical Unit to obtain the interface of.
1052 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1053 * @thread EMT
1054 */
1055VMMR3DECL(int) PDMR3DeviceDetach(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, uint32_t fFlags)
1056{
1057 return PDMR3DriverDetach(pUVM, pszDevice, iInstance, iLun, NULL, 0, fFlags);
1058}
1059
1060
1061/**
1062 * References the critical section associated with a device for the use by a
1063 * timer or similar created by the device.
1064 *
1065 * @returns Pointer to the critical section.
1066 * @param pVM The cross context VM structure.
1067 * @param pDevIns The device instance in question.
1068 *
1069 * @internal
1070 */
1071VMMR3_INT_DECL(PPDMCRITSECT) PDMR3DevGetCritSect(PVM pVM, PPDMDEVINS pDevIns)
1072{
1073 VM_ASSERT_EMT(pVM); RT_NOREF_PV(pVM);
1074 VM_ASSERT_STATE(pVM, VMSTATE_CREATING);
1075 AssertPtr(pDevIns);
1076
1077 PPDMCRITSECT pCritSect = pDevIns->pCritSectRoR3;
1078 AssertPtr(pCritSect);
1079 pCritSect->s.fUsedByTimerOrSimilar = true;
1080
1081 return pCritSect;
1082}
1083
1084
1085/**
1086 * Attaches a preconfigured driver to an existing device or driver instance.
1087 *
1088 * This is used to change drivers and suchlike at runtime. The driver or device
1089 * at the end of the chain will be told to attach to whatever is configured
1090 * below it.
1091 *
1092 * @returns VBox status code.
1093 * @param pUVM The user mode VM handle.
1094 * @param pszDevice Device name.
1095 * @param iInstance Device instance.
1096 * @param iLun The Logical Unit to obtain the interface of.
1097 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1098 * @param ppBase Where to store the base interface pointer. Optional.
1099 *
1100 * @thread EMT
1101 */
1102VMMR3DECL(int) PDMR3DriverAttach(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, uint32_t fFlags, PPPDMIBASE ppBase)
1103{
1104 LogFlow(("PDMR3DriverAttach: pszDevice=%p:{%s} iInstance=%d iLun=%d fFlags=%#x ppBase=%p\n",
1105 pszDevice, pszDevice, iInstance, iLun, fFlags, ppBase));
1106 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1107 PVM pVM = pUVM->pVM;
1108 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1109 VM_ASSERT_EMT(pVM);
1110
1111 if (ppBase)
1112 *ppBase = NULL;
1113
1114 /*
1115 * Find the LUN in question.
1116 */
1117 PPDMLUN pLun;
1118 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
1119 if (RT_SUCCESS(rc))
1120 {
1121 /*
1122 * Anything attached to the LUN?
1123 */
1124 PPDMDRVINS pDrvIns = pLun->pTop;
1125 if (!pDrvIns)
1126 {
1127 /* No, ask the device to attach to the new stuff. */
1128 PPDMDEVINS pDevIns = pLun->pDevIns;
1129 if (pDevIns->pReg->pfnAttach)
1130 {
1131 PDMCritSectEnter(pVM, pDevIns->pCritSectRoR3, VERR_IGNORED);
1132 rc = pDevIns->pReg->pfnAttach(pDevIns, iLun, fFlags);
1133 if (RT_SUCCESS(rc) && ppBase)
1134 *ppBase = pLun->pTop ? &pLun->pTop->IBase : NULL;
1135 PDMCritSectLeave(pVM, pDevIns->pCritSectRoR3);
1136 }
1137 else
1138 rc = VERR_PDM_DEVICE_NO_RT_ATTACH;
1139 }
1140 else
1141 {
1142 /* Yes, find the bottom most driver and ask it to attach to the new stuff. */
1143 while (pDrvIns->Internal.s.pDown)
1144 pDrvIns = pDrvIns->Internal.s.pDown;
1145 if (pDrvIns->pReg->pfnAttach)
1146 {
1147 rc = pDrvIns->pReg->pfnAttach(pDrvIns, fFlags);
1148 if (RT_SUCCESS(rc) && ppBase)
1149 *ppBase = pDrvIns->Internal.s.pDown
1150 ? &pDrvIns->Internal.s.pDown->IBase
1151 : NULL;
1152 }
1153 else
1154 rc = VERR_PDM_DRIVER_NO_RT_ATTACH;
1155 }
1156 }
1157
1158 if (ppBase)
1159 LogFlow(("PDMR3DriverAttach: returns %Rrc *ppBase=%p\n", rc, *ppBase));
1160 else
1161 LogFlow(("PDMR3DriverAttach: returns %Rrc\n", rc));
1162 return rc;
1163}
1164
1165
1166/**
1167 * Detaches the specified driver instance.
1168 *
1169 * This is used to replumb drivers at runtime for simulating hot plugging and
1170 * media changes.
1171 *
1172 * This is a superset of PDMR3DeviceDetach. It allows detaching drivers from
1173 * any driver or device by specifying the driver to start detaching at. The
1174 * only prerequisite is that the driver or device above implements the
1175 * pfnDetach callback (PDMDRVREG / PDMDEVREG).
1176 *
1177 * @returns VBox status code.
1178 * @param pUVM The user mode VM handle.
1179 * @param pszDevice Device name.
1180 * @param iDevIns Device instance.
1181 * @param iLun The Logical Unit in which to look for the driver.
1182 * @param pszDriver The name of the driver which to detach. If NULL
1183 * then the entire driver chain is detatched.
1184 * @param iOccurrence The occurrence of that driver in the chain. This is
1185 * usually 0.
1186 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1187 * @thread EMT
1188 */
1189VMMR3DECL(int) PDMR3DriverDetach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun,
1190 const char *pszDriver, unsigned iOccurrence, uint32_t fFlags)
1191{
1192 LogFlow(("PDMR3DriverDetach: pszDevice=%p:{%s} iDevIns=%u iLun=%u pszDriver=%p:{%s} iOccurrence=%u fFlags=%#x\n",
1193 pszDevice, pszDevice, iDevIns, iLun, pszDriver, pszDriver, iOccurrence, fFlags));
1194 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1195 PVM pVM = pUVM->pVM;
1196 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1197 VM_ASSERT_EMT(pVM);
1198 AssertPtr(pszDevice);
1199 AssertPtrNull(pszDriver);
1200 Assert(iOccurrence == 0 || pszDriver);
1201 Assert(!(fFlags & ~(PDM_TACH_FLAGS_NOT_HOT_PLUG)));
1202
1203 /*
1204 * Find the LUN in question.
1205 */
1206 PPDMLUN pLun;
1207 int rc = pdmR3DevFindLun(pVM, pszDevice, iDevIns, iLun, &pLun);
1208 if (RT_SUCCESS(rc))
1209 {
1210 /*
1211 * Locate the driver.
1212 */
1213 PPDMDRVINS pDrvIns = pLun->pTop;
1214 if (pDrvIns)
1215 {
1216 if (pszDriver)
1217 {
1218 while (pDrvIns)
1219 {
1220 if (!strcmp(pDrvIns->pReg->szName, pszDriver))
1221 {
1222 if (iOccurrence == 0)
1223 break;
1224 iOccurrence--;
1225 }
1226 pDrvIns = pDrvIns->Internal.s.pDown;
1227 }
1228 }
1229 if (pDrvIns)
1230 rc = pdmR3DrvDetach(pDrvIns, fFlags);
1231 else
1232 rc = VERR_PDM_DRIVER_INSTANCE_NOT_FOUND;
1233 }
1234 else
1235 rc = VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN;
1236 }
1237
1238 LogFlow(("PDMR3DriverDetach: returns %Rrc\n", rc));
1239 return rc;
1240}
1241
1242
1243/**
1244 * Runtime detach and reattach of a new driver chain or sub chain.
1245 *
1246 * This is intended to be called on a non-EMT thread, this will instantiate the
1247 * new driver (sub-)chain, and then the EMTs will do the actual replumbing. The
1248 * destruction of the old driver chain will be taken care of on the calling
1249 * thread.
1250 *
1251 * @returns VBox status code.
1252 * @param pUVM The user mode VM handle.
1253 * @param pszDevice Device name.
1254 * @param iDevIns Device instance.
1255 * @param iLun The Logical Unit in which to look for the driver.
1256 * @param pszDriver The name of the driver which to detach and replace.
1257 * If NULL then the entire driver chain is to be
1258 * reattached.
1259 * @param iOccurrence The occurrence of that driver in the chain. This is
1260 * usually 0.
1261 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1262 * @param pCfg The configuration of the new driver chain that is
1263 * going to be attached. The subtree starts with the
1264 * node containing a Driver key, a Config subtree and
1265 * optionally an AttachedDriver subtree.
1266 * If this parameter is NULL, then this call will work
1267 * like at a non-pause version of PDMR3DriverDetach.
1268 * @param ppBase Where to store the base interface pointer to the new
1269 * driver. Optional.
1270 *
1271 * @thread Any thread. The EMTs will be involved at some point though.
1272 */
1273VMMR3DECL(int) PDMR3DriverReattach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun,
1274 const char *pszDriver, unsigned iOccurrence, uint32_t fFlags,
1275 PCFGMNODE pCfg, PPPDMIBASE ppBase)
1276{
1277 NOREF(pUVM); NOREF(pszDevice); NOREF(iDevIns); NOREF(iLun); NOREF(pszDriver); NOREF(iOccurrence);
1278 NOREF(fFlags); NOREF(pCfg); NOREF(ppBase);
1279 return VERR_NOT_IMPLEMENTED;
1280}
1281
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