VirtualBox

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

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

header (C) fixes

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