VirtualBox

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

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

VMM/PDMDriver: Add CFGM and SSM helpers to PDMDRVHLPR3, bugref:10074

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