VirtualBox

source: vbox/trunk/src/VBox/Devices/Misc/DevPlatform.cpp@ 106129

Last change on this file since 106129 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.6 KB
Line 
1/* $Id: DevPlatform.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * DevPlatform - Guest platform <-> VirtualBox Integration Framework.
4 */
5
6/*
7 * Copyright (C) 2023-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_DEV_PLATFORM
33
34#include <VBox/vmm/pdmdev.h>
35#include <VBox/vmm/pgm.h>
36#include <VBox/vmm/cpum.h>
37#include <VBox/vmm/mm.h>
38#include <VBox/log.h>
39#include <VBox/err.h>
40#include <VBox/param.h>
41#include <VBox/vmm/dbgf.h>
42
43#include <iprt/asm.h>
44#include <iprt/assert.h>
45#include <iprt/ctype.h>
46#include <iprt/file.h>
47#include <iprt/list.h>
48#include <iprt/mem.h>
49#include <iprt/string.h>
50#include <iprt/uuid.h>
51#include <iprt/path.h>
52#include <iprt/string.h>
53
54#include "VBoxDD.h"
55#include "VBoxDD2.h"
56
57
58/*********************************************************************************************************************************
59* Structures and Typedefs *
60*********************************************************************************************************************************/
61/**
62 * Platform resource entry.
63 */
64typedef struct DEVPLATFORMRESOURCE
65{
66 /** Node in the list of resources added to the VM. */
67 RTLISTNODE NdLst;
68 /** The ID in the resource store or filename to load. */
69 const char *pszResourceIdOrFilename;
70 /** The physical load address of the resource. */
71 RTGCPHYS GCPhysResource;
72 /** The resource data. */
73 uint8_t const *pu8Resource;
74 /** The resource data pointer to be passed to RTFileReadAllFree (only valid when DEVPLATFORMRESOURCE::fResourceId is false). */
75 uint8_t *pu8ResourceFree;
76 /** The size of the resource. */
77 size_t cbResource;
78 /** Flag whether the resource is loaded from the resource store of from a file. */
79 bool fResourceId;
80 /** Name of the resource. */
81 char szName[32];
82} DEVPLATFORMRESOURCE;
83/** Pointer to a platform resource entry. */
84typedef DEVPLATFORMRESOURCE *PDEVPLATFORMRESOURCE;
85/** Pointer to a constant platform resource entry. */
86typedef const DEVPLATFORMRESOURCE *PCDEVPLATFORMRESOURCE;
87
88
89/**
90 * The plaatform device state structure, shared state.
91 */
92typedef struct DEVPLATFORM
93{
94 /** Pointer back to the device instance. */
95 PPDMDEVINS pDevIns;
96
97 /** The resource namespace. */
98 char *pszResourceNamespace;
99
100 /** List head for resources added in the memory setup phase
101 * (written to guest memory). */
102 RTLISTANCHOR LstResourcesMem;
103 /** List head for resources added as a ROM file. */
104 RTLISTANCHOR LstResourcesRom;
105
106 /**
107 * Resource port - LUN\#0.
108 */
109 struct
110 {
111 /** The base interface we provide the resource driver. */
112 PDMIBASE IBase;
113 /** The resource driver base interface. */
114 PPDMIBASE pDrvBase;
115 /** The VFS interface of the driver below for resource state loading and storing. */
116 PPDMIVFSCONNECTOR pDrvVfs;
117 } Lun0;
118} DEVPLATFORM;
119/** Pointer to the platform device state. */
120typedef DEVPLATFORM *PDEVPLATFORM;
121
122
123/*********************************************************************************************************************************
124* Defined Constants And Macros *
125*********************************************************************************************************************************/
126
127
128/*********************************************************************************************************************************
129* Global Variables *
130*********************************************************************************************************************************/
131# ifdef VBOX_WITH_EFI_IN_DD2
132/** Special file name value for indicating the 32-bit built-in EFI firmware. */
133static const char g_szEfiBuiltinAArch32[] = "VBoxEFIAArch32.fd";
134/** Special file name value for indicating the 64-bit built-in EFI firmware. */
135static const char g_szEfiBuiltinAArch64[] = "VBoxEFIAArch64.fd";
136# endif
137
138
139/**
140 * Resolves the given resource content.
141 *
142 * @returns VBox status code.
143 * @param pDevIns The device instance data.
144 * @param pThis The device state for the current context.
145 * @param pRes The resource to resolve.
146 * @param ppvFree Where to store pointer to the function freeing the resource data
147 * (RTFileReadAllFree() or PDMDevHlpMMHeapFree()).
148 * @param ppv Where to store the pointer to the reoucer data content.
149 * @param pcb Where to store the size of the content in bytes.
150 */
151static int platformR3ResourceResolveContent(PPDMDEVINS pDevIns, PDEVPLATFORM pThis,
152 PCDEVPLATFORMRESOURCE pRes,
153 void **ppvFree, void const **ppv, size_t *pcb)
154{
155 if (pRes->fResourceId)
156 {
157#ifdef VBOX_WITH_EFI_IN_DD2
158 if (RTStrCmp(pRes->pszResourceIdOrFilename, g_szEfiBuiltinAArch32) == 0)
159 {
160 *ppvFree = NULL;
161 *ppv = g_abEfiFirmwareAArch32;
162 *pcb = g_cbEfiFirmwareAArch32;
163 }
164 else if (RTStrCmp(pRes->pszResourceIdOrFilename, g_szEfiBuiltinAArch64) == 0)
165 {
166 *ppvFree = NULL;
167 *ppv = g_abEfiFirmwareAArch64;
168 *pcb = g_cbEfiFirmwareAArch64;
169 }
170 else
171#endif
172 {
173 AssertPtrReturn(pThis->Lun0.pDrvVfs, VERR_INVALID_STATE);
174
175 uint64_t cbResource = 0;
176 int rc = pThis->Lun0.pDrvVfs->pfnQuerySize(pThis->Lun0.pDrvVfs, pThis->pszResourceNamespace, pRes->pszResourceIdOrFilename, &cbResource);
177 if (RT_SUCCESS(rc))
178 {
179 void *pv = PDMDevHlpMMHeapAlloc(pDevIns, cbResource);
180 if (pv)
181 {
182 rc = pThis->Lun0.pDrvVfs->pfnReadAll(pThis->Lun0.pDrvVfs, pThis->pszResourceNamespace, pRes->pszResourceIdOrFilename, pv, cbResource);
183 if (RT_FAILURE(rc))
184 {
185 PDMDevHlpMMHeapFree(pDevIns, pv);
186 return rc;
187 }
188
189 *ppvFree = pv;
190 *ppv = pv;
191 *pcb = cbResource;
192 }
193 else
194 rc = VERR_NO_MEMORY;
195 }
196 AssertLogRelRCReturn(rc, rc);
197 }
198 }
199 else
200 {
201 void *pvFile;
202 size_t cbFile;
203 int rc = RTFileReadAllEx(pRes->pszResourceIdOrFilename,
204 0 /*off*/,
205 RTFOFF_MAX /*cbMax*/,
206 RTFILE_RDALL_O_DENY_WRITE,
207 &pvFile,
208 &cbFile);
209 if (RT_FAILURE(rc))
210 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
211 N_("Loading the resource '%s' failed with rc=%Rrc"),
212 pRes->pszResourceIdOrFilename, rc);
213 *ppvFree = (uint8_t *)pvFile;
214 *ppv = (uint8_t *)pvFile;
215 *pcb = cbFile;
216 }
217
218 return VINF_SUCCESS;
219}
220
221
222/**
223 * Returns the load address of the given resource.
224 *
225 * @returns Guest physical load address of the resource.
226 * @param pDevIns The device instance data.
227 * @param pRes The resource to get the load address from.
228 */
229DECLINLINE(RTGCPHYS) platformR3ResourceGetLoadAddress(PPDMDEVINS pDevIns, PCDEVPLATFORMRESOURCE pRes)
230{
231 /*
232 * Maximum means determine the guest physical address width and place at the end
233 * (which requires the size of the resource to be known (assuming we won't ever have
234 * one byte large contents to be placed at the end).
235 */
236 if (pRes->GCPhysResource == RTGCPHYS_MAX)
237 {
238 uint8_t cPhysAddrBits, cLinearAddrBits;
239 PDMDevHlpCpuGetGuestAddrWidths(pDevIns, &cPhysAddrBits, &cLinearAddrBits);
240
241 return RT_BIT_64(cPhysAddrBits) - pRes->cbResource;
242 }
243
244 return pRes->GCPhysResource;
245}
246
247
248/**
249 * Destroys the given resource list.
250 *
251 * @param pDevIns The device instance data.
252 * @param pLst The resource list to destroy.
253 */
254static void platformR3DestructResourceList(PPDMDEVINS pDevIns, PRTLISTANCHOR pLst)
255{
256 PDEVPLATFORMRESOURCE pIt, pItNext;
257
258 RTListForEachSafe(pLst, pIt, pItNext, DEVPLATFORMRESOURCE, NdLst)
259 {
260 RTListNodeRemove(&pIt->NdLst);
261
262 if (pIt->pu8ResourceFree)
263 {
264 if (!pIt->fResourceId)
265 RTFileReadAllFree(pIt->pu8ResourceFree, (size_t)pIt->cbResource);
266 else
267 PDMDevHlpMMHeapFree(pDevIns, pIt->pu8ResourceFree);
268 }
269
270 PDMDevHlpMMHeapFree(pDevIns, (void *)pIt->pszResourceIdOrFilename);
271
272 pIt->pszResourceIdOrFilename = NULL;
273 pIt->pu8ResourceFree = NULL;
274 pIt->pu8Resource = NULL;
275 pIt->cbResource = 0;
276
277 PDMDevHlpMMHeapFree(pDevIns, pIt);
278 }
279}
280
281
282/**
283 * @copydoc(PDMIBASE::pfnQueryInterface)
284 */
285static DECLCALLBACK(void *) platformR3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
286{
287 LogFlowFunc(("ENTER: pIBase=%p pszIID=%p\n", pInterface, pszIID));
288 PDEVPLATFORM pThis = RT_FROM_MEMBER(pInterface, DEVPLATFORM, Lun0.IBase);
289
290 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Lun0.IBase);
291 return NULL;
292}
293
294
295/**
296 * @interface_method_impl{PDMDEVREG,pfnMemSetup}
297 */
298static DECLCALLBACK(void) platformR3MemSetup(PPDMDEVINS pDevIns, PDMDEVMEMSETUPCTX enmCtx)
299{
300 PDEVPLATFORM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPLATFORM);
301 LogFlow(("platformR3MemSetup\n"));
302
303 RT_NOREF(enmCtx);
304
305 /* Iterate over the memory resource list and write everything there. */
306 PDEVPLATFORMRESOURCE pIt;
307 RTListForEach(&pThis->LstResourcesMem, pIt, DEVPLATFORMRESOURCE, NdLst)
308 {
309 int rc = platformR3ResourceResolveContent(pDevIns, pThis, pIt, (void **)&pIt->pu8ResourceFree, (const void **)&pIt->pu8Resource, &pIt->cbResource);
310 if (RT_SUCCESS(rc))
311 {
312 rc = PDMDevHlpPhysWrite(pDevIns, platformR3ResourceGetLoadAddress(pDevIns, pIt), pIt->pu8Resource, pIt->cbResource);
313
314 /* Don't need to keep it around, will be queried the next time the VM is reset. */
315 if (pIt->pu8ResourceFree)
316 {
317 if (!pIt->fResourceId)
318 RTFileReadAllFree(pIt->pu8ResourceFree, (size_t)pIt->cbResource);
319 else
320 PDMDevHlpMMHeapFree(pDevIns, pIt->pu8ResourceFree);
321 }
322
323 pIt->pu8ResourceFree = NULL;
324 pIt->pu8Resource = NULL;
325 pIt->cbResource = 0;
326 }
327 AssertLogRelRCReturnVoid(rc);
328 }
329}
330
331
332/**
333 * Destruct a device instance.
334 *
335 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
336 * resources can be freed correctly.
337 *
338 * @param pDevIns The device instance data.
339 */
340static DECLCALLBACK(int) platformR3Destruct(PPDMDEVINS pDevIns)
341{
342 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
343 PDEVPLATFORM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPLATFORM);
344
345 /*
346 * Walk the resource lists and free everything.
347 */
348 platformR3DestructResourceList(pDevIns, &pThis->LstResourcesMem);
349 platformR3DestructResourceList(pDevIns, &pThis->LstResourcesRom);
350
351 RTListInit(&pThis->LstResourcesMem);
352 RTListInit(&pThis->LstResourcesRom);
353
354 /*
355 * Free MM heap pointers (waste of time, but whatever).
356 */
357 if (pThis->pszResourceNamespace)
358 {
359 PDMDevHlpMMHeapFree(pDevIns, pThis->pszResourceNamespace);
360 pThis->pszResourceNamespace = NULL;
361 }
362
363 return VINF_SUCCESS;
364}
365
366
367/**
368 * Load the ROM resources into the guest physical address space.
369 *
370 * @returns VBox status code.
371 * @param pDevIns The device instance.
372 * @param pThis The device state for the current context.
373 */
374static int platformR3LoadRoms(PPDMDEVINS pDevIns, PDEVPLATFORM pThis)
375{
376 int rc = VINF_SUCCESS;
377
378 PDEVPLATFORMRESOURCE pIt;
379 RTListForEach(&pThis->LstResourcesRom, pIt, DEVPLATFORMRESOURCE, NdLst)
380 {
381 rc = platformR3ResourceResolveContent(pDevIns, pThis, pIt, (void **)&pIt->pu8ResourceFree, (void const **)&pIt->pu8Resource, &pIt->cbResource);
382 if (RT_SUCCESS(rc))
383 rc = PDMDevHlpROMRegister(pDevIns, platformR3ResourceGetLoadAddress(pDevIns, pIt), pIt->cbResource, pIt->pu8Resource, pIt->cbResource,
384 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, pIt->szName);
385 AssertRCReturn(rc, rc);
386 }
387
388 return rc;
389}
390
391
392/**
393 * @interface_method_impl{PDMDEVREG,pfnConstruct}
394 */
395static DECLCALLBACK(int) platformR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
396{
397 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
398 PDEVPLATFORM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVPLATFORM);
399 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
400 int rc;
401
402 RT_NOREF(iInstance);
403 Assert(iInstance == 0);
404
405 /*
406 * Initalize the basic variables so that the destructor always works.
407 */
408 pThis->pDevIns = pDevIns;
409 pThis->pszResourceNamespace = NULL;
410 pThis->Lun0.IBase.pfnQueryInterface = platformR3QueryInterface;
411 RTListInit(&pThis->LstResourcesMem);
412 RTListInit(&pThis->LstResourcesRom);
413
414 /*
415 * Validate and read the configuration.
416 */
417 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "ResourceNamespace", "Resources");
418
419 rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "ResourceNamespace", &pThis->pszResourceNamespace);
420 if (RT_FAILURE(rc) && rc != VERR_CFGM_VALUE_NOT_FOUND)
421 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
422 N_("Configuration error: Querying \"ResourceNamespace\" as a string failed"));
423
424 /*
425 * Resource storage.
426 */
427 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->Lun0.IBase, &pThis->Lun0.pDrvBase, "ResourceStorage");
428 if (RT_SUCCESS(rc))
429 {
430 pThis->Lun0.pDrvVfs = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pDrvBase, PDMIVFSCONNECTOR);
431 if (!pThis->Lun0.pDrvVfs)
432 return PDMDevHlpVMSetError(pDevIns, VERR_PDM_MISSING_INTERFACE_BELOW, RT_SRC_POS, N_("Resource storage driver is missing VFS interface below"));
433 }
434 else
435 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("Can't attach resource Storage driver"));
436
437 /*
438 * Load the resources.
439 */
440 PCFGMNODE pCfgRes = pHlp->pfnCFGMGetChild(pCfg, "Resources");
441 if (pCfgRes)
442 {
443 pCfgRes = pHlp->pfnCFGMGetFirstChild(pCfgRes);
444 while (pCfgRes)
445 {
446 rc = pHlp->pfnCFGMValidateConfig(pCfgRes, "/",
447 "RegisterAsRom"
448 "|Filename"
449 "|ResourceId"
450 "|GCPhysLoadAddress",
451 "",
452 pDevIns->pReg->szName, pDevIns->iInstance);
453 if (RT_FAILURE(rc))
454 return rc;
455
456 bool fRegisterAsRom;
457 rc = pHlp->pfnCFGMQueryBool(pCfgRes, "RegisterAsRom", &fRegisterAsRom);
458 if (RT_FAILURE(rc))
459 return PDMDEV_SET_ERROR(pDevIns, rc,
460 N_("Configuration error: Querying \"RegisterAsRom\" as boolean failed"));
461
462 PDEVPLATFORMRESOURCE pRes = (PDEVPLATFORMRESOURCE)PDMDevHlpMMHeapAlloc(pDevIns, sizeof(*pRes));
463 if (!pRes)
464 return PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY,
465 N_("Configuration error: Failed to allocate resource node"));
466
467 rc = pHlp->pfnCFGMGetName(pCfgRes, &pRes->szName[0], sizeof(pRes->szName));
468 if (RT_FAILURE(rc))
469 return PDMDEV_SET_ERROR(pDevIns, rc,
470 N_("Configuration error: Querying resource name as a string failed"));
471
472 rc = pHlp->pfnCFGMQueryU64Def(pCfgRes, "GCPhysLoadAddress", &pRes->GCPhysResource, RTGCPHYS_MAX);
473 if (RT_FAILURE(rc))
474 return PDMDEV_SET_ERROR(pDevIns, rc,
475 N_("Configuration error: Querying \"GCPhysLoadAddress\" as integer failed"));
476
477 /* Setting a filename overrides the resource store (think of CFGM extradata from the user). */
478 pRes->fResourceId = false;
479 rc = pHlp->pfnCFGMQueryStringAlloc(pCfgRes, "Filename", (char **)&pRes->pszResourceIdOrFilename);
480 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
481 {
482 /* There must be an existing resource ID. */
483 rc = pHlp->pfnCFGMQueryStringAlloc(pCfgRes, "ResourceId", (char **)&pRes->pszResourceIdOrFilename);
484 if (RT_SUCCESS(rc))
485 pRes->fResourceId = true;
486 }
487 if (RT_FAILURE(rc))
488 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
489 N_("Configuration error: Querying \"Filename\" or \"ResourceId\" as a string failed"));
490
491 /* Add it to the appropriate list. */
492 RTListAppend(fRegisterAsRom ? &pThis->LstResourcesRom : &pThis->LstResourcesMem, &pRes->NdLst);
493
494 /* Next one please. */
495 pCfgRes = pHlp->pfnCFGMGetNextChild(pCfgRes);
496 }
497 }
498
499 /* Load and register the ROM resources. */
500 rc = platformR3LoadRoms(pDevIns, pThis);
501 if (RT_FAILURE(rc))
502 return rc;
503
504 return VINF_SUCCESS;
505}
506
507
508/**
509 * The device registration structure.
510 */
511const PDMDEVREG g_DevicePlatform =
512{
513 /* .u32Version = */ PDM_DEVREG_VERSION,
514 /* .uReserved0 = */ 0,
515 /* .szName = */ "platform",
516 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_NEW_STYLE,
517 /* .fClass = */ PDM_DEVREG_CLASS_ARCH_BIOS,
518 /* .cMaxInstances = */ 1,
519 /* .uSharedVersion = */ 42,
520 /* .cbInstanceShared = */ sizeof(DEVPLATFORM),
521 /* .cbInstanceCC = */ 0,
522 /* .cbInstanceRC = */ 0,
523 /* .cMaxPciDevices = */ 0,
524 /* .cMaxMsixVectors = */ 0,
525 /* .pszDescription = */ "Generic platform device for registering ROMs and loading resources into guest RAM.\n",
526#if defined(IN_RING3)
527 /* .pszRCMod = */ "",
528 /* .pszR0Mod = */ "",
529 /* .pfnConstruct = */ platformR3Construct,
530 /* .pfnDestruct = */ platformR3Destruct,
531 /* .pfnRelocate = */ NULL,
532 /* .pfnMemSetup = */ platformR3MemSetup,
533 /* .pfnPowerOn = */ NULL,
534 /* .pfnReset = */ NULL,
535 /* .pfnSuspend = */ NULL,
536 /* .pfnResume = */ NULL,
537 /* .pfnAttach = */ NULL,
538 /* .pfnDetach = */ NULL,
539 /* .pfnQueryInterface = */ NULL,
540 /* .pfnInitComplete = */ NULL,
541 /* .pfnPowerOff = */ NULL,
542 /* .pfnSoftReset = */ NULL,
543 /* .pfnReserved0 = */ NULL,
544 /* .pfnReserved1 = */ NULL,
545 /* .pfnReserved2 = */ NULL,
546 /* .pfnReserved3 = */ NULL,
547 /* .pfnReserved4 = */ NULL,
548 /* .pfnReserved5 = */ NULL,
549 /* .pfnReserved6 = */ NULL,
550 /* .pfnReserved7 = */ NULL,
551#elif defined(IN_RING0)
552 /* .pfnEarlyConstruct = */ NULL,
553 /* .pfnConstruct = */ NULL,
554 /* .pfnDestruct = */ NULL,
555 /* .pfnFinalDestruct = */ NULL,
556 /* .pfnRequest = */ NULL,
557 /* .pfnReserved0 = */ NULL,
558 /* .pfnReserved1 = */ NULL,
559 /* .pfnReserved2 = */ NULL,
560 /* .pfnReserved3 = */ NULL,
561 /* .pfnReserved4 = */ NULL,
562 /* .pfnReserved5 = */ NULL,
563 /* .pfnReserved6 = */ NULL,
564 /* .pfnReserved7 = */ NULL,
565#elif defined(IN_RC)
566 /* .pfnConstruct = */ NULL,
567 /* .pfnReserved0 = */ NULL,
568 /* .pfnReserved1 = */ NULL,
569 /* .pfnReserved2 = */ NULL,
570 /* .pfnReserved3 = */ NULL,
571 /* .pfnReserved4 = */ NULL,
572 /* .pfnReserved5 = */ NULL,
573 /* .pfnReserved6 = */ NULL,
574 /* .pfnReserved7 = */ NULL,
575#else
576# error "Not in IN_RING3, IN_RING0 or IN_RC!"
577#endif
578 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
579};
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