VirtualBox

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

Last change on this file since 109008 was 108968, checked in by vboxsync, 7 days ago

VMM,Main,Devices: Respect VBOX_VMM_TARGET_ARMV8 correctly on amd64 hosts (for IEM debugging purposes). jiraref:VBP-1598

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette