VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use