VirtualBox

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

最後變更 在這個檔案從80281是 80281,由 vboxsync 提交於 6 年 前

VMM,++: Refactoring code to use VMMC & VMMCPUCC. bugref:9217

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette