VirtualBox

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

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

VMM,Devices: Add callbacks to required MMR3* APIs to the helper callbacks tables and convert devices and drivers to make use of those, bugref:10074

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 84.8 KB
Line 
1/* $Id: PDMDriver.cpp 91897 2021-10-20 13:42:39Z 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,pfnMMHeapFree} */
1380static DECLCALLBACK(void) pdmR3DrvHlp_MMHeapFree(PPDMDRVINS pDrvIns, void *pv)
1381{
1382 PDMDRV_ASSERT_DRVINS(pDrvIns);
1383 LogFlow(("pdmR3DrvHlp_MMHeapFree: caller='%s'/%d: pv=%p\n",
1384 pDrvIns->pReg->szName, pDrvIns->iInstance, pv));
1385
1386 MMR3HeapFree(pv);
1387
1388 LogFlow(("pdmR3DrvHlp_MMHeapFree: caller='%s'/%d: returns\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
1389}
1390
1391
1392/** @interface_method_impl{PDMDRVHLPR3,pfnDBGFInfoRegister} */
1393static DECLCALLBACK(int) pdmR3DrvHlp_DBGFInfoRegister(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDRV pfnHandler)
1394{
1395 PDMDRV_ASSERT_DRVINS(pDrvIns);
1396 LogFlow(("pdmR3DrvHlp_DBGFInfoRegister: caller='%s'/%d: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p\n",
1397 pDrvIns->pReg->szName, pDrvIns->iInstance, pszName, pszName, pszDesc, pszDesc, pfnHandler));
1398
1399 int rc = DBGFR3InfoRegisterDriver(pDrvIns->Internal.s.pVMR3, pszName, pszDesc, pfnHandler, pDrvIns);
1400
1401 LogFlow(("pdmR3DrvHlp_DBGFInfoRegister: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1402 return rc;
1403}
1404
1405
1406/** @interface_method_impl{PDMDRVHLPR3,pfnDBGFInfoRegisterArgv} */
1407static DECLCALLBACK(int) pdmR3DrvHlp_DBGFInfoRegisterArgv(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVDRV pfnHandler)
1408{
1409 PDMDRV_ASSERT_DRVINS(pDrvIns);
1410 LogFlow(("pdmR3DrvHlp_DBGFInfoRegisterArgv: caller='%s'/%d: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p\n",
1411 pDrvIns->pReg->szName, pDrvIns->iInstance, pszName, pszName, pszDesc, pszDesc, pfnHandler));
1412
1413 int rc = DBGFR3InfoRegisterDriverArgv(pDrvIns->Internal.s.pVMR3, pszName, pszDesc, pfnHandler, pDrvIns);
1414
1415 LogFlow(("pdmR3DrvHlp_DBGFInfoRegisterArgv: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1416 return rc;
1417}
1418
1419
1420/** @interface_method_impl{PDMDRVHLPR3,pfnDBGFInfoDeregister} */
1421static DECLCALLBACK(int) pdmR3DrvHlp_DBGFInfoDeregister(PPDMDRVINS pDrvIns, const char *pszName)
1422{
1423 PDMDRV_ASSERT_DRVINS(pDrvIns);
1424 LogFlow(("pdmR3DrvHlp_DBGFInfoDeregister: caller='%s'/%d: pszName=%p:{%s}\n",
1425 pDrvIns->pReg->szName, pDrvIns->iInstance, pszName, pszName));
1426
1427 int rc = DBGFR3InfoDeregisterDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, pszName);
1428
1429 LogFlow(("pdmR3DrvHlp_DBGFInfoDeregister: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1430
1431 return rc;
1432}
1433
1434
1435/** @interface_method_impl{PDMDRVHLPR3,pfnSTAMRegister} */
1436static DECLCALLBACK(void) pdmR3DrvHlp_STAMRegister(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, const char *pszName,
1437 STAMUNIT enmUnit, const char *pszDesc)
1438{
1439 PDMDRV_ASSERT_DRVINS(pDrvIns);
1440 PVM pVM = pDrvIns->Internal.s.pVMR3;
1441 VM_ASSERT_EMT(pVM);
1442
1443#ifdef VBOX_WITH_STATISTICS /** @todo rework this to always be compiled in */
1444 if (*pszName == '/')
1445 STAM_REG(pDrvIns->Internal.s.pVMR3, pvSample, enmType, pszName, enmUnit, pszDesc);
1446 else
1447 STAMR3RegisterF(pVM, pvSample, enmType, STAMVISIBILITY_ALWAYS, enmUnit, pszDesc,
1448 "/Drivers/%s-%u/%s", pDrvIns->pReg->szName, pDrvIns->iInstance, pszName);
1449#else
1450 RT_NOREF(pDrvIns, pvSample, enmType, pszName, enmUnit, pszDesc, pVM);
1451#endif
1452}
1453
1454
1455/** @interface_method_impl{PDMDRVHLPR3,pfnSTAMRegisterV} */
1456static DECLCALLBACK(void) pdmR3DrvHlp_STAMRegisterV(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
1457 STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list args)
1458{
1459 PDMDRV_ASSERT_DRVINS(pDrvIns);
1460 PVM pVM = pDrvIns->Internal.s.pVMR3;
1461 VM_ASSERT_EMT(pVM);
1462
1463 int rc;
1464 if (*pszName == '/')
1465 rc = STAMR3RegisterV(pVM, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, args);
1466 else
1467 {
1468 /* We need to format it to check whether it starts with a
1469 slash or not (will rework this later). */
1470 char szFormatted[2048];
1471 ssize_t cchBase = RTStrPrintf2(szFormatted, sizeof(szFormatted) - 1024, "/Drivers/%s-%u/",
1472 pDrvIns->pReg->szName, pDrvIns->iInstance);
1473 AssertReturnVoid(cchBase > 0);
1474
1475 ssize_t cch2 = RTStrPrintf2V(&szFormatted[cchBase], sizeof(szFormatted) - cchBase, pszName, args);
1476 AssertReturnVoid(cch2 > 0);
1477
1478 rc = STAMR3Register(pVM, pvSample, enmType, enmVisibility,
1479 &szFormatted[szFormatted[cchBase] == '/' ? cchBase : 0], enmUnit, pszDesc);
1480 }
1481 AssertRC(rc);
1482}
1483
1484
1485/** @interface_method_impl{PDMDRVHLPR3,pfnSTAMRegisterF} */
1486static DECLCALLBACK(void) pdmR3DrvHlp_STAMRegisterF(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
1487 STAMUNIT enmUnit, const char *pszDesc, const char *pszName, ...)
1488{
1489 va_list va;
1490 va_start(va, pszName);
1491 pdmR3DrvHlp_STAMRegisterV(pDrvIns, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, va);
1492 va_end(va);
1493}
1494
1495
1496/** @interface_method_impl{PDMDRVHLPR3,pfnSTAMDeregister} */
1497static DECLCALLBACK(int) pdmR3DrvHlp_STAMDeregister(PPDMDRVINS pDrvIns, void *pvSample)
1498{
1499 PDMDRV_ASSERT_DRVINS(pDrvIns);
1500 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1501
1502 return STAMR3DeregisterByAddr(pDrvIns->Internal.s.pVMR3->pUVM, pvSample);
1503}
1504
1505
1506/** @interface_method_impl{PDMDRVHLPR3,pfnSTAMDeregisterByPrefix} */
1507static DECLCALLBACK(int) pdmR3DrvHlp_STAMDeregisterByPrefix(PPDMDRVINS pDrvIns, const char *pszPrefix)
1508{
1509 PDMDRV_ASSERT_DRVINS(pDrvIns);
1510
1511 if (*pszPrefix == '/')
1512 return STAMR3DeregisterByPrefix(pDrvIns->Internal.s.pVMR3->pUVM, pszPrefix);
1513
1514 char szTmp[2048];
1515 ssize_t cch = RTStrPrintf2(szTmp, sizeof(szTmp), "/Drivers/%s-%u/%s", pDrvIns->pReg->szName, pDrvIns->iInstance, pszPrefix);
1516 AssertReturn(cch > 0, VERR_BUFFER_OVERFLOW);
1517 return STAMR3DeregisterByPrefix(pDrvIns->Internal.s.pVMR3->pUVM, szTmp);
1518}
1519
1520
1521/** @interface_method_impl{PDMDRVHLPR3,pfnSUPCallVMMR0Ex} */
1522static DECLCALLBACK(int) pdmR3DrvHlp_SUPCallVMMR0Ex(PPDMDRVINS pDrvIns, unsigned uOperation, void *pvArg, unsigned cbArg)
1523{
1524 PDMDRV_ASSERT_DRVINS(pDrvIns);
1525 LogFlow(("pdmR3DrvHlp_SSMCallVMMR0Ex: caller='%s'/%d: uOperation=%u pvArg=%p cbArg=%d\n",
1526 pDrvIns->pReg->szName, pDrvIns->iInstance, uOperation, pvArg, cbArg));
1527 RT_NOREF_PV(cbArg);
1528
1529 int rc;
1530 if ( uOperation >= VMMR0_DO_SRV_START
1531 && uOperation < VMMR0_DO_SRV_END)
1532 rc = SUPR3CallVMMR0Ex(VMCC_GET_VMR0_FOR_CALL(pDrvIns->Internal.s.pVMR3), NIL_VMCPUID, uOperation, 0, (PSUPVMMR0REQHDR)pvArg);
1533 else
1534 {
1535 AssertMsgFailed(("Invalid uOperation=%u\n", uOperation));
1536 rc = VERR_INVALID_PARAMETER;
1537 }
1538
1539 LogFlow(("pdmR3DrvHlp_SUPCallVMMR0Ex: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1540 return rc;
1541}
1542
1543
1544/** @interface_method_impl{PDMDRVHLPR3,pfnUSBRegisterHub} */
1545static DECLCALLBACK(int) pdmR3DrvHlp_USBRegisterHub(PPDMDRVINS pDrvIns, uint32_t fVersions, uint32_t cPorts, PCPDMUSBHUBREG pUsbHubReg, PPCPDMUSBHUBHLP ppUsbHubHlp)
1546{
1547 PDMDRV_ASSERT_DRVINS(pDrvIns);
1548 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1549 LogFlow(("pdmR3DrvHlp_USBRegisterHub: caller='%s'/%d: fVersions=%#x cPorts=%#x pUsbHubReg=%p ppUsbHubHlp=%p\n",
1550 pDrvIns->pReg->szName, pDrvIns->iInstance, fVersions, cPorts, pUsbHubReg, ppUsbHubHlp));
1551
1552#ifdef VBOX_WITH_USB
1553 int rc = pdmR3UsbRegisterHub(pDrvIns->Internal.s.pVMR3, pDrvIns, fVersions, cPorts, pUsbHubReg, ppUsbHubHlp);
1554#else
1555 int rc = VERR_NOT_SUPPORTED;
1556#endif
1557
1558 LogFlow(("pdmR3DrvHlp_USBRegisterHub: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1559 return rc;
1560}
1561
1562
1563/** @interface_method_impl{PDMDRVHLPR3,pfnSetAsyncNotification} */
1564static DECLCALLBACK(int) pdmR3DrvHlp_SetAsyncNotification(PPDMDRVINS pDrvIns, PFNPDMDRVASYNCNOTIFY pfnAsyncNotify)
1565{
1566 PDMDRV_ASSERT_DRVINS(pDrvIns);
1567 VM_ASSERT_EMT0(pDrvIns->Internal.s.pVMR3);
1568 LogFlow(("pdmR3DrvHlp_SetAsyncNotification: caller='%s'/%d: pfnAsyncNotify=%p\n", pDrvIns->pReg->szName, pDrvIns->iInstance, pfnAsyncNotify));
1569
1570 int rc = VINF_SUCCESS;
1571 AssertStmt(pfnAsyncNotify, rc = VERR_INVALID_PARAMETER);
1572 AssertStmt(!pDrvIns->Internal.s.pfnAsyncNotify, rc = VERR_WRONG_ORDER);
1573 AssertStmt(pDrvIns->Internal.s.fVMSuspended || pDrvIns->Internal.s.fVMReset, rc = VERR_WRONG_ORDER);
1574 VMSTATE enmVMState = VMR3GetState(pDrvIns->Internal.s.pVMR3);
1575 AssertStmt( enmVMState == VMSTATE_SUSPENDING
1576 || enmVMState == VMSTATE_SUSPENDING_EXT_LS
1577 || enmVMState == VMSTATE_SUSPENDING_LS
1578 || enmVMState == VMSTATE_RESETTING
1579 || enmVMState == VMSTATE_RESETTING_LS
1580 || enmVMState == VMSTATE_POWERING_OFF
1581 || enmVMState == VMSTATE_POWERING_OFF_LS,
1582 rc = VERR_INVALID_STATE);
1583
1584 if (RT_SUCCESS(rc))
1585 pDrvIns->Internal.s.pfnAsyncNotify = pfnAsyncNotify;
1586
1587 LogFlow(("pdmR3DrvHlp_SetAsyncNotification: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1588 return rc;
1589}
1590
1591
1592/** @interface_method_impl{PDMDRVHLPR3,pfnAsyncNotificationCompleted} */
1593static DECLCALLBACK(void) pdmR3DrvHlp_AsyncNotificationCompleted(PPDMDRVINS pDrvIns)
1594{
1595 PDMDRV_ASSERT_DRVINS(pDrvIns);
1596 PVM pVM = pDrvIns->Internal.s.pVMR3;
1597
1598 VMSTATE enmVMState = VMR3GetState(pVM);
1599 if ( enmVMState == VMSTATE_SUSPENDING
1600 || enmVMState == VMSTATE_SUSPENDING_EXT_LS
1601 || enmVMState == VMSTATE_SUSPENDING_LS
1602 || enmVMState == VMSTATE_RESETTING
1603 || enmVMState == VMSTATE_RESETTING_LS
1604 || enmVMState == VMSTATE_POWERING_OFF
1605 || enmVMState == VMSTATE_POWERING_OFF_LS)
1606 {
1607 LogFlow(("pdmR3DrvHlp_AsyncNotificationCompleted: caller='%s'/%d:\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
1608 VMR3AsyncPdmNotificationWakeupU(pVM->pUVM);
1609 }
1610 else
1611 LogFlow(("pdmR3DrvHlp_AsyncNotificationCompleted: caller='%s'/%d: enmVMState=%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance, enmVMState));
1612}
1613
1614
1615/** @interface_method_impl{PDMDRVHLPR3,pfnThreadCreate} */
1616static DECLCALLBACK(int) pdmR3DrvHlp_ThreadCreate(PPDMDRVINS pDrvIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDRV pfnThread,
1617 PFNPDMTHREADWAKEUPDRV pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
1618{
1619 PDMDRV_ASSERT_DRVINS(pDrvIns);
1620 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1621 LogFlow(("pdmR3DrvHlp_ThreadCreate: caller='%s'/%d: ppThread=%p pvUser=%p pfnThread=%p pfnWakeup=%p cbStack=%#zx enmType=%d pszName=%p:{%s}\n",
1622 pDrvIns->pReg->szName, pDrvIns->iInstance, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName, pszName));
1623
1624 int rc = pdmR3ThreadCreateDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName);
1625
1626 LogFlow(("pdmR3DrvHlp_ThreadCreate: caller='%s'/%d: returns %Rrc *ppThread=%RTthrd\n", pDrvIns->pReg->szName, pDrvIns->iInstance,
1627 rc, *ppThread));
1628 return rc;
1629}
1630
1631
1632/** @interface_method_impl{PDMDRVHLPR3,pfnAsyncCompletionTemplateCreate} */
1633static DECLCALLBACK(int) pdmR3DrvHlp_AsyncCompletionTemplateCreate(PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate,
1634 PFNPDMASYNCCOMPLETEDRV pfnCompleted, void *pvTemplateUser,
1635 const char *pszDesc)
1636{
1637 PDMDRV_ASSERT_DRVINS(pDrvIns);
1638 LogFlow(("pdmR3DrvHlp_AsyncCompletionTemplateCreate: caller='%s'/%d: ppTemplate=%p pfnCompleted=%p pszDesc=%p:{%s}\n",
1639 pDrvIns->pReg->szName, pDrvIns->iInstance, ppTemplate, pfnCompleted, pszDesc, pszDesc));
1640
1641 int rc = pdmR3AsyncCompletionTemplateCreateDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, ppTemplate, pfnCompleted, pvTemplateUser, pszDesc);
1642
1643 LogFlow(("pdmR3DrvHlp_AsyncCompletionTemplateCreate: caller='%s'/%d: returns %Rrc *ppThread=%p\n", pDrvIns->pReg->szName,
1644 pDrvIns->iInstance, rc, *ppTemplate));
1645 return rc;
1646}
1647
1648
1649/** @interface_method_impl{PDMDRVHLPR3,pfnNetShaperAttach} */
1650static DECLCALLBACK(int) pdmR3DrvHlp_NetShaperAttach(PPDMDRVINS pDrvIns, const char *pszBwGroup, PPDMNSFILTER pFilter)
1651{
1652#ifdef VBOX_WITH_NETSHAPER
1653 PDMDRV_ASSERT_DRVINS(pDrvIns);
1654 LogFlow(("pdmR3DrvHlp_NetShaperAttach: caller='%s'/%d: pFilter=%p pszBwGroup=%p:{%s}\n",
1655 pDrvIns->pReg->szName, pDrvIns->iInstance, pFilter, pszBwGroup, pszBwGroup));
1656
1657 int rc = PDMR3NsAttach(pDrvIns->Internal.s.pVMR3->pUVM, pDrvIns, pszBwGroup, pFilter);
1658
1659 LogFlow(("pdmR3DrvHlp_NetShaperAttach: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1660 pDrvIns->iInstance, rc));
1661 return rc;
1662#else
1663 RT_NOREF(pDrvIns, pszBwGroup, pFilter);
1664 return VERR_NOT_IMPLEMENTED;
1665#endif
1666}
1667
1668
1669/** @interface_method_impl{PDMDRVHLPR3,pfnNetShaperDetach} */
1670static DECLCALLBACK(int) pdmR3DrvHlp_NetShaperDetach(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter)
1671{
1672#ifdef VBOX_WITH_NETSHAPER
1673 PDMDRV_ASSERT_DRVINS(pDrvIns);
1674 LogFlow(("pdmR3DrvHlp_NetShaperDetach: caller='%s'/%d: pFilter=%p\n",
1675 pDrvIns->pReg->szName, pDrvIns->iInstance, pFilter));
1676
1677 int rc = PDMR3NsDetach(pDrvIns->Internal.s.pVMR3->pUVM, pDrvIns, pFilter);
1678
1679 LogFlow(("pdmR3DrvHlp_NetShaperDetach: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1680 pDrvIns->iInstance, rc));
1681 return rc;
1682#else
1683 RT_NOREF(pDrvIns, pFilter);
1684 return VERR_NOT_IMPLEMENTED;
1685#endif
1686}
1687
1688
1689/** @interface_method_impl{PDMDRVHLPR3,pfnNetShaperAllocateBandwidth} */
1690static DECLCALLBACK(bool) pdmR3DrvHlp_NetShaperAllocateBandwidth(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter, size_t cbTransfer)
1691{
1692#ifdef VBOX_WITH_NETSHAPER
1693 PDMDRV_ASSERT_DRVINS(pDrvIns);
1694 LogFlow(("pdmR3DrvHlp_NetShaperDetach: caller='%s'/%d: pFilter=%p cbTransfer=%#zx\n",
1695 pDrvIns->pReg->szName, pDrvIns->iInstance, pFilter, cbTransfer));
1696
1697 bool const fRc = PDMNetShaperAllocateBandwidth(pDrvIns->Internal.s.pVMR3, pFilter, cbTransfer);
1698
1699 LogFlow(("pdmR3DrvHlp_NetShaperDetach: caller='%s'/%d: returns %RTbool\n", pDrvIns->pReg->szName, pDrvIns->iInstance, fRc));
1700 return fRc;
1701#else
1702 RT_NOREF(pDrvIns, pFilter, cbTransfer);
1703 return true;
1704#endif
1705}
1706
1707
1708/** @interface_method_impl{PDMDRVHLPR3,pfnLdrGetRCInterfaceSymbols} */
1709static DECLCALLBACK(int) pdmR3DrvHlp_LdrGetRCInterfaceSymbols(PPDMDRVINS pDrvIns, void *pvInterface, size_t cbInterface,
1710 const char *pszSymPrefix, const char *pszSymList)
1711{
1712 PDMDRV_ASSERT_DRVINS(pDrvIns);
1713 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1714 LogFlow(("pdmR3DrvHlp_LdrGetRCInterfaceSymbols: caller='%s'/%d: pvInterface=%p cbInterface=%zu pszSymPrefix=%p:{%s} pszSymList=%p:{%s}\n",
1715 pDrvIns->pReg->szName, pDrvIns->iInstance, pvInterface, cbInterface, pszSymPrefix, pszSymPrefix, pszSymList, pszSymList));
1716
1717 int rc;
1718 if ( strncmp(pszSymPrefix, "drv", 3) == 0
1719 && RTStrIStr(pszSymPrefix + 3, pDrvIns->pReg->szName) != NULL)
1720 {
1721 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_RC)
1722 rc = PDMR3LdrGetInterfaceSymbols(pDrvIns->Internal.s.pVMR3,
1723 pvInterface, cbInterface,
1724 pDrvIns->pReg->szRCMod, pDrvIns->Internal.s.pDrv->pszRCSearchPath,
1725 pszSymPrefix, pszSymList,
1726 false /*fRing0OrRC*/);
1727 else
1728 {
1729 AssertMsgFailed(("Not a raw-mode enabled driver\n"));
1730 rc = VERR_PERMISSION_DENIED;
1731 }
1732 }
1733 else
1734 {
1735 AssertMsgFailed(("Invalid prefix '%s' for '%s'; must start with 'drv' and contain the driver name!\n",
1736 pszSymPrefix, pDrvIns->pReg->szName));
1737 rc = VERR_INVALID_NAME;
1738 }
1739
1740 LogFlow(("pdmR3DrvHlp_LdrGetRCInterfaceSymbols: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1741 pDrvIns->iInstance, rc));
1742 return rc;
1743}
1744
1745
1746/** @interface_method_impl{PDMDRVHLPR3,pfnLdrGetR0InterfaceSymbols} */
1747static DECLCALLBACK(int) pdmR3DrvHlp_LdrGetR0InterfaceSymbols(PPDMDRVINS pDrvIns, void *pvInterface, size_t cbInterface,
1748 const char *pszSymPrefix, const char *pszSymList)
1749{
1750 PDMDRV_ASSERT_DRVINS(pDrvIns);
1751 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1752 LogFlow(("pdmR3DrvHlp_LdrGetR0InterfaceSymbols: caller='%s'/%d: pvInterface=%p cbInterface=%zu pszSymPrefix=%p:{%s} pszSymList=%p:{%s}\n",
1753 pDrvIns->pReg->szName, pDrvIns->iInstance, pvInterface, cbInterface, pszSymPrefix, pszSymPrefix, pszSymList, pszSymList));
1754
1755 int rc;
1756 if ( strncmp(pszSymPrefix, "drv", 3) == 0
1757 && RTStrIStr(pszSymPrefix + 3, pDrvIns->pReg->szName) != NULL)
1758 {
1759 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_R0)
1760 rc = PDMR3LdrGetInterfaceSymbols(pDrvIns->Internal.s.pVMR3,
1761 pvInterface, cbInterface,
1762 pDrvIns->pReg->szR0Mod, pDrvIns->Internal.s.pDrv->pszR0SearchPath,
1763 pszSymPrefix, pszSymList,
1764 true /*fRing0OrRC*/);
1765 else
1766 {
1767 AssertMsgFailed(("Not a ring-0 enabled driver\n"));
1768 rc = VERR_PERMISSION_DENIED;
1769 }
1770 }
1771 else
1772 {
1773 AssertMsgFailed(("Invalid prefix '%s' for '%s'; must start with 'drv' and contain the driver name!\n",
1774 pszSymPrefix, pDrvIns->pReg->szName));
1775 rc = VERR_INVALID_NAME;
1776 }
1777
1778 LogFlow(("pdmR3DrvHlp_LdrGetR0InterfaceSymbols: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1779 pDrvIns->iInstance, rc));
1780 return rc;
1781}
1782
1783
1784/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectInit} */
1785static DECLCALLBACK(int) pdmR3DrvHlp_CritSectInit(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect,
1786 RT_SRC_POS_DECL, const char *pszName)
1787{
1788 PDMDRV_ASSERT_DRVINS(pDrvIns);
1789 PVM pVM = pDrvIns->Internal.s.pVMR3;
1790 VM_ASSERT_EMT(pVM);
1791 LogFlow(("pdmR3DrvHlp_CritSectInit: caller='%s'/%d: pCritSect=%p pszName=%s\n",
1792 pDrvIns->pReg->szName, pDrvIns->iInstance, pCritSect, pszName));
1793
1794 int rc = pdmR3CritSectInitDriver(pVM, pDrvIns, pCritSect, RT_SRC_POS_ARGS, "%s_%u", pszName, pDrvIns->iInstance);
1795
1796 LogFlow(("pdmR3DrvHlp_CritSectInit: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1797 pDrvIns->iInstance, rc));
1798 return rc;
1799}
1800
1801/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectYield} */
1802static DECLCALLBACK(bool) pdmR3DrvHlp_CritSectYield(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)
1803{
1804 PDMDRV_ASSERT_DRVINS(pDrvIns);
1805 RT_NOREF(pDrvIns);
1806 return PDMR3CritSectYield(pDrvIns->Internal.s.pVMR3, pCritSect);
1807}
1808
1809
1810/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectEnter} */
1811static DECLCALLBACK(int) pdmR3DrvHlp_CritSectEnter(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy)
1812{
1813 PDMDRV_ASSERT_DRVINS(pDrvIns);
1814 return PDMCritSectEnter(pDrvIns->Internal.s.pVMR3, pCritSect, rcBusy);
1815}
1816
1817
1818/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectEnterDebug} */
1819static DECLCALLBACK(int) pdmR3DrvHlp_CritSectEnterDebug(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy,
1820 RTHCUINTPTR uId, RT_SRC_POS_DECL)
1821{
1822 PDMDRV_ASSERT_DRVINS(pDrvIns);
1823 return PDMCritSectEnterDebug(pDrvIns->Internal.s.pVMR3, pCritSect, rcBusy, uId, RT_SRC_POS_ARGS);
1824}
1825
1826
1827/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectTryEnter} */
1828static DECLCALLBACK(int) pdmR3DrvHlp_CritSectTryEnter(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)
1829{
1830 PDMDRV_ASSERT_DRVINS(pDrvIns);
1831 return PDMCritSectTryEnter(pDrvIns->Internal.s.pVMR3, pCritSect);
1832}
1833
1834
1835/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectTryEnterDebug} */
1836static DECLCALLBACK(int) pdmR3DrvHlp_CritSectTryEnterDebug(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect,
1837 RTHCUINTPTR uId, RT_SRC_POS_DECL)
1838{
1839 PDMDRV_ASSERT_DRVINS(pDrvIns);
1840 return PDMCritSectTryEnterDebug(pDrvIns->Internal.s.pVMR3, pCritSect, uId, RT_SRC_POS_ARGS);
1841}
1842
1843
1844/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectLeave} */
1845static DECLCALLBACK(int) pdmR3DrvHlp_CritSectLeave(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)
1846{
1847 PDMDRV_ASSERT_DRVINS(pDrvIns);
1848 return PDMCritSectLeave(pDrvIns->Internal.s.pVMR3, pCritSect);
1849}
1850
1851
1852/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectIsOwner} */
1853static DECLCALLBACK(bool) pdmR3DrvHlp_CritSectIsOwner(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)
1854{
1855 PDMDRV_ASSERT_DRVINS(pDrvIns);
1856 return PDMCritSectIsOwner(pDrvIns->Internal.s.pVMR3, pCritSect);
1857}
1858
1859
1860/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectIsInitialized} */
1861static DECLCALLBACK(bool) pdmR3DrvHlp_CritSectIsInitialized(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)
1862{
1863 PDMDRV_ASSERT_DRVINS(pDrvIns);
1864 RT_NOREF(pDrvIns);
1865 return PDMCritSectIsInitialized(pCritSect);
1866}
1867
1868
1869/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectHasWaiters} */
1870static DECLCALLBACK(bool) pdmR3DrvHlp_CritSectHasWaiters(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)
1871{
1872 PDMDRV_ASSERT_DRVINS(pDrvIns);
1873 return PDMCritSectHasWaiters(pDrvIns->Internal.s.pVMR3, pCritSect);
1874}
1875
1876
1877/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectGetRecursion} */
1878static DECLCALLBACK(uint32_t) pdmR3DrvHlp_CritSectGetRecursion(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)
1879{
1880 PDMDRV_ASSERT_DRVINS(pDrvIns);
1881 RT_NOREF(pDrvIns);
1882 return PDMCritSectGetRecursion(pCritSect);
1883}
1884
1885
1886/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectScheduleExitEvent} */
1887static DECLCALLBACK(int) pdmR3DrvHlp_CritSectScheduleExitEvent(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect,
1888 SUPSEMEVENT hEventToSignal)
1889{
1890 PDMDRV_ASSERT_DRVINS(pDrvIns);
1891 RT_NOREF(pDrvIns);
1892 return PDMHCCritSectScheduleExitEvent(pCritSect, hEventToSignal);
1893}
1894
1895
1896/** @interface_method_impl{PDMDRVHLPR3,pfnCritSectDelete} */
1897static DECLCALLBACK(int) pdmR3DrvHlp_CritSectDelete(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)
1898{
1899 PDMDRV_ASSERT_DRVINS(pDrvIns);
1900 return PDMR3CritSectDelete(pDrvIns->Internal.s.pVMR3, pCritSect);
1901}
1902
1903
1904/** @interface_method_impl{PDMDRVHLPR3,pfnCallR0} */
1905static DECLCALLBACK(int) pdmR3DrvHlp_CallR0(PPDMDRVINS pDrvIns, uint32_t uOperation, uint64_t u64Arg)
1906{
1907 PDMDRV_ASSERT_DRVINS(pDrvIns);
1908 PVM pVM = pDrvIns->Internal.s.pVMR3;
1909 LogFlow(("pdmR3DrvHlp_CallR0: caller='%s'/%d: uOperation=%#x u64Arg=%#RX64\n",
1910 pDrvIns->pReg->szName, pDrvIns->iInstance, uOperation, u64Arg));
1911
1912 /*
1913 * Lazy resolve the ring-0 entry point.
1914 */
1915 int rc = VINF_SUCCESS;
1916 PFNPDMDRVREQHANDLERR0 pfnReqHandlerR0 = pDrvIns->Internal.s.pfnReqHandlerR0;
1917 if (RT_UNLIKELY(pfnReqHandlerR0 == NIL_RTR0PTR))
1918 {
1919 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_R0)
1920 {
1921 char szSymbol[ sizeof("drvR0") + sizeof(pDrvIns->pReg->szName) + sizeof("ReqHandler")];
1922 strcat(strcat(strcpy(szSymbol, "drvR0"), pDrvIns->pReg->szName), "ReqHandler");
1923 szSymbol[sizeof("drvR0") - 1] = RT_C_TO_UPPER(szSymbol[sizeof("drvR0") - 1]);
1924
1925 rc = PDMR3LdrGetSymbolR0Lazy(pVM, pDrvIns->pReg->szR0Mod, pDrvIns->Internal.s.pDrv->pszR0SearchPath, szSymbol,
1926 &pfnReqHandlerR0);
1927 if (RT_SUCCESS(rc))
1928 pDrvIns->Internal.s.pfnReqHandlerR0 = pfnReqHandlerR0;
1929 else
1930 pfnReqHandlerR0 = NIL_RTR0PTR;
1931 }
1932 else
1933 rc = VERR_ACCESS_DENIED;
1934 }
1935 if (RT_LIKELY(pfnReqHandlerR0 != NIL_RTR0PTR))
1936 {
1937 /*
1938 * Make the ring-0 call.
1939 */
1940 PDMDRIVERCALLREQHANDLERREQ Req;
1941 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1942 Req.Hdr.cbReq = sizeof(Req);
1943 Req.pDrvInsR0 = PDMDRVINS_2_R0PTR(pDrvIns);
1944 Req.uOperation = uOperation;
1945 Req.u32Alignment = 0;
1946 Req.u64Arg = u64Arg;
1947 rc = SUPR3CallVMMR0Ex(VMCC_GET_VMR0_FOR_CALL(pVM), NIL_VMCPUID, VMMR0_DO_PDM_DRIVER_CALL_REQ_HANDLER, 0, &Req.Hdr);
1948 }
1949
1950 LogFlow(("pdmR3DrvHlp_CallR0: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1951 pDrvIns->iInstance, rc));
1952 return rc;
1953}
1954
1955
1956/** @interface_method_impl{PDMDRVHLPR3,pfnBlkCacheRetain} */
1957static DECLCALLBACK(int) pdmR3DrvHlp_BlkCacheRetain(PPDMDRVINS pDrvIns, PPPDMBLKCACHE ppBlkCache,
1958 PFNPDMBLKCACHEXFERCOMPLETEDRV pfnXferComplete,
1959 PFNPDMBLKCACHEXFERENQUEUEDRV pfnXferEnqueue,
1960 PFNPDMBLKCACHEXFERENQUEUEDISCARDDRV pfnXferEnqueueDiscard,
1961 const char *pcszId)
1962{
1963 PDMDRV_ASSERT_DRVINS(pDrvIns);
1964 return PDMR3BlkCacheRetainDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, ppBlkCache,
1965 pfnXferComplete, pfnXferEnqueue, pfnXferEnqueueDiscard, pcszId);
1966}
1967
1968
1969
1970/** @interface_method_impl{PDMDRVHLPR3,pfnVMGetSuspendReason} */
1971static DECLCALLBACK(VMSUSPENDREASON) pdmR3DrvHlp_VMGetSuspendReason(PPDMDRVINS pDrvIns)
1972{
1973 PDMDRV_ASSERT_DRVINS(pDrvIns);
1974 PVM pVM = pDrvIns->Internal.s.pVMR3;
1975 VM_ASSERT_EMT(pVM);
1976 VMSUSPENDREASON enmReason = VMR3GetSuspendReason(pVM->pUVM);
1977 LogFlow(("pdmR3DrvHlp_VMGetSuspendReason: caller='%s'/%d: returns %d\n",
1978 pDrvIns->pReg->szName, pDrvIns->iInstance, enmReason));
1979 return enmReason;
1980}
1981
1982
1983/** @interface_method_impl{PDMDRVHLPR3,pfnVMGetResumeReason} */
1984static DECLCALLBACK(VMRESUMEREASON) pdmR3DrvHlp_VMGetResumeReason(PPDMDRVINS pDrvIns)
1985{
1986 PDMDRV_ASSERT_DRVINS(pDrvIns);
1987 PVM pVM = pDrvIns->Internal.s.pVMR3;
1988 VM_ASSERT_EMT(pVM);
1989 VMRESUMEREASON enmReason = VMR3GetResumeReason(pVM->pUVM);
1990 LogFlow(("pdmR3DrvHlp_VMGetResumeReason: caller='%s'/%d: returns %d\n",
1991 pDrvIns->pReg->szName, pDrvIns->iInstance, enmReason));
1992 return enmReason;
1993}
1994
1995
1996/** @interface_method_impl{PDMDRVHLPR3,pfnQueryGenericUserObject} */
1997static DECLCALLBACK(void *) pdmR3DrvHlp_QueryGenericUserObject(PPDMDRVINS pDrvIns, PCRTUUID pUuid)
1998{
1999 PDMDRV_ASSERT_DRVINS(pDrvIns);
2000 LogFlow(("pdmR3DrvHlp_QueryGenericUserObject: caller='%s'/%d: pUuid=%p:%RTuuid\n",
2001 pDrvIns->pReg->szName, pDrvIns->iInstance, pUuid, pUuid));
2002
2003 void *pvRet;
2004 PUVM pUVM = pDrvIns->Internal.s.pVMR3->pUVM;
2005 if (pUVM->pVmm2UserMethods->pfnQueryGenericObject)
2006 pvRet = pUVM->pVmm2UserMethods->pfnQueryGenericObject(pUVM->pVmm2UserMethods, pUVM, pUuid);
2007 else
2008 pvRet = NULL;
2009
2010 LogRel(("pdmR3DrvHlp_QueryGenericUserObject: caller='%s'/%d: returns %#p for %RTuuid\n",
2011 pDrvIns->pReg->szName, pDrvIns->iInstance, pvRet, pUuid));
2012 return pvRet;
2013}
2014
2015
2016/**
2017 * The driver helper structure.
2018 */
2019const PDMDRVHLPR3 g_pdmR3DrvHlp =
2020{
2021 PDM_DRVHLPR3_VERSION,
2022 pdmR3DrvHlp_Attach,
2023 pdmR3DrvHlp_Detach,
2024 pdmR3DrvHlp_DetachSelf,
2025 pdmR3DrvHlp_MountPrepare,
2026 pdmR3DrvHlp_AssertEMT,
2027 pdmR3DrvHlp_AssertOther,
2028 pdmR3DrvHlp_VMSetErrorV,
2029 pdmR3DrvHlp_VMSetRuntimeErrorV,
2030 pdmR3DrvHlp_VMState,
2031 pdmR3DrvHlp_VMTeleportedAndNotFullyResumedYet,
2032 pdmR3DrvHlp_GetSupDrvSession,
2033 pdmR3DrvHlp_QueueCreate,
2034 pdmR3DrvHlp_TMGetVirtualFreq,
2035 pdmR3DrvHlp_TMGetVirtualTime,
2036 pdmR3DrvHlp_TimerCreate,
2037 pdmR3DrvHlp_SSMRegister,
2038 pdmR3DrvHlp_SSMDeregister,
2039 SSMR3PutStruct,
2040 SSMR3PutStructEx,
2041 SSMR3PutBool,
2042 SSMR3PutU8,
2043 SSMR3PutS8,
2044 SSMR3PutU16,
2045 SSMR3PutS16,
2046 SSMR3PutU32,
2047 SSMR3PutS32,
2048 SSMR3PutU64,
2049 SSMR3PutS64,
2050 SSMR3PutU128,
2051 SSMR3PutS128,
2052 SSMR3PutUInt,
2053 SSMR3PutSInt,
2054 SSMR3PutGCUInt,
2055 SSMR3PutGCUIntReg,
2056 SSMR3PutGCPhys32,
2057 SSMR3PutGCPhys64,
2058 SSMR3PutGCPhys,
2059 SSMR3PutGCPtr,
2060 SSMR3PutGCUIntPtr,
2061 SSMR3PutRCPtr,
2062 SSMR3PutIOPort,
2063 SSMR3PutSel,
2064 SSMR3PutMem,
2065 SSMR3PutStrZ,
2066 SSMR3GetStruct,
2067 SSMR3GetStructEx,
2068 SSMR3GetBool,
2069 SSMR3GetBoolV,
2070 SSMR3GetU8,
2071 SSMR3GetU8V,
2072 SSMR3GetS8,
2073 SSMR3GetS8V,
2074 SSMR3GetU16,
2075 SSMR3GetU16V,
2076 SSMR3GetS16,
2077 SSMR3GetS16V,
2078 SSMR3GetU32,
2079 SSMR3GetU32V,
2080 SSMR3GetS32,
2081 SSMR3GetS32V,
2082 SSMR3GetU64,
2083 SSMR3GetU64V,
2084 SSMR3GetS64,
2085 SSMR3GetS64V,
2086 SSMR3GetU128,
2087 SSMR3GetU128V,
2088 SSMR3GetS128,
2089 SSMR3GetS128V,
2090 SSMR3GetGCPhys32,
2091 SSMR3GetGCPhys32V,
2092 SSMR3GetGCPhys64,
2093 SSMR3GetGCPhys64V,
2094 SSMR3GetGCPhys,
2095 SSMR3GetGCPhysV,
2096 SSMR3GetUInt,
2097 SSMR3GetSInt,
2098 SSMR3GetGCUInt,
2099 SSMR3GetGCUIntReg,
2100 SSMR3GetGCPtr,
2101 SSMR3GetGCUIntPtr,
2102 SSMR3GetRCPtr,
2103 SSMR3GetIOPort,
2104 SSMR3GetSel,
2105 SSMR3GetMem,
2106 SSMR3GetStrZ,
2107 SSMR3GetStrZEx,
2108 SSMR3Skip,
2109 SSMR3SkipToEndOfUnit,
2110 SSMR3SetLoadError,
2111 SSMR3SetLoadErrorV,
2112 SSMR3SetCfgError,
2113 SSMR3SetCfgErrorV,
2114 SSMR3HandleGetStatus,
2115 SSMR3HandleGetAfter,
2116 SSMR3HandleIsLiveSave,
2117 SSMR3HandleMaxDowntime,
2118 SSMR3HandleHostBits,
2119 SSMR3HandleRevision,
2120 SSMR3HandleVersion,
2121 SSMR3HandleHostOSAndArch,
2122 CFGMR3Exists,
2123 CFGMR3QueryType,
2124 CFGMR3QuerySize,
2125 CFGMR3QueryInteger,
2126 CFGMR3QueryIntegerDef,
2127 CFGMR3QueryString,
2128 CFGMR3QueryStringDef,
2129 CFGMR3QueryBytes,
2130 CFGMR3QueryU64,
2131 CFGMR3QueryU64Def,
2132 CFGMR3QueryS64,
2133 CFGMR3QueryS64Def,
2134 CFGMR3QueryU32,
2135 CFGMR3QueryU32Def,
2136 CFGMR3QueryS32,
2137 CFGMR3QueryS32Def,
2138 CFGMR3QueryU16,
2139 CFGMR3QueryU16Def,
2140 CFGMR3QueryS16,
2141 CFGMR3QueryS16Def,
2142 CFGMR3QueryU8,
2143 CFGMR3QueryU8Def,
2144 CFGMR3QueryS8,
2145 CFGMR3QueryS8Def,
2146 CFGMR3QueryBool,
2147 CFGMR3QueryBoolDef,
2148 CFGMR3QueryPort,
2149 CFGMR3QueryPortDef,
2150 CFGMR3QueryUInt,
2151 CFGMR3QueryUIntDef,
2152 CFGMR3QuerySInt,
2153 CFGMR3QuerySIntDef,
2154 CFGMR3QueryPtr,
2155 CFGMR3QueryPtrDef,
2156 CFGMR3QueryGCPtr,
2157 CFGMR3QueryGCPtrDef,
2158 CFGMR3QueryGCPtrU,
2159 CFGMR3QueryGCPtrUDef,
2160 CFGMR3QueryGCPtrS,
2161 CFGMR3QueryGCPtrSDef,
2162 CFGMR3QueryStringAlloc,
2163 CFGMR3QueryStringAllocDef,
2164 CFGMR3GetParent,
2165 CFGMR3GetChild,
2166 CFGMR3GetChildF,
2167 CFGMR3GetChildFV,
2168 CFGMR3GetFirstChild,
2169 CFGMR3GetNextChild,
2170 CFGMR3GetName,
2171 CFGMR3GetNameLen,
2172 CFGMR3AreChildrenValid,
2173 CFGMR3GetFirstValue,
2174 CFGMR3GetNextValue,
2175 CFGMR3GetValueName,
2176 CFGMR3GetValueNameLen,
2177 CFGMR3GetValueType,
2178 CFGMR3AreValuesValid,
2179 CFGMR3ValidateConfig,
2180 pdmR3DrvHlp_MMHeapFree,
2181 pdmR3DrvHlp_DBGFInfoRegister,
2182 pdmR3DrvHlp_DBGFInfoRegisterArgv,
2183 pdmR3DrvHlp_DBGFInfoDeregister,
2184 pdmR3DrvHlp_STAMRegister,
2185 pdmR3DrvHlp_STAMRegisterF,
2186 pdmR3DrvHlp_STAMRegisterV,
2187 pdmR3DrvHlp_STAMDeregister,
2188 pdmR3DrvHlp_SUPCallVMMR0Ex,
2189 pdmR3DrvHlp_USBRegisterHub,
2190 pdmR3DrvHlp_SetAsyncNotification,
2191 pdmR3DrvHlp_AsyncNotificationCompleted,
2192 pdmR3DrvHlp_ThreadCreate,
2193 pdmR3DrvHlp_AsyncCompletionTemplateCreate,
2194 pdmR3DrvHlp_NetShaperAttach,
2195 pdmR3DrvHlp_NetShaperDetach,
2196 pdmR3DrvHlp_NetShaperAllocateBandwidth,
2197 pdmR3DrvHlp_LdrGetRCInterfaceSymbols,
2198 pdmR3DrvHlp_LdrGetR0InterfaceSymbols,
2199 pdmR3DrvHlp_CritSectInit,
2200 pdmR3DrvHlp_CritSectYield,
2201 pdmR3DrvHlp_CritSectEnter,
2202 pdmR3DrvHlp_CritSectEnterDebug,
2203 pdmR3DrvHlp_CritSectTryEnter,
2204 pdmR3DrvHlp_CritSectTryEnterDebug,
2205 pdmR3DrvHlp_CritSectLeave,
2206 pdmR3DrvHlp_CritSectIsOwner,
2207 pdmR3DrvHlp_CritSectIsInitialized,
2208 pdmR3DrvHlp_CritSectHasWaiters,
2209 pdmR3DrvHlp_CritSectGetRecursion,
2210 pdmR3DrvHlp_CritSectScheduleExitEvent,
2211 pdmR3DrvHlp_CritSectDelete,
2212 pdmR3DrvHlp_CallR0,
2213 pdmR3DrvHlp_BlkCacheRetain,
2214 pdmR3DrvHlp_VMGetSuspendReason,
2215 pdmR3DrvHlp_VMGetResumeReason,
2216 pdmR3DrvHlp_TimerSetMillies,
2217 pdmR3DrvHlp_STAMDeregisterByPrefix,
2218 pdmR3DrvHlp_QueryGenericUserObject,
2219 NULL,
2220 NULL,
2221 NULL,
2222 NULL,
2223 NULL,
2224 NULL,
2225 NULL,
2226 PDM_DRVHLPR3_VERSION /* u32TheEnd */
2227};
2228
2229/** @} */
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