VirtualBox

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

Last change on this file since 33000 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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

© 2023 Oracle
ContactPrivacy policyTerms of Use