VirtualBox

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

Last change on this file since 36944 was 35810, checked in by vboxsync, 14 years ago

VMM: Replace most VERR_VERSION_MISMATCH by more specific error statuses. Translating the errors returned by device, driver and USB device constructors into specific ones for the benefit of old extension pack and misc use of the status.

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