VirtualBox

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

Last change on this file since 106476 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

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