VirtualBox

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

Last change on this file since 106372 was 106061, checked in by vboxsync, 4 months ago

Copyright year updates by scm.

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