VirtualBox

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

Last change on this file since 28112 was 26944, checked in by vboxsync, 15 years ago

PDM,IOM,TM: Added an optional per-device critsect for avoiding the global IOM lock. Only port I/O and timer callbacks use it, cannot yet be used with MMIO callbacks (will assert and fail).

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