VirtualBox

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

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

Devices: warnings.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette