VirtualBox

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

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

DevEFI.cpp: Updates.

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