VirtualBox

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

Last change on this file since 64497 was 64497, checked in by vboxsync, 8 years ago

PDMDriver.cpp Corrected driver transformation value name 'Driver' to 'Device' since it's actually matching the device name and not the driver (that's matched by 'AboveDriver'). Also added some docs to the basic keys and value involved in driver chain transformations.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 73.4 KB
Line 
1/* $Id: PDMDriver.cpp 64497 2016-11-01 04:38:06Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device and Driver Manager, Driver parts.
4 */
5
6/*
7 * Copyright (C) 2006-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_PDM_DRIVER
23#include "PDMInternal.h"
24#include <VBox/vmm/pdm.h>
25#include <VBox/vmm/mm.h>
26#include <VBox/vmm/cfgm.h>
27#include <VBox/vmm/hm.h>
28#include <VBox/vmm/vmm.h>
29#include <VBox/sup.h>
30#include <VBox/vmm/vm.h>
31#include <VBox/version.h>
32#include <VBox/err.h>
33
34#include <VBox/log.h>
35#include <iprt/assert.h>
36#include <iprt/asm.h>
37#include <iprt/ctype.h>
38#include <iprt/mem.h>
39#include <iprt/thread.h>
40#include <iprt/path.h>
41#include <iprt/string.h>
42
43
44/*********************************************************************************************************************************
45* Structures and Typedefs *
46*********************************************************************************************************************************/
47/**
48 * Internal callback structure pointer.
49 *
50 * The main purpose is to define the extra data we associate
51 * with PDMDRVREGCB so we can find the VM instance and so on.
52 */
53typedef struct PDMDRVREGCBINT
54{
55 /** The callback structure. */
56 PDMDRVREGCB Core;
57 /** A bit of padding. */
58 uint32_t u32[4];
59 /** VM Handle. */
60 PVM pVM;
61 /** Pointer to the configuration node the registrations should be
62 * associated with. Can be NULL. */
63 PCFGMNODE pCfgNode;
64} PDMDRVREGCBINT, *PPDMDRVREGCBINT;
65typedef const PDMDRVREGCBINT *PCPDMDRVREGCBINT;
66
67
68/*********************************************************************************************************************************
69* Internal Functions *
70*********************************************************************************************************************************/
71static DECLCALLBACK(int) pdmR3DrvRegister(PCPDMDRVREGCB pCallbacks, PCPDMDRVREG pReg);
72static int pdmR3DrvLoad(PVM pVM, PPDMDRVREGCBINT pRegCB, const char *pszFilename, const char *pszName);
73
74
75/**
76 * Register drivers in a statically linked environment.
77 *
78 * @returns VBox status code.
79 * @param pVM The cross context VM structure.
80 * @param pfnCallback Driver registration callback
81 */
82VMMR3DECL(int) PDMR3DrvStaticRegistration(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 RegCB.pCfgNode = NULL;
92
93 int rc = pfnCallback(&RegCB.Core, VBOX_VERSION);
94 if (RT_FAILURE(rc))
95 AssertMsgFailed(("VBoxDriversRegister failed with rc=%Rrc\n", rc));
96
97 return rc;
98}
99
100
101/**
102 * This function will initialize the drivers for this VM instance.
103 *
104 * First of all this mean loading the builtin drivers and letting them
105 * register themselves. Beyond that any additional driver modules are
106 * loaded and called for registration.
107 *
108 * @returns VBox status code.
109 * @param pVM The cross context VM structure.
110 */
111int pdmR3DrvInit(PVM pVM)
112{
113 LogFlow(("pdmR3DrvInit:\n"));
114
115 AssertRelease(!(RT_OFFSETOF(PDMDRVINS, achInstanceData) & 15));
116 PPDMDRVINS pDrvInsAssert; NOREF(pDrvInsAssert);
117 AssertCompile(sizeof(pDrvInsAssert->Internal.s) <= sizeof(pDrvInsAssert->Internal.padding));
118 AssertRelease(sizeof(pDrvInsAssert->Internal.s) <= sizeof(pDrvInsAssert->Internal.padding));
119
120 /*
121 * The registration callbacks.
122 */
123 PDMDRVREGCBINT RegCB;
124 RegCB.Core.u32Version = PDM_DRVREG_CB_VERSION;
125 RegCB.Core.pfnRegister = pdmR3DrvRegister;
126 RegCB.pVM = pVM;
127 RegCB.pCfgNode = NULL;
128
129 /*
130 * Load the builtin module
131 */
132 PCFGMNODE pDriversNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "PDM/Drivers");
133 bool fLoadBuiltin;
134 int rc = CFGMR3QueryBool(pDriversNode, "LoadBuiltin", &fLoadBuiltin);
135 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
136 fLoadBuiltin = true;
137 else if (RT_FAILURE(rc))
138 {
139 AssertMsgFailed(("Configuration error: Querying boolean \"LoadBuiltin\" failed with %Rrc\n", rc));
140 return rc;
141 }
142 if (fLoadBuiltin)
143 {
144 /* make filename */
145 char *pszFilename = pdmR3FileR3("VBoxDD", true /*fShared*/);
146 if (!pszFilename)
147 return VERR_NO_TMP_MEMORY;
148 rc = pdmR3DrvLoad(pVM, &RegCB, pszFilename, "VBoxDD");
149 RTMemTmpFree(pszFilename);
150 if (RT_FAILURE(rc))
151 return rc;
152 }
153
154 /*
155 * Load additional driver modules.
156 */
157 for (PCFGMNODE pCur = CFGMR3GetFirstChild(pDriversNode); pCur; pCur = CFGMR3GetNextChild(pCur))
158 {
159 /*
160 * Get the name and path.
161 */
162 char szName[PDMMOD_NAME_LEN];
163 rc = CFGMR3GetName(pCur, &szName[0], sizeof(szName));
164 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
165 {
166 AssertMsgFailed(("configuration error: The module name is too long, cchName=%zu.\n", CFGMR3GetNameLen(pCur)));
167 return VERR_PDM_MODULE_NAME_TOO_LONG;
168 }
169 else if (RT_FAILURE(rc))
170 {
171 AssertMsgFailed(("CFGMR3GetName -> %Rrc.\n", rc));
172 return rc;
173 }
174
175 /* the path is optional, if no path the module name + path is used. */
176 char szFilename[RTPATH_MAX];
177 rc = CFGMR3QueryString(pCur, "Path", &szFilename[0], sizeof(szFilename));
178 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
179 strcpy(szFilename, szName);
180 else if (RT_FAILURE(rc))
181 {
182 AssertMsgFailed(("configuration error: Failure to query the module path, rc=%Rrc.\n", rc));
183 return rc;
184 }
185
186 /* prepend path? */
187 if (!RTPathHavePath(szFilename))
188 {
189 char *psz = pdmR3FileR3(szFilename, false /*fShared*/);
190 if (!psz)
191 return VERR_NO_TMP_MEMORY;
192 size_t cch = strlen(psz) + 1;
193 if (cch > sizeof(szFilename))
194 {
195 RTMemTmpFree(psz);
196 AssertMsgFailed(("Filename too long! cch=%d '%s'\n", cch, psz));
197 return VERR_FILENAME_TOO_LONG;
198 }
199 memcpy(szFilename, psz, cch);
200 RTMemTmpFree(psz);
201 }
202
203 /*
204 * Load the module and register it's drivers.
205 */
206 RegCB.pCfgNode = pCur;
207 rc = pdmR3DrvLoad(pVM, &RegCB, szFilename, szName);
208 if (RT_FAILURE(rc))
209 return rc;
210 }
211
212 LogFlow(("pdmR3DrvInit: returns VINF_SUCCESS\n"));
213 return VINF_SUCCESS;
214}
215
216
217/**
218 * Loads one driver module and call the registration entry point.
219 *
220 * @returns VBox status code.
221 * @param pVM The cross context VM structure.
222 * @param pRegCB The registration callback stuff.
223 * @param pszFilename Module filename.
224 * @param pszName Module name.
225 */
226static int pdmR3DrvLoad(PVM pVM, PPDMDRVREGCBINT pRegCB, const char *pszFilename, const char *pszName)
227{
228 /*
229 * Load it.
230 */
231 int rc = pdmR3LoadR3U(pVM->pUVM, pszFilename, pszName);
232 if (RT_SUCCESS(rc))
233 {
234 /*
235 * Get the registration export and call it.
236 */
237 FNPDMVBOXDRIVERSREGISTER *pfnVBoxDriversRegister;
238 rc = PDMR3LdrGetSymbolR3(pVM, pszName, "VBoxDriversRegister", (void **)&pfnVBoxDriversRegister);
239 if (RT_SUCCESS(rc))
240 {
241 Log(("PDM: Calling VBoxDriversRegister (%p) of %s (%s)\n", pfnVBoxDriversRegister, pszName, pszFilename));
242 rc = pfnVBoxDriversRegister(&pRegCB->Core, VBOX_VERSION);
243 if (RT_SUCCESS(rc))
244 Log(("PDM: Successfully loaded driver module %s (%s).\n", pszName, pszFilename));
245 else
246 AssertMsgFailed(("VBoxDriversRegister failed with rc=%Rrc\n", rc));
247 }
248 else
249 {
250 AssertMsgFailed(("Failed to locate 'VBoxDriversRegister' in %s (%s) rc=%Rrc\n", pszName, pszFilename, rc));
251 if (rc == VERR_SYMBOL_NOT_FOUND)
252 rc = VERR_PDM_NO_REGISTRATION_EXPORT;
253 }
254 }
255 else
256 AssertMsgFailed(("Failed to load %s (%s) rc=%Rrc!\n", pszName, pszFilename, rc));
257 return rc;
258}
259
260
261/** @interface_method_impl{PDMDRVREGCB,pfnRegister} */
262static DECLCALLBACK(int) pdmR3DrvRegister(PCPDMDRVREGCB pCallbacks, PCPDMDRVREG pReg)
263{
264 /*
265 * Validate the registration structure.
266 */
267 AssertPtrReturn(pReg, VERR_INVALID_POINTER);
268 AssertMsgReturn(pReg->u32Version == PDM_DRVREG_VERSION,
269 ("%#x\n", pReg->u32Version),
270 VERR_PDM_UNKNOWN_DRVREG_VERSION);
271 AssertReturn(pReg->szName[0], VERR_PDM_INVALID_DRIVER_REGISTRATION);
272 AssertMsgReturn(RTStrEnd(pReg->szName, sizeof(pReg->szName)),
273 ("%.*s\n", sizeof(pReg->szName), pReg->szName),
274 VERR_PDM_INVALID_DRIVER_REGISTRATION);
275 AssertMsgReturn(pdmR3IsValidName(pReg->szName), ("%.*s\n", sizeof(pReg->szName), pReg->szName),
276 VERR_PDM_INVALID_DRIVER_REGISTRATION);
277 AssertMsgReturn( !(pReg->fFlags & PDM_DRVREG_FLAGS_R0)
278 || ( pReg->szR0Mod[0]
279 && RTStrEnd(pReg->szR0Mod, sizeof(pReg->szR0Mod))),
280 ("%s: %.*s\n", pReg->szName, sizeof(pReg->szR0Mod), pReg->szR0Mod),
281 VERR_PDM_INVALID_DRIVER_REGISTRATION);
282 AssertMsgReturn( !(pReg->fFlags & PDM_DRVREG_FLAGS_RC)
283 || ( pReg->szRCMod[0]
284 && RTStrEnd(pReg->szRCMod, sizeof(pReg->szRCMod))),
285 ("%s: %.*s\n", pReg->szName, sizeof(pReg->szRCMod), pReg->szRCMod),
286 VERR_PDM_INVALID_DRIVER_REGISTRATION);
287 AssertMsgReturn(VALID_PTR(pReg->pszDescription),
288 ("%s: %p\n", pReg->szName, pReg->pszDescription),
289 VERR_PDM_INVALID_DRIVER_REGISTRATION);
290 AssertMsgReturn(!(pReg->fFlags & ~(PDM_DRVREG_FLAGS_HOST_BITS_MASK | PDM_DRVREG_FLAGS_R0 | PDM_DRVREG_FLAGS_RC)),
291 ("%s: %#x\n", pReg->szName, pReg->fFlags),
292 VERR_PDM_INVALID_DRIVER_REGISTRATION);
293 AssertMsgReturn((pReg->fFlags & PDM_DRVREG_FLAGS_HOST_BITS_MASK) == PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
294 ("%s: %#x\n", pReg->szName, pReg->fFlags),
295 VERR_PDM_INVALID_DRIVER_HOST_BITS);
296 AssertMsgReturn(pReg->cMaxInstances > 0,
297 ("%s: %#x\n", pReg->szName, pReg->cMaxInstances),
298 VERR_PDM_INVALID_DRIVER_REGISTRATION);
299 AssertMsgReturn(pReg->cbInstance <= _1M,
300 ("%s: %#x\n", pReg->szName, pReg->cbInstance),
301 VERR_PDM_INVALID_DRIVER_REGISTRATION);
302 AssertMsgReturn(VALID_PTR(pReg->pfnConstruct),
303 ("%s: %p\n", pReg->szName, pReg->pfnConstruct),
304 VERR_PDM_INVALID_DRIVER_REGISTRATION);
305 AssertMsgReturn(VALID_PTR(pReg->pfnRelocate) || !(pReg->fFlags & PDM_DRVREG_FLAGS_RC),
306 ("%s: %#x\n", pReg->szName, pReg->cbInstance),
307 VERR_PDM_INVALID_DRIVER_REGISTRATION);
308 AssertMsgReturn(pReg->pfnSoftReset == NULL,
309 ("%s: %p\n", pReg->szName, pReg->pfnSoftReset),
310 VERR_PDM_INVALID_DRIVER_REGISTRATION);
311 AssertMsgReturn(pReg->u32VersionEnd == PDM_DRVREG_VERSION,
312 ("%s: %#x\n", pReg->szName, pReg->u32VersionEnd),
313 VERR_PDM_INVALID_DRIVER_REGISTRATION);
314
315 /*
316 * Check for duplicate and find FIFO entry at the same time.
317 */
318 PCPDMDRVREGCBINT pRegCB = (PCPDMDRVREGCBINT)pCallbacks;
319 PPDMDRV pDrvPrev = NULL;
320 PPDMDRV pDrv = pRegCB->pVM->pdm.s.pDrvs;
321 for (; pDrv; pDrvPrev = pDrv, pDrv = pDrv->pNext)
322 {
323 if (!strcmp(pDrv->pReg->szName, pReg->szName))
324 {
325 AssertMsgFailed(("Driver '%s' already exists\n", pReg->szName));
326 return VERR_PDM_DRIVER_NAME_CLASH;
327 }
328 }
329
330 /*
331 * Allocate new driver structure and insert it into the list.
332 */
333 int rc;
334 pDrv = (PPDMDRV)MMR3HeapAlloc(pRegCB->pVM, MM_TAG_PDM_DRIVER, sizeof(*pDrv));
335 if (pDrv)
336 {
337 pDrv->pNext = NULL;
338 pDrv->cInstances = 0;
339 pDrv->iNextInstance = 0;
340 pDrv->pReg = pReg;
341 rc = CFGMR3QueryStringAllocDef( pRegCB->pCfgNode, "RCSearchPath", &pDrv->pszRCSearchPath, NULL);
342 if (RT_SUCCESS(rc))
343 rc = CFGMR3QueryStringAllocDef(pRegCB->pCfgNode, "R0SearchPath", &pDrv->pszR0SearchPath, NULL);
344 if (RT_SUCCESS(rc))
345 {
346 if (pDrvPrev)
347 pDrvPrev->pNext = pDrv;
348 else
349 pRegCB->pVM->pdm.s.pDrvs = pDrv;
350 Log(("PDM: Registered driver '%s'\n", pReg->szName));
351 return VINF_SUCCESS;
352 }
353 MMR3HeapFree(pDrv);
354 }
355 else
356 rc = VERR_NO_MEMORY;
357 return rc;
358}
359
360
361/**
362 * Lookups a driver structure by name.
363 * @internal
364 */
365PPDMDRV pdmR3DrvLookup(PVM pVM, const char *pszName)
366{
367 for (PPDMDRV pDrv = pVM->pdm.s.pDrvs; pDrv; pDrv = pDrv->pNext)
368 if (!strcmp(pDrv->pReg->szName, pszName))
369 return pDrv;
370 return NULL;
371}
372
373
374/**
375 * Transforms the driver chain as it's being instantiated.
376 *
377 * Worker for pdmR3DrvInstantiate.
378 *
379 * @returns VBox status code.
380 * @param pVM The cross context VM structure.
381 * @param pDrvAbove The driver above, NULL if top.
382 * @param pLun The LUN.
383 * @param ppNode The AttachedDriver node, replaced if any
384 * morphing took place.
385 */
386static int pdmR3DrvMaybeTransformChain(PVM pVM, PPDMDRVINS pDrvAbove, PPDMLUN pLun, PCFGMNODE *ppNode)
387{
388 /*
389 * The typical state of affairs is that there are no injections.
390 */
391 PCFGMNODE pCurTrans = CFGMR3GetFirstChild(CFGMR3GetChild(CFGMR3GetRoot(pVM), "PDM/DriverTransformations"));
392 if (!pCurTrans)
393 return VINF_SUCCESS;
394
395 /*
396 * Gather the attributes used in the matching process.
397 */
398 const char *pszDevice = pLun->pDevIns
399 ? pLun->pDevIns->Internal.s.pDevR3->pReg->szName
400 : pLun->pUsbIns->Internal.s.pUsbDev->pReg->szName;
401 char szLun[32];
402 RTStrPrintf(szLun, sizeof(szLun), "%u", pLun->iLun);
403 const char *pszAbove = pDrvAbove ? pDrvAbove->Internal.s.pDrv->pReg->szName : "<top>";
404 char *pszThisDrv;
405 int rc = CFGMR3QueryStringAlloc(*ppNode, "Driver", &pszThisDrv);
406 AssertMsgRCReturn(rc, ("Query for string value of \"Driver\" -> %Rrc\n", rc),
407 rc == VERR_CFGM_VALUE_NOT_FOUND ? VERR_PDM_CFG_MISSING_DRIVER_NAME : rc);
408
409 uint64_t uInjectTransformationAbove = 0;
410 if (pDrvAbove)
411 {
412 rc = CFGMR3QueryIntegerDef(CFGMR3GetParent(*ppNode), "InjectTransformationPtr", &uInjectTransformationAbove, 0);
413 AssertLogRelRCReturn(rc, rc);
414 }
415
416
417 /*
418 * Enumerate possible driver chain transformations.
419 */
420 unsigned cTransformations = 0;
421 for (; pCurTrans != NULL; pCurTrans = CFGMR3GetNextChild(pCurTrans))
422 {
423 char szCurTransNm[256];
424 rc = CFGMR3GetName(pCurTrans, szCurTransNm, sizeof(szCurTransNm));
425 AssertLogRelRCReturn(rc, rc);
426
427 /** @cfgm{/PDM/DriverTransformations/<name>/Device,string,*}
428 * One or more simple wildcard patters separated by '|' for matching
429 * the devices this transformation rule applies to. */
430 char *pszMultiPat;
431 rc = CFGMR3QueryStringAllocDef(pCurTrans, "Device", &pszMultiPat, "*");
432 AssertLogRelRCReturn(rc, rc);
433 bool fMatch = RTStrSimplePatternMultiMatch(pszMultiPat, RTSTR_MAX, pszDevice, RTSTR_MAX, NULL);
434 MMR3HeapFree(pszMultiPat);
435 if (!fMatch)
436 continue;
437
438 /** @cfgm{/PDM/DriverTransformations/<name>/LUN,string,*}
439 * One or more simple wildcard patters separated by '|' for matching
440 * the LUNs this transformation rule applies to. */
441 rc = CFGMR3QueryStringAllocDef(pCurTrans, "LUN", &pszMultiPat, "*");
442 AssertLogRelRCReturn(rc, rc);
443 fMatch = RTStrSimplePatternMultiMatch(pszMultiPat, RTSTR_MAX, szLun, RTSTR_MAX, NULL);
444 MMR3HeapFree(pszMultiPat);
445 if (!fMatch)
446 continue;
447
448 /** @cfgm{/PDM/DriverTransformations/<name>/BelowDriver,string,*}
449 * One or more simple wildcard patters separated by '|' for matching the
450 * drivers the transformation should be applied below. This means, that
451 * when the drivers matched here attached another driver below them, the
452 * transformation will be applied. To represent the device, '<top>' is
453 * used. */
454 rc = CFGMR3QueryStringAllocDef(pCurTrans, "BelowDriver", &pszMultiPat, "*");
455 AssertLogRelRCReturn(rc, rc);
456 fMatch = RTStrSimplePatternMultiMatch(pszMultiPat, RTSTR_MAX, pszAbove, RTSTR_MAX, NULL);
457 MMR3HeapFree(pszMultiPat);
458 if (!fMatch)
459 continue;
460
461 /** @cfgm{/PDM/DriverTransformations/<name>/AboveDriver,string,*}
462 * One or more simple wildcard patters separated by '|' for matching the
463 * drivers the transformation should be applie above or at (depending on
464 * the action). The value being matched against here is the driver that
465 * is in the process of being attached, so for mergeconfig actions this is
466 * usually what you need to match on. */
467 rc = CFGMR3QueryStringAlloc(pCurTrans, "AboveDriver", &pszMultiPat);
468 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
469 rc = VINF_SUCCESS;
470 else
471 {
472 AssertLogRelRCReturn(rc, rc);
473 fMatch = RTStrSimplePatternMultiMatch(pszMultiPat, RTSTR_MAX, pszThisDrv, RTSTR_MAX, NULL);
474 MMR3HeapFree(pszMultiPat);
475 if (!fMatch)
476 continue;
477 if (uInjectTransformationAbove == (uintptr_t)pCurTrans)
478 continue;
479 }
480
481 /*
482 * We've got a match! Now, what are we supposed to do?
483 */
484 /** @cfgm{/PDM/DriverTransformations/<name>/Action,string,inject}
485 * The action that the the transformation takes. Possible values are:
486 * - inject
487 * - mergeconfig: This merges and the content of the 'Config' key under the
488 * transformation into the driver's own 'Config' key, replacing any
489 * duplicates.
490 * - remove
491 * - removetree
492 * - replace
493 * - replacetree
494 */
495 char szAction[16];
496 rc = CFGMR3QueryStringDef(pCurTrans, "Action", szAction, sizeof(szAction), "inject");
497 AssertLogRelRCReturn(rc, rc);
498 AssertLogRelMsgReturn( !strcmp(szAction, "inject")
499 || !strcmp(szAction, "mergeconfig")
500 || !strcmp(szAction, "remove")
501 || !strcmp(szAction, "removetree")
502 || !strcmp(szAction, "replace")
503 || !strcmp(szAction, "replacetree")
504 ,
505 ("Action='%s', valid values are 'inject', 'mergeconfig', 'replace', 'replacetree', 'remove', 'removetree'.\n", szAction),
506 VERR_PDM_MISCONFIGURED_DRV_TRANSFORMATION);
507 LogRel(("PDMDriver: Applying '%s' to '%s'::[%s]...'%s': %s\n", szCurTransNm, pszDevice, szLun, pszThisDrv, szAction));
508 CFGMR3Dump(*ppNode);
509 CFGMR3Dump(pCurTrans);
510
511 /* Get the attached driver to inject. */
512 PCFGMNODE pTransAttDrv = NULL;
513 if (!strcmp(szAction, "inject") || !strcmp(szAction, "replace") || !strcmp(szAction, "replacetree"))
514 {
515 pTransAttDrv = CFGMR3GetChild(pCurTrans, "AttachedDriver");
516 AssertLogRelMsgReturn(pTransAttDrv,
517 ("An %s transformation requires an AttachedDriver child node!\n", szAction),
518 VERR_PDM_MISCONFIGURED_DRV_TRANSFORMATION);
519 }
520
521
522 /*
523 * Remove the node.
524 */
525 if (!strcmp(szAction, "remove") || !strcmp(szAction, "removetree"))
526 {
527 PCFGMNODE pBelowThis = CFGMR3GetChild(*ppNode, "AttachedDriver");
528 if (!pBelowThis || !strcmp(szAction, "removetree"))
529 {
530 CFGMR3RemoveNode(*ppNode);
531 *ppNode = NULL;
532 }
533 else
534 {
535 PCFGMNODE pBelowThisCopy;
536 rc = CFGMR3DuplicateSubTree(pBelowThis, &pBelowThisCopy);
537 AssertLogRelRCReturn(rc, rc);
538
539 rc = CFGMR3ReplaceSubTree(*ppNode, pBelowThisCopy);
540 AssertLogRelRCReturnStmt(rc, CFGMR3RemoveNode(pBelowThis), rc);
541 }
542 }
543 /*
544 * Replace the driver about to be instantiated.
545 */
546 else if (!strcmp(szAction, "replace") || !strcmp(szAction, "replacetree"))
547 {
548 PCFGMNODE pTransCopy;
549 rc = CFGMR3DuplicateSubTree(pTransAttDrv, &pTransCopy);
550 AssertLogRelRCReturn(rc, rc);
551
552 PCFGMNODE pBelowThis = CFGMR3GetChild(*ppNode, "AttachedDriver");
553 if (!pBelowThis || !strcmp(szAction, "replacetree"))
554 rc = VINF_SUCCESS;
555 else
556 {
557 PCFGMNODE pBelowThisCopy;
558 rc = CFGMR3DuplicateSubTree(pBelowThis, &pBelowThisCopy);
559 if (RT_SUCCESS(rc))
560 {
561 rc = CFGMR3InsertSubTree(pTransCopy, "AttachedDriver", pBelowThisCopy, NULL);
562 AssertLogRelRC(rc);
563 if (RT_FAILURE(rc))
564 CFGMR3RemoveNode(pBelowThisCopy);
565 }
566 }
567 if (RT_SUCCESS(rc))
568 rc = CFGMR3ReplaceSubTree(*ppNode, pTransCopy);
569 if (RT_FAILURE(rc))
570 CFGMR3RemoveNode(pTransCopy);
571 }
572 /*
573 * Inject a driver before the driver about to be instantiated.
574 */
575 else if (!strcmp(szAction, "inject"))
576 {
577 PCFGMNODE pTransCopy;
578 rc = CFGMR3DuplicateSubTree(pTransAttDrv, &pTransCopy);
579 AssertLogRelRCReturn(rc, rc);
580
581 PCFGMNODE pThisCopy;
582 rc = CFGMR3DuplicateSubTree(*ppNode, &pThisCopy);
583 if (RT_SUCCESS(rc))
584 {
585 rc = CFGMR3InsertSubTree(pTransCopy, "AttachedDriver", pThisCopy, NULL);
586 if (RT_SUCCESS(rc))
587 {
588 rc = CFGMR3InsertInteger(pTransCopy, "InjectTransformationPtr", (uintptr_t)pCurTrans);
589 AssertLogRelRC(rc);
590 rc = CFGMR3InsertString(pTransCopy, "InjectTransformationNm", szCurTransNm);
591 AssertLogRelRC(rc);
592 if (RT_SUCCESS(rc))
593 rc = CFGMR3ReplaceSubTree(*ppNode, pTransCopy);
594 }
595 else
596 {
597 AssertLogRelRC(rc);
598 CFGMR3RemoveNode(pThisCopy);
599 }
600 }
601 if (RT_FAILURE(rc))
602 CFGMR3RemoveNode(pTransCopy);
603 }
604 /*
605 * Merge the Config node of the transformation with the one of the
606 * current driver.
607 */
608 else if (!strcmp(szAction, "mergeconfig"))
609 {
610 PCFGMNODE pTransConfig = CFGMR3GetChild(pCurTrans, "Config");
611 AssertLogRelReturn(pTransConfig, VERR_PDM_MISCONFIGURED_DRV_TRANSFORMATION);
612
613 PCFGMNODE pDrvConfig = CFGMR3GetChild(*ppNode, "Config");
614 if (*ppNode)
615 CFGMR3InsertNode(*ppNode, "Config", &pDrvConfig);
616 AssertLogRelReturn(pDrvConfig, VERR_PDM_CANNOT_TRANSFORM_REMOVED_DRIVER);
617
618 rc = CFGMR3CopyTree(pDrvConfig, pTransConfig, CFGM_COPY_FLAGS_REPLACE_VALUES | CFGM_COPY_FLAGS_MERGE_KEYS);
619 AssertLogRelRCReturn(rc, rc);
620 }
621 else
622 AssertFailed();
623
624 cTransformations++;
625 if (*ppNode)
626 CFGMR3Dump(*ppNode);
627 else
628 LogRel(("PDMDriver: The transformation removed the driver.\n"));
629 }
630
631 /*
632 * Note what happened in the release log.
633 */
634 if (cTransformations > 0)
635 LogRel(("PDMDriver: Transformations done. Applied %u driver transformations.\n", cTransformations));
636
637 return rc;
638}
639
640
641/**
642 * Instantiate a driver.
643 *
644 * @returns VBox status code, including informational statuses.
645 *
646 * @param pVM The cross context VM structure.
647 * @param pNode The CFGM node for the driver.
648 * @param pBaseInterface The base interface.
649 * @param pDrvAbove The driver above it. NULL if it's the top-most
650 * driver.
651 * @param pLun The LUN the driver is being attached to. NULL
652 * if we're instantiating a driver chain before
653 * attaching it - untested.
654 * @param ppBaseInterface Where to return the pointer to the base
655 * interface of the newly created driver.
656 *
657 * @remarks Recursive calls to this function is normal as the drivers will
658 * attach to anything below them during the pfnContruct call.
659 *
660 * @todo Need to extend this interface a bit so that the driver
661 * transformation feature can attach drivers to unconfigured LUNs and
662 * at the end of chains.
663 */
664int pdmR3DrvInstantiate(PVM pVM, PCFGMNODE pNode, PPDMIBASE pBaseInterface, PPDMDRVINS pDrvAbove,
665 PPDMLUN pLun, PPDMIBASE *ppBaseInterface)
666{
667 Assert(!pDrvAbove || !pDrvAbove->Internal.s.pDown);
668 Assert(!pDrvAbove || !pDrvAbove->pDownBase);
669
670 Assert(pBaseInterface->pfnQueryInterface(pBaseInterface, PDMIBASE_IID) == pBaseInterface);
671
672 /*
673 * Do driver chain injections
674 */
675 int rc = pdmR3DrvMaybeTransformChain(pVM, pDrvAbove, pLun, &pNode);
676 if (RT_FAILURE(rc))
677 return rc;
678 if (!pNode)
679 return VERR_PDM_NO_ATTACHED_DRIVER;
680
681 /*
682 * Find the driver.
683 */
684 char *pszName;
685 rc = CFGMR3QueryStringAlloc(pNode, "Driver", &pszName);
686 if (RT_SUCCESS(rc))
687 {
688 PPDMDRV pDrv = pdmR3DrvLookup(pVM, pszName);
689 if ( pDrv
690 && pDrv->cInstances < pDrv->pReg->cMaxInstances)
691 {
692 /* config node */
693 PCFGMNODE pConfigNode = CFGMR3GetChild(pNode, "Config");
694 if (!pConfigNode)
695 rc = CFGMR3InsertNode(pNode, "Config", &pConfigNode);
696 if (RT_SUCCESS(rc))
697 {
698 CFGMR3SetRestrictedRoot(pConfigNode);
699
700 /*
701 * Allocate the driver instance.
702 */
703 size_t cb = RT_OFFSETOF(PDMDRVINS, achInstanceData[pDrv->pReg->cbInstance]);
704 cb = RT_ALIGN_Z(cb, 16);
705 bool const fHyperHeap = !!(pDrv->pReg->fFlags & (PDM_DRVREG_FLAGS_R0 | PDM_DRVREG_FLAGS_RC));
706 PPDMDRVINS pNew;
707 if (fHyperHeap)
708 rc = MMHyperAlloc(pVM, cb, 64, MM_TAG_PDM_DRIVER, (void **)&pNew);
709 else
710 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_DRIVER, cb, (void **)&pNew);
711 if (RT_SUCCESS(rc))
712 {
713 /*
714 * Initialize the instance structure (declaration order).
715 */
716 pNew->u32Version = PDM_DRVINS_VERSION;
717 pNew->iInstance = pDrv->iNextInstance;
718 pNew->Internal.s.pUp = pDrvAbove ? pDrvAbove : NULL;
719 //pNew->Internal.s.pDown = NULL;
720 pNew->Internal.s.pLun = pLun;
721 pNew->Internal.s.pDrv = pDrv;
722 pNew->Internal.s.pVMR3 = pVM;
723 pNew->Internal.s.pVMR0 = pDrv->pReg->fFlags & PDM_DRVREG_FLAGS_R0 ? pVM->pVMR0 : NIL_RTR0PTR;
724 pNew->Internal.s.pVMRC = pDrv->pReg->fFlags & PDM_DRVREG_FLAGS_RC ? pVM->pVMRC : NIL_RTRCPTR;
725 //pNew->Internal.s.fDetaching = false;
726 pNew->Internal.s.fVMSuspended = true; /** @todo should be 'false', if driver is attached at runtime. */
727 //pNew->Internal.s.fVMReset = false;
728 pNew->Internal.s.fHyperHeap = fHyperHeap;
729 //pNew->Internal.s.pfnAsyncNotify = NULL;
730 pNew->Internal.s.pCfgHandle = pNode;
731 pNew->pReg = pDrv->pReg;
732 pNew->pCfg = pConfigNode;
733 pNew->pUpBase = pBaseInterface;
734 Assert(!pDrvAbove || pBaseInterface == &pDrvAbove->IBase);
735 //pNew->pDownBase = NULL;
736 //pNew->IBase.pfnQueryInterface = NULL;
737 //pNew->fTracing = 0;
738 pNew->idTracing = ++pVM->pdm.s.idTracingOther;
739 pNew->pHlpR3 = &g_pdmR3DrvHlp;
740 pNew->pvInstanceDataR3 = &pNew->achInstanceData[0];
741 if (pDrv->pReg->fFlags & PDM_DRVREG_FLAGS_R0)
742 {
743 pNew->pvInstanceDataR0 = MMHyperR3ToR0(pVM, &pNew->achInstanceData[0]);
744 rc = PDMR3LdrGetSymbolR0(pVM, NULL, "g_pdmR0DrvHlp", &pNew->pHlpR0);
745 AssertReleaseRCReturn(rc, rc);
746 }
747 if ( (pDrv->pReg->fFlags & PDM_DRVREG_FLAGS_RC)
748 && !HMIsEnabled(pVM))
749 {
750 pNew->pvInstanceDataR0 = MMHyperR3ToRC(pVM, &pNew->achInstanceData[0]);
751 rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDrvHlp", &pNew->pHlpRC);
752 AssertReleaseRCReturn(rc, rc);
753 }
754
755 pDrv->iNextInstance++;
756 pDrv->cInstances++;
757
758 /*
759 * Link with it with the driver above / LUN.
760 */
761 if (pDrvAbove)
762 {
763 pDrvAbove->pDownBase = &pNew->IBase;
764 pDrvAbove->Internal.s.pDown = pNew;
765 }
766 else if (pLun)
767 pLun->pTop = pNew;
768 if (pLun)
769 pLun->pBottom = pNew;
770
771 /*
772 * Invoke the constructor.
773 */
774 rc = pDrv->pReg->pfnConstruct(pNew, pNew->pCfg, 0 /*fFlags*/);
775 if (RT_SUCCESS(rc))
776 {
777 AssertPtr(pNew->IBase.pfnQueryInterface);
778 Assert(pNew->IBase.pfnQueryInterface(&pNew->IBase, PDMIBASE_IID) == &pNew->IBase);
779
780 /* Success! */
781 *ppBaseInterface = &pNew->IBase;
782 if (pLun)
783 Log(("PDM: Attached driver %p:'%s'/%d to LUN#%d on device '%s'/%d, pDrvAbove=%p:'%s'/%d\n",
784 pNew, pDrv->pReg->szName, pNew->iInstance,
785 pLun->iLun,
786 pLun->pDevIns ? pLun->pDevIns->pReg->szName : pLun->pUsbIns->pReg->szName,
787 pLun->pDevIns ? pLun->pDevIns->iInstance : pLun->pUsbIns->iInstance,
788 pDrvAbove, pDrvAbove ? pDrvAbove->pReg->szName : "", pDrvAbove ? pDrvAbove->iInstance : UINT32_MAX));
789 else
790 Log(("PDM: Attached driver %p:'%s'/%d, pDrvAbove=%p:'%s'/%d\n",
791 pNew, pDrv->pReg->szName, pNew->iInstance,
792 pDrvAbove, pDrvAbove ? pDrvAbove->pReg->szName : "", pDrvAbove ? pDrvAbove->iInstance : UINT32_MAX));
793 }
794 else
795 {
796 pdmR3DrvDestroyChain(pNew, PDM_TACH_FLAGS_NO_CALLBACKS);
797 if (rc == VERR_VERSION_MISMATCH)
798 rc = VERR_PDM_DRIVER_VERSION_MISMATCH;
799 }
800 }
801 else
802 AssertMsgFailed(("Failed to allocate %d bytes for instantiating driver '%s'! rc=%Rrc\n", cb, pszName, rc));
803 }
804 else
805 AssertMsgFailed(("Failed to create Config node! rc=%Rrc\n", rc));
806 }
807 else if (pDrv)
808 {
809 AssertMsgFailed(("Too many instances of driver '%s', max is %u\n", pszName, pDrv->pReg->cMaxInstances));
810 rc = VERR_PDM_TOO_MANY_DRIVER_INSTANCES;
811 }
812 else
813 {
814 AssertMsgFailed(("Driver '%s' wasn't found!\n", pszName));
815 rc = VERR_PDM_DRIVER_NOT_FOUND;
816 }
817 MMR3HeapFree(pszName);
818 }
819 else
820 {
821 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
822 rc = VERR_PDM_CFG_MISSING_DRIVER_NAME;
823 else
824 AssertMsgFailed(("Query for string value of \"Driver\" -> %Rrc\n", rc));
825 }
826 return rc;
827}
828
829
830/**
831 * Detaches a driver from whatever it's attached to.
832 * This will of course lead to the destruction of the driver and all drivers below it in the chain.
833 *
834 * @returns VINF_SUCCESS
835 * @param pDrvIns The driver instance to detach.
836 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
837 */
838int pdmR3DrvDetach(PPDMDRVINS pDrvIns, uint32_t fFlags)
839{
840 PDMDRV_ASSERT_DRVINS(pDrvIns);
841 LogFlow(("pdmR3DrvDetach: pDrvIns=%p '%s'/%d\n", pDrvIns, pDrvIns->pReg->szName, pDrvIns->iInstance));
842 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
843
844 /*
845 * Check that we're not doing this recursively, that could have unwanted sideeffects!
846 */
847 if (pDrvIns->Internal.s.fDetaching)
848 {
849 AssertMsgFailed(("Recursive detach! '%s'/%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
850 return VINF_SUCCESS;
851 }
852
853 /*
854 * Check that we actually can detach this instance.
855 * The requirement is that the driver/device above has a detach method.
856 */
857 if ( pDrvIns->Internal.s.pUp
858 ? !pDrvIns->Internal.s.pUp->pReg->pfnDetach
859 : pDrvIns->Internal.s.pLun->pDevIns
860 ? !pDrvIns->Internal.s.pLun->pDevIns->pReg->pfnDetach
861 : !pDrvIns->Internal.s.pLun->pUsbIns->pReg->pfnDriverDetach
862 )
863 {
864 AssertMsgFailed(("Cannot detach driver instance because the driver/device above doesn't support it!\n"));
865 return VERR_PDM_DRIVER_DETACH_NOT_POSSIBLE;
866 }
867
868 /*
869 * Join paths with pdmR3DrvDestroyChain.
870 */
871 pdmR3DrvDestroyChain(pDrvIns, fFlags);
872 return VINF_SUCCESS;
873}
874
875
876/**
877 * Destroys a driver chain starting with the specified driver.
878 *
879 * This is used when unplugging a device at run time.
880 *
881 * @param pDrvIns Pointer to the driver instance to start with.
882 * @param fFlags PDM_TACH_FLAGS_NOT_HOT_PLUG, PDM_TACH_FLAGS_NO_CALLBACKS
883 * or 0.
884 */
885void pdmR3DrvDestroyChain(PPDMDRVINS pDrvIns, uint32_t fFlags)
886{
887 PVM pVM = pDrvIns->Internal.s.pVMR3;
888 VM_ASSERT_EMT(pVM);
889
890 /*
891 * Detach the bottommost driver until we've detached pDrvIns.
892 */
893 pDrvIns->Internal.s.fDetaching = true;
894 PPDMDRVINS pCur;
895 do
896 {
897 /* find the driver to detach. */
898 pCur = pDrvIns;
899 while (pCur->Internal.s.pDown)
900 pCur = pCur->Internal.s.pDown;
901 LogFlow(("pdmR3DrvDestroyChain: pCur=%p '%s'/%d\n", pCur, pCur->pReg->szName, pCur->iInstance));
902
903 /*
904 * Unlink it and notify parent.
905 */
906 pCur->Internal.s.fDetaching = true;
907
908 PPDMLUN pLun = pCur->Internal.s.pLun;
909 Assert(pLun->pBottom == pCur);
910 pLun->pBottom = pCur->Internal.s.pUp;
911
912 if (pCur->Internal.s.pUp)
913 {
914 /* driver parent */
915 PPDMDRVINS pParent = pCur->Internal.s.pUp;
916 pCur->Internal.s.pUp = NULL;
917 pParent->Internal.s.pDown = NULL;
918
919 if (!(fFlags & PDM_TACH_FLAGS_NO_CALLBACKS) && pParent->pReg->pfnDetach)
920 pParent->pReg->pfnDetach(pParent, fFlags);
921
922 pParent->pDownBase = NULL;
923 }
924 else
925 {
926 /* device parent */
927 Assert(pLun->pTop == pCur);
928 pLun->pTop = NULL;
929 if (!(fFlags & PDM_TACH_FLAGS_NO_CALLBACKS))
930 {
931 if (pLun->pDevIns)
932 {
933 if (pLun->pDevIns->pReg->pfnDetach)
934 {
935 PDMCritSectEnter(pLun->pDevIns->pCritSectRoR3, VERR_IGNORED);
936 pLun->pDevIns->pReg->pfnDetach(pLun->pDevIns, pLun->iLun, fFlags);
937 PDMCritSectLeave(pLun->pDevIns->pCritSectRoR3);
938 }
939 }
940 else
941 {
942 if (pLun->pUsbIns->pReg->pfnDriverDetach)
943 {
944 /** @todo USB device locking? */
945 pLun->pUsbIns->pReg->pfnDriverDetach(pLun->pUsbIns, pLun->iLun, fFlags);
946 }
947 }
948 }
949 }
950
951 /*
952 * Call destructor.
953 */
954 pCur->pUpBase = NULL;
955 if (pCur->pReg->pfnDestruct)
956 pCur->pReg->pfnDestruct(pCur);
957 pCur->Internal.s.pDrv->cInstances--;
958
959 /*
960 * Free all resources allocated by the driver.
961 */
962 /* Queues. */
963 int rc = PDMR3QueueDestroyDriver(pVM, pCur);
964 AssertRC(rc);
965
966 /* Timers. */
967 rc = TMR3TimerDestroyDriver(pVM, pCur);
968 AssertRC(rc);
969
970 /* SSM data units. */
971 rc = SSMR3DeregisterDriver(pVM, pCur, NULL, 0);
972 AssertRC(rc);
973
974 /* PDM threads. */
975 rc = pdmR3ThreadDestroyDriver(pVM, pCur);
976 AssertRC(rc);
977
978 /* Info handlers. */
979 rc = DBGFR3InfoDeregisterDriver(pVM, pCur, NULL);
980 AssertRC(rc);
981
982 /* PDM critsects. */
983 rc = pdmR3CritSectBothDeleteDriver(pVM, pCur);
984 AssertRC(rc);
985
986 /* Block caches. */
987 PDMR3BlkCacheReleaseDriver(pVM, pCur);
988
989#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
990 /* Completion templates.*/
991 pdmR3AsyncCompletionTemplateDestroyDriver(pVM, pCur);
992#endif
993
994 /* Finally, the driver it self. */
995 bool fHyperHeap = pCur->Internal.s.fHyperHeap;
996 ASMMemFill32(pCur, RT_OFFSETOF(PDMDRVINS, achInstanceData[pCur->pReg->cbInstance]), 0xdeadd0d0);
997 if (fHyperHeap)
998 MMHyperFree(pVM, pCur);
999 else
1000 MMR3HeapFree(pCur);
1001
1002 } while (pCur != pDrvIns);
1003}
1004
1005
1006
1007
1008/** @name Driver Helpers
1009 * @{
1010 */
1011
1012/** @interface_method_impl{PDMDRVHLPR3,pfnAttach} */
1013static DECLCALLBACK(int) pdmR3DrvHlp_Attach(PPDMDRVINS pDrvIns, uint32_t fFlags, PPDMIBASE *ppBaseInterface)
1014{
1015 PDMDRV_ASSERT_DRVINS(pDrvIns);
1016 PVM pVM = pDrvIns->Internal.s.pVMR3;
1017 VM_ASSERT_EMT(pVM);
1018 LogFlow(("pdmR3DrvHlp_Attach: caller='%s'/%d: fFlags=%#x\n", pDrvIns->pReg->szName, pDrvIns->iInstance, fFlags));
1019 Assert(!(fFlags & ~(PDM_TACH_FLAGS_NOT_HOT_PLUG)));
1020 RT_NOREF_PV(fFlags);
1021
1022 /*
1023 * Check that there isn't anything attached already.
1024 */
1025 int rc;
1026 if (!pDrvIns->Internal.s.pDown)
1027 {
1028 Assert(pDrvIns->Internal.s.pLun->pBottom == pDrvIns);
1029
1030 /*
1031 * Get the attached driver configuration.
1032 */
1033 PCFGMNODE pNode = CFGMR3GetChild(pDrvIns->Internal.s.pCfgHandle, "AttachedDriver");
1034 if (pNode)
1035 rc = pdmR3DrvInstantiate(pVM, pNode, &pDrvIns->IBase, pDrvIns, pDrvIns->Internal.s.pLun, ppBaseInterface);
1036 else
1037 rc = VERR_PDM_NO_ATTACHED_DRIVER;
1038 }
1039 else
1040 {
1041 AssertMsgFailed(("Already got a driver attached. The driver should keep track of such things!\n"));
1042 rc = VERR_PDM_DRIVER_ALREADY_ATTACHED;
1043 }
1044
1045 LogFlow(("pdmR3DrvHlp_Attach: caller='%s'/%d: return %Rrc\n",
1046 pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1047 return rc;
1048}
1049
1050
1051/** @interface_method_impl{PDMDRVHLPR3,pfnDetach} */
1052static DECLCALLBACK(int) pdmR3DrvHlp_Detach(PPDMDRVINS pDrvIns, uint32_t fFlags)
1053{
1054 PDMDRV_ASSERT_DRVINS(pDrvIns);
1055 LogFlow(("pdmR3DrvHlp_Detach: caller='%s'/%d: fFlags=%#x\n",
1056 pDrvIns->pReg->szName, pDrvIns->iInstance, fFlags));
1057 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1058
1059 /*
1060 * Anything attached?
1061 */
1062 int rc;
1063 if (pDrvIns->Internal.s.pDown)
1064 rc = pdmR3DrvDetach(pDrvIns->Internal.s.pDown, fFlags);
1065 else
1066 {
1067 AssertMsgFailed(("Nothing attached!\n"));
1068 rc = VERR_PDM_NO_DRIVER_ATTACHED;
1069 }
1070
1071 LogFlow(("pdmR3DrvHlp_Detach: caller='%s'/%d: returns %Rrc\n",
1072 pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1073 return rc;
1074}
1075
1076
1077/** @interface_method_impl{PDMDRVHLPR3,pfnDetachSelf} */
1078static DECLCALLBACK(int) pdmR3DrvHlp_DetachSelf(PPDMDRVINS pDrvIns, uint32_t fFlags)
1079{
1080 PDMDRV_ASSERT_DRVINS(pDrvIns);
1081 LogFlow(("pdmR3DrvHlp_DetachSelf: caller='%s'/%d: fFlags=%#x\n",
1082 pDrvIns->pReg->szName, pDrvIns->iInstance, fFlags));
1083 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1084
1085 int rc = pdmR3DrvDetach(pDrvIns, fFlags);
1086
1087 LogFlow(("pdmR3DrvHlp_Detach: returns %Rrc\n", rc)); /* pDrvIns is freed by now. */
1088 return rc;
1089}
1090
1091
1092/** @interface_method_impl{PDMDRVHLPR3,pfnMountPrepare} */
1093static DECLCALLBACK(int) pdmR3DrvHlp_MountPrepare(PPDMDRVINS pDrvIns, const char *pszFilename, const char *pszCoreDriver)
1094{
1095 PDMDRV_ASSERT_DRVINS(pDrvIns);
1096 LogFlow(("pdmR3DrvHlp_MountPrepare: caller='%s'/%d: pszFilename=%p:{%s} pszCoreDriver=%p:{%s}\n",
1097 pDrvIns->pReg->szName, pDrvIns->iInstance, pszFilename, pszFilename, pszCoreDriver, pszCoreDriver));
1098 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1099
1100 /*
1101 * Do the caller have anything attached below itself?
1102 */
1103 if (pDrvIns->Internal.s.pDown)
1104 {
1105 AssertMsgFailed(("Cannot prepare a mount when something's attached to you!\n"));
1106 return VERR_PDM_DRIVER_ALREADY_ATTACHED;
1107 }
1108
1109 /*
1110 * We're asked to prepare, so we'll start off by nuking the
1111 * attached configuration tree.
1112 */
1113 PCFGMNODE pNode = CFGMR3GetChild(pDrvIns->Internal.s.pCfgHandle, "AttachedDriver");
1114 if (pNode)
1115 CFGMR3RemoveNode(pNode);
1116
1117 /*
1118 * If there is no core driver, we'll have to probe for it.
1119 */
1120 if (!pszCoreDriver)
1121 {
1122 /** @todo implement image probing. */
1123 AssertReleaseMsgFailed(("Not implemented!\n"));
1124 return VERR_NOT_IMPLEMENTED;
1125 }
1126
1127 /*
1128 * Construct the basic attached driver configuration.
1129 */
1130 int rc = CFGMR3InsertNode(pDrvIns->Internal.s.pCfgHandle, "AttachedDriver", &pNode);
1131 if (RT_SUCCESS(rc))
1132 {
1133 rc = CFGMR3InsertString(pNode, "Driver", pszCoreDriver);
1134 if (RT_SUCCESS(rc))
1135 {
1136 PCFGMNODE pCfg;
1137 rc = CFGMR3InsertNode(pNode, "Config", &pCfg);
1138 if (RT_SUCCESS(rc))
1139 {
1140 rc = CFGMR3InsertString(pCfg, "Path", pszFilename);
1141 if (RT_SUCCESS(rc))
1142 {
1143 LogFlow(("pdmR3DrvHlp_MountPrepare: caller='%s'/%d: returns %Rrc (Driver=%s)\n",
1144 pDrvIns->pReg->szName, pDrvIns->iInstance, rc, pszCoreDriver));
1145 return rc;
1146 }
1147 else
1148 AssertMsgFailed(("Path string insert failed, rc=%Rrc\n", rc));
1149 }
1150 else
1151 AssertMsgFailed(("Config node failed, rc=%Rrc\n", rc));
1152 }
1153 else
1154 AssertMsgFailed(("Driver string insert failed, rc=%Rrc\n", rc));
1155 CFGMR3RemoveNode(pNode);
1156 }
1157 else
1158 AssertMsgFailed(("AttachedDriver node insert failed, rc=%Rrc\n", rc));
1159
1160 LogFlow(("pdmR3DrvHlp_MountPrepare: caller='%s'/%d: returns %Rrc\n",
1161 pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1162 return rc;
1163}
1164
1165
1166/** @interface_method_impl{PDMDRVHLPR3,pfnAssertEMT} */
1167static DECLCALLBACK(bool) pdmR3DrvHlp_AssertEMT(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)
1168{
1169 PDMDRV_ASSERT_DRVINS(pDrvIns);
1170 if (VM_IS_EMT(pDrvIns->Internal.s.pVMR3))
1171 return true;
1172
1173 char szMsg[100];
1174 RTStrPrintf(szMsg, sizeof(szMsg), "AssertEMT '%s'/%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance);
1175 RTAssertMsg1Weak(szMsg, iLine, pszFile, pszFunction);
1176 AssertBreakpoint();
1177 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1178 return false;
1179}
1180
1181
1182/** @interface_method_impl{PDMDRVHLPR3,pfnAssertOther} */
1183static DECLCALLBACK(bool) pdmR3DrvHlp_AssertOther(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)
1184{
1185 PDMDRV_ASSERT_DRVINS(pDrvIns);
1186 if (!VM_IS_EMT(pDrvIns->Internal.s.pVMR3))
1187 return true;
1188
1189 char szMsg[100];
1190 RTStrPrintf(szMsg, sizeof(szMsg), "AssertOther '%s'/%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance);
1191 RTAssertMsg1Weak(szMsg, iLine, pszFile, pszFunction);
1192 AssertBreakpoint();
1193 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1194 return false;
1195}
1196
1197
1198/** @interface_method_impl{PDMDRVHLPR3,pfnVMSetError} */
1199static DECLCALLBACK(int) pdmR3DrvHlp_VMSetError(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
1200{
1201 PDMDRV_ASSERT_DRVINS(pDrvIns);
1202 va_list args;
1203 va_start(args, pszFormat);
1204 int rc2 = VMSetErrorV(pDrvIns->Internal.s.pVMR3, rc, RT_SRC_POS_ARGS, pszFormat, args); Assert(rc2 == rc); NOREF(rc2);
1205 va_end(args);
1206 return rc;
1207}
1208
1209
1210/** @interface_method_impl{PDMDRVHLPR3,pfnVMSetErrorV} */
1211static DECLCALLBACK(int) pdmR3DrvHlp_VMSetErrorV(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
1212{
1213 PDMDRV_ASSERT_DRVINS(pDrvIns);
1214 int rc2 = VMSetErrorV(pDrvIns->Internal.s.pVMR3, rc, RT_SRC_POS_ARGS, pszFormat, va); Assert(rc2 == rc); NOREF(rc2);
1215 return rc;
1216}
1217
1218
1219/** @interface_method_impl{PDMDRVHLPR3,pfnVMSetRuntimeError} */
1220static DECLCALLBACK(int) pdmR3DrvHlp_VMSetRuntimeError(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
1221{
1222 PDMDRV_ASSERT_DRVINS(pDrvIns);
1223 va_list args;
1224 va_start(args, pszFormat);
1225 int rc = VMSetRuntimeErrorV(pDrvIns->Internal.s.pVMR3, fFlags, pszErrorId, pszFormat, args);
1226 va_end(args);
1227 return rc;
1228}
1229
1230
1231/** @interface_method_impl{PDMDRVHLPR3,pfnVMSetRuntimeErrorV} */
1232static DECLCALLBACK(int) pdmR3DrvHlp_VMSetRuntimeErrorV(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)
1233{
1234 PDMDRV_ASSERT_DRVINS(pDrvIns);
1235 int rc = VMSetRuntimeErrorV(pDrvIns->Internal.s.pVMR3, fFlags, pszErrorId, pszFormat, va);
1236 return rc;
1237}
1238
1239
1240/** @interface_method_impl{PDMDRVHLPR3,pfnVMState} */
1241static DECLCALLBACK(VMSTATE) pdmR3DrvHlp_VMState(PPDMDRVINS pDrvIns)
1242{
1243 PDMDRV_ASSERT_DRVINS(pDrvIns);
1244
1245 VMSTATE enmVMState = VMR3GetState(pDrvIns->Internal.s.pVMR3);
1246
1247 LogFlow(("pdmR3DrvHlp_VMState: caller='%s'/%d: returns %d (%s)\n", pDrvIns->pReg->szName, pDrvIns->iInstance,
1248 enmVMState, VMR3GetStateName(enmVMState)));
1249 return enmVMState;
1250}
1251
1252
1253/** @interface_method_impl{PDMDRVHLPR3,pfnVMTeleportedAndNotFullyResumedYet} */
1254static DECLCALLBACK(bool) pdmR3DrvHlp_VMTeleportedAndNotFullyResumedYet(PPDMDRVINS pDrvIns)
1255{
1256 PDMDRV_ASSERT_DRVINS(pDrvIns);
1257
1258 bool fRc = VMR3TeleportedAndNotFullyResumedYet(pDrvIns->Internal.s.pVMR3);
1259
1260 LogFlow(("pdmR3DrvHlp_VMState: caller='%s'/%d: returns %RTbool)\n", pDrvIns->pReg->szName, pDrvIns->iInstance,
1261 fRc));
1262 return fRc;
1263}
1264
1265
1266/** @interface_method_impl{PDMDRVHLPR3,pfnGetSupDrvSession} */
1267static DECLCALLBACK(PSUPDRVSESSION) pdmR3DrvHlp_GetSupDrvSession(PPDMDRVINS pDrvIns)
1268{
1269 PDMDRV_ASSERT_DRVINS(pDrvIns);
1270
1271 PSUPDRVSESSION pSession = pDrvIns->Internal.s.pVMR3->pSession;
1272 LogFlow(("pdmR3DrvHlp_GetSupDrvSession: caller='%s'/%d: returns %p)\n", pDrvIns->pReg->szName, pDrvIns->iInstance,
1273 pSession));
1274 return pSession;
1275}
1276
1277
1278/** @interface_method_impl{PDMDRVHLPR3,pfnQueueCreate} */
1279static DECLCALLBACK(int) pdmR3DrvHlp_QueueCreate(PPDMDRVINS pDrvIns, uint32_t cbItem, uint32_t cItems, uint32_t cMilliesInterval,
1280 PFNPDMQUEUEDRV pfnCallback, const char *pszName, PPDMQUEUE *ppQueue)
1281{
1282 PDMDRV_ASSERT_DRVINS(pDrvIns);
1283 LogFlow(("pdmR3DrvHlp_PDMQueueCreate: caller='%s'/%d: cbItem=%d cItems=%d cMilliesInterval=%d pfnCallback=%p pszName=%p:{%s} ppQueue=%p\n",
1284 pDrvIns->pReg->szName, pDrvIns->iInstance, cbItem, cItems, cMilliesInterval, pfnCallback, pszName, pszName, ppQueue));
1285 PVM pVM = pDrvIns->Internal.s.pVMR3;
1286 VM_ASSERT_EMT(pVM);
1287
1288 if (pDrvIns->iInstance > 0)
1289 {
1290 pszName = MMR3HeapAPrintf(pVM, MM_TAG_PDM_DRIVER_DESC, "%s_%u", pszName, pDrvIns->iInstance);
1291 AssertLogRelReturn(pszName, VERR_NO_MEMORY);
1292 }
1293
1294 int rc = PDMR3QueueCreateDriver(pVM, pDrvIns, cbItem, cItems, cMilliesInterval, pfnCallback, pszName, ppQueue);
1295
1296 LogFlow(("pdmR3DrvHlp_PDMQueueCreate: caller='%s'/%d: returns %Rrc *ppQueue=%p\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc, *ppQueue));
1297 return rc;
1298}
1299
1300
1301/** @interface_method_impl{PDMDRVHLPR3,pfnTMGetVirtualFreq} */
1302static DECLCALLBACK(uint64_t) pdmR3DrvHlp_TMGetVirtualFreq(PPDMDRVINS pDrvIns)
1303{
1304 PDMDRV_ASSERT_DRVINS(pDrvIns);
1305
1306 return TMVirtualGetFreq(pDrvIns->Internal.s.pVMR3);
1307}
1308
1309
1310/** @interface_method_impl{PDMDRVHLPR3,pfnTMGetVirtualTime} */
1311static DECLCALLBACK(uint64_t) pdmR3DrvHlp_TMGetVirtualTime(PPDMDRVINS pDrvIns)
1312{
1313 PDMDRV_ASSERT_DRVINS(pDrvIns);
1314
1315 return TMVirtualGet(pDrvIns->Internal.s.pVMR3);
1316}
1317
1318
1319/** @interface_method_impl{PDMDRVHLPR3,pfnTMTimerCreate} */
1320static DECLCALLBACK(int) pdmR3DrvHlp_TMTimerCreate(PPDMDRVINS pDrvIns, TMCLOCK enmClock, PFNTMTIMERDRV pfnCallback, void *pvUser, uint32_t fFlags, const char *pszDesc, PPTMTIMERR3 ppTimer)
1321{
1322 PDMDRV_ASSERT_DRVINS(pDrvIns);
1323 LogFlow(("pdmR3DrvHlp_TMTimerCreate: caller='%s'/%d: enmClock=%d pfnCallback=%p pvUser=%p fFlags=%#x pszDesc=%p:{%s} ppTimer=%p\n",
1324 pDrvIns->pReg->szName, pDrvIns->iInstance, enmClock, pfnCallback, pvUser, fFlags, pszDesc, pszDesc, ppTimer));
1325
1326 int rc = TMR3TimerCreateDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, ppTimer);
1327
1328 LogFlow(("pdmR3DrvHlp_TMTimerCreate: caller='%s'/%d: returns %Rrc *ppTimer=%p\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc, *ppTimer));
1329 return rc;
1330}
1331
1332
1333
1334/** @interface_method_impl{PDMDRVHLPR3,pfnSSMRegister} */
1335static DECLCALLBACK(int) pdmR3DrvHlp_SSMRegister(PPDMDRVINS pDrvIns, uint32_t uVersion, size_t cbGuess,
1336 PFNSSMDRVLIVEPREP pfnLivePrep, PFNSSMDRVLIVEEXEC pfnLiveExec, PFNSSMDRVLIVEVOTE pfnLiveVote,
1337 PFNSSMDRVSAVEPREP pfnSavePrep, PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVSAVEDONE pfnSaveDone,
1338 PFNSSMDRVLOADPREP pfnLoadPrep, PFNSSMDRVLOADEXEC pfnLoadExec, PFNSSMDRVLOADDONE pfnLoadDone)
1339{
1340 PDMDRV_ASSERT_DRVINS(pDrvIns);
1341 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1342 LogFlow(("pdmR3DrvHlp_SSMRegister: caller='%s'/%d: uVersion=%#x cbGuess=%#x \n"
1343 " pfnLivePrep=%p pfnLiveExec=%p pfnLiveVote=%p pfnSavePrep=%p pfnSaveExec=%p pfnSaveDone=%p pszLoadPrep=%p pfnLoadExec=%p pfnLoaddone=%p\n",
1344 pDrvIns->pReg->szName, pDrvIns->iInstance, uVersion, cbGuess,
1345 pfnLivePrep, pfnLiveExec, pfnLiveVote,
1346 pfnSavePrep, pfnSaveExec, pfnSaveDone, pfnLoadPrep, pfnLoadExec, pfnLoadDone));
1347
1348 int rc = SSMR3RegisterDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, pDrvIns->pReg->szName, pDrvIns->iInstance,
1349 uVersion, cbGuess,
1350 pfnLivePrep, pfnLiveExec, pfnLiveVote,
1351 pfnSavePrep, pfnSaveExec, pfnSaveDone,
1352 pfnLoadPrep, pfnLoadExec, pfnLoadDone);
1353
1354 LogFlow(("pdmR3DrvHlp_SSMRegister: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1355 return rc;
1356}
1357
1358
1359/** @interface_method_impl{PDMDRVHLPR3,pfnSSMDeregister} */
1360static DECLCALLBACK(int) pdmR3DrvHlp_SSMDeregister(PPDMDRVINS pDrvIns, const char *pszName, uint32_t uInstance)
1361{
1362 PDMDRV_ASSERT_DRVINS(pDrvIns);
1363 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1364 LogFlow(("pdmR3DrvHlp_SSMDeregister: caller='%s'/%d: pszName=%p:{%s} uInstance=%#x\n",
1365 pDrvIns->pReg->szName, pDrvIns->iInstance, pszName, pszName, uInstance));
1366
1367 int rc = SSMR3DeregisterDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, pszName, uInstance);
1368
1369 LogFlow(("pdmR3DrvHlp_SSMDeregister: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1370 return rc;
1371}
1372
1373
1374/** @interface_method_impl{PDMDRVHLPR3,pfnDBGFInfoRegister} */
1375static DECLCALLBACK(int) pdmR3DrvHlp_DBGFInfoRegister(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDRV pfnHandler)
1376{
1377 PDMDRV_ASSERT_DRVINS(pDrvIns);
1378 LogFlow(("pdmR3DrvHlp_DBGFInfoRegister: caller='%s'/%d: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p\n",
1379 pDrvIns->pReg->szName, pDrvIns->iInstance, pszName, pszName, pszDesc, pszDesc, pfnHandler));
1380
1381 int rc = DBGFR3InfoRegisterDriver(pDrvIns->Internal.s.pVMR3, pszName, pszDesc, pfnHandler, pDrvIns);
1382
1383 LogFlow(("pdmR3DrvHlp_DBGFInfoRegister: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1384 return rc;
1385}
1386
1387
1388/** @interface_method_impl{PDMDRVHLPR3,pfnDBGFInfoDeregister} */
1389static DECLCALLBACK(int) pdmR3DrvHlp_DBGFInfoDeregister(PPDMDRVINS pDrvIns, const char *pszName)
1390{
1391 PDMDRV_ASSERT_DRVINS(pDrvIns);
1392 LogFlow(("pdmR3DrvHlp_DBGFInfoDeregister: caller='%s'/%d: pszName=%p:{%s}\n",
1393 pDrvIns->pReg->szName, pDrvIns->iInstance, pszName, pszName));
1394
1395 int rc = DBGFR3InfoDeregisterDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, pszName);
1396
1397 LogFlow(("pdmR3DrvHlp_DBGFInfoDeregister: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1398
1399 return rc;
1400}
1401
1402
1403/** @interface_method_impl{PDMDRVHLPR3,pfnSTAMRegister} */
1404static DECLCALLBACK(void) pdmR3DrvHlp_STAMRegister(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, const char *pszName,
1405 STAMUNIT enmUnit, const char *pszDesc)
1406{
1407 PDMDRV_ASSERT_DRVINS(pDrvIns);
1408 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1409
1410 STAM_REG(pDrvIns->Internal.s.pVMR3, pvSample, enmType, pszName, enmUnit, pszDesc);
1411 RT_NOREF6(pDrvIns, pvSample, enmType, pszName, enmUnit, pszDesc);
1412 /** @todo track the samples so they can be dumped & deregistered when the driver instance is destroyed.
1413 * For now we just have to be careful not to use this call for drivers which can be unloaded. */
1414}
1415
1416
1417/** @interface_method_impl{PDMDRVHLPR3,pfnSTAMRegisterF} */
1418static DECLCALLBACK(void) pdmR3DrvHlp_STAMRegisterF(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
1419 STAMUNIT enmUnit, const char *pszDesc, const char *pszName, ...)
1420{
1421 PDMDRV_ASSERT_DRVINS(pDrvIns);
1422 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1423
1424 va_list args;
1425 va_start(args, pszName);
1426 int rc = STAMR3RegisterV(pDrvIns->Internal.s.pVMR3, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, args);
1427 va_end(args);
1428 AssertRC(rc);
1429}
1430
1431
1432/** @interface_method_impl{PDMDRVHLPR3,pfnSTAMRegisterV} */
1433static DECLCALLBACK(void) pdmR3DrvHlp_STAMRegisterV(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
1434 STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list args)
1435{
1436 PDMDRV_ASSERT_DRVINS(pDrvIns);
1437 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1438
1439 int rc = STAMR3RegisterV(pDrvIns->Internal.s.pVMR3, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, args);
1440 AssertRC(rc);
1441}
1442
1443
1444/** @interface_method_impl{PDMDRVHLPR3,pfnSTAMDeregister} */
1445static DECLCALLBACK(int) pdmR3DrvHlp_STAMDeregister(PPDMDRVINS pDrvIns, void *pvSample)
1446{
1447 PDMDRV_ASSERT_DRVINS(pDrvIns);
1448 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1449
1450 return STAMR3DeregisterByAddr(pDrvIns->Internal.s.pVMR3->pUVM, pvSample);
1451}
1452
1453
1454/** @interface_method_impl{PDMDRVHLPR3,pfnSUPCallVMMR0Ex} */
1455static DECLCALLBACK(int) pdmR3DrvHlp_SUPCallVMMR0Ex(PPDMDRVINS pDrvIns, unsigned uOperation, void *pvArg, unsigned cbArg)
1456{
1457 PDMDRV_ASSERT_DRVINS(pDrvIns);
1458 LogFlow(("pdmR3DrvHlp_SSMCallVMMR0Ex: caller='%s'/%d: uOperation=%u pvArg=%p cbArg=%d\n",
1459 pDrvIns->pReg->szName, pDrvIns->iInstance, uOperation, pvArg, cbArg));
1460 RT_NOREF_PV(cbArg);
1461
1462 int rc;
1463 if ( uOperation >= VMMR0_DO_SRV_START
1464 && uOperation < VMMR0_DO_SRV_END)
1465 rc = SUPR3CallVMMR0Ex(pDrvIns->Internal.s.pVMR3->pVMR0, NIL_VMCPUID, uOperation, 0, (PSUPVMMR0REQHDR)pvArg);
1466 else
1467 {
1468 AssertMsgFailed(("Invalid uOperation=%u\n", uOperation));
1469 rc = VERR_INVALID_PARAMETER;
1470 }
1471
1472 LogFlow(("pdmR3DrvHlp_SUPCallVMMR0Ex: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1473 return rc;
1474}
1475
1476
1477/** @interface_method_impl{PDMDRVHLPR3,pfnUSBRegisterHub} */
1478static DECLCALLBACK(int) pdmR3DrvHlp_USBRegisterHub(PPDMDRVINS pDrvIns, uint32_t fVersions, uint32_t cPorts, PCPDMUSBHUBREG pUsbHubReg, PPCPDMUSBHUBHLP ppUsbHubHlp)
1479{
1480 PDMDRV_ASSERT_DRVINS(pDrvIns);
1481 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1482 LogFlow(("pdmR3DrvHlp_USBRegisterHub: caller='%s'/%d: fVersions=%#x cPorts=%#x pUsbHubReg=%p ppUsbHubHlp=%p\n",
1483 pDrvIns->pReg->szName, pDrvIns->iInstance, fVersions, cPorts, pUsbHubReg, ppUsbHubHlp));
1484
1485#ifdef VBOX_WITH_USB
1486 int rc = pdmR3UsbRegisterHub(pDrvIns->Internal.s.pVMR3, pDrvIns, fVersions, cPorts, pUsbHubReg, ppUsbHubHlp);
1487#else
1488 int rc = VERR_NOT_SUPPORTED;
1489#endif
1490
1491 LogFlow(("pdmR3DrvHlp_USBRegisterHub: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1492 return rc;
1493}
1494
1495
1496/** @interface_method_impl{PDMDRVHLPR3,pfnSetAsyncNotification} */
1497static DECLCALLBACK(int) pdmR3DrvHlp_SetAsyncNotification(PPDMDRVINS pDrvIns, PFNPDMDRVASYNCNOTIFY pfnAsyncNotify)
1498{
1499 PDMDRV_ASSERT_DRVINS(pDrvIns);
1500 VM_ASSERT_EMT0(pDrvIns->Internal.s.pVMR3);
1501 LogFlow(("pdmR3DrvHlp_SetAsyncNotification: caller='%s'/%d: pfnAsyncNotify=%p\n", pDrvIns->pReg->szName, pDrvIns->iInstance, pfnAsyncNotify));
1502
1503 int rc = VINF_SUCCESS;
1504 AssertStmt(pfnAsyncNotify, rc = VERR_INVALID_PARAMETER);
1505 AssertStmt(!pDrvIns->Internal.s.pfnAsyncNotify, rc = VERR_WRONG_ORDER);
1506 AssertStmt(pDrvIns->Internal.s.fVMSuspended || pDrvIns->Internal.s.fVMReset, rc = VERR_WRONG_ORDER);
1507 VMSTATE enmVMState = VMR3GetState(pDrvIns->Internal.s.pVMR3);
1508 AssertStmt( enmVMState == VMSTATE_SUSPENDING
1509 || enmVMState == VMSTATE_SUSPENDING_EXT_LS
1510 || enmVMState == VMSTATE_SUSPENDING_LS
1511 || enmVMState == VMSTATE_RESETTING
1512 || enmVMState == VMSTATE_RESETTING_LS
1513 || enmVMState == VMSTATE_POWERING_OFF
1514 || enmVMState == VMSTATE_POWERING_OFF_LS,
1515 rc = VERR_INVALID_STATE);
1516
1517 if (RT_SUCCESS(rc))
1518 pDrvIns->Internal.s.pfnAsyncNotify = pfnAsyncNotify;
1519
1520 LogFlow(("pdmR3DrvHlp_SetAsyncNotification: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1521 return rc;
1522}
1523
1524
1525/** @interface_method_impl{PDMDRVHLPR3,pfnAsyncNotificationCompleted} */
1526static DECLCALLBACK(void) pdmR3DrvHlp_AsyncNotificationCompleted(PPDMDRVINS pDrvIns)
1527{
1528 PDMDRV_ASSERT_DRVINS(pDrvIns);
1529 PVM pVM = pDrvIns->Internal.s.pVMR3;
1530
1531 VMSTATE enmVMState = VMR3GetState(pVM);
1532 if ( enmVMState == VMSTATE_SUSPENDING
1533 || enmVMState == VMSTATE_SUSPENDING_EXT_LS
1534 || enmVMState == VMSTATE_SUSPENDING_LS
1535 || enmVMState == VMSTATE_RESETTING
1536 || enmVMState == VMSTATE_RESETTING_LS
1537 || enmVMState == VMSTATE_POWERING_OFF
1538 || enmVMState == VMSTATE_POWERING_OFF_LS)
1539 {
1540 LogFlow(("pdmR3DrvHlp_AsyncNotificationCompleted: caller='%s'/%d:\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
1541 VMR3AsyncPdmNotificationWakeupU(pVM->pUVM);
1542 }
1543 else
1544 LogFlow(("pdmR3DrvHlp_AsyncNotificationCompleted: caller='%s'/%d: enmVMState=%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance, enmVMState));
1545}
1546
1547
1548/** @interface_method_impl{PDMDRVHLPR3,pfnThreadCreate} */
1549static DECLCALLBACK(int) pdmR3DrvHlp_ThreadCreate(PPDMDRVINS pDrvIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDRV pfnThread,
1550 PFNPDMTHREADWAKEUPDRV pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
1551{
1552 PDMDRV_ASSERT_DRVINS(pDrvIns);
1553 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1554 LogFlow(("pdmR3DrvHlp_ThreadCreate: caller='%s'/%d: ppThread=%p pvUser=%p pfnThread=%p pfnWakeup=%p cbStack=%#zx enmType=%d pszName=%p:{%s}\n",
1555 pDrvIns->pReg->szName, pDrvIns->iInstance, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName, pszName));
1556
1557 int rc = pdmR3ThreadCreateDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName);
1558
1559 LogFlow(("pdmR3DrvHlp_ThreadCreate: caller='%s'/%d: returns %Rrc *ppThread=%RTthrd\n", pDrvIns->pReg->szName, pDrvIns->iInstance,
1560 rc, *ppThread));
1561 return rc;
1562}
1563
1564
1565/** @interface_method_impl{PDMDRVHLPR3,pfnAsyncCompletionTemplateCreate} */
1566static DECLCALLBACK(int) pdmR3DrvHlp_AsyncCompletionTemplateCreate(PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate,
1567 PFNPDMASYNCCOMPLETEDRV pfnCompleted, void *pvTemplateUser,
1568 const char *pszDesc)
1569{
1570 PDMDRV_ASSERT_DRVINS(pDrvIns);
1571 LogFlow(("pdmR3DrvHlp_AsyncCompletionTemplateCreate: caller='%s'/%d: ppTemplate=%p pfnCompleted=%p pszDesc=%p:{%s}\n",
1572 pDrvIns->pReg->szName, pDrvIns->iInstance, ppTemplate, pfnCompleted, pszDesc, pszDesc));
1573
1574 int rc = pdmR3AsyncCompletionTemplateCreateDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, ppTemplate, pfnCompleted, pvTemplateUser, pszDesc);
1575
1576 LogFlow(("pdmR3DrvHlp_AsyncCompletionTemplateCreate: caller='%s'/%d: returns %Rrc *ppThread=%p\n", pDrvIns->pReg->szName,
1577 pDrvIns->iInstance, rc, *ppTemplate));
1578 return rc;
1579}
1580
1581
1582#ifdef VBOX_WITH_NETSHAPER
1583/** @interface_method_impl{PDMDRVHLPR3,pfnNetShaperAttach} */
1584static DECLCALLBACK(int) pdmR3DrvHlp_NetShaperAttach(PPDMDRVINS pDrvIns, const char *pszBwGroup, PPDMNSFILTER pFilter)
1585{
1586 PDMDRV_ASSERT_DRVINS(pDrvIns);
1587 LogFlow(("pdmR3DrvHlp_NetShaperAttach: caller='%s'/%d: pFilter=%p pszBwGroup=%p:{%s}\n",
1588 pDrvIns->pReg->szName, pDrvIns->iInstance, pFilter, pszBwGroup, pszBwGroup));
1589
1590 int rc = PDMR3NsAttach(pDrvIns->Internal.s.pVMR3->pUVM, pDrvIns, pszBwGroup, pFilter);
1591
1592 LogFlow(("pdmR3DrvHlp_NetShaperAttach: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1593 pDrvIns->iInstance, rc));
1594 return rc;
1595}
1596
1597
1598/** @interface_method_impl{PDMDRVHLPR3,pfnNetShaperDetach} */
1599static DECLCALLBACK(int) pdmR3DrvHlp_NetShaperDetach(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter)
1600{
1601 PDMDRV_ASSERT_DRVINS(pDrvIns);
1602 LogFlow(("pdmR3DrvHlp_NetShaperDetach: caller='%s'/%d: pFilter=%p\n",
1603 pDrvIns->pReg->szName, pDrvIns->iInstance, pFilter));
1604
1605 int rc = PDMR3NsDetach(pDrvIns->Internal.s.pVMR3->pUVM, pDrvIns, pFilter);
1606
1607 LogFlow(("pdmR3DrvHlp_NetShaperDetach: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1608 pDrvIns->iInstance, rc));
1609 return rc;
1610}
1611#endif /* VBOX_WITH_NETSHAPER */
1612
1613
1614/** @interface_method_impl{PDMDRVHLPR3,pfnLdrGetRCInterfaceSymbols} */
1615static DECLCALLBACK(int) pdmR3DrvHlp_LdrGetRCInterfaceSymbols(PPDMDRVINS pDrvIns, void *pvInterface, size_t cbInterface,
1616 const char *pszSymPrefix, const char *pszSymList)
1617{
1618 PDMDRV_ASSERT_DRVINS(pDrvIns);
1619 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1620 LogFlow(("pdmR3DrvHlp_LdrGetRCInterfaceSymbols: caller='%s'/%d: pvInterface=%p cbInterface=%zu pszSymPrefix=%p:{%s} pszSymList=%p:{%s}\n",
1621 pDrvIns->pReg->szName, pDrvIns->iInstance, pvInterface, cbInterface, pszSymPrefix, pszSymPrefix, pszSymList, pszSymList));
1622
1623 int rc;
1624 if ( strncmp(pszSymPrefix, "drv", 3) == 0
1625 && RTStrIStr(pszSymPrefix + 3, pDrvIns->pReg->szName) != NULL)
1626 {
1627 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_RC)
1628 rc = PDMR3LdrGetInterfaceSymbols(pDrvIns->Internal.s.pVMR3,
1629 pvInterface, cbInterface,
1630 pDrvIns->pReg->szRCMod, pDrvIns->Internal.s.pDrv->pszRCSearchPath,
1631 pszSymPrefix, pszSymList,
1632 false /*fRing0OrRC*/);
1633 else
1634 {
1635 AssertMsgFailed(("Not a raw-mode enabled driver\n"));
1636 rc = VERR_PERMISSION_DENIED;
1637 }
1638 }
1639 else
1640 {
1641 AssertMsgFailed(("Invalid prefix '%s' for '%s'; must start with 'drv' and contain the driver name!\n",
1642 pszSymPrefix, pDrvIns->pReg->szName));
1643 rc = VERR_INVALID_NAME;
1644 }
1645
1646 LogFlow(("pdmR3DrvHlp_LdrGetRCInterfaceSymbols: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1647 pDrvIns->iInstance, rc));
1648 return rc;
1649}
1650
1651
1652/** @interface_method_impl{PDMDRVHLPR3,pfnLdrGetR0InterfaceSymbols} */
1653static DECLCALLBACK(int) pdmR3DrvHlp_LdrGetR0InterfaceSymbols(PPDMDRVINS pDrvIns, void *pvInterface, size_t cbInterface,
1654 const char *pszSymPrefix, const char *pszSymList)
1655{
1656 PDMDRV_ASSERT_DRVINS(pDrvIns);
1657 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1658 LogFlow(("pdmR3DrvHlp_LdrGetR0InterfaceSymbols: caller='%s'/%d: pvInterface=%p cbInterface=%zu pszSymPrefix=%p:{%s} pszSymList=%p:{%s}\n",
1659 pDrvIns->pReg->szName, pDrvIns->iInstance, pvInterface, cbInterface, pszSymPrefix, pszSymPrefix, pszSymList, pszSymList));
1660
1661 int rc;
1662 if ( strncmp(pszSymPrefix, "drv", 3) == 0
1663 && RTStrIStr(pszSymPrefix + 3, pDrvIns->pReg->szName) != NULL)
1664 {
1665 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_R0)
1666 rc = PDMR3LdrGetInterfaceSymbols(pDrvIns->Internal.s.pVMR3,
1667 pvInterface, cbInterface,
1668 pDrvIns->pReg->szR0Mod, pDrvIns->Internal.s.pDrv->pszR0SearchPath,
1669 pszSymPrefix, pszSymList,
1670 true /*fRing0OrRC*/);
1671 else
1672 {
1673 AssertMsgFailed(("Not a ring-0 enabled driver\n"));
1674 rc = VERR_PERMISSION_DENIED;
1675 }
1676 }
1677 else
1678 {
1679 AssertMsgFailed(("Invalid prefix '%s' for '%s'; must start with 'drv' and contain the driver name!\n",
1680 pszSymPrefix, pDrvIns->pReg->szName));
1681 rc = VERR_INVALID_NAME;
1682 }
1683
1684 LogFlow(("pdmR3DrvHlp_LdrGetR0InterfaceSymbols: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1685 pDrvIns->iInstance, rc));
1686 return rc;
1687}
1688
1689
1690/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectInit} */
1691static DECLCALLBACK(int) pdmR3DrvHlp_CritSectInit(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect,
1692 RT_SRC_POS_DECL, const char *pszName)
1693{
1694 PDMDRV_ASSERT_DRVINS(pDrvIns);
1695 PVM pVM = pDrvIns->Internal.s.pVMR3;
1696 VM_ASSERT_EMT(pVM);
1697 LogFlow(("pdmR3DrvHlp_CritSectInit: caller='%s'/%d: pCritSect=%p pszName=%s\n",
1698 pDrvIns->pReg->szName, pDrvIns->iInstance, pCritSect, pszName));
1699
1700 int rc = pdmR3CritSectInitDriver(pVM, pDrvIns, pCritSect, RT_SRC_POS_ARGS, "%s_%u", pszName, pDrvIns->iInstance);
1701
1702 LogFlow(("pdmR3DrvHlp_CritSectInit: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1703 pDrvIns->iInstance, rc));
1704 return rc;
1705}
1706
1707
1708/** @interface_method_impl{PDMDRVHLPR3,pfnCallR0} */
1709static DECLCALLBACK(int) pdmR3DrvHlp_CallR0(PPDMDRVINS pDrvIns, uint32_t uOperation, uint64_t u64Arg)
1710{
1711 PDMDRV_ASSERT_DRVINS(pDrvIns);
1712 PVM pVM = pDrvIns->Internal.s.pVMR3;
1713 LogFlow(("pdmR3DrvHlp_CallR0: caller='%s'/%d: uOperation=%#x u64Arg=%#RX64\n",
1714 pDrvIns->pReg->szName, pDrvIns->iInstance, uOperation, u64Arg));
1715
1716 /*
1717 * Lazy resolve the ring-0 entry point.
1718 */
1719 int rc = VINF_SUCCESS;
1720 PFNPDMDRVREQHANDLERR0 pfnReqHandlerR0 = pDrvIns->Internal.s.pfnReqHandlerR0;
1721 if (RT_UNLIKELY(pfnReqHandlerR0 == NIL_RTR0PTR))
1722 {
1723 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_R0)
1724 {
1725 char szSymbol[ sizeof("drvR0") + sizeof(pDrvIns->pReg->szName) + sizeof("ReqHandler")];
1726 strcat(strcat(strcpy(szSymbol, "drvR0"), pDrvIns->pReg->szName), "ReqHandler");
1727 szSymbol[sizeof("drvR0") - 1] = RT_C_TO_UPPER(szSymbol[sizeof("drvR0") - 1]);
1728
1729 rc = PDMR3LdrGetSymbolR0Lazy(pVM, pDrvIns->pReg->szR0Mod, pDrvIns->Internal.s.pDrv->pszR0SearchPath, szSymbol,
1730 &pfnReqHandlerR0);
1731 if (RT_SUCCESS(rc))
1732 pDrvIns->Internal.s.pfnReqHandlerR0 = pfnReqHandlerR0;
1733 else
1734 pfnReqHandlerR0 = NIL_RTR0PTR;
1735 }
1736 else
1737 rc = VERR_ACCESS_DENIED;
1738 }
1739 if (RT_LIKELY(pfnReqHandlerR0 != NIL_RTR0PTR))
1740 {
1741 /*
1742 * Make the ring-0 call.
1743 */
1744 PDMDRIVERCALLREQHANDLERREQ Req;
1745 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1746 Req.Hdr.cbReq = sizeof(Req);
1747 Req.pDrvInsR0 = PDMDRVINS_2_R0PTR(pDrvIns);
1748 Req.uOperation = uOperation;
1749 Req.u32Alignment = 0;
1750 Req.u64Arg = u64Arg;
1751 rc = SUPR3CallVMMR0Ex(pVM->pVMR0, NIL_VMCPUID, VMMR0_DO_PDM_DRIVER_CALL_REQ_HANDLER, 0, &Req.Hdr);
1752 }
1753
1754 LogFlow(("pdmR3DrvHlp_CallR0: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1755 pDrvIns->iInstance, rc));
1756 return rc;
1757}
1758
1759
1760/** @interface_method_impl{PDMDRVHLPR3,pfnFTSetCheckpoint} */
1761static DECLCALLBACK(int) pdmR3DrvHlp_FTSetCheckpoint(PPDMDRVINS pDrvIns, FTMCHECKPOINTTYPE enmType)
1762{
1763 PDMDRV_ASSERT_DRVINS(pDrvIns);
1764 return FTMSetCheckpoint(pDrvIns->Internal.s.pVMR3, enmType);
1765}
1766
1767
1768/** @interface_method_impl{PDMDRVHLPR3,pfnBlkCacheRetain} */
1769static DECLCALLBACK(int) pdmR3DrvHlp_BlkCacheRetain(PPDMDRVINS pDrvIns, PPPDMBLKCACHE ppBlkCache,
1770 PFNPDMBLKCACHEXFERCOMPLETEDRV pfnXferComplete,
1771 PFNPDMBLKCACHEXFERENQUEUEDRV pfnXferEnqueue,
1772 PFNPDMBLKCACHEXFERENQUEUEDISCARDDRV pfnXferEnqueueDiscard,
1773 const char *pcszId)
1774{
1775 PDMDRV_ASSERT_DRVINS(pDrvIns);
1776 return PDMR3BlkCacheRetainDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, ppBlkCache,
1777 pfnXferComplete, pfnXferEnqueue, pfnXferEnqueueDiscard, pcszId);
1778}
1779
1780
1781
1782/** @interface_method_impl{PDMDRVHLPR3,pfnVMGetSuspendReason} */
1783static DECLCALLBACK(VMSUSPENDREASON) pdmR3DrvHlp_VMGetSuspendReason(PPDMDRVINS pDrvIns)
1784{
1785 PDMDRV_ASSERT_DRVINS(pDrvIns);
1786 PVM pVM = pDrvIns->Internal.s.pVMR3;
1787 VM_ASSERT_EMT(pVM);
1788 VMSUSPENDREASON enmReason = VMR3GetSuspendReason(pVM->pUVM);
1789 LogFlow(("pdmR3DrvHlp_VMGetSuspendReason: caller='%s'/%d: returns %d\n",
1790 pDrvIns->pReg->szName, pDrvIns->iInstance, enmReason));
1791 return enmReason;
1792}
1793
1794
1795/** @interface_method_impl{PDMDRVHLPR3,pfnVMGetResumeReason} */
1796static DECLCALLBACK(VMRESUMEREASON) pdmR3DrvHlp_VMGetResumeReason(PPDMDRVINS pDrvIns)
1797{
1798 PDMDRV_ASSERT_DRVINS(pDrvIns);
1799 PVM pVM = pDrvIns->Internal.s.pVMR3;
1800 VM_ASSERT_EMT(pVM);
1801 VMRESUMEREASON enmReason = VMR3GetResumeReason(pVM->pUVM);
1802 LogFlow(("pdmR3DrvHlp_VMGetResumeReason: caller='%s'/%d: returns %d\n",
1803 pDrvIns->pReg->szName, pDrvIns->iInstance, enmReason));
1804 return enmReason;
1805}
1806
1807
1808/**
1809 * The driver helper structure.
1810 */
1811const PDMDRVHLPR3 g_pdmR3DrvHlp =
1812{
1813 PDM_DRVHLPR3_VERSION,
1814 pdmR3DrvHlp_Attach,
1815 pdmR3DrvHlp_Detach,
1816 pdmR3DrvHlp_DetachSelf,
1817 pdmR3DrvHlp_MountPrepare,
1818 pdmR3DrvHlp_AssertEMT,
1819 pdmR3DrvHlp_AssertOther,
1820 pdmR3DrvHlp_VMSetError,
1821 pdmR3DrvHlp_VMSetErrorV,
1822 pdmR3DrvHlp_VMSetRuntimeError,
1823 pdmR3DrvHlp_VMSetRuntimeErrorV,
1824 pdmR3DrvHlp_VMState,
1825 pdmR3DrvHlp_VMTeleportedAndNotFullyResumedYet,
1826 pdmR3DrvHlp_GetSupDrvSession,
1827 pdmR3DrvHlp_QueueCreate,
1828 pdmR3DrvHlp_TMGetVirtualFreq,
1829 pdmR3DrvHlp_TMGetVirtualTime,
1830 pdmR3DrvHlp_TMTimerCreate,
1831 pdmR3DrvHlp_SSMRegister,
1832 pdmR3DrvHlp_SSMDeregister,
1833 pdmR3DrvHlp_DBGFInfoRegister,
1834 pdmR3DrvHlp_DBGFInfoDeregister,
1835 pdmR3DrvHlp_STAMRegister,
1836 pdmR3DrvHlp_STAMRegisterF,
1837 pdmR3DrvHlp_STAMRegisterV,
1838 pdmR3DrvHlp_STAMDeregister,
1839 pdmR3DrvHlp_SUPCallVMMR0Ex,
1840 pdmR3DrvHlp_USBRegisterHub,
1841 pdmR3DrvHlp_SetAsyncNotification,
1842 pdmR3DrvHlp_AsyncNotificationCompleted,
1843 pdmR3DrvHlp_ThreadCreate,
1844 pdmR3DrvHlp_AsyncCompletionTemplateCreate,
1845#ifdef VBOX_WITH_NETSHAPER
1846 pdmR3DrvHlp_NetShaperAttach,
1847 pdmR3DrvHlp_NetShaperDetach,
1848#endif /* VBOX_WITH_NETSHAPER */
1849 pdmR3DrvHlp_LdrGetRCInterfaceSymbols,
1850 pdmR3DrvHlp_LdrGetR0InterfaceSymbols,
1851 pdmR3DrvHlp_CritSectInit,
1852 pdmR3DrvHlp_CallR0,
1853 pdmR3DrvHlp_FTSetCheckpoint,
1854 pdmR3DrvHlp_BlkCacheRetain,
1855 pdmR3DrvHlp_VMGetSuspendReason,
1856 pdmR3DrvHlp_VMGetResumeReason,
1857 NULL,
1858 NULL,
1859 NULL,
1860 NULL,
1861 NULL,
1862 NULL,
1863 NULL,
1864 NULL,
1865 NULL,
1866 NULL,
1867 PDM_DRVHLPR3_VERSION /* u32TheEnd */
1868};
1869
1870/** @} */
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