VirtualBox

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

Last change on this file since 25414 was 24730, checked in by vboxsync, 15 years ago

PDM: Implemented making device/driver/usb-device suspend and poweroff notifications asynchronous when needed. Also prepped the way for failing poweron and resume.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use