VirtualBox

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

Last change on this file since 33826 was 33540, checked in by vboxsync, 14 years ago

*: spelling fixes, thanks Timeless!

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