VirtualBox

source: vbox/trunk/src/VBox/VMM/PDMDriver.cpp@ 28258

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

PDM critsects for drivers. Fixed critsect cleanup in failure path. Started on new transmit locking scheme (required for intnet buffer serialization).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 51.4 KB
Line 
1/* $Id: PDMDriver.cpp 28258 2010-04-13 14:51:16Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device and Driver Manager, Driver parts.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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_DRIVER
27#include "PDMInternal.h"
28#include <VBox/pdm.h>
29#include <VBox/mm.h>
30#include <VBox/cfgm.h>
31#include <VBox/vmm.h>
32#include <VBox/sup.h>
33#include <VBox/vm.h>
34#include <VBox/version.h>
35#include <VBox/err.h>
36
37#include <VBox/log.h>
38#include <iprt/assert.h>
39#include <iprt/thread.h>
40#include <iprt/string.h>
41#include <iprt/asm.h>
42#include <iprt/alloc.h>
43#include <iprt/path.h>
44
45
46/*******************************************************************************
47* Structures and Typedefs *
48*******************************************************************************/
49/**
50 * Internal callback structure pointer.
51 *
52 * The main purpose is to define the extra data we associate
53 * with PDMDRVREGCB so we can find the VM instance and so on.
54 */
55typedef struct PDMDRVREGCBINT
56{
57 /** The callback structure. */
58 PDMDRVREGCB Core;
59 /** A bit of padding. */
60 uint32_t u32[4];
61 /** VM Handle. */
62 PVM pVM;
63} PDMDRVREGCBINT, *PPDMDRVREGCBINT;
64typedef const PDMDRVREGCBINT *PCPDMDRVREGCBINT;
65
66
67/*******************************************************************************
68* Internal Functions *
69*******************************************************************************/
70static DECLCALLBACK(int) pdmR3DrvRegister(PCPDMDRVREGCB pCallbacks, PCPDMDRVREG pReg);
71static int pdmR3DrvLoad(PVM pVM, PPDMDRVREGCBINT pRegCB, const char *pszFilename, const char *pszName);
72
73
74
75/**
76 * Register external drivers
77 *
78 * @returns VBox status code.
79 * @param pVM The VM to operate on.
80 * @param pfnCallback Driver registration callback
81 */
82VMMR3DECL(int) PDMR3RegisterDrivers(PVM pVM, FNPDMVBOXDRIVERSREGISTER pfnCallback)
83{
84 /*
85 * The registration callbacks.
86 */
87 PDMDRVREGCBINT RegCB;
88 RegCB.Core.u32Version = PDM_DRVREG_CB_VERSION;
89 RegCB.Core.pfnRegister = pdmR3DrvRegister;
90 RegCB.pVM = pVM;
91
92 int rc = pfnCallback(&RegCB.Core, VBOX_VERSION);
93 if (RT_FAILURE(rc))
94 AssertMsgFailed(("VBoxDriversRegister failed with rc=%Rrc\n"));
95
96 return rc;
97}
98
99/**
100 * This function will initialize the drivers for this VM instance.
101 *
102 * First of all this mean loading the builtin drivers and letting them
103 * register themselves. Beyond that any additional driver modules are
104 * loaded and called for registration.
105 *
106 * @returns VBox status code.
107 * @param pVM VM Handle.
108 */
109int pdmR3DrvInit(PVM pVM)
110{
111 LogFlow(("pdmR3DrvInit:\n"));
112
113 AssertRelease(!(RT_OFFSETOF(PDMDRVINS, achInstanceData) & 15));
114 PPDMDRVINS pDrvInsAssert;
115 AssertRelease(sizeof(pDrvInsAssert->Internal.s) <= sizeof(pDrvInsAssert->Internal.padding));
116
117 /*
118 * The registration callbacks.
119 */
120 PDMDRVREGCBINT RegCB;
121 RegCB.Core.u32Version = PDM_DRVREG_CB_VERSION;
122 RegCB.Core.pfnRegister = pdmR3DrvRegister;
123 RegCB.pVM = pVM;
124
125 /*
126 * Load the builtin module
127 */
128 PCFGMNODE pDriversNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "PDM/Drivers");
129 bool fLoadBuiltin;
130 int rc = CFGMR3QueryBool(pDriversNode, "LoadBuiltin", &fLoadBuiltin);
131 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
132 fLoadBuiltin = true;
133 else if (RT_FAILURE(rc))
134 {
135 AssertMsgFailed(("Configuration error: Querying boolean \"LoadBuiltin\" failed with %Rrc\n", rc));
136 return rc;
137 }
138 if (fLoadBuiltin)
139 {
140 /* make filename */
141 char *pszFilename = pdmR3FileR3("VBoxDD", /*fShared=*/true);
142 if (!pszFilename)
143 return VERR_NO_TMP_MEMORY;
144 rc = pdmR3DrvLoad(pVM, &RegCB, pszFilename, "VBoxDD");
145 RTMemTmpFree(pszFilename);
146 if (RT_FAILURE(rc))
147 return rc;
148 }
149
150 /*
151 * Load additional driver modules.
152 */
153 for (PCFGMNODE pCur = CFGMR3GetFirstChild(pDriversNode); pCur; pCur = CFGMR3GetNextChild(pCur))
154 {
155 /*
156 * Get the name and path.
157 */
158 char szName[PDMMOD_NAME_LEN];
159 rc = CFGMR3GetName(pCur, &szName[0], sizeof(szName));
160 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
161 {
162 AssertMsgFailed(("configuration error: The module name is too long, cchName=%zu.\n", CFGMR3GetNameLen(pCur)));
163 return VERR_PDM_MODULE_NAME_TOO_LONG;
164 }
165 else if (RT_FAILURE(rc))
166 {
167 AssertMsgFailed(("CFGMR3GetName -> %Rrc.\n", rc));
168 return rc;
169 }
170
171 /* the path is optional, if no path the module name + path is used. */
172 char szFilename[RTPATH_MAX];
173 rc = CFGMR3QueryString(pCur, "Path", &szFilename[0], sizeof(szFilename));
174 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
175 strcpy(szFilename, szName);
176 else if (RT_FAILURE(rc))
177 {
178 AssertMsgFailed(("configuration error: Failure to query the module path, rc=%Rrc.\n", rc));
179 return rc;
180 }
181
182 /* prepend path? */
183 if (!RTPathHavePath(szFilename))
184 {
185 char *psz = pdmR3FileR3(szFilename);
186 if (!psz)
187 return VERR_NO_TMP_MEMORY;
188 size_t cch = strlen(psz) + 1;
189 if (cch > sizeof(szFilename))
190 {
191 RTMemTmpFree(psz);
192 AssertMsgFailed(("Filename too long! cch=%d '%s'\n", cch, psz));
193 return VERR_FILENAME_TOO_LONG;
194 }
195 memcpy(szFilename, psz, cch);
196 RTMemTmpFree(psz);
197 }
198
199 /*
200 * Load the module and register it's drivers.
201 */
202 rc = pdmR3DrvLoad(pVM, &RegCB, szFilename, szName);
203 if (RT_FAILURE(rc))
204 return rc;
205 }
206
207 LogFlow(("pdmR3DrvInit: returns VINF_SUCCESS\n"));
208 return VINF_SUCCESS;
209}
210
211
212/**
213 * Loads one driver module and call the registration entry point.
214 *
215 * @returns VBox status code.
216 * @param pVM VM handle.
217 * @param pRegCB The registration callback stuff.
218 * @param pszFilename Module filename.
219 * @param pszName Module name.
220 */
221static int pdmR3DrvLoad(PVM pVM, PPDMDRVREGCBINT pRegCB, const char *pszFilename, const char *pszName)
222{
223 /*
224 * Load it.
225 */
226 int rc = pdmR3LoadR3U(pVM->pUVM, pszFilename, pszName);
227 if (RT_SUCCESS(rc))
228 {
229 /*
230 * Get the registration export and call it.
231 */
232 FNPDMVBOXDRIVERSREGISTER *pfnVBoxDriversRegister;
233 rc = PDMR3LdrGetSymbolR3(pVM, pszName, "VBoxDriversRegister", (void **)&pfnVBoxDriversRegister);
234 if (RT_SUCCESS(rc))
235 {
236 Log(("PDM: Calling VBoxDriversRegister (%p) of %s (%s)\n", pfnVBoxDriversRegister, pszName, pszFilename));
237 rc = pfnVBoxDriversRegister(&pRegCB->Core, VBOX_VERSION);
238 if (RT_SUCCESS(rc))
239 Log(("PDM: Successfully loaded driver module %s (%s).\n", pszName, pszFilename));
240 else
241 AssertMsgFailed(("VBoxDriversRegister failed with rc=%Rrc\n"));
242 }
243 else
244 {
245 AssertMsgFailed(("Failed to locate 'VBoxDriversRegister' in %s (%s) rc=%Rrc\n", pszName, pszFilename, rc));
246 if (rc == VERR_SYMBOL_NOT_FOUND)
247 rc = VERR_PDM_NO_REGISTRATION_EXPORT;
248 }
249 }
250 else
251 AssertMsgFailed(("Failed to load %s (%s) rc=%Rrc!\n", pszName, pszFilename, rc));
252 return rc;
253}
254
255
256/** @interface_method_impl{PDMDRVREGCB,pfnRegister} */
257static DECLCALLBACK(int) pdmR3DrvRegister(PCPDMDRVREGCB pCallbacks, PCPDMDRVREG pReg)
258{
259 /*
260 * Validate the registration structure.
261 */
262 AssertPtrReturn(pReg, VERR_INVALID_POINTER);
263 AssertMsgReturn(pReg->u32Version == PDM_DRVREG_VERSION,
264 ("%#x\n", pReg->u32Version),
265 VERR_PDM_UNKNOWN_DRVREG_VERSION);
266 AssertReturn(pReg->szName[0], VERR_PDM_INVALID_DRIVER_REGISTRATION);
267 AssertMsgReturn(memchr(pReg->szName, '\0', sizeof(pReg->szName)),
268 (".*s\n", sizeof(pReg->szName), pReg->szName),
269 VERR_PDM_INVALID_DRIVER_REGISTRATION);
270 AssertMsgReturn( !(pReg->fFlags & PDM_DRVREG_FLAGS_R0)
271 || ( pReg->szR0Mod[0]
272 && memchr(pReg->szR0Mod, '\0', sizeof(pReg->szR0Mod))),
273 ("%s: %.*s\n", pReg->szName, sizeof(pReg->szR0Mod), pReg->szR0Mod),
274 VERR_PDM_INVALID_DRIVER_REGISTRATION);
275 AssertMsgReturn( !(pReg->fFlags & PDM_DRVREG_FLAGS_RC)
276 || ( pReg->szRCMod[0]
277 && memchr(pReg->szRCMod, '\0', sizeof(pReg->szRCMod))),
278 ("%s: %.*s\n", pReg->szName, sizeof(pReg->szRCMod), pReg->szRCMod),
279 VERR_PDM_INVALID_DRIVER_REGISTRATION);
280 AssertMsgReturn(VALID_PTR(pReg->pszDescription),
281 ("%s: %p\n", pReg->szName, pReg->pszDescription),
282 VERR_PDM_INVALID_DRIVER_REGISTRATION);
283 AssertMsgReturn(!(pReg->fFlags & ~(PDM_DRVREG_FLAGS_HOST_BITS_MASK | PDM_DRVREG_FLAGS_R0 | PDM_DRVREG_FLAGS_RC)),
284 ("%s: %#x\n", pReg->szName, pReg->fFlags),
285 VERR_PDM_INVALID_DRIVER_REGISTRATION);
286 AssertMsgReturn((pReg->fFlags & PDM_DRVREG_FLAGS_HOST_BITS_MASK) == PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
287 ("%s: %#x\n", pReg->szName, pReg->fFlags),
288 VERR_PDM_INVALID_DRIVER_HOST_BITS);
289 AssertMsgReturn(pReg->cMaxInstances > 0,
290 ("%s: %#x\n", pReg->szName, pReg->cMaxInstances),
291 VERR_PDM_INVALID_DRIVER_REGISTRATION);
292 AssertMsgReturn(pReg->cbInstance <= _1M,
293 ("%s: %#x\n", pReg->szName, pReg->cbInstance),
294 VERR_PDM_INVALID_DRIVER_REGISTRATION);
295 AssertMsgReturn(VALID_PTR(pReg->pfnConstruct),
296 ("%s: %p\n", pReg->szName, pReg->pfnConstruct),
297 VERR_PDM_INVALID_DRIVER_REGISTRATION);
298 AssertMsgReturn(VALID_PTR(pReg->pfnRelocate) || !(pReg->fFlags & PDM_DRVREG_FLAGS_RC),
299 ("%s: %#x\n", pReg->szName, pReg->cbInstance),
300 VERR_PDM_INVALID_DRIVER_REGISTRATION);
301 AssertMsgReturn(pReg->pfnSoftReset == NULL,
302 ("%s: %p\n", pReg->szName, pReg->pfnSoftReset),
303 VERR_PDM_INVALID_DRIVER_REGISTRATION);
304 AssertMsgReturn(pReg->u32VersionEnd == PDM_DRVREG_VERSION,
305 ("%s: #x\n", pReg->szName, pReg->u32VersionEnd),
306 VERR_PDM_INVALID_DRIVER_REGISTRATION);
307
308 /*
309 * Check for duplicate and find FIFO entry at the same time.
310 */
311 PCPDMDRVREGCBINT pRegCB = (PCPDMDRVREGCBINT)pCallbacks;
312 PPDMDRV pDrvPrev = NULL;
313 PPDMDRV pDrv = pRegCB->pVM->pdm.s.pDrvs;
314 for (; pDrv; pDrvPrev = pDrv, pDrv = pDrv->pNext)
315 {
316 if (!strcmp(pDrv->pReg->szName, pReg->szName))
317 {
318 AssertMsgFailed(("Driver '%s' already exists\n", pReg->szName));
319 return VERR_PDM_DRIVER_NAME_CLASH;
320 }
321 }
322
323 /*
324 * Allocate new driver structure and insert it into the list.
325 */
326 pDrv = (PPDMDRV)MMR3HeapAlloc(pRegCB->pVM, MM_TAG_PDM_DRIVER, sizeof(*pDrv));
327 if (pDrv)
328 {
329 pDrv->pNext = NULL;
330 pDrv->cInstances = 0;
331 pDrv->iNextInstance = 0;
332 pDrv->pReg = pReg;
333
334 if (pDrvPrev)
335 pDrvPrev->pNext = pDrv;
336 else
337 pRegCB->pVM->pdm.s.pDrvs = pDrv;
338 Log(("PDM: Registered driver '%s'\n", pReg->szName));
339 return VINF_SUCCESS;
340 }
341 return VERR_NO_MEMORY;
342}
343
344
345/**
346 * Lookups a driver structure by name.
347 * @internal
348 */
349PPDMDRV pdmR3DrvLookup(PVM pVM, const char *pszName)
350{
351 for (PPDMDRV pDrv = pVM->pdm.s.pDrvs; pDrv; pDrv = pDrv->pNext)
352 if (!strcmp(pDrv->pReg->szName, pszName))
353 return pDrv;
354 return NULL;
355}
356
357
358/**
359 * Instantiate a driver.
360 *
361 * @returns VBox status code, including informational statuses.
362 *
363 * @param pVM The VM handle.
364 * @param pNode The CFGM node for the driver.
365 * @param pBaseInterface The base interface.
366 * @param pDrvAbove The driver above it. NULL if it's the top-most
367 * driver.
368 * @param pLun The LUN the driver is being attached to. NULL
369 * if we're instantiating a driver chain before
370 * attaching it - untested.
371 * @param ppBaseInterface Where to return the pointer to the base
372 * interface of the newly created driver.
373 *
374 * @remarks Recursive calls to this function is normal as the drivers will
375 * attach to anything below them during the pfnContruct call.
376 */
377int pdmR3DrvInstantiate(PVM pVM, PCFGMNODE pNode, PPDMIBASE pBaseInterface, PPDMDRVINS pDrvAbove,
378 PPDMLUN pLun, PPDMIBASE *ppBaseInterface)
379{
380 Assert(!pDrvAbove || !pDrvAbove->Internal.s.pDown);
381 Assert(!pDrvAbove || !pDrvAbove->pDownBase);
382
383 Assert(pBaseInterface->pfnQueryInterface(pBaseInterface, PDMIBASE_IID) == pBaseInterface);
384
385 /*
386 * Find the driver.
387 */
388 char *pszName;
389 int rc = CFGMR3QueryStringAlloc(pNode, "Driver", &pszName);
390 if (RT_SUCCESS(rc))
391 {
392 PPDMDRV pDrv = pdmR3DrvLookup(pVM, pszName);
393 MMR3HeapFree(pszName);
394 if ( pDrv
395 && pDrv->cInstances < pDrv->pReg->cMaxInstances)
396 {
397 /* config node */
398 PCFGMNODE pConfigNode = CFGMR3GetChild(pNode, "Config");
399 if (!pConfigNode)
400 rc = CFGMR3InsertNode(pNode, "Config", &pConfigNode);
401 if (RT_SUCCESS(rc))
402 {
403 CFGMR3SetRestrictedRoot(pConfigNode);
404
405 /*
406 * Allocate the driver instance.
407 */
408 size_t cb = RT_OFFSETOF(PDMDRVINS, achInstanceData[pDrv->pReg->cbInstance]);
409 cb = RT_ALIGN_Z(cb, 16);
410 bool const fHyperHeap = !!(pDrv->pReg->fFlags & (PDM_DRVREG_FLAGS_R0 | PDM_DRVREG_FLAGS_RC));
411 PPDMDRVINS pNew;
412 if (fHyperHeap)
413 rc = MMHyperAlloc(pVM, cb, 64, MM_TAG_PDM_DRIVER, (void **)&pNew);
414 else
415 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_DRIVER, cb, (void **)&pNew);
416 if (pNew)
417 {
418 /*
419 * Initialize the instance structure (declaration order).
420 */
421 pNew->u32Version = PDM_DRVINS_VERSION;
422 pNew->Internal.s.pUp = pDrvAbove ? pDrvAbove : NULL;
423 //pNew->Internal.s.pDown = NULL;
424 pNew->Internal.s.pLun = pLun;
425 pNew->Internal.s.pDrv = pDrv;
426 pNew->Internal.s.pVMR3 = pVM;
427 pNew->Internal.s.pVMR0 = pDrv->pReg->fFlags & PDM_DRVREG_FLAGS_R0 ? pVM->pVMR0 : NIL_RTR0PTR;
428 pNew->Internal.s.pVMRC = pDrv->pReg->fFlags & PDM_DRVREG_FLAGS_RC ? pVM->pVMRC : NIL_RTRCPTR;
429 //pNew->Internal.s.fDetaching = false;
430 pNew->Internal.s.fVMSuspended = true;
431 //pNew->Internal.s.fVMReset = false;
432 pNew->Internal.s.fHyperHeap = fHyperHeap;
433 //pNew->Internal.s.pfnAsyncNotify = NULL;
434 pNew->Internal.s.pCfgHandle = pNode;
435 pNew->pReg = pDrv->pReg;
436 pNew->pCfg = pConfigNode;
437 pNew->iInstance = pDrv->iNextInstance;
438 pNew->pUpBase = pBaseInterface;
439 Assert(!pDrvAbove || pBaseInterface == &pDrvAbove->IBase);
440 //pNew->pDownBase = NULL;
441 //pNew->IBase.pfnQueryInterface = NULL;
442 pNew->pHlpR3 = &g_pdmR3DrvHlp;
443 pNew->pvInstanceDataR3 = &pNew->achInstanceData[0];
444 if (pDrv->pReg->fFlags & PDM_DRVREG_FLAGS_R0)
445 {
446 pNew->pvInstanceDataR0 = MMHyperR3ToR0(pVM, &pNew->achInstanceData[0]);
447 rc = PDMR3LdrGetSymbolR0(pVM, NULL, "g_pdmR0DrvHlp", &pNew->pHlpR0);
448 AssertReleaseRCReturn(rc, rc);
449
450 }
451 if (pDrv->pReg->fFlags & PDM_DRVREG_FLAGS_RC)
452 {
453 pNew->pvInstanceDataR0 = MMHyperR3ToRC(pVM, &pNew->achInstanceData[0]);
454 rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDrvHlp", &pNew->pHlpRC);
455 AssertReleaseRCReturn(rc, rc);
456 }
457
458 pDrv->iNextInstance++;
459 pDrv->cInstances++;
460
461 /*
462 * Link with it with the driver above / LUN.
463 */
464 if (pDrvAbove)
465 {
466 pDrvAbove->pDownBase = &pNew->IBase;
467 pDrvAbove->Internal.s.pDown = pNew;
468 }
469 else if (pLun)
470 pLun->pTop = pNew;
471 if (pLun)
472 pLun->pBottom = pNew;
473
474 /*
475 * Invoke the constructor.
476 */
477 rc = pDrv->pReg->pfnConstruct(pNew, pNew->pCfg, 0 /*fFlags*/);
478 if (RT_SUCCESS(rc))
479 {
480 AssertPtr(pNew->IBase.pfnQueryInterface);
481 Assert(pNew->IBase.pfnQueryInterface(&pNew->IBase, PDMIBASE_IID) == &pNew->IBase);
482
483 /* Success! */
484 *ppBaseInterface = &pNew->IBase;
485 if (pLun)
486 Log(("PDM: Attached driver %p:'%s'/%d to LUN#%d on device '%s'/%d, pDrvAbove=%p:'%s'/%d\n",
487 pNew, pDrv->pReg->szName, pNew->iInstance,
488 pLun->iLun,
489 pLun->pDevIns ? pLun->pDevIns->pReg->szName : pLun->pUsbIns->pReg->szName,
490 pLun->pDevIns ? pLun->pDevIns->iInstance : pLun->pUsbIns->iInstance,
491 pDrvAbove, pDrvAbove ? pDrvAbove->pReg->szName : "", pDrvAbove ? pDrvAbove->iInstance : UINT32_MAX));
492 else
493 Log(("PDM: Attached driver %p:'%s'/%d, pDrvAbove=%p:'%s'/%d\n",
494 pNew, pDrv->pReg->szName, pNew->iInstance,
495 pDrvAbove, pDrvAbove ? pDrvAbove->pReg->szName : "", pDrvAbove ? pDrvAbove->iInstance : UINT32_MAX));
496 }
497 else
498 pdmR3DrvDestroyChain(pNew, PDM_TACH_FLAGS_NO_CALLBACKS);
499 }
500 else
501 {
502 AssertMsgFailed(("Failed to allocate %d bytes for instantiating driver '%s'\n", cb, pszName));
503 rc = VERR_NO_MEMORY;
504 }
505 }
506 else
507 AssertMsgFailed(("Failed to create Config node! rc=%Rrc\n", rc));
508 }
509 else if (pDrv)
510 {
511 AssertMsgFailed(("Too many instances of driver '%s', max is %u\n", pszName, pDrv->pReg->cMaxInstances));
512 rc = VERR_PDM_TOO_MANY_DRIVER_INSTANCES;
513 }
514 else
515 {
516 AssertMsgFailed(("Driver '%s' wasn't found!\n", pszName));
517 rc = VERR_PDM_DRIVER_NOT_FOUND;
518 }
519 }
520 else
521 {
522 AssertMsgFailed(("Query for string value of \"Driver\" -> %Rrc\n", rc));
523 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
524 rc = VERR_PDM_CFG_MISSING_DRIVER_NAME;
525 }
526 return rc;
527}
528
529
530/**
531 * Detaches a driver from whatever it's attached to.
532 * This will of course lead to the destruction of the driver and all drivers below it in the chain.
533 *
534 * @returns VINF_SUCCESS
535 * @param pDrvIns The driver instance to detach.
536 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
537 */
538int pdmR3DrvDetach(PPDMDRVINS pDrvIns, uint32_t fFlags)
539{
540 PDMDRV_ASSERT_DRVINS(pDrvIns);
541 LogFlow(("pdmR3DrvDetach: pDrvIns=%p '%s'/%d\n", pDrvIns, pDrvIns->pReg->szName, pDrvIns->iInstance));
542 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
543
544 /*
545 * Check that we're not doing this recursively, that could have unwanted sideeffects!
546 */
547 if (pDrvIns->Internal.s.fDetaching)
548 {
549 AssertMsgFailed(("Recursive detach! '%s'/%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
550 return VINF_SUCCESS; }
551
552 /*
553 * Check that we actually can detach this instance.
554 * The requirement is that the driver/device above has a detach method.
555 */
556 if (pDrvIns->Internal.s.pUp
557 ? !pDrvIns->Internal.s.pUp->pReg->pfnDetach
558 : !pDrvIns->Internal.s.pLun->pDevIns->pReg->pfnDetach)
559 {
560 AssertMsgFailed(("Cannot detach driver instance because the driver/device above doesn't support it!\n"));
561 return VERR_PDM_DRIVER_DETACH_NOT_POSSIBLE;
562 }
563
564 /*
565 * Join paths with pdmR3DrvDestroyChain.
566 */
567 pdmR3DrvDestroyChain(pDrvIns, fFlags);
568 return VINF_SUCCESS;
569}
570
571
572/**
573 * Destroys a driver chain starting with the specified driver.
574 *
575 * This is used when unplugging a device at run time.
576 *
577 * @param pDrvIns Pointer to the driver instance to start with.
578 * @param fFlags PDM_TACH_FLAGS_NOT_HOT_PLUG, PDM_TACH_FLAGS_NO_CALLBACKS
579 * or 0.
580 */
581void pdmR3DrvDestroyChain(PPDMDRVINS pDrvIns, uint32_t fFlags)
582{
583 PVM pVM = pDrvIns->Internal.s.pVMR3;
584 VM_ASSERT_EMT(pVM);
585
586 /*
587 * Detach the bottommost driver until we've detached pDrvIns.
588 */
589 pDrvIns->Internal.s.fDetaching = true;
590 PPDMDRVINS pCur;
591 do
592 {
593 /* find the driver to detach. */
594 pCur = pDrvIns;
595 while (pCur->Internal.s.pDown)
596 pCur = pCur->Internal.s.pDown;
597 LogFlow(("pdmR3DrvDestroyChain: pCur=%p '%s'/%d\n", pCur, pCur->pReg->szName, pCur->iInstance));
598
599 /*
600 * Unlink it and notify parent.
601 */
602 pCur->Internal.s.fDetaching = true;
603
604 PPDMLUN pLun = pCur->Internal.s.pLun;
605 Assert(pLun->pBottom == pCur);
606 pLun->pBottom = pCur->Internal.s.pUp;
607
608 if (pCur->Internal.s.pUp)
609 {
610 /* driver parent */
611 PPDMDRVINS pParent = pCur->Internal.s.pUp;
612 pCur->Internal.s.pUp = NULL;
613 pParent->Internal.s.pDown = NULL;
614
615 if (!(fFlags & PDM_TACH_FLAGS_NO_CALLBACKS) && pParent->pReg->pfnDetach)
616 pParent->pReg->pfnDetach(pParent, fFlags);
617
618 pParent->pDownBase = NULL;
619 }
620 else
621 {
622 /* device parent */
623 Assert(pLun->pTop == pCur);
624 pLun->pTop = NULL;
625 if (!(fFlags & PDM_TACH_FLAGS_NO_CALLBACKS) && pLun->pDevIns->pReg->pfnDetach)
626 pLun->pDevIns->pReg->pfnDetach(pLun->pDevIns, pLun->iLun, fFlags);
627 }
628
629 /*
630 * Call destructor.
631 */
632 pCur->pUpBase = NULL;
633 if (pCur->pReg->pfnDestruct)
634 pCur->pReg->pfnDestruct(pCur);
635 pCur->Internal.s.pDrv->cInstances--;
636
637 /*
638 * Free all resources allocated by the driver.
639 */
640 /* Queues. */
641 int rc = PDMR3QueueDestroyDriver(pVM, pCur);
642 AssertRC(rc);
643
644 /* Timers. */
645 rc = TMR3TimerDestroyDriver(pVM, pCur);
646 AssertRC(rc);
647
648 /* SSM data units. */
649 rc = SSMR3DeregisterDriver(pVM, pCur, NULL, 0);
650 AssertRC(rc);
651
652 /* PDM threads. */
653 rc = pdmR3ThreadDestroyDriver(pVM, pCur);
654 AssertRC(rc);
655
656 /* PDM critsects. */
657 rc = pdmR3CritSectDeleteDriver(pVM, pCur);
658 AssertRC(rc);
659
660 /* Finally, the driver it self. */
661 bool fHyperHeap = pCur->Internal.s.fHyperHeap;
662 ASMMemFill32(pCur, RT_OFFSETOF(PDMDRVINS, achInstanceData[pCur->pReg->cbInstance]), 0xdeadd0d0);
663 if (fHyperHeap)
664 MMHyperFree(pVM, pCur);
665 else
666 MMR3HeapFree(pCur);
667
668 } while (pCur != pDrvIns);
669}
670
671
672
673
674/** @name Driver Helpers
675 * @{
676 */
677
678/** @interface_method_impl{PDMDRVHLP,pfnAttach} */
679static DECLCALLBACK(int) pdmR3DrvHlp_Attach(PPDMDRVINS pDrvIns, uint32_t fFlags, PPDMIBASE *ppBaseInterface)
680{
681 PDMDRV_ASSERT_DRVINS(pDrvIns);
682 PVM pVM = pDrvIns->Internal.s.pVMR3;
683 VM_ASSERT_EMT(pVM);
684 LogFlow(("pdmR3DrvHlp_Attach: caller='%s'/%d: fFlags=%#x\n", pDrvIns->pReg->szName, pDrvIns->iInstance, fFlags));
685 Assert(!(fFlags & ~(PDM_TACH_FLAGS_NOT_HOT_PLUG)));
686
687 /*
688 * Check that there isn't anything attached already.
689 */
690 int rc;
691 if (!pDrvIns->Internal.s.pDown)
692 {
693 Assert(pDrvIns->Internal.s.pLun->pBottom == pDrvIns);
694
695 /*
696 * Get the attached driver configuration.
697 */
698 PCFGMNODE pNode = CFGMR3GetChild(pDrvIns->Internal.s.pCfgHandle, "AttachedDriver");
699 if (pNode)
700 rc = pdmR3DrvInstantiate(pVM, pNode, &pDrvIns->IBase, pDrvIns, pDrvIns->Internal.s.pLun, ppBaseInterface);
701 else
702 rc = VERR_PDM_NO_ATTACHED_DRIVER;
703 }
704 else
705 {
706 AssertMsgFailed(("Already got a driver attached. The driver should keep track of such things!\n"));
707 rc = VERR_PDM_DRIVER_ALREADY_ATTACHED;
708 }
709
710 LogFlow(("pdmR3DrvHlp_Attach: caller='%s'/%d: return %Rrc\n",
711 pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
712 return rc;
713}
714
715
716/** @interface_method_impl{PDMDRVHLP,pfnDetach} */
717static DECLCALLBACK(int) pdmR3DrvHlp_Detach(PPDMDRVINS pDrvIns, uint32_t fFlags)
718{
719 PDMDRV_ASSERT_DRVINS(pDrvIns);
720 LogFlow(("pdmR3DrvHlp_Detach: caller='%s'/%d: fFlags=%#x\n",
721 pDrvIns->pReg->szName, pDrvIns->iInstance, fFlags));
722 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
723
724 /*
725 * Anything attached?
726 */
727 int rc;
728 if (pDrvIns->Internal.s.pDown)
729 rc = pdmR3DrvDetach(pDrvIns->Internal.s.pDown, fFlags);
730 else
731 {
732 AssertMsgFailed(("Nothing attached!\n"));
733 rc = VERR_PDM_NO_DRIVER_ATTACHED;
734 }
735
736 LogFlow(("pdmR3DrvHlp_Detach: caller='%s'/%d: returns %Rrc\n",
737 pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
738 return rc;
739}
740
741
742/** @interface_method_impl{PDMDRVHLP,pfnDetachSelf} */
743static DECLCALLBACK(int) pdmR3DrvHlp_DetachSelf(PPDMDRVINS pDrvIns, uint32_t fFlags)
744{
745 PDMDRV_ASSERT_DRVINS(pDrvIns);
746 LogFlow(("pdmR3DrvHlp_DetachSelf: caller='%s'/%d: fFlags=%#x\n",
747 pDrvIns->pReg->szName, pDrvIns->iInstance, fFlags));
748 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
749
750 int rc = pdmR3DrvDetach(pDrvIns, fFlags);
751
752 LogFlow(("pdmR3DrvHlp_Detach: returns %Rrc\n", rc)); /* pDrvIns is freed by now. */
753 return rc;
754}
755
756
757/** @interface_method_impl{PDMDRVHLP,pfnMountPrepare} */
758static DECLCALLBACK(int) pdmR3DrvHlp_MountPrepare(PPDMDRVINS pDrvIns, const char *pszFilename, const char *pszCoreDriver)
759{
760 PDMDRV_ASSERT_DRVINS(pDrvIns);
761 LogFlow(("pdmR3DrvHlp_MountPrepare: caller='%s'/%d: pszFilename=%p:{%s} pszCoreDriver=%p:{%s}\n",
762 pDrvIns->pReg->szName, pDrvIns->iInstance, pszFilename, pszFilename, pszCoreDriver, pszCoreDriver));
763 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
764
765 /*
766 * Do the caller have anything attached below itself?
767 */
768 if (pDrvIns->Internal.s.pDown)
769 {
770 AssertMsgFailed(("Cannot prepare a mount when something's attached to you!\n"));
771 return VERR_PDM_DRIVER_ALREADY_ATTACHED;
772 }
773
774 /*
775 * We're asked to prepare, so we'll start off by nuking the
776 * attached configuration tree.
777 */
778 PCFGMNODE pNode = CFGMR3GetChild(pDrvIns->Internal.s.pCfgHandle, "AttachedDriver");
779 if (pNode)
780 CFGMR3RemoveNode(pNode);
781
782 /*
783 * If there is no core driver, we'll have to probe for it.
784 */
785 if (!pszCoreDriver)
786 {
787 /** @todo implement image probing. */
788 AssertReleaseMsgFailed(("Not implemented!\n"));
789 return VERR_NOT_IMPLEMENTED;
790 }
791
792 /*
793 * Construct the basic attached driver configuration.
794 */
795 int rc = CFGMR3InsertNode(pDrvIns->Internal.s.pCfgHandle, "AttachedDriver", &pNode);
796 if (RT_SUCCESS(rc))
797 {
798 rc = CFGMR3InsertString(pNode, "Driver", pszCoreDriver);
799 if (RT_SUCCESS(rc))
800 {
801 PCFGMNODE pCfg;
802 rc = CFGMR3InsertNode(pNode, "Config", &pCfg);
803 if (RT_SUCCESS(rc))
804 {
805 rc = CFGMR3InsertString(pCfg, "Path", pszFilename);
806 if (RT_SUCCESS(rc))
807 {
808 LogFlow(("pdmR3DrvHlp_MountPrepare: caller='%s'/%d: returns %Rrc (Driver=%s)\n",
809 pDrvIns->pReg->szName, pDrvIns->iInstance, rc, pszCoreDriver));
810 return rc;
811 }
812 else
813 AssertMsgFailed(("Path string insert failed, rc=%Rrc\n", rc));
814 }
815 else
816 AssertMsgFailed(("Config node failed, rc=%Rrc\n", rc));
817 }
818 else
819 AssertMsgFailed(("Driver string insert failed, rc=%Rrc\n", rc));
820 CFGMR3RemoveNode(pNode);
821 }
822 else
823 AssertMsgFailed(("AttachedDriver node insert failed, rc=%Rrc\n", rc));
824
825 LogFlow(("pdmR3DrvHlp_MountPrepare: caller='%s'/%d: returns %Rrc\n",
826 pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
827 return rc;
828}
829
830
831/** @interface_method_impl{PDMDRVHLP,pfnAssertEMT} */
832static DECLCALLBACK(bool) pdmR3DrvHlp_AssertEMT(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)
833{
834 PDMDRV_ASSERT_DRVINS(pDrvIns);
835 if (VM_IS_EMT(pDrvIns->Internal.s.pVMR3))
836 return true;
837
838 char szMsg[100];
839 RTStrPrintf(szMsg, sizeof(szMsg), "AssertEMT '%s'/%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance);
840 RTAssertMsg1Weak(szMsg, iLine, pszFile, pszFunction);
841 AssertBreakpoint();
842 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
843 return false;
844}
845
846
847/** @interface_method_impl{PDMDRVHLP,pfnAssertOther} */
848static DECLCALLBACK(bool) pdmR3DrvHlp_AssertOther(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)
849{
850 PDMDRV_ASSERT_DRVINS(pDrvIns);
851 if (!VM_IS_EMT(pDrvIns->Internal.s.pVMR3))
852 return true;
853
854 char szMsg[100];
855 RTStrPrintf(szMsg, sizeof(szMsg), "AssertOther '%s'/%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance);
856 RTAssertMsg1Weak(szMsg, iLine, pszFile, pszFunction);
857 AssertBreakpoint();
858 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
859 return false;
860}
861
862
863/** @interface_method_impl{PDMDRVHLP,pfnVMSetError} */
864static DECLCALLBACK(int) pdmR3DrvHlp_VMSetError(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
865{
866 PDMDRV_ASSERT_DRVINS(pDrvIns);
867 va_list args;
868 va_start(args, pszFormat);
869 int rc2 = VMSetErrorV(pDrvIns->Internal.s.pVMR3, rc, RT_SRC_POS_ARGS, pszFormat, args); Assert(rc2 == rc); NOREF(rc2);
870 va_end(args);
871 return rc;
872}
873
874
875/** @interface_method_impl{PDMDRVHLP,pfnVMSetErrorV} */
876static DECLCALLBACK(int) pdmR3DrvHlp_VMSetErrorV(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
877{
878 PDMDRV_ASSERT_DRVINS(pDrvIns);
879 int rc2 = VMSetErrorV(pDrvIns->Internal.s.pVMR3, rc, RT_SRC_POS_ARGS, pszFormat, va); Assert(rc2 == rc); NOREF(rc2);
880 return rc;
881}
882
883
884/** @interface_method_impl{PDMDRVHLP,pfnVMSetRuntimeError} */
885static DECLCALLBACK(int) pdmR3DrvHlp_VMSetRuntimeError(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
886{
887 PDMDRV_ASSERT_DRVINS(pDrvIns);
888 va_list args;
889 va_start(args, pszFormat);
890 int rc = VMSetRuntimeErrorV(pDrvIns->Internal.s.pVMR3, fFlags, pszErrorId, pszFormat, args);
891 va_end(args);
892 return rc;
893}
894
895
896/** @interface_method_impl{PDMDRVHLP,pfnVMSetRuntimeErrorV} */
897static DECLCALLBACK(int) pdmR3DrvHlp_VMSetRuntimeErrorV(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)
898{
899 PDMDRV_ASSERT_DRVINS(pDrvIns);
900 int rc = VMSetRuntimeErrorV(pDrvIns->Internal.s.pVMR3, fFlags, pszErrorId, pszFormat, va);
901 return rc;
902}
903
904
905/** @interface_method_impl{PDMDEVHLPR3,pfnVMState} */
906static DECLCALLBACK(VMSTATE) pdmR3DrvHlp_VMState(PPDMDRVINS pDrvIns)
907{
908 PDMDRV_ASSERT_DRVINS(pDrvIns);
909
910 VMSTATE enmVMState = VMR3GetState(pDrvIns->Internal.s.pVMR3);
911
912 LogFlow(("pdmR3DrvHlp_VMState: caller='%s'/%d: returns %d (%s)\n", pDrvIns->pReg->szName, pDrvIns->iInstance,
913 enmVMState, VMR3GetStateName(enmVMState)));
914 return enmVMState;
915}
916
917
918/** @interface_method_impl{PDMDEVHLPR3,pfnVMTeleportedAndNotFullyResumedYet} */
919static DECLCALLBACK(bool) pdmR3DrvHlp_VMTeleportedAndNotFullyResumedYet(PPDMDRVINS pDrvIns)
920{
921 PDMDRV_ASSERT_DRVINS(pDrvIns);
922
923 bool fRc = VMR3TeleportedAndNotFullyResumedYet(pDrvIns->Internal.s.pVMR3);
924
925 LogFlow(("pdmR3DrvHlp_VMState: caller='%s'/%d: returns %RTbool)\n", pDrvIns->pReg->szName, pDrvIns->iInstance,
926 fRc));
927 return fRc;
928}
929
930
931/** @interface_method_impl{PDMDRVHLP,pfnQueueCreate} */
932static DECLCALLBACK(int) pdmR3DrvHlp_QueueCreate(PPDMDRVINS pDrvIns, uint32_t cbItem, uint32_t cItems, uint32_t cMilliesInterval,
933 PFNPDMQUEUEDRV pfnCallback, const char *pszName, PPDMQUEUE *ppQueue)
934{
935 PDMDRV_ASSERT_DRVINS(pDrvIns);
936 LogFlow(("pdmR3DrvHlp_PDMQueueCreate: caller='%s'/%d: cbItem=%d cItems=%d cMilliesInterval=%d pfnCallback=%p pszName=%p:{%s} ppQueue=%p\n",
937 pDrvIns->pReg->szName, pDrvIns->iInstance, cbItem, cItems, cMilliesInterval, pfnCallback, pszName, pszName, ppQueue, ppQueue));
938 PVM pVM = pDrvIns->Internal.s.pVMR3;
939 VM_ASSERT_EMT(pVM);
940
941 if (pDrvIns->iInstance > 0)
942 {
943 pszName = MMR3HeapAPrintf(pVM, MM_TAG_PDM_DRIVER_DESC, "%s_%u", pszName, pDrvIns->iInstance);
944 AssertLogRelReturn(pszName, VERR_NO_MEMORY);
945 }
946
947 int rc = PDMR3QueueCreateDriver(pVM, pDrvIns, cbItem, cItems, cMilliesInterval, pfnCallback, pszName, ppQueue);
948
949 LogFlow(("pdmR3DrvHlp_PDMQueueCreate: caller='%s'/%d: returns %Rrc *ppQueue=%p\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc, *ppQueue));
950 return rc;
951}
952
953
954/** @interface_method_impl{PDMDRVHLP,pfnTMGetVirtualFreq} */
955static DECLCALLBACK(uint64_t) pdmR3DrvHlp_TMGetVirtualFreq(PPDMDRVINS pDrvIns)
956{
957 PDMDRV_ASSERT_DRVINS(pDrvIns);
958
959 return TMVirtualGetFreq(pDrvIns->Internal.s.pVMR3);
960}
961
962
963/** @interface_method_impl{PDMDRVHLP,pfnTMGetVirtualTime} */
964static DECLCALLBACK(uint64_t) pdmR3DrvHlp_TMGetVirtualTime(PPDMDRVINS pDrvIns)
965{
966 PDMDRV_ASSERT_DRVINS(pDrvIns);
967
968 return TMVirtualGet(pDrvIns->Internal.s.pVMR3);
969}
970
971
972/** @interface_method_impl{PDMDRVHLP,pfnTMTimerCreate} */
973static DECLCALLBACK(int) pdmR3DrvHlp_TMTimerCreate(PPDMDRVINS pDrvIns, TMCLOCK enmClock, PFNTMTIMERDRV pfnCallback, void *pvUser, uint32_t fFlags, const char *pszDesc, PPTMTIMERR3 ppTimer)
974{
975 PDMDRV_ASSERT_DRVINS(pDrvIns);
976 LogFlow(("pdmR3DrvHlp_TMTimerCreate: caller='%s'/%d: enmClock=%d pfnCallback=%p pvUser=%p fFlags=%#x pszDesc=%p:{%s} ppTimer=%p\n",
977 pDrvIns->pReg->szName, pDrvIns->iInstance, enmClock, pfnCallback, pvUser, fFlags, pszDesc, pszDesc, ppTimer));
978
979 int rc = TMR3TimerCreateDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, ppTimer);
980
981 LogFlow(("pdmR3DrvHlp_TMTimerCreate: caller='%s'/%d: returns %Rrc *ppTimer=%p\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc, *ppTimer));
982 return rc;
983}
984
985
986
987/** @interface_method_impl{PDMDRVHLP,pfnSSMRegister} */
988static DECLCALLBACK(int) pdmR3DrvHlp_SSMRegister(PPDMDRVINS pDrvIns, uint32_t uVersion, size_t cbGuess,
989 PFNSSMDRVLIVEPREP pfnLivePrep, PFNSSMDRVLIVEEXEC pfnLiveExec, PFNSSMDRVLIVEVOTE pfnLiveVote,
990 PFNSSMDRVSAVEPREP pfnSavePrep, PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVSAVEDONE pfnSaveDone,
991 PFNSSMDRVLOADPREP pfnLoadPrep, PFNSSMDRVLOADEXEC pfnLoadExec, PFNSSMDRVLOADDONE pfnLoadDone)
992{
993 PDMDRV_ASSERT_DRVINS(pDrvIns);
994 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
995 LogFlow(("pdmR3DrvHlp_SSMRegister: caller='%s'/%d: uVersion=#x cbGuess=%#x \n"
996 " pfnLivePrep=%p pfnLiveExec=%p pfnLiveVote=%p pfnSavePrep=%p pfnSaveExec=%p pfnSaveDone=%p pszLoadPrep=%p pfnLoadExec=%p pfnLoaddone=%p\n",
997 pDrvIns->pReg->szName, pDrvIns->iInstance, uVersion, cbGuess,
998 pfnLivePrep, pfnLiveExec, pfnLiveVote,
999 pfnSavePrep, pfnSaveExec, pfnSaveDone, pfnLoadPrep, pfnLoadExec, pfnLoadDone));
1000
1001 int rc = SSMR3RegisterDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, pDrvIns->pReg->szName, pDrvIns->iInstance,
1002 uVersion, cbGuess,
1003 pfnLivePrep, pfnLiveExec, pfnLiveVote,
1004 pfnSavePrep, pfnSaveExec, pfnSaveDone,
1005 pfnLoadPrep, pfnLoadExec, pfnLoadDone);
1006
1007 LogFlow(("pdmR3DrvHlp_SSMRegister: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1008 return rc;
1009}
1010
1011
1012/** @interface_method_impl{PDMDRVHLP,pfnSSMDeregister} */
1013static DECLCALLBACK(int) pdmR3DrvHlp_SSMDeregister(PPDMDRVINS pDrvIns, const char *pszName, uint32_t u32Instance)
1014{
1015 PDMDRV_ASSERT_DRVINS(pDrvIns);
1016 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1017 LogFlow(("pdmR3DrvHlp_SSMDeregister: caller='%s'/%d: pszName=%p:{%s} u32Instance=%#x\n",
1018 pDrvIns->pReg->szName, pDrvIns->iInstance, pszName, pszName, u32Instance));
1019
1020 int rc = SSMR3DeregisterDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, pszName, u32Instance);
1021
1022 LogFlow(("pdmR3DrvHlp_SSMDeregister: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1023 return rc;
1024}
1025
1026
1027/** @interface_method_impl{PDMDRVHLP,pfnSTAMRegister} */
1028static DECLCALLBACK(void) pdmR3DrvHlp_STAMRegister(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, const char *pszName, STAMUNIT enmUnit, const char *pszDesc)
1029{
1030 PDMDRV_ASSERT_DRVINS(pDrvIns);
1031 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1032
1033 STAM_REG(pDrvIns->Internal.s.pVMR3, pvSample, enmType, pszName, enmUnit, pszDesc);
1034 /** @todo track the samples so they can be dumped & deregistered when the driver instance is destroyed.
1035 * For now we just have to be careful not to use this call for drivers which can be unloaded. */
1036}
1037
1038
1039/** @interface_method_impl{PDMDRVHLP,pfnSTAMRegisterF} */
1040static DECLCALLBACK(void) pdmR3DrvHlp_STAMRegisterF(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
1041 STAMUNIT enmUnit, const char *pszDesc, const char *pszName, ...)
1042{
1043 PDMDRV_ASSERT_DRVINS(pDrvIns);
1044 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1045
1046 va_list args;
1047 va_start(args, pszName);
1048 int rc = STAMR3RegisterV(pDrvIns->Internal.s.pVMR3, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, args);
1049 va_end(args);
1050 AssertRC(rc);
1051}
1052
1053
1054/** @interface_method_impl{PDMDRVHLP,pfnSTAMRegisterV} */
1055static DECLCALLBACK(void) pdmR3DrvHlp_STAMRegisterV(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
1056 STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list args)
1057{
1058 PDMDRV_ASSERT_DRVINS(pDrvIns);
1059 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1060
1061 int rc = STAMR3RegisterV(pDrvIns->Internal.s.pVMR3, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, args);
1062 AssertRC(rc);
1063}
1064
1065
1066/** @interface_method_impl{PDMDRVHLP,pfnSTAMDeregister} */
1067static DECLCALLBACK(int) pdmR3DrvHlp_STAMDeregister(PPDMDRVINS pDrvIns, void *pvSample)
1068{
1069 PDMDRV_ASSERT_DRVINS(pDrvIns);
1070 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1071
1072 int rc = STAMR3DeregisterU(pDrvIns->Internal.s.pVMR3->pUVM, pvSample);
1073 AssertRC(rc);
1074 return rc;
1075}
1076
1077
1078/** @interface_method_impl{PDMDRVHLP,pfnSUPCallVMMR0Ex} */
1079static DECLCALLBACK(int) pdmR3DrvHlp_SUPCallVMMR0Ex(PPDMDRVINS pDrvIns, unsigned uOperation, void *pvArg, unsigned cbArg)
1080{
1081 PDMDRV_ASSERT_DRVINS(pDrvIns);
1082 LogFlow(("pdmR3DrvHlp_SSMCallVMMR0Ex: caller='%s'/%d: uOperation=%u pvArg=%p cbArg=%d\n",
1083 pDrvIns->pReg->szName, pDrvIns->iInstance, uOperation, pvArg, cbArg));
1084 int rc;
1085 if ( uOperation >= VMMR0_DO_SRV_START
1086 && uOperation < VMMR0_DO_SRV_END)
1087 rc = SUPR3CallVMMR0Ex(pDrvIns->Internal.s.pVMR3->pVMR0, NIL_VMCPUID, uOperation, 0, (PSUPVMMR0REQHDR)pvArg);
1088 else
1089 {
1090 AssertMsgFailed(("Invalid uOperation=%u\n", uOperation));
1091 rc = VERR_INVALID_PARAMETER;
1092 }
1093
1094 LogFlow(("pdmR3DrvHlp_SUPCallVMMR0Ex: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1095 return rc;
1096}
1097
1098
1099/** @interface_method_impl{PDMDRVHLP,pfnUSBRegisterHub} */
1100static DECLCALLBACK(int) pdmR3DrvHlp_USBRegisterHub(PPDMDRVINS pDrvIns, uint32_t fVersions, uint32_t cPorts, PCPDMUSBHUBREG pUsbHubReg, PPCPDMUSBHUBHLP ppUsbHubHlp)
1101{
1102 PDMDRV_ASSERT_DRVINS(pDrvIns);
1103 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1104 LogFlow(("pdmR3DrvHlp_USBRegisterHub: caller='%s'/%d: fVersions=%#x cPorts=%#x pUsbHubReg=%p ppUsbHubHlp=%p\n",
1105 pDrvIns->pReg->szName, pDrvIns->iInstance, fVersions, cPorts, pUsbHubReg, ppUsbHubHlp));
1106
1107#ifdef VBOX_WITH_USB
1108 int rc = pdmR3UsbRegisterHub(pDrvIns->Internal.s.pVMR3, pDrvIns, fVersions, cPorts, pUsbHubReg, ppUsbHubHlp);
1109#else
1110 int rc = VERR_NOT_SUPPORTED;
1111#endif
1112
1113 LogFlow(("pdmR3DrvHlp_USBRegisterHub: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1114 return rc;
1115}
1116
1117
1118/** @interface_method_impl{PDMDRVHLP,pfnSetAsyncNotification} */
1119static DECLCALLBACK(int) pdmR3DrvHlp_SetAsyncNotification(PPDMDRVINS pDrvIns, PFNPDMDRVASYNCNOTIFY pfnAsyncNotify)
1120{
1121 PDMDRV_ASSERT_DRVINS(pDrvIns);
1122 VM_ASSERT_EMT0(pDrvIns->Internal.s.pVMR3);
1123 LogFlow(("pdmR3DrvHlp_SetAsyncNotification: caller='%s'/%d: pfnAsyncNotify=%p\n", pDrvIns->pReg->szName, pDrvIns->iInstance, pfnAsyncNotify));
1124
1125 int rc = VINF_SUCCESS;
1126 AssertStmt(pfnAsyncNotify, rc = VERR_INVALID_PARAMETER);
1127 AssertStmt(!pDrvIns->Internal.s.pfnAsyncNotify, rc = VERR_WRONG_ORDER);
1128 AssertStmt(pDrvIns->Internal.s.fVMSuspended || pDrvIns->Internal.s.fVMReset, rc = VERR_WRONG_ORDER);
1129 VMSTATE enmVMState = VMR3GetState(pDrvIns->Internal.s.pVMR3);
1130 AssertStmt( enmVMState == VMSTATE_SUSPENDING
1131 || enmVMState == VMSTATE_SUSPENDING_EXT_LS
1132 || enmVMState == VMSTATE_SUSPENDING_LS
1133 || enmVMState == VMSTATE_RESETTING
1134 || enmVMState == VMSTATE_RESETTING_LS
1135 || enmVMState == VMSTATE_POWERING_OFF
1136 || enmVMState == VMSTATE_POWERING_OFF_LS,
1137 rc = VERR_INVALID_STATE);
1138
1139 if (RT_SUCCESS(rc))
1140 pDrvIns->Internal.s.pfnAsyncNotify = pfnAsyncNotify;
1141
1142 LogFlow(("pdmR3DrvHlp_SetAsyncNotification: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1143 return rc;
1144}
1145
1146
1147/** @interface_method_impl{PDMDRVHLP,pfnAsyncNotificationCompleted} */
1148static DECLCALLBACK(void) pdmR3DrvHlp_AsyncNotificationCompleted(PPDMDRVINS pDrvIns)
1149{
1150 PDMDRV_ASSERT_DRVINS(pDrvIns);
1151 PVM pVM = pDrvIns->Internal.s.pVMR3;
1152
1153 VMSTATE enmVMState = VMR3GetState(pVM);
1154 if ( enmVMState == VMSTATE_SUSPENDING
1155 || enmVMState == VMSTATE_SUSPENDING_EXT_LS
1156 || enmVMState == VMSTATE_SUSPENDING_LS
1157 || enmVMState == VMSTATE_RESETTING
1158 || enmVMState == VMSTATE_RESETTING_LS
1159 || enmVMState == VMSTATE_POWERING_OFF
1160 || enmVMState == VMSTATE_POWERING_OFF_LS)
1161 {
1162 LogFlow(("pdmR3DrvHlp_AsyncNotificationCompleted: caller='%s'/%d:\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
1163 VMR3AsyncPdmNotificationWakeupU(pVM->pUVM);
1164 }
1165 else
1166 LogFlow(("pdmR3DrvHlp_AsyncNotificationCompleted: caller='%s'/%d: enmVMState=%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance, enmVMState));
1167}
1168
1169
1170/** @interface_method_impl{PDMDRVHLP,pfnThreadCreate} */
1171static DECLCALLBACK(int) pdmR3DrvHlp_ThreadCreate(PPDMDRVINS pDrvIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDRV pfnThread,
1172 PFNPDMTHREADWAKEUPDRV pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
1173{
1174 PDMDRV_ASSERT_DRVINS(pDrvIns);
1175 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1176 LogFlow(("pdmR3DrvHlp_ThreadCreate: caller='%s'/%d: ppThread=%p pvUser=%p pfnThread=%p pfnWakeup=%p cbStack=%#zx enmType=%d pszName=%p:{%s}\n",
1177 pDrvIns->pReg->szName, pDrvIns->iInstance, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName, pszName));
1178
1179 int rc = pdmR3ThreadCreateDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName);
1180
1181 LogFlow(("pdmR3DrvHlp_ThreadCreate: caller='%s'/%d: returns %Rrc *ppThread=%RTthrd\n", pDrvIns->pReg->szName, pDrvIns->iInstance,
1182 rc, *ppThread));
1183 return rc;
1184}
1185
1186
1187/** @interface_method_impl{PDMDRVHLP,pfnAsyncCompletionTemplateCreate} */
1188static DECLCALLBACK(int) pdmR3DrvHlp_AsyncCompletionTemplateCreate(PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate,
1189 PFNPDMASYNCCOMPLETEDRV pfnCompleted, void *pvTemplateUser,
1190 const char *pszDesc)
1191{
1192 PDMDRV_ASSERT_DRVINS(pDrvIns);
1193 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1194 LogFlow(("pdmR3DrvHlp_AsyncCompletionTemplateCreate: caller='%s'/%d: ppTemplate=%p pfnCompleted=%p pszDesc=%p:{%s}\n",
1195 pDrvIns->pReg->szName, pDrvIns->iInstance, ppTemplate, pfnCompleted, pszDesc, pszDesc));
1196
1197 int rc = PDMR3AsyncCompletionTemplateCreateDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, ppTemplate, pfnCompleted, pvTemplateUser, pszDesc);
1198
1199 LogFlow(("pdmR3DrvHlp_AsyncCompletionTemplateCreate: caller='%s'/%d: returns %Rrc *ppThread=%p\n", pDrvIns->pReg->szName,
1200 pDrvIns->iInstance, rc, *ppTemplate));
1201 return rc;
1202}
1203
1204
1205/** @interface_method_impl{PDMDRVHLP,pfnLdrGetRCInterfaceSymbols} */
1206static DECLCALLBACK(int) pdmR3DrvHlp_LdrGetRCInterfaceSymbols(PPDMDRVINS pDrvIns, void *pvInterface, size_t cbInterface,
1207 const char *pszSymPrefix, const char *pszSymList)
1208{
1209 PDMDRV_ASSERT_DRVINS(pDrvIns);
1210 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1211 LogFlow(("pdmR3DrvHlp_LdrGetRCInterfaceSymbols: caller='%s'/%d: pvInterface=%p cbInterface=%zu pszSymPrefix=%p:{%s} pszSymList=%p:{%s}\n",
1212 pDrvIns->pReg->szName, pDrvIns->iInstance, pvInterface, cbInterface, pszSymPrefix, pszSymPrefix, pszSymList, pszSymList));
1213
1214 int rc;
1215 if ( strncmp(pszSymPrefix, "drv", 3) == 0
1216 && RTStrIStr(pszSymPrefix + 3, pDrvIns->pReg->szName) != NULL)
1217 {
1218 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_RC)
1219 rc = PDMR3LdrGetInterfaceSymbols(pDrvIns->Internal.s.pVMR3, pvInterface, cbInterface,
1220 pDrvIns->pReg->szName, pszSymPrefix, pszSymList,
1221 false /*fRing0OrRC*/);
1222 else
1223 {
1224 AssertMsgFailed(("Not a raw-mode enabled driver\n"));
1225 rc = VERR_PERMISSION_DENIED;
1226 }
1227 }
1228 else
1229 {
1230 AssertMsgFailed(("Invalid prefix '%s' for '%s'; must start with 'drv' and contain the driver name!\n",
1231 pszSymPrefix, pDrvIns->pReg->szName));
1232 rc = VERR_INVALID_NAME;
1233 }
1234
1235 LogFlow(("pdmR3DrvHlp_LdrGetRCInterfaceSymbols: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1236 pDrvIns->iInstance, rc));
1237 return rc;
1238}
1239
1240
1241/** @interface_method_impl{PDMDRVHLP,pfnLdrGetR0InterfaceSymbols} */
1242static DECLCALLBACK(int) pdmR3DrvHlp_LdrGetR0InterfaceSymbols(PPDMDRVINS pDrvIns, void *pvInterface, size_t cbInterface,
1243 const char *pszSymPrefix, const char *pszSymList)
1244{
1245 PDMDRV_ASSERT_DRVINS(pDrvIns);
1246 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1247 LogFlow(("pdmR3DrvHlp_LdrGetR0InterfaceSymbols: caller='%s'/%d: pvInterface=%p cbInterface=%zu pszSymPrefix=%p:{%s} pszSymList=%p:{%s}\n",
1248 pDrvIns->pReg->szName, pDrvIns->iInstance, pvInterface, cbInterface, pszSymPrefix, pszSymPrefix, pszSymList, pszSymList));
1249
1250 int rc;
1251 if ( strncmp(pszSymPrefix, "drv", 3) == 0
1252 && RTStrIStr(pszSymPrefix + 3, pDrvIns->pReg->szName) != NULL)
1253 {
1254 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_R0)
1255 rc = PDMR3LdrGetInterfaceSymbols(pDrvIns->Internal.s.pVMR3, pvInterface, cbInterface,
1256 pDrvIns->pReg->szName, pszSymPrefix, pszSymList,
1257 true /*fRing0OrRC*/);
1258 else
1259 {
1260 AssertMsgFailed(("Not a ring-0 enabled driver\n"));
1261 rc = VERR_PERMISSION_DENIED;
1262 }
1263 }
1264 else
1265 {
1266 AssertMsgFailed(("Invalid prefix '%s' for '%s'; must start with 'drv' and contain the driver name!\n",
1267 pszSymPrefix, pDrvIns->pReg->szName));
1268 rc = VERR_INVALID_NAME;
1269 }
1270
1271 LogFlow(("pdmR3DrvHlp_LdrGetR0InterfaceSymbols: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1272 pDrvIns->iInstance, rc));
1273 return rc;
1274}
1275
1276
1277/** @interface_method_impl{PDMDRVHLP,pfnCritSectInit} */
1278static DECLCALLBACK(int) pdmR3DrvHlp_CritSectInit(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect,
1279 RT_SRC_POS_DECL, const char *pszName)
1280{
1281 PDMDRV_ASSERT_DRVINS(pDrvIns);
1282 PVM pVM = pDrvIns->Internal.s.pVMR3;
1283 VM_ASSERT_EMT(pVM);
1284 LogFlow(("pdmR3DrvHlp_CritSectInit: caller='%s'/%d: pCritSect=%p pszName=%s\n",
1285 pDrvIns->pReg->szName, pDrvIns->iInstance, pCritSect, pszName));
1286
1287 int rc = pdmR3CritSectInitDriver(pVM, pDrvIns, pCritSect, RT_SRC_POS_ARGS, "%s_%u", pszName, pDrvIns->iInstance);
1288
1289 LogFlow(("pdmR3DrvHlp_CritSectInit: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1290 pDrvIns->iInstance, rc));
1291 return rc;
1292}
1293
1294
1295/**
1296 * The driver helper structure.
1297 */
1298const PDMDRVHLPR3 g_pdmR3DrvHlp =
1299{
1300 PDM_DRVHLPR3_VERSION,
1301 pdmR3DrvHlp_Attach,
1302 pdmR3DrvHlp_Detach,
1303 pdmR3DrvHlp_DetachSelf,
1304 pdmR3DrvHlp_MountPrepare,
1305 pdmR3DrvHlp_AssertEMT,
1306 pdmR3DrvHlp_AssertOther,
1307 pdmR3DrvHlp_VMSetError,
1308 pdmR3DrvHlp_VMSetErrorV,
1309 pdmR3DrvHlp_VMSetRuntimeError,
1310 pdmR3DrvHlp_VMSetRuntimeErrorV,
1311 pdmR3DrvHlp_VMState,
1312 pdmR3DrvHlp_VMTeleportedAndNotFullyResumedYet,
1313 pdmR3DrvHlp_QueueCreate,
1314 pdmR3DrvHlp_TMGetVirtualFreq,
1315 pdmR3DrvHlp_TMGetVirtualTime,
1316 pdmR3DrvHlp_TMTimerCreate,
1317 pdmR3DrvHlp_SSMRegister,
1318 pdmR3DrvHlp_SSMDeregister,
1319 pdmR3DrvHlp_STAMRegister,
1320 pdmR3DrvHlp_STAMRegisterF,
1321 pdmR3DrvHlp_STAMRegisterV,
1322 pdmR3DrvHlp_STAMDeregister,
1323 pdmR3DrvHlp_SUPCallVMMR0Ex,
1324 pdmR3DrvHlp_USBRegisterHub,
1325 pdmR3DrvHlp_SetAsyncNotification,
1326 pdmR3DrvHlp_AsyncNotificationCompleted,
1327 pdmR3DrvHlp_ThreadCreate,
1328 pdmR3DrvHlp_AsyncCompletionTemplateCreate,
1329 pdmR3DrvHlp_LdrGetRCInterfaceSymbols,
1330 pdmR3DrvHlp_LdrGetR0InterfaceSymbols,
1331 pdmR3DrvHlp_CritSectInit,
1332 PDM_DRVHLPR3_VERSION /* u32TheEnd */
1333};
1334
1335/** @} */
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette