VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/DevOVMF.cpp@ 42397

Last change on this file since 42397 was 42397, checked in by vboxsync, 12 years ago

EFI/Ovmf: Intermediate changes to boot Ovmf based firmware (disabled:VBOX_WITH_OVMF).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 38.9 KB
Line 
1/* $Id: DevOVMF.cpp 42397 2012-07-25 15:22:05Z vboxsync $ */
2/** @file
3 * DevEFI - EFI <-> VirtualBox Integration Framework.
4 */
5
6/*
7 * Copyright (C) 2006-2009 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* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_DEV_EFI
22
23#include <VBox/vmm/pdmdev.h>
24#include <VBox/vmm/pgm.h>
25#include <VBox/vmm/mm.h>
26#include <VBox/log.h>
27#include <VBox/err.h>
28#include <VBox/param.h>
29#include <VBox/vmm/dbgf.h>
30
31#include <iprt/asm.h>
32#include <iprt/assert.h>
33#include <iprt/file.h>
34#include <iprt/mem.h>
35#include <iprt/string.h>
36#include <iprt/uuid.h>
37#include <iprt/path.h>
38#include <iprt/string.h>
39#include <iprt/mp.h>
40#ifdef DEBUG
41# include <iprt/stream.h>
42# define DEVEFI_WITH_VBOXDBG_SCRIPT
43#endif
44
45#include "Firmware2/VBoxPkg/Include/DevEFI.h"
46#include "VBoxDD.h"
47#include "VBoxDD2.h"
48#include "../PC/DevFwCommon.h"
49
50/* EFI includes */
51#include <ProcessorBind.h>
52#include <Common/UefiBaseTypes.h>
53#include <Common/PiFirmwareVolume.h>
54#include <Common/PiFirmwareFile.h>
55
56/*******************************************************************************
57* Structures and Typedefs *
58*******************************************************************************/
59typedef struct DEVEFI
60{
61 /** Pointer back to the device instance. */
62 PPDMDEVINS pDevIns;
63 /** EFI message buffer. */
64 char szMsg[VBOX_EFI_DEBUG_BUFFER];
65 /** EFI message buffer index. */
66 uint32_t iMsg;
67 /** EFI panic message buffer. */
68 char szPanicMsg[2048];
69 /** EFI panic message buffer index. */
70 uint32_t iPanicMsg;
71 /** The system EFI ROM data. */
72 uint8_t *pu8EfiRom;
73 /** The size of the system EFI ROM. */
74 uint64_t cbEfiRom;
75 /** The name of the EFI ROM file. */
76 char *pszEfiRomFile;
77 /** Thunk page pointer. */
78 uint8_t *pu8EfiThunk;
79 /** First entry point of the EFI firmware */
80 RTGCPHYS GCEntryPoint0;
81 /* Second Entry Point (PeiCore)*/
82 RTGCPHYS GCEntryPoint1;
83 /** EFI firmware physical load address */
84 RTGCPHYS GCLoadAddress;
85 /** Current info selector */
86 uint32_t iInfoSelector;
87 /** Current info position */
88 int32_t iInfoPosition;
89
90 /** Number of virtual CPUs. (Config) */
91 uint32_t cCpus;
92 /** RAM below 4GB (in bytes). (Config) */
93 uint32_t cbBelow4GB;
94 /** RAM above 4GB (in bytes). (Config) */
95 uint64_t cbAbove4GB;
96
97 uint64_t cbRam;
98
99 uint64_t cbRamHole;
100
101 /** The DMI tables. */
102 uint8_t au8DMIPage[0x1000];
103
104 /** I/O-APIC enabled? */
105 uint8_t u8IOAPIC;
106
107 /* Boot parameters passed to the firmware */
108 char szBootArgs[256];
109
110 /* Host UUID (for DMI) */
111 RTUUID aUuid;
112
113 /* Device properties buffer */
114 uint8_t* pu8DeviceProps;
115 /* Device properties buffer size */
116 uint32_t u32DevicePropsLen;
117
118 /* Virtual machine front side bus frequency */
119 uint64_t u64FsbFrequency;
120 /* Virtual machine time stamp counter frequency */
121 uint64_t u64TscFrequency;
122 /* Virtual machine CPU frequency */
123 uint64_t u64CpuFrequency;
124 /* GOP mode */
125 uint32_t u32GopMode;
126 /* Uga mode resolutions */
127 uint32_t u32UgaHorisontal;
128 uint32_t u32UgaVertical;
129} DEVEFI;
130typedef DEVEFI *PDEVEFI;
131
132/**
133 * Write to CMOS memory.
134 * This is used by the init complete code.
135 */
136static void cmosWrite(PPDMDEVINS pDevIns, int off, uint32_t u32Val)
137{
138 Assert(off < 128);
139 Assert(u32Val < 256);
140
141 int rc = PDMDevHlpCMOSWrite(pDevIns, off, u32Val);
142 AssertRC(rc);
143}
144
145
146static uint32_t efiInfoSize(PDEVEFI pThis)
147{
148 switch (pThis->iInfoSelector)
149 {
150 case EFI_INFO_INDEX_VOLUME_BASE:
151 case EFI_INFO_INDEX_VOLUME_SIZE:
152 case EFI_INFO_INDEX_TEMPMEM_BASE:
153 case EFI_INFO_INDEX_TEMPMEM_SIZE:
154 case EFI_INFO_INDEX_STACK_BASE:
155 case EFI_INFO_INDEX_STACK_SIZE:
156 case EFI_INFO_INDEX_GOP_MODE:
157 case EFI_INFO_INDEX_UGA_VERTICAL_RESOLUTION:
158 case EFI_INFO_INDEX_UGA_HORISONTAL_RESOLUTION:
159 return 4;
160 case EFI_INFO_INDEX_BOOT_ARGS:
161 return (uint32_t)RTStrNLen(pThis->szBootArgs,
162 sizeof pThis->szBootArgs) + 1;
163 case EFI_INFO_INDEX_DEVICE_PROPS:
164 return pThis->u32DevicePropsLen;
165 case EFI_INFO_INDEX_FSB_FREQUENCY:
166 case EFI_INFO_INDEX_CPU_FREQUENCY:
167 case EFI_INFO_INDEX_TSC_FREQUENCY:
168 return 8;
169 }
170 Assert(false);
171 return 0;
172}
173
174static uint8_t efiInfoNextByte(PDEVEFI pThis)
175{
176 union
177 {
178 uint32_t u32;
179 uint64_t u64;
180 } value;
181
182 switch (pThis->iInfoSelector)
183 {
184 case EFI_INFO_INDEX_VOLUME_BASE:
185 value.u32 = pThis->GCLoadAddress;
186 break;
187 case EFI_INFO_INDEX_VOLUME_SIZE:
188 value.u32 = pThis->cbEfiRom;
189 break;
190 case EFI_INFO_INDEX_TEMPMEM_BASE:
191 value.u32 = VBOX_EFI_TOP_OF_STACK; /* just after stack */
192 break;
193 case EFI_INFO_INDEX_TEMPMEM_SIZE:
194 value.u32 = 512 * 1024; /* 512 K */
195 break;
196 case EFI_INFO_INDEX_STACK_BASE:
197 /* Keep in sync with value in EfiThunk.asm */
198 value.u32 = VBOX_EFI_TOP_OF_STACK - 128*1024; /* 2M - 128 K */
199 break;
200 case EFI_INFO_INDEX_STACK_SIZE:
201 value.u32 = 128*1024; /* 128 K */
202 break;
203 case EFI_INFO_INDEX_FSB_FREQUENCY:
204 value.u64 = pThis->u64FsbFrequency;
205 break;
206 case EFI_INFO_INDEX_TSC_FREQUENCY:
207 value.u64 = pThis->u64TscFrequency;
208 break;
209 case EFI_INFO_INDEX_CPU_FREQUENCY:
210 value.u64 = pThis->u64CpuFrequency;
211 break;
212 case EFI_INFO_INDEX_BOOT_ARGS:
213 return pThis->szBootArgs[pThis->iInfoPosition];
214 case EFI_INFO_INDEX_DEVICE_PROPS:
215 return pThis->pu8DeviceProps[pThis->iInfoPosition];
216 case EFI_INFO_INDEX_GOP_MODE:
217 value.u32 = pThis->u32GopMode;
218 break;
219 case EFI_INFO_INDEX_UGA_HORISONTAL_RESOLUTION:
220 value.u32 = pThis->u32UgaHorisontal;
221 break;
222 case EFI_INFO_INDEX_UGA_VERTICAL_RESOLUTION:
223 value.u32 = pThis->u32UgaVertical;
224 break;
225 default:
226 Assert(false);
227 value.u64 = 0;
228 break;
229 }
230
231 return *((uint8_t*)&value+pThis->iInfoPosition);
232}
233
234/**
235 * Port I/O Handler for IN operations.
236 *
237 * @returns VBox status code.
238 *
239 * @param pDevIns The device instance.
240 * @param pvUser User argument - ignored.
241 * @param Port Port number used for the IN operation.
242 * @param pu32 Where to store the result.
243 * @param cb Number of bytes read.
244 */
245static DECLCALLBACK(int) efiIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
246{
247 PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
248 Log4(("EFI in: %x %x\n", Port, cb));
249
250 switch (Port)
251 {
252 case EFI_INFO_PORT:
253 if (pThis->iInfoPosition == -1 && cb == 4)
254 {
255 *pu32 = efiInfoSize(pThis);
256 pThis->iInfoPosition = 0;
257 }
258 else
259 {
260 /* So far */
261 if (cb != 1)
262 return VERR_IOM_IOPORT_UNUSED;
263 *pu32 = efiInfoNextByte(pThis);
264 pThis->iInfoPosition++;
265 }
266 return VINF_SUCCESS;
267
268 case EFI_PANIC_PORT:
269#ifdef IN_RING3
270 LogRel(("Panic port read!\n"));
271 /* Insert special code here on panic reads */
272 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "EFI Panic: panic port read!\n");
273#else
274 /* Reschedule to R3 */
275 return VINF_IOM_R3_IOPORT_READ;
276#endif
277 }
278
279 return VERR_IOM_IOPORT_UNUSED;
280}
281
282
283/**
284 * Port I/O Handler for OUT operations.
285 *
286 * @returns VBox status code.
287 *
288 * @param pDevIns The device instance.
289 * @param pvUser User argument - ignored.
290 * @param Port Port number used for the IN operation.
291 * @param u32 The value to output.
292 * @param cb The value size in bytes.
293 */
294static DECLCALLBACK(int) efiIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
295{
296 PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
297 Log4(("efi: out %x %x %d\n", Port, u32, cb));
298
299 switch (Port)
300 {
301 case EFI_INFO_PORT:
302 pThis->iInfoSelector = u32;
303 pThis->iInfoPosition = -1;
304 break;
305 case EFI_DEBUG_PORT:
306 {
307 /* The raw version. */
308 switch (u32)
309 {
310 case '\r': Log3(("efi: <return>\n")); break;
311 case '\n': Log3(("efi: <newline>\n")); break;
312 case '\t': Log3(("efi: <tab>\n")); break;
313 default: Log3(("efi: %c (%02x)\n", u32, u32)); break;
314 }
315 /* The readable, buffered version. */
316 if (u32 == '\n' || u32 == '\r')
317 {
318 pThis->szMsg[pThis->iMsg] = '\0';
319 if (pThis->iMsg)
320 {
321 Log(("efi: %s\n", pThis->szMsg));
322#ifdef DEVEFI_WITH_VBOXDBG_SCRIPT
323 const char *pszVBoxDbg = strstr(pThis->szMsg, "VBoxDbg> ");
324 if (pszVBoxDbg)
325 {
326 pszVBoxDbg += sizeof("VBoxDbg> ") - 1;
327
328 PRTSTREAM pStrm;
329 int rc = RTStrmOpen("./DevEFI.VBoxDbg", "a", &pStrm);
330 if (RT_SUCCESS(rc))
331 {
332 RTStrmPutStr(pStrm, pszVBoxDbg);
333 RTStrmPutCh(pStrm, '\n');
334 RTStrmClose(pStrm);
335 }
336 }
337#endif
338 }
339 pThis->iMsg = 0;
340 }
341 else
342 {
343 if (pThis->iMsg >= sizeof(pThis->szMsg)-1)
344 {
345 pThis->szMsg[pThis->iMsg] = '\0';
346 Log(("efi: %s\n", pThis->szMsg));
347 pThis->iMsg = 0;
348 }
349 pThis->szMsg[pThis->iMsg] = (char )u32;
350 pThis->szMsg[++pThis->iMsg] = '\0';
351 }
352 break;
353 }
354
355 case EFI_PANIC_PORT:
356 {
357 switch (u32)
358 {
359 case EFI_PANIC_CMD_BAD_ORG:
360#if 0
361 LogRel(("EFI Panic: You have to fix ORG offset in EfiThunk.asm! Must be 0x%x\n",
362 g_cbEfiThunkBinary));
363 RTAssertMsg2Weak("Fix ORG offset in EfiThunk.asm: must be 0x%x\n",
364 g_cbEfiThunkBinary);
365 break;
366#endif
367
368 case EFI_PANIC_CMD_THUNK_TRAP:
369 LogRel(("EFI Panic: Unexpected trap!!\n"));
370#ifdef VBOX_STRICT
371 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "EFI Panic: Unexpected trap during early bootstrap!\n");
372#else
373 AssertReleaseMsgFailed(("Unexpected trap during early EFI bootstrap!!\n"));
374#endif
375 break;
376
377 case EFI_PANIC_CMD_START_MSG:
378 pThis->iPanicMsg = 0;
379 pThis->szPanicMsg[0] = '\0';
380 break;
381
382 case EFI_PANIC_CMD_END_MSG:
383 LogRel(("EFI Panic: %s\n", pThis->szPanicMsg));
384#ifdef VBOX_STRICT
385 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "EFI Panic: %s\n", pThis->szPanicMsg);
386#else
387 return VERR_INTERNAL_ERROR;
388#endif
389
390 default:
391 if ( u32 >= EFI_PANIC_CMD_MSG_FIRST
392 && u32 <= EFI_PANIC_CMD_MSG_LAST)
393 {
394 /* Add the message char to the buffer. */
395 uint32_t i = pThis->iPanicMsg;
396 if (i + 1 < sizeof(pThis->szPanicMsg))
397 {
398 char ch = EFI_PANIC_CMD_MSG_GET_CHAR(u32);
399 if ( ch == '\n'
400 && i > 0
401 && pThis->szPanicMsg[i - 1] == '\r')
402 i--;
403 pThis->szPanicMsg[i] = ch;
404 pThis->szPanicMsg[i + 1] = '\0';
405 pThis->iPanicMsg = i + 1;
406 }
407 }
408 else
409 Log(("EFI: Unknown panic command: %#x (cb=%d)\n", u32, cb));
410 break;
411 }
412 break;
413 }
414
415 default:
416 Log(("EFI: Write to reserved port %RTiop: %#x (cb=%d)\n", Port, u32, cb));
417 break;
418 }
419 return VINF_SUCCESS;
420}
421
422/**
423 * Init complete notification.
424 *
425 * @returns VBOX status code.
426 * @param pDevIns The device instance.
427 */
428static DECLCALLBACK(int) efiInitComplete(PPDMDEVINS pDevIns)
429{
430 /* PC Bios */
431 PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
432 uint32_t u32;
433
434 /*
435 * Memory sizes.
436 */
437 uint64_t const offRamHole = _4G - pThis->cbRamHole;
438 if (pThis->cbRam > 16 * _1M)
439 u32 = (uint32_t)( (RT_MIN(RT_MIN(pThis->cbRam, offRamHole), UINT32_C(0xffe00000)) - 16U * _1M) / _64K );
440 else
441 u32 = 0;
442 cmosWrite(pDevIns, 0x34, u32 & 0xff);
443 cmosWrite(pDevIns, 0x35, u32 >> 8);
444
445 /*
446 * Number of CPUs.
447 */
448 cmosWrite(pDevIns, 0x60, pThis->cCpus & 0xff);
449
450 return VINF_SUCCESS;
451}
452
453/**
454 * Reset notification.
455 *
456 * @returns VBox status.
457 * @param pDevIns The device instance data.
458 */
459static DECLCALLBACK(void) efiReset(PPDMDEVINS pDevIns)
460{
461 PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
462 int rc;
463
464 LogFlow(("efiReset\n"));
465
466 pThis->iInfoSelector = 0;
467 pThis->iInfoPosition = -1;
468
469 pThis->iMsg = 0;
470 pThis->szMsg[0] = '\0';
471 pThis->iPanicMsg = 0;
472 pThis->szPanicMsg[0] = '\0';
473
474 /*
475 * Plan some structures in RAM.
476 */
477 FwCommonPlantSmbiosAndDmiHdrs(pDevIns);
478 if (pThis->u8IOAPIC)
479 FwCommonPlantMpsFloatPtr(pDevIns);
480
481 /*
482 * Re-shadow the Firmware Volume and make it RAM/RAM.
483 */
484 uint32_t cPages = RT_ALIGN_64(pThis->cbEfiRom, PAGE_SIZE) >> PAGE_SHIFT;
485 RTGCPHYS GCPhys = pThis->GCLoadAddress;
486 while (cPages > 0)
487 {
488 uint8_t abPage[PAGE_SIZE];
489
490 /* Read the (original) ROM page and write it back to the RAM page. */
491 rc = PDMDevHlpROMProtectShadow(pDevIns, GCPhys, PAGE_SIZE, PGMROMPROT_READ_ROM_WRITE_RAM);
492 AssertLogRelRC(rc);
493
494 rc = PDMDevHlpPhysRead(pDevIns, GCPhys, abPage, PAGE_SIZE);
495 AssertLogRelRC(rc);
496 if (RT_FAILURE(rc))
497 memset(abPage, 0xcc, sizeof(abPage));
498
499 rc = PDMDevHlpPhysWrite(pDevIns, GCPhys, abPage, PAGE_SIZE);
500 AssertLogRelRC(rc);
501
502 /* Switch to the RAM/RAM mode. */
503 rc = PDMDevHlpROMProtectShadow(pDevIns, GCPhys, PAGE_SIZE, PGMROMPROT_READ_RAM_WRITE_RAM);
504 AssertLogRelRC(rc);
505
506 /* Advance */
507 GCPhys += PAGE_SIZE;
508 cPages--;
509 }
510}
511
512/**
513 * Destruct a device instance.
514 *
515 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
516 * resources can be freed correctly.
517 *
518 * @param pDevIns The device instance data.
519 */
520static DECLCALLBACK(int) efiDestruct(PPDMDEVINS pDevIns)
521{
522 PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
523
524 /*
525 * Free MM heap pointers.
526 */
527 if (pThis->pu8EfiRom)
528 {
529 RTFileReadAllFree(pThis->pu8EfiRom, (size_t)pThis->cbEfiRom);
530 pThis->pu8EfiRom = NULL;
531 }
532
533 if (pThis->pszEfiRomFile)
534 {
535 MMR3HeapFree(pThis->pszEfiRomFile);
536 pThis->pszEfiRomFile = NULL;
537 }
538
539 if (pThis->pu8EfiThunk)
540 {
541 MMR3HeapFree(pThis->pu8EfiThunk);
542 pThis->pu8EfiThunk = NULL;
543 }
544
545 if (pThis->pu8DeviceProps)
546 {
547 MMR3HeapFree(pThis->pu8DeviceProps);
548 pThis->pu8DeviceProps = NULL;
549 pThis->u32DevicePropsLen = 0;
550 }
551
552 return VINF_SUCCESS;
553}
554
555/**
556 * Helper that searches for a FFS file of a given type.
557 *
558 * @returns Pointer to the FFS file header if found, NULL if not.
559 *
560 * @param pFfsFile Pointer to the FFS file header to start searching at.
561 * @param pbEnd The end of the firmware volume.
562 * @param FileType The file type to look for.
563 * @param pcbFfsFile Where to store the FFS file size (includes header).
564 */
565DECLINLINE(EFI_FFS_FILE_HEADER const *)
566efiFwVolFindFileByType(EFI_FFS_FILE_HEADER const *pFfsFile, uint8_t const *pbEnd, EFI_FV_FILETYPE FileType, uint32_t *pcbFile)
567{
568#define FFS_SIZE(hdr) RT_MAKE_U32_FROM_U8((hdr)->Size[0], (hdr)->Size[1], (hdr)->Size[2], 0)
569 while ((uintptr_t)pFfsFile < (uintptr_t)pbEnd)
570 {
571 if (pFfsFile->Type == FileType)
572 {
573 *pcbFile = FFS_SIZE(pFfsFile);
574 LogFunc(("Found %RTuuid of type:%d\n", &pFfsFile->Name, FileType));
575 return pFfsFile;
576 }
577 pFfsFile = (EFI_FFS_FILE_HEADER *)((uintptr_t)pFfsFile + RT_ALIGN(FFS_SIZE(pFfsFile), 8));
578 }
579 return NULL;
580}
581
582
583/**
584 * Parse EFI ROM headers and find entry points.
585 *
586 * @returns VBox status.
587 * @param pThis The device instance data.
588 */
589static int efiParseFirmware(PDEVEFI pThis)
590{
591 EFI_FIRMWARE_VOLUME_HEADER const *pFwVolHdr = (EFI_FIRMWARE_VOLUME_HEADER const *)pThis->pu8EfiRom;
592
593 /*
594 * Validate firmware volume header.
595 */
596 AssertLogRelMsgReturn(pFwVolHdr->Signature == RT_MAKE_U32_FROM_U8('_', 'F', 'V', 'H'),
597 ("%#x, expected %#x\n", pFwVolHdr->Signature, RT_MAKE_U32_FROM_U8('_', 'F', 'V', 'H')),
598 VERR_INVALID_MAGIC);
599 AssertLogRelMsgReturn(pFwVolHdr->Revision == EFI_FVH_REVISION,
600 ("%#x, expected %#x\n", pFwVolHdr->Signature, EFI_FVH_REVISION),
601 VERR_VERSION_MISMATCH);
602 /** @todo check checksum, see PE spec vol. 3 */
603 AssertLogRelMsgReturn(pFwVolHdr->FvLength <= pThis->cbEfiRom,
604 ("%#llx, expected %#llx\n", pFwVolHdr->FvLength, pThis->cbEfiRom),
605 VERR_INVALID_PARAMETER);
606 AssertLogRelMsgReturn( pFwVolHdr->BlockMap[0].Length > 0
607 && pFwVolHdr->BlockMap[0].NumBlocks > 0,
608 ("%#x, %x\n", pFwVolHdr->BlockMap[0].Length, pFwVolHdr->BlockMap[0].NumBlocks),
609 VERR_INVALID_PARAMETER);
610
611 AssertLogRelMsgReturn(!(pThis->cbEfiRom & PAGE_OFFSET_MASK), ("%RX64\n", pThis->cbEfiRom), VERR_INVALID_PARAMETER);
612
613 uint8_t const * const pbFwVolEnd = pThis->pu8EfiRom + pFwVolHdr->FvLength;
614 pThis->GCLoadAddress = UINT32_C(0xfffff000) - pThis->cbEfiRom + PAGE_SIZE;
615
616#if 0
617 /*
618 * Ffs files are stored one by one, so to find SECURITY_CORE we've to
619 * search thru every one on the way.
620 */
621 uint32_t cbFfsFile = 0; /* shut up gcc */
622 EFI_FFS_FILE_HEADER const *pFfsFile = (EFI_FFS_FILE_HEADER const *)(pThis->pu8EfiRom + pFwVolHdr->HeaderLength);
623 pFfsFile = efiFwVolFindFileByType(pFfsFile, pbFwVolEnd, EFI_FV_FILETYPE_SECURITY_CORE, &cbFfsFile);
624 AssertLogRelMsgReturn(pFfsFile, ("No SECURITY_CORE found in the firmware volume\n"), VERR_FILE_NOT_FOUND);
625
626 RTGCPHYS ImageBase = NIL_RTGCPHYS;
627 uint8_t *pbImage = NULL;
628 pThis->GCEntryPoint0 = efiFindRelativeAddressOfEPAndBaseAddressOfModule(pFfsFile, cbFfsFile, &ImageBase, &pbImage);
629 pThis->GCEntryPoint0 += pbImage - pThis->pu8EfiRom;
630 Assert(pThis->pu8EfiRom <= pbImage);
631 Assert(pbImage < pThis->pu8EfiRom + pThis->cbEfiRom);
632 /*
633 * Calc the firmware load address from the image base and validate it.
634 */
635 pThis->GCLoadAddress = ImageBase - (pbImage - pThis->pu8EfiRom);
636 pThis->GCEntryPoint0 += pThis->GCLoadAddress;
637 AssertLogRelMsgReturn(~(pThis->GCLoadAddress & PAGE_OFFSET_MASK),
638 ("%RGp\n", pThis->GCLoadAddress),
639 VERR_INVALID_PARAMETER);
640 AssertLogRelMsgReturn(pThis->GCLoadAddress > UINT32_C(0xf0000000),
641 ("%RGp\n", pThis->GCLoadAddress),
642 VERR_OUT_OF_RANGE);
643 AssertLogRelMsgReturn( pThis->GCLoadAddress + (pThis->cbEfiRom - 1) > UINT32_C(0xf0000000)
644 && pThis->GCLoadAddress + (pThis->cbEfiRom - 1) < UINT32_C(0xffffe000),
645 ("%RGp + %RX64\n", pThis->GCLoadAddress, pThis->cbEfiRom),
646 VERR_OUT_OF_RANGE);
647
648 LogRel(("EFI: Firmware volume loading at %RGp, SEC CORE at %RGp with EP at %RGp\n",
649 pThis->GCLoadAddress, ImageBase, pThis->GCEntryPoint0));
650
651 pFfsFile = efiFwVolFindFileByType(pFfsFile, pbFwVolEnd, EFI_FV_FILETYPE_PEI_CORE, &cbFfsFile);
652 pThis->GCEntryPoint1 = efiFindRelativeAddressOfEPAndBaseAddressOfModule(pFfsFile, cbFfsFile, NULL, &pbImage);
653 pThis->GCEntryPoint1 += pThis->GCLoadAddress;
654 pThis->GCEntryPoint1 += pbImage - pThis->pu8EfiRom;
655 LogRel(("EFI: Firmware volume loading at %RGp, PEI CORE at with EP at %RGp\n",
656 pThis->GCLoadAddress, pThis->GCEntryPoint1));
657#endif
658 return VINF_SUCCESS;
659}
660
661/**
662 * Load EFI ROM file into the memory.
663 *
664 * @returns VBox status.
665 * @param pThis The device instance data.
666 * @param pCfg Configuration node handle for the device.
667 */
668static int efiLoadRom(PDEVEFI pThis, PCFGMNODE pCfg)
669{
670 /*
671 * Read the entire firmware volume into memory.
672 */
673 void *pvFile;
674 size_t cbFile;
675 int rc = RTFileReadAllEx(pThis->pszEfiRomFile,
676 0 /*off*/,
677 RTFOFF_MAX /*cbMax*/,
678 RTFILE_RDALL_O_DENY_WRITE,
679 &pvFile,
680 &cbFile);
681 if (RT_FAILURE(rc))
682 return PDMDevHlpVMSetError(pThis->pDevIns, rc, RT_SRC_POS,
683 N_("Loading the EFI firmware volume '%s' failed with rc=%Rrc"),
684 pThis->pszEfiRomFile, rc);
685 pThis->pu8EfiRom = (uint8_t *)pvFile;
686 pThis->cbEfiRom = cbFile;
687
688 /*
689 * Validate firmware volume and figure out the load address as well as the SEC entry point.
690 */
691 rc = efiParseFirmware(pThis);
692 if (RT_FAILURE(rc))
693 return PDMDevHlpVMSetError(pThis->pDevIns, rc, RT_SRC_POS,
694 N_("Parsing the EFI firmware volume '%s' failed with rc=%Rrc"),
695 pThis->pszEfiRomFile, rc);
696
697 /*
698 * Map the firmware volume into memory as shadowed ROM.
699 */
700 /** @todo fix PGMR3PhysRomRegister so it doesn't mess up in SUPLib when mapping a big ROM image. */
701 RTGCPHYS cbQuart = RT_ALIGN_64(pThis->cbEfiRom / 4, PAGE_SIZE);
702 rc = PDMDevHlpROMRegister(pThis->pDevIns,
703 pThis->GCLoadAddress,
704 cbQuart,
705 pThis->pu8EfiRom,
706 cbQuart,
707 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
708 "EFI Firmware Volume");
709 AssertRCReturn(rc, rc);
710 rc = PDMDevHlpROMProtectShadow(pThis->pDevIns, pThis->GCLoadAddress, (uint32_t)cbQuart, PGMROMPROT_READ_RAM_WRITE_IGNORE);
711 AssertRCReturn(rc, rc);
712 rc = PDMDevHlpROMRegister(pThis->pDevIns,
713 pThis->GCLoadAddress + cbQuart,
714 cbQuart,
715 pThis->pu8EfiRom + cbQuart,
716 cbQuart,
717 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
718 "EFI Firmware Volume (Part 2)");
719 if (RT_FAILURE(rc))
720 return rc;
721 rc = PDMDevHlpROMRegister(pThis->pDevIns,
722 pThis->GCLoadAddress + cbQuart * 2,
723 cbQuart,
724 pThis->pu8EfiRom + cbQuart * 2,
725 cbQuart,
726 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
727 "EFI Firmware Volume (Part 3)");
728 if (RT_FAILURE(rc))
729 return rc;
730 rc = PDMDevHlpROMRegister(pThis->pDevIns,
731 pThis->GCLoadAddress + cbQuart * 3,
732 pThis->cbEfiRom - cbQuart * 3,
733 pThis->pu8EfiRom + cbQuart * 3,
734 pThis->cbEfiRom - cbQuart * 3,
735 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
736 "EFI Firmware Volume (Part 4)");
737 if (RT_FAILURE(rc))
738 return rc;
739 return VINF_SUCCESS;
740}
741
742#if 0
743/**
744 * Patches and loads the EfiThunk ROM image.
745 *
746 * The thunk image is where the CPU starts and will switch it into
747 * 32-bit protected or long mode and invoke the SEC CORE image in the
748 * firmware volume. It also contains some static VM configuration data
749 * at the very beginning of the page, see DEVEFIINFO.
750 *
751 * @returns VBox status code.
752 * @param pThis The device instance data.
753 * @param pCfg Configuration node handle for the device.
754 */
755static int efiLoadThunk(PDEVEFI pThis, PCFGMNODE pCfg)
756{
757 uint8_t f64BitEntry = 0;
758 int rc;
759
760 rc = CFGMR3QueryU8Def(pCfg, "64BitEntry", &f64BitEntry, 0);
761 if (RT_FAILURE (rc))
762 return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
763 N_("Configuration error: Failed to read \"64BitEntry\""));
764
765 /*
766 * Make a copy of the page and set the values of the DEVEFIINFO structure
767 * found at the beginning of it.
768 */
769
770 if (f64BitEntry)
771 LogRel(("Using 64-bit EFI firmware\n"));
772
773 /* Duplicate the page so we can change it. */
774 AssertRelease(g_cbEfiThunkBinary == PAGE_SIZE);
775 pThis->pu8EfiThunk = (uint8_t *)PDMDevHlpMMHeapAlloc(pThis->pDevIns, PAGE_SIZE);
776 if (pThis->pu8EfiThunk == NULL)
777 return VERR_NO_MEMORY;
778 memcpy(pThis->pu8EfiThunk, &g_abEfiThunkBinary[0], PAGE_SIZE);
779
780 /* Fill in the info. */
781 PDEVEFIINFO pEfiInfo = (PDEVEFIINFO)pThis->pu8EfiThunk;
782 pEfiInfo->pfnFirmwareEP = (uint32_t)pThis->GCEntryPoint0;
783 //AssertRelease(pEfiInfo->pfnFirmwareEP == pThis->GCEntryPoint0);
784 pEfiInfo->HighEPAddress = 0;
785 pEfiInfo->PhysFwVol = pThis->GCLoadAddress;
786 pEfiInfo->cbFwVol = (uint32_t)pThis->cbEfiRom;
787 AssertRelease(pEfiInfo->cbFwVol == (uint32_t)pThis->cbEfiRom);
788 pEfiInfo->cbBelow4GB = pThis->cbBelow4GB;
789 pEfiInfo->cbAbove4GB = pThis->cbAbove4GB;
790 /* zeroth bit controls use of 64-bit entry point in fw */
791 pEfiInfo->fFlags = f64BitEntry ? 1 : 0;
792 pEfiInfo->cCpus = pThis->cCpus;
793 pEfiInfo->pfnPeiEP = (uint32_t)pThis->GCEntryPoint1;
794 pEfiInfo->u32Reserved2 = 0;
795
796 /* Register the page as a ROM (data will be copied). */
797 rc = PDMDevHlpROMRegister(pThis->pDevIns, UINT32_C(0xfffff000), PAGE_SIZE,
798 pThis->pu8EfiThunk, PAGE_SIZE,
799 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "EFI Thunk");
800 if (RT_FAILURE(rc))
801 return rc;
802
803#if 1 /** @todo this is probably not necessary. */
804 /*
805 * Map thunk page also at low address, so that real->protected mode jump code can
806 * store GDT/IDT in code segment in low memory and load them during switch to the
807 * protected mode, while being in 16-bits mode.
808 *
809 * @todo: maybe need to unregister later or place somewhere else (although could
810 * be needed during reset)
811 */
812 rc = PDMDevHlpROMRegister(pThis->pDevIns, 0xff000, PAGE_SIZE,
813 pThis->pu8EfiThunk, PAGE_SIZE,
814 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "EFI Thunk (2)");
815 if (RT_FAILURE(rc))
816 return rc;
817#endif
818
819 return rc;
820}
821#endif
822
823
824static uint8_t efiGetHalfByte(char ch)
825{
826 uint8_t val;
827
828 if (ch >= '0' && ch <= '9')
829 val = ch - '0';
830 else if (ch >= 'A' && ch <= 'F')
831 val = ch - 'A' + 10;
832 else if(ch >= 'a' && ch <= 'f')
833 val = ch - 'a' + 10;
834 else
835 val = 0xff;
836
837 return val;
838
839}
840
841
842static int efiParseDeviceString(PDEVEFI pThis, char* pszDeviceProps)
843{
844 int rc = 0;
845 uint32_t iStr, iHex, u32OutLen;
846 uint8_t u8Value = 0; /* (shut up gcc) */
847 bool fUpper = true;
848
849 u32OutLen = (uint32_t)RTStrNLen(pszDeviceProps, RTSTR_MAX) / 2 + 1;
850
851 pThis->pu8DeviceProps =
852 (uint8_t*)PDMDevHlpMMHeapAlloc(pThis->pDevIns, u32OutLen);
853 if (!pThis->pu8DeviceProps)
854 return VERR_NO_MEMORY;
855
856 for (iStr=0, iHex = 0; pszDeviceProps[iStr]; iStr++)
857 {
858 uint8_t u8Hb = efiGetHalfByte(pszDeviceProps[iStr]);
859 if (u8Hb > 0xf)
860 continue;
861
862 if (fUpper)
863 u8Value = u8Hb << 4;
864 else
865 pThis->pu8DeviceProps[iHex++] = u8Hb | u8Value;
866
867 Assert(iHex < u32OutLen);
868 fUpper = !fUpper;
869 }
870
871 Assert(iHex == 0 || fUpper);
872 pThis->u32DevicePropsLen = iHex;
873
874 return rc;
875}
876
877/**
878 * @interface_method_impl{PDMDEVREG,pfnConstruct}
879 */
880static DECLCALLBACK(int) efiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
881{
882 PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
883 int rc;
884
885 Assert(iInstance == 0);
886
887 pThis->pDevIns = pDevIns;
888
889 /*
890 * Validate and read the configuration.
891 */
892 if (!CFGMR3AreValuesValid(pCfg,
893 "EfiRom\0"
894 "RamSize\0"
895 "RamHoleSize\0"
896 "NumCPUs\0"
897 "UUID\0"
898 "IOAPIC\0"
899 "DmiBIOSVendor\0"
900 "DmiBIOSVersion\0"
901 "DmiBIOSReleaseDate\0"
902 "DmiBIOSReleaseMajor\0"
903 "DmiBIOSReleaseMinor\0"
904 "DmiBIOSFirmwareMajor\0"
905 "DmiBIOSFirmwareMinor\0"
906 "DmiSystemSKU\0"
907 "DmiSystemFamily\0"
908 "DmiSystemProduct\0"
909 "DmiSystemSerial\0"
910 "DmiSystemUuid\0"
911 "DmiSystemVendor\0"
912 "DmiSystemVersion\0"
913 "DmiChassisVendor\0"
914 "DmiChassisVersion\0"
915 "DmiChassisSerial\0"
916 "DmiChassisAssetTag\0"
917#ifdef VBOX_WITH_DMI_OEMSTRINGS
918 "DmiOEMVBoxVer\0"
919 "DmiOEMVBoxRev\0"
920#endif
921 "DmiUseHostInfo\0"
922 "DmiExposeMemoryTable\0"
923 "DmiExposeProcInf\0"
924 "64BitEntry\0"
925 "BootArgs\0"
926 "DeviceProps\0"
927 "GopMode\0"
928 "UgaHorizontalResolution\0"
929 "UgaVerticalResolution\0"
930 ))
931 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
932 N_("Configuration error: Invalid config value(s) for the EFI device"));
933
934 /* CPU count (optional). */
935 rc = CFGMR3QueryU32Def(pCfg, "NumCPUs", &pThis->cCpus, 1);
936 AssertLogRelRCReturn(rc, rc);
937
938 rc = CFGMR3QueryU8Def(pCfg, "IOAPIC", &pThis->u8IOAPIC, 1);
939 if (RT_FAILURE (rc))
940 return PDMDEV_SET_ERROR(pDevIns, rc,
941 N_("Configuration error: Failed to read \"IOAPIC\""));
942
943 /*
944 * Query the machine's UUID for SMBIOS/DMI use.
945 */
946 RTUUID uuid;
947 rc = CFGMR3QueryBytes(pCfg, "UUID", &uuid, sizeof(uuid));
948 if (RT_FAILURE(rc))
949 return PDMDEV_SET_ERROR(pDevIns, rc,
950 N_("Configuration error: Querying \"UUID\" failed"));
951
952 /*
953 * Convert the UUID to network byte order. Not entirely straightforward as
954 * parts are MSB already...
955 */
956 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
957 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
958 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
959 memcpy(&pThis->aUuid, &uuid, sizeof pThis->aUuid);
960
961
962 /*
963 * RAM sizes
964 */
965 rc = CFGMR3QueryU64(pCfg, "RamSize", &pThis->cbRam);
966 AssertLogRelRCReturn(rc, rc);
967 rc = CFGMR3QueryU64(pCfg, "RamHoleSize", &pThis->cbRamHole);
968 AssertLogRelRCReturn(rc, rc);
969 pThis->cbBelow4GB = RT_MIN(pThis->cbRam, _4G - pThis->cbRamHole);
970 pThis->cbAbove4GB = pThis->cbRam - pThis->cbBelow4GB;
971
972 /*
973 * Get the system EFI ROM file name.
974 */
975 rc = CFGMR3QueryStringAlloc(pCfg, "EfiRom", &pThis->pszEfiRomFile);
976 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
977 {
978 pThis->pszEfiRomFile = (char *)PDMDevHlpMMHeapAlloc(pDevIns, RTPATH_MAX);
979 if (!pThis->pszEfiRomFile)
980 return VERR_NO_MEMORY;
981
982 rc = RTPathAppPrivateArchTop(pThis->pszEfiRomFile, RTPATH_MAX);
983 AssertRCReturn(rc, rc);
984 rc = RTPathAppend(pThis->pszEfiRomFile, RTPATH_MAX, "VBoxEFI32.fd");
985 AssertRCReturn(rc, rc);
986 }
987 else if (RT_FAILURE(rc))
988 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
989 N_("Configuration error: Querying \"EfiRom\" as a string failed"));
990 else if (!*pThis->pszEfiRomFile)
991 {
992 MMR3HeapFree(pThis->pszEfiRomFile);
993 pThis->pszEfiRomFile = NULL;
994 }
995
996 /*
997 * Get boot args.
998 */
999 rc = CFGMR3QueryString(pCfg, "BootArgs",
1000 pThis->szBootArgs, sizeof pThis->szBootArgs);
1001 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1002 {
1003 strcpy(pThis->szBootArgs, "");
1004 rc = VINF_SUCCESS;
1005 }
1006 if (RT_FAILURE(rc))
1007 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1008 N_("Configuration error: Querying \"BootArgs\" as a string failed"));
1009
1010 LogRel(("EFI boot args: %s\n", pThis->szBootArgs));
1011
1012 /*
1013 * Get device props.
1014 */
1015 char* pszDeviceProps;
1016 rc = CFGMR3QueryStringAlloc(pCfg, "DeviceProps", &pszDeviceProps);
1017 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1018 {
1019 pszDeviceProps = NULL;
1020 rc = VINF_SUCCESS;
1021 }
1022 if (RT_FAILURE(rc))
1023 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1024 N_("Configuration error: Querying \"DeviceProps\" as a string failed"));
1025 if (pszDeviceProps)
1026 {
1027 LogRel(("EFI device props: %s\n", pszDeviceProps));
1028 rc = efiParseDeviceString(pThis, pszDeviceProps);
1029 MMR3HeapFree(pszDeviceProps);
1030 if (RT_FAILURE(rc))
1031 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1032 N_("Configuration error: Cannot parse device properties"));
1033 }
1034 else
1035 {
1036 pThis->pu8DeviceProps = NULL;
1037 pThis->u32DevicePropsLen = 0;
1038 }
1039
1040 /*
1041 * CPU frequencies
1042 */
1043 // @todo: we need to have VMM API to access TSC increase speed, for now provide reasonable default
1044 pThis->u64TscFrequency = RTMpGetMaxFrequency(0) * 1024 * 1024;// TMCpuTicksPerSecond(PDMDevHlpGetVM(pDevIns));
1045 if (pThis->u64TscFrequency == 0)
1046 pThis->u64TscFrequency = UINT64_C(2500000000);
1047 /* Multiplier is read from MSR_IA32_PERF_STATUS, and now is hardcoded as 4 */
1048 pThis->u64FsbFrequency = pThis->u64TscFrequency / 4;
1049 pThis->u64CpuFrequency = pThis->u64TscFrequency;
1050
1051 /*
1052 * GOP graphics
1053 */
1054 rc = CFGMR3QueryU32(pCfg, "GopMode", &pThis->u32GopMode);
1055 AssertRC(rc);
1056 if (pThis->u32GopMode == UINT32_MAX)
1057 {
1058 pThis->u32GopMode = 2; /* 1024x768 */
1059 }
1060
1061 /*
1062 * Uga graphics
1063 */
1064 rc = CFGMR3QueryU32(pCfg, "UgaHorizontalResolution", &pThis->u32UgaHorisontal);
1065 AssertRC(rc);
1066 if (pThis->u32UgaHorisontal == 0)
1067 {
1068 pThis->u32UgaHorisontal = 1024; /* 1024x768 */
1069 }
1070 rc = CFGMR3QueryU32(pCfg, "UgaVerticalResolution", &pThis->u32UgaVertical);
1071 AssertRC(rc);
1072 if (pThis->u32UgaVertical == 0)
1073 {
1074 pThis->u32UgaVertical = 768; /* 1024x768 */
1075 }
1076
1077#ifdef DEVEFI_WITH_VBOXDBG_SCRIPT
1078 /*
1079 * Zap the debugger script
1080 */
1081 RTFileDelete("./DevEFI.VBoxDbg");
1082#endif
1083
1084 /*
1085 * Load firmware volume and thunk ROM.
1086 */
1087 rc = efiLoadRom(pThis, pCfg);
1088 if (RT_FAILURE(rc))
1089 return rc;
1090
1091#if 0
1092 rc = efiLoadThunk(pThis, pCfg);
1093 if (RT_FAILURE(rc))
1094 return rc;
1095#endif
1096
1097 /*
1098 * Register our communication ports.
1099 */
1100 rc = PDMDevHlpIOPortRegister(pDevIns, EFI_PORT_BASE, EFI_PORT_COUNT, NULL,
1101 efiIOPortWrite, efiIOPortRead,
1102 NULL, NULL, "EFI communication ports");
1103 if (RT_FAILURE(rc))
1104 return rc;
1105
1106 /*
1107 * Plant DMI and MPS tables
1108 * XXX I wonder if we really need these tables as there is no SMBIOS header...
1109 */
1110 uint16_t cbDmiTablesDummy;
1111 rc = FwCommonPlantDMITable(pDevIns, pThis->au8DMIPage, VBOX_DMI_TABLE_SIZE, &pThis->aUuid,
1112 pDevIns->pCfg, pThis->cCpus, &cbDmiTablesDummy);
1113 AssertRCReturn(rc, rc);
1114 if (pThis->u8IOAPIC)
1115 FwCommonPlantMpsTable(pDevIns,
1116 pThis->au8DMIPage + VBOX_DMI_TABLE_SIZE,
1117 _4K - VBOX_DMI_TABLE_SIZE, pThis->cCpus);
1118 rc = PDMDevHlpROMRegister(pDevIns, VBOX_DMI_TABLE_BASE, _4K, pThis->au8DMIPage, _4K,
1119 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "DMI tables");
1120
1121 AssertRCReturn(rc, rc);
1122
1123 /*
1124 * Call reset to set things up.
1125 */
1126 efiReset(pDevIns);
1127
1128 return VINF_SUCCESS;
1129}
1130
1131/**
1132 * The device registration structure.
1133 */
1134const PDMDEVREG g_DeviceEFI =
1135{
1136 /* u32Version */
1137 PDM_DEVREG_VERSION,
1138 /* szName */
1139 "efi",
1140 /* szRCMod */
1141 "",
1142 /* szR0Mod */
1143 "",
1144 /* pszDescription */
1145 "Extensible Firmware Interface Device",
1146 /* fFlags */
1147 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64,
1148 /* fClass */
1149 PDM_DEVREG_CLASS_ARCH_BIOS,
1150 /* cMaxInstances */
1151 1,
1152 /* cbInstance */
1153 sizeof(DEVEFI),
1154 /* pfnConstruct */
1155 efiConstruct,
1156 /* pfnDestruct */
1157 efiDestruct,
1158 /* pfnRelocate */
1159 NULL,
1160 /* pfnIOCtl */
1161 NULL,
1162 /* pfnPowerOn */
1163 NULL,
1164 /* pfnReset */
1165 efiReset,
1166 /* pfnSuspend */
1167 NULL,
1168 /* pfnResume */
1169 NULL,
1170 /* pfnAttach */
1171 NULL,
1172 /* pfnDetach */
1173 NULL,
1174 /* pfnQueryInterface. */
1175 NULL,
1176 /* pfnInitComplete. */
1177 efiInitComplete,
1178 /* pfnPowerOff */
1179 NULL,
1180 /* pfnSoftReset */
1181 NULL,
1182 /* u32VersionEnd */
1183 PDM_DEVREG_VERSION
1184};
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