VirtualBox

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

Last change on this file since 45103 was 44528, checked in by vboxsync, 12 years ago

header (C) fixes

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