VirtualBox

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

Last change on this file since 37578 was 37466, checked in by vboxsync, 14 years ago

VMM,Devices: Automatically use a per-device lock instead of the giant IOM lock. With exception of the PIC, APIC, IOAPIC and PCI buses which are all using the PDM crit sect, there should be no calls between devices. So, this change should be relatively safe.

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