VirtualBox

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

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

VMM,CFGM: Drop CFGMR3QueryPtr and CFGMR3QueryPtrDef, bugref:10053

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 88.0 KB
Line 
1/* $Id: PDMDriver.cpp 94369 2022-03-25 07:42:32Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device and Driver Manager, Driver parts.
4 */
5
6/*
7 * Copyright (C) 2006-2022 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 PPDMDRVINS pNew;
707#undef PDM_WITH_RING0_DRIVERS
708#ifdef PDM_WITH_RING0_DRIVERS
709 bool const fHyperHeap = !!(pDrv->pReg->fFlags & (PDM_DRVREG_FLAGS_R0 | PDM_DRVREG_FLAGS_RC));
710 if (fHyperHeap)
711 rc = MMHyperAlloc(pVM, cb, 64, MM_TAG_PDM_DRIVER, (void **)&pNew);
712 else
713#endif
714 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_DRIVER, cb, (void **)&pNew);
715 if (RT_SUCCESS(rc))
716 {
717 /*
718 * Initialize the instance structure (declaration order).
719 */
720 pNew->u32Version = PDM_DRVINS_VERSION;
721 pNew->iInstance = pDrv->iNextInstance;
722 pNew->Internal.s.pUp = pDrvAbove ? pDrvAbove : NULL;
723 //pNew->Internal.s.pDown = NULL;
724 pNew->Internal.s.pLun = pLun;
725 pNew->Internal.s.pDrv = pDrv;
726 pNew->Internal.s.pVMR3 = pVM;
727#ifdef PDM_WITH_RING0_DRIVERS
728 pNew->Internal.s.pVMR0 = pDrv->pReg->fFlags & PDM_DRVREG_FLAGS_R0 ? pVM->pVMR0ForCall : NIL_RTR0PTR;
729 pNew->Internal.s.pVMRC = pDrv->pReg->fFlags & PDM_DRVREG_FLAGS_RC ? pVM->pVMRC : NIL_RTRCPTR;
730#endif
731 //pNew->Internal.s.fDetaching = false;
732 pNew->Internal.s.fVMSuspended = true; /** @todo should be 'false', if driver is attached at runtime. */
733 //pNew->Internal.s.fVMReset = false;
734#ifdef PDM_WITH_RING0_DRIVERS
735 pNew->Internal.s.fHyperHeap = fHyperHeap;
736#endif
737 //pNew->Internal.s.pfnAsyncNotify = NULL;
738 pNew->Internal.s.pCfgHandle = pNode;
739 pNew->pReg = pDrv->pReg;
740 pNew->pCfg = pConfigNode;
741 pNew->pUpBase = pBaseInterface;
742 Assert(!pDrvAbove || pBaseInterface == &pDrvAbove->IBase);
743 //pNew->pDownBase = NULL;
744 //pNew->IBase.pfnQueryInterface = NULL;
745 //pNew->fTracing = 0;
746 pNew->idTracing = ++pVM->pdm.s.idTracingOther;
747 pNew->pHlpR3 = &g_pdmR3DrvHlp;
748 pNew->pvInstanceDataR3 = &pNew->achInstanceData[0];
749#ifdef PDM_WITH_RING0_DRIVERS
750 if (pDrv->pReg->fFlags & PDM_DRVREG_FLAGS_R0)
751 {
752 pNew->pvInstanceDataR0 = MMHyperR3ToR0(pVM, &pNew->achInstanceData[0]);
753 rc = PDMR3LdrGetSymbolR0(pVM, NULL, "g_pdmR0DrvHlp", &pNew->pHlpR0);
754 AssertReleaseRCReturn(rc, rc);
755 }
756# ifdef VBOX_WITH_RAW_MODE_KEEP
757 if ( (pDrv->pReg->fFlags & PDM_DRVREG_FLAGS_RC)
758 && VM_IS_RAW_MODE_ENABLED(pVM))
759 {
760 pNew->pvInstanceDataR0 = MMHyperR3ToRC(pVM, &pNew->achInstanceData[0]);
761 rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDrvHlp", &pNew->pHlpRC);
762 AssertReleaseRCReturn(rc, rc);
763 }
764# endif
765#endif
766
767 pDrv->iNextInstance++;
768 pDrv->cInstances++;
769
770 /*
771 * Link with it with the driver above / LUN.
772 */
773 if (pDrvAbove)
774 {
775 pDrvAbove->pDownBase = &pNew->IBase;
776 pDrvAbove->Internal.s.pDown = pNew;
777 }
778 else if (pLun)
779 pLun->pTop = pNew;
780 if (pLun)
781 pLun->pBottom = pNew;
782
783 /*
784 * Invoke the constructor.
785 */
786 rc = pDrv->pReg->pfnConstruct(pNew, pNew->pCfg, 0 /*fFlags*/);
787 if (RT_SUCCESS(rc))
788 {
789 AssertPtr(pNew->IBase.pfnQueryInterface);
790 Assert(pNew->IBase.pfnQueryInterface(&pNew->IBase, PDMIBASE_IID) == &pNew->IBase);
791
792 /* Success! */
793 *ppBaseInterface = &pNew->IBase;
794 if (pLun)
795 Log(("PDM: Attached driver %p:'%s'/%d to LUN#%d on device '%s'/%d, pDrvAbove=%p:'%s'/%d\n",
796 pNew, pDrv->pReg->szName, pNew->iInstance,
797 pLun->iLun,
798 pLun->pDevIns ? pLun->pDevIns->pReg->szName : pLun->pUsbIns->pReg->szName,
799 pLun->pDevIns ? pLun->pDevIns->iInstance : pLun->pUsbIns->iInstance,
800 pDrvAbove, pDrvAbove ? pDrvAbove->pReg->szName : "", pDrvAbove ? pDrvAbove->iInstance : UINT32_MAX));
801 else
802 Log(("PDM: Attached driver %p:'%s'/%d, pDrvAbove=%p:'%s'/%d\n",
803 pNew, pDrv->pReg->szName, pNew->iInstance,
804 pDrvAbove, pDrvAbove ? pDrvAbove->pReg->szName : "", pDrvAbove ? pDrvAbove->iInstance : UINT32_MAX));
805 }
806 else
807 {
808 pdmR3DrvDestroyChain(pNew, PDM_TACH_FLAGS_NO_CALLBACKS);
809 if (rc == VERR_VERSION_MISMATCH)
810 rc = VERR_PDM_DRIVER_VERSION_MISMATCH;
811 }
812 }
813 else
814 AssertMsgFailed(("Failed to allocate %d bytes for instantiating driver '%s'! rc=%Rrc\n", cb, pszName, rc));
815 }
816 else
817 AssertMsgFailed(("Failed to create Config node! rc=%Rrc\n", rc));
818 }
819 else if (pDrv)
820 {
821 AssertMsgFailed(("Too many instances of driver '%s', max is %u\n", pszName, pDrv->pReg->cMaxInstances));
822 rc = VERR_PDM_TOO_MANY_DRIVER_INSTANCES;
823 }
824 else
825 {
826 AssertMsgFailed(("Driver '%s' wasn't found!\n", pszName));
827 rc = VERR_PDM_DRIVER_NOT_FOUND;
828 }
829 MMR3HeapFree(pszName);
830 }
831 else
832 {
833 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
834 rc = VERR_PDM_CFG_MISSING_DRIVER_NAME;
835 else
836 AssertMsgFailed(("Query for string value of \"Driver\" -> %Rrc\n", rc));
837 }
838 return rc;
839}
840
841
842/**
843 * Detaches a driver from whatever it's attached to.
844 * This will of course lead to the destruction of the driver and all drivers below it in the chain.
845 *
846 * @returns VINF_SUCCESS
847 * @param pDrvIns The driver instance to detach.
848 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
849 */
850int pdmR3DrvDetach(PPDMDRVINS pDrvIns, uint32_t fFlags)
851{
852 PDMDRV_ASSERT_DRVINS(pDrvIns);
853 LogFlow(("pdmR3DrvDetach: pDrvIns=%p '%s'/%d\n", pDrvIns, pDrvIns->pReg->szName, pDrvIns->iInstance));
854 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
855
856 /*
857 * Check that we're not doing this recursively, that could have unwanted sideeffects!
858 */
859 if (pDrvIns->Internal.s.fDetaching)
860 {
861 AssertMsgFailed(("Recursive detach! '%s'/%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
862 return VINF_SUCCESS;
863 }
864
865 /*
866 * Check that we actually can detach this instance.
867 * The requirement is that the driver/device above has a detach method.
868 */
869 if ( pDrvIns->Internal.s.pUp
870 ? !pDrvIns->Internal.s.pUp->pReg->pfnDetach
871 : pDrvIns->Internal.s.pLun->pDevIns
872 ? !pDrvIns->Internal.s.pLun->pDevIns->pReg->pfnDetach
873 : !pDrvIns->Internal.s.pLun->pUsbIns->pReg->pfnDriverDetach
874 )
875 {
876 AssertMsgFailed(("Cannot detach driver instance because the driver/device above doesn't support it!\n"));
877 return VERR_PDM_DRIVER_DETACH_NOT_POSSIBLE;
878 }
879
880 /*
881 * Join paths with pdmR3DrvDestroyChain.
882 */
883 pdmR3DrvDestroyChain(pDrvIns, fFlags);
884 return VINF_SUCCESS;
885}
886
887
888/**
889 * Destroys a driver chain starting with the specified driver.
890 *
891 * This is used when unplugging a device at run time.
892 *
893 * @param pDrvIns Pointer to the driver instance to start with.
894 * @param fFlags PDM_TACH_FLAGS_NOT_HOT_PLUG, PDM_TACH_FLAGS_NO_CALLBACKS
895 * or 0.
896 */
897void pdmR3DrvDestroyChain(PPDMDRVINS pDrvIns, uint32_t fFlags)
898{
899 PVM pVM = pDrvIns->Internal.s.pVMR3;
900 VM_ASSERT_EMT(pVM);
901
902 /*
903 * Detach the bottommost driver until we've detached pDrvIns.
904 */
905 pDrvIns->Internal.s.fDetaching = true;
906 PPDMDRVINS pCur;
907 do
908 {
909 /* find the driver to detach. */
910 pCur = pDrvIns;
911 while (pCur->Internal.s.pDown)
912 pCur = pCur->Internal.s.pDown;
913 LogFlow(("pdmR3DrvDestroyChain: pCur=%p '%s'/%d\n", pCur, pCur->pReg->szName, pCur->iInstance));
914
915 /*
916 * Unlink it and notify parent.
917 */
918 pCur->Internal.s.fDetaching = true;
919
920 PPDMLUN pLun = pCur->Internal.s.pLun;
921 Assert(pLun->pBottom == pCur);
922 pLun->pBottom = pCur->Internal.s.pUp;
923
924 if (pCur->Internal.s.pUp)
925 {
926 /* driver parent */
927 PPDMDRVINS pParent = pCur->Internal.s.pUp;
928 pCur->Internal.s.pUp = NULL;
929 pParent->Internal.s.pDown = NULL;
930
931 if (!(fFlags & PDM_TACH_FLAGS_NO_CALLBACKS) && pParent->pReg->pfnDetach)
932 pParent->pReg->pfnDetach(pParent, fFlags);
933
934 pParent->pDownBase = NULL;
935 }
936 else
937 {
938 /* device parent */
939 Assert(pLun->pTop == pCur);
940 pLun->pTop = NULL;
941 if (!(fFlags & PDM_TACH_FLAGS_NO_CALLBACKS))
942 {
943 if (pLun->pDevIns)
944 {
945 if (pLun->pDevIns->pReg->pfnDetach)
946 {
947 PDMCritSectEnter(pVM, pLun->pDevIns->pCritSectRoR3, VERR_IGNORED);
948 pLun->pDevIns->pReg->pfnDetach(pLun->pDevIns, pLun->iLun, fFlags);
949 PDMCritSectLeave(pVM, pLun->pDevIns->pCritSectRoR3);
950 }
951 }
952 else
953 {
954 if (pLun->pUsbIns->pReg->pfnDriverDetach)
955 {
956 /** @todo USB device locking? */
957 pLun->pUsbIns->pReg->pfnDriverDetach(pLun->pUsbIns, pLun->iLun, fFlags);
958 }
959 }
960 }
961 }
962
963 /*
964 * Call destructor.
965 */
966 pCur->pUpBase = NULL;
967 if (pCur->pReg->pfnDestruct)
968 pCur->pReg->pfnDestruct(pCur);
969 pCur->Internal.s.pDrv->cInstances--;
970
971 /*
972 * Free all resources allocated by the driver.
973 */
974 /* Queues. */
975 int rc = PDMR3QueueDestroyDriver(pVM, pCur);
976 AssertRC(rc);
977
978 /* Timers. */
979 rc = TMR3TimerDestroyDriver(pVM, pCur);
980 AssertRC(rc);
981
982 /* SSM data units. */
983 rc = SSMR3DeregisterDriver(pVM, pCur, NULL, 0);
984 AssertRC(rc);
985
986 /* PDM threads. */
987 rc = pdmR3ThreadDestroyDriver(pVM, pCur);
988 AssertRC(rc);
989
990 /* Info handlers. */
991 rc = DBGFR3InfoDeregisterDriver(pVM, pCur, NULL);
992 AssertRC(rc);
993
994 /* PDM critsects. */
995 rc = pdmR3CritSectBothDeleteDriver(pVM, pCur);
996 AssertRC(rc);
997
998 /* Block caches. */
999 PDMR3BlkCacheReleaseDriver(pVM, pCur);
1000
1001#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
1002 /* Completion templates.*/
1003 pdmR3AsyncCompletionTemplateDestroyDriver(pVM, pCur);
1004#endif
1005
1006 /* Finally, the driver it self. */
1007#ifdef PDM_WITH_RING0_DRIVERS
1008 bool const fHyperHeap = pCur->Internal.s.fHyperHeap;
1009#endif
1010 ASMMemFill32(pCur, RT_UOFFSETOF_DYN(PDMDRVINS, achInstanceData[pCur->pReg->cbInstance]), 0xdeadd0d0);
1011#ifdef PDM_WITH_RING0_DRIVERS
1012 if (fHyperHeap)
1013 MMHyperFree(pVM, pCur);
1014 else
1015#endif
1016 MMR3HeapFree(pCur);
1017
1018 } while (pCur != pDrvIns);
1019}
1020
1021
1022
1023
1024/** @name Driver Helpers
1025 * @{
1026 */
1027
1028/** @interface_method_impl{PDMDRVHLPR3,pfnAttach} */
1029static DECLCALLBACK(int) pdmR3DrvHlp_Attach(PPDMDRVINS pDrvIns, uint32_t fFlags, PPDMIBASE *ppBaseInterface)
1030{
1031 PDMDRV_ASSERT_DRVINS(pDrvIns);
1032 PVM pVM = pDrvIns->Internal.s.pVMR3;
1033 VM_ASSERT_EMT(pVM);
1034 LogFlow(("pdmR3DrvHlp_Attach: caller='%s'/%d: fFlags=%#x\n", pDrvIns->pReg->szName, pDrvIns->iInstance, fFlags));
1035 Assert(!(fFlags & ~(PDM_TACH_FLAGS_NOT_HOT_PLUG)));
1036 RT_NOREF_PV(fFlags);
1037
1038 /*
1039 * Check that there isn't anything attached already.
1040 */
1041 int rc;
1042 if (!pDrvIns->Internal.s.pDown)
1043 {
1044 Assert(pDrvIns->Internal.s.pLun->pBottom == pDrvIns);
1045
1046 /*
1047 * Get the attached driver configuration.
1048 */
1049 PCFGMNODE pNode = CFGMR3GetChild(pDrvIns->Internal.s.pCfgHandle, "AttachedDriver");
1050 if (pNode)
1051 rc = pdmR3DrvInstantiate(pVM, pNode, &pDrvIns->IBase, pDrvIns, pDrvIns->Internal.s.pLun, ppBaseInterface);
1052 else
1053 rc = VERR_PDM_NO_ATTACHED_DRIVER;
1054 }
1055 else
1056 {
1057 AssertMsgFailed(("Already got a driver attached. The driver should keep track of such things!\n"));
1058 rc = VERR_PDM_DRIVER_ALREADY_ATTACHED;
1059 }
1060
1061 LogFlow(("pdmR3DrvHlp_Attach: caller='%s'/%d: return %Rrc\n",
1062 pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1063 return rc;
1064}
1065
1066
1067/** @interface_method_impl{PDMDRVHLPR3,pfnDetach} */
1068static DECLCALLBACK(int) pdmR3DrvHlp_Detach(PPDMDRVINS pDrvIns, uint32_t fFlags)
1069{
1070 PDMDRV_ASSERT_DRVINS(pDrvIns);
1071 LogFlow(("pdmR3DrvHlp_Detach: caller='%s'/%d: fFlags=%#x\n",
1072 pDrvIns->pReg->szName, pDrvIns->iInstance, fFlags));
1073 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1074
1075 /*
1076 * Anything attached?
1077 */
1078 int rc;
1079 if (pDrvIns->Internal.s.pDown)
1080 rc = pdmR3DrvDetach(pDrvIns->Internal.s.pDown, fFlags);
1081 else
1082 {
1083 AssertMsgFailed(("Nothing attached!\n"));
1084 rc = VERR_PDM_NO_DRIVER_ATTACHED;
1085 }
1086
1087 LogFlow(("pdmR3DrvHlp_Detach: caller='%s'/%d: returns %Rrc\n",
1088 pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1089 return rc;
1090}
1091
1092
1093/** @interface_method_impl{PDMDRVHLPR3,pfnDetachSelf} */
1094static DECLCALLBACK(int) pdmR3DrvHlp_DetachSelf(PPDMDRVINS pDrvIns, uint32_t fFlags)
1095{
1096 PDMDRV_ASSERT_DRVINS(pDrvIns);
1097 LogFlow(("pdmR3DrvHlp_DetachSelf: caller='%s'/%d: fFlags=%#x\n",
1098 pDrvIns->pReg->szName, pDrvIns->iInstance, fFlags));
1099 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1100
1101 int rc = pdmR3DrvDetach(pDrvIns, fFlags);
1102
1103 LogFlow(("pdmR3DrvHlp_Detach: returns %Rrc\n", rc)); /* pDrvIns is freed by now. */
1104 return rc;
1105}
1106
1107
1108/** @interface_method_impl{PDMDRVHLPR3,pfnMountPrepare} */
1109static DECLCALLBACK(int) pdmR3DrvHlp_MountPrepare(PPDMDRVINS pDrvIns, const char *pszFilename, const char *pszCoreDriver)
1110{
1111 PDMDRV_ASSERT_DRVINS(pDrvIns);
1112 LogFlow(("pdmR3DrvHlp_MountPrepare: caller='%s'/%d: pszFilename=%p:{%s} pszCoreDriver=%p:{%s}\n",
1113 pDrvIns->pReg->szName, pDrvIns->iInstance, pszFilename, pszFilename, pszCoreDriver, pszCoreDriver));
1114 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1115
1116 /*
1117 * Do the caller have anything attached below itself?
1118 */
1119 if (pDrvIns->Internal.s.pDown)
1120 {
1121 AssertMsgFailed(("Cannot prepare a mount when something's attached to you!\n"));
1122 return VERR_PDM_DRIVER_ALREADY_ATTACHED;
1123 }
1124
1125 /*
1126 * We're asked to prepare, so we'll start off by nuking the
1127 * attached configuration tree.
1128 */
1129 PCFGMNODE pNode = CFGMR3GetChild(pDrvIns->Internal.s.pCfgHandle, "AttachedDriver");
1130 if (pNode)
1131 CFGMR3RemoveNode(pNode);
1132
1133 /*
1134 * If there is no core driver, we'll have to probe for it.
1135 */
1136 if (!pszCoreDriver)
1137 {
1138 /** @todo implement image probing. */
1139 AssertReleaseMsgFailed(("Not implemented!\n"));
1140 return VERR_NOT_IMPLEMENTED;
1141 }
1142
1143 /*
1144 * Construct the basic attached driver configuration.
1145 */
1146 int rc = CFGMR3InsertNode(pDrvIns->Internal.s.pCfgHandle, "AttachedDriver", &pNode);
1147 if (RT_SUCCESS(rc))
1148 {
1149 rc = CFGMR3InsertString(pNode, "Driver", pszCoreDriver);
1150 if (RT_SUCCESS(rc))
1151 {
1152 PCFGMNODE pCfg;
1153 rc = CFGMR3InsertNode(pNode, "Config", &pCfg);
1154 if (RT_SUCCESS(rc))
1155 {
1156 rc = CFGMR3InsertString(pCfg, "Path", pszFilename);
1157 if (RT_SUCCESS(rc))
1158 {
1159 LogFlow(("pdmR3DrvHlp_MountPrepare: caller='%s'/%d: returns %Rrc (Driver=%s)\n",
1160 pDrvIns->pReg->szName, pDrvIns->iInstance, rc, pszCoreDriver));
1161 return rc;
1162 }
1163 else
1164 AssertMsgFailed(("Path string insert failed, rc=%Rrc\n", rc));
1165 }
1166 else
1167 AssertMsgFailed(("Config node failed, rc=%Rrc\n", rc));
1168 }
1169 else
1170 AssertMsgFailed(("Driver string insert failed, rc=%Rrc\n", rc));
1171 CFGMR3RemoveNode(pNode);
1172 }
1173 else
1174 AssertMsgFailed(("AttachedDriver node insert failed, rc=%Rrc\n", rc));
1175
1176 LogFlow(("pdmR3DrvHlp_MountPrepare: caller='%s'/%d: returns %Rrc\n",
1177 pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1178 return rc;
1179}
1180
1181
1182/** @interface_method_impl{PDMDRVHLPR3,pfnAssertEMT} */
1183static DECLCALLBACK(bool) pdmR3DrvHlp_AssertEMT(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), "AssertEMT '%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,pfnAssertOther} */
1199static DECLCALLBACK(bool) pdmR3DrvHlp_AssertOther(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)
1200{
1201 PDMDRV_ASSERT_DRVINS(pDrvIns);
1202 if (!VM_IS_EMT(pDrvIns->Internal.s.pVMR3))
1203 return true;
1204
1205 char szMsg[100];
1206 RTStrPrintf(szMsg, sizeof(szMsg), "AssertOther '%s'/%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance);
1207 RTAssertMsg1Weak(szMsg, iLine, pszFile, pszFunction);
1208 AssertBreakpoint();
1209 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1210 return false;
1211}
1212
1213
1214/** @interface_method_impl{PDMDRVHLPR3,pfnVMSetErrorV} */
1215static DECLCALLBACK(int) pdmR3DrvHlp_VMSetErrorV(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
1216{
1217 PDMDRV_ASSERT_DRVINS(pDrvIns);
1218 int rc2 = VMSetErrorV(pDrvIns->Internal.s.pVMR3, rc, RT_SRC_POS_ARGS, pszFormat, va); Assert(rc2 == rc); NOREF(rc2);
1219 return rc;
1220}
1221
1222
1223/** @interface_method_impl{PDMDRVHLPR3,pfnVMSetRuntimeErrorV} */
1224static DECLCALLBACK(int) pdmR3DrvHlp_VMSetRuntimeErrorV(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)
1225{
1226 PDMDRV_ASSERT_DRVINS(pDrvIns);
1227 int rc = VMSetRuntimeErrorV(pDrvIns->Internal.s.pVMR3, fFlags, pszErrorId, pszFormat, va);
1228 return rc;
1229}
1230
1231
1232/** @interface_method_impl{PDMDRVHLPR3,pfnVMState} */
1233static DECLCALLBACK(VMSTATE) pdmR3DrvHlp_VMState(PPDMDRVINS pDrvIns)
1234{
1235 PDMDRV_ASSERT_DRVINS(pDrvIns);
1236
1237 VMSTATE enmVMState = VMR3GetState(pDrvIns->Internal.s.pVMR3);
1238
1239 LogFlow(("pdmR3DrvHlp_VMState: caller='%s'/%d: returns %d (%s)\n", pDrvIns->pReg->szName, pDrvIns->iInstance,
1240 enmVMState, VMR3GetStateName(enmVMState)));
1241 return enmVMState;
1242}
1243
1244
1245/** @interface_method_impl{PDMDRVHLPR3,pfnVMTeleportedAndNotFullyResumedYet} */
1246static DECLCALLBACK(bool) pdmR3DrvHlp_VMTeleportedAndNotFullyResumedYet(PPDMDRVINS pDrvIns)
1247{
1248 PDMDRV_ASSERT_DRVINS(pDrvIns);
1249
1250 bool fRc = VMR3TeleportedAndNotFullyResumedYet(pDrvIns->Internal.s.pVMR3);
1251
1252 LogFlow(("pdmR3DrvHlp_VMState: caller='%s'/%d: returns %RTbool)\n", pDrvIns->pReg->szName, pDrvIns->iInstance,
1253 fRc));
1254 return fRc;
1255}
1256
1257
1258/** @interface_method_impl{PDMDRVHLPR3,pfnGetSupDrvSession} */
1259static DECLCALLBACK(PSUPDRVSESSION) pdmR3DrvHlp_GetSupDrvSession(PPDMDRVINS pDrvIns)
1260{
1261 PDMDRV_ASSERT_DRVINS(pDrvIns);
1262
1263 PSUPDRVSESSION pSession = pDrvIns->Internal.s.pVMR3->pSession;
1264 LogFlow(("pdmR3DrvHlp_GetSupDrvSession: caller='%s'/%d: returns %p)\n", pDrvIns->pReg->szName, pDrvIns->iInstance,
1265 pSession));
1266 return pSession;
1267}
1268
1269
1270/** @interface_method_impl{PDMDRVHLPR3,pfnQueueCreate} */
1271static DECLCALLBACK(int) pdmR3DrvHlp_QueueCreate(PPDMDRVINS pDrvIns, uint32_t cbItem, uint32_t cItems, uint32_t cMilliesInterval,
1272 PFNPDMQUEUEDRV pfnCallback, const char *pszName, PDMQUEUEHANDLE *phQueue)
1273{
1274 PDMDRV_ASSERT_DRVINS(pDrvIns);
1275 LogFlow(("pdmR3DrvHlp_PDMQueueCreate: caller='%s'/%d: cbItem=%d cItems=%d cMilliesInterval=%d pfnCallback=%p pszName=%p:{%s} phQueue=%p\n",
1276 pDrvIns->pReg->szName, pDrvIns->iInstance, cbItem, cItems, cMilliesInterval, pfnCallback, pszName, pszName, phQueue));
1277 PVM pVM = pDrvIns->Internal.s.pVMR3;
1278 VM_ASSERT_EMT(pVM);
1279
1280 if (pDrvIns->iInstance > 0)
1281 {
1282 pszName = MMR3HeapAPrintf(pVM, MM_TAG_PDM_DRIVER_DESC, "%s_%u", pszName, pDrvIns->iInstance);
1283 AssertLogRelReturn(pszName, VERR_NO_MEMORY);
1284 }
1285
1286 int rc = PDMR3QueueCreateDriver(pVM, pDrvIns, cbItem, cItems, cMilliesInterval, pfnCallback, pszName, phQueue);
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(pDrvIns->Internal.s.pVMR3, hQueue, pDrvIns);
1297}
1298
1299
1300/** @interface_method_impl{PDMDRVHLPR3,pfnQueueInsert} */
1301static DECLCALLBACK(int) pdmR3DrvHlp_QueueInsert(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)
1302{
1303 return PDMQueueInsert(pDrvIns->Internal.s.pVMR3, hQueue, pDrvIns, pItem);
1304}
1305
1306
1307/** @interface_method_impl{PDMDRVHLPR3,pfnQueueFlushIfNecessary} */
1308static DECLCALLBACK(bool) pdmR3DrvHlp_QueueFlushIfNecessary(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue)
1309{
1310 return PDMQueueFlushIfNecessary(pDrvIns->Internal.s.pVMR3, hQueue, pDrvIns) == VINF_SUCCESS;
1311}
1312
1313
1314/** @interface_method_impl{PDMDRVHLPR3,pfnTMGetVirtualFreq} */
1315static DECLCALLBACK(uint64_t) pdmR3DrvHlp_TMGetVirtualFreq(PPDMDRVINS pDrvIns)
1316{
1317 PDMDRV_ASSERT_DRVINS(pDrvIns);
1318
1319 return TMVirtualGetFreq(pDrvIns->Internal.s.pVMR3);
1320}
1321
1322
1323/** @interface_method_impl{PDMDRVHLPR3,pfnTMGetVirtualTime} */
1324static DECLCALLBACK(uint64_t) pdmR3DrvHlp_TMGetVirtualTime(PPDMDRVINS pDrvIns)
1325{
1326 PDMDRV_ASSERT_DRVINS(pDrvIns);
1327
1328 return TMVirtualGet(pDrvIns->Internal.s.pVMR3);
1329}
1330
1331
1332/** @interface_method_impl{PDMDRVHLPR3,pfnTimerCreate} */
1333static DECLCALLBACK(int) pdmR3DrvHlp_TimerCreate(PPDMDRVINS pDrvIns, TMCLOCK enmClock, PFNTMTIMERDRV pfnCallback, void *pvUser,
1334 uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer)
1335{
1336 PDMDRV_ASSERT_DRVINS(pDrvIns);
1337 LogFlow(("pdmR3DrvHlp_TimerCreate: caller='%s'/%d: enmClock=%d pfnCallback=%p pvUser=%p fFlags=%#x pszDesc=%p:{%s} phTimer=%p\n",
1338 pDrvIns->pReg->szName, pDrvIns->iInstance, enmClock, pfnCallback, pvUser, fFlags, pszDesc, pszDesc, phTimer));
1339
1340 /* Mangle the timer name if there are more than once instance of this driver. */
1341 char szName[32];
1342 AssertReturn(strlen(pszDesc) < sizeof(szName) - 3, VERR_INVALID_NAME);
1343 if (pDrvIns->iInstance > 0)
1344 {
1345 RTStrPrintf(szName, sizeof(szName), "%s[%u]", pszDesc, pDrvIns->iInstance);
1346 pszDesc = szName;
1347 }
1348
1349 /* Clear the ring-0 flag if the driver isn't configured for ring-0. */
1350 if (fFlags & TMTIMER_FLAGS_RING0)
1351 {
1352 AssertReturn(!(fFlags & TMTIMER_FLAGS_NO_RING0), VERR_INVALID_FLAGS);
1353 Assert(pDrvIns->Internal.s.pDrv->pReg->fFlags & PDM_DRVREG_FLAGS_R0);
1354#ifdef PDM_WITH_RING0_DRIVERS
1355 if (!(pDrvIns->Internal.s.fIntFlags & PDMDRVINSINT_FLAGS_R0_ENABLED)) /** @todo PDMDRVINSINT_FLAGS_R0_ENABLED? */
1356#endif
1357 fFlags = (fFlags & ~TMTIMER_FLAGS_RING0) | TMTIMER_FLAGS_NO_RING0;
1358 }
1359 else
1360 fFlags |= TMTIMER_FLAGS_NO_RING0;
1361
1362 int rc = TMR3TimerCreateDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, phTimer);
1363
1364 LogFlow(("pdmR3DrvHlp_TMTimerCreate: caller='%s'/%d: returns %Rrc *phTimer=%p\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc, *phTimer));
1365 return rc;
1366}
1367
1368
1369/** @interface_method_impl{PDMDRVHLPR3,pfnTimerDestroy} */
1370static DECLCALLBACK(int) pdmR3DrvHlp_TimerDestroy(PPDMDRVINS pDrvIns, TMTIMERHANDLE hTimer)
1371{
1372 PDMDRV_ASSERT_DRVINS(pDrvIns);
1373 LogFlow(("pdmR3DrvHlp_TimerDestroy: caller='%s'/%d: hTimer=%RX64\n",
1374 pDrvIns->pReg->szName, pDrvIns->iInstance, hTimer));
1375
1376 int rc = TMR3TimerDestroy(pDrvIns->Internal.s.pVMR3, hTimer);
1377
1378 LogFlow(("pdmR3DrvHlp_TimerDestroy: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1379 return rc;
1380}
1381
1382
1383/** @interface_method_impl{PDMDRVHLPR3,pfnTimerSetMillies} */
1384static DECLCALLBACK(int) pdmR3DrvHlp_TimerSetMillies(PPDMDRVINS pDrvIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext)
1385{
1386 PDMDRV_ASSERT_DRVINS(pDrvIns);
1387 return TMTimerSetMillies(pDrvIns->Internal.s.pVMR3, hTimer, cMilliesToNext);
1388}
1389
1390
1391/** @interface_method_impl{PDMDRVHLPR3,pfnSSMRegister} */
1392static DECLCALLBACK(int) pdmR3DrvHlp_SSMRegister(PPDMDRVINS pDrvIns, uint32_t uVersion, size_t cbGuess,
1393 PFNSSMDRVLIVEPREP pfnLivePrep, PFNSSMDRVLIVEEXEC pfnLiveExec, PFNSSMDRVLIVEVOTE pfnLiveVote,
1394 PFNSSMDRVSAVEPREP pfnSavePrep, PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVSAVEDONE pfnSaveDone,
1395 PFNSSMDRVLOADPREP pfnLoadPrep, PFNSSMDRVLOADEXEC pfnLoadExec, PFNSSMDRVLOADDONE pfnLoadDone)
1396{
1397 PDMDRV_ASSERT_DRVINS(pDrvIns);
1398 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1399 LogFlow(("pdmR3DrvHlp_SSMRegister: caller='%s'/%d: uVersion=%#x cbGuess=%#x \n"
1400 " pfnLivePrep=%p pfnLiveExec=%p pfnLiveVote=%p pfnSavePrep=%p pfnSaveExec=%p pfnSaveDone=%p pszLoadPrep=%p pfnLoadExec=%p pfnLoaddone=%p\n",
1401 pDrvIns->pReg->szName, pDrvIns->iInstance, uVersion, cbGuess,
1402 pfnLivePrep, pfnLiveExec, pfnLiveVote,
1403 pfnSavePrep, pfnSaveExec, pfnSaveDone, pfnLoadPrep, pfnLoadExec, pfnLoadDone));
1404
1405 int rc = SSMR3RegisterDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, pDrvIns->pReg->szName, pDrvIns->iInstance,
1406 uVersion, cbGuess,
1407 pfnLivePrep, pfnLiveExec, pfnLiveVote,
1408 pfnSavePrep, pfnSaveExec, pfnSaveDone,
1409 pfnLoadPrep, pfnLoadExec, pfnLoadDone);
1410
1411 LogFlow(("pdmR3DrvHlp_SSMRegister: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1412 return rc;
1413}
1414
1415
1416/** @interface_method_impl{PDMDRVHLPR3,pfnSSMDeregister} */
1417static DECLCALLBACK(int) pdmR3DrvHlp_SSMDeregister(PPDMDRVINS pDrvIns, const char *pszName, uint32_t uInstance)
1418{
1419 PDMDRV_ASSERT_DRVINS(pDrvIns);
1420 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1421 LogFlow(("pdmR3DrvHlp_SSMDeregister: caller='%s'/%d: pszName=%p:{%s} uInstance=%#x\n",
1422 pDrvIns->pReg->szName, pDrvIns->iInstance, pszName, pszName, uInstance));
1423
1424 int rc = SSMR3DeregisterDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, pszName, uInstance);
1425
1426 LogFlow(("pdmR3DrvHlp_SSMDeregister: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1427 return rc;
1428}
1429
1430
1431/** @interface_method_impl{PDMDRVHLPR3,pfnMMHeapFree} */
1432static DECLCALLBACK(void) pdmR3DrvHlp_MMHeapFree(PPDMDRVINS pDrvIns, void *pv)
1433{
1434 PDMDRV_ASSERT_DRVINS(pDrvIns); RT_NOREF(pDrvIns);
1435 LogFlow(("pdmR3DrvHlp_MMHeapFree: caller='%s'/%d: pv=%p\n",
1436 pDrvIns->pReg->szName, pDrvIns->iInstance, pv));
1437
1438 MMR3HeapFree(pv);
1439
1440 LogFlow(("pdmR3DrvHlp_MMHeapFree: caller='%s'/%d: returns\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
1441}
1442
1443
1444/** @interface_method_impl{PDMDRVHLPR3,pfnDBGFInfoRegister} */
1445static DECLCALLBACK(int) pdmR3DrvHlp_DBGFInfoRegister(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDRV pfnHandler)
1446{
1447 PDMDRV_ASSERT_DRVINS(pDrvIns);
1448 LogFlow(("pdmR3DrvHlp_DBGFInfoRegister: caller='%s'/%d: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p\n",
1449 pDrvIns->pReg->szName, pDrvIns->iInstance, pszName, pszName, pszDesc, pszDesc, pfnHandler));
1450
1451 int rc = DBGFR3InfoRegisterDriver(pDrvIns->Internal.s.pVMR3, pszName, pszDesc, pfnHandler, pDrvIns);
1452
1453 LogFlow(("pdmR3DrvHlp_DBGFInfoRegister: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1454 return rc;
1455}
1456
1457
1458/** @interface_method_impl{PDMDRVHLPR3,pfnDBGFInfoRegisterArgv} */
1459static DECLCALLBACK(int) pdmR3DrvHlp_DBGFInfoRegisterArgv(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVDRV pfnHandler)
1460{
1461 PDMDRV_ASSERT_DRVINS(pDrvIns);
1462 LogFlow(("pdmR3DrvHlp_DBGFInfoRegisterArgv: caller='%s'/%d: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p\n",
1463 pDrvIns->pReg->szName, pDrvIns->iInstance, pszName, pszName, pszDesc, pszDesc, pfnHandler));
1464
1465 int rc = DBGFR3InfoRegisterDriverArgv(pDrvIns->Internal.s.pVMR3, pszName, pszDesc, pfnHandler, pDrvIns);
1466
1467 LogFlow(("pdmR3DrvHlp_DBGFInfoRegisterArgv: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1468 return rc;
1469}
1470
1471
1472/** @interface_method_impl{PDMDRVHLPR3,pfnDBGFInfoDeregister} */
1473static DECLCALLBACK(int) pdmR3DrvHlp_DBGFInfoDeregister(PPDMDRVINS pDrvIns, const char *pszName)
1474{
1475 PDMDRV_ASSERT_DRVINS(pDrvIns);
1476 LogFlow(("pdmR3DrvHlp_DBGFInfoDeregister: caller='%s'/%d: pszName=%p:{%s}\n",
1477 pDrvIns->pReg->szName, pDrvIns->iInstance, pszName, pszName));
1478
1479 int rc = DBGFR3InfoDeregisterDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, pszName);
1480
1481 LogFlow(("pdmR3DrvHlp_DBGFInfoDeregister: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1482
1483 return rc;
1484}
1485
1486
1487/** @interface_method_impl{PDMDRVHLPR3,pfnSTAMRegister} */
1488static DECLCALLBACK(void) pdmR3DrvHlp_STAMRegister(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, const char *pszName,
1489 STAMUNIT enmUnit, const char *pszDesc)
1490{
1491 PDMDRV_ASSERT_DRVINS(pDrvIns);
1492 PVM pVM = pDrvIns->Internal.s.pVMR3;
1493 VM_ASSERT_EMT(pVM);
1494
1495#ifdef VBOX_WITH_STATISTICS /** @todo rework this to always be compiled in */
1496 if (*pszName == '/')
1497 STAM_REG(pDrvIns->Internal.s.pVMR3, pvSample, enmType, pszName, enmUnit, pszDesc);
1498 else
1499 STAMR3RegisterF(pVM, pvSample, enmType, STAMVISIBILITY_ALWAYS, enmUnit, pszDesc,
1500 "/Drivers/%s-%u/%s", pDrvIns->pReg->szName, pDrvIns->iInstance, pszName);
1501#else
1502 RT_NOREF(pDrvIns, pvSample, enmType, pszName, enmUnit, pszDesc, pVM);
1503#endif
1504}
1505
1506
1507/** @interface_method_impl{PDMDRVHLPR3,pfnSTAMRegisterV} */
1508static DECLCALLBACK(void) pdmR3DrvHlp_STAMRegisterV(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
1509 STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list args)
1510{
1511 PDMDRV_ASSERT_DRVINS(pDrvIns);
1512 PVM pVM = pDrvIns->Internal.s.pVMR3;
1513 VM_ASSERT_EMT(pVM);
1514
1515 int rc;
1516 if (*pszName == '/')
1517 rc = STAMR3RegisterV(pVM, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, args);
1518 else
1519 {
1520 /* We need to format it to check whether it starts with a
1521 slash or not (will rework this later). */
1522 char szFormatted[2048];
1523 ssize_t cchBase = RTStrPrintf2(szFormatted, sizeof(szFormatted) - 1024, "/Drivers/%s-%u/",
1524 pDrvIns->pReg->szName, pDrvIns->iInstance);
1525 AssertReturnVoid(cchBase > 0);
1526
1527 ssize_t cch2 = RTStrPrintf2V(&szFormatted[cchBase], sizeof(szFormatted) - cchBase, pszName, args);
1528 AssertReturnVoid(cch2 > 0);
1529
1530 rc = STAMR3Register(pVM, pvSample, enmType, enmVisibility,
1531 &szFormatted[szFormatted[cchBase] == '/' ? cchBase : 0], enmUnit, pszDesc);
1532 }
1533 AssertRC(rc);
1534}
1535
1536
1537/** @interface_method_impl{PDMDRVHLPR3,pfnSTAMRegisterF} */
1538static DECLCALLBACK(void) pdmR3DrvHlp_STAMRegisterF(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
1539 STAMUNIT enmUnit, const char *pszDesc, const char *pszName, ...)
1540{
1541 va_list va;
1542 va_start(va, pszName);
1543 pdmR3DrvHlp_STAMRegisterV(pDrvIns, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, va);
1544 va_end(va);
1545}
1546
1547
1548/** @interface_method_impl{PDMDRVHLPR3,pfnSTAMDeregister} */
1549static DECLCALLBACK(int) pdmR3DrvHlp_STAMDeregister(PPDMDRVINS pDrvIns, void *pvSample)
1550{
1551 PDMDRV_ASSERT_DRVINS(pDrvIns);
1552 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1553
1554 return STAMR3DeregisterByAddr(pDrvIns->Internal.s.pVMR3->pUVM, pvSample);
1555}
1556
1557
1558/** @interface_method_impl{PDMDRVHLPR3,pfnSTAMDeregisterByPrefix} */
1559static DECLCALLBACK(int) pdmR3DrvHlp_STAMDeregisterByPrefix(PPDMDRVINS pDrvIns, const char *pszPrefix)
1560{
1561 PDMDRV_ASSERT_DRVINS(pDrvIns);
1562
1563 if (*pszPrefix == '/')
1564 return STAMR3DeregisterByPrefix(pDrvIns->Internal.s.pVMR3->pUVM, pszPrefix);
1565
1566 char szTmp[2048];
1567 ssize_t cch = RTStrPrintf2(szTmp, sizeof(szTmp), "/Drivers/%s-%u/%s", pDrvIns->pReg->szName, pDrvIns->iInstance, pszPrefix);
1568 AssertReturn(cch > 0, VERR_BUFFER_OVERFLOW);
1569 return STAMR3DeregisterByPrefix(pDrvIns->Internal.s.pVMR3->pUVM, szTmp);
1570}
1571
1572
1573/** @interface_method_impl{PDMDRVHLPR3,pfnSUPCallVMMR0Ex} */
1574static DECLCALLBACK(int) pdmR3DrvHlp_SUPCallVMMR0Ex(PPDMDRVINS pDrvIns, unsigned uOperation, void *pvArg, unsigned cbArg)
1575{
1576 PDMDRV_ASSERT_DRVINS(pDrvIns);
1577 LogFlow(("pdmR3DrvHlp_SSMCallVMMR0Ex: caller='%s'/%d: uOperation=%u pvArg=%p cbArg=%d\n",
1578 pDrvIns->pReg->szName, pDrvIns->iInstance, uOperation, pvArg, cbArg));
1579 RT_NOREF_PV(cbArg);
1580
1581 int rc;
1582 if ( uOperation >= VMMR0_DO_SRV_START
1583 && uOperation < VMMR0_DO_SRV_END)
1584 rc = SUPR3CallVMMR0Ex(VMCC_GET_VMR0_FOR_CALL(pDrvIns->Internal.s.pVMR3), NIL_VMCPUID, uOperation, 0, (PSUPVMMR0REQHDR)pvArg);
1585 else
1586 {
1587 AssertMsgFailed(("Invalid uOperation=%u\n", uOperation));
1588 rc = VERR_INVALID_PARAMETER;
1589 }
1590
1591 LogFlow(("pdmR3DrvHlp_SUPCallVMMR0Ex: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1592 return rc;
1593}
1594
1595
1596/** @interface_method_impl{PDMDRVHLPR3,pfnUSBRegisterHub} */
1597static DECLCALLBACK(int) pdmR3DrvHlp_USBRegisterHub(PPDMDRVINS pDrvIns, uint32_t fVersions, uint32_t cPorts, PCPDMUSBHUBREG pUsbHubReg, PPCPDMUSBHUBHLP ppUsbHubHlp)
1598{
1599 PDMDRV_ASSERT_DRVINS(pDrvIns);
1600 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1601 LogFlow(("pdmR3DrvHlp_USBRegisterHub: caller='%s'/%d: fVersions=%#x cPorts=%#x pUsbHubReg=%p ppUsbHubHlp=%p\n",
1602 pDrvIns->pReg->szName, pDrvIns->iInstance, fVersions, cPorts, pUsbHubReg, ppUsbHubHlp));
1603
1604#ifdef VBOX_WITH_USB
1605 int rc = pdmR3UsbRegisterHub(pDrvIns->Internal.s.pVMR3, pDrvIns, fVersions, cPorts, pUsbHubReg, ppUsbHubHlp);
1606#else
1607 int rc = VERR_NOT_SUPPORTED;
1608#endif
1609
1610 LogFlow(("pdmR3DrvHlp_USBRegisterHub: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1611 return rc;
1612}
1613
1614
1615/** @interface_method_impl{PDMDRVHLPR3,pfnSetAsyncNotification} */
1616static DECLCALLBACK(int) pdmR3DrvHlp_SetAsyncNotification(PPDMDRVINS pDrvIns, PFNPDMDRVASYNCNOTIFY pfnAsyncNotify)
1617{
1618 PDMDRV_ASSERT_DRVINS(pDrvIns);
1619 VM_ASSERT_EMT0(pDrvIns->Internal.s.pVMR3);
1620 LogFlow(("pdmR3DrvHlp_SetAsyncNotification: caller='%s'/%d: pfnAsyncNotify=%p\n", pDrvIns->pReg->szName, pDrvIns->iInstance, pfnAsyncNotify));
1621
1622 int rc = VINF_SUCCESS;
1623 AssertStmt(pfnAsyncNotify, rc = VERR_INVALID_PARAMETER);
1624 AssertStmt(!pDrvIns->Internal.s.pfnAsyncNotify, rc = VERR_WRONG_ORDER);
1625 AssertStmt(pDrvIns->Internal.s.fVMSuspended || pDrvIns->Internal.s.fVMReset, rc = VERR_WRONG_ORDER);
1626 VMSTATE enmVMState = VMR3GetState(pDrvIns->Internal.s.pVMR3);
1627 AssertStmt( enmVMState == VMSTATE_SUSPENDING
1628 || enmVMState == VMSTATE_SUSPENDING_EXT_LS
1629 || enmVMState == VMSTATE_SUSPENDING_LS
1630 || enmVMState == VMSTATE_RESETTING
1631 || enmVMState == VMSTATE_RESETTING_LS
1632 || enmVMState == VMSTATE_POWERING_OFF
1633 || enmVMState == VMSTATE_POWERING_OFF_LS,
1634 rc = VERR_INVALID_STATE);
1635
1636 if (RT_SUCCESS(rc))
1637 pDrvIns->Internal.s.pfnAsyncNotify = pfnAsyncNotify;
1638
1639 LogFlow(("pdmR3DrvHlp_SetAsyncNotification: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1640 return rc;
1641}
1642
1643
1644/** @interface_method_impl{PDMDRVHLPR3,pfnAsyncNotificationCompleted} */
1645static DECLCALLBACK(void) pdmR3DrvHlp_AsyncNotificationCompleted(PPDMDRVINS pDrvIns)
1646{
1647 PDMDRV_ASSERT_DRVINS(pDrvIns);
1648 PVM pVM = pDrvIns->Internal.s.pVMR3;
1649
1650 VMSTATE enmVMState = VMR3GetState(pVM);
1651 if ( enmVMState == VMSTATE_SUSPENDING
1652 || enmVMState == VMSTATE_SUSPENDING_EXT_LS
1653 || enmVMState == VMSTATE_SUSPENDING_LS
1654 || enmVMState == VMSTATE_RESETTING
1655 || enmVMState == VMSTATE_RESETTING_LS
1656 || enmVMState == VMSTATE_POWERING_OFF
1657 || enmVMState == VMSTATE_POWERING_OFF_LS)
1658 {
1659 LogFlow(("pdmR3DrvHlp_AsyncNotificationCompleted: caller='%s'/%d:\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
1660 VMR3AsyncPdmNotificationWakeupU(pVM->pUVM);
1661 }
1662 else
1663 LogFlow(("pdmR3DrvHlp_AsyncNotificationCompleted: caller='%s'/%d: enmVMState=%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance, enmVMState));
1664}
1665
1666
1667/** @interface_method_impl{PDMDRVHLPR3,pfnThreadCreate} */
1668static DECLCALLBACK(int) pdmR3DrvHlp_ThreadCreate(PPDMDRVINS pDrvIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDRV pfnThread,
1669 PFNPDMTHREADWAKEUPDRV pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
1670{
1671 PDMDRV_ASSERT_DRVINS(pDrvIns);
1672 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1673 LogFlow(("pdmR3DrvHlp_ThreadCreate: caller='%s'/%d: ppThread=%p pvUser=%p pfnThread=%p pfnWakeup=%p cbStack=%#zx enmType=%d pszName=%p:{%s}\n",
1674 pDrvIns->pReg->szName, pDrvIns->iInstance, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName, pszName));
1675
1676 int rc = pdmR3ThreadCreateDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName);
1677
1678 LogFlow(("pdmR3DrvHlp_ThreadCreate: caller='%s'/%d: returns %Rrc *ppThread=%RTthrd\n", pDrvIns->pReg->szName, pDrvIns->iInstance,
1679 rc, *ppThread));
1680 return rc;
1681}
1682
1683
1684/** @interface_method_impl{PDMDRVHLPR3,pfnAsyncCompletionTemplateCreate} */
1685static DECLCALLBACK(int) pdmR3DrvHlp_AsyncCompletionTemplateCreate(PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate,
1686 PFNPDMASYNCCOMPLETEDRV pfnCompleted, void *pvTemplateUser,
1687 const char *pszDesc)
1688{
1689 PDMDRV_ASSERT_DRVINS(pDrvIns);
1690 LogFlow(("pdmR3DrvHlp_AsyncCompletionTemplateCreate: caller='%s'/%d: ppTemplate=%p pfnCompleted=%p pszDesc=%p:{%s}\n",
1691 pDrvIns->pReg->szName, pDrvIns->iInstance, ppTemplate, pfnCompleted, pszDesc, pszDesc));
1692
1693 int rc = pdmR3AsyncCompletionTemplateCreateDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, ppTemplate, pfnCompleted, pvTemplateUser, pszDesc);
1694
1695 LogFlow(("pdmR3DrvHlp_AsyncCompletionTemplateCreate: caller='%s'/%d: returns %Rrc *ppThread=%p\n", pDrvIns->pReg->szName,
1696 pDrvIns->iInstance, rc, *ppTemplate));
1697 return rc;
1698}
1699
1700
1701/** @interface_method_impl{PDMDRVHLPR3,pfnNetShaperAttach} */
1702static DECLCALLBACK(int) pdmR3DrvHlp_NetShaperAttach(PPDMDRVINS pDrvIns, const char *pszBwGroup, PPDMNSFILTER pFilter)
1703{
1704#ifdef VBOX_WITH_NETSHAPER
1705 PDMDRV_ASSERT_DRVINS(pDrvIns);
1706 LogFlow(("pdmR3DrvHlp_NetShaperAttach: caller='%s'/%d: pFilter=%p pszBwGroup=%p:{%s}\n",
1707 pDrvIns->pReg->szName, pDrvIns->iInstance, pFilter, pszBwGroup, pszBwGroup));
1708
1709 int rc = PDMR3NsAttach(pDrvIns->Internal.s.pVMR3, pDrvIns, pszBwGroup, pFilter);
1710
1711 LogFlow(("pdmR3DrvHlp_NetShaperAttach: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1712 pDrvIns->iInstance, rc));
1713 return rc;
1714#else
1715 RT_NOREF(pDrvIns, pszBwGroup, pFilter);
1716 return VERR_NOT_IMPLEMENTED;
1717#endif
1718}
1719
1720
1721/** @interface_method_impl{PDMDRVHLPR3,pfnNetShaperDetach} */
1722static DECLCALLBACK(int) pdmR3DrvHlp_NetShaperDetach(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter)
1723{
1724#ifdef VBOX_WITH_NETSHAPER
1725 PDMDRV_ASSERT_DRVINS(pDrvIns);
1726 LogFlow(("pdmR3DrvHlp_NetShaperDetach: caller='%s'/%d: pFilter=%p\n",
1727 pDrvIns->pReg->szName, pDrvIns->iInstance, pFilter));
1728
1729 int rc = PDMR3NsDetach(pDrvIns->Internal.s.pVMR3, pDrvIns, pFilter);
1730
1731 LogFlow(("pdmR3DrvHlp_NetShaperDetach: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1732 pDrvIns->iInstance, rc));
1733 return rc;
1734#else
1735 RT_NOREF(pDrvIns, pFilter);
1736 return VERR_NOT_IMPLEMENTED;
1737#endif
1738}
1739
1740
1741/** @interface_method_impl{PDMDRVHLPR3,pfnNetShaperAllocateBandwidth} */
1742static DECLCALLBACK(bool) pdmR3DrvHlp_NetShaperAllocateBandwidth(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter, size_t cbTransfer)
1743{
1744#ifdef VBOX_WITH_NETSHAPER
1745 PDMDRV_ASSERT_DRVINS(pDrvIns);
1746 LogFlow(("pdmR3DrvHlp_NetShaperDetach: caller='%s'/%d: pFilter=%p cbTransfer=%#zx\n",
1747 pDrvIns->pReg->szName, pDrvIns->iInstance, pFilter, cbTransfer));
1748
1749 bool const fRc = PDMNetShaperAllocateBandwidth(pDrvIns->Internal.s.pVMR3, pFilter, cbTransfer);
1750
1751 LogFlow(("pdmR3DrvHlp_NetShaperDetach: caller='%s'/%d: returns %RTbool\n", pDrvIns->pReg->szName, pDrvIns->iInstance, fRc));
1752 return fRc;
1753#else
1754 RT_NOREF(pDrvIns, pFilter, cbTransfer);
1755 return true;
1756#endif
1757}
1758
1759
1760/** @interface_method_impl{PDMDRVHLPR3,pfnLdrGetRCInterfaceSymbols} */
1761static DECLCALLBACK(int) pdmR3DrvHlp_LdrGetRCInterfaceSymbols(PPDMDRVINS pDrvIns, void *pvInterface, size_t cbInterface,
1762 const char *pszSymPrefix, const char *pszSymList)
1763{
1764 PDMDRV_ASSERT_DRVINS(pDrvIns);
1765 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1766 LogFlow(("pdmR3DrvHlp_LdrGetRCInterfaceSymbols: caller='%s'/%d: pvInterface=%p cbInterface=%zu pszSymPrefix=%p:{%s} pszSymList=%p:{%s}\n",
1767 pDrvIns->pReg->szName, pDrvIns->iInstance, pvInterface, cbInterface, pszSymPrefix, pszSymPrefix, pszSymList, pszSymList));
1768
1769 int rc;
1770 if ( strncmp(pszSymPrefix, "drv", 3) == 0
1771 && RTStrIStr(pszSymPrefix + 3, pDrvIns->pReg->szName) != NULL)
1772 {
1773 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_RC)
1774#ifdef PDM_WITH_RING0_DRIVERS
1775 rc = PDMR3LdrGetInterfaceSymbols(pDrvIns->Internal.s.pVMR3,
1776 pvInterface, cbInterface,
1777 pDrvIns->pReg->szRCMod, pDrvIns->Internal.s.pDrv->pszRCSearchPath,
1778 pszSymPrefix, pszSymList,
1779 false /*fRing0OrRC*/);
1780#else
1781 {
1782 AssertLogRelMsgFailed(("ring-0 drivers are not supported in this VBox version!\n"));
1783 RT_NOREF(pvInterface, cbInterface, pszSymList);
1784 rc = VERR_NOT_SUPPORTED;
1785 }
1786#endif
1787 else
1788 {
1789 AssertMsgFailed(("Not a raw-mode enabled driver\n"));
1790 rc = VERR_PERMISSION_DENIED;
1791 }
1792 }
1793 else
1794 {
1795 AssertMsgFailed(("Invalid prefix '%s' for '%s'; must start with 'drv' and contain the driver name!\n",
1796 pszSymPrefix, pDrvIns->pReg->szName));
1797 rc = VERR_INVALID_NAME;
1798 }
1799
1800 LogFlow(("pdmR3DrvHlp_LdrGetRCInterfaceSymbols: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1801 pDrvIns->iInstance, rc));
1802 return rc;
1803}
1804
1805
1806/** @interface_method_impl{PDMDRVHLPR3,pfnLdrGetR0InterfaceSymbols} */
1807static DECLCALLBACK(int) pdmR3DrvHlp_LdrGetR0InterfaceSymbols(PPDMDRVINS pDrvIns, void *pvInterface, size_t cbInterface,
1808 const char *pszSymPrefix, const char *pszSymList)
1809{
1810 PDMDRV_ASSERT_DRVINS(pDrvIns);
1811 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1812 LogFlow(("pdmR3DrvHlp_LdrGetR0InterfaceSymbols: caller='%s'/%d: pvInterface=%p cbInterface=%zu pszSymPrefix=%p:{%s} pszSymList=%p:{%s}\n",
1813 pDrvIns->pReg->szName, pDrvIns->iInstance, pvInterface, cbInterface, pszSymPrefix, pszSymPrefix, pszSymList, pszSymList));
1814
1815 int rc;
1816 if ( strncmp(pszSymPrefix, "drv", 3) == 0
1817 && RTStrIStr(pszSymPrefix + 3, pDrvIns->pReg->szName) != NULL)
1818 {
1819 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_R0)
1820#ifdef PDM_WITH_RING0_DRIVERS
1821 rc = PDMR3LdrGetInterfaceSymbols(pDrvIns->Internal.s.pVMR3,
1822 pvInterface, cbInterface,
1823 pDrvIns->pReg->szR0Mod, pDrvIns->Internal.s.pDrv->pszR0SearchPath,
1824 pszSymPrefix, pszSymList,
1825 true /*fRing0OrRC*/);
1826#else
1827 {
1828 AssertLogRelMsgFailed(("ring-0 drivers are not supported in this VBox version!\n"));
1829 RT_NOREF(pvInterface, cbInterface, pszSymList);
1830 rc = VERR_NOT_SUPPORTED;
1831 }
1832#endif
1833 else
1834 {
1835 AssertMsgFailed(("Not a ring-0 enabled driver\n"));
1836 rc = VERR_PERMISSION_DENIED;
1837 }
1838 }
1839 else
1840 {
1841 AssertMsgFailed(("Invalid prefix '%s' for '%s'; must start with 'drv' and contain the driver name!\n",
1842 pszSymPrefix, pDrvIns->pReg->szName));
1843 rc = VERR_INVALID_NAME;
1844 }
1845
1846 LogFlow(("pdmR3DrvHlp_LdrGetR0InterfaceSymbols: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1847 pDrvIns->iInstance, rc));
1848 return rc;
1849}
1850
1851
1852/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectInit} */
1853static DECLCALLBACK(int) pdmR3DrvHlp_CritSectInit(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect,
1854 RT_SRC_POS_DECL, const char *pszName)
1855{
1856 PDMDRV_ASSERT_DRVINS(pDrvIns);
1857 PVM pVM = pDrvIns->Internal.s.pVMR3;
1858 VM_ASSERT_EMT(pVM);
1859 LogFlow(("pdmR3DrvHlp_CritSectInit: caller='%s'/%d: pCritSect=%p pszName=%s\n",
1860 pDrvIns->pReg->szName, pDrvIns->iInstance, pCritSect, pszName));
1861
1862 int rc = pdmR3CritSectInitDriver(pVM, pDrvIns, pCritSect, RT_SRC_POS_ARGS, "%s_%u", pszName, pDrvIns->iInstance);
1863
1864 LogFlow(("pdmR3DrvHlp_CritSectInit: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1865 pDrvIns->iInstance, rc));
1866 return rc;
1867}
1868
1869/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectYield} */
1870static DECLCALLBACK(bool) pdmR3DrvHlp_CritSectYield(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)
1871{
1872 PDMDRV_ASSERT_DRVINS(pDrvIns);
1873 RT_NOREF(pDrvIns);
1874 return PDMR3CritSectYield(pDrvIns->Internal.s.pVMR3, pCritSect);
1875}
1876
1877
1878/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectEnter} */
1879static DECLCALLBACK(int) pdmR3DrvHlp_CritSectEnter(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy)
1880{
1881 PDMDRV_ASSERT_DRVINS(pDrvIns);
1882 return PDMCritSectEnter(pDrvIns->Internal.s.pVMR3, pCritSect, rcBusy);
1883}
1884
1885
1886/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectEnterDebug} */
1887static DECLCALLBACK(int) pdmR3DrvHlp_CritSectEnterDebug(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy,
1888 RTHCUINTPTR uId, RT_SRC_POS_DECL)
1889{
1890 PDMDRV_ASSERT_DRVINS(pDrvIns);
1891 return PDMCritSectEnterDebug(pDrvIns->Internal.s.pVMR3, pCritSect, rcBusy, uId, RT_SRC_POS_ARGS);
1892}
1893
1894
1895/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectTryEnter} */
1896static DECLCALLBACK(int) pdmR3DrvHlp_CritSectTryEnter(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)
1897{
1898 PDMDRV_ASSERT_DRVINS(pDrvIns);
1899 return PDMCritSectTryEnter(pDrvIns->Internal.s.pVMR3, pCritSect);
1900}
1901
1902
1903/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectTryEnterDebug} */
1904static DECLCALLBACK(int) pdmR3DrvHlp_CritSectTryEnterDebug(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect,
1905 RTHCUINTPTR uId, RT_SRC_POS_DECL)
1906{
1907 PDMDRV_ASSERT_DRVINS(pDrvIns);
1908 return PDMCritSectTryEnterDebug(pDrvIns->Internal.s.pVMR3, pCritSect, uId, RT_SRC_POS_ARGS);
1909}
1910
1911
1912/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectLeave} */
1913static DECLCALLBACK(int) pdmR3DrvHlp_CritSectLeave(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)
1914{
1915 PDMDRV_ASSERT_DRVINS(pDrvIns);
1916 return PDMCritSectLeave(pDrvIns->Internal.s.pVMR3, pCritSect);
1917}
1918
1919
1920/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectIsOwner} */
1921static DECLCALLBACK(bool) pdmR3DrvHlp_CritSectIsOwner(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)
1922{
1923 PDMDRV_ASSERT_DRVINS(pDrvIns);
1924 return PDMCritSectIsOwner(pDrvIns->Internal.s.pVMR3, pCritSect);
1925}
1926
1927
1928/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectIsInitialized} */
1929static DECLCALLBACK(bool) pdmR3DrvHlp_CritSectIsInitialized(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)
1930{
1931 PDMDRV_ASSERT_DRVINS(pDrvIns);
1932 RT_NOREF(pDrvIns);
1933 return PDMCritSectIsInitialized(pCritSect);
1934}
1935
1936
1937/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectHasWaiters} */
1938static DECLCALLBACK(bool) pdmR3DrvHlp_CritSectHasWaiters(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)
1939{
1940 PDMDRV_ASSERT_DRVINS(pDrvIns);
1941 return PDMCritSectHasWaiters(pDrvIns->Internal.s.pVMR3, pCritSect);
1942}
1943
1944
1945/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectGetRecursion} */
1946static DECLCALLBACK(uint32_t) pdmR3DrvHlp_CritSectGetRecursion(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)
1947{
1948 PDMDRV_ASSERT_DRVINS(pDrvIns);
1949 RT_NOREF(pDrvIns);
1950 return PDMCritSectGetRecursion(pCritSect);
1951}
1952
1953
1954/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectScheduleExitEvent} */
1955static DECLCALLBACK(int) pdmR3DrvHlp_CritSectScheduleExitEvent(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect,
1956 SUPSEMEVENT hEventToSignal)
1957{
1958 PDMDRV_ASSERT_DRVINS(pDrvIns);
1959 RT_NOREF(pDrvIns);
1960 return PDMHCCritSectScheduleExitEvent(pCritSect, hEventToSignal);
1961}
1962
1963
1964/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectDelete} */
1965static DECLCALLBACK(int) pdmR3DrvHlp_CritSectDelete(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)
1966{
1967 PDMDRV_ASSERT_DRVINS(pDrvIns);
1968 return PDMR3CritSectDelete(pDrvIns->Internal.s.pVMR3, pCritSect);
1969}
1970
1971
1972/** @interface_method_impl{PDMDRVHLPR3,pfnCallR0} */
1973static DECLCALLBACK(int) pdmR3DrvHlp_CallR0(PPDMDRVINS pDrvIns, uint32_t uOperation, uint64_t u64Arg)
1974{
1975 PDMDRV_ASSERT_DRVINS(pDrvIns);
1976#ifdef PDM_WITH_RING0_DRIVERS
1977 PVM pVM = pDrvIns->Internal.s.pVMR3;
1978#endif
1979 LogFlow(("pdmR3DrvHlp_CallR0: caller='%s'/%d: uOperation=%#x u64Arg=%#RX64\n",
1980 pDrvIns->pReg->szName, pDrvIns->iInstance, uOperation, u64Arg));
1981
1982 /*
1983 * Lazy resolve the ring-0 entry point.
1984 */
1985 int rc = VINF_SUCCESS;
1986 PFNPDMDRVREQHANDLERR0 pfnReqHandlerR0 = pDrvIns->Internal.s.pfnReqHandlerR0;
1987 if (RT_UNLIKELY(pfnReqHandlerR0 == NIL_RTR0PTR))
1988 {
1989 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_R0)
1990 {
1991#ifdef PDM_WITH_RING0_DRIVERS
1992 char szSymbol[ sizeof("drvR0") + sizeof(pDrvIns->pReg->szName) + sizeof("ReqHandler")];
1993 strcat(strcat(strcpy(szSymbol, "drvR0"), pDrvIns->pReg->szName), "ReqHandler");
1994 szSymbol[sizeof("drvR0") - 1] = RT_C_TO_UPPER(szSymbol[sizeof("drvR0") - 1]);
1995
1996 rc = PDMR3LdrGetSymbolR0Lazy(pVM, pDrvIns->pReg->szR0Mod, pDrvIns->Internal.s.pDrv->pszR0SearchPath, szSymbol,
1997 &pfnReqHandlerR0);
1998 if (RT_SUCCESS(rc))
1999 pDrvIns->Internal.s.pfnReqHandlerR0 = pfnReqHandlerR0;
2000 else
2001 pfnReqHandlerR0 = NIL_RTR0PTR;
2002#else
2003 RT_NOREF(uOperation, u64Arg);
2004 rc = VERR_NOT_SUPPORTED;
2005#endif
2006 }
2007 else
2008 rc = VERR_ACCESS_DENIED;
2009 }
2010 if (RT_LIKELY(pfnReqHandlerR0 != NIL_RTR0PTR && RT_SUCCESS(rc)))
2011 {
2012#ifdef PDM_WITH_RING0_DRIVERS
2013 /*
2014 * Make the ring-0 call.
2015 */
2016 PDMDRIVERCALLREQHANDLERREQ Req;
2017 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
2018 Req.Hdr.cbReq = sizeof(Req);
2019 Req.pDrvInsR0 = PDMDRVINS_2_R0PTR(pDrvIns);
2020 Req.uOperation = uOperation;
2021 Req.u32Alignment = 0;
2022 Req.u64Arg = u64Arg;
2023 rc = SUPR3CallVMMR0Ex(VMCC_GET_VMR0_FOR_CALL(pVM), NIL_VMCPUID, VMMR0_DO_PDM_DRIVER_CALL_REQ_HANDLER, 0, &Req.Hdr);
2024#else
2025 rc = VERR_NOT_SUPPORTED;
2026#endif
2027 }
2028
2029 LogFlow(("pdmR3DrvHlp_CallR0: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
2030 return rc;
2031}
2032
2033
2034/** @interface_method_impl{PDMDRVHLPR3,pfnBlkCacheRetain} */
2035static DECLCALLBACK(int) pdmR3DrvHlp_BlkCacheRetain(PPDMDRVINS pDrvIns, PPPDMBLKCACHE ppBlkCache,
2036 PFNPDMBLKCACHEXFERCOMPLETEDRV pfnXferComplete,
2037 PFNPDMBLKCACHEXFERENQUEUEDRV pfnXferEnqueue,
2038 PFNPDMBLKCACHEXFERENQUEUEDISCARDDRV pfnXferEnqueueDiscard,
2039 const char *pcszId)
2040{
2041 PDMDRV_ASSERT_DRVINS(pDrvIns);
2042 return PDMR3BlkCacheRetainDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, ppBlkCache,
2043 pfnXferComplete, pfnXferEnqueue, pfnXferEnqueueDiscard, pcszId);
2044}
2045
2046
2047
2048/** @interface_method_impl{PDMDRVHLPR3,pfnVMGetSuspendReason} */
2049static DECLCALLBACK(VMSUSPENDREASON) pdmR3DrvHlp_VMGetSuspendReason(PPDMDRVINS pDrvIns)
2050{
2051 PDMDRV_ASSERT_DRVINS(pDrvIns);
2052 PVM pVM = pDrvIns->Internal.s.pVMR3;
2053 VM_ASSERT_EMT(pVM);
2054 VMSUSPENDREASON enmReason = VMR3GetSuspendReason(pVM->pUVM);
2055 LogFlow(("pdmR3DrvHlp_VMGetSuspendReason: caller='%s'/%d: returns %d\n",
2056 pDrvIns->pReg->szName, pDrvIns->iInstance, enmReason));
2057 return enmReason;
2058}
2059
2060
2061/** @interface_method_impl{PDMDRVHLPR3,pfnVMGetResumeReason} */
2062static DECLCALLBACK(VMRESUMEREASON) pdmR3DrvHlp_VMGetResumeReason(PPDMDRVINS pDrvIns)
2063{
2064 PDMDRV_ASSERT_DRVINS(pDrvIns);
2065 PVM pVM = pDrvIns->Internal.s.pVMR3;
2066 VM_ASSERT_EMT(pVM);
2067 VMRESUMEREASON enmReason = VMR3GetResumeReason(pVM->pUVM);
2068 LogFlow(("pdmR3DrvHlp_VMGetResumeReason: caller='%s'/%d: returns %d\n",
2069 pDrvIns->pReg->szName, pDrvIns->iInstance, enmReason));
2070 return enmReason;
2071}
2072
2073
2074/** @interface_method_impl{PDMDRVHLPR3,pfnQueryGenericUserObject} */
2075static DECLCALLBACK(void *) pdmR3DrvHlp_QueryGenericUserObject(PPDMDRVINS pDrvIns, PCRTUUID pUuid)
2076{
2077 PDMDRV_ASSERT_DRVINS(pDrvIns);
2078 LogFlow(("pdmR3DrvHlp_QueryGenericUserObject: caller='%s'/%d: pUuid=%p:%RTuuid\n",
2079 pDrvIns->pReg->szName, pDrvIns->iInstance, pUuid, pUuid));
2080
2081 void *pvRet;
2082 PUVM pUVM = pDrvIns->Internal.s.pVMR3->pUVM;
2083 if (pUVM->pVmm2UserMethods->pfnQueryGenericObject)
2084 pvRet = pUVM->pVmm2UserMethods->pfnQueryGenericObject(pUVM->pVmm2UserMethods, pUVM, pUuid);
2085 else
2086 pvRet = NULL;
2087
2088 LogRel(("pdmR3DrvHlp_QueryGenericUserObject: caller='%s'/%d: returns %#p for %RTuuid\n",
2089 pDrvIns->pReg->szName, pDrvIns->iInstance, pvRet, pUuid));
2090 return pvRet;
2091}
2092
2093
2094/**
2095 * The driver helper structure.
2096 */
2097const PDMDRVHLPR3 g_pdmR3DrvHlp =
2098{
2099 PDM_DRVHLPR3_VERSION,
2100 pdmR3DrvHlp_Attach,
2101 pdmR3DrvHlp_Detach,
2102 pdmR3DrvHlp_DetachSelf,
2103 pdmR3DrvHlp_MountPrepare,
2104 pdmR3DrvHlp_AssertEMT,
2105 pdmR3DrvHlp_AssertOther,
2106 pdmR3DrvHlp_VMSetErrorV,
2107 pdmR3DrvHlp_VMSetRuntimeErrorV,
2108 pdmR3DrvHlp_VMState,
2109 pdmR3DrvHlp_VMTeleportedAndNotFullyResumedYet,
2110 pdmR3DrvHlp_GetSupDrvSession,
2111 pdmR3DrvHlp_QueueCreate,
2112 pdmR3DrvHlp_QueueAlloc,
2113 pdmR3DrvHlp_QueueInsert,
2114 pdmR3DrvHlp_QueueFlushIfNecessary,
2115 pdmR3DrvHlp_TMGetVirtualFreq,
2116 pdmR3DrvHlp_TMGetVirtualTime,
2117 pdmR3DrvHlp_TimerCreate,
2118 pdmR3DrvHlp_TimerDestroy,
2119 pdmR3DrvHlp_SSMRegister,
2120 pdmR3DrvHlp_SSMDeregister,
2121 SSMR3PutStruct,
2122 SSMR3PutStructEx,
2123 SSMR3PutBool,
2124 SSMR3PutU8,
2125 SSMR3PutS8,
2126 SSMR3PutU16,
2127 SSMR3PutS16,
2128 SSMR3PutU32,
2129 SSMR3PutS32,
2130 SSMR3PutU64,
2131 SSMR3PutS64,
2132 SSMR3PutU128,
2133 SSMR3PutS128,
2134 SSMR3PutUInt,
2135 SSMR3PutSInt,
2136 SSMR3PutGCUInt,
2137 SSMR3PutGCUIntReg,
2138 SSMR3PutGCPhys32,
2139 SSMR3PutGCPhys64,
2140 SSMR3PutGCPhys,
2141 SSMR3PutGCPtr,
2142 SSMR3PutGCUIntPtr,
2143 SSMR3PutRCPtr,
2144 SSMR3PutIOPort,
2145 SSMR3PutSel,
2146 SSMR3PutMem,
2147 SSMR3PutStrZ,
2148 SSMR3GetStruct,
2149 SSMR3GetStructEx,
2150 SSMR3GetBool,
2151 SSMR3GetBoolV,
2152 SSMR3GetU8,
2153 SSMR3GetU8V,
2154 SSMR3GetS8,
2155 SSMR3GetS8V,
2156 SSMR3GetU16,
2157 SSMR3GetU16V,
2158 SSMR3GetS16,
2159 SSMR3GetS16V,
2160 SSMR3GetU32,
2161 SSMR3GetU32V,
2162 SSMR3GetS32,
2163 SSMR3GetS32V,
2164 SSMR3GetU64,
2165 SSMR3GetU64V,
2166 SSMR3GetS64,
2167 SSMR3GetS64V,
2168 SSMR3GetU128,
2169 SSMR3GetU128V,
2170 SSMR3GetS128,
2171 SSMR3GetS128V,
2172 SSMR3GetGCPhys32,
2173 SSMR3GetGCPhys32V,
2174 SSMR3GetGCPhys64,
2175 SSMR3GetGCPhys64V,
2176 SSMR3GetGCPhys,
2177 SSMR3GetGCPhysV,
2178 SSMR3GetUInt,
2179 SSMR3GetSInt,
2180 SSMR3GetGCUInt,
2181 SSMR3GetGCUIntReg,
2182 SSMR3GetGCPtr,
2183 SSMR3GetGCUIntPtr,
2184 SSMR3GetRCPtr,
2185 SSMR3GetIOPort,
2186 SSMR3GetSel,
2187 SSMR3GetMem,
2188 SSMR3GetStrZ,
2189 SSMR3GetStrZEx,
2190 SSMR3Skip,
2191 SSMR3SkipToEndOfUnit,
2192 SSMR3SetLoadError,
2193 SSMR3SetLoadErrorV,
2194 SSMR3SetCfgError,
2195 SSMR3SetCfgErrorV,
2196 SSMR3HandleGetStatus,
2197 SSMR3HandleGetAfter,
2198 SSMR3HandleIsLiveSave,
2199 SSMR3HandleMaxDowntime,
2200 SSMR3HandleHostBits,
2201 SSMR3HandleRevision,
2202 SSMR3HandleVersion,
2203 SSMR3HandleHostOSAndArch,
2204 CFGMR3Exists,
2205 CFGMR3QueryType,
2206 CFGMR3QuerySize,
2207 CFGMR3QueryInteger,
2208 CFGMR3QueryIntegerDef,
2209 CFGMR3QueryString,
2210 CFGMR3QueryStringDef,
2211 CFGMR3QueryPassword,
2212 CFGMR3QueryPasswordDef,
2213 CFGMR3QueryBytes,
2214 CFGMR3QueryU64,
2215 CFGMR3QueryU64Def,
2216 CFGMR3QueryS64,
2217 CFGMR3QueryS64Def,
2218 CFGMR3QueryU32,
2219 CFGMR3QueryU32Def,
2220 CFGMR3QueryS32,
2221 CFGMR3QueryS32Def,
2222 CFGMR3QueryU16,
2223 CFGMR3QueryU16Def,
2224 CFGMR3QueryS16,
2225 CFGMR3QueryS16Def,
2226 CFGMR3QueryU8,
2227 CFGMR3QueryU8Def,
2228 CFGMR3QueryS8,
2229 CFGMR3QueryS8Def,
2230 CFGMR3QueryBool,
2231 CFGMR3QueryBoolDef,
2232 CFGMR3QueryPort,
2233 CFGMR3QueryPortDef,
2234 CFGMR3QueryUInt,
2235 CFGMR3QueryUIntDef,
2236 CFGMR3QuerySInt,
2237 CFGMR3QuerySIntDef,
2238 CFGMR3QueryGCPtr,
2239 CFGMR3QueryGCPtrDef,
2240 CFGMR3QueryGCPtrU,
2241 CFGMR3QueryGCPtrUDef,
2242 CFGMR3QueryGCPtrS,
2243 CFGMR3QueryGCPtrSDef,
2244 CFGMR3QueryStringAlloc,
2245 CFGMR3QueryStringAllocDef,
2246 CFGMR3GetParent,
2247 CFGMR3GetChild,
2248 CFGMR3GetChildF,
2249 CFGMR3GetChildFV,
2250 CFGMR3GetFirstChild,
2251 CFGMR3GetNextChild,
2252 CFGMR3GetName,
2253 CFGMR3GetNameLen,
2254 CFGMR3AreChildrenValid,
2255 CFGMR3GetFirstValue,
2256 CFGMR3GetNextValue,
2257 CFGMR3GetValueName,
2258 CFGMR3GetValueNameLen,
2259 CFGMR3GetValueType,
2260 CFGMR3AreValuesValid,
2261 CFGMR3ValidateConfig,
2262 pdmR3DrvHlp_MMHeapFree,
2263 pdmR3DrvHlp_DBGFInfoRegister,
2264 pdmR3DrvHlp_DBGFInfoRegisterArgv,
2265 pdmR3DrvHlp_DBGFInfoDeregister,
2266 pdmR3DrvHlp_STAMRegister,
2267 pdmR3DrvHlp_STAMRegisterF,
2268 pdmR3DrvHlp_STAMRegisterV,
2269 pdmR3DrvHlp_STAMDeregister,
2270 pdmR3DrvHlp_SUPCallVMMR0Ex,
2271 pdmR3DrvHlp_USBRegisterHub,
2272 pdmR3DrvHlp_SetAsyncNotification,
2273 pdmR3DrvHlp_AsyncNotificationCompleted,
2274 pdmR3DrvHlp_ThreadCreate,
2275 PDMR3ThreadDestroy,
2276 PDMR3ThreadIAmSuspending,
2277 PDMR3ThreadIAmRunning,
2278 PDMR3ThreadSleep,
2279 PDMR3ThreadSuspend,
2280 PDMR3ThreadResume,
2281 pdmR3DrvHlp_AsyncCompletionTemplateCreate,
2282 PDMR3AsyncCompletionTemplateDestroy,
2283 PDMR3AsyncCompletionEpCreateForFile,
2284 PDMR3AsyncCompletionEpClose,
2285 PDMR3AsyncCompletionEpGetSize,
2286 PDMR3AsyncCompletionEpSetSize,
2287 PDMR3AsyncCompletionEpSetBwMgr,
2288 PDMR3AsyncCompletionEpFlush,
2289 PDMR3AsyncCompletionEpRead,
2290 PDMR3AsyncCompletionEpWrite,
2291 pdmR3DrvHlp_NetShaperAttach,
2292 pdmR3DrvHlp_NetShaperDetach,
2293 pdmR3DrvHlp_NetShaperAllocateBandwidth,
2294 pdmR3DrvHlp_LdrGetRCInterfaceSymbols,
2295 pdmR3DrvHlp_LdrGetR0InterfaceSymbols,
2296 pdmR3DrvHlp_CritSectInit,
2297 pdmR3DrvHlp_CritSectYield,
2298 pdmR3DrvHlp_CritSectEnter,
2299 pdmR3DrvHlp_CritSectEnterDebug,
2300 pdmR3DrvHlp_CritSectTryEnter,
2301 pdmR3DrvHlp_CritSectTryEnterDebug,
2302 pdmR3DrvHlp_CritSectLeave,
2303 pdmR3DrvHlp_CritSectIsOwner,
2304 pdmR3DrvHlp_CritSectIsInitialized,
2305 pdmR3DrvHlp_CritSectHasWaiters,
2306 pdmR3DrvHlp_CritSectGetRecursion,
2307 pdmR3DrvHlp_CritSectScheduleExitEvent,
2308 pdmR3DrvHlp_CritSectDelete,
2309 pdmR3DrvHlp_CallR0,
2310 pdmR3DrvHlp_BlkCacheRetain,
2311 PDMR3BlkCacheRelease,
2312 PDMR3BlkCacheClear,
2313 PDMR3BlkCacheSuspend,
2314 PDMR3BlkCacheResume,
2315 PDMR3BlkCacheIoXferComplete,
2316 PDMR3BlkCacheRead,
2317 PDMR3BlkCacheWrite,
2318 PDMR3BlkCacheFlush,
2319 PDMR3BlkCacheDiscard,
2320 pdmR3DrvHlp_VMGetSuspendReason,
2321 pdmR3DrvHlp_VMGetResumeReason,
2322 pdmR3DrvHlp_TimerSetMillies,
2323 pdmR3DrvHlp_STAMDeregisterByPrefix,
2324 pdmR3DrvHlp_QueryGenericUserObject,
2325 NULL,
2326 NULL,
2327 NULL,
2328 NULL,
2329 NULL,
2330 NULL,
2331 NULL,
2332 NULL,
2333 NULL,
2334 PDM_DRVHLPR3_VERSION /* u32TheEnd */
2335};
2336
2337/** @} */
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