VirtualBox

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

Last change on this file since 16462 was 14299, checked in by vboxsync, 16 years ago

Corrected grammos in comments. No code changes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 29.9 KB
Line 
1/* $Id: PDMDevice.cpp 14299 2008-11-18 13:25:40Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device and Driver Manager, Device parts.
4 */
5
6/*
7 * Copyright (C) 2006-2007 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 pDevReg);
78static DECLCALLBACK(void *) pdmR3DevReg_MMHeapAlloc(PPDMDEVREGCB pCallbacks, size_t cb);
79static int pdmR3DevLoadModules(PVM pVM);
80static int pdmR3DevLoad(PVM pVM, PPDMDEVREGCBINT pRegCB, const char *pszFilename, const char *pszName);
81
82
83
84
85/**
86 * This function will initialize the devices for this VM instance.
87 *
88 *
89 * First of all this mean loading the builtin device and letting them
90 * register themselves. Beyond that any additional device modules are
91 * loaded and called for registration.
92 *
93 * Then the device configuration is enumerated, the instantiation order
94 * is determined, and finally they are instantiated.
95 *
96 * After all devices have been successfully instantiated the primary
97 * PCI Bus device is called to emulate the PCI BIOS, i.e. making the
98 * resource assignments. If there is no PCI device, this step is of course
99 * skipped.
100 *
101 * Finally the init completion routines of the instantiated devices
102 * are called.
103 *
104 * @returns VBox status code.
105 * @param pVM VM Handle.
106 */
107int pdmR3DevInit(PVM pVM)
108{
109 LogFlow(("pdmR3DevInit:\n"));
110
111 AssertRelease(!(RT_OFFSETOF(PDMDEVINS, achInstanceData) & 15));
112 AssertRelease(sizeof(pVM->pdm.s.pDevInstances->Internal.s) <= sizeof(pVM->pdm.s.pDevInstances->Internal.padding));
113
114 /*
115 * Load device modules.
116 */
117 int rc = pdmR3DevLoadModules(pVM);
118 if (RT_FAILURE(rc))
119 return rc;
120
121#ifdef VBOX_WITH_USB
122 /* ditto for USB Devices. */
123 rc = pdmR3UsbLoadModules(pVM);
124 if (RT_FAILURE(rc))
125 return rc;
126#endif
127
128 /*
129 * Get the RC & R0 devhlps and create the devhlp R3 task queue.
130 */
131 PCPDMDEVHLPRC pDevHlpRC;
132 rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDevHlp", &pDevHlpRC);
133 AssertReleaseRCReturn(rc, rc);
134
135 PCPDMDEVHLPR0 pDevHlpR0;
136 rc = PDMR3LdrGetSymbolR0(pVM, NULL, "g_pdmR0DevHlp", &pDevHlpR0);
137 AssertReleaseRCReturn(rc, rc);
138
139 rc = PDMR3QueueCreateInternal(pVM, sizeof(PDMDEVHLPTASK), 8, 0, pdmR3DevHlpQueueConsumer, true, &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->pDevReg->szDeviceName)];
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->pDevReg->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 for (pInstanceNode = CFGMR3GetFirstChild(pCur); pInstanceNode; pInstanceNode = CFGMR3GetNextChild(pInstanceNode))
211 {
212 paDevs[i].pNode = pInstanceNode;
213 paDevs[i].pDev = pDev;
214 paDevs[i].u32Order = u32Order;
215
216 /* Get the instance number. */
217 char szInstance[32];
218 rc = CFGMR3GetName(pInstanceNode, szInstance, sizeof(szInstance));
219 AssertMsgRCReturn(rc, ("Configuration error: instance name is too long (or something)! rc=%Rrc\n", rc), rc);
220 char *pszNext = NULL;
221 rc = RTStrToUInt32Ex(szInstance, &pszNext, 0, &paDevs[i].iInstance);
222 AssertMsgRCReturn(rc, ("Configuration error: RTStrToInt32Ex failed on the instance name '%s'! rc=%Rrc\n", szInstance, rc), rc);
223 AssertMsgReturn(!*pszNext, ("Configuration error: the instance name '%s' isn't all digits. (%s)\n", szInstance, pszNext), VERR_INVALID_PARAMETER);
224
225 /* next instance */
226 i++;
227 }
228 } /* devices */
229 Assert(i == cDevs);
230
231 /*
232 * Sort the device array ascending on u32Order. (bubble)
233 */
234 unsigned c = cDevs - 1;
235 while (c)
236 {
237 unsigned j = 0;
238 for (i = 0; i < c; i++)
239 if (paDevs[i].u32Order > paDevs[i + 1].u32Order)
240 {
241 paDevs[cDevs] = paDevs[i + 1];
242 paDevs[i + 1] = paDevs[i];
243 paDevs[i] = paDevs[cDevs];
244 j = i;
245 }
246 c = j;
247 }
248
249
250 /*
251 *
252 * Instantiate the devices.
253 *
254 */
255 for (i = 0; i < cDevs; i++)
256 {
257 /*
258 * Gather a bit of config.
259 */
260 /* trusted */
261 bool fTrusted;
262 rc = CFGMR3QueryBool(paDevs[i].pNode, "Trusted", &fTrusted);
263 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
264 fTrusted = false;
265 else if (RT_FAILURE(rc))
266 {
267 AssertMsgFailed(("configuration error: failed to query boolean \"Trusted\", rc=%Rrc\n", rc));
268 return rc;
269 }
270 /* config node */
271 PCFGMNODE pConfigNode = CFGMR3GetChild(paDevs[i].pNode, "Config");
272 if (!pConfigNode)
273 {
274 rc = CFGMR3InsertNode(paDevs[i].pNode, "Config", &pConfigNode);
275 if (RT_FAILURE(rc))
276 {
277 AssertMsgFailed(("Failed to create Config node! rc=%Rrc\n", rc));
278 return rc;
279 }
280 }
281 CFGMR3SetRestrictedRoot(pConfigNode);
282
283 /*
284 * Allocate the device instance.
285 */
286 size_t cb = RT_OFFSETOF(PDMDEVINS, achInstanceData[paDevs[i].pDev->pDevReg->cbInstance]);
287 cb = RT_ALIGN_Z(cb, 16);
288 PPDMDEVINS pDevIns;
289 if (paDevs[i].pDev->pDevReg->fFlags & (PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0))
290 rc = MMR3HyperAllocOnceNoRel(pVM, cb, 0, MM_TAG_PDM_DEVICE, (void **)&pDevIns);
291 else
292 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_DEVICE, cb, (void **)&pDevIns);
293 if (RT_FAILURE(rc))
294 {
295 AssertMsgFailed(("Failed to allocate %d bytes of instance data for device '%s'. rc=%Rrc\n",
296 cb, paDevs[i].pDev->pDevReg->szDeviceName, rc));
297 return rc;
298 }
299
300 /*
301 * Initialize it.
302 */
303 pDevIns->u32Version = PDM_DEVINS_VERSION;
304 //pDevIns->Internal.s.pNextR3 = NULL;
305 //pDevIns->Internal.s.pPerDeviceNextR3 = NULL;
306 pDevIns->Internal.s.pDevR3 = paDevs[i].pDev;
307 pDevIns->Internal.s.pVMR3 = pVM;
308 pDevIns->Internal.s.pVMR0 = pVM->pVMR0;
309 pDevIns->Internal.s.pVMRC = pVM->pVMRC;
310 //pDevIns->Internal.s.pLunsR3 = NULL;
311 pDevIns->Internal.s.pCfgHandle = paDevs[i].pNode;
312 //pDevIns->Internal.s.pPciDeviceR3 = NULL;
313 //pDevIns->Internal.s.pPciBusR3 = NULL;
314 //pDevIns->Internal.s.pPciDeviceR0 = 0;
315 //pDevIns->Internal.s.pPciBusR0 = 0;
316 //pDevIns->Internal.s.pPciDeviceRC = 0;
317 //pDevIns->Internal.s.pPciBusRC = 0;
318 pDevIns->pDevHlpR3 = fTrusted ? &g_pdmR3DevHlpTrusted : &g_pdmR3DevHlpUnTrusted;
319 pDevIns->pDevHlpRC = pDevHlpRC;
320 pDevIns->pDevHlpR0 = pDevHlpR0;
321 pDevIns->pDevReg = paDevs[i].pDev->pDevReg;
322 pDevIns->pCfgHandle = pConfigNode;
323 pDevIns->iInstance = paDevs[i].iInstance;
324 pDevIns->pvInstanceDataR3 = &pDevIns->achInstanceData[0];
325 pDevIns->pvInstanceDataRC = pDevIns->pDevReg->fFlags & PDM_DEVREG_FLAGS_RC
326 ? MMHyperR3ToRC(pVM, pDevIns->pvInstanceDataR3) : NIL_RTRCPTR;
327 pDevIns->pvInstanceDataR0 = pDevIns->pDevReg->fFlags & PDM_DEVREG_FLAGS_R0
328 ? MMHyperR3ToR0(pVM, pDevIns->pvInstanceDataR3) : NIL_RTR0PTR;
329
330 /*
331 * Link it into all the lists.
332 */
333 /* The global instance FIFO. */
334 PPDMDEVINS pPrev1 = pVM->pdm.s.pDevInstances;
335 if (!pPrev1)
336 pVM->pdm.s.pDevInstances = pDevIns;
337 else
338 {
339 while (pPrev1->Internal.s.pNextR3)
340 pPrev1 = pPrev1->Internal.s.pNextR3;
341 pPrev1->Internal.s.pNextR3 = pDevIns;
342 }
343
344 /* The per device instance FIFO. */
345 PPDMDEVINS pPrev2 = paDevs[i].pDev->pInstances;
346 if (!pPrev2)
347 paDevs[i].pDev->pInstances = pDevIns;
348 else
349 {
350 while (pPrev2->Internal.s.pPerDeviceNextR3)
351 pPrev2 = pPrev2->Internal.s.pPerDeviceNextR3;
352 pPrev2->Internal.s.pPerDeviceNextR3 = pDevIns;
353 }
354
355 /*
356 * Call the constructor.
357 */
358 Log(("PDM: Constructing device '%s' instance %d...\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
359 rc = pDevIns->pDevReg->pfnConstruct(pDevIns, pDevIns->iInstance, pDevIns->pCfgHandle);
360 if (RT_FAILURE(rc))
361 {
362 LogRel(("PDM: Failed to construct '%s'/%d! %Rra\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance, rc));
363 /* because we're damn lazy right now, we'll say that the destructor will be called even if the constructor fails. */
364 return rc;
365 }
366 } /* for device instances */
367
368#ifdef VBOX_WITH_USB
369 /* ditto for USB Devices. */
370 rc = pdmR3UsbInstantiateDevices(pVM);
371 if (RT_FAILURE(rc))
372 return rc;
373#endif
374
375
376 /*
377 *
378 * PCI BIOS Fake and Init Complete.
379 *
380 */
381 if (pVM->pdm.s.aPciBuses[0].pDevInsR3)
382 {
383 pdmLock(pVM);
384 rc = pVM->pdm.s.aPciBuses[0].pfnFakePCIBIOSR3(pVM->pdm.s.aPciBuses[0].pDevInsR3);
385 pdmUnlock(pVM);
386 if (RT_FAILURE(rc))
387 {
388 AssertMsgFailed(("PCI BIOS fake failed rc=%Rrc\n", rc));
389 return rc;
390 }
391 }
392
393 for (PPDMDEVINS pDevIns = pVM->pdm.s.pDevInstances; pDevIns; pDevIns = pDevIns->Internal.s.pNextR3)
394 {
395 if (pDevIns->pDevReg->pfnInitComplete)
396 {
397 rc = pDevIns->pDevReg->pfnInitComplete(pDevIns);
398 if (RT_FAILURE(rc))
399 {
400 AssertMsgFailed(("InitComplete on device '%s'/%d failed with rc=%Rrc\n",
401 pDevIns->pDevReg->szDeviceName, pDevIns->iInstance, rc));
402 return rc;
403 }
404 }
405 }
406
407#ifdef VBOX_WITH_USB
408 /* ditto for USB Devices. */
409 rc = pdmR3UsbVMInitComplete(pVM);
410 if (RT_FAILURE(rc))
411 return rc;
412#endif
413
414 LogFlow(("pdmR3DevInit: returns %Rrc\n", VINF_SUCCESS));
415 return VINF_SUCCESS;
416}
417
418
419/**
420 * Lookups a device structure by name.
421 * @internal
422 */
423PPDMDEV pdmR3DevLookup(PVM pVM, const char *pszName)
424{
425 size_t cchName = strlen(pszName);
426 for (PPDMDEV pDev = pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
427 if ( pDev->cchName == cchName
428 && !strcmp(pDev->pDevReg->szDeviceName, pszName))
429 return pDev;
430 return NULL;
431}
432
433
434/**
435 * Loads the device modules.
436 *
437 * @returns VBox status code.
438 * @param pVM Pointer to the shared VM structure.
439 */
440static int pdmR3DevLoadModules(PVM pVM)
441{
442 /*
443 * Initialize the callback structure.
444 */
445 PDMDEVREGCBINT RegCB;
446 RegCB.Core.u32Version = PDM_DEVREG_CB_VERSION;
447 RegCB.Core.pfnRegister = pdmR3DevReg_Register;
448 RegCB.Core.pfnMMHeapAlloc = pdmR3DevReg_MMHeapAlloc;
449 RegCB.pVM = pVM;
450
451 /*
452 * Load the builtin module
453 */
454 PCFGMNODE pDevicesNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "PDM/Devices");
455 bool fLoadBuiltin;
456 int rc = CFGMR3QueryBool(pDevicesNode, "LoadBuiltin", &fLoadBuiltin);
457 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
458 fLoadBuiltin = true;
459 else if (RT_FAILURE(rc))
460 {
461 AssertMsgFailed(("Configuration error: Querying boolean \"LoadBuiltin\" failed with %Rrc\n", rc));
462 return rc;
463 }
464 if (fLoadBuiltin)
465 {
466 /* make filename */
467 char *pszFilename = pdmR3FileR3("VBoxDD", /* fShared = */ true);
468 if (!pszFilename)
469 return VERR_NO_TMP_MEMORY;
470 rc = pdmR3DevLoad(pVM, &RegCB, pszFilename, "VBoxDD");
471 RTMemTmpFree(pszFilename);
472 if (RT_FAILURE(rc))
473 return rc;
474
475 /* make filename */
476 pszFilename = pdmR3FileR3("VBoxDD2", /* fShared = */ true);
477 if (!pszFilename)
478 return VERR_NO_TMP_MEMORY;
479 rc = pdmR3DevLoad(pVM, &RegCB, pszFilename, "VBoxDD2");
480 RTMemTmpFree(pszFilename);
481 if (RT_FAILURE(rc))
482 return rc;
483 }
484
485 /*
486 * Load additional device modules.
487 */
488 PCFGMNODE pCur;
489 for (pCur = CFGMR3GetFirstChild(pDevicesNode); pCur; pCur = CFGMR3GetNextChild(pCur))
490 {
491 /*
492 * Get the name and path.
493 */
494 char szName[PDMMOD_NAME_LEN];
495 rc = CFGMR3GetName(pCur, &szName[0], sizeof(szName));
496 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
497 {
498 AssertMsgFailed(("configuration error: The module name is too long, cchName=%zu.\n", CFGMR3GetNameLen(pCur)));
499 return VERR_PDM_MODULE_NAME_TOO_LONG;
500 }
501 else if (RT_FAILURE(rc))
502 {
503 AssertMsgFailed(("CFGMR3GetName -> %Rrc.\n", rc));
504 return rc;
505 }
506
507 /* the path is optional, if no path the module name + path is used. */
508 char szFilename[RTPATH_MAX];
509 rc = CFGMR3QueryString(pCur, "Path", &szFilename[0], sizeof(szFilename));
510 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
511 strcpy(szFilename, szName);
512 else if (RT_FAILURE(rc))
513 {
514 AssertMsgFailed(("configuration error: Failure to query the module path, rc=%Rrc.\n", rc));
515 return rc;
516 }
517
518 /* prepend path? */
519 if (!RTPathHavePath(szFilename))
520 {
521 char *psz = pdmR3FileR3(szFilename);
522 if (!psz)
523 return VERR_NO_TMP_MEMORY;
524 size_t cch = strlen(psz) + 1;
525 if (cch > sizeof(szFilename))
526 {
527 RTMemTmpFree(psz);
528 AssertMsgFailed(("Filename too long! cch=%d '%s'\n", cch, psz));
529 return VERR_FILENAME_TOO_LONG;
530 }
531 memcpy(szFilename, psz, cch);
532 RTMemTmpFree(psz);
533 }
534
535 /*
536 * Load the module and register it's devices.
537 */
538 rc = pdmR3DevLoad(pVM, &RegCB, szFilename, szName);
539 if (RT_FAILURE(rc))
540 return rc;
541 }
542
543 return VINF_SUCCESS;
544}
545
546
547/**
548 * Loads one device module and call the registration entry point.
549 *
550 * @returns VBox status code.
551 * @param pVM VM handle.
552 * @param pRegCB The registration callback stuff.
553 * @param pszFilename Module filename.
554 * @param pszName Module name.
555 */
556static int pdmR3DevLoad(PVM pVM, PPDMDEVREGCBINT pRegCB, const char *pszFilename, const char *pszName)
557{
558 /*
559 * Load it.
560 */
561 int rc = pdmR3LoadR3U(pVM->pUVM, pszFilename, pszName);
562 if (RT_SUCCESS(rc))
563 {
564 /*
565 * Get the registration export and call it.
566 */
567 FNPDMVBOXDEVICESREGISTER *pfnVBoxDevicesRegister;
568 rc = PDMR3LdrGetSymbolR3(pVM, pszName, "VBoxDevicesRegister", (void **)&pfnVBoxDevicesRegister);
569 if (RT_SUCCESS(rc))
570 {
571 Log(("PDM: Calling VBoxDevicesRegister (%p) of %s (%s)\n", pfnVBoxDevicesRegister, pszName, pszFilename));
572 rc = pfnVBoxDevicesRegister(&pRegCB->Core, VBOX_VERSION);
573 if (RT_SUCCESS(rc))
574 Log(("PDM: Successfully loaded device module %s (%s).\n", pszName, pszFilename));
575 else
576 AssertMsgFailed(("VBoxDevicesRegister failed with rc=%Rrc for module %s (%s)\n", rc, pszName, pszFilename));
577 }
578 else
579 {
580 AssertMsgFailed(("Failed to locate 'VBoxDevicesRegister' in %s (%s) rc=%Rrc\n", pszName, pszFilename, rc));
581 if (rc == VERR_SYMBOL_NOT_FOUND)
582 rc = VERR_PDM_NO_REGISTRATION_EXPORT;
583 }
584 }
585 else
586 AssertMsgFailed(("Failed to load %s %s!\n", pszFilename, pszName));
587 return rc;
588}
589
590
591/**
592 * Registers a device with the current VM instance.
593 *
594 * @returns VBox status code.
595 * @param pCallbacks Pointer to the callback table.
596 * @param pDevReg Pointer to the device registration record.
597 * This data must be permanent and readonly.
598 */
599static DECLCALLBACK(int) pdmR3DevReg_Register(PPDMDEVREGCB pCallbacks, PCPDMDEVREG pDevReg)
600{
601 /*
602 * Validate the registration structure.
603 */
604 Assert(pDevReg);
605 if (pDevReg->u32Version != PDM_DEVREG_VERSION)
606 {
607 AssertMsgFailed(("Unknown struct version %#x!\n", pDevReg->u32Version));
608 return VERR_PDM_UNKNOWN_DEVREG_VERSION;
609 }
610 if ( !pDevReg->szDeviceName[0]
611 || strlen(pDevReg->szDeviceName) >= sizeof(pDevReg->szDeviceName))
612 {
613 AssertMsgFailed(("Invalid name '%s'\n", pDevReg->szDeviceName));
614 return VERR_PDM_INVALID_DEVICE_REGISTRATION;
615 }
616 if ( (pDevReg->fFlags & PDM_DEVREG_FLAGS_RC)
617 && ( !pDevReg->szRCMod[0]
618 || strlen(pDevReg->szRCMod) >= sizeof(pDevReg->szRCMod)))
619 {
620 AssertMsgFailed(("Invalid GC module name '%s' - (Device %s)\n", pDevReg->szRCMod, pDevReg->szDeviceName));
621 return VERR_PDM_INVALID_DEVICE_REGISTRATION;
622 }
623 if ( (pDevReg->fFlags & PDM_DEVREG_FLAGS_R0)
624 && ( !pDevReg->szR0Mod[0]
625 || strlen(pDevReg->szR0Mod) >= sizeof(pDevReg->szR0Mod)))
626 {
627 AssertMsgFailed(("Invalid R0 module name '%s' - (Device %s)\n", pDevReg->szR0Mod, pDevReg->szDeviceName));
628 return VERR_PDM_INVALID_DEVICE_REGISTRATION;
629 }
630 if ((pDevReg->fFlags & PDM_DEVREG_FLAGS_HOST_BITS_MASK) != PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT)
631 {
632 AssertMsgFailed(("Invalid host bits flags! fFlags=%#x (Device %s)\n", pDevReg->fFlags, pDevReg->szDeviceName));
633 return VERR_PDM_INVALID_DEVICE_HOST_BITS;
634 }
635 if (!(pDevReg->fFlags & PDM_DEVREG_FLAGS_GUEST_BITS_MASK))
636 {
637 AssertMsgFailed(("Invalid guest bits flags! fFlags=%#x (Device %s)\n", pDevReg->fFlags, pDevReg->szDeviceName));
638 return VERR_PDM_INVALID_DEVICE_REGISTRATION;
639 }
640 if (!pDevReg->fClass)
641 {
642 AssertMsgFailed(("No class! (Device %s)\n", pDevReg->szDeviceName));
643 return VERR_PDM_INVALID_DEVICE_REGISTRATION;
644 }
645 if (pDevReg->cMaxInstances <= 0)
646 {
647 AssertMsgFailed(("Max instances %u! (Device %s)\n", pDevReg->cMaxInstances, pDevReg->szDeviceName));
648 return VERR_PDM_INVALID_DEVICE_REGISTRATION;
649 }
650 if (pDevReg->cbInstance > (RTUINT)(pDevReg->fFlags & (PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0) ? 96 * _1K : _1M))
651 {
652 AssertMsgFailed(("Instance size %d bytes! (Device %s)\n", pDevReg->cbInstance, pDevReg->szDeviceName));
653 return VERR_PDM_INVALID_DEVICE_REGISTRATION;
654 }
655 if (!pDevReg->pfnConstruct)
656 {
657 AssertMsgFailed(("No constructore! (Device %s)\n", pDevReg->szDeviceName));
658 return VERR_PDM_INVALID_DEVICE_REGISTRATION;
659 }
660 /* Check matching guest bits last without any asserting. Enables trial and error registration. */
661 if (!(pDevReg->fFlags & PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT))
662 {
663 Log(("PDM: Rejected device '%s' because it didn't match the guest bits.\n", pDevReg->szDeviceName));
664 return VERR_PDM_INVALID_DEVICE_GUEST_BITS;
665 }
666 AssertLogRelMsg(pDevReg->u32VersionEnd == PDM_DEVREG_VERSION,
667 ("u32VersionEnd=%#x, expected %#x. (szDeviceName=%s)\n",
668 pDevReg->u32VersionEnd, PDM_DEVREG_VERSION, pDevReg->szDeviceName));
669
670 /*
671 * Check for duplicate and find FIFO entry at the same time.
672 */
673 PCPDMDEVREGCBINT pRegCB = (PCPDMDEVREGCBINT)pCallbacks;
674 PPDMDEV pDevPrev = NULL;
675 PPDMDEV pDev = pRegCB->pVM->pdm.s.pDevs;
676 for (; pDev; pDevPrev = pDev, pDev = pDev->pNext)
677 {
678 if (!strcmp(pDev->pDevReg->szDeviceName, pDevReg->szDeviceName))
679 {
680 AssertMsgFailed(("Device '%s' already exists\n", pDevReg->szDeviceName));
681 return VERR_PDM_DEVICE_NAME_CLASH;
682 }
683 }
684
685 /*
686 * Allocate new device structure and insert it into the list.
687 */
688 pDev = (PPDMDEV)MMR3HeapAlloc(pRegCB->pVM, MM_TAG_PDM_DEVICE, sizeof(*pDev));
689 if (pDev)
690 {
691 pDev->pNext = NULL;
692 pDev->cInstances = 0;
693 pDev->pInstances = NULL;
694 pDev->pDevReg = pDevReg;
695 pDev->cchName = (uint32_t)strlen(pDevReg->szDeviceName);
696
697 if (pDevPrev)
698 pDevPrev->pNext = pDev;
699 else
700 pRegCB->pVM->pdm.s.pDevs = pDev;
701 Log(("PDM: Registered device '%s'\n", pDevReg->szDeviceName));
702 return VINF_SUCCESS;
703 }
704 return VERR_NO_MEMORY;
705}
706
707
708/**
709 * Allocate memory which is associated with current VM instance
710 * and automatically freed on it's destruction.
711 *
712 * @returns Pointer to allocated memory. The memory is *NOT* zero-ed.
713 * @param pCallbacks Pointer to the callback table.
714 * @param cb Number of bytes to allocate.
715 */
716static DECLCALLBACK(void *) pdmR3DevReg_MMHeapAlloc(PPDMDEVREGCB pCallbacks, size_t cb)
717{
718 Assert(pCallbacks);
719 Assert(pCallbacks->u32Version == PDM_DEVREG_CB_VERSION);
720
721 void *pv = MMR3HeapAlloc(((PPDMDEVREGCBINT)pCallbacks)->pVM, MM_TAG_PDM_DEVICE_USER, cb);
722 LogFlow(("pdmR3DevReg_MMHeapAlloc(,%#zx): returns %p\n", cb, pv));
723 return pv;
724}
725
726
727/**
728 * Locates a LUN.
729 *
730 * @returns VBox status code.
731 * @param pVM VM Handle.
732 * @param pszDevice Device name.
733 * @param iInstance Device instance.
734 * @param iLun The Logical Unit to obtain the interface of.
735 * @param ppLun Where to store the pointer to the LUN if found.
736 * @thread Try only do this in EMT...
737 */
738int pdmR3DevFindLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMLUN *ppLun)
739{
740 /*
741 * Iterate registered devices looking for the device.
742 */
743 size_t cchDevice = strlen(pszDevice);
744 for (PPDMDEV pDev = pVM->pdm.s.pDevs; pDev; pDev = pDev->pNext)
745 {
746 if ( pDev->cchName == cchDevice
747 && !memcmp(pDev->pDevReg->szDeviceName, pszDevice, cchDevice))
748 {
749 /*
750 * Iterate device instances.
751 */
752 for (PPDMDEVINS pDevIns = pDev->pInstances; pDevIns; pDevIns = pDevIns->Internal.s.pPerDeviceNextR3)
753 {
754 if (pDevIns->iInstance == iInstance)
755 {
756 /*
757 * Iterate luns.
758 */
759 for (PPDMLUN pLun = pDevIns->Internal.s.pLunsR3; pLun; pLun = pLun->pNext)
760 {
761 if (pLun->iLun == iLun)
762 {
763 *ppLun = pLun;
764 return VINF_SUCCESS;
765 }
766 }
767 return VERR_PDM_LUN_NOT_FOUND;
768 }
769 }
770 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND;
771 }
772 }
773 return VERR_PDM_DEVICE_NOT_FOUND;
774}
775
776
777/**
778 * Attaches a preconfigured driver to an existing device instance.
779 *
780 * This is used to change drivers and suchlike at runtime.
781 *
782 * @returns VBox status code.
783 * @param pVM VM Handle.
784 * @param pszDevice Device name.
785 * @param iInstance Device instance.
786 * @param iLun The Logical Unit to obtain the interface of.
787 * @param ppBase Where to store the base interface pointer. Optional.
788 * @thread EMT
789 */
790VMMR3DECL(int) PDMR3DeviceAttach(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
791{
792 VM_ASSERT_EMT(pVM);
793 LogFlow(("PDMR3DeviceAttach: pszDevice=%p:{%s} iInstance=%d iLun=%d ppBase=%p\n",
794 pszDevice, pszDevice, iInstance, iLun, 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->pDevReg->pfnAttach)
808 {
809 if (!pLun->pTop)
810 {
811 rc = pDevIns->pDevReg->pfnAttach(pDevIns, iLun);
812
813 }
814 else
815 rc = VERR_PDM_DRIVER_ALREADY_ATTACHED;
816 }
817 else
818 rc = VERR_PDM_DEVICE_NO_RT_ATTACH;
819
820 if (ppBase)
821 *ppBase = pLun->pTop ? &pLun->pTop->IBase : NULL;
822 }
823 else if (ppBase)
824 *ppBase = NULL;
825
826 if (ppBase)
827 LogFlow(("PDMR3DeviceAttach: returns %Rrc *ppBase=%p\n", rc, *ppBase));
828 else
829 LogFlow(("PDMR3DeviceAttach: returns %Rrc\n", rc));
830 return rc;
831}
832
833
834/**
835 * Detaches a driver chain from an existing device instance.
836 *
837 * This is used to change drivers and suchlike at runtime.
838 *
839 * @returns VBox status code.
840 * @param pVM VM Handle.
841 * @param pszDevice Device name.
842 * @param iInstance Device instance.
843 * @param iLun The Logical Unit to obtain the interface of.
844 * @thread EMT
845 */
846VMMR3DECL(int) PDMR3DeviceDetach(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun)
847{
848 VM_ASSERT_EMT(pVM);
849 LogFlow(("PDMR3DeviceDetach: pszDevice=%p:{%s} iInstance=%d iLun=%d\n",
850 pszDevice, pszDevice, iInstance, iLun));
851
852 /*
853 * Find the LUN in question.
854 */
855 PPDMLUN pLun;
856 int rc = pdmR3DevFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
857 if (RT_SUCCESS(rc))
858 {
859 /*
860 * Can we detach anything at runtime?
861 */
862 PPDMDEVINS pDevIns = pLun->pDevIns;
863 if (pDevIns->pDevReg->pfnDetach)
864 {
865 if (pLun->pTop)
866 rc = pdmR3DrvDetach(pLun->pTop);
867 else
868 rc = VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN;
869 }
870 else
871 rc = VERR_PDM_DEVICE_NO_RT_DETACH;
872 }
873
874 LogFlow(("PDMR3DeviceDetach: returns %Rrc\n", rc));
875 return rc;
876}
877
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