VirtualBox

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

Last change on this file since 29450 was 28853, checked in by vboxsync, 15 years ago

PDMR3AsyncCompletionTemplateCreateDriver,PDMDRVHLP::pfnAsyncCompletionTemplateCreate: Don't require EMT, the list operations are locked.

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