VirtualBox

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

Last change on this file since 29576 was 29521, checked in by vboxsync, 15 years ago

PDM: Added PDMDevHlpCallR0 and PDMDEV_VALIDATE_CONFIG_RETURN.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 53.7 KB
Line 
1/* $Id: PDMDriver.cpp 29521 2010-05-17 10:14:22Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device and Driver Manager, Driver parts.
4 */
5
6/*
7 * Copyright (C) 2006-2010 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/pdm.h>
25#include <VBox/mm.h>
26#include <VBox/cfgm.h>
27#include <VBox/vmm.h>
28#include <VBox/sup.h>
29#include <VBox/vm.h>
30#include <VBox/version.h>
31#include <VBox/err.h>
32
33#include <VBox/log.h>
34#include <iprt/assert.h>
35#include <iprt/asm.h>
36#include <iprt/ctype.h>
37#include <iprt/mem.h>
38#include <iprt/thread.h>
39#include <iprt/path.h>
40#include <iprt/string.h>
41
42
43/*******************************************************************************
44* Structures and Typedefs *
45*******************************************************************************/
46/**
47 * Internal callback structure pointer.
48 *
49 * The main purpose is to define the extra data we associate
50 * with PDMDRVREGCB so we can find the VM instance and so on.
51 */
52typedef struct PDMDRVREGCBINT
53{
54 /** The callback structure. */
55 PDMDRVREGCB Core;
56 /** A bit of padding. */
57 uint32_t u32[4];
58 /** VM Handle. */
59 PVM pVM;
60} PDMDRVREGCBINT, *PPDMDRVREGCBINT;
61typedef const PDMDRVREGCBINT *PCPDMDRVREGCBINT;
62
63
64/*******************************************************************************
65* Internal Functions *
66*******************************************************************************/
67static DECLCALLBACK(int) pdmR3DrvRegister(PCPDMDRVREGCB pCallbacks, PCPDMDRVREG pReg);
68static int pdmR3DrvLoad(PVM pVM, PPDMDRVREGCBINT pRegCB, const char *pszFilename, const char *pszName);
69
70
71
72/**
73 * Register external drivers
74 *
75 * @returns VBox status code.
76 * @param pVM The VM to operate on.
77 * @param pfnCallback Driver registration callback
78 */
79VMMR3DECL(int) PDMR3RegisterDrivers(PVM pVM, FNPDMVBOXDRIVERSREGISTER pfnCallback)
80{
81 /*
82 * The registration callbacks.
83 */
84 PDMDRVREGCBINT RegCB;
85 RegCB.Core.u32Version = PDM_DRVREG_CB_VERSION;
86 RegCB.Core.pfnRegister = pdmR3DrvRegister;
87 RegCB.pVM = pVM;
88
89 int rc = pfnCallback(&RegCB.Core, VBOX_VERSION);
90 if (RT_FAILURE(rc))
91 AssertMsgFailed(("VBoxDriversRegister failed with rc=%Rrc\n"));
92
93 return rc;
94}
95
96/**
97 * This function will initialize the drivers for this VM instance.
98 *
99 * First of all this mean loading the builtin drivers and letting them
100 * register themselves. Beyond that any additional driver modules are
101 * loaded and called for registration.
102 *
103 * @returns VBox status code.
104 * @param pVM VM Handle.
105 */
106int pdmR3DrvInit(PVM pVM)
107{
108 LogFlow(("pdmR3DrvInit:\n"));
109
110 AssertRelease(!(RT_OFFSETOF(PDMDRVINS, achInstanceData) & 15));
111 PPDMDRVINS pDrvInsAssert;
112 AssertRelease(sizeof(pDrvInsAssert->Internal.s) <= sizeof(pDrvInsAssert->Internal.padding));
113
114 /*
115 * The registration callbacks.
116 */
117 PDMDRVREGCBINT RegCB;
118 RegCB.Core.u32Version = PDM_DRVREG_CB_VERSION;
119 RegCB.Core.pfnRegister = pdmR3DrvRegister;
120 RegCB.pVM = pVM;
121
122 /*
123 * Load the builtin module
124 */
125 PCFGMNODE pDriversNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "PDM/Drivers");
126 bool fLoadBuiltin;
127 int rc = CFGMR3QueryBool(pDriversNode, "LoadBuiltin", &fLoadBuiltin);
128 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
129 fLoadBuiltin = true;
130 else if (RT_FAILURE(rc))
131 {
132 AssertMsgFailed(("Configuration error: Querying boolean \"LoadBuiltin\" failed with %Rrc\n", rc));
133 return rc;
134 }
135 if (fLoadBuiltin)
136 {
137 /* make filename */
138 char *pszFilename = pdmR3FileR3("VBoxDD", /*fShared=*/true);
139 if (!pszFilename)
140 return VERR_NO_TMP_MEMORY;
141 rc = pdmR3DrvLoad(pVM, &RegCB, pszFilename, "VBoxDD");
142 RTMemTmpFree(pszFilename);
143 if (RT_FAILURE(rc))
144 return rc;
145 }
146
147 /*
148 * Load additional driver modules.
149 */
150 for (PCFGMNODE pCur = CFGMR3GetFirstChild(pDriversNode); pCur; pCur = CFGMR3GetNextChild(pCur))
151 {
152 /*
153 * Get the name and path.
154 */
155 char szName[PDMMOD_NAME_LEN];
156 rc = CFGMR3GetName(pCur, &szName[0], sizeof(szName));
157 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
158 {
159 AssertMsgFailed(("configuration error: The module name is too long, cchName=%zu.\n", CFGMR3GetNameLen(pCur)));
160 return VERR_PDM_MODULE_NAME_TOO_LONG;
161 }
162 else if (RT_FAILURE(rc))
163 {
164 AssertMsgFailed(("CFGMR3GetName -> %Rrc.\n", rc));
165 return rc;
166 }
167
168 /* the path is optional, if no path the module name + path is used. */
169 char szFilename[RTPATH_MAX];
170 rc = CFGMR3QueryString(pCur, "Path", &szFilename[0], sizeof(szFilename));
171 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
172 strcpy(szFilename, szName);
173 else if (RT_FAILURE(rc))
174 {
175 AssertMsgFailed(("configuration error: Failure to query the module path, rc=%Rrc.\n", rc));
176 return rc;
177 }
178
179 /* prepend path? */
180 if (!RTPathHavePath(szFilename))
181 {
182 char *psz = pdmR3FileR3(szFilename);
183 if (!psz)
184 return VERR_NO_TMP_MEMORY;
185 size_t cch = strlen(psz) + 1;
186 if (cch > sizeof(szFilename))
187 {
188 RTMemTmpFree(psz);
189 AssertMsgFailed(("Filename too long! cch=%d '%s'\n", cch, psz));
190 return VERR_FILENAME_TOO_LONG;
191 }
192 memcpy(szFilename, psz, cch);
193 RTMemTmpFree(psz);
194 }
195
196 /*
197 * Load the module and register it's drivers.
198 */
199 rc = pdmR3DrvLoad(pVM, &RegCB, szFilename, szName);
200 if (RT_FAILURE(rc))
201 return rc;
202 }
203
204 LogFlow(("pdmR3DrvInit: returns VINF_SUCCESS\n"));
205 return VINF_SUCCESS;
206}
207
208
209/**
210 * Loads one driver module and call the registration entry point.
211 *
212 * @returns VBox status code.
213 * @param pVM VM handle.
214 * @param pRegCB The registration callback stuff.
215 * @param pszFilename Module filename.
216 * @param pszName Module name.
217 */
218static int pdmR3DrvLoad(PVM pVM, PPDMDRVREGCBINT pRegCB, const char *pszFilename, const char *pszName)
219{
220 /*
221 * Load it.
222 */
223 int rc = pdmR3LoadR3U(pVM->pUVM, pszFilename, pszName);
224 if (RT_SUCCESS(rc))
225 {
226 /*
227 * Get the registration export and call it.
228 */
229 FNPDMVBOXDRIVERSREGISTER *pfnVBoxDriversRegister;
230 rc = PDMR3LdrGetSymbolR3(pVM, pszName, "VBoxDriversRegister", (void **)&pfnVBoxDriversRegister);
231 if (RT_SUCCESS(rc))
232 {
233 Log(("PDM: Calling VBoxDriversRegister (%p) of %s (%s)\n", pfnVBoxDriversRegister, pszName, pszFilename));
234 rc = pfnVBoxDriversRegister(&pRegCB->Core, VBOX_VERSION);
235 if (RT_SUCCESS(rc))
236 Log(("PDM: Successfully loaded driver module %s (%s).\n", pszName, pszFilename));
237 else
238 AssertMsgFailed(("VBoxDriversRegister failed with rc=%Rrc\n"));
239 }
240 else
241 {
242 AssertMsgFailed(("Failed to locate 'VBoxDriversRegister' in %s (%s) rc=%Rrc\n", pszName, pszFilename, rc));
243 if (rc == VERR_SYMBOL_NOT_FOUND)
244 rc = VERR_PDM_NO_REGISTRATION_EXPORT;
245 }
246 }
247 else
248 AssertMsgFailed(("Failed to load %s (%s) rc=%Rrc!\n", pszName, pszFilename, rc));
249 return rc;
250}
251
252
253/** @interface_method_impl{PDMDRVREGCB,pfnRegister} */
254static DECLCALLBACK(int) pdmR3DrvRegister(PCPDMDRVREGCB pCallbacks, PCPDMDRVREG pReg)
255{
256 /*
257 * Validate the registration structure.
258 */
259 AssertPtrReturn(pReg, VERR_INVALID_POINTER);
260 AssertMsgReturn(pReg->u32Version == PDM_DRVREG_VERSION,
261 ("%#x\n", pReg->u32Version),
262 VERR_PDM_UNKNOWN_DRVREG_VERSION);
263 AssertReturn(pReg->szName[0], VERR_PDM_INVALID_DRIVER_REGISTRATION);
264 AssertMsgReturn(memchr(pReg->szName, '\0', sizeof(pReg->szName)),
265 (".*s\n", sizeof(pReg->szName), pReg->szName),
266 VERR_PDM_INVALID_DRIVER_REGISTRATION);
267 AssertMsgReturn( !(pReg->fFlags & PDM_DRVREG_FLAGS_R0)
268 || ( pReg->szR0Mod[0]
269 && memchr(pReg->szR0Mod, '\0', sizeof(pReg->szR0Mod))),
270 ("%s: %.*s\n", pReg->szName, sizeof(pReg->szR0Mod), pReg->szR0Mod),
271 VERR_PDM_INVALID_DRIVER_REGISTRATION);
272 AssertMsgReturn( !(pReg->fFlags & PDM_DRVREG_FLAGS_RC)
273 || ( pReg->szRCMod[0]
274 && memchr(pReg->szRCMod, '\0', sizeof(pReg->szRCMod))),
275 ("%s: %.*s\n", pReg->szName, sizeof(pReg->szRCMod), pReg->szRCMod),
276 VERR_PDM_INVALID_DRIVER_REGISTRATION);
277 AssertMsgReturn(VALID_PTR(pReg->pszDescription),
278 ("%s: %p\n", pReg->szName, pReg->pszDescription),
279 VERR_PDM_INVALID_DRIVER_REGISTRATION);
280 AssertMsgReturn(!(pReg->fFlags & ~(PDM_DRVREG_FLAGS_HOST_BITS_MASK | PDM_DRVREG_FLAGS_R0 | PDM_DRVREG_FLAGS_RC)),
281 ("%s: %#x\n", pReg->szName, pReg->fFlags),
282 VERR_PDM_INVALID_DRIVER_REGISTRATION);
283 AssertMsgReturn((pReg->fFlags & PDM_DRVREG_FLAGS_HOST_BITS_MASK) == PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
284 ("%s: %#x\n", pReg->szName, pReg->fFlags),
285 VERR_PDM_INVALID_DRIVER_HOST_BITS);
286 AssertMsgReturn(pReg->cMaxInstances > 0,
287 ("%s: %#x\n", pReg->szName, pReg->cMaxInstances),
288 VERR_PDM_INVALID_DRIVER_REGISTRATION);
289 AssertMsgReturn(pReg->cbInstance <= _1M,
290 ("%s: %#x\n", pReg->szName, pReg->cbInstance),
291 VERR_PDM_INVALID_DRIVER_REGISTRATION);
292 AssertMsgReturn(VALID_PTR(pReg->pfnConstruct),
293 ("%s: %p\n", pReg->szName, pReg->pfnConstruct),
294 VERR_PDM_INVALID_DRIVER_REGISTRATION);
295 AssertMsgReturn(VALID_PTR(pReg->pfnRelocate) || !(pReg->fFlags & PDM_DRVREG_FLAGS_RC),
296 ("%s: %#x\n", pReg->szName, pReg->cbInstance),
297 VERR_PDM_INVALID_DRIVER_REGISTRATION);
298 AssertMsgReturn(pReg->pfnSoftReset == NULL,
299 ("%s: %p\n", pReg->szName, pReg->pfnSoftReset),
300 VERR_PDM_INVALID_DRIVER_REGISTRATION);
301 AssertMsgReturn(pReg->u32VersionEnd == PDM_DRVREG_VERSION,
302 ("%s: #x\n", pReg->szName, pReg->u32VersionEnd),
303 VERR_PDM_INVALID_DRIVER_REGISTRATION);
304
305 /*
306 * Check for duplicate and find FIFO entry at the same time.
307 */
308 PCPDMDRVREGCBINT pRegCB = (PCPDMDRVREGCBINT)pCallbacks;
309 PPDMDRV pDrvPrev = NULL;
310 PPDMDRV pDrv = pRegCB->pVM->pdm.s.pDrvs;
311 for (; pDrv; pDrvPrev = pDrv, pDrv = pDrv->pNext)
312 {
313 if (!strcmp(pDrv->pReg->szName, pReg->szName))
314 {
315 AssertMsgFailed(("Driver '%s' already exists\n", pReg->szName));
316 return VERR_PDM_DRIVER_NAME_CLASH;
317 }
318 }
319
320 /*
321 * Allocate new driver structure and insert it into the list.
322 */
323 pDrv = (PPDMDRV)MMR3HeapAlloc(pRegCB->pVM, MM_TAG_PDM_DRIVER, sizeof(*pDrv));
324 if (pDrv)
325 {
326 pDrv->pNext = NULL;
327 pDrv->cInstances = 0;
328 pDrv->iNextInstance = 0;
329 pDrv->pReg = pReg;
330
331 if (pDrvPrev)
332 pDrvPrev->pNext = pDrv;
333 else
334 pRegCB->pVM->pdm.s.pDrvs = pDrv;
335 Log(("PDM: Registered driver '%s'\n", pReg->szName));
336 return VINF_SUCCESS;
337 }
338 return VERR_NO_MEMORY;
339}
340
341
342/**
343 * Lookups a driver structure by name.
344 * @internal
345 */
346PPDMDRV pdmR3DrvLookup(PVM pVM, const char *pszName)
347{
348 for (PPDMDRV pDrv = pVM->pdm.s.pDrvs; pDrv; pDrv = pDrv->pNext)
349 if (!strcmp(pDrv->pReg->szName, pszName))
350 return pDrv;
351 return NULL;
352}
353
354
355/**
356 * Instantiate a driver.
357 *
358 * @returns VBox status code, including informational statuses.
359 *
360 * @param pVM The VM handle.
361 * @param pNode The CFGM node for the driver.
362 * @param pBaseInterface The base interface.
363 * @param pDrvAbove The driver above it. NULL if it's the top-most
364 * driver.
365 * @param pLun The LUN the driver is being attached to. NULL
366 * if we're instantiating a driver chain before
367 * attaching it - untested.
368 * @param ppBaseInterface Where to return the pointer to the base
369 * interface of the newly created driver.
370 *
371 * @remarks Recursive calls to this function is normal as the drivers will
372 * attach to anything below them during the pfnContruct call.
373 */
374int pdmR3DrvInstantiate(PVM pVM, PCFGMNODE pNode, PPDMIBASE pBaseInterface, PPDMDRVINS pDrvAbove,
375 PPDMLUN pLun, PPDMIBASE *ppBaseInterface)
376{
377 Assert(!pDrvAbove || !pDrvAbove->Internal.s.pDown);
378 Assert(!pDrvAbove || !pDrvAbove->pDownBase);
379
380 Assert(pBaseInterface->pfnQueryInterface(pBaseInterface, PDMIBASE_IID) == pBaseInterface);
381
382 /*
383 * Find the driver.
384 */
385 char *pszName;
386 int rc = CFGMR3QueryStringAlloc(pNode, "Driver", &pszName);
387 if (RT_SUCCESS(rc))
388 {
389 PPDMDRV pDrv = pdmR3DrvLookup(pVM, pszName);
390 MMR3HeapFree(pszName);
391 if ( pDrv
392 && pDrv->cInstances < pDrv->pReg->cMaxInstances)
393 {
394 /* config node */
395 PCFGMNODE pConfigNode = CFGMR3GetChild(pNode, "Config");
396 if (!pConfigNode)
397 rc = CFGMR3InsertNode(pNode, "Config", &pConfigNode);
398 if (RT_SUCCESS(rc))
399 {
400 CFGMR3SetRestrictedRoot(pConfigNode);
401
402 /*
403 * Allocate the driver instance.
404 */
405 size_t cb = RT_OFFSETOF(PDMDRVINS, achInstanceData[pDrv->pReg->cbInstance]);
406 cb = RT_ALIGN_Z(cb, 16);
407 bool const fHyperHeap = !!(pDrv->pReg->fFlags & (PDM_DRVREG_FLAGS_R0 | PDM_DRVREG_FLAGS_RC));
408 PPDMDRVINS pNew;
409 if (fHyperHeap)
410 rc = MMHyperAlloc(pVM, cb, 64, MM_TAG_PDM_DRIVER, (void **)&pNew);
411 else
412 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_DRIVER, cb, (void **)&pNew);
413 if (pNew)
414 {
415 /*
416 * Initialize the instance structure (declaration order).
417 */
418 pNew->u32Version = PDM_DRVINS_VERSION;
419 pNew->Internal.s.pUp = pDrvAbove ? pDrvAbove : NULL;
420 //pNew->Internal.s.pDown = NULL;
421 pNew->Internal.s.pLun = pLun;
422 pNew->Internal.s.pDrv = pDrv;
423 pNew->Internal.s.pVMR3 = pVM;
424 pNew->Internal.s.pVMR0 = pDrv->pReg->fFlags & PDM_DRVREG_FLAGS_R0 ? pVM->pVMR0 : NIL_RTR0PTR;
425 pNew->Internal.s.pVMRC = pDrv->pReg->fFlags & PDM_DRVREG_FLAGS_RC ? pVM->pVMRC : NIL_RTRCPTR;
426 //pNew->Internal.s.fDetaching = false;
427 pNew->Internal.s.fVMSuspended = true;
428 //pNew->Internal.s.fVMReset = false;
429 pNew->Internal.s.fHyperHeap = fHyperHeap;
430 //pNew->Internal.s.pfnAsyncNotify = NULL;
431 pNew->Internal.s.pCfgHandle = pNode;
432 pNew->pReg = pDrv->pReg;
433 pNew->pCfg = pConfigNode;
434 pNew->iInstance = pDrv->iNextInstance;
435 pNew->pUpBase = pBaseInterface;
436 Assert(!pDrvAbove || pBaseInterface == &pDrvAbove->IBase);
437 //pNew->pDownBase = NULL;
438 //pNew->IBase.pfnQueryInterface = NULL;
439 pNew->pHlpR3 = &g_pdmR3DrvHlp;
440 pNew->pvInstanceDataR3 = &pNew->achInstanceData[0];
441 if (pDrv->pReg->fFlags & PDM_DRVREG_FLAGS_R0)
442 {
443 pNew->pvInstanceDataR0 = MMHyperR3ToR0(pVM, &pNew->achInstanceData[0]);
444 rc = PDMR3LdrGetSymbolR0(pVM, NULL, "g_pdmR0DrvHlp", &pNew->pHlpR0);
445 AssertReleaseRCReturn(rc, rc);
446
447 }
448 if (pDrv->pReg->fFlags & PDM_DRVREG_FLAGS_RC)
449 {
450 pNew->pvInstanceDataR0 = MMHyperR3ToRC(pVM, &pNew->achInstanceData[0]);
451 rc = PDMR3LdrGetSymbolRC(pVM, NULL, "g_pdmRCDrvHlp", &pNew->pHlpRC);
452 AssertReleaseRCReturn(rc, rc);
453 }
454
455 pDrv->iNextInstance++;
456 pDrv->cInstances++;
457
458 /*
459 * Link with it with the driver above / LUN.
460 */
461 if (pDrvAbove)
462 {
463 pDrvAbove->pDownBase = &pNew->IBase;
464 pDrvAbove->Internal.s.pDown = pNew;
465 }
466 else if (pLun)
467 pLun->pTop = pNew;
468 if (pLun)
469 pLun->pBottom = pNew;
470
471 /*
472 * Invoke the constructor.
473 */
474 rc = pDrv->pReg->pfnConstruct(pNew, pNew->pCfg, 0 /*fFlags*/);
475 if (RT_SUCCESS(rc))
476 {
477 AssertPtr(pNew->IBase.pfnQueryInterface);
478 Assert(pNew->IBase.pfnQueryInterface(&pNew->IBase, PDMIBASE_IID) == &pNew->IBase);
479
480 /* Success! */
481 *ppBaseInterface = &pNew->IBase;
482 if (pLun)
483 Log(("PDM: Attached driver %p:'%s'/%d to LUN#%d on device '%s'/%d, pDrvAbove=%p:'%s'/%d\n",
484 pNew, pDrv->pReg->szName, pNew->iInstance,
485 pLun->iLun,
486 pLun->pDevIns ? pLun->pDevIns->pReg->szName : pLun->pUsbIns->pReg->szName,
487 pLun->pDevIns ? pLun->pDevIns->iInstance : pLun->pUsbIns->iInstance,
488 pDrvAbove, pDrvAbove ? pDrvAbove->pReg->szName : "", pDrvAbove ? pDrvAbove->iInstance : UINT32_MAX));
489 else
490 Log(("PDM: Attached driver %p:'%s'/%d, pDrvAbove=%p:'%s'/%d\n",
491 pNew, pDrv->pReg->szName, pNew->iInstance,
492 pDrvAbove, pDrvAbove ? pDrvAbove->pReg->szName : "", pDrvAbove ? pDrvAbove->iInstance : UINT32_MAX));
493 }
494 else
495 pdmR3DrvDestroyChain(pNew, PDM_TACH_FLAGS_NO_CALLBACKS);
496 }
497 else
498 {
499 AssertMsgFailed(("Failed to allocate %d bytes for instantiating driver '%s'\n", cb, pszName));
500 rc = VERR_NO_MEMORY;
501 }
502 }
503 else
504 AssertMsgFailed(("Failed to create Config node! rc=%Rrc\n", rc));
505 }
506 else if (pDrv)
507 {
508 AssertMsgFailed(("Too many instances of driver '%s', max is %u\n", pszName, pDrv->pReg->cMaxInstances));
509 rc = VERR_PDM_TOO_MANY_DRIVER_INSTANCES;
510 }
511 else
512 {
513 AssertMsgFailed(("Driver '%s' wasn't found!\n", pszName));
514 rc = VERR_PDM_DRIVER_NOT_FOUND;
515 }
516 }
517 else
518 {
519 AssertMsgFailed(("Query for string value of \"Driver\" -> %Rrc\n", rc));
520 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
521 rc = VERR_PDM_CFG_MISSING_DRIVER_NAME;
522 }
523 return rc;
524}
525
526
527/**
528 * Detaches a driver from whatever it's attached to.
529 * This will of course lead to the destruction of the driver and all drivers below it in the chain.
530 *
531 * @returns VINF_SUCCESS
532 * @param pDrvIns The driver instance to detach.
533 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
534 */
535int pdmR3DrvDetach(PPDMDRVINS pDrvIns, uint32_t fFlags)
536{
537 PDMDRV_ASSERT_DRVINS(pDrvIns);
538 LogFlow(("pdmR3DrvDetach: pDrvIns=%p '%s'/%d\n", pDrvIns, pDrvIns->pReg->szName, pDrvIns->iInstance));
539 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
540
541 /*
542 * Check that we're not doing this recursively, that could have unwanted sideeffects!
543 */
544 if (pDrvIns->Internal.s.fDetaching)
545 {
546 AssertMsgFailed(("Recursive detach! '%s'/%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
547 return VINF_SUCCESS; }
548
549 /*
550 * Check that we actually can detach this instance.
551 * The requirement is that the driver/device above has a detach method.
552 */
553 if (pDrvIns->Internal.s.pUp
554 ? !pDrvIns->Internal.s.pUp->pReg->pfnDetach
555 : !pDrvIns->Internal.s.pLun->pDevIns->pReg->pfnDetach)
556 {
557 AssertMsgFailed(("Cannot detach driver instance because the driver/device above doesn't support it!\n"));
558 return VERR_PDM_DRIVER_DETACH_NOT_POSSIBLE;
559 }
560
561 /*
562 * Join paths with pdmR3DrvDestroyChain.
563 */
564 pdmR3DrvDestroyChain(pDrvIns, fFlags);
565 return VINF_SUCCESS;
566}
567
568
569/**
570 * Destroys a driver chain starting with the specified driver.
571 *
572 * This is used when unplugging a device at run time.
573 *
574 * @param pDrvIns Pointer to the driver instance to start with.
575 * @param fFlags PDM_TACH_FLAGS_NOT_HOT_PLUG, PDM_TACH_FLAGS_NO_CALLBACKS
576 * or 0.
577 */
578void pdmR3DrvDestroyChain(PPDMDRVINS pDrvIns, uint32_t fFlags)
579{
580 PVM pVM = pDrvIns->Internal.s.pVMR3;
581 VM_ASSERT_EMT(pVM);
582
583 /*
584 * Detach the bottommost driver until we've detached pDrvIns.
585 */
586 pDrvIns->Internal.s.fDetaching = true;
587 PPDMDRVINS pCur;
588 do
589 {
590 /* find the driver to detach. */
591 pCur = pDrvIns;
592 while (pCur->Internal.s.pDown)
593 pCur = pCur->Internal.s.pDown;
594 LogFlow(("pdmR3DrvDestroyChain: pCur=%p '%s'/%d\n", pCur, pCur->pReg->szName, pCur->iInstance));
595
596 /*
597 * Unlink it and notify parent.
598 */
599 pCur->Internal.s.fDetaching = true;
600
601 PPDMLUN pLun = pCur->Internal.s.pLun;
602 Assert(pLun->pBottom == pCur);
603 pLun->pBottom = pCur->Internal.s.pUp;
604
605 if (pCur->Internal.s.pUp)
606 {
607 /* driver parent */
608 PPDMDRVINS pParent = pCur->Internal.s.pUp;
609 pCur->Internal.s.pUp = NULL;
610 pParent->Internal.s.pDown = NULL;
611
612 if (!(fFlags & PDM_TACH_FLAGS_NO_CALLBACKS) && pParent->pReg->pfnDetach)
613 pParent->pReg->pfnDetach(pParent, fFlags);
614
615 pParent->pDownBase = NULL;
616 }
617 else
618 {
619 /* device parent */
620 Assert(pLun->pTop == pCur);
621 pLun->pTop = NULL;
622 if (!(fFlags & PDM_TACH_FLAGS_NO_CALLBACKS) && pLun->pDevIns->pReg->pfnDetach)
623 pLun->pDevIns->pReg->pfnDetach(pLun->pDevIns, pLun->iLun, fFlags);
624 }
625
626 /*
627 * Call destructor.
628 */
629 pCur->pUpBase = NULL;
630 if (pCur->pReg->pfnDestruct)
631 pCur->pReg->pfnDestruct(pCur);
632 pCur->Internal.s.pDrv->cInstances--;
633
634 /*
635 * Free all resources allocated by the driver.
636 */
637 /* Queues. */
638 int rc = PDMR3QueueDestroyDriver(pVM, pCur);
639 AssertRC(rc);
640
641 /* Timers. */
642 rc = TMR3TimerDestroyDriver(pVM, pCur);
643 AssertRC(rc);
644
645 /* SSM data units. */
646 rc = SSMR3DeregisterDriver(pVM, pCur, NULL, 0);
647 AssertRC(rc);
648
649 /* PDM threads. */
650 rc = pdmR3ThreadDestroyDriver(pVM, pCur);
651 AssertRC(rc);
652
653 /* PDM critsects. */
654 rc = pdmR3CritSectDeleteDriver(pVM, pCur);
655 AssertRC(rc);
656
657 /* Finally, the driver it self. */
658 bool fHyperHeap = pCur->Internal.s.fHyperHeap;
659 ASMMemFill32(pCur, RT_OFFSETOF(PDMDRVINS, achInstanceData[pCur->pReg->cbInstance]), 0xdeadd0d0);
660 if (fHyperHeap)
661 MMHyperFree(pVM, pCur);
662 else
663 MMR3HeapFree(pCur);
664
665 } while (pCur != pDrvIns);
666}
667
668
669
670
671/** @name Driver Helpers
672 * @{
673 */
674
675/** @interface_method_impl{PDMDRVHLP,pfnAttach} */
676static DECLCALLBACK(int) pdmR3DrvHlp_Attach(PPDMDRVINS pDrvIns, uint32_t fFlags, PPDMIBASE *ppBaseInterface)
677{
678 PDMDRV_ASSERT_DRVINS(pDrvIns);
679 PVM pVM = pDrvIns->Internal.s.pVMR3;
680 VM_ASSERT_EMT(pVM);
681 LogFlow(("pdmR3DrvHlp_Attach: caller='%s'/%d: fFlags=%#x\n", pDrvIns->pReg->szName, pDrvIns->iInstance, fFlags));
682 Assert(!(fFlags & ~(PDM_TACH_FLAGS_NOT_HOT_PLUG)));
683
684 /*
685 * Check that there isn't anything attached already.
686 */
687 int rc;
688 if (!pDrvIns->Internal.s.pDown)
689 {
690 Assert(pDrvIns->Internal.s.pLun->pBottom == pDrvIns);
691
692 /*
693 * Get the attached driver configuration.
694 */
695 PCFGMNODE pNode = CFGMR3GetChild(pDrvIns->Internal.s.pCfgHandle, "AttachedDriver");
696 if (pNode)
697 rc = pdmR3DrvInstantiate(pVM, pNode, &pDrvIns->IBase, pDrvIns, pDrvIns->Internal.s.pLun, ppBaseInterface);
698 else
699 rc = VERR_PDM_NO_ATTACHED_DRIVER;
700 }
701 else
702 {
703 AssertMsgFailed(("Already got a driver attached. The driver should keep track of such things!\n"));
704 rc = VERR_PDM_DRIVER_ALREADY_ATTACHED;
705 }
706
707 LogFlow(("pdmR3DrvHlp_Attach: caller='%s'/%d: return %Rrc\n",
708 pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
709 return rc;
710}
711
712
713/** @interface_method_impl{PDMDRVHLP,pfnDetach} */
714static DECLCALLBACK(int) pdmR3DrvHlp_Detach(PPDMDRVINS pDrvIns, uint32_t fFlags)
715{
716 PDMDRV_ASSERT_DRVINS(pDrvIns);
717 LogFlow(("pdmR3DrvHlp_Detach: caller='%s'/%d: fFlags=%#x\n",
718 pDrvIns->pReg->szName, pDrvIns->iInstance, fFlags));
719 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
720
721 /*
722 * Anything attached?
723 */
724 int rc;
725 if (pDrvIns->Internal.s.pDown)
726 rc = pdmR3DrvDetach(pDrvIns->Internal.s.pDown, fFlags);
727 else
728 {
729 AssertMsgFailed(("Nothing attached!\n"));
730 rc = VERR_PDM_NO_DRIVER_ATTACHED;
731 }
732
733 LogFlow(("pdmR3DrvHlp_Detach: caller='%s'/%d: returns %Rrc\n",
734 pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
735 return rc;
736}
737
738
739/** @interface_method_impl{PDMDRVHLP,pfnDetachSelf} */
740static DECLCALLBACK(int) pdmR3DrvHlp_DetachSelf(PPDMDRVINS pDrvIns, uint32_t fFlags)
741{
742 PDMDRV_ASSERT_DRVINS(pDrvIns);
743 LogFlow(("pdmR3DrvHlp_DetachSelf: caller='%s'/%d: fFlags=%#x\n",
744 pDrvIns->pReg->szName, pDrvIns->iInstance, fFlags));
745 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
746
747 int rc = pdmR3DrvDetach(pDrvIns, fFlags);
748
749 LogFlow(("pdmR3DrvHlp_Detach: returns %Rrc\n", rc)); /* pDrvIns is freed by now. */
750 return rc;
751}
752
753
754/** @interface_method_impl{PDMDRVHLP,pfnMountPrepare} */
755static DECLCALLBACK(int) pdmR3DrvHlp_MountPrepare(PPDMDRVINS pDrvIns, const char *pszFilename, const char *pszCoreDriver)
756{
757 PDMDRV_ASSERT_DRVINS(pDrvIns);
758 LogFlow(("pdmR3DrvHlp_MountPrepare: caller='%s'/%d: pszFilename=%p:{%s} pszCoreDriver=%p:{%s}\n",
759 pDrvIns->pReg->szName, pDrvIns->iInstance, pszFilename, pszFilename, pszCoreDriver, pszCoreDriver));
760 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
761
762 /*
763 * Do the caller have anything attached below itself?
764 */
765 if (pDrvIns->Internal.s.pDown)
766 {
767 AssertMsgFailed(("Cannot prepare a mount when something's attached to you!\n"));
768 return VERR_PDM_DRIVER_ALREADY_ATTACHED;
769 }
770
771 /*
772 * We're asked to prepare, so we'll start off by nuking the
773 * attached configuration tree.
774 */
775 PCFGMNODE pNode = CFGMR3GetChild(pDrvIns->Internal.s.pCfgHandle, "AttachedDriver");
776 if (pNode)
777 CFGMR3RemoveNode(pNode);
778
779 /*
780 * If there is no core driver, we'll have to probe for it.
781 */
782 if (!pszCoreDriver)
783 {
784 /** @todo implement image probing. */
785 AssertReleaseMsgFailed(("Not implemented!\n"));
786 return VERR_NOT_IMPLEMENTED;
787 }
788
789 /*
790 * Construct the basic attached driver configuration.
791 */
792 int rc = CFGMR3InsertNode(pDrvIns->Internal.s.pCfgHandle, "AttachedDriver", &pNode);
793 if (RT_SUCCESS(rc))
794 {
795 rc = CFGMR3InsertString(pNode, "Driver", pszCoreDriver);
796 if (RT_SUCCESS(rc))
797 {
798 PCFGMNODE pCfg;
799 rc = CFGMR3InsertNode(pNode, "Config", &pCfg);
800 if (RT_SUCCESS(rc))
801 {
802 rc = CFGMR3InsertString(pCfg, "Path", pszFilename);
803 if (RT_SUCCESS(rc))
804 {
805 LogFlow(("pdmR3DrvHlp_MountPrepare: caller='%s'/%d: returns %Rrc (Driver=%s)\n",
806 pDrvIns->pReg->szName, pDrvIns->iInstance, rc, pszCoreDriver));
807 return rc;
808 }
809 else
810 AssertMsgFailed(("Path string insert failed, rc=%Rrc\n", rc));
811 }
812 else
813 AssertMsgFailed(("Config node failed, rc=%Rrc\n", rc));
814 }
815 else
816 AssertMsgFailed(("Driver string insert failed, rc=%Rrc\n", rc));
817 CFGMR3RemoveNode(pNode);
818 }
819 else
820 AssertMsgFailed(("AttachedDriver node insert failed, rc=%Rrc\n", rc));
821
822 LogFlow(("pdmR3DrvHlp_MountPrepare: caller='%s'/%d: returns %Rrc\n",
823 pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
824 return rc;
825}
826
827
828/** @interface_method_impl{PDMDRVHLP,pfnAssertEMT} */
829static DECLCALLBACK(bool) pdmR3DrvHlp_AssertEMT(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)
830{
831 PDMDRV_ASSERT_DRVINS(pDrvIns);
832 if (VM_IS_EMT(pDrvIns->Internal.s.pVMR3))
833 return true;
834
835 char szMsg[100];
836 RTStrPrintf(szMsg, sizeof(szMsg), "AssertEMT '%s'/%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance);
837 RTAssertMsg1Weak(szMsg, iLine, pszFile, pszFunction);
838 AssertBreakpoint();
839 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
840 return false;
841}
842
843
844/** @interface_method_impl{PDMDRVHLP,pfnAssertOther} */
845static DECLCALLBACK(bool) pdmR3DrvHlp_AssertOther(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)
846{
847 PDMDRV_ASSERT_DRVINS(pDrvIns);
848 if (!VM_IS_EMT(pDrvIns->Internal.s.pVMR3))
849 return true;
850
851 char szMsg[100];
852 RTStrPrintf(szMsg, sizeof(szMsg), "AssertOther '%s'/%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance);
853 RTAssertMsg1Weak(szMsg, iLine, pszFile, pszFunction);
854 AssertBreakpoint();
855 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
856 return false;
857}
858
859
860/** @interface_method_impl{PDMDRVHLP,pfnVMSetError} */
861static DECLCALLBACK(int) pdmR3DrvHlp_VMSetError(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...)
862{
863 PDMDRV_ASSERT_DRVINS(pDrvIns);
864 va_list args;
865 va_start(args, pszFormat);
866 int rc2 = VMSetErrorV(pDrvIns->Internal.s.pVMR3, rc, RT_SRC_POS_ARGS, pszFormat, args); Assert(rc2 == rc); NOREF(rc2);
867 va_end(args);
868 return rc;
869}
870
871
872/** @interface_method_impl{PDMDRVHLP,pfnVMSetErrorV} */
873static DECLCALLBACK(int) pdmR3DrvHlp_VMSetErrorV(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
874{
875 PDMDRV_ASSERT_DRVINS(pDrvIns);
876 int rc2 = VMSetErrorV(pDrvIns->Internal.s.pVMR3, rc, RT_SRC_POS_ARGS, pszFormat, va); Assert(rc2 == rc); NOREF(rc2);
877 return rc;
878}
879
880
881/** @interface_method_impl{PDMDRVHLP,pfnVMSetRuntimeError} */
882static DECLCALLBACK(int) pdmR3DrvHlp_VMSetRuntimeError(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, ...)
883{
884 PDMDRV_ASSERT_DRVINS(pDrvIns);
885 va_list args;
886 va_start(args, pszFormat);
887 int rc = VMSetRuntimeErrorV(pDrvIns->Internal.s.pVMR3, fFlags, pszErrorId, pszFormat, args);
888 va_end(args);
889 return rc;
890}
891
892
893/** @interface_method_impl{PDMDRVHLP,pfnVMSetRuntimeErrorV} */
894static DECLCALLBACK(int) pdmR3DrvHlp_VMSetRuntimeErrorV(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)
895{
896 PDMDRV_ASSERT_DRVINS(pDrvIns);
897 int rc = VMSetRuntimeErrorV(pDrvIns->Internal.s.pVMR3, fFlags, pszErrorId, pszFormat, va);
898 return rc;
899}
900
901
902/** @interface_method_impl{PDMDEVHLPR3,pfnVMState} */
903static DECLCALLBACK(VMSTATE) pdmR3DrvHlp_VMState(PPDMDRVINS pDrvIns)
904{
905 PDMDRV_ASSERT_DRVINS(pDrvIns);
906
907 VMSTATE enmVMState = VMR3GetState(pDrvIns->Internal.s.pVMR3);
908
909 LogFlow(("pdmR3DrvHlp_VMState: caller='%s'/%d: returns %d (%s)\n", pDrvIns->pReg->szName, pDrvIns->iInstance,
910 enmVMState, VMR3GetStateName(enmVMState)));
911 return enmVMState;
912}
913
914
915/** @interface_method_impl{PDMDEVHLPR3,pfnVMTeleportedAndNotFullyResumedYet} */
916static DECLCALLBACK(bool) pdmR3DrvHlp_VMTeleportedAndNotFullyResumedYet(PPDMDRVINS pDrvIns)
917{
918 PDMDRV_ASSERT_DRVINS(pDrvIns);
919
920 bool fRc = VMR3TeleportedAndNotFullyResumedYet(pDrvIns->Internal.s.pVMR3);
921
922 LogFlow(("pdmR3DrvHlp_VMState: caller='%s'/%d: returns %RTbool)\n", pDrvIns->pReg->szName, pDrvIns->iInstance,
923 fRc));
924 return fRc;
925}
926
927
928/** @interface_method_impl{PDMDEVHLPR3,pfnGetSupDrvSession} */
929static DECLCALLBACK(PSUPDRVSESSION) pdmR3DrvHlp_GetSupDrvSession(PPDMDRVINS pDrvIns)
930{
931 PDMDRV_ASSERT_DRVINS(pDrvIns);
932
933 PSUPDRVSESSION pSession = pDrvIns->Internal.s.pVMR3->pSession;
934 LogFlow(("pdmR3DrvHlp_GetSupDrvSession: caller='%s'/%d: returns %p)\n", pDrvIns->pReg->szName, pDrvIns->iInstance,
935 pSession));
936 return pSession;
937}
938
939
940/** @interface_method_impl{PDMDRVHLP,pfnQueueCreate} */
941static DECLCALLBACK(int) pdmR3DrvHlp_QueueCreate(PPDMDRVINS pDrvIns, uint32_t cbItem, uint32_t cItems, uint32_t cMilliesInterval,
942 PFNPDMQUEUEDRV pfnCallback, const char *pszName, PPDMQUEUE *ppQueue)
943{
944 PDMDRV_ASSERT_DRVINS(pDrvIns);
945 LogFlow(("pdmR3DrvHlp_PDMQueueCreate: caller='%s'/%d: cbItem=%d cItems=%d cMilliesInterval=%d pfnCallback=%p pszName=%p:{%s} ppQueue=%p\n",
946 pDrvIns->pReg->szName, pDrvIns->iInstance, cbItem, cItems, cMilliesInterval, pfnCallback, pszName, pszName, ppQueue, ppQueue));
947 PVM pVM = pDrvIns->Internal.s.pVMR3;
948 VM_ASSERT_EMT(pVM);
949
950 if (pDrvIns->iInstance > 0)
951 {
952 pszName = MMR3HeapAPrintf(pVM, MM_TAG_PDM_DRIVER_DESC, "%s_%u", pszName, pDrvIns->iInstance);
953 AssertLogRelReturn(pszName, VERR_NO_MEMORY);
954 }
955
956 int rc = PDMR3QueueCreateDriver(pVM, pDrvIns, cbItem, cItems, cMilliesInterval, pfnCallback, pszName, ppQueue);
957
958 LogFlow(("pdmR3DrvHlp_PDMQueueCreate: caller='%s'/%d: returns %Rrc *ppQueue=%p\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc, *ppQueue));
959 return rc;
960}
961
962
963/** @interface_method_impl{PDMDRVHLP,pfnTMGetVirtualFreq} */
964static DECLCALLBACK(uint64_t) pdmR3DrvHlp_TMGetVirtualFreq(PPDMDRVINS pDrvIns)
965{
966 PDMDRV_ASSERT_DRVINS(pDrvIns);
967
968 return TMVirtualGetFreq(pDrvIns->Internal.s.pVMR3);
969}
970
971
972/** @interface_method_impl{PDMDRVHLP,pfnTMGetVirtualTime} */
973static DECLCALLBACK(uint64_t) pdmR3DrvHlp_TMGetVirtualTime(PPDMDRVINS pDrvIns)
974{
975 PDMDRV_ASSERT_DRVINS(pDrvIns);
976
977 return TMVirtualGet(pDrvIns->Internal.s.pVMR3);
978}
979
980
981/** @interface_method_impl{PDMDRVHLP,pfnTMTimerCreate} */
982static DECLCALLBACK(int) pdmR3DrvHlp_TMTimerCreate(PPDMDRVINS pDrvIns, TMCLOCK enmClock, PFNTMTIMERDRV pfnCallback, void *pvUser, uint32_t fFlags, const char *pszDesc, PPTMTIMERR3 ppTimer)
983{
984 PDMDRV_ASSERT_DRVINS(pDrvIns);
985 LogFlow(("pdmR3DrvHlp_TMTimerCreate: caller='%s'/%d: enmClock=%d pfnCallback=%p pvUser=%p fFlags=%#x pszDesc=%p:{%s} ppTimer=%p\n",
986 pDrvIns->pReg->szName, pDrvIns->iInstance, enmClock, pfnCallback, pvUser, fFlags, pszDesc, pszDesc, ppTimer));
987
988 int rc = TMR3TimerCreateDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, ppTimer);
989
990 LogFlow(("pdmR3DrvHlp_TMTimerCreate: caller='%s'/%d: returns %Rrc *ppTimer=%p\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc, *ppTimer));
991 return rc;
992}
993
994
995
996/** @interface_method_impl{PDMDRVHLP,pfnSSMRegister} */
997static DECLCALLBACK(int) pdmR3DrvHlp_SSMRegister(PPDMDRVINS pDrvIns, uint32_t uVersion, size_t cbGuess,
998 PFNSSMDRVLIVEPREP pfnLivePrep, PFNSSMDRVLIVEEXEC pfnLiveExec, PFNSSMDRVLIVEVOTE pfnLiveVote,
999 PFNSSMDRVSAVEPREP pfnSavePrep, PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVSAVEDONE pfnSaveDone,
1000 PFNSSMDRVLOADPREP pfnLoadPrep, PFNSSMDRVLOADEXEC pfnLoadExec, PFNSSMDRVLOADDONE pfnLoadDone)
1001{
1002 PDMDRV_ASSERT_DRVINS(pDrvIns);
1003 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1004 LogFlow(("pdmR3DrvHlp_SSMRegister: caller='%s'/%d: uVersion=#x cbGuess=%#x \n"
1005 " pfnLivePrep=%p pfnLiveExec=%p pfnLiveVote=%p pfnSavePrep=%p pfnSaveExec=%p pfnSaveDone=%p pszLoadPrep=%p pfnLoadExec=%p pfnLoaddone=%p\n",
1006 pDrvIns->pReg->szName, pDrvIns->iInstance, uVersion, cbGuess,
1007 pfnLivePrep, pfnLiveExec, pfnLiveVote,
1008 pfnSavePrep, pfnSaveExec, pfnSaveDone, pfnLoadPrep, pfnLoadExec, pfnLoadDone));
1009
1010 int rc = SSMR3RegisterDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, pDrvIns->pReg->szName, pDrvIns->iInstance,
1011 uVersion, cbGuess,
1012 pfnLivePrep, pfnLiveExec, pfnLiveVote,
1013 pfnSavePrep, pfnSaveExec, pfnSaveDone,
1014 pfnLoadPrep, pfnLoadExec, pfnLoadDone);
1015
1016 LogFlow(("pdmR3DrvHlp_SSMRegister: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1017 return rc;
1018}
1019
1020
1021/** @interface_method_impl{PDMDRVHLP,pfnSSMDeregister} */
1022static DECLCALLBACK(int) pdmR3DrvHlp_SSMDeregister(PPDMDRVINS pDrvIns, const char *pszName, uint32_t u32Instance)
1023{
1024 PDMDRV_ASSERT_DRVINS(pDrvIns);
1025 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1026 LogFlow(("pdmR3DrvHlp_SSMDeregister: caller='%s'/%d: pszName=%p:{%s} u32Instance=%#x\n",
1027 pDrvIns->pReg->szName, pDrvIns->iInstance, pszName, pszName, u32Instance));
1028
1029 int rc = SSMR3DeregisterDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, pszName, u32Instance);
1030
1031 LogFlow(("pdmR3DrvHlp_SSMDeregister: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1032 return rc;
1033}
1034
1035
1036/** @interface_method_impl{PDMDRVHLP,pfnSTAMRegister} */
1037static DECLCALLBACK(void) pdmR3DrvHlp_STAMRegister(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, const char *pszName, STAMUNIT enmUnit, const char *pszDesc)
1038{
1039 PDMDRV_ASSERT_DRVINS(pDrvIns);
1040 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1041
1042 STAM_REG(pDrvIns->Internal.s.pVMR3, pvSample, enmType, pszName, enmUnit, pszDesc);
1043 /** @todo track the samples so they can be dumped & deregistered when the driver instance is destroyed.
1044 * For now we just have to be careful not to use this call for drivers which can be unloaded. */
1045}
1046
1047
1048/** @interface_method_impl{PDMDRVHLP,pfnSTAMRegisterF} */
1049static DECLCALLBACK(void) pdmR3DrvHlp_STAMRegisterF(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
1050 STAMUNIT enmUnit, const char *pszDesc, const char *pszName, ...)
1051{
1052 PDMDRV_ASSERT_DRVINS(pDrvIns);
1053 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1054
1055 va_list args;
1056 va_start(args, pszName);
1057 int rc = STAMR3RegisterV(pDrvIns->Internal.s.pVMR3, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, args);
1058 va_end(args);
1059 AssertRC(rc);
1060}
1061
1062
1063/** @interface_method_impl{PDMDRVHLP,pfnSTAMRegisterV} */
1064static DECLCALLBACK(void) pdmR3DrvHlp_STAMRegisterV(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
1065 STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list args)
1066{
1067 PDMDRV_ASSERT_DRVINS(pDrvIns);
1068 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1069
1070 int rc = STAMR3RegisterV(pDrvIns->Internal.s.pVMR3, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, args);
1071 AssertRC(rc);
1072}
1073
1074
1075/** @interface_method_impl{PDMDRVHLP,pfnSTAMDeregister} */
1076static DECLCALLBACK(int) pdmR3DrvHlp_STAMDeregister(PPDMDRVINS pDrvIns, void *pvSample)
1077{
1078 PDMDRV_ASSERT_DRVINS(pDrvIns);
1079 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1080
1081 int rc = STAMR3DeregisterU(pDrvIns->Internal.s.pVMR3->pUVM, pvSample);
1082 AssertRC(rc);
1083 return rc;
1084}
1085
1086
1087/** @interface_method_impl{PDMDRVHLP,pfnSUPCallVMMR0Ex} */
1088static DECLCALLBACK(int) pdmR3DrvHlp_SUPCallVMMR0Ex(PPDMDRVINS pDrvIns, unsigned uOperation, void *pvArg, unsigned cbArg)
1089{
1090 PDMDRV_ASSERT_DRVINS(pDrvIns);
1091 LogFlow(("pdmR3DrvHlp_SSMCallVMMR0Ex: caller='%s'/%d: uOperation=%u pvArg=%p cbArg=%d\n",
1092 pDrvIns->pReg->szName, pDrvIns->iInstance, uOperation, pvArg, cbArg));
1093 int rc;
1094 if ( uOperation >= VMMR0_DO_SRV_START
1095 && uOperation < VMMR0_DO_SRV_END)
1096 rc = SUPR3CallVMMR0Ex(pDrvIns->Internal.s.pVMR3->pVMR0, NIL_VMCPUID, uOperation, 0, (PSUPVMMR0REQHDR)pvArg);
1097 else
1098 {
1099 AssertMsgFailed(("Invalid uOperation=%u\n", uOperation));
1100 rc = VERR_INVALID_PARAMETER;
1101 }
1102
1103 LogFlow(("pdmR3DrvHlp_SUPCallVMMR0Ex: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1104 return rc;
1105}
1106
1107
1108/** @interface_method_impl{PDMDRVHLP,pfnUSBRegisterHub} */
1109static DECLCALLBACK(int) pdmR3DrvHlp_USBRegisterHub(PPDMDRVINS pDrvIns, uint32_t fVersions, uint32_t cPorts, PCPDMUSBHUBREG pUsbHubReg, PPCPDMUSBHUBHLP ppUsbHubHlp)
1110{
1111 PDMDRV_ASSERT_DRVINS(pDrvIns);
1112 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1113 LogFlow(("pdmR3DrvHlp_USBRegisterHub: caller='%s'/%d: fVersions=%#x cPorts=%#x pUsbHubReg=%p ppUsbHubHlp=%p\n",
1114 pDrvIns->pReg->szName, pDrvIns->iInstance, fVersions, cPorts, pUsbHubReg, ppUsbHubHlp));
1115
1116#ifdef VBOX_WITH_USB
1117 int rc = pdmR3UsbRegisterHub(pDrvIns->Internal.s.pVMR3, pDrvIns, fVersions, cPorts, pUsbHubReg, ppUsbHubHlp);
1118#else
1119 int rc = VERR_NOT_SUPPORTED;
1120#endif
1121
1122 LogFlow(("pdmR3DrvHlp_USBRegisterHub: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1123 return rc;
1124}
1125
1126
1127/** @interface_method_impl{PDMDRVHLP,pfnSetAsyncNotification} */
1128static DECLCALLBACK(int) pdmR3DrvHlp_SetAsyncNotification(PPDMDRVINS pDrvIns, PFNPDMDRVASYNCNOTIFY pfnAsyncNotify)
1129{
1130 PDMDRV_ASSERT_DRVINS(pDrvIns);
1131 VM_ASSERT_EMT0(pDrvIns->Internal.s.pVMR3);
1132 LogFlow(("pdmR3DrvHlp_SetAsyncNotification: caller='%s'/%d: pfnAsyncNotify=%p\n", pDrvIns->pReg->szName, pDrvIns->iInstance, pfnAsyncNotify));
1133
1134 int rc = VINF_SUCCESS;
1135 AssertStmt(pfnAsyncNotify, rc = VERR_INVALID_PARAMETER);
1136 AssertStmt(!pDrvIns->Internal.s.pfnAsyncNotify, rc = VERR_WRONG_ORDER);
1137 AssertStmt(pDrvIns->Internal.s.fVMSuspended || pDrvIns->Internal.s.fVMReset, rc = VERR_WRONG_ORDER);
1138 VMSTATE enmVMState = VMR3GetState(pDrvIns->Internal.s.pVMR3);
1139 AssertStmt( enmVMState == VMSTATE_SUSPENDING
1140 || enmVMState == VMSTATE_SUSPENDING_EXT_LS
1141 || enmVMState == VMSTATE_SUSPENDING_LS
1142 || enmVMState == VMSTATE_RESETTING
1143 || enmVMState == VMSTATE_RESETTING_LS
1144 || enmVMState == VMSTATE_POWERING_OFF
1145 || enmVMState == VMSTATE_POWERING_OFF_LS,
1146 rc = VERR_INVALID_STATE);
1147
1148 if (RT_SUCCESS(rc))
1149 pDrvIns->Internal.s.pfnAsyncNotify = pfnAsyncNotify;
1150
1151 LogFlow(("pdmR3DrvHlp_SetAsyncNotification: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName, pDrvIns->iInstance, rc));
1152 return rc;
1153}
1154
1155
1156/** @interface_method_impl{PDMDRVHLP,pfnAsyncNotificationCompleted} */
1157static DECLCALLBACK(void) pdmR3DrvHlp_AsyncNotificationCompleted(PPDMDRVINS pDrvIns)
1158{
1159 PDMDRV_ASSERT_DRVINS(pDrvIns);
1160 PVM pVM = pDrvIns->Internal.s.pVMR3;
1161
1162 VMSTATE enmVMState = VMR3GetState(pVM);
1163 if ( enmVMState == VMSTATE_SUSPENDING
1164 || enmVMState == VMSTATE_SUSPENDING_EXT_LS
1165 || enmVMState == VMSTATE_SUSPENDING_LS
1166 || enmVMState == VMSTATE_RESETTING
1167 || enmVMState == VMSTATE_RESETTING_LS
1168 || enmVMState == VMSTATE_POWERING_OFF
1169 || enmVMState == VMSTATE_POWERING_OFF_LS)
1170 {
1171 LogFlow(("pdmR3DrvHlp_AsyncNotificationCompleted: caller='%s'/%d:\n", pDrvIns->pReg->szName, pDrvIns->iInstance));
1172 VMR3AsyncPdmNotificationWakeupU(pVM->pUVM);
1173 }
1174 else
1175 LogFlow(("pdmR3DrvHlp_AsyncNotificationCompleted: caller='%s'/%d: enmVMState=%d\n", pDrvIns->pReg->szName, pDrvIns->iInstance, enmVMState));
1176}
1177
1178
1179/** @interface_method_impl{PDMDRVHLP,pfnThreadCreate} */
1180static DECLCALLBACK(int) pdmR3DrvHlp_ThreadCreate(PPDMDRVINS pDrvIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDRV pfnThread,
1181 PFNPDMTHREADWAKEUPDRV pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
1182{
1183 PDMDRV_ASSERT_DRVINS(pDrvIns);
1184 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1185 LogFlow(("pdmR3DrvHlp_ThreadCreate: caller='%s'/%d: ppThread=%p pvUser=%p pfnThread=%p pfnWakeup=%p cbStack=%#zx enmType=%d pszName=%p:{%s}\n",
1186 pDrvIns->pReg->szName, pDrvIns->iInstance, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName, pszName));
1187
1188 int rc = pdmR3ThreadCreateDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName);
1189
1190 LogFlow(("pdmR3DrvHlp_ThreadCreate: caller='%s'/%d: returns %Rrc *ppThread=%RTthrd\n", pDrvIns->pReg->szName, pDrvIns->iInstance,
1191 rc, *ppThread));
1192 return rc;
1193}
1194
1195
1196/** @interface_method_impl{PDMDRVHLP,pfnAsyncCompletionTemplateCreate} */
1197static DECLCALLBACK(int) pdmR3DrvHlp_AsyncCompletionTemplateCreate(PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate,
1198 PFNPDMASYNCCOMPLETEDRV pfnCompleted, void *pvTemplateUser,
1199 const char *pszDesc)
1200{
1201 PDMDRV_ASSERT_DRVINS(pDrvIns);
1202 LogFlow(("pdmR3DrvHlp_AsyncCompletionTemplateCreate: caller='%s'/%d: ppTemplate=%p pfnCompleted=%p pszDesc=%p:{%s}\n",
1203 pDrvIns->pReg->szName, pDrvIns->iInstance, ppTemplate, pfnCompleted, pszDesc, pszDesc));
1204
1205 int rc = PDMR3AsyncCompletionTemplateCreateDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, ppTemplate, pfnCompleted, pvTemplateUser, pszDesc);
1206
1207 LogFlow(("pdmR3DrvHlp_AsyncCompletionTemplateCreate: caller='%s'/%d: returns %Rrc *ppThread=%p\n", pDrvIns->pReg->szName,
1208 pDrvIns->iInstance, rc, *ppTemplate));
1209 return rc;
1210}
1211
1212
1213/** @interface_method_impl{PDMDRVHLP,pfnLdrGetRCInterfaceSymbols} */
1214static DECLCALLBACK(int) pdmR3DrvHlp_LdrGetRCInterfaceSymbols(PPDMDRVINS pDrvIns, void *pvInterface, size_t cbInterface,
1215 const char *pszSymPrefix, const char *pszSymList)
1216{
1217 PDMDRV_ASSERT_DRVINS(pDrvIns);
1218 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1219 LogFlow(("pdmR3DrvHlp_LdrGetRCInterfaceSymbols: caller='%s'/%d: pvInterface=%p cbInterface=%zu pszSymPrefix=%p:{%s} pszSymList=%p:{%s}\n",
1220 pDrvIns->pReg->szName, pDrvIns->iInstance, pvInterface, cbInterface, pszSymPrefix, pszSymPrefix, pszSymList, pszSymList));
1221
1222 int rc;
1223 if ( strncmp(pszSymPrefix, "drv", 3) == 0
1224 && RTStrIStr(pszSymPrefix + 3, pDrvIns->pReg->szName) != NULL)
1225 {
1226 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_RC)
1227 rc = PDMR3LdrGetInterfaceSymbols(pDrvIns->Internal.s.pVMR3, pvInterface, cbInterface,
1228 pDrvIns->pReg->szRCMod, pszSymPrefix, pszSymList,
1229 false /*fRing0OrRC*/);
1230 else
1231 {
1232 AssertMsgFailed(("Not a raw-mode enabled driver\n"));
1233 rc = VERR_PERMISSION_DENIED;
1234 }
1235 }
1236 else
1237 {
1238 AssertMsgFailed(("Invalid prefix '%s' for '%s'; must start with 'drv' and contain the driver name!\n",
1239 pszSymPrefix, pDrvIns->pReg->szName));
1240 rc = VERR_INVALID_NAME;
1241 }
1242
1243 LogFlow(("pdmR3DrvHlp_LdrGetRCInterfaceSymbols: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1244 pDrvIns->iInstance, rc));
1245 return rc;
1246}
1247
1248
1249/** @interface_method_impl{PDMDRVHLP,pfnLdrGetR0InterfaceSymbols} */
1250static DECLCALLBACK(int) pdmR3DrvHlp_LdrGetR0InterfaceSymbols(PPDMDRVINS pDrvIns, void *pvInterface, size_t cbInterface,
1251 const char *pszSymPrefix, const char *pszSymList)
1252{
1253 PDMDRV_ASSERT_DRVINS(pDrvIns);
1254 VM_ASSERT_EMT(pDrvIns->Internal.s.pVMR3);
1255 LogFlow(("pdmR3DrvHlp_LdrGetR0InterfaceSymbols: caller='%s'/%d: pvInterface=%p cbInterface=%zu pszSymPrefix=%p:{%s} pszSymList=%p:{%s}\n",
1256 pDrvIns->pReg->szName, pDrvIns->iInstance, pvInterface, cbInterface, pszSymPrefix, pszSymPrefix, pszSymList, pszSymList));
1257
1258 int rc;
1259 if ( strncmp(pszSymPrefix, "drv", 3) == 0
1260 && RTStrIStr(pszSymPrefix + 3, pDrvIns->pReg->szName) != NULL)
1261 {
1262 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_R0)
1263 rc = PDMR3LdrGetInterfaceSymbols(pDrvIns->Internal.s.pVMR3, pvInterface, cbInterface,
1264 pDrvIns->pReg->szR0Mod, pszSymPrefix, pszSymList,
1265 true /*fRing0OrRC*/);
1266 else
1267 {
1268 AssertMsgFailed(("Not a ring-0 enabled driver\n"));
1269 rc = VERR_PERMISSION_DENIED;
1270 }
1271 }
1272 else
1273 {
1274 AssertMsgFailed(("Invalid prefix '%s' for '%s'; must start with 'drv' and contain the driver name!\n",
1275 pszSymPrefix, pDrvIns->pReg->szName));
1276 rc = VERR_INVALID_NAME;
1277 }
1278
1279 LogFlow(("pdmR3DrvHlp_LdrGetR0InterfaceSymbols: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1280 pDrvIns->iInstance, rc));
1281 return rc;
1282}
1283
1284
1285/** @interface_method_impl{PDMDRVHLP,pfnCritSectInit} */
1286static DECLCALLBACK(int) pdmR3DrvHlp_CritSectInit(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect,
1287 RT_SRC_POS_DECL, const char *pszName)
1288{
1289 PDMDRV_ASSERT_DRVINS(pDrvIns);
1290 PVM pVM = pDrvIns->Internal.s.pVMR3;
1291 VM_ASSERT_EMT(pVM);
1292 LogFlow(("pdmR3DrvHlp_CritSectInit: caller='%s'/%d: pCritSect=%p pszName=%s\n",
1293 pDrvIns->pReg->szName, pDrvIns->iInstance, pCritSect, pszName));
1294
1295 int rc = pdmR3CritSectInitDriver(pVM, pDrvIns, pCritSect, RT_SRC_POS_ARGS, "%s_%u", pszName, pDrvIns->iInstance);
1296
1297 LogFlow(("pdmR3DrvHlp_CritSectInit: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1298 pDrvIns->iInstance, rc));
1299 return rc;
1300}
1301
1302
1303/** @interface_method_impl{PDMDRVHLP,pfnCallR0} */
1304static DECLCALLBACK(int) pdmR3DrvHlp_CallR0(PPDMDRVINS pDrvIns, uint32_t uOperation, uint64_t u64Arg)
1305{
1306 PDMDRV_ASSERT_DRVINS(pDrvIns);
1307 PVM pVM = pDrvIns->Internal.s.pVMR3;
1308 LogFlow(("pdmR3DrvHlp_CallR0: caller='%s'/%d: uOperation=%#x u64Arg=%#RX64\n",
1309 pDrvIns->pReg->szName, pDrvIns->iInstance, uOperation, u64Arg));
1310
1311 /*
1312 * Lazy resolve the ring-0 entry point.
1313 */
1314 int rc = VINF_SUCCESS;
1315 PFNPDMDRVREQHANDLERR0 pfnReqHandlerR0 = pDrvIns->Internal.s.pfnReqHandlerR0;
1316 if (RT_UNLIKELY(pfnReqHandlerR0 == NIL_RTR0PTR))
1317 {
1318 if (pDrvIns->pReg->fFlags & PDM_DRVREG_FLAGS_R0)
1319 {
1320 char szSymbol[ sizeof("drvR0") + sizeof(pDrvIns->pReg->szName) + sizeof("ReqHandler")];
1321 strcat(strcat(strcpy(szSymbol, "drvR0"), pDrvIns->pReg->szName), "ReqHandler");
1322 szSymbol[sizeof("drvR0") - 1] = RT_C_TO_UPPER(szSymbol[sizeof("drvR0") - 1]);
1323
1324 rc = PDMR3LdrGetSymbolR0Lazy(pVM, pDrvIns->pReg->szR0Mod, szSymbol, &pfnReqHandlerR0);
1325 if (RT_SUCCESS(rc))
1326 pDrvIns->Internal.s.pfnReqHandlerR0 = pfnReqHandlerR0;
1327 else
1328 pfnReqHandlerR0 = NIL_RTR0PTR;
1329 }
1330 else
1331 rc = VERR_ACCESS_DENIED;
1332 }
1333 if (RT_LIKELY(pfnReqHandlerR0 != NIL_RTR0PTR))
1334 {
1335 /*
1336 * Make the ring-0 call.
1337 */
1338 PDMDRIVERCALLREQHANDLERREQ Req;
1339 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1340 Req.Hdr.cbReq = sizeof(Req);
1341 Req.pDrvInsR0 = PDMDRVINS_2_R0PTR(pDrvIns);
1342 Req.uOperation = uOperation;
1343 Req.u32Alignment = 0;
1344 Req.u64Arg = u64Arg;
1345 rc = SUPR3CallVMMR0Ex(pVM->pVMR0, NIL_VMCPUID, VMMR0_DO_PDM_DRIVER_CALL_REQ_HANDLER, 0, &Req.Hdr);
1346 }
1347
1348 LogFlow(("pdmR3DrvHlp_CallR0: caller='%s'/%d: returns %Rrc\n", pDrvIns->pReg->szName,
1349 pDrvIns->iInstance, rc));
1350 return rc;
1351}
1352
1353
1354/**
1355 * The driver helper structure.
1356 */
1357const PDMDRVHLPR3 g_pdmR3DrvHlp =
1358{
1359 PDM_DRVHLPR3_VERSION,
1360 pdmR3DrvHlp_Attach,
1361 pdmR3DrvHlp_Detach,
1362 pdmR3DrvHlp_DetachSelf,
1363 pdmR3DrvHlp_MountPrepare,
1364 pdmR3DrvHlp_AssertEMT,
1365 pdmR3DrvHlp_AssertOther,
1366 pdmR3DrvHlp_VMSetError,
1367 pdmR3DrvHlp_VMSetErrorV,
1368 pdmR3DrvHlp_VMSetRuntimeError,
1369 pdmR3DrvHlp_VMSetRuntimeErrorV,
1370 pdmR3DrvHlp_VMState,
1371 pdmR3DrvHlp_VMTeleportedAndNotFullyResumedYet,
1372 pdmR3DrvHlp_GetSupDrvSession,
1373 pdmR3DrvHlp_QueueCreate,
1374 pdmR3DrvHlp_TMGetVirtualFreq,
1375 pdmR3DrvHlp_TMGetVirtualTime,
1376 pdmR3DrvHlp_TMTimerCreate,
1377 pdmR3DrvHlp_SSMRegister,
1378 pdmR3DrvHlp_SSMDeregister,
1379 pdmR3DrvHlp_STAMRegister,
1380 pdmR3DrvHlp_STAMRegisterF,
1381 pdmR3DrvHlp_STAMRegisterV,
1382 pdmR3DrvHlp_STAMDeregister,
1383 pdmR3DrvHlp_SUPCallVMMR0Ex,
1384 pdmR3DrvHlp_USBRegisterHub,
1385 pdmR3DrvHlp_SetAsyncNotification,
1386 pdmR3DrvHlp_AsyncNotificationCompleted,
1387 pdmR3DrvHlp_ThreadCreate,
1388 pdmR3DrvHlp_AsyncCompletionTemplateCreate,
1389 pdmR3DrvHlp_LdrGetRCInterfaceSymbols,
1390 pdmR3DrvHlp_LdrGetR0InterfaceSymbols,
1391 pdmR3DrvHlp_CritSectInit,
1392 pdmR3DrvHlp_CallR0,
1393 PDM_DRVHLPR3_VERSION /* u32TheEnd */
1394};
1395
1396/** @} */
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