VirtualBox

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

Last change on this file since 43667 was 41965, checked in by vboxsync, 12 years ago

VMM: ran scm. Mostly svn:keywords changes (adding Revision).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 39.0 KB
Line 
1/* $Id: PDMDevice.cpp 41965 2012-06-29 02:52:49Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device and Driver Manager, Device parts.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_PDM_DEVICE
23#include "PDMInternal.h"
24#include <VBox/vmm/pdm.h>
25#include <VBox/vmm/mm.h>
26#include <VBox/vmm/pgm.h>
27#include <VBox/vmm/iom.h>
28#include <VBox/vmm/cfgm.h>
29#ifdef VBOX_WITH_REM
30# include <VBox/vmm/rem.h>
31#endif
32#include <VBox/vmm/dbgf.h>
33#include <VBox/vmm/vm.h>
34#include <VBox/vmm/vmm.h>
35
36#include <VBox/version.h>
37#include <VBox/log.h>
38#include <VBox/err.h>
39#include <iprt/alloc.h>
40#include <iprt/alloca.h>
41#include <iprt/asm.h>
42#include <iprt/assert.h>
43#include <iprt/path.h>
44#include <iprt/semaphore.h>
45#include <iprt/string.h>
46#include <iprt/thread.h>
47
48
49/*******************************************************************************
50* Structures and Typedefs *
51*******************************************************************************/
52/**
53 * Internal callback structure pointer.
54 * The main purpose is to define the extra data we associate
55 * with PDMDEVREGCB so we can find the VM instance and so on.
56 */
57typedef struct PDMDEVREGCBINT
58{
59 /** The callback structure. */
60 PDMDEVREGCB Core;
61 /** A bit of padding. */
62 uint32_t u32[4];
63 /** VM Handle. */
64 PVM pVM;
65 /** Pointer to the configuration node the registrations should be
66 * associated with. Can be NULL. */
67 PCFGMNODE pCfgNode;
68} PDMDEVREGCBINT;
69/** Pointer to a PDMDEVREGCBINT structure. */
70typedef PDMDEVREGCBINT *PPDMDEVREGCBINT;
71/** Pointer to a const PDMDEVREGCBINT structure. */
72typedef const PDMDEVREGCBINT *PCPDMDEVREGCBINT;
73
74
75/*******************************************************************************
76* Internal Functions *
77*******************************************************************************/
78static DECLCALLBACK(int) pdmR3DevReg_Register(PPDMDEVREGCB pCallbacks, PCPDMDEVREG pReg);
79static int pdmR3DevLoadModules(PVM pVM);
80static int pdmR3DevLoad(PVM pVM, PPDMDEVREGCBINT pRegCB, const char *pszFilename, const char *pszName);
81
82
83
84
85/**
86 * This function will initialize the devices for this VM instance.
87 *
88 *
89 * First of all this mean loading the builtin device and letting them
90 * register themselves. Beyond that any additional device modules are
91 * loaded and called for registration.
92 *
93 * Then the device configuration is enumerated, the instantiation order
94 * is determined, and finally they are instantiated.
95 *
96 * After all devices have been successfully instantiated the primary
97 * PCI Bus device is called to emulate the PCI BIOS, i.e. making the
98 * resource assignments. If there is no PCI device, this step is of course
99 * skipped.
100 *
101 * Finally the init completion routines of the instantiated devices
102 * are called.
103 *
104 * @returns VBox status code.
105 * @param pVM Pointer to the VM.
106 */
107int pdmR3DevInit(PVM pVM)
108{
109 LogFlow(("pdmR3DevInit:\n"));
110
111 AssertRelease(!(RT_OFFSETOF(PDMDEVINS, achInstanceData) & 15));
112 AssertRelease(sizeof(pVM->pdm.s.pDevInstances->Internal.s) <= sizeof(pVM->pdm.s.pDevInstances->Internal.padding));
113
114 /*
115 * Load device modules.
116 */
117 int rc = pdmR3DevLoadModules(pVM);
118 if (RT_FAILURE(rc))
119 return rc;
120
121#ifdef VBOX_WITH_USB
122 /* ditto for USB Devices. */
123 rc = pdmR3UsbLoadModules(pVM);
124 if (RT_FAILURE(rc))
125 return rc;
126#endif
127
128 /*
129 * Get the RC & R0 devhlps and create the devhlp R3 task queue.
130 */
131 PCPDMDEVHLPRC pHlpRC;
132 rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDevHlp", &pHlpRC);
133 AssertReleaseRCReturn(rc, rc);
134
135 PCPDMDEVHLPR0 pHlpR0;
136 rc = PDMR3LdrGetSymbolR0(pVM, NULL, "g_pdmR0DevHlp", &pHlpR0);
137 AssertReleaseRCReturn(rc, rc);
138
139 rc = PDMR3QueueCreateInternal(pVM, sizeof(PDMDEVHLPTASK), 8, 0, pdmR3DevHlpQueueConsumer, true, "DevHlp",
140 &pVM->pdm.s.pDevHlpQueueR3);
141 AssertRCReturn(rc, rc);
142 pVM->pdm.s.pDevHlpQueueR0 = PDMQueueR0Ptr(pVM->pdm.s.pDevHlpQueueR3);
143 pVM->pdm.s.pDevHlpQueueRC = PDMQueueRCPtr(pVM->pdm.s.pDevHlpQueueR3);
144
145
146 /*
147 *
148 * Enumerate the device instance configurations
149 * and come up with a instantiation order.
150 *
151 */
152 /* Switch to /Devices, which contains the device instantiations. */
153 PCFGMNODE pDevicesNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "Devices");
154
155 /*
156 * Count the device instances.
157 */
158 PCFGMNODE pCur;
159 PCFGMNODE pInstanceNode;
160 unsigned cDevs = 0;
161 for (pCur = CFGMR3GetFirstChild(pDevicesNode); pCur; pCur = CFGMR3GetNextChild(pCur))
162 for (pInstanceNode = CFGMR3GetFirstChild(pCur); pInstanceNode; pInstanceNode = CFGMR3GetNextChild(pInstanceNode))
163 cDevs++;
164 if (!cDevs)
165 {
166 Log(("PDM: No devices were configured!\n"));
167 return VINF_SUCCESS;
168 }
169 Log2(("PDM: cDevs=%d!\n", cDevs));
170
171 /*
172 * Collect info on each device instance.
173 */
174 struct DEVORDER
175 {
176 /** Configuration node. */
177 PCFGMNODE pNode;
178 /** Pointer to device. */
179 PPDMDEV pDev;
180 /** Init order. */
181 uint32_t u32Order;
182 /** VBox instance number. */
183 uint32_t iInstance;
184 } *paDevs = (struct DEVORDER *)alloca(sizeof(paDevs[0]) * (cDevs + 1)); /* (One extra for swapping) */
185 Assert(paDevs);
186 unsigned i = 0;
187 for (pCur = CFGMR3GetFirstChild(pDevicesNode); pCur; pCur = CFGMR3GetNextChild(pCur))
188 {
189 /* Get the device name. */
190 char szName[sizeof(paDevs[0].pDev->pReg->szName)];
191 rc = CFGMR3GetName(pCur, szName, sizeof(szName));
192 AssertMsgRCReturn(rc, ("Configuration error: device name is too long (or something)! rc=%Rrc\n", rc), rc);
193
194 /* Find the device. */
195 PPDMDEV pDev = pdmR3DevLookup(pVM, szName);
196 AssertLogRelMsgReturn(pDev, ("Configuration error: device '%s' not found!\n", szName), VERR_PDM_DEVICE_NOT_FOUND);
197
198 /* Configured priority or use default based on device class? */
199 uint32_t u32Order;
200 rc = CFGMR3QueryU32(pCur, "Priority", &u32Order);
201 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
202 {
203 uint32_t u32 = pDev->pReg->fClass;
204 for (u32Order = 1; !(u32 & u32Order); u32Order <<= 1)
205 /* nop */;
206 }
207 else
208 AssertMsgRCReturn(rc, ("Configuration error: reading \"Priority\" for the '%s' device failed rc=%Rrc!\n", szName, rc), rc);
209
210 /* Enumerate the device instances. */
211 uint32_t const iStart = i;
212 for (pInstanceNode = CFGMR3GetFirstChild(pCur); pInstanceNode; pInstanceNode = CFGMR3GetNextChild(pInstanceNode))
213 {
214 paDevs[i].pNode = pInstanceNode;
215 paDevs[i].pDev = pDev;
216 paDevs[i].u32Order = u32Order;
217
218 /* Get the instance number. */
219 char szInstance[32];
220 rc = CFGMR3GetName(pInstanceNode, szInstance, sizeof(szInstance));
221 AssertMsgRCReturn(rc, ("Configuration error: instance name is too long (or something)! rc=%Rrc\n", rc), rc);
222 char *pszNext = NULL;
223 rc = RTStrToUInt32Ex(szInstance, &pszNext, 0, &paDevs[i].iInstance);
224 AssertMsgRCReturn(rc, ("Configuration error: RTStrToInt32Ex failed on the instance name '%s'! rc=%Rrc\n", szInstance, rc), rc);
225 AssertMsgReturn(!*pszNext, ("Configuration error: the instance name '%s' isn't all digits. (%s)\n", szInstance, pszNext), VERR_INVALID_PARAMETER);
226
227 /* next instance */
228 i++;
229 }
230
231 /* check the number of instances */
232 if (i - iStart > pDev->pReg->cMaxInstances)
233 AssertLogRelMsgFailedReturn(("Configuration error: Too many instances of %s was configured: %u, max %u\n",
234 szName, i - iStart, pDev->pReg->cMaxInstances),
235 VERR_PDM_TOO_MANY_DEVICE_INSTANCES);
236 } /* devices */
237 Assert(i == cDevs);
238
239 /*
240 * Sort the device array ascending on u32Order. (bubble)
241 */
242 unsigned c = cDevs - 1;
243 while (c)
244 {
245 unsigned j = 0;
246 for (i = 0; i < c; i++)
247 if (paDevs[i].u32Order > paDevs[i + 1].u32Order)
248 {
249 paDevs[cDevs] = paDevs[i + 1];
250 paDevs[i + 1] = paDevs[i];
251 paDevs[i] = paDevs[cDevs];
252 j = i;
253 }
254 c = j;
255 }
256
257
258 /*
259 *
260 * Instantiate the devices.
261 *
262 */
263 for (i = 0; i < cDevs; i++)
264 {
265 /*
266 * Gather a bit of config.
267 */
268 /* trusted */
269 bool fTrusted;
270 rc = CFGMR3QueryBool(paDevs[i].pNode, "Trusted", &fTrusted);
271 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
272 fTrusted = false;
273 else if (RT_FAILURE(rc))
274 {
275 AssertMsgFailed(("configuration error: failed to query boolean \"Trusted\", rc=%Rrc\n", rc));
276 return rc;
277 }
278 /* config node */
279 PCFGMNODE pConfigNode = CFGMR3GetChild(paDevs[i].pNode, "Config");
280 if (!pConfigNode)
281 {
282 rc = CFGMR3InsertNode(paDevs[i].pNode, "Config", &pConfigNode);
283 if (RT_FAILURE(rc))
284 {
285 AssertMsgFailed(("Failed to create Config node! rc=%Rrc\n", rc));
286 return rc;
287 }
288 }
289 CFGMR3SetRestrictedRoot(pConfigNode);
290
291 /*
292 * Allocate the device instance and critical section.
293 */
294 AssertReturn(paDevs[i].pDev->cInstances < paDevs[i].pDev->pReg->cMaxInstances, VERR_PDM_TOO_MANY_DEVICE_INSTANCES);
295 size_t cb = RT_OFFSETOF(PDMDEVINS, achInstanceData[paDevs[i].pDev->pReg->cbInstance]);
296 cb = RT_ALIGN_Z(cb, 16);
297 PPDMDEVINS pDevIns;
298 if (paDevs[i].pDev->pReg->fFlags & (PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0))
299 rc = MMR3HyperAllocOnceNoRel(pVM, cb, 0, MM_TAG_PDM_DEVICE, (void **)&pDevIns);
300 else
301 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_DEVICE, cb, (void **)&pDevIns);
302 AssertLogRelMsgRCReturn(rc,
303 ("Failed to allocate %d bytes of instance data for device '%s'. rc=%Rrc\n",
304 cb, paDevs[i].pDev->pReg->szName, rc),
305 rc);
306 PPDMCRITSECT pCritSect;
307 if (paDevs[i].pDev->pReg->fFlags & (PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0))
308 rc = MMHyperAlloc(pVM, sizeof(*pCritSect), 0, MM_TAG_PDM_DEVICE, (void **)&pCritSect);
309 else
310 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_DEVICE, sizeof(*pCritSect), (void **)&pCritSect);
311 AssertLogRelMsgRCReturn(rc, ("Failed to allocate a critical section for the device\n", rc), rc);
312
313 /*
314 * Initialize it.
315 */
316 pDevIns->u32Version = PDM_DEVINS_VERSION;
317 pDevIns->iInstance = paDevs[i].iInstance;
318 //pDevIns->Internal.s.pNextR3 = NULL;
319 //pDevIns->Internal.s.pPerDeviceNextR3 = NULL;
320 pDevIns->Internal.s.pDevR3 = paDevs[i].pDev;
321 pDevIns->Internal.s.pVMR3 = pVM;
322 pDevIns->Internal.s.pVMR0 = pVM->pVMR0;
323 pDevIns->Internal.s.pVMRC = pVM->pVMRC;
324 //pDevIns->Internal.s.pLunsR3 = NULL;
325 pDevIns->Internal.s.pCfgHandle = paDevs[i].pNode;
326 //pDevIns->Internal.s.pPciDeviceR3 = NULL;
327 //pDevIns->Internal.s.pPciBusR3 = NULL;
328 //pDevIns->Internal.s.pPciDeviceR0 = 0;
329 //pDevIns->Internal.s.pPciBusR0 = 0;
330 //pDevIns->Internal.s.pPciDeviceRC = 0;
331 //pDevIns->Internal.s.pPciBusRC = 0;
332 pDevIns->Internal.s.fIntFlags = PDMDEVINSINT_FLAGS_SUSPENDED;
333 //pDevIns->Internal.s.uLastIrqTag = 0;
334 pDevIns->pHlpR3 = fTrusted ? &g_pdmR3DevHlpTrusted : &g_pdmR3DevHlpUnTrusted;
335 pDevIns->pHlpRC = pHlpRC;
336 pDevIns->pHlpR0 = pHlpR0;
337 pDevIns->pReg = paDevs[i].pDev->pReg;
338 pDevIns->pCfg = pConfigNode;
339 //pDevIns->IBase.pfnQueryInterface = NULL;
340 //pDevIns->fTracing = 0;
341 pDevIns->idTracing = ++pVM->pdm.s.idTracingDev;
342 pDevIns->pvInstanceDataR3 = &pDevIns->achInstanceData[0];
343 pDevIns->pvInstanceDataRC = pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_RC
344 ? MMHyperR3ToRC(pVM, pDevIns->pvInstanceDataR3) : NIL_RTRCPTR;
345 pDevIns->pvInstanceDataR0 = pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_R0
346 ? MMHyperR3ToR0(pVM, pDevIns->pvInstanceDataR3) : NIL_RTR0PTR;
347
348 pDevIns->pCritSectRoR3 = pCritSect;
349 pDevIns->pCritSectRoRC = pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_RC
350 ? MMHyperR3ToRC(pVM, pCritSect) : NIL_RTRCPTR;
351 pDevIns->pCritSectRoR0 = pDevIns->pReg->fFlags & PDM_DEVREG_FLAGS_R0
352 ? MMHyperR3ToR0(pVM, pCritSect) : NIL_RTR0PTR;
353
354 rc = pdmR3CritSectInitDeviceAuto(pVM, pDevIns, pCritSect, RT_SRC_POS,
355 "%s#%u Auto", pDevIns->pReg->szName, pDevIns->iInstance);
356 AssertLogRelRCReturn(rc, rc);
357
358 /*
359 * Link it into all the lists.
360 */
361 /* The global instance FIFO. */
362 PPDMDEVINS pPrev1 = pVM->pdm.s.pDevInstances;
363 if (!pPrev1)
364 pVM->pdm.s.pDevInstances = pDevIns;
365 else
366 {
367 while (pPrev1->Internal.s.pNextR3)
368 pPrev1 = pPrev1->Internal.s.pNextR3;
369 pPrev1->Internal.s.pNextR3 = pDevIns;
370 }
371
372 /* The per device instance FIFO. */
373 PPDMDEVINS pPrev2 = paDevs[i].pDev->pInstances;
374 if (!pPrev2)
375 paDevs[i].pDev->pInstances = pDevIns;
376 else
377 {
378 while (pPrev2->Internal.s.pPerDeviceNextR3)
379 pPrev2 = pPrev2->Internal.s.pPerDeviceNextR3;
380 pPrev2->Internal.s.pPerDeviceNextR3 = pDevIns;
381 }
382
383 /*
384 * Call the constructor.
385 */
386 paDevs[i].pDev->cInstances++;
387 Log(("PDM: Constructing device '%s' instance %d...\n", pDevIns->pReg->szName, pDevIns->iInstance));
388 rc = pDevIns->pReg->pfnConstruct(pDevIns, pDevIns->iInstance, pDevIns->pCfg);
389 if (RT_FAILURE(rc))
390 {
391 LogRel(("PDM: Failed to construct '%s'/%d! %Rra\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
392 paDevs[i].pDev->cInstances--;
393 /* Because we're damn lazy, the destructor will be called even if
394 the constructor fails. So, no unlinking. */
395 return rc == VERR_VERSION_MISMATCH ? VERR_PDM_DEVICE_VERSION_MISMATCH : rc;
396 }
397 } /* for device instances */
398
399#ifdef VBOX_WITH_USB
400 /* ditto for USB Devices. */
401 rc = pdmR3UsbInstantiateDevices(pVM);
402 if (RT_FAILURE(rc))
403 return rc;
404#endif
405
406
407 /*
408 *
409 * PCI BIOS Fake and Init Complete.
410 *
411 */
412 if (pVM->pdm.s.aPciBuses[0].pDevInsR3)
413 {
414 pdmLock(pVM);
415 rc = pVM->pdm.s.aPciBuses[0].pfnFakePCIBIOSR3(pVM->pdm.s.aPciBuses[0].pDevInsR3);
416 pdmUnlock(pVM);
417 if (RT_FAILURE(rc))
418 {
419 AssertMsgFailed(("PCI BIOS fake failed rc=%Rrc\n", rc));
420 return rc;
421 }
422 }
423
424 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
425 {
426 if (pDevIns->pReg->pfnInitComplete)
427 {
428 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
429 rc = pDevIns->pReg->pfnInitComplete(pDevIns);
430 PDMCritSectLeave(pDevIns->pCritSectRoR3);
431 if (RT_FAILURE(rc))
432 {
433 AssertMsgFailed(("InitComplete on device '%s'/%d failed with rc=%Rrc\n",
434 pDevIns->pReg->szName, pDevIns->iInstance, rc));
435 return rc;
436 }
437 }
438 }
439
440#ifdef VBOX_WITH_USB
441 /* ditto for USB Devices. */
442 rc = pdmR3UsbVMInitComplete(pVM);
443 if (RT_FAILURE(rc))
444 return rc;
445#endif
446
447 LogFlow(("pdmR3DevInit: returns %Rrc\n", VINF_SUCCESS));
448 return VINF_SUCCESS;
449}
450
451
452/**
453 * Lookups a device structure by name.
454 * @internal
455 */
456PPDMDEV pdmR3DevLookup(PVM pVM, const char *pszName)
457{
458 size_t cchName = strlen(pszName);
459 for (PPDMDEV pDev = pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
460 if ( pDev->cchName == cchName
461 && !strcmp(pDev->pReg->szName, pszName))
462 return pDev;
463 return NULL;
464}
465
466
467/**
468 * Loads the device modules.
469 *
470 * @returns VBox status code.
471 * @param pVM Pointer to the VM.
472 */
473static int pdmR3DevLoadModules(PVM pVM)
474{
475 /*
476 * Initialize the callback structure.
477 */
478 PDMDEVREGCBINT RegCB;
479 RegCB.Core.u32Version = PDM_DEVREG_CB_VERSION;
480 RegCB.Core.pfnRegister = pdmR3DevReg_Register;
481 RegCB.pVM = pVM;
482 RegCB.pCfgNode = NULL;
483
484 /*
485 * Load the builtin module
486 */
487 PCFGMNODE pDevicesNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "PDM/Devices");
488 bool fLoadBuiltin;
489 int rc = CFGMR3QueryBool(pDevicesNode, "LoadBuiltin", &fLoadBuiltin);
490 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
491 fLoadBuiltin = true;
492 else if (RT_FAILURE(rc))
493 {
494 AssertMsgFailed(("Configuration error: Querying boolean \"LoadBuiltin\" failed with %Rrc\n", rc));
495 return rc;
496 }
497 if (fLoadBuiltin)
498 {
499 /* make filename */
500 char *pszFilename = pdmR3FileR3("VBoxDD", true /*fShared*/);
501 if (!pszFilename)
502 return VERR_NO_TMP_MEMORY;
503 rc = pdmR3DevLoad(pVM, &RegCB, pszFilename, "VBoxDD");
504 RTMemTmpFree(pszFilename);
505 if (RT_FAILURE(rc))
506 return rc;
507
508 /* make filename */
509 pszFilename = pdmR3FileR3("VBoxDD2", true /*fShared*/);
510 if (!pszFilename)
511 return VERR_NO_TMP_MEMORY;
512 rc = pdmR3DevLoad(pVM, &RegCB, pszFilename, "VBoxDD2");
513 RTMemTmpFree(pszFilename);
514 if (RT_FAILURE(rc))
515 return rc;
516 }
517
518 /*
519 * Load additional device modules.
520 */
521 PCFGMNODE pCur;
522 for (pCur = CFGMR3GetFirstChild(pDevicesNode); pCur; pCur = CFGMR3GetNextChild(pCur))
523 {
524 /*
525 * Get the name and path.
526 */
527 char szName[PDMMOD_NAME_LEN];
528 rc = CFGMR3GetName(pCur, &szName[0], sizeof(szName));
529 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
530 {
531 AssertMsgFailed(("configuration error: The module name is too long, cchName=%zu.\n", CFGMR3GetNameLen(pCur)));
532 return VERR_PDM_MODULE_NAME_TOO_LONG;
533 }
534 else if (RT_FAILURE(rc))
535 {
536 AssertMsgFailed(("CFGMR3GetName -> %Rrc.\n", rc));
537 return rc;
538 }
539
540 /* the path is optional, if no path the module name + path is used. */
541 char szFilename[RTPATH_MAX];
542 rc = CFGMR3QueryString(pCur, "Path", &szFilename[0], sizeof(szFilename));
543 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
544 strcpy(szFilename, szName);
545 else if (RT_FAILURE(rc))
546 {
547 AssertMsgFailed(("configuration error: Failure to query the module path, rc=%Rrc.\n", rc));
548 return rc;
549 }
550
551 /* prepend path? */
552 if (!RTPathHavePath(szFilename))
553 {
554 char *psz = pdmR3FileR3(szFilename, false /*fShared*/);
555 if (!psz)
556 return VERR_NO_TMP_MEMORY;
557 size_t cch = strlen(psz) + 1;
558 if (cch > sizeof(szFilename))
559 {
560 RTMemTmpFree(psz);
561 AssertMsgFailed(("Filename too long! cch=%d '%s'\n", cch, psz));
562 return VERR_FILENAME_TOO_LONG;
563 }
564 memcpy(szFilename, psz, cch);
565 RTMemTmpFree(psz);
566 }
567
568 /*
569 * Load the module and register it's devices.
570 */
571 RegCB.pCfgNode = pCur;
572 rc = pdmR3DevLoad(pVM, &RegCB, szFilename, szName);
573 if (RT_FAILURE(rc))
574 return rc;
575 }
576
577 return VINF_SUCCESS;
578}
579
580
581/**
582 * Loads one device module and call the registration entry point.
583 *
584 * @returns VBox status code.
585 * @param pVM Pointer to the VM.
586 * @param pRegCB The registration callback stuff.
587 * @param pszFilename Module filename.
588 * @param pszName Module name.
589 */
590static int pdmR3DevLoad(PVM pVM, PPDMDEVREGCBINT pRegCB, const char *pszFilename, const char *pszName)
591{
592 /*
593 * Load it.
594 */
595 int rc = pdmR3LoadR3U(pVM->pUVM, pszFilename, pszName);
596 if (RT_SUCCESS(rc))
597 {
598 /*
599 * Get the registration export and call it.
600 */
601 FNPDMVBOXDEVICESREGISTER *pfnVBoxDevicesRegister;
602 rc = PDMR3LdrGetSymbolR3(pVM, pszName, "VBoxDevicesRegister", (void **)&pfnVBoxDevicesRegister);
603 if (RT_SUCCESS(rc))
604 {
605 Log(("PDM: Calling VBoxDevicesRegister (%p) of %s (%s)\n", pfnVBoxDevicesRegister, pszName, pszFilename));
606 rc = pfnVBoxDevicesRegister(&pRegCB->Core, VBOX_VERSION);
607 if (RT_SUCCESS(rc))
608 Log(("PDM: Successfully loaded device module %s (%s).\n", pszName, pszFilename));
609 else
610 AssertMsgFailed(("VBoxDevicesRegister failed with rc=%Rrc for module %s (%s)\n", rc, pszName, pszFilename));
611 }
612 else
613 {
614 AssertMsgFailed(("Failed to locate 'VBoxDevicesRegister' in %s (%s) rc=%Rrc\n", pszName, pszFilename, rc));
615 if (rc == VERR_SYMBOL_NOT_FOUND)
616 rc = VERR_PDM_NO_REGISTRATION_EXPORT;
617 }
618 }
619 else
620 AssertMsgFailed(("Failed to load %s %s!\n", pszFilename, pszName));
621 return rc;
622}
623
624
625/**
626 * @interface_method_impl{PDMDEVREGCB,pfnRegister}
627 */
628static DECLCALLBACK(int) pdmR3DevReg_Register(PPDMDEVREGCB pCallbacks, PCPDMDEVREG pReg)
629{
630 /*
631 * Validate the registration structure.
632 */
633 Assert(pReg);
634 AssertMsgReturn(pReg->u32Version == PDM_DEVREG_VERSION,
635 ("Unknown struct version %#x!\n", pReg->u32Version),
636 VERR_PDM_UNKNOWN_DEVREG_VERSION);
637
638 AssertMsgReturn( pReg->szName[0]
639 && strlen(pReg->szName) < sizeof(pReg->szName)
640 && pdmR3IsValidName(pReg->szName),
641 ("Invalid name '%.s'\n", sizeof(pReg->szName), pReg->szName),
642 VERR_PDM_INVALID_DEVICE_REGISTRATION);
643 AssertMsgReturn( !(pReg->fFlags & PDM_DEVREG_FLAGS_RC)
644 || ( pReg->szRCMod[0]
645 && strlen(pReg->szRCMod) < sizeof(pReg->szRCMod)),
646 ("Invalid GC module name '%s' - (Device %s)\n", pReg->szRCMod, pReg->szName),
647 VERR_PDM_INVALID_DEVICE_REGISTRATION);
648 AssertMsgReturn( !(pReg->fFlags & PDM_DEVREG_FLAGS_R0)
649 || ( pReg->szR0Mod[0]
650 && strlen(pReg->szR0Mod) < sizeof(pReg->szR0Mod)),
651 ("Invalid R0 module name '%s' - (Device %s)\n", pReg->szR0Mod, pReg->szName),
652 VERR_PDM_INVALID_DEVICE_REGISTRATION);
653 AssertMsgReturn((pReg->fFlags & PDM_DEVREG_FLAGS_HOST_BITS_MASK) == PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT,
654 ("Invalid host bits flags! fFlags=%#x (Device %s)\n", pReg->fFlags, pReg->szName),
655 VERR_PDM_INVALID_DEVICE_HOST_BITS);
656 AssertMsgReturn((pReg->fFlags & PDM_DEVREG_FLAGS_GUEST_BITS_MASK),
657 ("Invalid guest bits flags! fFlags=%#x (Device %s)\n", pReg->fFlags, pReg->szName),
658 VERR_PDM_INVALID_DEVICE_REGISTRATION);
659 AssertMsgReturn(pReg->fClass,
660 ("No class! (Device %s)\n", pReg->szName),
661 VERR_PDM_INVALID_DEVICE_REGISTRATION);
662 AssertMsgReturn(pReg->cMaxInstances > 0,
663 ("Max instances %u! (Device %s)\n", pReg->cMaxInstances, pReg->szName),
664 VERR_PDM_INVALID_DEVICE_REGISTRATION);
665 AssertMsgReturn(pReg->cbInstance <= (uint32_t)(pReg->fFlags & (PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0) ? 96 * _1K : _1M),
666 ("Instance size %d bytes! (Device %s)\n", pReg->cbInstance, pReg->szName),
667 VERR_PDM_INVALID_DEVICE_REGISTRATION);
668 AssertMsgReturn(pReg->pfnConstruct,
669 ("No constructor! (Device %s)\n", pReg->szName),
670 VERR_PDM_INVALID_DEVICE_REGISTRATION);
671 AssertLogRelMsgReturn((pReg->fFlags & PDM_DEVREG_FLAGS_GUEST_BITS_MASK) == PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT,
672 ("PDM: Rejected device '%s' because it didn't match the guest bits.\n", pReg->szName),
673 VERR_PDM_INVALID_DEVICE_GUEST_BITS);
674 AssertLogRelMsg(pReg->u32VersionEnd == PDM_DEVREG_VERSION,
675 ("u32VersionEnd=%#x, expected %#x. (szName=%s)\n",
676 pReg->u32VersionEnd, PDM_DEVREG_VERSION, pReg->szName));
677
678 /*
679 * Check for duplicate and find FIFO entry at the same time.
680 */
681 PCPDMDEVREGCBINT pRegCB = (PCPDMDEVREGCBINT)pCallbacks;
682 PPDMDEV pDevPrev = NULL;
683 PPDMDEV pDev = pRegCB->pVM->pdm.s.pDevs;
684 for (; pDev; pDevPrev = pDev, pDev = pDev->pNext)
685 AssertMsgReturn(strcmp(pDev->pReg->szName, pReg->szName),
686 ("Device '%s' already exists\n", pReg->szName),
687 VERR_PDM_DEVICE_NAME_CLASH);
688
689 /*
690 * Allocate new device structure, initialize and insert it into the list.
691 */
692 int rc;
693 pDev = (PPDMDEV)MMR3HeapAlloc(pRegCB->pVM, MM_TAG_PDM_DEVICE, sizeof(*pDev));
694 if (pDev)
695 {
696 pDev->pNext = NULL;
697 pDev->cInstances = 0;
698 pDev->pInstances = NULL;
699 pDev->pReg = pReg;
700 pDev->cchName = (uint32_t)strlen(pReg->szName);
701 rc = CFGMR3QueryStringAllocDef( pRegCB->pCfgNode, "RCSearchPath", &pDev->pszRCSearchPath, NULL);
702 if (RT_SUCCESS(rc))
703 rc = CFGMR3QueryStringAllocDef(pRegCB->pCfgNode, "R0SearchPath", &pDev->pszR0SearchPath, NULL);
704 if (RT_SUCCESS(rc))
705 {
706 if (pDevPrev)
707 pDevPrev->pNext = pDev;
708 else
709 pRegCB->pVM->pdm.s.pDevs = pDev;
710 Log(("PDM: Registered device '%s'\n", pReg->szName));
711 return VINF_SUCCESS;
712 }
713
714 MMR3HeapFree(pDev);
715 }
716 else
717 rc = VERR_NO_MEMORY;
718 return rc;
719}
720
721
722/**
723 * Locates a LUN.
724 *
725 * @returns VBox status code.
726 * @param pVM Pointer to the VM.
727 * @param pszDevice Device name.
728 * @param iInstance Device instance.
729 * @param iLun The Logical Unit to obtain the interface of.
730 * @param ppLun Where to store the pointer to the LUN if found.
731 * @thread Try only do this in EMT...
732 */
733int pdmR3DevFindLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPPDMLUN ppLun)
734{
735 /*
736 * Iterate registered devices looking for the device.
737 */
738 size_t cchDevice = strlen(pszDevice);
739 for (PPDMDEV pDev = pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
740 {
741 if ( pDev->cchName == cchDevice
742 && !memcmp(pDev->pReg->szName, pszDevice, cchDevice))
743 {
744 /*
745 * Iterate device instances.
746 */
747 for (PPDMDEVINS pDevIns = pDev->pInstances; pDevIns; pDevIns = pDevIns->Internal.s.pPerDeviceNextR3)
748 {
749 if (pDevIns->iInstance == iInstance)
750 {
751 /*
752 * Iterate luns.
753 */
754 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
755 {
756 if (pLun->iLun == iLun)
757 {
758 *ppLun = pLun;
759 return VINF_SUCCESS;
760 }
761 }
762 return VERR_PDM_LUN_NOT_FOUND;
763 }
764 }
765 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND;
766 }
767 }
768 return VERR_PDM_DEVICE_NOT_FOUND;
769}
770
771
772/**
773 * Attaches a preconfigured driver to an existing device instance.
774 *
775 * This is used to change drivers and suchlike at runtime.
776 *
777 * @returns VBox status code.
778 * @param pVM Pointer to the VM.
779 * @param pszDevice Device name.
780 * @param iInstance Device instance.
781 * @param iLun The Logical Unit to obtain the interface of.
782 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
783 * @param ppBase Where to store the base interface pointer. Optional.
784 * @thread EMT
785 */
786VMMR3DECL(int) PDMR3DeviceAttach(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, uint32_t fFlags, PPPDMIBASE ppBase)
787{
788 VM_ASSERT_EMT(pVM);
789 LogFlow(("PDMR3DeviceAttach: pszDevice=%p:{%s} iInstance=%d iLun=%d fFlags=%#x ppBase=%p\n",
790 pszDevice, pszDevice, iInstance, iLun, fFlags, ppBase));
791
792 /*
793 * Find the LUN in question.
794 */
795 PPDMLUN pLun;
796 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
797 if (RT_SUCCESS(rc))
798 {
799 /*
800 * Can we attach anything at runtime?
801 */
802 PPDMDEVINS pDevIns = pLun->pDevIns;
803 if (pDevIns->pReg->pfnAttach)
804 {
805 if (!pLun->pTop)
806 {
807 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
808 rc = pDevIns->pReg->pfnAttach(pDevIns, iLun, fFlags);
809 PDMCritSectLeave(pDevIns->pCritSectRoR3);
810 }
811 else
812 rc = VERR_PDM_DRIVER_ALREADY_ATTACHED;
813 }
814 else
815 rc = VERR_PDM_DEVICE_NO_RT_ATTACH;
816
817 if (ppBase)
818 *ppBase = pLun->pTop ? &pLun->pTop->IBase : NULL;
819 }
820 else if (ppBase)
821 *ppBase = NULL;
822
823 if (ppBase)
824 LogFlow(("PDMR3DeviceAttach: returns %Rrc *ppBase=%p\n", rc, *ppBase));
825 else
826 LogFlow(("PDMR3DeviceAttach: returns %Rrc\n", rc));
827 return rc;
828}
829
830
831/**
832 * Detaches a driver chain from an existing device instance.
833 *
834 * This is used to change drivers and suchlike at runtime.
835 *
836 * @returns VBox status code.
837 * @param pVM Pointer to the VM.
838 * @param pszDevice Device name.
839 * @param iInstance Device instance.
840 * @param iLun The Logical Unit to obtain the interface of.
841 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
842 * @thread EMT
843 */
844VMMR3DECL(int) PDMR3DeviceDetach(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, uint32_t fFlags)
845{
846 return PDMR3DriverDetach(pVM, pszDevice, iInstance, iLun, NULL, 0, fFlags);
847}
848
849
850/**
851 * References the critical section associated with a device for the use by a
852 * timer or similar created by the device.
853 *
854 * @returns Pointer to the critical section.
855 * @param pVM Pointer to the VM.
856 * @param pDevIns The device instance in question.
857 *
858 * @internal
859 */
860VMMR3_INT_DECL(PPDMCRITSECT) PDMR3DevGetCritSect(PVM pVM, PPDMDEVINS pDevIns)
861{
862 VM_ASSERT_EMT(pVM);
863 VM_ASSERT_STATE(pVM, VMSTATE_CREATING);
864 AssertPtr(pDevIns);
865
866 PPDMCRITSECT pCritSect = pDevIns->pCritSectRoR3;
867 AssertPtr(pCritSect);
868 pCritSect->s.fUsedByTimerOrSimilar = true;
869
870 return pCritSect;
871}
872
873
874/**
875 * Attaches a preconfigured driver to an existing device or driver instance.
876 *
877 * This is used to change drivers and suchlike at runtime. The driver or device
878 * at the end of the chain will be told to attach to whatever is configured
879 * below it.
880 *
881 * @returns VBox status code.
882 * @param pVM Pointer to the VM.
883 * @param pszDevice Device name.
884 * @param iInstance Device instance.
885 * @param iLun The Logical Unit to obtain the interface of.
886 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
887 * @param ppBase Where to store the base interface pointer. Optional.
888 *
889 * @thread EMT
890 */
891VMMR3DECL(int) PDMR3DriverAttach(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, uint32_t fFlags, PPPDMIBASE ppBase)
892{
893 VM_ASSERT_EMT(pVM);
894 LogFlow(("PDMR3DriverAttach: pszDevice=%p:{%s} iInstance=%d iLun=%d fFlags=%#x ppBase=%p\n",
895 pszDevice, pszDevice, iInstance, iLun, fFlags, ppBase));
896
897 if (ppBase)
898 *ppBase = NULL;
899
900 /*
901 * Find the LUN in question.
902 */
903 PPDMLUN pLun;
904 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
905 if (RT_SUCCESS(rc))
906 {
907 /*
908 * Anything attached to the LUN?
909 */
910 PPDMDRVINS pDrvIns = pLun->pTop;
911 if (!pDrvIns)
912 {
913 /* No, ask the device to attach to the new stuff. */
914 PPDMDEVINS pDevIns = pLun->pDevIns;
915 if (pDevIns->pReg->pfnAttach)
916 {
917 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
918 rc = pDevIns->pReg->pfnAttach(pDevIns, iLun, fFlags);
919 if (RT_SUCCESS(rc) && ppBase)
920 *ppBase = pLun->pTop ? &pLun->pTop->IBase : NULL;
921 PDMCritSectLeave(pDevIns->pCritSectRoR3);
922 }
923 else
924 rc = VERR_PDM_DEVICE_NO_RT_ATTACH;
925 }
926 else
927 {
928 /* Yes, find the bottom most driver and ask it to attach to the new stuff. */
929 while (pDrvIns->Internal.s.pDown)
930 pDrvIns = pDrvIns->Internal.s.pDown;
931 if (pDrvIns->pReg->pfnAttach)
932 {
933 rc = pDrvIns->pReg->pfnAttach(pDrvIns, fFlags);
934 if (RT_SUCCESS(rc) && ppBase)
935 *ppBase = pDrvIns->Internal.s.pDown
936 ? &pDrvIns->Internal.s.pDown->IBase
937 : NULL;
938 }
939 else
940 rc = VERR_PDM_DRIVER_NO_RT_ATTACH;
941 }
942 }
943
944 if (ppBase)
945 LogFlow(("PDMR3DriverAttach: returns %Rrc *ppBase=%p\n", rc, *ppBase));
946 else
947 LogFlow(("PDMR3DriverAttach: returns %Rrc\n", rc));
948 return rc;
949}
950
951
952/**
953 * Detaches the specified driver instance.
954 *
955 * This is used to replumb drivers at runtime for simulating hot plugging and
956 * media changes.
957 *
958 * This is a superset of PDMR3DeviceDetach. It allows detaching drivers from
959 * any driver or device by specifying the driver to start detaching at. The
960 * only prerequisite is that the driver or device above implements the
961 * pfnDetach callback (PDMDRVREG / PDMDEVREG).
962 *
963 * @returns VBox status code.
964 * @param pVM Pointer to the VM.
965 * @param pszDevice Device name.
966 * @param iDevIns Device instance.
967 * @param iLun The Logical Unit in which to look for the driver.
968 * @param pszDriver The name of the driver which to detach. If NULL
969 * then the entire driver chain is detatched.
970 * @param iOccurance The occurrence of that driver in the chain. This is
971 * usually 0.
972 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
973 * @thread EMT
974 */
975VMMR3DECL(int) PDMR3DriverDetach(PVM pVM, const char *pszDevice, unsigned iDevIns, unsigned iLun,
976 const char *pszDriver, unsigned iOccurance, uint32_t fFlags)
977{
978 LogFlow(("PDMR3DriverDetach: pszDevice=%p:{%s} iDevIns=%u iLun=%u pszDriver=%p:{%s} iOccurance=%u fFlags=%#x\n",
979 pszDevice, pszDevice, iDevIns, iLun, pszDriver, iOccurance, fFlags));
980 VM_ASSERT_EMT(pVM);
981 AssertPtr(pszDevice);
982 AssertPtrNull(pszDriver);
983 Assert(iOccurance == 0 || pszDriver);
984 Assert(!(fFlags & ~(PDM_TACH_FLAGS_NOT_HOT_PLUG)));
985
986 /*
987 * Find the LUN in question.
988 */
989 PPDMLUN pLun;
990 int rc = pdmR3DevFindLun(pVM, pszDevice, iDevIns, iLun, &pLun);
991 if (RT_SUCCESS(rc))
992 {
993 /*
994 * Locate the driver.
995 */
996 PPDMDRVINS pDrvIns = pLun->pTop;
997 if (pDrvIns)
998 {
999 if (pszDriver)
1000 {
1001 while (pDrvIns)
1002 {
1003 if (!strcmp(pDrvIns->pReg->szName, pszDriver))
1004 {
1005 if (iOccurance == 0)
1006 break;
1007 iOccurance--;
1008 }
1009 pDrvIns = pDrvIns->Internal.s.pDown;
1010 }
1011 }
1012 if (pDrvIns)
1013 rc = pdmR3DrvDetach(pDrvIns, fFlags);
1014 else
1015 rc = VERR_PDM_DRIVER_INSTANCE_NOT_FOUND;
1016 }
1017 else
1018 rc = VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN;
1019 }
1020
1021 LogFlow(("PDMR3DriverDetach: returns %Rrc\n", rc));
1022 return rc;
1023}
1024
1025
1026/**
1027 * Runtime detach and reattach of a new driver chain or sub chain.
1028 *
1029 * This is intended to be called on a non-EMT thread, this will instantiate the
1030 * new driver (sub-)chain, and then the EMTs will do the actual replumbing. The
1031 * destruction of the old driver chain will be taken care of on the calling
1032 * thread.
1033 *
1034 * @returns VBox status code.
1035 * @param pVM Pointer to the VM.
1036 * @param pszDevice Device name.
1037 * @param iDevIns Device instance.
1038 * @param iLun The Logical Unit in which to look for the driver.
1039 * @param pszDriver The name of the driver which to detach and replace.
1040 * If NULL then the entire driver chain is to be
1041 * reattached.
1042 * @param iOccurance The occurrence of that driver in the chain. This is
1043 * usually 0.
1044 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1045 * @param pCfg The configuration of the new driver chain that is
1046 * going to be attached. The subtree starts with the
1047 * node containing a Driver key, a Config subtree and
1048 * optionally an AttachedDriver subtree.
1049 * If this parameter is NULL, then this call will work
1050 * like at a non-pause version of PDMR3DriverDetach.
1051 * @param ppBase Where to store the base interface pointer to the new
1052 * driver. Optional.
1053 *
1054 * @thread Any thread. The EMTs will be involved at some point though.
1055 */
1056VMMR3DECL(int) PDMR3DriverReattach(PVM pVM, const char *pszDevice, unsigned iDevIns, unsigned iLun,
1057 const char *pszDriver, unsigned iOccurance, uint32_t fFlags,
1058 PCFGMNODE pCfg, PPPDMIBASE ppBase)
1059{
1060 NOREF(pVM); NOREF(pszDevice); NOREF(iDevIns); NOREF(iLun); NOREF(pszDriver); NOREF(iOccurance);
1061 NOREF(fFlags); NOREF(pCfg); NOREF(ppBase);
1062 return VERR_NOT_IMPLEMENTED;
1063}
1064
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use