VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/DevEFI.cpp@ 26208

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

EFI: bits

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