VirtualBox

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

Last change on this file since 39913 was 39839, checked in by vboxsync, 13 years ago

PDM: Initial driver chain transformation code (untested).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 38.6 KB
Line 
1/* $Id: PDMDevice.cpp 39839 2012-01-23 16:05:57Z 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 AssertLogRelMsgReturn(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 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
423 rc = pDevIns->pReg->pfnInitComplete(pDevIns);
424 PDMCritSectLeave(pDevIns->pCritSectRoR3);
425 if (RT_FAILURE(rc))
426 {
427 AssertMsgFailed(("InitComplete on device '%s'/%d failed with rc=%Rrc\n",
428 pDevIns->pReg->szName, pDevIns->iInstance, rc));
429 return rc;
430 }
431 }
432 }
433
434#ifdef VBOX_WITH_USB
435 /* ditto for USB Devices. */
436 rc = pdmR3UsbVMInitComplete(pVM);
437 if (RT_FAILURE(rc))
438 return rc;
439#endif
440
441 LogFlow(("pdmR3DevInit: returns %Rrc\n", VINF_SUCCESS));
442 return VINF_SUCCESS;
443}
444
445
446/**
447 * Lookups a device structure by name.
448 * @internal
449 */
450PPDMDEV pdmR3DevLookup(PVM pVM, const char *pszName)
451{
452 size_t cchName = strlen(pszName);
453 for (PPDMDEV pDev = pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
454 if ( pDev->cchName == cchName
455 && !strcmp(pDev->pReg->szName, pszName))
456 return pDev;
457 return NULL;
458}
459
460
461/**
462 * Loads the device modules.
463 *
464 * @returns VBox status code.
465 * @param pVM Pointer to the shared VM structure.
466 */
467static int pdmR3DevLoadModules(PVM pVM)
468{
469 /*
470 * Initialize the callback structure.
471 */
472 PDMDEVREGCBINT RegCB;
473 RegCB.Core.u32Version = PDM_DEVREG_CB_VERSION;
474 RegCB.Core.pfnRegister = pdmR3DevReg_Register;
475 RegCB.pVM = pVM;
476 RegCB.pCfgNode = NULL;
477
478 /*
479 * Load the builtin module
480 */
481 PCFGMNODE pDevicesNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "PDM/Devices");
482 bool fLoadBuiltin;
483 int rc = CFGMR3QueryBool(pDevicesNode, "LoadBuiltin", &fLoadBuiltin);
484 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
485 fLoadBuiltin = true;
486 else if (RT_FAILURE(rc))
487 {
488 AssertMsgFailed(("Configuration error: Querying boolean \"LoadBuiltin\" failed with %Rrc\n", rc));
489 return rc;
490 }
491 if (fLoadBuiltin)
492 {
493 /* make filename */
494 char *pszFilename = pdmR3FileR3("VBoxDD", true /*fShared*/);
495 if (!pszFilename)
496 return VERR_NO_TMP_MEMORY;
497 rc = pdmR3DevLoad(pVM, &RegCB, pszFilename, "VBoxDD");
498 RTMemTmpFree(pszFilename);
499 if (RT_FAILURE(rc))
500 return rc;
501
502 /* make filename */
503 pszFilename = pdmR3FileR3("VBoxDD2", true /*fShared*/);
504 if (!pszFilename)
505 return VERR_NO_TMP_MEMORY;
506 rc = pdmR3DevLoad(pVM, &RegCB, pszFilename, "VBoxDD2");
507 RTMemTmpFree(pszFilename);
508 if (RT_FAILURE(rc))
509 return rc;
510 }
511
512 /*
513 * Load additional device modules.
514 */
515 PCFGMNODE pCur;
516 for (pCur = CFGMR3GetFirstChild(pDevicesNode); pCur; pCur = CFGMR3GetNextChild(pCur))
517 {
518 /*
519 * Get the name and path.
520 */
521 char szName[PDMMOD_NAME_LEN];
522 rc = CFGMR3GetName(pCur, &szName[0], sizeof(szName));
523 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
524 {
525 AssertMsgFailed(("configuration error: The module name is too long, cchName=%zu.\n", CFGMR3GetNameLen(pCur)));
526 return VERR_PDM_MODULE_NAME_TOO_LONG;
527 }
528 else if (RT_FAILURE(rc))
529 {
530 AssertMsgFailed(("CFGMR3GetName -> %Rrc.\n", rc));
531 return rc;
532 }
533
534 /* the path is optional, if no path the module name + path is used. */
535 char szFilename[RTPATH_MAX];
536 rc = CFGMR3QueryString(pCur, "Path", &szFilename[0], sizeof(szFilename));
537 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
538 strcpy(szFilename, szName);
539 else if (RT_FAILURE(rc))
540 {
541 AssertMsgFailed(("configuration error: Failure to query the module path, rc=%Rrc.\n", rc));
542 return rc;
543 }
544
545 /* prepend path? */
546 if (!RTPathHavePath(szFilename))
547 {
548 char *psz = pdmR3FileR3(szFilename, false /*fShared*/);
549 if (!psz)
550 return VERR_NO_TMP_MEMORY;
551 size_t cch = strlen(psz) + 1;
552 if (cch > sizeof(szFilename))
553 {
554 RTMemTmpFree(psz);
555 AssertMsgFailed(("Filename too long! cch=%d '%s'\n", cch, psz));
556 return VERR_FILENAME_TOO_LONG;
557 }
558 memcpy(szFilename, psz, cch);
559 RTMemTmpFree(psz);
560 }
561
562 /*
563 * Load the module and register it's devices.
564 */
565 RegCB.pCfgNode = pCur;
566 rc = pdmR3DevLoad(pVM, &RegCB, szFilename, szName);
567 if (RT_FAILURE(rc))
568 return rc;
569 }
570
571 return VINF_SUCCESS;
572}
573
574
575/**
576 * Loads one device module and call the registration entry point.
577 *
578 * @returns VBox status code.
579 * @param pVM VM handle.
580 * @param pRegCB The registration callback stuff.
581 * @param pszFilename Module filename.
582 * @param pszName Module name.
583 */
584static int pdmR3DevLoad(PVM pVM, PPDMDEVREGCBINT pRegCB, const char *pszFilename, const char *pszName)
585{
586 /*
587 * Load it.
588 */
589 int rc = pdmR3LoadR3U(pVM->pUVM, pszFilename, pszName);
590 if (RT_SUCCESS(rc))
591 {
592 /*
593 * Get the registration export and call it.
594 */
595 FNPDMVBOXDEVICESREGISTER *pfnVBoxDevicesRegister;
596 rc = PDMR3LdrGetSymbolR3(pVM, pszName, "VBoxDevicesRegister", (void **)&pfnVBoxDevicesRegister);
597 if (RT_SUCCESS(rc))
598 {
599 Log(("PDM: Calling VBoxDevicesRegister (%p) of %s (%s)\n", pfnVBoxDevicesRegister, pszName, pszFilename));
600 rc = pfnVBoxDevicesRegister(&pRegCB->Core, VBOX_VERSION);
601 if (RT_SUCCESS(rc))
602 Log(("PDM: Successfully loaded device module %s (%s).\n", pszName, pszFilename));
603 else
604 AssertMsgFailed(("VBoxDevicesRegister failed with rc=%Rrc for module %s (%s)\n", rc, pszName, pszFilename));
605 }
606 else
607 {
608 AssertMsgFailed(("Failed to locate 'VBoxDevicesRegister' in %s (%s) rc=%Rrc\n", pszName, pszFilename, rc));
609 if (rc == VERR_SYMBOL_NOT_FOUND)
610 rc = VERR_PDM_NO_REGISTRATION_EXPORT;
611 }
612 }
613 else
614 AssertMsgFailed(("Failed to load %s %s!\n", pszFilename, pszName));
615 return rc;
616}
617
618
619/**
620 * @interface_method_impl{PDMDEVREGCB,pfnRegister}
621 */
622static DECLCALLBACK(int) pdmR3DevReg_Register(PPDMDEVREGCB pCallbacks, PCPDMDEVREG pReg)
623{
624 /*
625 * Validate the registration structure.
626 */
627 Assert(pReg);
628 AssertMsgReturn(pReg->u32Version == PDM_DEVREG_VERSION,
629 ("Unknown struct version %#x!\n", pReg->u32Version),
630 VERR_PDM_UNKNOWN_DEVREG_VERSION);
631
632 AssertMsgReturn( pReg->szName[0]
633 && strlen(pReg->szName) < sizeof(pReg->szName)
634 && pdmR3IsValidName(pReg->szName),
635 ("Invalid name '%.s'\n", sizeof(pReg->szName), pReg->szName),
636 VERR_PDM_INVALID_DEVICE_REGISTRATION);
637 AssertMsgReturn( !(pReg->fFlags & PDM_DEVREG_FLAGS_RC)
638 || ( pReg->szRCMod[0]
639 && strlen(pReg->szRCMod) < sizeof(pReg->szRCMod)),
640 ("Invalid GC module name '%s' - (Device %s)\n", pReg->szRCMod, pReg->szName),
641 VERR_PDM_INVALID_DEVICE_REGISTRATION);
642 AssertMsgReturn( !(pReg->fFlags & PDM_DEVREG_FLAGS_R0)
643 || ( pReg->szR0Mod[0]
644 && strlen(pReg->szR0Mod) < sizeof(pReg->szR0Mod)),
645 ("Invalid R0 module name '%s' - (Device %s)\n", pReg->szR0Mod, pReg->szName),
646 VERR_PDM_INVALID_DEVICE_REGISTRATION);
647 AssertMsgReturn((pReg->fFlags & PDM_DEVREG_FLAGS_HOST_BITS_MASK) == PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT,
648 ("Invalid host bits flags! fFlags=%#x (Device %s)\n", pReg->fFlags, pReg->szName),
649 VERR_PDM_INVALID_DEVICE_HOST_BITS);
650 AssertMsgReturn((pReg->fFlags & PDM_DEVREG_FLAGS_GUEST_BITS_MASK),
651 ("Invalid guest bits flags! fFlags=%#x (Device %s)\n", pReg->fFlags, pReg->szName),
652 VERR_PDM_INVALID_DEVICE_REGISTRATION);
653 AssertMsgReturn(pReg->fClass,
654 ("No class! (Device %s)\n", pReg->szName),
655 VERR_PDM_INVALID_DEVICE_REGISTRATION);
656 AssertMsgReturn(pReg->cMaxInstances > 0,
657 ("Max instances %u! (Device %s)\n", pReg->cMaxInstances, pReg->szName),
658 VERR_PDM_INVALID_DEVICE_REGISTRATION);
659 AssertMsgReturn(pReg->cbInstance <= (uint32_t)(pReg->fFlags & (PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0) ? 96 * _1K : _1M),
660 ("Instance size %d bytes! (Device %s)\n", pReg->cbInstance, pReg->szName),
661 VERR_PDM_INVALID_DEVICE_REGISTRATION);
662 AssertMsgReturn(pReg->pfnConstruct,
663 ("No constructor! (Device %s)\n", pReg->szName),
664 VERR_PDM_INVALID_DEVICE_REGISTRATION);
665 AssertLogRelMsgReturn((pReg->fFlags & PDM_DEVREG_FLAGS_GUEST_BITS_MASK) == PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT,
666 ("PDM: Rejected device '%s' because it didn't match the guest bits.\n", pReg->szName),
667 VERR_PDM_INVALID_DEVICE_GUEST_BITS);
668 AssertLogRelMsg(pReg->u32VersionEnd == PDM_DEVREG_VERSION,
669 ("u32VersionEnd=%#x, expected %#x. (szName=%s)\n",
670 pReg->u32VersionEnd, PDM_DEVREG_VERSION, pReg->szName));
671
672 /*
673 * Check for duplicate and find FIFO entry at the same time.
674 */
675 PCPDMDEVREGCBINT pRegCB = (PCPDMDEVREGCBINT)pCallbacks;
676 PPDMDEV pDevPrev = NULL;
677 PPDMDEV pDev = pRegCB->pVM->pdm.s.pDevs;
678 for (; pDev; pDevPrev = pDev, pDev = pDev->pNext)
679 AssertMsgReturn(strcmp(pDev->pReg->szName, pReg->szName),
680 ("Device '%s' already exists\n", pReg->szName),
681 VERR_PDM_DEVICE_NAME_CLASH);
682
683 /*
684 * Allocate new device structure, initialize and insert it into the list.
685 */
686 int rc;
687 pDev = (PPDMDEV)MMR3HeapAlloc(pRegCB->pVM, MM_TAG_PDM_DEVICE, sizeof(*pDev));
688 if (pDev)
689 {
690 pDev->pNext = NULL;
691 pDev->cInstances = 0;
692 pDev->pInstances = NULL;
693 pDev->pReg = pReg;
694 pDev->cchName = (uint32_t)strlen(pReg->szName);
695 rc = CFGMR3QueryStringAllocDef( pRegCB->pCfgNode, "RCSearchPath", &pDev->pszRCSearchPath, NULL);
696 if (RT_SUCCESS(rc))
697 rc = CFGMR3QueryStringAllocDef(pRegCB->pCfgNode, "R0SearchPath", &pDev->pszR0SearchPath, NULL);
698 if (RT_SUCCESS(rc))
699 {
700 if (pDevPrev)
701 pDevPrev->pNext = pDev;
702 else
703 pRegCB->pVM->pdm.s.pDevs = pDev;
704 Log(("PDM: Registered device '%s'\n", pReg->szName));
705 return VINF_SUCCESS;
706 }
707
708 MMR3HeapFree(pDev);
709 }
710 else
711 rc = VERR_NO_MEMORY;
712 return rc;
713}
714
715
716/**
717 * Locates a LUN.
718 *
719 * @returns VBox status code.
720 * @param pVM VM Handle.
721 * @param pszDevice Device name.
722 * @param iInstance Device instance.
723 * @param iLun The Logical Unit to obtain the interface of.
724 * @param ppLun Where to store the pointer to the LUN if found.
725 * @thread Try only do this in EMT...
726 */
727int pdmR3DevFindLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPPDMLUN ppLun)
728{
729 /*
730 * Iterate registered devices looking for the device.
731 */
732 size_t cchDevice = strlen(pszDevice);
733 for (PPDMDEV pDev = pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
734 {
735 if ( pDev->cchName == cchDevice
736 && !memcmp(pDev->pReg->szName, pszDevice, cchDevice))
737 {
738 /*
739 * Iterate device instances.
740 */
741 for (PPDMDEVINS pDevIns = pDev->pInstances; pDevIns; pDevIns = pDevIns->Internal.s.pPerDeviceNextR3)
742 {
743 if (pDevIns->iInstance == iInstance)
744 {
745 /*
746 * Iterate luns.
747 */
748 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
749 {
750 if (pLun->iLun == iLun)
751 {
752 *ppLun = pLun;
753 return VINF_SUCCESS;
754 }
755 }
756 return VERR_PDM_LUN_NOT_FOUND;
757 }
758 }
759 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND;
760 }
761 }
762 return VERR_PDM_DEVICE_NOT_FOUND;
763}
764
765
766/**
767 * Attaches a preconfigured driver to an existing device instance.
768 *
769 * This is used to change drivers and suchlike at runtime.
770 *
771 * @returns VBox status code.
772 * @param pVM VM Handle.
773 * @param pszDevice Device name.
774 * @param iInstance Device instance.
775 * @param iLun The Logical Unit to obtain the interface of.
776 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
777 * @param ppBase Where to store the base interface pointer. Optional.
778 * @thread EMT
779 */
780VMMR3DECL(int) PDMR3DeviceAttach(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, uint32_t fFlags, PPPDMIBASE ppBase)
781{
782 VM_ASSERT_EMT(pVM);
783 LogFlow(("PDMR3DeviceAttach: pszDevice=%p:{%s} iInstance=%d iLun=%d fFlags=%#x ppBase=%p\n",
784 pszDevice, pszDevice, iInstance, iLun, fFlags, ppBase));
785
786 /*
787 * Find the LUN in question.
788 */
789 PPDMLUN pLun;
790 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
791 if (RT_SUCCESS(rc))
792 {
793 /*
794 * Can we attach anything at runtime?
795 */
796 PPDMDEVINS pDevIns = pLun->pDevIns;
797 if (pDevIns->pReg->pfnAttach)
798 {
799 if (!pLun->pTop)
800 {
801 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
802 rc = pDevIns->pReg->pfnAttach(pDevIns, iLun, fFlags);
803 PDMCritSectLeave(pDevIns->pCritSectRoR3);
804 }
805 else
806 rc = VERR_PDM_DRIVER_ALREADY_ATTACHED;
807 }
808 else
809 rc = VERR_PDM_DEVICE_NO_RT_ATTACH;
810
811 if (ppBase)
812 *ppBase = pLun->pTop ? &pLun->pTop->IBase : NULL;
813 }
814 else if (ppBase)
815 *ppBase = NULL;
816
817 if (ppBase)
818 LogFlow(("PDMR3DeviceAttach: returns %Rrc *ppBase=%p\n", rc, *ppBase));
819 else
820 LogFlow(("PDMR3DeviceAttach: returns %Rrc\n", rc));
821 return rc;
822}
823
824
825/**
826 * Detaches a driver chain from an existing device instance.
827 *
828 * This is used to change drivers and suchlike at runtime.
829 *
830 * @returns VBox status code.
831 * @param pVM VM Handle.
832 * @param pszDevice Device name.
833 * @param iInstance Device instance.
834 * @param iLun The Logical Unit to obtain the interface of.
835 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
836 * @thread EMT
837 */
838VMMR3DECL(int) PDMR3DeviceDetach(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, uint32_t fFlags)
839{
840 return PDMR3DriverDetach(pVM, pszDevice, iInstance, iLun, NULL, 0, fFlags);
841}
842
843
844/**
845 * References the critical section associated with a device for the use by a
846 * timer or similar created by the device.
847 *
848 * @returns Pointer to the critical section.
849 * @param pVM The VM handle.
850 * @param pDevIns The device instance in question.
851 *
852 * @internal
853 */
854VMMR3_INT_DECL(PPDMCRITSECT) PDMR3DevGetCritSect(PVM pVM, PPDMDEVINS pDevIns)
855{
856 VM_ASSERT_EMT(pVM);
857 VM_ASSERT_STATE(pVM, VMSTATE_CREATING);
858 AssertPtr(pDevIns);
859
860 PPDMCRITSECT pCritSect = pDevIns->pCritSectRoR3;
861 AssertPtr(pCritSect);
862 pCritSect->s.fUsedByTimerOrSimilar = true;
863
864 return pCritSect;
865}
866
867
868/**
869 * Attaches a preconfigured driver to an existing device or driver instance.
870 *
871 * This is used to change drivers and suchlike at runtime. The driver or device
872 * at the end of the chain will be told to attach to whatever is configured
873 * below it.
874 *
875 * @returns VBox status code.
876 * @param pVM VM Handle.
877 * @param pszDevice Device name.
878 * @param iInstance Device instance.
879 * @param iLun The Logical Unit to obtain the interface of.
880 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
881 * @param ppBase Where to store the base interface pointer. Optional.
882 *
883 * @thread EMT
884 */
885VMMR3DECL(int) PDMR3DriverAttach(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, uint32_t fFlags, PPPDMIBASE ppBase)
886{
887 VM_ASSERT_EMT(pVM);
888 LogFlow(("PDMR3DriverAttach: pszDevice=%p:{%s} iInstance=%d iLun=%d fFlags=%#x ppBase=%p\n",
889 pszDevice, pszDevice, iInstance, iLun, fFlags, ppBase));
890
891 if (ppBase)
892 *ppBase = NULL;
893
894 /*
895 * Find the LUN in question.
896 */
897 PPDMLUN pLun;
898 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
899 if (RT_SUCCESS(rc))
900 {
901 /*
902 * Anything attached to the LUN?
903 */
904 PPDMDRVINS pDrvIns = pLun->pTop;
905 if (!pDrvIns)
906 {
907 /* No, ask the device to attach to the new stuff. */
908 PPDMDEVINS pDevIns = pLun->pDevIns;
909 if (pDevIns->pReg->pfnAttach)
910 {
911 PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
912 rc = pDevIns->pReg->pfnAttach(pDevIns, iLun, fFlags);
913 if (RT_SUCCESS(rc) && ppBase)
914 *ppBase = pLun->pTop ? &pLun->pTop->IBase : NULL;
915 PDMCritSectLeave(pDevIns->pCritSectRoR3);
916 }
917 else
918 rc = VERR_PDM_DEVICE_NO_RT_ATTACH;
919 }
920 else
921 {
922 /* Yes, find the bottom most driver and ask it to attach to the new stuff. */
923 while (pDrvIns->Internal.s.pDown)
924 pDrvIns = pDrvIns->Internal.s.pDown;
925 if (pDrvIns->pReg->pfnAttach)
926 {
927 rc = pDrvIns->pReg->pfnAttach(pDrvIns, fFlags);
928 if (RT_SUCCESS(rc) && ppBase)
929 *ppBase = pDrvIns->Internal.s.pDown
930 ? &pDrvIns->Internal.s.pDown->IBase
931 : NULL;
932 }
933 else
934 rc = VERR_PDM_DRIVER_NO_RT_ATTACH;
935 }
936 }
937
938 if (ppBase)
939 LogFlow(("PDMR3DriverAttach: returns %Rrc *ppBase=%p\n", rc, *ppBase));
940 else
941 LogFlow(("PDMR3DriverAttach: returns %Rrc\n", rc));
942 return rc;
943}
944
945
946/**
947 * Detaches the specified driver instance.
948 *
949 * This is used to replumb drivers at runtime for simulating hot plugging and
950 * media changes.
951 *
952 * This is a superset of PDMR3DeviceDetach. It allows detaching drivers from
953 * any driver or device by specifying the driver to start detaching at. The
954 * only prerequisite is that the driver or device above implements the
955 * pfnDetach callback (PDMDRVREG / PDMDEVREG).
956 *
957 * @returns VBox status code.
958 * @param pVM VM Handle.
959 * @param pszDevice Device name.
960 * @param iDevIns Device instance.
961 * @param iLun The Logical Unit in which to look for the driver.
962 * @param pszDriver The name of the driver which to detach. If NULL
963 * then the entire driver chain is detatched.
964 * @param iOccurance The occurrence of that driver in the chain. This is
965 * usually 0.
966 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
967 * @thread EMT
968 */
969VMMR3DECL(int) PDMR3DriverDetach(PVM pVM, const char *pszDevice, unsigned iDevIns, unsigned iLun,
970 const char *pszDriver, unsigned iOccurance, uint32_t fFlags)
971{
972 LogFlow(("PDMR3DriverDetach: pszDevice=%p:{%s} iDevIns=%u iLun=%u pszDriver=%p:{%s} iOccurance=%u fFlags=%#x\n",
973 pszDevice, pszDevice, iDevIns, iLun, pszDriver, iOccurance, fFlags));
974 VM_ASSERT_EMT(pVM);
975 AssertPtr(pszDevice);
976 AssertPtrNull(pszDriver);
977 Assert(iOccurance == 0 || pszDriver);
978 Assert(!(fFlags & ~(PDM_TACH_FLAGS_NOT_HOT_PLUG)));
979
980 /*
981 * Find the LUN in question.
982 */
983 PPDMLUN pLun;
984 int rc = pdmR3DevFindLun(pVM, pszDevice, iDevIns, iLun, &pLun);
985 if (RT_SUCCESS(rc))
986 {
987 /*
988 * Locate the driver.
989 */
990 PPDMDRVINS pDrvIns = pLun->pTop;
991 if (pDrvIns)
992 {
993 if (pszDriver)
994 {
995 while (pDrvIns)
996 {
997 if (!strcmp(pDrvIns->pReg->szName, pszDriver))
998 {
999 if (iOccurance == 0)
1000 break;
1001 iOccurance--;
1002 }
1003 pDrvIns = pDrvIns->Internal.s.pDown;
1004 }
1005 }
1006 if (pDrvIns)
1007 rc = pdmR3DrvDetach(pDrvIns, fFlags);
1008 else
1009 rc = VERR_PDM_DRIVER_INSTANCE_NOT_FOUND;
1010 }
1011 else
1012 rc = VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN;
1013 }
1014
1015 LogFlow(("PDMR3DriverDetach: returns %Rrc\n", rc));
1016 return rc;
1017}
1018
1019
1020/**
1021 * Runtime detach and reattach of a new driver chain or sub chain.
1022 *
1023 * This is intended to be called on a non-EMT thread, this will instantiate the
1024 * new driver (sub-)chain, and then the EMTs will do the actual replumbing. The
1025 * destruction of the old driver chain will be taken care of on the calling
1026 * thread.
1027 *
1028 * @returns VBox status code.
1029 * @param pVM VM Handle.
1030 * @param pszDevice Device name.
1031 * @param iDevIns Device instance.
1032 * @param iLun The Logical Unit in which to look for the driver.
1033 * @param pszDriver The name of the driver which to detach and replace.
1034 * If NULL then the entire driver chain is to be
1035 * reattached.
1036 * @param iOccurance The occurrence of that driver in the chain. This is
1037 * usually 0.
1038 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1039 * @param pCfg The configuration of the new driver chain that is
1040 * going to be attached. The subtree starts with the
1041 * node containing a Driver key, a Config subtree and
1042 * optionally an AttachedDriver subtree.
1043 * If this parameter is NULL, then this call will work
1044 * like at a non-pause version of PDMR3DriverDetach.
1045 * @param ppBase Where to store the base interface pointer to the new
1046 * driver. Optional.
1047 *
1048 * @thread Any thread. The EMTs will be involved at some point though.
1049 */
1050VMMR3DECL(int) PDMR3DriverReattach(PVM pVM, const char *pszDevice, unsigned iDevIns, unsigned iLun,
1051 const char *pszDriver, unsigned iOccurance, uint32_t fFlags,
1052 PCFGMNODE pCfg, PPPDMIBASE ppBase)
1053{
1054 NOREF(pVM); NOREF(pszDevice); NOREF(iDevIns); NOREF(iLun); NOREF(pszDriver); NOREF(iOccurance);
1055 NOREF(fFlags); NOREF(pCfg); NOREF(ppBase);
1056 return VERR_NOT_IMPLEMENTED;
1057}
1058
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