VirtualBox

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

Last change on this file since 92516 was 91955, checked in by vboxsync, 3 years ago

VMM,Devices: Eliminate direct calls to PDMR3AsyncCompletion* and PDMR3BlkCache* and use the device helper callbacks, bugref:10074 [build fix]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 86.7 KB
Line 
1/* $Id: PDMDriver.cpp 91955 2021-10-21 14:26:20Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device and Driver Manager, Driver parts.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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/vmcc.h>
31
32#include <VBox/version.h>
33#include <VBox/err.h>
34
35#include <VBox/log.h>
36#include <iprt/assert.h>
37#include <iprt/asm.h>
38#include <iprt/ctype.h>
39#include <iprt/mem.h>
40#include <iprt/thread.h>
41#include <iprt/path.h>
42#include <iprt/string.h>
43
44
45/*********************************************************************************************************************************
46* Structures and Typedefs *
47*********************************************************************************************************************************/
48/**
49 * Internal callback structure pointer.
50 *
51 * The main purpose is to define the extra data we associate
52 * with PDMDRVREGCB so we can find the VM instance and so on.
53 */
54typedef struct PDMDRVREGCBINT
55{
56 /** The callback structure. */
57 PDMDRVREGCB Core;
58 /** A bit of padding. */
59 uint32_t u32[4];
60 /** VM Handle. */
61 PVM pVM;
62 /** Pointer to the configuration node the registrations should be
63 * associated with. Can be NULL. */
64 PCFGMNODE pCfgNode;
65} PDMDRVREGCBINT, *PPDMDRVREGCBINT;
66typedef const PDMDRVREGCBINT *PCPDMDRVREGCBINT;
67
68
69/*********************************************************************************************************************************
70* Internal Functions *
71*********************************************************************************************************************************/
72static DECLCALLBACK(int) pdmR3DrvRegister(PCPDMDRVREGCB pCallbacks, PCPDMDRVREG pReg);
73static int pdmR3DrvLoad(PVM pVM, PPDMDRVREGCBINT pRegCB, const char *pszFilename, const char *pszName);
74
75
76/**
77 * Register drivers in a statically linked environment.
78 *
79 * @returns VBox status code.
80 * @param pVM The cross context VM structure.
81 * @param pfnCallback Driver registration callback
82 */
83VMMR3DECL(int) PDMR3DrvStaticRegistration(PVM pVM, FNPDMVBOXDRIVERSREGISTER pfnCallback)
84{
85 /*
86 * The registration callbacks.
87 */
88 PDMDRVREGCBINT RegCB;
89 RegCB.Core.u32Version = PDM_DRVREG_CB_VERSION;
90 RegCB.Core.pfnRegister = pdmR3DrvRegister;
91 RegCB.pVM = pVM;
92 RegCB.pCfgNode = NULL;
93
94 int rc = pfnCallback(&RegCB.Core, VBOX_VERSION);
95 if (RT_FAILURE(rc))
96 AssertMsgFailed(("VBoxDriversRegister failed with rc=%Rrc\n", rc));
97
98 return rc;
99}
100
101
102/**
103 * This function will initialize the drivers for this VM instance.
104 *
105 * First of all this mean loading the builtin drivers and letting them
106 * register themselves. Beyond that any additional driver modules are
107 * loaded and called for registration.
108 *
109 * @returns VBox status code.
110 * @param pVM The cross context VM structure.
111 */
112int pdmR3DrvInit(PVM pVM)
113{
114 LogFlow(("pdmR3DrvInit:\n"));
115
116 AssertRelease(!(RT_UOFFSETOF(PDMDRVINS, achInstanceData) & 15));
117 PPDMDRVINS pDrvInsAssert; NOREF(pDrvInsAssert);
118 AssertCompile(sizeof(pDrvInsAssert->Internal.s) <= sizeof(pDrvInsAssert->Internal.padding));
119 AssertRelease(sizeof(pDrvInsAssert->Internal.s) <= sizeof(pDrvInsAssert->Internal.padding));
120
121 /*
122 * The registration callbacks.
123 */
124 PDMDRVREGCBINT RegCB;
125 RegCB.Core.u32Version = PDM_DRVREG_CB_VERSION;
126 RegCB.Core.pfnRegister = pdmR3DrvRegister;
127 RegCB.pVM = pVM;
128 RegCB.pCfgNode = NULL;
129
130 /*
131 * Load the builtin module
132 */
133 PCFGMNODE pDriversNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "PDM/Drivers");
134 bool fLoadBuiltin;
135 int rc = CFGMR3QueryBool(pDriversNode, "LoadBuiltin", &fLoadBuiltin);
136 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
137 fLoadBuiltin = true;
138 else if (RT_FAILURE(rc))
139 {
140 AssertMsgFailed(("Configuration error: Querying boolean \"LoadBuiltin\" failed with %Rrc\n", rc));
141 return rc;
142 }
143 if (fLoadBuiltin)
144 {
145 /* make filename */
146 char *pszFilename = pdmR3FileR3("VBoxDD", true /*fShared*/);
147 if (!pszFilename)
148 return VERR_NO_TMP_MEMORY;
149 rc = pdmR3DrvLoad(pVM, &RegCB, pszFilename, "VBoxDD");
150 RTMemTmpFree(pszFilename);
151 if (RT_FAILURE(rc))
152 return rc;
153 }
154
155 /*
156 * Load additional driver modules.
157 */
158 for (PCFGMNODE pCur = CFGMR3GetFirstChild(pDriversNode); pCur; pCur = CFGMR3GetNextChild(pCur))
159 {
160 /*
161 * Get the name and path.
162 */
163 char szName[PDMMOD_NAME_LEN];
164 rc = CFGMR3GetName(pCur, &szName[0], sizeof(szName));
165 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
166 {
167 AssertMsgFailed(("configuration error: The module name is too long, cchName=%zu.\n", CFGMR3GetNameLen(pCur)));
168 return VERR_PDM_MODULE_NAME_TOO_LONG;
169 }
170 else if (RT_FAILURE(rc))
171 {
172 AssertMsgFailed(("CFGMR3GetName -> %Rrc.\n", rc));
173 return rc;
174 }
175
176 /* the path is optional, if no path the module name + path is used. */
177 char szFilename[RTPATH_MAX];
178 rc = CFGMR3QueryString(pCur, "Path", &szFilename[0], sizeof(szFilename));
179 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
180 strcpy(szFilename, szName);
181 else if (RT_FAILURE(rc))
182 {
183 AssertMsgFailed(("configuration error: Failure to query the module path, rc=%Rrc.\n", rc));
184 return rc;
185 }
186
187 /* prepend path? */
188 if (!RTPathHavePath(szFilename))
189 {
190 char *psz = pdmR3FileR3(szFilename, false /*fShared*/);
191 if (!psz)
192 return VERR_NO_TMP_MEMORY;
193 size_t cch = strlen(psz) + 1;
194 if (cch > sizeof(szFilename))
195 {
196 RTMemTmpFree(psz);
197 AssertMsgFailed(("Filename too long! cch=%d '%s'\n", cch, psz));
198 return VERR_FILENAME_TOO_LONG;
199 }
200 memcpy(szFilename, psz, cch);
201 RTMemTmpFree(psz);
202 }
203
204 /*
205 * Load the module and register it's drivers.
206 */
207 RegCB.pCfgNode = pCur;
208 rc = pdmR3DrvLoad(pVM, &RegCB, szFilename, szName);
209 if (RT_FAILURE(rc))
210 return rc;
211 }
212
213 LogFlow(("pdmR3DrvInit: returns VINF_SUCCESS\n"));
214 return VINF_SUCCESS;
215}
216
217
218/**
219 * Loads one driver module and call the registration entry point.
220 *
221 * @returns VBox status code.
222 * @param pVM The cross context VM structure.
223 * @param pRegCB The registration callback stuff.
224 * @param pszFilename Module filename.
225 * @param pszName Module name.
226 */
227static int pdmR3DrvLoad(PVM pVM, PPDMDRVREGCBINT pRegCB, const char *pszFilename, const char *pszName)
228{
229 /*
230 * Load it.
231 */
232 int rc = pdmR3LoadR3U(pVM->pUVM, pszFilename, pszName);
233 if (RT_SUCCESS(rc))
234 {
235 /*
236 * Get the registration export and call it.
237 */
238 FNPDMVBOXDRIVERSREGISTER *pfnVBoxDriversRegister;
239 rc = PDMR3LdrGetSymbolR3(pVM, pszName, "VBoxDriversRegister", (void **)&pfnVBoxDriversRegister);
240 if (RT_SUCCESS(rc))
241 {
242 Log(("PDM: Calling VBoxDriversRegister (%p) of %s (%s)\n", pfnVBoxDriversRegister, pszName, pszFilename));
243 rc = pfnVBoxDriversRegister(&pRegCB->Core, VBOX_VERSION);
244 if (RT_SUCCESS(rc))
245 Log(("PDM: Successfully loaded driver module %s (%s).\n", pszName, pszFilename));
246 else
247 AssertMsgFailed(("VBoxDriversRegister failed with rc=%Rrc\n", rc));
248 }
249 else
250 {
251 AssertMsgFailed(("Failed to locate 'VBoxDriversRegister' in %s (%s) rc=%Rrc\n", pszName, pszFilename, rc));
252 if (rc == VERR_SYMBOL_NOT_FOUND)
253 rc = VERR_PDM_NO_REGISTRATION_EXPORT;
254 }
255 }
256 else
257 AssertMsgFailed(("Failed to load %s (%s) rc=%Rrc!\n", pszName, pszFilename, rc));
258 return rc;
259}
260
261
262/** @interface_method_impl{PDMDRVREGCB,pfnRegister} */
263static DECLCALLBACK(int) pdmR3DrvRegister(PCPDMDRVREGCB pCallbacks, PCPDMDRVREG pReg)
264{
265 /*
266 * Validate the registration structure.
267 */
268 AssertPtrReturn(pReg, VERR_INVALID_POINTER);
269 AssertMsgReturn(pReg->u32Version == PDM_DRVREG_VERSION,
270 ("%#x\n", pReg->u32Version),
271 VERR_PDM_UNKNOWN_DRVREG_VERSION);
272 AssertReturn(pReg->szName[0], VERR_PDM_INVALID_DRIVER_REGISTRATION);
273 AssertMsgReturn(RTStrEnd(pReg->szName, sizeof(pReg->szName)),
274 ("%.*s\n", sizeof(pReg->szName), pReg->szName),
275 VERR_PDM_INVALID_DRIVER_REGISTRATION);
276 AssertMsgReturn(pdmR3IsValidName(pReg->szName), ("%.*s\n", sizeof(pReg->szName), pReg->szName),
277 VERR_PDM_INVALID_DRIVER_REGISTRATION);
278 AssertMsgReturn( !(pReg->fFlags & PDM_DRVREG_FLAGS_R0)
279 || ( pReg->szR0Mod[0]
280 && RTStrEnd(pReg->szR0Mod, sizeof(pReg->szR0Mod))),
281 ("%s: %.*s\n", pReg->szName, sizeof(pReg->szR0Mod), pReg->szR0Mod),
282 VERR_PDM_INVALID_DRIVER_REGISTRATION);
283 AssertMsgReturn( !(pReg->fFlags & PDM_DRVREG_FLAGS_RC)
284 || ( pReg->szRCMod[0]
285 && RTStrEnd(pReg->szRCMod, sizeof(pReg->szRCMod))),
286 ("%s: %.*s\n", pReg->szName, sizeof(pReg->szRCMod), pReg->szRCMod),
287 VERR_PDM_INVALID_DRIVER_REGISTRATION);
288 AssertMsgReturn(RT_VALID_PTR(pReg->pszDescription),
289 ("%s: %p\n", pReg->szName, pReg->pszDescription),
290 VERR_PDM_INVALID_DRIVER_REGISTRATION);
291 AssertMsgReturn(!(pReg->fFlags & ~(PDM_DRVREG_FLAGS_HOST_BITS_MASK | PDM_DRVREG_FLAGS_R0 | PDM_DRVREG_FLAGS_RC)),
292 ("%s: %#x\n", pReg->szName, pReg->fFlags),
293 VERR_PDM_INVALID_DRIVER_REGISTRATION);
294 AssertMsgReturn((pReg->fFlags & PDM_DRVREG_FLAGS_HOST_BITS_MASK) == PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
295 ("%s: %#x\n", pReg->szName, pReg->fFlags),
296 VERR_PDM_INVALID_DRIVER_HOST_BITS);
297 AssertMsgReturn(pReg->cMaxInstances > 0,
298 ("%s: %#x\n", pReg->szName, pReg->cMaxInstances),
299 VERR_PDM_INVALID_DRIVER_REGISTRATION);
300 AssertMsgReturn(pReg->cbInstance <= _1M,
301 ("%s: %#x\n", pReg->szName, pReg->cbInstance),
302 VERR_PDM_INVALID_DRIVER_REGISTRATION);
303 AssertMsgReturn(RT_VALID_PTR(pReg->pfnConstruct),
304 ("%s: %p\n", pReg->szName, pReg->pfnConstruct),
305 VERR_PDM_INVALID_DRIVER_REGISTRATION);
306 AssertMsgReturn(RT_VALID_PTR(pReg->pfnRelocate) || !(pReg->fFlags & PDM_DRVREG_FLAGS_RC),
307 ("%s: %#x\n", pReg->szName, pReg->cbInstance),
308 VERR_PDM_INVALID_DRIVER_REGISTRATION);
309 AssertMsgReturn(pReg->pfnSoftReset == NULL,
310 ("%s: %p\n", pReg->szName, pReg->pfnSoftReset),
311 VERR_PDM_INVALID_DRIVER_REGISTRATION);
312 AssertMsgReturn(pReg->u32VersionEnd == PDM_DRVREG_VERSION,
313 ("%s: %#x\n", pReg->szName, pReg->u32VersionEnd),
314 VERR_PDM_INVALID_DRIVER_REGISTRATION);
315
316 /*
317 * Check for duplicate and find FIFO entry at the same time.
318 */
319 PCPDMDRVREGCBINT pRegCB = (PCPDMDRVREGCBINT)pCallbacks;
320 PPDMDRV pDrvPrev = NULL;
321 PPDMDRV pDrv = pRegCB->pVM->pdm.s.pDrvs;
322 for (; pDrv; pDrvPrev = pDrv, pDrv = pDrv->pNext)
323 {
324 if (!strcmp(pDrv->pReg->szName, pReg->szName))
325 {
326 AssertMsgFailed(("Driver '%s' already exists\n", pReg->szName));
327 return VERR_PDM_DRIVER_NAME_CLASH;
328 }
329 }
330
331 /*
332 * Allocate new driver structure and insert it into the list.
333 */
334 int rc;
335 pDrv = (PPDMDRV)MMR3HeapAlloc(pRegCB->pVM, MM_TAG_PDM_DRIVER, sizeof(*pDrv));
336 if (pDrv)
337 {
338 pDrv->pNext = NULL;
339 pDrv->cInstances = 0;
340 pDrv->iNextInstance = 0;
341 pDrv->pReg = pReg;
342 rc = CFGMR3QueryStringAllocDef( pRegCB->pCfgNode, "RCSearchPath", &pDrv->pszRCSearchPath, NULL);
343 if (RT_SUCCESS(rc))
344 rc = CFGMR3QueryStringAllocDef(pRegCB->pCfgNode, "R0SearchPath", &pDrv->pszR0SearchPath, NULL);
345 if (RT_SUCCESS(rc))
346 {
347 if (pDrvPrev)
348 pDrvPrev->pNext = pDrv;
349 else
350 pRegCB->pVM->pdm.s.pDrvs = pDrv;
351 Log(("PDM: Registered driver '%s'\n", pReg->szName));
352 return VINF_SUCCESS;
353 }
354 MMR3HeapFree(pDrv);
355 }
356 else
357 rc = VERR_NO_MEMORY;
358 return rc;
359}
360
361
362/**
363 * Lookups a driver structure by name.
364 * @internal
365 */
366PPDMDRV pdmR3DrvLookup(PVM pVM, const char *pszName)
367{
368 for (PPDMDRV pDrv = pVM->pdm.s.pDrvs; pDrv; pDrv = pDrv->pNext)
369 if (!strcmp(pDrv->pReg->szName, pszName))
370 return pDrv;
371 return NULL;
372}
373
374
375/**
376 * Transforms the driver chain as it's being instantiated.
377 *
378 * Worker for pdmR3DrvInstantiate.
379 *
380 * @returns VBox status code.
381 * @param pVM The cross context VM structure.
382 * @param pDrvAbove The driver above, NULL if top.
383 * @param pLun The LUN.
384 * @param ppNode The AttachedDriver node, replaced if any
385 * morphing took place.
386 */
387static int pdmR3DrvMaybeTransformChain(PVM pVM, PPDMDRVINS pDrvAbove, PPDMLUN pLun, PCFGMNODE *ppNode)
388{
389 /*
390 * The typical state of affairs is that there are no injections.
391 */
392 PCFGMNODE pCurTrans = CFGMR3GetFirstChild(CFGMR3GetChild(CFGMR3GetRoot(pVM), "PDM/DriverTransformations"));
393 if (!pCurTrans)
394 return VINF_SUCCESS;
395
396 /*
397 * Gather the attributes used in the matching process.
398 */
399 const char *pszDevice = pLun->pDevIns
400 ? pLun->pDevIns->Internal.s.pDevR3->pReg->szName
401 : pLun->pUsbIns->Internal.s.pUsbDev->pReg->szName;
402 char szLun[32];
403 RTStrPrintf(szLun, sizeof(szLun), "%u", pLun->iLun);
404 const char *pszAbove = pDrvAbove ? pDrvAbove->Internal.s.pDrv->pReg->szName : "<top>";
405 char *pszThisDrv;
406 int rc = CFGMR3QueryStringAlloc(*ppNode, "Driver", &pszThisDrv);
407 AssertMsgRCReturn(rc, ("Query for string value of \"Driver\" -> %Rrc\n", rc),
408 rc == VERR_CFGM_VALUE_NOT_FOUND ? VERR_PDM_CFG_MISSING_DRIVER_NAME : rc);
409
410 uint64_t uInjectTransformationAbove = 0;
411 if (pDrvAbove)
412 {
413 rc = CFGMR3QueryIntegerDef(CFGMR3GetParent(*ppNode), "InjectTransformationPtr", &uInjectTransformationAbove, 0);
414 AssertLogRelRCReturn(rc, rc);
415 }
416
417
418 /*
419 * Enumerate possible driver chain transformations.
420 */
421 unsigned cTransformations = 0;
422 for (; pCurTrans != NULL; pCurTrans = CFGMR3GetNextChild(pCurTrans))
423 {
424 char szCurTransNm[256];
425 rc = CFGMR3GetName(pCurTrans, szCurTransNm, sizeof(szCurTransNm));
426 AssertLogRelRCReturn(rc, rc);
427
428 /** @cfgm{/PDM/DriverTransformations/&lt;name&gt;/Device,string,*}
429 * One or more simple wildcard patters separated by '|' for matching
430 * the devices this transformation rule applies to. */
431 char *pszMultiPat;
432 rc = CFGMR3QueryStringAllocDef(pCurTrans, "Device", &pszMultiPat, "*");
433 AssertLogRelRCReturn(rc, rc);
434 bool fMatch = RTStrSimplePatternMultiMatch(pszMultiPat, RTSTR_MAX, pszDevice, RTSTR_MAX, NULL);
435 MMR3HeapFree(pszMultiPat);
436 if (!fMatch)
437 continue;
438
439 /** @cfgm{/PDM/DriverTransformations/&lt;name&gt;/LUN,string,*}
440 * One or more simple wildcard patters separated by '|' for matching
441 * the LUNs this transformation rule applies to. */
442 rc = CFGMR3QueryStringAllocDef(pCurTrans, "LUN", &pszMultiPat, "*");
443 AssertLogRelRCReturn(rc, rc);
444 fMatch = RTStrSimplePatternMultiMatch(pszMultiPat, RTSTR_MAX, szLun, RTSTR_MAX, NULL);
445 MMR3HeapFree(pszMultiPat);
446 if (!fMatch)
447 continue;
448
449 /** @cfgm{/PDM/DriverTransformations/&lt;name&gt;/BelowDriver,string,*}
450 * One or more simple wildcard patters separated by '|' for matching the
451 * drivers the transformation should be applied below. This means, that
452 * when the drivers matched here attached another driver below them, the
453 * transformation will be applied. To represent the device, '&lt;top&gt;'
454 * is used. */
455 rc = CFGMR3QueryStringAllocDef(pCurTrans, "BelowDriver", &pszMultiPat, "*");
456 AssertLogRelRCReturn(rc, rc);
457 fMatch = RTStrSimplePatternMultiMatch(pszMultiPat, RTSTR_MAX, pszAbove, RTSTR_MAX, NULL);
458 MMR3HeapFree(pszMultiPat);
459 if (!fMatch)
460 continue;
461
462 /** @cfgm{/PDM/DriverTransformations/&lt;name&gt;/AboveDriver,string,*}
463 * One or more simple wildcard patters separated by '|' for matching the
464 * drivers the transformation should be applie above or at (depending on
465 * the action). The value being matched against here is the driver that
466 * is in the process of being attached, so for mergeconfig actions this is
467 * usually what you need to match on. */
468 rc = CFGMR3QueryStringAlloc(pCurTrans, "AboveDriver", &pszMultiPat);
469 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
470 rc = VINF_SUCCESS;
471 else
472 {
473 AssertLogRelRCReturn(rc, rc);
474 fMatch = RTStrSimplePatternMultiMatch(pszMultiPat, RTSTR_MAX, pszThisDrv, RTSTR_MAX, NULL);
475 MMR3HeapFree(pszMultiPat);
476 if (!fMatch)
477 continue;
478 if (uInjectTransformationAbove == (uintptr_t)pCurTrans)
479 continue;
480 }
481
482 /*
483 * We've got a match! Now, what are we supposed to do?
484 */
485 /** @cfgm{/PDM/DriverTransformations/&lt;name&gt;/Action,string,inject}
486 * The action that the transformation takes. Possible values are:
487 * - inject
488 * - mergeconfig: This merges and the content of the 'Config' key under the
489 * transformation into the driver's own 'Config' key, replacing any
490 * duplicates.
491 * - remove
492 * - removetree
493 * - replace
494 * - replacetree
495 */
496 char szAction[16];
497 rc = CFGMR3QueryStringDef(pCurTrans, "Action", szAction, sizeof(szAction), "inject");
498 AssertLogRelRCReturn(rc, rc);
499 AssertLogRelMsgReturn( !strcmp(szAction, "inject")
500 || !strcmp(szAction, "mergeconfig")
501 || !strcmp(szAction, "remove")
502 || !strcmp(szAction, "removetree")
503 || !strcmp(szAction, "replace")
504 || !strcmp(szAction, "replacetree")
505 ,
506 ("Action='%s', valid values are 'inject', 'mergeconfig', 'replace', 'replacetree', 'remove', 'removetree'.\n", szAction),
507 VERR_PDM_MISCONFIGURED_DRV_TRANSFORMATION);
508 LogRel(("PDMDriver: Applying '%s' to '%s'::[%s]...'%s': %s\n", szCurTransNm, pszDevice, szLun, pszThisDrv, szAction));
509 CFGMR3Dump(*ppNode);
510 CFGMR3Dump(pCurTrans);
511
512 /* Get the attached driver to inject. */
513 PCFGMNODE pTransAttDrv = NULL;
514 if (!strcmp(szAction, "inject") || !strcmp(szAction, "replace") || !strcmp(szAction, "replacetree"))
515 {
516 pTransAttDrv = CFGMR3GetChild(pCurTrans, "AttachedDriver");
517 AssertLogRelMsgReturn(pTransAttDrv,
518 ("An %s transformation requires an AttachedDriver child node!\n", szAction),
519 VERR_PDM_MISCONFIGURED_DRV_TRANSFORMATION);
520 }
521
522
523 /*
524 * Remove the node.
525 */
526 if (!strcmp(szAction, "remove") || !strcmp(szAction, "removetree"))
527 {
528 PCFGMNODE pBelowThis = CFGMR3GetChild(*ppNode, "AttachedDriver");
529 if (!pBelowThis || !strcmp(szAction, "removetree"))
530 {
531 CFGMR3RemoveNode(*ppNode);
532 *ppNode = NULL;
533 }
534 else
535 {
536 PCFGMNODE pBelowThisCopy;
537 rc = CFGMR3DuplicateSubTree(pBelowThis, &pBelowThisCopy);
538 AssertLogRelRCReturn(rc, rc);
539
540 rc = CFGMR3ReplaceSubTree(*ppNode, pBelowThisCopy);
541 AssertLogRelRCReturnStmt(rc, CFGMR3RemoveNode(pBelowThis), rc);
542 }
543 }
544 /*
545 * Replace the driver about to be instantiated.
546 */
547 else if (!strcmp(szAction, "replace") || !strcmp(szAction, "replacetree"))
548 {
549 PCFGMNODE pTransCopy;
550 rc = CFGMR3DuplicateSubTree(pTransAttDrv, &pTransCopy);
551 AssertLogRelRCReturn(rc, rc);
552
553 PCFGMNODE pBelowThis = CFGMR3GetChild(*ppNode, "AttachedDriver");
554 if (!pBelowThis || !strcmp(szAction, "replacetree"))
555 rc = VINF_SUCCESS;
556 else
557 {
558 PCFGMNODE pBelowThisCopy;
559 rc = CFGMR3DuplicateSubTree(pBelowThis, &pBelowThisCopy);
560 if (RT_SUCCESS(rc))
561 {
562 rc = CFGMR3InsertSubTree(pTransCopy, "AttachedDriver", pBelowThisCopy, NULL);
563 AssertLogRelRC(rc);
564 if (RT_FAILURE(rc))
565 CFGMR3RemoveNode(pBelowThisCopy);
566 }
567 }
568 if (RT_SUCCESS(rc))
569 rc = CFGMR3ReplaceSubTree(*ppNode, pTransCopy);
570 if (RT_FAILURE(rc))
571 CFGMR3RemoveNode(pTransCopy);
572 }
573 /*
574 * Inject a driver before the driver about to be instantiated.
575 */
576 else if (!strcmp(szAction, "inject"))
577 {
578 PCFGMNODE pTransCopy;
579 rc = CFGMR3DuplicateSubTree(pTransAttDrv, &pTransCopy);
580 AssertLogRelRCReturn(rc, rc);
581
582 PCFGMNODE pThisCopy;
583 rc = CFGMR3DuplicateSubTree(*ppNode, &pThisCopy);
584 if (RT_SUCCESS(rc))
585 {
586 rc = CFGMR3InsertSubTree(pTransCopy, "AttachedDriver", pThisCopy, NULL);
587 if (RT_SUCCESS(rc))
588 {
589 rc = CFGMR3InsertInteger(pTransCopy, "InjectTransformationPtr", (uintptr_t)pCurTrans);
590 AssertLogRelRC(rc);
591 rc = CFGMR3InsertString(pTransCopy, "InjectTransformationNm", szCurTransNm);
592 AssertLogRelRC(rc);
593 if (RT_SUCCESS(rc))
594 rc = CFGMR3ReplaceSubTree(*ppNode, pTransCopy);
595 }
596 else
597 {
598 AssertLogRelRC(rc);
599 CFGMR3RemoveNode(pThisCopy);
600 }
601 }
602 if (RT_FAILURE(rc))
603 CFGMR3RemoveNode(pTransCopy);
604 }
605 /*
606 * Merge the Config node of the transformation with the one of the
607 * current driver.
608 */
609 else if (!strcmp(szAction, "mergeconfig"))
610 {
611 PCFGMNODE pTransConfig = CFGMR3GetChild(pCurTrans, "Config");
612 AssertLogRelReturn(pTransConfig, VERR_PDM_MISCONFIGURED_DRV_TRANSFORMATION);
613
614 PCFGMNODE pDrvConfig = CFGMR3GetChild(*ppNode, "Config");
615 if (*ppNode)
616 CFGMR3InsertNode(*ppNode, "Config", &pDrvConfig);
617 AssertLogRelReturn(pDrvConfig, VERR_PDM_CANNOT_TRANSFORM_REMOVED_DRIVER);
618
619 rc = CFGMR3CopyTree(pDrvConfig, pTransConfig, CFGM_COPY_FLAGS_REPLACE_VALUES | CFGM_COPY_FLAGS_MERGE_KEYS);
620 AssertLogRelRCReturn(rc, rc);
621 }
622 else
623 AssertFailed();
624
625 cTransformations++;
626 if (*ppNode)
627 CFGMR3Dump(*ppNode);
628 else
629 LogRel(("PDMDriver: The transformation removed the driver.\n"));
630 }
631
632 /*
633 * Note what happened in the release log.
634 */
635 if (cTransformations > 0)
636 LogRel(("PDMDriver: Transformations done. Applied %u driver transformations.\n", cTransformations));
637
638 return rc;
639}
640
641
642/**
643 * Instantiate a driver.
644 *
645 * @returns VBox status code, including informational statuses.
646 *
647 * @param pVM The cross context VM structure.
648 * @param pNode The CFGM node for the driver.
649 * @param pBaseInterface The base interface.
650 * @param pDrvAbove The driver above it. NULL if it's the top-most
651 * driver.
652 * @param pLun The LUN the driver is being attached to. NULL
653 * if we're instantiating a driver chain before
654 * attaching it - untested.
655 * @param ppBaseInterface Where to return the pointer to the base
656 * interface of the newly created driver.
657 *
658 * @remarks Recursive calls to this function is normal as the drivers will
659 * attach to anything below them during the pfnContruct call.
660 *
661 * @todo Need to extend this interface a bit so that the driver
662 * transformation feature can attach drivers to unconfigured LUNs and
663 * at the end of chains.
664 */
665int pdmR3DrvInstantiate(PVM pVM, PCFGMNODE pNode, PPDMIBASE pBaseInterface, PPDMDRVINS pDrvAbove,
666 PPDMLUN pLun, PPDMIBASE *ppBaseInterface)
667{
668 Assert(!pDrvAbove || !pDrvAbove->Internal.s.pDown);
669 Assert(!pDrvAbove || !pDrvAbove->pDownBase);
670
671 Assert(pBaseInterface->pfnQueryInterface(pBaseInterface, PDMIBASE_IID) == pBaseInterface);
672
673 /*
674 * Do driver chain injections
675 */
676 int rc = pdmR3DrvMaybeTransformChain(pVM, pDrvAbove, pLun, &pNode);
677 if (RT_FAILURE(rc))
678 return rc;
679 if (!pNode)
680 return VERR_PDM_NO_ATTACHED_DRIVER;
681
682 /*
683 * Find the driver.
684 */
685 char *pszName;
686 rc = CFGMR3QueryStringAlloc(pNode, "Driver", &pszName);
687 if (RT_SUCCESS(rc))
688 {
689 PPDMDRV pDrv = pdmR3DrvLookup(pVM, pszName);
690 if ( pDrv
691 && pDrv->cInstances < pDrv->pReg->cMaxInstances)
692 {
693 /* config node */
694 PCFGMNODE pConfigNode = CFGMR3GetChild(pNode, "Config");
695 if (!pConfigNode)
696 rc = CFGMR3InsertNode(pNode, "Config", &pConfigNode);
697 if (RT_SUCCESS(rc))
698 {
699 CFGMR3SetRestrictedRoot(pConfigNode);
700
701 /*
702 * Allocate the driver instance.
703 */
704 size_t cb = RT_UOFFSETOF_DYN(PDMDRVINS, achInstanceData[pDrv->pReg->cbInstance]);
705 cb = RT_ALIGN_Z(cb, 16);
706 bool const fHyperHeap = !!(pDrv->pReg->fFlags & (PDM_DRVREG_FLAGS_R0 | PDM_DRVREG_FLAGS_RC));
707 PPDMDRVINS pNew;
708 if (fHyperHeap)
709 rc = MMHyperAlloc(pVM, cb, 64, MM_TAG_PDM_DRIVER, (void **)&pNew);
710 else
711 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_DRIVER, cb, (void **)&pNew);
712 if (RT_SUCCESS(rc))
713 {
714 /*
715 * Initialize the instance structure (declaration order).
716 */
717 pNew->u32Version = PDM_DRVINS_VERSION;
718 pNew->iInstance = pDrv->iNextInstance;
719 pNew->Internal.s.pUp = pDrvAbove ? pDrvAbove : NULL;
720 //pNew->Internal.s.pDown = NULL;
721 pNew->Internal.s.pLun = pLun;
722 pNew->Internal.s.pDrv = pDrv;
723 pNew->Internal.s.pVMR3 = pVM;
724 pNew->Internal.s.pVMR0 = pDrv->pReg->fFlags & PDM_DRVREG_FLAGS_R0 ? pVM->pVMR0ForCall : NIL_RTR0PTR;
725 pNew->Internal.s.pVMRC = pDrv->pReg->fFlags & PDM_DRVREG_FLAGS_RC ? pVM->pVMRC : NIL_RTRCPTR;
726 //pNew->Internal.s.fDetaching = false;
727 pNew->Internal.s.fVMSuspended = true; /** @todo should be 'false', if driver is attached at runtime. */
728 //pNew->Internal.s.fVMReset = false;
729 pNew->Internal.s.fHyperHeap = fHyperHeap;
730 //pNew->Internal.s.pfnAsyncNotify = NULL;
731 pNew->Internal.s.pCfgHandle = pNode;
732 pNew->pReg = pDrv->pReg;
733 pNew->pCfg = pConfigNode;
734 pNew->pUpBase = pBaseInterface;
735 Assert(!pDrvAbove || pBaseInterface == &pDrvAbove->IBase);
736 //pNew->pDownBase = NULL;
737 //pNew->IBase.pfnQueryInterface = NULL;
738 //pNew->fTracing = 0;
739 pNew->idTracing = ++pVM->pdm.s.idTracingOther;
740 pNew->pHlpR3 = &g_pdmR3DrvHlp;
741 pNew->pvInstanceDataR3 = &pNew->achInstanceData[0];
742 if (pDrv->pReg->fFlags & PDM_DRVREG_FLAGS_R0)
743 {
744 pNew->pvInstanceDataR0 = MMHyperR3ToR0(pVM, &pNew->achInstanceData[0]);
745 rc = PDMR3LdrGetSymbolR0(pVM, NULL, "g_pdmR0DrvHlp", &pNew->pHlpR0);
746 AssertReleaseRCReturn(rc, rc);
747 }
748#ifdef VBOX_WITH_RAW_MODE_KEEP
749 if ( (pDrv->pReg->fFlags & PDM_DRVREG_FLAGS_RC)
750 && VM_IS_RAW_MODE_ENABLED(pVM))
751 {
752 pNew->pvInstanceDataR0 = MMHyperR3ToRC(pVM, &pNew->achInstanceData[0]);
753 rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDrvHlp", &pNew->pHlpRC);
754 AssertReleaseRCReturn(rc, rc);
755 }
756#endif
757
758 pDrv->iNextInstance++;
759 pDrv->cInstances++;
760
761 /*
762 * Link with it with the driver above / LUN.
763 */
764 if (pDrvAbove)
765 {
766 pDrvAbove->pDownBase = &pNew->IBase;
767 pDrvAbove->Internal.s.pDown = pNew;
768 }
769 else if (pLun)
770 pLun->pTop = pNew;
771 if (pLun)
772 pLun->pBottom = pNew;
773
774 /*
775 * Invoke the constructor.
776 */
777 rc = pDrv->pReg->pfnConstruct(pNew, pNew->pCfg, 0 /*fFlags*/);
778 if (RT_SUCCESS(rc))
779 {
780 AssertPtr(pNew->IBase.pfnQueryInterface);
781 Assert(pNew->IBase.pfnQueryInterface(&pNew->IBase, PDMIBASE_IID) == &pNew->IBase);
782
783 /* Success! */
784 *ppBaseInterface = &pNew->IBase;
785 if (pLun)
786 Log(("PDM: Attached driver %p:'%s'/%d to LUN#%d on device '%s'/%d, pDrvAbove=%p:'%s'/%d\n",
787 pNew, pDrv->pReg->szName, pNew->iInstance,
788 pLun->iLun,
789 pLun->pDevIns ? pLun->pDevIns->pReg->szName : pLun->pUsbIns->pReg->szName,
790 pLun->pDevIns ? pLun->pDevIns->iInstance : pLun->pUsbIns->iInstance,
791 pDrvAbove, pDrvAbove ? pDrvAbove->pReg->szName : "", pDrvAbove ? pDrvAbove->iInstance : UINT32_MAX));
792 else
793 Log(("PDM: Attached driver %p:'%s'/%d, pDrvAbove=%p:'%s'/%d\n",
794 pNew, pDrv->pReg->szName, pNew->iInstance,
795 pDrvAbove, pDrvAbove ? pDrvAbove->pReg->szName : "", pDrvAbove ? pDrvAbove->iInstance : UINT32_MAX));
796 }
797 else
798 {
799 pdmR3DrvDestroyChain(pNew, PDM_TACH_FLAGS_NO_CALLBACKS);
800 if (rc == VERR_VERSION_MISMATCH)
801 rc = VERR_PDM_DRIVER_VERSION_MISMATCH;
802 }
803 }
804 else
805 AssertMsgFailed(("Failed to allocate %d bytes for instantiating driver '%s'! rc=%Rrc\n", cb, pszName, rc));
806 }
807 else
808 AssertMsgFailed(("Failed to create Config node! rc=%Rrc\n", rc));
809 }
810 else if (pDrv)
811 {
812 AssertMsgFailed(("Too many instances of driver '%s', max is %u\n", pszName, pDrv->pReg->cMaxInstances));
813 rc = VERR_PDM_TOO_MANY_DRIVER_INSTANCES;
814 }
815 else
816 {
817 AssertMsgFailed(("Driver '%s' wasn't found!\n", pszName));
818 rc = VERR_PDM_DRIVER_NOT_FOUND;
819 }
820 MMR3HeapFree(pszName);
821 }
822 else
823 {
824 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
825 rc = VERR_PDM_CFG_MISSING_DRIVER_NAME;
826 else
827 AssertMsgFailed(("Query for string value of \"Driver\" -> %Rrc\n", rc));
828 }
829 return rc;
830}
831
832
833/**
834 * Detaches a driver from whatever it's attached to.
835 * This will of course lead to the destruction of the driver and all drivers below it in the chain.
836 *
837 * @returns VINF_SUCCESS
838 * @param pDrvIns The driver instance to detach.
839 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
840 */
841int pdmR3DrvDetach(PPDMDRVINS pDrvIns, uint32_t fFlags)
842{
843 PDMDRV_ASSERT_DRVINS(pDrvIns);
844 LogFlow(("pdmR3DrvDetach: pDrvIns=%p '%s'/%d\n", pDrvIns, pDrvIns->pReg->szName, pDrvIns->iInstance));
845 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
846
847 /*
848 * Check that we're not doing this recursively, that could have unwanted sideeffects!
849 */
850 if (pDrvIns->Internal.s.fDetaching)
851 {
852 AssertMsgFailed(("Recursive detach! '%s'/%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
853 return VINF_SUCCESS;
854 }
855
856 /*
857 * Check that we actually can detach this instance.
858 * The requirement is that the driver/device above has a detach method.
859 */
860 if ( pDrvIns->Internal.s.pUp
861 ? !pDrvIns->Internal.s.pUp->pReg->pfnDetach
862 : pDrvIns->Internal.s.pLun->pDevIns
863 ? !pDrvIns->Internal.s.pLun->pDevIns->pReg->pfnDetach
864 : !pDrvIns->Internal.s.pLun->pUsbIns->pReg->pfnDriverDetach
865 )
866 {
867 AssertMsgFailed(("Cannot detach driver instance because the driver/device above doesn't support it!\n"));
868 return VERR_PDM_DRIVER_DETACH_NOT_POSSIBLE;
869 }
870
871 /*
872 * Join paths with pdmR3DrvDestroyChain.
873 */
874 pdmR3DrvDestroyChain(pDrvIns, fFlags);
875 return VINF_SUCCESS;
876}
877
878
879/**
880 * Destroys a driver chain starting with the specified driver.
881 *
882 * This is used when unplugging a device at run time.
883 *
884 * @param pDrvIns Pointer to the driver instance to start with.
885 * @param fFlags PDM_TACH_FLAGS_NOT_HOT_PLUG, PDM_TACH_FLAGS_NO_CALLBACKS
886 * or 0.
887 */
888void pdmR3DrvDestroyChain(PPDMDRVINS pDrvIns, uint32_t fFlags)
889{
890 PVM pVM = pDrvIns->Internal.s.pVMR3;
891 VM_ASSERT_EMT(pVM);
892
893 /*
894 * Detach the bottommost driver until we've detached pDrvIns.
895 */
896 pDrvIns->Internal.s.fDetaching = true;
897 PPDMDRVINS pCur;
898 do
899 {
900 /* find the driver to detach. */
901 pCur = pDrvIns;
902 while (pCur->Internal.s.pDown)
903 pCur = pCur->Internal.s.pDown;
904 LogFlow(("pdmR3DrvDestroyChain: pCur=%p '%s'/%d\n", pCur, pCur->pReg->szName, pCur->iInstance));
905
906 /*
907 * Unlink it and notify parent.
908 */
909 pCur->Internal.s.fDetaching = true;
910
911 PPDMLUN pLun = pCur->Internal.s.pLun;
912 Assert(pLun->pBottom == pCur);
913 pLun->pBottom = pCur->Internal.s.pUp;
914
915 if (pCur->Internal.s.pUp)
916 {
917 /* driver parent */
918 PPDMDRVINS pParent = pCur->Internal.s.pUp;
919 pCur->Internal.s.pUp = NULL;
920 pParent->Internal.s.pDown = NULL;
921
922 if (!(fFlags & PDM_TACH_FLAGS_NO_CALLBACKS) && pParent->pReg->pfnDetach)
923 pParent->pReg->pfnDetach(pParent, fFlags);
924
925 pParent->pDownBase = NULL;
926 }
927 else
928 {
929 /* device parent */
930 Assert(pLun->pTop == pCur);
931 pLun->pTop = NULL;
932 if (!(fFlags & PDM_TACH_FLAGS_NO_CALLBACKS))
933 {
934 if (pLun->pDevIns)
935 {
936 if (pLun->pDevIns->pReg->pfnDetach)
937 {
938 PDMCritSectEnter(pVM, pLun->pDevIns->pCritSectRoR3, VERR_IGNORED);
939 pLun->pDevIns->pReg->pfnDetach(pLun->pDevIns, pLun->iLun, fFlags);
940 PDMCritSectLeave(pVM, pLun->pDevIns->pCritSectRoR3);
941 }
942 }
943 else
944 {
945 if (pLun->pUsbIns->pReg->pfnDriverDetach)
946 {
947 /** @todo USB device locking? */
948 pLun->pUsbIns->pReg->pfnDriverDetach(pLun->pUsbIns, pLun->iLun, fFlags);
949 }
950 }
951 }
952 }
953
954 /*
955 * Call destructor.
956 */
957 pCur->pUpBase = NULL;
958 if (pCur->pReg->pfnDestruct)
959 pCur->pReg->pfnDestruct(pCur);
960 pCur->Internal.s.pDrv->cInstances--;
961
962 /*
963 * Free all resources allocated by the driver.
964 */
965 /* Queues. */
966 int rc = PDMR3QueueDestroyDriver(pVM, pCur);
967 AssertRC(rc);
968
969 /* Timers. */
970 rc = TMR3TimerDestroyDriver(pVM, pCur);
971 AssertRC(rc);
972
973 /* SSM data units. */
974 rc = SSMR3DeregisterDriver(pVM, pCur, NULL, 0);
975 AssertRC(rc);
976
977 /* PDM threads. */
978 rc = pdmR3ThreadDestroyDriver(pVM, pCur);
979 AssertRC(rc);
980
981 /* Info handlers. */
982 rc = DBGFR3InfoDeregisterDriver(pVM, pCur, NULL);
983 AssertRC(rc);
984
985 /* PDM critsects. */
986 rc = pdmR3CritSectBothDeleteDriver(pVM, pCur);
987 AssertRC(rc);
988
989 /* Block caches. */
990 PDMR3BlkCacheReleaseDriver(pVM, pCur);
991
992#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
993 /* Completion templates.*/
994 pdmR3AsyncCompletionTemplateDestroyDriver(pVM, pCur);
995#endif
996
997 /* Finally, the driver it self. */
998 bool fHyperHeap = pCur->Internal.s.fHyperHeap;
999 ASMMemFill32(pCur, RT_UOFFSETOF_DYN(PDMDRVINS, achInstanceData[pCur->pReg->cbInstance]), 0xdeadd0d0);
1000 if (fHyperHeap)
1001 MMHyperFree(pVM, pCur);
1002 else
1003 MMR3HeapFree(pCur);
1004
1005 } while (pCur != pDrvIns);
1006}
1007
1008
1009
1010
1011/** @name Driver Helpers
1012 * @{
1013 */
1014
1015/** @interface_method_impl{PDMDRVHLPR3,pfnAttach} */
1016static DECLCALLBACK(int) pdmR3DrvHlp_Attach(PPDMDRVINS pDrvIns, uint32_t fFlags, PPDMIBASE *ppBaseInterface)
1017{
1018 PDMDRV_ASSERT_DRVINS(pDrvIns);
1019 PVM pVM = pDrvIns->Internal.s.pVMR3;
1020 VM_ASSERT_EMT(pVM);
1021 LogFlow(("pdmR3DrvHlp_Attach: caller='%s'/%d: fFlags=%#x\n", pDrvIns->pReg->szName, pDrvIns->iInstance, fFlags));
1022 Assert(!(fFlags & ~(PDM_TACH_FLAGS_NOT_HOT_PLUG)));
1023 RT_NOREF_PV(fFlags);
1024
1025 /*
1026 * Check that there isn't anything attached already.
1027 */
1028 int rc;
1029 if (!pDrvIns->Internal.s.pDown)
1030 {
1031 Assert(pDrvIns->Internal.s.pLun->pBottom == pDrvIns);
1032
1033 /*
1034 * Get the attached driver configuration.
1035 */
1036 PCFGMNODE pNode = CFGMR3GetChild(pDrvIns->Internal.s.pCfgHandle, "AttachedDriver");
1037 if (pNode)
1038 rc = pdmR3DrvInstantiate(pVM, pNode, &pDrvIns->IBase, pDrvIns, pDrvIns->Internal.s.pLun, ppBaseInterface);
1039 else
1040 rc = VERR_PDM_NO_ATTACHED_DRIVER;
1041 }
1042 else
1043 {
1044 AssertMsgFailed(("Already got a driver attached. The driver should keep track of such things!\n"));
1045 rc = VERR_PDM_DRIVER_ALREADY_ATTACHED;
1046 }
1047
1048 LogFlow(("pdmR3DrvHlp_Attach: caller='%s'/%d: return %Rrc\n",
1049 pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1050 return rc;
1051}
1052
1053
1054/** @interface_method_impl{PDMDRVHLPR3,pfnDetach} */
1055static DECLCALLBACK(int) pdmR3DrvHlp_Detach(PPDMDRVINS pDrvIns, uint32_t fFlags)
1056{
1057 PDMDRV_ASSERT_DRVINS(pDrvIns);
1058 LogFlow(("pdmR3DrvHlp_Detach: caller='%s'/%d: fFlags=%#x\n",
1059 pDrvIns->pReg->szName, pDrvIns->iInstance, fFlags));
1060 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1061
1062 /*
1063 * Anything attached?
1064 */
1065 int rc;
1066 if (pDrvIns->Internal.s.pDown)
1067 rc = pdmR3DrvDetach(pDrvIns->Internal.s.pDown, fFlags);
1068 else
1069 {
1070 AssertMsgFailed(("Nothing attached!\n"));
1071 rc = VERR_PDM_NO_DRIVER_ATTACHED;
1072 }
1073
1074 LogFlow(("pdmR3DrvHlp_Detach: caller='%s'/%d: returns %Rrc\n",
1075 pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1076 return rc;
1077}
1078
1079
1080/** @interface_method_impl{PDMDRVHLPR3,pfnDetachSelf} */
1081static DECLCALLBACK(int) pdmR3DrvHlp_DetachSelf(PPDMDRVINS pDrvIns, uint32_t fFlags)
1082{
1083 PDMDRV_ASSERT_DRVINS(pDrvIns);
1084 LogFlow(("pdmR3DrvHlp_DetachSelf: caller='%s'/%d: fFlags=%#x\n",
1085 pDrvIns->pReg->szName, pDrvIns->iInstance, fFlags));
1086 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1087
1088 int rc = pdmR3DrvDetach(pDrvIns, fFlags);
1089
1090 LogFlow(("pdmR3DrvHlp_Detach: returns %Rrc\n", rc)); /* pDrvIns is freed by now. */
1091 return rc;
1092}
1093
1094
1095/** @interface_method_impl{PDMDRVHLPR3,pfnMountPrepare} */
1096static DECLCALLBACK(int) pdmR3DrvHlp_MountPrepare(PPDMDRVINS pDrvIns, const char *pszFilename, const char *pszCoreDriver)
1097{
1098 PDMDRV_ASSERT_DRVINS(pDrvIns);
1099 LogFlow(("pdmR3DrvHlp_MountPrepare: caller='%s'/%d: pszFilename=%p:{%s} pszCoreDriver=%p:{%s}\n",
1100 pDrvIns->pReg->szName, pDrvIns->iInstance, pszFilename, pszFilename, pszCoreDriver, pszCoreDriver));
1101 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1102
1103 /*
1104 * Do the caller have anything attached below itself?
1105 */
1106 if (pDrvIns->Internal.s.pDown)
1107 {
1108 AssertMsgFailed(("Cannot prepare a mount when something's attached to you!\n"));
1109 return VERR_PDM_DRIVER_ALREADY_ATTACHED;
1110 }
1111
1112 /*
1113 * We're asked to prepare, so we'll start off by nuking the
1114 * attached configuration tree.
1115 */
1116 PCFGMNODE pNode = CFGMR3GetChild(pDrvIns->Internal.s.pCfgHandle, "AttachedDriver");
1117 if (pNode)
1118 CFGMR3RemoveNode(pNode);
1119
1120 /*
1121 * If there is no core driver, we'll have to probe for it.
1122 */
1123 if (!pszCoreDriver)
1124 {
1125 /** @todo implement image probing. */
1126 AssertReleaseMsgFailed(("Not implemented!\n"));
1127 return VERR_NOT_IMPLEMENTED;
1128 }
1129
1130 /*
1131 * Construct the basic attached driver configuration.
1132 */
1133 int rc = CFGMR3InsertNode(pDrvIns->Internal.s.pCfgHandle, "AttachedDriver", &pNode);
1134 if (RT_SUCCESS(rc))
1135 {
1136 rc = CFGMR3InsertString(pNode, "Driver", pszCoreDriver);
1137 if (RT_SUCCESS(rc))
1138 {
1139 PCFGMNODE pCfg;
1140 rc = CFGMR3InsertNode(pNode, "Config", &pCfg);
1141 if (RT_SUCCESS(rc))
1142 {
1143 rc = CFGMR3InsertString(pCfg, "Path", pszFilename);
1144 if (RT_SUCCESS(rc))
1145 {
1146 LogFlow(("pdmR3DrvHlp_MountPrepare: caller='%s'/%d: returns %Rrc (Driver=%s)\n",
1147 pDrvIns->pReg->szName, pDrvIns->iInstance, rc, pszCoreDriver));
1148 return rc;
1149 }
1150 else
1151 AssertMsgFailed(("Path string insert failed, rc=%Rrc\n", rc));
1152 }
1153 else
1154 AssertMsgFailed(("Config node failed, rc=%Rrc\n", rc));
1155 }
1156 else
1157 AssertMsgFailed(("Driver string insert failed, rc=%Rrc\n", rc));
1158 CFGMR3RemoveNode(pNode);
1159 }
1160 else
1161 AssertMsgFailed(("AttachedDriver node insert failed, rc=%Rrc\n", rc));
1162
1163 LogFlow(("pdmR3DrvHlp_MountPrepare: caller='%s'/%d: returns %Rrc\n",
1164 pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1165 return rc;
1166}
1167
1168
1169/** @interface_method_impl{PDMDRVHLPR3,pfnAssertEMT} */
1170static DECLCALLBACK(bool) pdmR3DrvHlp_AssertEMT(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)
1171{
1172 PDMDRV_ASSERT_DRVINS(pDrvIns);
1173 if (VM_IS_EMT(pDrvIns->Internal.s.pVMR3))
1174 return true;
1175
1176 char szMsg[100];
1177 RTStrPrintf(szMsg, sizeof(szMsg), "AssertEMT '%s'/%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance);
1178 RTAssertMsg1Weak(szMsg, iLine, pszFile, pszFunction);
1179 AssertBreakpoint();
1180 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1181 return false;
1182}
1183
1184
1185/** @interface_method_impl{PDMDRVHLPR3,pfnAssertOther} */
1186static DECLCALLBACK(bool) pdmR3DrvHlp_AssertOther(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)
1187{
1188 PDMDRV_ASSERT_DRVINS(pDrvIns);
1189 if (!VM_IS_EMT(pDrvIns->Internal.s.pVMR3))
1190 return true;
1191
1192 char szMsg[100];
1193 RTStrPrintf(szMsg, sizeof(szMsg), "AssertOther '%s'/%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance);
1194 RTAssertMsg1Weak(szMsg, iLine, pszFile, pszFunction);
1195 AssertBreakpoint();
1196 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1197 return false;
1198}
1199
1200
1201/** @interface_method_impl{PDMDRVHLPR3,pfnVMSetErrorV} */
1202static DECLCALLBACK(int) pdmR3DrvHlp_VMSetErrorV(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
1203{
1204 PDMDRV_ASSERT_DRVINS(pDrvIns);
1205 int rc2 = VMSetErrorV(pDrvIns->Internal.s.pVMR3, rc, RT_SRC_POS_ARGS, pszFormat, va); Assert(rc2 == rc); NOREF(rc2);
1206 return rc;
1207}
1208
1209
1210/** @interface_method_impl{PDMDRVHLPR3,pfnVMSetRuntimeErrorV} */
1211static DECLCALLBACK(int) pdmR3DrvHlp_VMSetRuntimeErrorV(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)
1212{
1213 PDMDRV_ASSERT_DRVINS(pDrvIns);
1214 int rc = VMSetRuntimeErrorV(pDrvIns->Internal.s.pVMR3, fFlags, pszErrorId, pszFormat, va);
1215 return rc;
1216}
1217
1218
1219/** @interface_method_impl{PDMDRVHLPR3,pfnVMState} */
1220static DECLCALLBACK(VMSTATE) pdmR3DrvHlp_VMState(PPDMDRVINS pDrvIns)
1221{
1222 PDMDRV_ASSERT_DRVINS(pDrvIns);
1223
1224 VMSTATE enmVMState = VMR3GetState(pDrvIns->Internal.s.pVMR3);
1225
1226 LogFlow(("pdmR3DrvHlp_VMState: caller='%s'/%d: returns %d (%s)\n", pDrvIns->pReg->szName, pDrvIns->iInstance,
1227 enmVMState, VMR3GetStateName(enmVMState)));
1228 return enmVMState;
1229}
1230
1231
1232/** @interface_method_impl{PDMDRVHLPR3,pfnVMTeleportedAndNotFullyResumedYet} */
1233static DECLCALLBACK(bool) pdmR3DrvHlp_VMTeleportedAndNotFullyResumedYet(PPDMDRVINS pDrvIns)
1234{
1235 PDMDRV_ASSERT_DRVINS(pDrvIns);
1236
1237 bool fRc = VMR3TeleportedAndNotFullyResumedYet(pDrvIns->Internal.s.pVMR3);
1238
1239 LogFlow(("pdmR3DrvHlp_VMState: caller='%s'/%d: returns %RTbool)\n", pDrvIns->pReg->szName, pDrvIns->iInstance,
1240 fRc));
1241 return fRc;
1242}
1243
1244
1245/** @interface_method_impl{PDMDRVHLPR3,pfnGetSupDrvSession} */
1246static DECLCALLBACK(PSUPDRVSESSION) pdmR3DrvHlp_GetSupDrvSession(PPDMDRVINS pDrvIns)
1247{
1248 PDMDRV_ASSERT_DRVINS(pDrvIns);
1249
1250 PSUPDRVSESSION pSession = pDrvIns->Internal.s.pVMR3->pSession;
1251 LogFlow(("pdmR3DrvHlp_GetSupDrvSession: caller='%s'/%d: returns %p)\n", pDrvIns->pReg->szName, pDrvIns->iInstance,
1252 pSession));
1253 return pSession;
1254}
1255
1256
1257/**
1258 * Conversion from handle to queue pointer (temporary).
1259 */
1260DECLINLINE(PPDMQUEUE) pdmR3DrvHlp_QueueToPtr(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue)
1261{
1262 PDMDRV_ASSERT_DRVINS(pDrvIns);
1263 RT_NOREF(pDrvIns);
1264 return (PPDMQUEUE)hQueue;
1265}
1266
1267
1268/** @interface_method_impl{PDMDRVHLPR3,pfnQueueCreate} */
1269static DECLCALLBACK(int) pdmR3DrvHlp_QueueCreate(PPDMDRVINS pDrvIns, uint32_t cbItem, uint32_t cItems, uint32_t cMilliesInterval,
1270 PFNPDMQUEUEDRV pfnCallback, const char *pszName, PDMQUEUEHANDLE *phQueue)
1271{
1272 PDMDRV_ASSERT_DRVINS(pDrvIns);
1273 LogFlow(("pdmR3DrvHlp_PDMQueueCreate: caller='%s'/%d: cbItem=%d cItems=%d cMilliesInterval=%d pfnCallback=%p pszName=%p:{%s} phQueue=%p\n",
1274 pDrvIns->pReg->szName, pDrvIns->iInstance, cbItem, cItems, cMilliesInterval, pfnCallback, pszName, pszName, phQueue));
1275 PVM pVM = pDrvIns->Internal.s.pVMR3;
1276 VM_ASSERT_EMT(pVM);
1277
1278 if (pDrvIns->iInstance > 0)
1279 {
1280 pszName = MMR3HeapAPrintf(pVM, MM_TAG_PDM_DRIVER_DESC, "%s_%u", pszName, pDrvIns->iInstance);
1281 AssertLogRelReturn(pszName, VERR_NO_MEMORY);
1282 }
1283
1284 PPDMQUEUE pQueue = NULL;
1285 int rc = PDMR3QueueCreateDriver(pVM, pDrvIns, cbItem, cItems, cMilliesInterval, pfnCallback, pszName, &pQueue);
1286 *phQueue = (PDMQUEUEHANDLE)pQueue;
1287
1288 LogFlow(("pdmR3DrvHlp_PDMQueueCreate: caller='%s'/%d: returns %Rrc *phQueue=%p\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc, *phQueue));
1289 return rc;
1290}
1291
1292
1293/** @interface_method_impl{PDMDRVHLPR3,pfnQueueAlloc} */
1294static DECLCALLBACK(PPDMQUEUEITEMCORE) pdmR3DrvHlp_QueueAlloc(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue)
1295{
1296 return PDMQueueAlloc(pdmR3DrvHlp_QueueToPtr(pDrvIns, hQueue));
1297}
1298
1299
1300/** @interface_method_impl{PDMDRVHLPR3,pfnQueueInsert} */
1301static DECLCALLBACK(void) pdmR3DrvHlp_QueueInsert(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)
1302{
1303 return PDMQueueInsert(pdmR3DrvHlp_QueueToPtr(pDrvIns, hQueue), pItem);
1304}
1305
1306
1307/** @interface_method_impl{PDMDRVHLPR3,pfnQueueFlushIfNecessary} */
1308static DECLCALLBACK(bool) pdmR3DrvHlp_QueueFlushIfNecessary(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue)
1309{
1310 return PDMQueueFlushIfNecessary(pdmR3DrvHlp_QueueToPtr(pDrvIns, hQueue));
1311}
1312
1313
1314
1315/** @interface_method_impl{PDMDRVHLPR3,pfnTMGetVirtualFreq} */
1316static DECLCALLBACK(uint64_t) pdmR3DrvHlp_TMGetVirtualFreq(PPDMDRVINS pDrvIns)
1317{
1318 PDMDRV_ASSERT_DRVINS(pDrvIns);
1319
1320 return TMVirtualGetFreq(pDrvIns->Internal.s.pVMR3);
1321}
1322
1323
1324/** @interface_method_impl{PDMDRVHLPR3,pfnTMGetVirtualTime} */
1325static DECLCALLBACK(uint64_t) pdmR3DrvHlp_TMGetVirtualTime(PPDMDRVINS pDrvIns)
1326{
1327 PDMDRV_ASSERT_DRVINS(pDrvIns);
1328
1329 return TMVirtualGet(pDrvIns->Internal.s.pVMR3);
1330}
1331
1332
1333/** @interface_method_impl{PDMDRVHLPR3,pfnTimerCreate} */
1334static DECLCALLBACK(int) pdmR3DrvHlp_TimerCreate(PPDMDRVINS pDrvIns, TMCLOCK enmClock, PFNTMTIMERDRV pfnCallback, void *pvUser,
1335 uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer)
1336{
1337 PDMDRV_ASSERT_DRVINS(pDrvIns);
1338 LogFlow(("pdmR3DrvHlp_TimerCreate: caller='%s'/%d: enmClock=%d pfnCallback=%p pvUser=%p fFlags=%#x pszDesc=%p:{%s} phTimer=%p\n",
1339 pDrvIns->pReg->szName, pDrvIns->iInstance, enmClock, pfnCallback, pvUser, fFlags, pszDesc, pszDesc, phTimer));
1340
1341 /* Mangle the timer name if there are more than once instance of this driver. */
1342 char szName[32];
1343 AssertReturn(strlen(pszDesc) < sizeof(szName) - 3, VERR_INVALID_NAME);
1344 if (pDrvIns->iInstance > 0)
1345 {
1346 RTStrPrintf(szName, sizeof(szName), "%s[%u]", pszDesc, pDrvIns->iInstance);
1347 pszDesc = szName;
1348 }
1349
1350 /* Clear the ring-0 flag if the driver isn't configured for ring-0. */
1351 if (fFlags & TMTIMER_FLAGS_RING0)
1352 {
1353 AssertReturn(!(fFlags & TMTIMER_FLAGS_NO_RING0), VERR_INVALID_FLAGS);
1354 Assert(pDrvIns->Internal.s.pDrv->pReg->fFlags & PDM_DRVREG_FLAGS_R0);
1355 /* if (!(pDrvIns->Internal.s.fIntFlags & PDMDRVINSINT_FLAGS_R0_ENABLED)) */ /** @todo PDMDRVINSINT_FLAGS_R0_ENABLED? */
1356 fFlags = (fFlags & ~TMTIMER_FLAGS_RING0) | TMTIMER_FLAGS_NO_RING0;
1357 }
1358 else
1359 fFlags |= TMTIMER_FLAGS_NO_RING0;
1360
1361 int rc = TMR3TimerCreateDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, phTimer);
1362
1363 LogFlow(("pdmR3DrvHlp_TMTimerCreate: caller='%s'/%d: returns %Rrc *phTimer=%p\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc, *phTimer));
1364 return rc;
1365}
1366
1367
1368/** @interface_method_impl{PDMDRVHLPR3,pfnTimerSetMillies} */
1369static DECLCALLBACK(int) pdmR3DrvHlp_TimerSetMillies(PPDMDRVINS pDrvIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext)
1370{
1371 PDMDRV_ASSERT_DRVINS(pDrvIns);
1372 return TMTimerSetMillies(pDrvIns->Internal.s.pVMR3, hTimer, cMilliesToNext);
1373}
1374
1375
1376/** @interface_method_impl{PDMDRVHLPR3,pfnSSMRegister} */
1377static DECLCALLBACK(int) pdmR3DrvHlp_SSMRegister(PPDMDRVINS pDrvIns, uint32_t uVersion, size_t cbGuess,
1378 PFNSSMDRVLIVEPREP pfnLivePrep, PFNSSMDRVLIVEEXEC pfnLiveExec, PFNSSMDRVLIVEVOTE pfnLiveVote,
1379 PFNSSMDRVSAVEPREP pfnSavePrep, PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVSAVEDONE pfnSaveDone,
1380 PFNSSMDRVLOADPREP pfnLoadPrep, PFNSSMDRVLOADEXEC pfnLoadExec, PFNSSMDRVLOADDONE pfnLoadDone)
1381{
1382 PDMDRV_ASSERT_DRVINS(pDrvIns);
1383 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1384 LogFlow(("pdmR3DrvHlp_SSMRegister: caller='%s'/%d: uVersion=%#x cbGuess=%#x \n"
1385 " pfnLivePrep=%p pfnLiveExec=%p pfnLiveVote=%p pfnSavePrep=%p pfnSaveExec=%p pfnSaveDone=%p pszLoadPrep=%p pfnLoadExec=%p pfnLoaddone=%p\n",
1386 pDrvIns->pReg->szName, pDrvIns->iInstance, uVersion, cbGuess,
1387 pfnLivePrep, pfnLiveExec, pfnLiveVote,
1388 pfnSavePrep, pfnSaveExec, pfnSaveDone, pfnLoadPrep, pfnLoadExec, pfnLoadDone));
1389
1390 int rc = SSMR3RegisterDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, pDrvIns->pReg->szName, pDrvIns->iInstance,
1391 uVersion, cbGuess,
1392 pfnLivePrep, pfnLiveExec, pfnLiveVote,
1393 pfnSavePrep, pfnSaveExec, pfnSaveDone,
1394 pfnLoadPrep, pfnLoadExec, pfnLoadDone);
1395
1396 LogFlow(("pdmR3DrvHlp_SSMRegister: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1397 return rc;
1398}
1399
1400
1401/** @interface_method_impl{PDMDRVHLPR3,pfnSSMDeregister} */
1402static DECLCALLBACK(int) pdmR3DrvHlp_SSMDeregister(PPDMDRVINS pDrvIns, const char *pszName, uint32_t uInstance)
1403{
1404 PDMDRV_ASSERT_DRVINS(pDrvIns);
1405 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1406 LogFlow(("pdmR3DrvHlp_SSMDeregister: caller='%s'/%d: pszName=%p:{%s} uInstance=%#x\n",
1407 pDrvIns->pReg->szName, pDrvIns->iInstance, pszName, pszName, uInstance));
1408
1409 int rc = SSMR3DeregisterDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, pszName, uInstance);
1410
1411 LogFlow(("pdmR3DrvHlp_SSMDeregister: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1412 return rc;
1413}
1414
1415
1416/** @interface_method_impl{PDMDRVHLPR3,pfnMMHeapFree} */
1417static DECLCALLBACK(void) pdmR3DrvHlp_MMHeapFree(PPDMDRVINS pDrvIns, void *pv)
1418{
1419 PDMDRV_ASSERT_DRVINS(pDrvIns); RT_NOREF(pDrvIns);
1420 LogFlow(("pdmR3DrvHlp_MMHeapFree: caller='%s'/%d: pv=%p\n",
1421 pDrvIns->pReg->szName, pDrvIns->iInstance, pv));
1422
1423 MMR3HeapFree(pv);
1424
1425 LogFlow(("pdmR3DrvHlp_MMHeapFree: caller='%s'/%d: returns\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
1426}
1427
1428
1429/** @interface_method_impl{PDMDRVHLPR3,pfnDBGFInfoRegister} */
1430static DECLCALLBACK(int) pdmR3DrvHlp_DBGFInfoRegister(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDRV pfnHandler)
1431{
1432 PDMDRV_ASSERT_DRVINS(pDrvIns);
1433 LogFlow(("pdmR3DrvHlp_DBGFInfoRegister: caller='%s'/%d: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p\n",
1434 pDrvIns->pReg->szName, pDrvIns->iInstance, pszName, pszName, pszDesc, pszDesc, pfnHandler));
1435
1436 int rc = DBGFR3InfoRegisterDriver(pDrvIns->Internal.s.pVMR3, pszName, pszDesc, pfnHandler, pDrvIns);
1437
1438 LogFlow(("pdmR3DrvHlp_DBGFInfoRegister: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1439 return rc;
1440}
1441
1442
1443/** @interface_method_impl{PDMDRVHLPR3,pfnDBGFInfoRegisterArgv} */
1444static DECLCALLBACK(int) pdmR3DrvHlp_DBGFInfoRegisterArgv(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVDRV pfnHandler)
1445{
1446 PDMDRV_ASSERT_DRVINS(pDrvIns);
1447 LogFlow(("pdmR3DrvHlp_DBGFInfoRegisterArgv: caller='%s'/%d: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p\n",
1448 pDrvIns->pReg->szName, pDrvIns->iInstance, pszName, pszName, pszDesc, pszDesc, pfnHandler));
1449
1450 int rc = DBGFR3InfoRegisterDriverArgv(pDrvIns->Internal.s.pVMR3, pszName, pszDesc, pfnHandler, pDrvIns);
1451
1452 LogFlow(("pdmR3DrvHlp_DBGFInfoRegisterArgv: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1453 return rc;
1454}
1455
1456
1457/** @interface_method_impl{PDMDRVHLPR3,pfnDBGFInfoDeregister} */
1458static DECLCALLBACK(int) pdmR3DrvHlp_DBGFInfoDeregister(PPDMDRVINS pDrvIns, const char *pszName)
1459{
1460 PDMDRV_ASSERT_DRVINS(pDrvIns);
1461 LogFlow(("pdmR3DrvHlp_DBGFInfoDeregister: caller='%s'/%d: pszName=%p:{%s}\n",
1462 pDrvIns->pReg->szName, pDrvIns->iInstance, pszName, pszName));
1463
1464 int rc = DBGFR3InfoDeregisterDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, pszName);
1465
1466 LogFlow(("pdmR3DrvHlp_DBGFInfoDeregister: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1467
1468 return rc;
1469}
1470
1471
1472/** @interface_method_impl{PDMDRVHLPR3,pfnSTAMRegister} */
1473static DECLCALLBACK(void) pdmR3DrvHlp_STAMRegister(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, const char *pszName,
1474 STAMUNIT enmUnit, const char *pszDesc)
1475{
1476 PDMDRV_ASSERT_DRVINS(pDrvIns);
1477 PVM pVM = pDrvIns->Internal.s.pVMR3;
1478 VM_ASSERT_EMT(pVM);
1479
1480#ifdef VBOX_WITH_STATISTICS /** @todo rework this to always be compiled in */
1481 if (*pszName == '/')
1482 STAM_REG(pDrvIns->Internal.s.pVMR3, pvSample, enmType, pszName, enmUnit, pszDesc);
1483 else
1484 STAMR3RegisterF(pVM, pvSample, enmType, STAMVISIBILITY_ALWAYS, enmUnit, pszDesc,
1485 "/Drivers/%s-%u/%s", pDrvIns->pReg->szName, pDrvIns->iInstance, pszName);
1486#else
1487 RT_NOREF(pDrvIns, pvSample, enmType, pszName, enmUnit, pszDesc, pVM);
1488#endif
1489}
1490
1491
1492/** @interface_method_impl{PDMDRVHLPR3,pfnSTAMRegisterV} */
1493static DECLCALLBACK(void) pdmR3DrvHlp_STAMRegisterV(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
1494 STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list args)
1495{
1496 PDMDRV_ASSERT_DRVINS(pDrvIns);
1497 PVM pVM = pDrvIns->Internal.s.pVMR3;
1498 VM_ASSERT_EMT(pVM);
1499
1500 int rc;
1501 if (*pszName == '/')
1502 rc = STAMR3RegisterV(pVM, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, args);
1503 else
1504 {
1505 /* We need to format it to check whether it starts with a
1506 slash or not (will rework this later). */
1507 char szFormatted[2048];
1508 ssize_t cchBase = RTStrPrintf2(szFormatted, sizeof(szFormatted) - 1024, "/Drivers/%s-%u/",
1509 pDrvIns->pReg->szName, pDrvIns->iInstance);
1510 AssertReturnVoid(cchBase > 0);
1511
1512 ssize_t cch2 = RTStrPrintf2V(&szFormatted[cchBase], sizeof(szFormatted) - cchBase, pszName, args);
1513 AssertReturnVoid(cch2 > 0);
1514
1515 rc = STAMR3Register(pVM, pvSample, enmType, enmVisibility,
1516 &szFormatted[szFormatted[cchBase] == '/' ? cchBase : 0], enmUnit, pszDesc);
1517 }
1518 AssertRC(rc);
1519}
1520
1521
1522/** @interface_method_impl{PDMDRVHLPR3,pfnSTAMRegisterF} */
1523static DECLCALLBACK(void) pdmR3DrvHlp_STAMRegisterF(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
1524 STAMUNIT enmUnit, const char *pszDesc, const char *pszName, ...)
1525{
1526 va_list va;
1527 va_start(va, pszName);
1528 pdmR3DrvHlp_STAMRegisterV(pDrvIns, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, va);
1529 va_end(va);
1530}
1531
1532
1533/** @interface_method_impl{PDMDRVHLPR3,pfnSTAMDeregister} */
1534static DECLCALLBACK(int) pdmR3DrvHlp_STAMDeregister(PPDMDRVINS pDrvIns, void *pvSample)
1535{
1536 PDMDRV_ASSERT_DRVINS(pDrvIns);
1537 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1538
1539 return STAMR3DeregisterByAddr(pDrvIns->Internal.s.pVMR3->pUVM, pvSample);
1540}
1541
1542
1543/** @interface_method_impl{PDMDRVHLPR3,pfnSTAMDeregisterByPrefix} */
1544static DECLCALLBACK(int) pdmR3DrvHlp_STAMDeregisterByPrefix(PPDMDRVINS pDrvIns, const char *pszPrefix)
1545{
1546 PDMDRV_ASSERT_DRVINS(pDrvIns);
1547
1548 if (*pszPrefix == '/')
1549 return STAMR3DeregisterByPrefix(pDrvIns->Internal.s.pVMR3->pUVM, pszPrefix);
1550
1551 char szTmp[2048];
1552 ssize_t cch = RTStrPrintf2(szTmp, sizeof(szTmp), "/Drivers/%s-%u/%s", pDrvIns->pReg->szName, pDrvIns->iInstance, pszPrefix);
1553 AssertReturn(cch > 0, VERR_BUFFER_OVERFLOW);
1554 return STAMR3DeregisterByPrefix(pDrvIns->Internal.s.pVMR3->pUVM, szTmp);
1555}
1556
1557
1558/** @interface_method_impl{PDMDRVHLPR3,pfnSUPCallVMMR0Ex} */
1559static DECLCALLBACK(int) pdmR3DrvHlp_SUPCallVMMR0Ex(PPDMDRVINS pDrvIns, unsigned uOperation, void *pvArg, unsigned cbArg)
1560{
1561 PDMDRV_ASSERT_DRVINS(pDrvIns);
1562 LogFlow(("pdmR3DrvHlp_SSMCallVMMR0Ex: caller='%s'/%d: uOperation=%u pvArg=%p cbArg=%d\n",
1563 pDrvIns->pReg->szName, pDrvIns->iInstance, uOperation, pvArg, cbArg));
1564 RT_NOREF_PV(cbArg);
1565
1566 int rc;
1567 if ( uOperation >= VMMR0_DO_SRV_START
1568 && uOperation < VMMR0_DO_SRV_END)
1569 rc = SUPR3CallVMMR0Ex(VMCC_GET_VMR0_FOR_CALL(pDrvIns->Internal.s.pVMR3), NIL_VMCPUID, uOperation, 0, (PSUPVMMR0REQHDR)pvArg);
1570 else
1571 {
1572 AssertMsgFailed(("Invalid uOperation=%u\n", uOperation));
1573 rc = VERR_INVALID_PARAMETER;
1574 }
1575
1576 LogFlow(("pdmR3DrvHlp_SUPCallVMMR0Ex: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1577 return rc;
1578}
1579
1580
1581/** @interface_method_impl{PDMDRVHLPR3,pfnUSBRegisterHub} */
1582static DECLCALLBACK(int) pdmR3DrvHlp_USBRegisterHub(PPDMDRVINS pDrvIns, uint32_t fVersions, uint32_t cPorts, PCPDMUSBHUBREG pUsbHubReg, PPCPDMUSBHUBHLP ppUsbHubHlp)
1583{
1584 PDMDRV_ASSERT_DRVINS(pDrvIns);
1585 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1586 LogFlow(("pdmR3DrvHlp_USBRegisterHub: caller='%s'/%d: fVersions=%#x cPorts=%#x pUsbHubReg=%p ppUsbHubHlp=%p\n",
1587 pDrvIns->pReg->szName, pDrvIns->iInstance, fVersions, cPorts, pUsbHubReg, ppUsbHubHlp));
1588
1589#ifdef VBOX_WITH_USB
1590 int rc = pdmR3UsbRegisterHub(pDrvIns->Internal.s.pVMR3, pDrvIns, fVersions, cPorts, pUsbHubReg, ppUsbHubHlp);
1591#else
1592 int rc = VERR_NOT_SUPPORTED;
1593#endif
1594
1595 LogFlow(("pdmR3DrvHlp_USBRegisterHub: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1596 return rc;
1597}
1598
1599
1600/** @interface_method_impl{PDMDRVHLPR3,pfnSetAsyncNotification} */
1601static DECLCALLBACK(int) pdmR3DrvHlp_SetAsyncNotification(PPDMDRVINS pDrvIns, PFNPDMDRVASYNCNOTIFY pfnAsyncNotify)
1602{
1603 PDMDRV_ASSERT_DRVINS(pDrvIns);
1604 VM_ASSERT_EMT0(pDrvIns->Internal.s.pVMR3);
1605 LogFlow(("pdmR3DrvHlp_SetAsyncNotification: caller='%s'/%d: pfnAsyncNotify=%p\n", pDrvIns->pReg->szName, pDrvIns->iInstance, pfnAsyncNotify));
1606
1607 int rc = VINF_SUCCESS;
1608 AssertStmt(pfnAsyncNotify, rc = VERR_INVALID_PARAMETER);
1609 AssertStmt(!pDrvIns->Internal.s.pfnAsyncNotify, rc = VERR_WRONG_ORDER);
1610 AssertStmt(pDrvIns->Internal.s.fVMSuspended || pDrvIns->Internal.s.fVMReset, rc = VERR_WRONG_ORDER);
1611 VMSTATE enmVMState = VMR3GetState(pDrvIns->Internal.s.pVMR3);
1612 AssertStmt( enmVMState == VMSTATE_SUSPENDING
1613 || enmVMState == VMSTATE_SUSPENDING_EXT_LS
1614 || enmVMState == VMSTATE_SUSPENDING_LS
1615 || enmVMState == VMSTATE_RESETTING
1616 || enmVMState == VMSTATE_RESETTING_LS
1617 || enmVMState == VMSTATE_POWERING_OFF
1618 || enmVMState == VMSTATE_POWERING_OFF_LS,
1619 rc = VERR_INVALID_STATE);
1620
1621 if (RT_SUCCESS(rc))
1622 pDrvIns->Internal.s.pfnAsyncNotify = pfnAsyncNotify;
1623
1624 LogFlow(("pdmR3DrvHlp_SetAsyncNotification: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1625 return rc;
1626}
1627
1628
1629/** @interface_method_impl{PDMDRVHLPR3,pfnAsyncNotificationCompleted} */
1630static DECLCALLBACK(void) pdmR3DrvHlp_AsyncNotificationCompleted(PPDMDRVINS pDrvIns)
1631{
1632 PDMDRV_ASSERT_DRVINS(pDrvIns);
1633 PVM pVM = pDrvIns->Internal.s.pVMR3;
1634
1635 VMSTATE enmVMState = VMR3GetState(pVM);
1636 if ( enmVMState == VMSTATE_SUSPENDING
1637 || enmVMState == VMSTATE_SUSPENDING_EXT_LS
1638 || enmVMState == VMSTATE_SUSPENDING_LS
1639 || enmVMState == VMSTATE_RESETTING
1640 || enmVMState == VMSTATE_RESETTING_LS
1641 || enmVMState == VMSTATE_POWERING_OFF
1642 || enmVMState == VMSTATE_POWERING_OFF_LS)
1643 {
1644 LogFlow(("pdmR3DrvHlp_AsyncNotificationCompleted: caller='%s'/%d:\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
1645 VMR3AsyncPdmNotificationWakeupU(pVM->pUVM);
1646 }
1647 else
1648 LogFlow(("pdmR3DrvHlp_AsyncNotificationCompleted: caller='%s'/%d: enmVMState=%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance, enmVMState));
1649}
1650
1651
1652/** @interface_method_impl{PDMDRVHLPR3,pfnThreadCreate} */
1653static DECLCALLBACK(int) pdmR3DrvHlp_ThreadCreate(PPDMDRVINS pDrvIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDRV pfnThread,
1654 PFNPDMTHREADWAKEUPDRV pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
1655{
1656 PDMDRV_ASSERT_DRVINS(pDrvIns);
1657 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1658 LogFlow(("pdmR3DrvHlp_ThreadCreate: caller='%s'/%d: ppThread=%p pvUser=%p pfnThread=%p pfnWakeup=%p cbStack=%#zx enmType=%d pszName=%p:{%s}\n",
1659 pDrvIns->pReg->szName, pDrvIns->iInstance, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName, pszName));
1660
1661 int rc = pdmR3ThreadCreateDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName);
1662
1663 LogFlow(("pdmR3DrvHlp_ThreadCreate: caller='%s'/%d: returns %Rrc *ppThread=%RTthrd\n", pDrvIns->pReg->szName, pDrvIns->iInstance,
1664 rc, *ppThread));
1665 return rc;
1666}
1667
1668
1669/** @interface_method_impl{PDMDRVHLPR3,pfnAsyncCompletionTemplateCreate} */
1670static DECLCALLBACK(int) pdmR3DrvHlp_AsyncCompletionTemplateCreate(PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate,
1671 PFNPDMASYNCCOMPLETEDRV pfnCompleted, void *pvTemplateUser,
1672 const char *pszDesc)
1673{
1674 PDMDRV_ASSERT_DRVINS(pDrvIns);
1675 LogFlow(("pdmR3DrvHlp_AsyncCompletionTemplateCreate: caller='%s'/%d: ppTemplate=%p pfnCompleted=%p pszDesc=%p:{%s}\n",
1676 pDrvIns->pReg->szName, pDrvIns->iInstance, ppTemplate, pfnCompleted, pszDesc, pszDesc));
1677
1678 int rc = pdmR3AsyncCompletionTemplateCreateDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, ppTemplate, pfnCompleted, pvTemplateUser, pszDesc);
1679
1680 LogFlow(("pdmR3DrvHlp_AsyncCompletionTemplateCreate: caller='%s'/%d: returns %Rrc *ppThread=%p\n", pDrvIns->pReg->szName,
1681 pDrvIns->iInstance, rc, *ppTemplate));
1682 return rc;
1683}
1684
1685
1686/** @interface_method_impl{PDMDRVHLPR3,pfnNetShaperAttach} */
1687static DECLCALLBACK(int) pdmR3DrvHlp_NetShaperAttach(PPDMDRVINS pDrvIns, const char *pszBwGroup, PPDMNSFILTER pFilter)
1688{
1689#ifdef VBOX_WITH_NETSHAPER
1690 PDMDRV_ASSERT_DRVINS(pDrvIns);
1691 LogFlow(("pdmR3DrvHlp_NetShaperAttach: caller='%s'/%d: pFilter=%p pszBwGroup=%p:{%s}\n",
1692 pDrvIns->pReg->szName, pDrvIns->iInstance, pFilter, pszBwGroup, pszBwGroup));
1693
1694 int rc = PDMR3NsAttach(pDrvIns->Internal.s.pVMR3->pUVM, pDrvIns, pszBwGroup, pFilter);
1695
1696 LogFlow(("pdmR3DrvHlp_NetShaperAttach: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1697 pDrvIns->iInstance, rc));
1698 return rc;
1699#else
1700 RT_NOREF(pDrvIns, pszBwGroup, pFilter);
1701 return VERR_NOT_IMPLEMENTED;
1702#endif
1703}
1704
1705
1706/** @interface_method_impl{PDMDRVHLPR3,pfnNetShaperDetach} */
1707static DECLCALLBACK(int) pdmR3DrvHlp_NetShaperDetach(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter)
1708{
1709#ifdef VBOX_WITH_NETSHAPER
1710 PDMDRV_ASSERT_DRVINS(pDrvIns);
1711 LogFlow(("pdmR3DrvHlp_NetShaperDetach: caller='%s'/%d: pFilter=%p\n",
1712 pDrvIns->pReg->szName, pDrvIns->iInstance, pFilter));
1713
1714 int rc = PDMR3NsDetach(pDrvIns->Internal.s.pVMR3->pUVM, pDrvIns, pFilter);
1715
1716 LogFlow(("pdmR3DrvHlp_NetShaperDetach: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1717 pDrvIns->iInstance, rc));
1718 return rc;
1719#else
1720 RT_NOREF(pDrvIns, pFilter);
1721 return VERR_NOT_IMPLEMENTED;
1722#endif
1723}
1724
1725
1726/** @interface_method_impl{PDMDRVHLPR3,pfnNetShaperAllocateBandwidth} */
1727static DECLCALLBACK(bool) pdmR3DrvHlp_NetShaperAllocateBandwidth(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter, size_t cbTransfer)
1728{
1729#ifdef VBOX_WITH_NETSHAPER
1730 PDMDRV_ASSERT_DRVINS(pDrvIns);
1731 LogFlow(("pdmR3DrvHlp_NetShaperDetach: caller='%s'/%d: pFilter=%p cbTransfer=%#zx\n",
1732 pDrvIns->pReg->szName, pDrvIns->iInstance, pFilter, cbTransfer));
1733
1734 bool const fRc = PDMNetShaperAllocateBandwidth(pDrvIns->Internal.s.pVMR3, pFilter, cbTransfer);
1735
1736 LogFlow(("pdmR3DrvHlp_NetShaperDetach: caller='%s'/%d: returns %RTbool\n", pDrvIns->pReg->szName, pDrvIns->iInstance, fRc));
1737 return fRc;
1738#else
1739 RT_NOREF(pDrvIns, pFilter, cbTransfer);
1740 return true;
1741#endif
1742}
1743
1744
1745/** @interface_method_impl{PDMDRVHLPR3,pfnLdrGetRCInterfaceSymbols} */
1746static DECLCALLBACK(int) pdmR3DrvHlp_LdrGetRCInterfaceSymbols(PPDMDRVINS pDrvIns, void *pvInterface, size_t cbInterface,
1747 const char *pszSymPrefix, const char *pszSymList)
1748{
1749 PDMDRV_ASSERT_DRVINS(pDrvIns);
1750 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1751 LogFlow(("pdmR3DrvHlp_LdrGetRCInterfaceSymbols: caller='%s'/%d: pvInterface=%p cbInterface=%zu pszSymPrefix=%p:{%s} pszSymList=%p:{%s}\n",
1752 pDrvIns->pReg->szName, pDrvIns->iInstance, pvInterface, cbInterface, pszSymPrefix, pszSymPrefix, pszSymList, pszSymList));
1753
1754 int rc;
1755 if ( strncmp(pszSymPrefix, "drv", 3) == 0
1756 && RTStrIStr(pszSymPrefix + 3, pDrvIns->pReg->szName) != NULL)
1757 {
1758 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_RC)
1759 rc = PDMR3LdrGetInterfaceSymbols(pDrvIns->Internal.s.pVMR3,
1760 pvInterface, cbInterface,
1761 pDrvIns->pReg->szRCMod, pDrvIns->Internal.s.pDrv->pszRCSearchPath,
1762 pszSymPrefix, pszSymList,
1763 false /*fRing0OrRC*/);
1764 else
1765 {
1766 AssertMsgFailed(("Not a raw-mode enabled driver\n"));
1767 rc = VERR_PERMISSION_DENIED;
1768 }
1769 }
1770 else
1771 {
1772 AssertMsgFailed(("Invalid prefix '%s' for '%s'; must start with 'drv' and contain the driver name!\n",
1773 pszSymPrefix, pDrvIns->pReg->szName));
1774 rc = VERR_INVALID_NAME;
1775 }
1776
1777 LogFlow(("pdmR3DrvHlp_LdrGetRCInterfaceSymbols: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1778 pDrvIns->iInstance, rc));
1779 return rc;
1780}
1781
1782
1783/** @interface_method_impl{PDMDRVHLPR3,pfnLdrGetR0InterfaceSymbols} */
1784static DECLCALLBACK(int) pdmR3DrvHlp_LdrGetR0InterfaceSymbols(PPDMDRVINS pDrvIns, void *pvInterface, size_t cbInterface,
1785 const char *pszSymPrefix, const char *pszSymList)
1786{
1787 PDMDRV_ASSERT_DRVINS(pDrvIns);
1788 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1789 LogFlow(("pdmR3DrvHlp_LdrGetR0InterfaceSymbols: caller='%s'/%d: pvInterface=%p cbInterface=%zu pszSymPrefix=%p:{%s} pszSymList=%p:{%s}\n",
1790 pDrvIns->pReg->szName, pDrvIns->iInstance, pvInterface, cbInterface, pszSymPrefix, pszSymPrefix, pszSymList, pszSymList));
1791
1792 int rc;
1793 if ( strncmp(pszSymPrefix, "drv", 3) == 0
1794 && RTStrIStr(pszSymPrefix + 3, pDrvIns->pReg->szName) != NULL)
1795 {
1796 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_R0)
1797 rc = PDMR3LdrGetInterfaceSymbols(pDrvIns->Internal.s.pVMR3,
1798 pvInterface, cbInterface,
1799 pDrvIns->pReg->szR0Mod, pDrvIns->Internal.s.pDrv->pszR0SearchPath,
1800 pszSymPrefix, pszSymList,
1801 true /*fRing0OrRC*/);
1802 else
1803 {
1804 AssertMsgFailed(("Not a ring-0 enabled driver\n"));
1805 rc = VERR_PERMISSION_DENIED;
1806 }
1807 }
1808 else
1809 {
1810 AssertMsgFailed(("Invalid prefix '%s' for '%s'; must start with 'drv' and contain the driver name!\n",
1811 pszSymPrefix, pDrvIns->pReg->szName));
1812 rc = VERR_INVALID_NAME;
1813 }
1814
1815 LogFlow(("pdmR3DrvHlp_LdrGetR0InterfaceSymbols: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1816 pDrvIns->iInstance, rc));
1817 return rc;
1818}
1819
1820
1821/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectInit} */
1822static DECLCALLBACK(int) pdmR3DrvHlp_CritSectInit(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect,
1823 RT_SRC_POS_DECL, const char *pszName)
1824{
1825 PDMDRV_ASSERT_DRVINS(pDrvIns);
1826 PVM pVM = pDrvIns->Internal.s.pVMR3;
1827 VM_ASSERT_EMT(pVM);
1828 LogFlow(("pdmR3DrvHlp_CritSectInit: caller='%s'/%d: pCritSect=%p pszName=%s\n",
1829 pDrvIns->pReg->szName, pDrvIns->iInstance, pCritSect, pszName));
1830
1831 int rc = pdmR3CritSectInitDriver(pVM, pDrvIns, pCritSect, RT_SRC_POS_ARGS, "%s_%u", pszName, pDrvIns->iInstance);
1832
1833 LogFlow(("pdmR3DrvHlp_CritSectInit: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1834 pDrvIns->iInstance, rc));
1835 return rc;
1836}
1837
1838/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectYield} */
1839static DECLCALLBACK(bool) pdmR3DrvHlp_CritSectYield(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)
1840{
1841 PDMDRV_ASSERT_DRVINS(pDrvIns);
1842 RT_NOREF(pDrvIns);
1843 return PDMR3CritSectYield(pDrvIns->Internal.s.pVMR3, pCritSect);
1844}
1845
1846
1847/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectEnter} */
1848static DECLCALLBACK(int) pdmR3DrvHlp_CritSectEnter(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy)
1849{
1850 PDMDRV_ASSERT_DRVINS(pDrvIns);
1851 return PDMCritSectEnter(pDrvIns->Internal.s.pVMR3, pCritSect, rcBusy);
1852}
1853
1854
1855/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectEnterDebug} */
1856static DECLCALLBACK(int) pdmR3DrvHlp_CritSectEnterDebug(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy,
1857 RTHCUINTPTR uId, RT_SRC_POS_DECL)
1858{
1859 PDMDRV_ASSERT_DRVINS(pDrvIns);
1860 return PDMCritSectEnterDebug(pDrvIns->Internal.s.pVMR3, pCritSect, rcBusy, uId, RT_SRC_POS_ARGS);
1861}
1862
1863
1864/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectTryEnter} */
1865static DECLCALLBACK(int) pdmR3DrvHlp_CritSectTryEnter(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)
1866{
1867 PDMDRV_ASSERT_DRVINS(pDrvIns);
1868 return PDMCritSectTryEnter(pDrvIns->Internal.s.pVMR3, pCritSect);
1869}
1870
1871
1872/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectTryEnterDebug} */
1873static DECLCALLBACK(int) pdmR3DrvHlp_CritSectTryEnterDebug(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect,
1874 RTHCUINTPTR uId, RT_SRC_POS_DECL)
1875{
1876 PDMDRV_ASSERT_DRVINS(pDrvIns);
1877 return PDMCritSectTryEnterDebug(pDrvIns->Internal.s.pVMR3, pCritSect, uId, RT_SRC_POS_ARGS);
1878}
1879
1880
1881/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectLeave} */
1882static DECLCALLBACK(int) pdmR3DrvHlp_CritSectLeave(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)
1883{
1884 PDMDRV_ASSERT_DRVINS(pDrvIns);
1885 return PDMCritSectLeave(pDrvIns->Internal.s.pVMR3, pCritSect);
1886}
1887
1888
1889/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectIsOwner} */
1890static DECLCALLBACK(bool) pdmR3DrvHlp_CritSectIsOwner(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)
1891{
1892 PDMDRV_ASSERT_DRVINS(pDrvIns);
1893 return PDMCritSectIsOwner(pDrvIns->Internal.s.pVMR3, pCritSect);
1894}
1895
1896
1897/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectIsInitialized} */
1898static DECLCALLBACK(bool) pdmR3DrvHlp_CritSectIsInitialized(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)
1899{
1900 PDMDRV_ASSERT_DRVINS(pDrvIns);
1901 RT_NOREF(pDrvIns);
1902 return PDMCritSectIsInitialized(pCritSect);
1903}
1904
1905
1906/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectHasWaiters} */
1907static DECLCALLBACK(bool) pdmR3DrvHlp_CritSectHasWaiters(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)
1908{
1909 PDMDRV_ASSERT_DRVINS(pDrvIns);
1910 return PDMCritSectHasWaiters(pDrvIns->Internal.s.pVMR3, pCritSect);
1911}
1912
1913
1914/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectGetRecursion} */
1915static DECLCALLBACK(uint32_t) pdmR3DrvHlp_CritSectGetRecursion(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)
1916{
1917 PDMDRV_ASSERT_DRVINS(pDrvIns);
1918 RT_NOREF(pDrvIns);
1919 return PDMCritSectGetRecursion(pCritSect);
1920}
1921
1922
1923/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectScheduleExitEvent} */
1924static DECLCALLBACK(int) pdmR3DrvHlp_CritSectScheduleExitEvent(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect,
1925 SUPSEMEVENT hEventToSignal)
1926{
1927 PDMDRV_ASSERT_DRVINS(pDrvIns);
1928 RT_NOREF(pDrvIns);
1929 return PDMHCCritSectScheduleExitEvent(pCritSect, hEventToSignal);
1930}
1931
1932
1933/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectDelete} */
1934static DECLCALLBACK(int) pdmR3DrvHlp_CritSectDelete(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)
1935{
1936 PDMDRV_ASSERT_DRVINS(pDrvIns);
1937 return PDMR3CritSectDelete(pDrvIns->Internal.s.pVMR3, pCritSect);
1938}
1939
1940
1941/** @interface_method_impl{PDMDRVHLPR3,pfnCallR0} */
1942static DECLCALLBACK(int) pdmR3DrvHlp_CallR0(PPDMDRVINS pDrvIns, uint32_t uOperation, uint64_t u64Arg)
1943{
1944 PDMDRV_ASSERT_DRVINS(pDrvIns);
1945 PVM pVM = pDrvIns->Internal.s.pVMR3;
1946 LogFlow(("pdmR3DrvHlp_CallR0: caller='%s'/%d: uOperation=%#x u64Arg=%#RX64\n",
1947 pDrvIns->pReg->szName, pDrvIns->iInstance, uOperation, u64Arg));
1948
1949 /*
1950 * Lazy resolve the ring-0 entry point.
1951 */
1952 int rc = VINF_SUCCESS;
1953 PFNPDMDRVREQHANDLERR0 pfnReqHandlerR0 = pDrvIns->Internal.s.pfnReqHandlerR0;
1954 if (RT_UNLIKELY(pfnReqHandlerR0 == NIL_RTR0PTR))
1955 {
1956 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_R0)
1957 {
1958 char szSymbol[ sizeof("drvR0") + sizeof(pDrvIns->pReg->szName) + sizeof("ReqHandler")];
1959 strcat(strcat(strcpy(szSymbol, "drvR0"), pDrvIns->pReg->szName), "ReqHandler");
1960 szSymbol[sizeof("drvR0") - 1] = RT_C_TO_UPPER(szSymbol[sizeof("drvR0") - 1]);
1961
1962 rc = PDMR3LdrGetSymbolR0Lazy(pVM, pDrvIns->pReg->szR0Mod, pDrvIns->Internal.s.pDrv->pszR0SearchPath, szSymbol,
1963 &pfnReqHandlerR0);
1964 if (RT_SUCCESS(rc))
1965 pDrvIns->Internal.s.pfnReqHandlerR0 = pfnReqHandlerR0;
1966 else
1967 pfnReqHandlerR0 = NIL_RTR0PTR;
1968 }
1969 else
1970 rc = VERR_ACCESS_DENIED;
1971 }
1972 if (RT_LIKELY(pfnReqHandlerR0 != NIL_RTR0PTR))
1973 {
1974 /*
1975 * Make the ring-0 call.
1976 */
1977 PDMDRIVERCALLREQHANDLERREQ Req;
1978 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1979 Req.Hdr.cbReq = sizeof(Req);
1980 Req.pDrvInsR0 = PDMDRVINS_2_R0PTR(pDrvIns);
1981 Req.uOperation = uOperation;
1982 Req.u32Alignment = 0;
1983 Req.u64Arg = u64Arg;
1984 rc = SUPR3CallVMMR0Ex(VMCC_GET_VMR0_FOR_CALL(pVM), NIL_VMCPUID, VMMR0_DO_PDM_DRIVER_CALL_REQ_HANDLER, 0, &Req.Hdr);
1985 }
1986
1987 LogFlow(("pdmR3DrvHlp_CallR0: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1988 pDrvIns->iInstance, rc));
1989 return rc;
1990}
1991
1992
1993/** @interface_method_impl{PDMDRVHLPR3,pfnBlkCacheRetain} */
1994static DECLCALLBACK(int) pdmR3DrvHlp_BlkCacheRetain(PPDMDRVINS pDrvIns, PPPDMBLKCACHE ppBlkCache,
1995 PFNPDMBLKCACHEXFERCOMPLETEDRV pfnXferComplete,
1996 PFNPDMBLKCACHEXFERENQUEUEDRV pfnXferEnqueue,
1997 PFNPDMBLKCACHEXFERENQUEUEDISCARDDRV pfnXferEnqueueDiscard,
1998 const char *pcszId)
1999{
2000 PDMDRV_ASSERT_DRVINS(pDrvIns);
2001 return PDMR3BlkCacheRetainDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, ppBlkCache,
2002 pfnXferComplete, pfnXferEnqueue, pfnXferEnqueueDiscard, pcszId);
2003}
2004
2005
2006
2007/** @interface_method_impl{PDMDRVHLPR3,pfnVMGetSuspendReason} */
2008static DECLCALLBACK(VMSUSPENDREASON) pdmR3DrvHlp_VMGetSuspendReason(PPDMDRVINS pDrvIns)
2009{
2010 PDMDRV_ASSERT_DRVINS(pDrvIns);
2011 PVM pVM = pDrvIns->Internal.s.pVMR3;
2012 VM_ASSERT_EMT(pVM);
2013 VMSUSPENDREASON enmReason = VMR3GetSuspendReason(pVM->pUVM);
2014 LogFlow(("pdmR3DrvHlp_VMGetSuspendReason: caller='%s'/%d: returns %d\n",
2015 pDrvIns->pReg->szName, pDrvIns->iInstance, enmReason));
2016 return enmReason;
2017}
2018
2019
2020/** @interface_method_impl{PDMDRVHLPR3,pfnVMGetResumeReason} */
2021static DECLCALLBACK(VMRESUMEREASON) pdmR3DrvHlp_VMGetResumeReason(PPDMDRVINS pDrvIns)
2022{
2023 PDMDRV_ASSERT_DRVINS(pDrvIns);
2024 PVM pVM = pDrvIns->Internal.s.pVMR3;
2025 VM_ASSERT_EMT(pVM);
2026 VMRESUMEREASON enmReason = VMR3GetResumeReason(pVM->pUVM);
2027 LogFlow(("pdmR3DrvHlp_VMGetResumeReason: caller='%s'/%d: returns %d\n",
2028 pDrvIns->pReg->szName, pDrvIns->iInstance, enmReason));
2029 return enmReason;
2030}
2031
2032
2033/** @interface_method_impl{PDMDRVHLPR3,pfnQueryGenericUserObject} */
2034static DECLCALLBACK(void *) pdmR3DrvHlp_QueryGenericUserObject(PPDMDRVINS pDrvIns, PCRTUUID pUuid)
2035{
2036 PDMDRV_ASSERT_DRVINS(pDrvIns);
2037 LogFlow(("pdmR3DrvHlp_QueryGenericUserObject: caller='%s'/%d: pUuid=%p:%RTuuid\n",
2038 pDrvIns->pReg->szName, pDrvIns->iInstance, pUuid, pUuid));
2039
2040 void *pvRet;
2041 PUVM pUVM = pDrvIns->Internal.s.pVMR3->pUVM;
2042 if (pUVM->pVmm2UserMethods->pfnQueryGenericObject)
2043 pvRet = pUVM->pVmm2UserMethods->pfnQueryGenericObject(pUVM->pVmm2UserMethods, pUVM, pUuid);
2044 else
2045 pvRet = NULL;
2046
2047 LogRel(("pdmR3DrvHlp_QueryGenericUserObject: caller='%s'/%d: returns %#p for %RTuuid\n",
2048 pDrvIns->pReg->szName, pDrvIns->iInstance, pvRet, pUuid));
2049 return pvRet;
2050}
2051
2052
2053/**
2054 * The driver helper structure.
2055 */
2056const PDMDRVHLPR3 g_pdmR3DrvHlp =
2057{
2058 PDM_DRVHLPR3_VERSION,
2059 pdmR3DrvHlp_Attach,
2060 pdmR3DrvHlp_Detach,
2061 pdmR3DrvHlp_DetachSelf,
2062 pdmR3DrvHlp_MountPrepare,
2063 pdmR3DrvHlp_AssertEMT,
2064 pdmR3DrvHlp_AssertOther,
2065 pdmR3DrvHlp_VMSetErrorV,
2066 pdmR3DrvHlp_VMSetRuntimeErrorV,
2067 pdmR3DrvHlp_VMState,
2068 pdmR3DrvHlp_VMTeleportedAndNotFullyResumedYet,
2069 pdmR3DrvHlp_GetSupDrvSession,
2070 pdmR3DrvHlp_QueueCreate,
2071 pdmR3DrvHlp_QueueAlloc,
2072 pdmR3DrvHlp_QueueInsert,
2073 pdmR3DrvHlp_QueueFlushIfNecessary,
2074 pdmR3DrvHlp_TMGetVirtualFreq,
2075 pdmR3DrvHlp_TMGetVirtualTime,
2076 pdmR3DrvHlp_TimerCreate,
2077 pdmR3DrvHlp_SSMRegister,
2078 pdmR3DrvHlp_SSMDeregister,
2079 SSMR3PutStruct,
2080 SSMR3PutStructEx,
2081 SSMR3PutBool,
2082 SSMR3PutU8,
2083 SSMR3PutS8,
2084 SSMR3PutU16,
2085 SSMR3PutS16,
2086 SSMR3PutU32,
2087 SSMR3PutS32,
2088 SSMR3PutU64,
2089 SSMR3PutS64,
2090 SSMR3PutU128,
2091 SSMR3PutS128,
2092 SSMR3PutUInt,
2093 SSMR3PutSInt,
2094 SSMR3PutGCUInt,
2095 SSMR3PutGCUIntReg,
2096 SSMR3PutGCPhys32,
2097 SSMR3PutGCPhys64,
2098 SSMR3PutGCPhys,
2099 SSMR3PutGCPtr,
2100 SSMR3PutGCUIntPtr,
2101 SSMR3PutRCPtr,
2102 SSMR3PutIOPort,
2103 SSMR3PutSel,
2104 SSMR3PutMem,
2105 SSMR3PutStrZ,
2106 SSMR3GetStruct,
2107 SSMR3GetStructEx,
2108 SSMR3GetBool,
2109 SSMR3GetBoolV,
2110 SSMR3GetU8,
2111 SSMR3GetU8V,
2112 SSMR3GetS8,
2113 SSMR3GetS8V,
2114 SSMR3GetU16,
2115 SSMR3GetU16V,
2116 SSMR3GetS16,
2117 SSMR3GetS16V,
2118 SSMR3GetU32,
2119 SSMR3GetU32V,
2120 SSMR3GetS32,
2121 SSMR3GetS32V,
2122 SSMR3GetU64,
2123 SSMR3GetU64V,
2124 SSMR3GetS64,
2125 SSMR3GetS64V,
2126 SSMR3GetU128,
2127 SSMR3GetU128V,
2128 SSMR3GetS128,
2129 SSMR3GetS128V,
2130 SSMR3GetGCPhys32,
2131 SSMR3GetGCPhys32V,
2132 SSMR3GetGCPhys64,
2133 SSMR3GetGCPhys64V,
2134 SSMR3GetGCPhys,
2135 SSMR3GetGCPhysV,
2136 SSMR3GetUInt,
2137 SSMR3GetSInt,
2138 SSMR3GetGCUInt,
2139 SSMR3GetGCUIntReg,
2140 SSMR3GetGCPtr,
2141 SSMR3GetGCUIntPtr,
2142 SSMR3GetRCPtr,
2143 SSMR3GetIOPort,
2144 SSMR3GetSel,
2145 SSMR3GetMem,
2146 SSMR3GetStrZ,
2147 SSMR3GetStrZEx,
2148 SSMR3Skip,
2149 SSMR3SkipToEndOfUnit,
2150 SSMR3SetLoadError,
2151 SSMR3SetLoadErrorV,
2152 SSMR3SetCfgError,
2153 SSMR3SetCfgErrorV,
2154 SSMR3HandleGetStatus,
2155 SSMR3HandleGetAfter,
2156 SSMR3HandleIsLiveSave,
2157 SSMR3HandleMaxDowntime,
2158 SSMR3HandleHostBits,
2159 SSMR3HandleRevision,
2160 SSMR3HandleVersion,
2161 SSMR3HandleHostOSAndArch,
2162 CFGMR3Exists,
2163 CFGMR3QueryType,
2164 CFGMR3QuerySize,
2165 CFGMR3QueryInteger,
2166 CFGMR3QueryIntegerDef,
2167 CFGMR3QueryString,
2168 CFGMR3QueryStringDef,
2169 CFGMR3QueryBytes,
2170 CFGMR3QueryU64,
2171 CFGMR3QueryU64Def,
2172 CFGMR3QueryS64,
2173 CFGMR3QueryS64Def,
2174 CFGMR3QueryU32,
2175 CFGMR3QueryU32Def,
2176 CFGMR3QueryS32,
2177 CFGMR3QueryS32Def,
2178 CFGMR3QueryU16,
2179 CFGMR3QueryU16Def,
2180 CFGMR3QueryS16,
2181 CFGMR3QueryS16Def,
2182 CFGMR3QueryU8,
2183 CFGMR3QueryU8Def,
2184 CFGMR3QueryS8,
2185 CFGMR3QueryS8Def,
2186 CFGMR3QueryBool,
2187 CFGMR3QueryBoolDef,
2188 CFGMR3QueryPort,
2189 CFGMR3QueryPortDef,
2190 CFGMR3QueryUInt,
2191 CFGMR3QueryUIntDef,
2192 CFGMR3QuerySInt,
2193 CFGMR3QuerySIntDef,
2194 CFGMR3QueryPtr,
2195 CFGMR3QueryPtrDef,
2196 CFGMR3QueryGCPtr,
2197 CFGMR3QueryGCPtrDef,
2198 CFGMR3QueryGCPtrU,
2199 CFGMR3QueryGCPtrUDef,
2200 CFGMR3QueryGCPtrS,
2201 CFGMR3QueryGCPtrSDef,
2202 CFGMR3QueryStringAlloc,
2203 CFGMR3QueryStringAllocDef,
2204 CFGMR3GetParent,
2205 CFGMR3GetChild,
2206 CFGMR3GetChildF,
2207 CFGMR3GetChildFV,
2208 CFGMR3GetFirstChild,
2209 CFGMR3GetNextChild,
2210 CFGMR3GetName,
2211 CFGMR3GetNameLen,
2212 CFGMR3AreChildrenValid,
2213 CFGMR3GetFirstValue,
2214 CFGMR3GetNextValue,
2215 CFGMR3GetValueName,
2216 CFGMR3GetValueNameLen,
2217 CFGMR3GetValueType,
2218 CFGMR3AreValuesValid,
2219 CFGMR3ValidateConfig,
2220 pdmR3DrvHlp_MMHeapFree,
2221 pdmR3DrvHlp_DBGFInfoRegister,
2222 pdmR3DrvHlp_DBGFInfoRegisterArgv,
2223 pdmR3DrvHlp_DBGFInfoDeregister,
2224 pdmR3DrvHlp_STAMRegister,
2225 pdmR3DrvHlp_STAMRegisterF,
2226 pdmR3DrvHlp_STAMRegisterV,
2227 pdmR3DrvHlp_STAMDeregister,
2228 pdmR3DrvHlp_SUPCallVMMR0Ex,
2229 pdmR3DrvHlp_USBRegisterHub,
2230 pdmR3DrvHlp_SetAsyncNotification,
2231 pdmR3DrvHlp_AsyncNotificationCompleted,
2232 pdmR3DrvHlp_ThreadCreate,
2233 PDMR3ThreadDestroy,
2234 PDMR3ThreadIAmSuspending,
2235 PDMR3ThreadIAmRunning,
2236 PDMR3ThreadSleep,
2237 PDMR3ThreadSuspend,
2238 PDMR3ThreadResume,
2239 pdmR3DrvHlp_AsyncCompletionTemplateCreate,
2240 PDMR3AsyncCompletionTemplateDestroy,
2241 PDMR3AsyncCompletionEpCreateForFile,
2242 PDMR3AsyncCompletionEpClose,
2243 PDMR3AsyncCompletionEpGetSize,
2244 PDMR3AsyncCompletionEpSetSize,
2245 PDMR3AsyncCompletionEpSetBwMgr,
2246 PDMR3AsyncCompletionEpFlush,
2247 PDMR3AsyncCompletionEpRead,
2248 PDMR3AsyncCompletionEpWrite,
2249 pdmR3DrvHlp_NetShaperAttach,
2250 pdmR3DrvHlp_NetShaperDetach,
2251 pdmR3DrvHlp_NetShaperAllocateBandwidth,
2252 pdmR3DrvHlp_LdrGetRCInterfaceSymbols,
2253 pdmR3DrvHlp_LdrGetR0InterfaceSymbols,
2254 pdmR3DrvHlp_CritSectInit,
2255 pdmR3DrvHlp_CritSectYield,
2256 pdmR3DrvHlp_CritSectEnter,
2257 pdmR3DrvHlp_CritSectEnterDebug,
2258 pdmR3DrvHlp_CritSectTryEnter,
2259 pdmR3DrvHlp_CritSectTryEnterDebug,
2260 pdmR3DrvHlp_CritSectLeave,
2261 pdmR3DrvHlp_CritSectIsOwner,
2262 pdmR3DrvHlp_CritSectIsInitialized,
2263 pdmR3DrvHlp_CritSectHasWaiters,
2264 pdmR3DrvHlp_CritSectGetRecursion,
2265 pdmR3DrvHlp_CritSectScheduleExitEvent,
2266 pdmR3DrvHlp_CritSectDelete,
2267 pdmR3DrvHlp_CallR0,
2268 pdmR3DrvHlp_BlkCacheRetain,
2269 PDMR3BlkCacheRelease,
2270 PDMR3BlkCacheClear,
2271 PDMR3BlkCacheSuspend,
2272 PDMR3BlkCacheResume,
2273 PDMR3BlkCacheIoXferComplete,
2274 PDMR3BlkCacheRead,
2275 PDMR3BlkCacheWrite,
2276 PDMR3BlkCacheFlush,
2277 PDMR3BlkCacheDiscard,
2278 pdmR3DrvHlp_VMGetSuspendReason,
2279 pdmR3DrvHlp_VMGetResumeReason,
2280 pdmR3DrvHlp_TimerSetMillies,
2281 pdmR3DrvHlp_STAMDeregisterByPrefix,
2282 pdmR3DrvHlp_QueryGenericUserObject,
2283 NULL,
2284 NULL,
2285 NULL,
2286 NULL,
2287 NULL,
2288 NULL,
2289 NULL,
2290 NULL,
2291 NULL,
2292 PDM_DRVHLPR3_VERSION /* u32TheEnd */
2293};
2294
2295/** @} */
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