VirtualBox

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

Last change on this file since 43030 was 41284, checked in by vboxsync, 13 years ago

DevEFI: warning (NULL => NIL_RTGCPHYS)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 45.2 KB
Line 
1/* $Id: DevEFI.cpp 41284 2012-05-14 14:19:35Z 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/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 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_R3_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 LogFunc(("Found %RTuuid of type:%d\n", &pFfsFile->Name, FileType));
574 return pFfsFile;
575 }
576 pFfsFile = (EFI_FFS_FILE_HEADER *)((uintptr_t)pFfsFile + RT_ALIGN(FFS_SIZE(pFfsFile), 8));
577 }
578 return NULL;
579}
580
581static int efiFindRelativeAddressOfEPAndBaseAddressOfModule(EFI_FFS_FILE_HEADER const *pFfsFile, uint32_t cbFfsFile, RTGCPHYS *pImageBase, uint8_t **ppbImage)
582{
583 /*
584 * Sections headers are lays at the beginning of block it describes,
585 * the first section header is located immediately after FFS header.
586 */
587 EFI_FILE_SECTION_POINTER uSecHdrPtr;
588 uint8_t const * const pbFfsFileEnd = (uint8_t *)pFfsFile + cbFfsFile;
589 uint8_t const *pbImage = NULL;
590 uint8_t const *pbSecHdr = (uint8_t const *)&pFfsFile[1]; /* FFS header has fixed size */
591 for (; (uintptr_t)pbSecHdr < (uintptr_t)pbFfsFileEnd;
592 pbSecHdr += SECTION_SIZE(uSecHdrPtr.CommonHeader))
593 {
594 uSecHdrPtr.CommonHeader = (EFI_COMMON_SECTION_HEADER *)pbSecHdr;
595 if ( uSecHdrPtr.CommonHeader->Type == EFI_SECTION_PE32
596 || uSecHdrPtr.CommonHeader->Type == EFI_SECTION_TE)
597 {
598 /*Here should be other code containing sections*/
599 pbImage = (uint8_t const *)&uSecHdrPtr.Pe32Section[1]; /* the PE/PE+/TE headers begins just after the Section Header */
600 break;
601 }
602 Log2(("EFI: Section of type:%d has been detected\n", uSecHdrPtr.CommonHeader->Type));
603 }
604 AssertLogRelMsgReturn(pbImage, ("Failed to find PE32 or TE section for the SECURITY_CORE FFS\n"), VERR_INVALID_PARAMETER);
605
606 /*
607 * Parse the image extracting the ImageBase and the EntryPoint.
608 */
609 int rc = VINF_SUCCESS;
610 union EfiHdrUnion
611 {
612 EFI_IMAGE_DOS_HEADER Dos;
613 EFI_IMAGE_NT_HEADERS32 Nt32;
614 EFI_IMAGE_NT_HEADERS64 Nt64;
615 EFI_TE_IMAGE_HEADER Te;
616 };
617 EfiHdrUnion const *pHdr = (EfiHdrUnion const *)pbImage;
618
619 /* Skip MZ if found. */
620 if (pHdr->Dos.e_magic == RT_MAKE_U16('M', 'Z'))
621 {
622 uint8_t const *pbNewHdr = (uint8_t const *)pHdr + pHdr->Dos.e_lfanew;
623 AssertLogRelMsgReturn( (uintptr_t)pbNewHdr < (uintptr_t)pbFfsFileEnd
624 && (uintptr_t)pbNewHdr >= (uintptr_t)&pHdr->Dos.e_lfanew + sizeof(pHdr->Dos.e_lfanew),
625 ("%x\n", pHdr->Dos.e_lfanew),
626 VERR_BAD_EXE_FORMAT);
627 pHdr = (EfiHdrUnion const *)pbNewHdr;
628 }
629
630 RTGCPHYS ImageBase;
631 RTGCPHYS EpRVA;
632 if (pHdr->Nt32.Signature == RT_MAKE_U32_FROM_U8('P', 'E', 0, 0))
633 {
634 AssertLogRelMsgReturn( ( pHdr->Nt32.FileHeader.Machine == EFI_IMAGE_FILE_MACHINE_I386
635 && pHdr->Nt32.FileHeader.SizeOfOptionalHeader == sizeof(pHdr->Nt32.OptionalHeader))
636 || ( pHdr->Nt32.FileHeader.Machine == EFI_IMAGE_MACHINE_X64
637 && pHdr->Nt32.FileHeader.SizeOfOptionalHeader == sizeof(pHdr->Nt64.OptionalHeader)),
638 ("%x / %x\n", pHdr->Nt32.FileHeader.Machine, pHdr->Nt32.FileHeader.SizeOfOptionalHeader),
639 VERR_LDR_ARCH_MISMATCH);
640 EFI_IMAGE_SECTION_HEADER *pSectionsHeaders = NULL;
641 int cSectionsHeaders = 0;
642 if (pHdr->Nt32.FileHeader.Machine == EFI_IMAGE_FILE_MACHINE_I386)
643 {
644 Log2(("EFI: PE32/i386\n"));
645 AssertLogRelMsgReturn(pHdr->Nt32.OptionalHeader.SizeOfImage < cbFfsFile,
646 ("%#x / %#x\n", pHdr->Nt32.OptionalHeader.SizeOfImage, cbFfsFile),
647 VERR_BAD_EXE_FORMAT);
648 ImageBase = pHdr->Nt32.OptionalHeader.ImageBase;
649 EpRVA = pHdr->Nt32.OptionalHeader.AddressOfEntryPoint;
650 EpRVA -= pHdr->Nt32.OptionalHeader.BaseOfCode;
651 AssertLogRelMsgReturn(EpRVA < pHdr->Nt32.OptionalHeader.SizeOfImage,
652 ("%#RGp / %#x\n", EpRVA, pHdr->Nt32.OptionalHeader.SizeOfImage),
653 VERR_BAD_EXE_FORMAT);
654 pSectionsHeaders = (EFI_IMAGE_SECTION_HEADER *)((uint8_t *)&pHdr->Nt32.OptionalHeader + pHdr->Nt32.FileHeader.SizeOfOptionalHeader);
655 cSectionsHeaders = pHdr->Nt32.FileHeader.NumberOfSections;
656 }
657 else
658 {
659 Log2(("EFI: PE+/AMD64 %RX16\n", pHdr->Nt32.FileHeader.Machine));
660 AssertLogRelMsgReturn(pHdr->Nt64.OptionalHeader.SizeOfImage < cbFfsFile,
661 ("%#x / %#x\n", pHdr->Nt64.OptionalHeader.SizeOfImage, cbFfsFile),
662 VERR_BAD_EXE_FORMAT);
663 ImageBase = pHdr->Nt64.OptionalHeader.ImageBase;
664 EpRVA = pHdr->Nt64.OptionalHeader.AddressOfEntryPoint;
665 EpRVA -= pHdr->Nt64.OptionalHeader.BaseOfCode;
666 AssertLogRelMsgReturn(EpRVA < pHdr->Nt64.OptionalHeader.SizeOfImage,
667 ("%#RGp / %#x\n", EpRVA, pHdr->Nt64.OptionalHeader.SizeOfImage),
668 VERR_BAD_EXE_FORMAT);
669 pSectionsHeaders = (EFI_IMAGE_SECTION_HEADER *)((uint8_t *)&pHdr->Nt64.OptionalHeader + pHdr->Nt64.FileHeader.SizeOfOptionalHeader);
670 cSectionsHeaders = pHdr->Nt64.FileHeader.NumberOfSections;
671 }
672 AssertPtrReturn(pSectionsHeaders, VERR_BAD_EXE_FORMAT);
673 int idxSection = 0;
674 for (; idxSection < cSectionsHeaders; ++idxSection)
675 {
676 EFI_IMAGE_SECTION_HEADER *pSection = &pSectionsHeaders[idxSection];
677 if (!RTStrCmp((const char *)&pSection->Name[0], ".text"))
678 {
679 EpRVA += pSection->PointerToRawData;
680 break;
681 }
682 }
683 }
684 else if (pHdr->Te.Signature == RT_MAKE_U16('V', 'Z'))
685 {
686 /* TE header */
687 Log2(("EFI: TE header\n"));
688 AssertLogRelMsgReturn( pHdr->Te.Machine == EFI_IMAGE_FILE_MACHINE_I386
689 || pHdr->Te.Machine == EFI_IMAGE_MACHINE_X64,
690 ("%x\n", pHdr->Te.Machine),
691 VERR_LDR_ARCH_MISMATCH);
692 ImageBase = pHdr->Te.ImageBase;
693 EpRVA = pHdr->Te.AddressOfEntryPoint;
694 AssertLogRelMsgReturn(EpRVA < cbFfsFile,
695 ("%#RGp / %#x\n", EpRVA, cbFfsFile),
696 VERR_BAD_EXE_FORMAT);
697 }
698 else
699 AssertLogRelMsgFailedReturn(("%#x\n", pHdr->Nt32.Signature), VERR_INVALID_EXE_SIGNATURE);
700
701 Log2(("EFI: EpRVA=%RGp ImageBase=%RGp EntryPoint=%RGp\n", EpRVA, ImageBase, EpRVA + ImageBase));
702 if (pImageBase != NULL)
703 *pImageBase = ImageBase;
704 if (ppbImage != NULL)
705 *ppbImage = (uint8_t *)pbImage;
706 return (EpRVA);
707}
708
709/**
710 * Parse EFI ROM headers and find entry points.
711 *
712 * @returns VBox status.
713 * @param pThis The device instance data.
714 */
715static int efiParseFirmware(PDEVEFI pThis)
716{
717 EFI_FIRMWARE_VOLUME_HEADER const *pFwVolHdr = (EFI_FIRMWARE_VOLUME_HEADER const *)pThis->pu8EfiRom;
718
719 /*
720 * Validate firmware volume header.
721 */
722 AssertLogRelMsgReturn(pFwVolHdr->Signature == RT_MAKE_U32_FROM_U8('_', 'F', 'V', 'H'),
723 ("%#x, expected %#x\n", pFwVolHdr->Signature, RT_MAKE_U32_FROM_U8('_', 'F', 'V', 'H')),
724 VERR_INVALID_MAGIC);
725 AssertLogRelMsgReturn(pFwVolHdr->Revision == EFI_FVH_REVISION,
726 ("%#x, expected %#x\n", pFwVolHdr->Signature, EFI_FVH_REVISION),
727 VERR_VERSION_MISMATCH);
728 /** @todo check checksum, see PE spec vol. 3 */
729 AssertLogRelMsgReturn(pFwVolHdr->FvLength <= pThis->cbEfiRom,
730 ("%#llx, expected %#llx\n", pFwVolHdr->FvLength, pThis->cbEfiRom),
731 VERR_INVALID_PARAMETER);
732 AssertLogRelMsgReturn( pFwVolHdr->BlockMap[0].Length > 0
733 && pFwVolHdr->BlockMap[0].NumBlocks > 0,
734 ("%#x, %x\n", pFwVolHdr->BlockMap[0].Length, pFwVolHdr->BlockMap[0].NumBlocks),
735 VERR_INVALID_PARAMETER);
736
737 AssertLogRelMsgReturn(!(pThis->cbEfiRom & PAGE_OFFSET_MASK), ("%RX64\n", pThis->cbEfiRom), VERR_INVALID_PARAMETER);
738
739 uint8_t const * const pbFwVolEnd = pThis->pu8EfiRom + pFwVolHdr->FvLength;
740
741 /*
742 * Ffs files are stored one by one, so to find SECURITY_CORE we've to
743 * search thru every one on the way.
744 */
745 uint32_t cbFfsFile = 0; /* shut up gcc */
746 EFI_FFS_FILE_HEADER const *pFfsFile = (EFI_FFS_FILE_HEADER const *)(pThis->pu8EfiRom + pFwVolHdr->HeaderLength);
747 pFfsFile = efiFwVolFindFileByType(pFfsFile, pbFwVolEnd, EFI_FV_FILETYPE_SECURITY_CORE, &cbFfsFile);
748 AssertLogRelMsgReturn(pFfsFile, ("No SECURITY_CORE found in the firmware volume\n"), VERR_FILE_NOT_FOUND);
749
750 RTGCPHYS ImageBase = NIL_RTGCPHYS;
751 uint8_t *pbImage = NULL;
752 pThis->GCEntryPoint0 = efiFindRelativeAddressOfEPAndBaseAddressOfModule(pFfsFile, cbFfsFile, &ImageBase, &pbImage);
753 pThis->GCEntryPoint0 += pbImage - pThis->pu8EfiRom;
754 Assert(pThis->pu8EfiRom <= pbImage);
755 Assert(pbImage < pThis->pu8EfiRom + pThis->cbEfiRom);
756 /*
757 * Calc the firmware load address from the image base and validate it.
758 */
759 pThis->GCLoadAddress = ImageBase - (pbImage - pThis->pu8EfiRom);
760 pThis->GCEntryPoint0 += pThis->GCLoadAddress;
761 AssertLogRelMsgReturn(~(pThis->GCLoadAddress & PAGE_OFFSET_MASK),
762 ("%RGp\n", pThis->GCLoadAddress),
763 VERR_INVALID_PARAMETER);
764 AssertLogRelMsgReturn(pThis->GCLoadAddress > UINT32_C(0xf0000000),
765 ("%RGp\n", pThis->GCLoadAddress),
766 VERR_OUT_OF_RANGE);
767 AssertLogRelMsgReturn( pThis->GCLoadAddress + (pThis->cbEfiRom - 1) > UINT32_C(0xf0000000)
768 && pThis->GCLoadAddress + (pThis->cbEfiRom - 1) < UINT32_C(0xffffe000),
769 ("%RGp + %RX64\n", pThis->GCLoadAddress, pThis->cbEfiRom),
770 VERR_OUT_OF_RANGE);
771
772 LogRel(("EFI: Firmware volume loading at %RGp, SEC CORE at %RGp with EP at %RGp\n",
773 pThis->GCLoadAddress, ImageBase, pThis->GCEntryPoint0));
774
775 pFfsFile = efiFwVolFindFileByType(pFfsFile, pbFwVolEnd, EFI_FV_FILETYPE_PEI_CORE, &cbFfsFile);
776 pThis->GCEntryPoint1 = efiFindRelativeAddressOfEPAndBaseAddressOfModule(pFfsFile, cbFfsFile, NULL, &pbImage);
777 pThis->GCEntryPoint1 += pThis->GCLoadAddress;
778 pThis->GCEntryPoint1 += pbImage - pThis->pu8EfiRom;
779 LogRel(("EFI: Firmware volume loading at %RGp, PEI CORE at with EP at %RGp\n",
780 pThis->GCLoadAddress, pThis->GCEntryPoint1));
781 return VINF_SUCCESS;
782}
783
784/**
785 * Load EFI ROM file into the memory.
786 *
787 * @returns VBox status.
788 * @param pThis The device instance data.
789 * @param pCfg Configuration node handle for the device.
790 */
791static int efiLoadRom(PDEVEFI pThis, PCFGMNODE pCfg)
792{
793 /*
794 * Read the entire firmware volume into memory.
795 */
796 void *pvFile;
797 size_t cbFile;
798 int rc = RTFileReadAllEx(pThis->pszEfiRomFile,
799 0 /*off*/,
800 RTFOFF_MAX /*cbMax*/,
801 RTFILE_RDALL_O_DENY_WRITE,
802 &pvFile,
803 &cbFile);
804 if (RT_FAILURE(rc))
805 return PDMDevHlpVMSetError(pThis->pDevIns, rc, RT_SRC_POS,
806 N_("Loading the EFI firmware volume '%s' failed with rc=%Rrc"),
807 pThis->pszEfiRomFile, rc);
808 pThis->pu8EfiRom = (uint8_t *)pvFile;
809 pThis->cbEfiRom = cbFile;
810
811 /*
812 * Validate firmware volume and figure out the load address as well as the SEC entry point.
813 */
814 rc = efiParseFirmware(pThis);
815 if (RT_FAILURE(rc))
816 return PDMDevHlpVMSetError(pThis->pDevIns, rc, RT_SRC_POS,
817 N_("Parsing the EFI firmware volume '%s' failed with rc=%Rrc"),
818 pThis->pszEfiRomFile, rc);
819
820 /*
821 * Map the firmware volume into memory as shadowed ROM.
822 */
823 /** @todo fix PGMR3PhysRomRegister so it doesn't mess up in SUPLib when mapping a big ROM image. */
824 RTGCPHYS cbQuart = RT_ALIGN_64(pThis->cbEfiRom / 4, PAGE_SIZE);
825 rc = PDMDevHlpROMRegister(pThis->pDevIns,
826 pThis->GCLoadAddress,
827 cbQuart,
828 pThis->pu8EfiRom,
829 cbQuart,
830 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
831 "EFI Firmware Volume");
832 AssertRCReturn(rc, rc);
833 rc = PDMDevHlpROMProtectShadow(pThis->pDevIns, pThis->GCLoadAddress, (uint32_t)cbQuart, PGMROMPROT_READ_RAM_WRITE_IGNORE);
834 AssertRCReturn(rc, rc);
835 rc = PDMDevHlpROMRegister(pThis->pDevIns,
836 pThis->GCLoadAddress + cbQuart,
837 cbQuart,
838 pThis->pu8EfiRom + cbQuart,
839 cbQuart,
840 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
841 "EFI Firmware Volume (Part 2)");
842 if (RT_FAILURE(rc))
843 return rc;
844 rc = PDMDevHlpROMRegister(pThis->pDevIns,
845 pThis->GCLoadAddress + cbQuart * 2,
846 cbQuart,
847 pThis->pu8EfiRom + cbQuart * 2,
848 cbQuart,
849 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
850 "EFI Firmware Volume (Part 3)");
851 if (RT_FAILURE(rc))
852 return rc;
853 rc = PDMDevHlpROMRegister(pThis->pDevIns,
854 pThis->GCLoadAddress + cbQuart * 3,
855 pThis->cbEfiRom - cbQuart * 3,
856 pThis->pu8EfiRom + cbQuart * 3,
857 pThis->cbEfiRom - cbQuart * 3,
858 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
859 "EFI Firmware Volume (Part 4)");
860 if (RT_FAILURE(rc))
861 return rc;
862 return VINF_SUCCESS;
863}
864
865/**
866 * Patches and loads the EfiThunk ROM image.
867 *
868 * The thunk image is where the CPU starts and will switch it into
869 * 32-bit protected or long mode and invoke the SEC CORE image in the
870 * firmware volume. It also contains some static VM configuration data
871 * at the very beginning of the page, see DEVEFIINFO.
872 *
873 * @returns VBox status code.
874 * @param pThis The device instance data.
875 * @param pCfg Configuration node handle for the device.
876 */
877static int efiLoadThunk(PDEVEFI pThis, PCFGMNODE pCfg)
878{
879 uint8_t f64BitEntry = 0;
880 int rc;
881
882 rc = CFGMR3QueryU8Def(pCfg, "64BitEntry", &f64BitEntry, 0);
883 if (RT_FAILURE (rc))
884 return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
885 N_("Configuration error: Failed to read \"64BitEntry\""));
886
887 /*
888 * Make a copy of the page and set the values of the DEVEFIINFO structure
889 * found at the beginning of it.
890 */
891
892 if (f64BitEntry)
893 LogRel(("Using 64-bit EFI firmware\n"));
894
895 /* Duplicate the page so we can change it. */
896 AssertRelease(g_cbEfiThunkBinary == PAGE_SIZE);
897 pThis->pu8EfiThunk = (uint8_t *)PDMDevHlpMMHeapAlloc(pThis->pDevIns, PAGE_SIZE);
898 if (pThis->pu8EfiThunk == NULL)
899 return VERR_NO_MEMORY;
900 memcpy(pThis->pu8EfiThunk, &g_abEfiThunkBinary[0], PAGE_SIZE);
901
902 /* Fill in the info. */
903 PDEVEFIINFO pEfiInfo = (PDEVEFIINFO)pThis->pu8EfiThunk;
904 pEfiInfo->pfnFirmwareEP = (uint32_t)pThis->GCEntryPoint0;
905 //AssertRelease(pEfiInfo->pfnFirmwareEP == pThis->GCEntryPoint0);
906 pEfiInfo->HighEPAddress = 0;
907 pEfiInfo->PhysFwVol = pThis->GCLoadAddress;
908 pEfiInfo->cbFwVol = (uint32_t)pThis->cbEfiRom;
909 AssertRelease(pEfiInfo->cbFwVol == (uint32_t)pThis->cbEfiRom);
910 pEfiInfo->cbBelow4GB = pThis->cbBelow4GB;
911 pEfiInfo->cbAbove4GB = pThis->cbAbove4GB;
912 /* zeroth bit controls use of 64-bit entry point in fw */
913 pEfiInfo->fFlags = f64BitEntry ? 1 : 0;
914 pEfiInfo->cCpus = pThis->cCpus;
915 pEfiInfo->pfnPeiEP = (uint32_t)pThis->GCEntryPoint1;
916 pEfiInfo->u32Reserved2 = 0;
917
918 /* Register the page as a ROM (data will be copied). */
919 rc = PDMDevHlpROMRegister(pThis->pDevIns, UINT32_C(0xfffff000), PAGE_SIZE,
920 pThis->pu8EfiThunk, PAGE_SIZE,
921 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "EFI Thunk");
922 if (RT_FAILURE(rc))
923 return rc;
924
925#if 1 /** @todo this is probably not necessary. */
926 /*
927 * Map thunk page also at low address, so that real->protected mode jump code can
928 * store GDT/IDT in code segment in low memory and load them during switch to the
929 * protected mode, while being in 16-bits mode.
930 *
931 * @todo: maybe need to unregister later or place somewhere else (although could
932 * be needed during reset)
933 */
934 rc = PDMDevHlpROMRegister(pThis->pDevIns, 0xff000, PAGE_SIZE,
935 pThis->pu8EfiThunk, PAGE_SIZE,
936 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "EFI Thunk (2)");
937 if (RT_FAILURE(rc))
938 return rc;
939#endif
940
941 return rc;
942}
943
944
945static uint8_t efiGetHalfByte(char ch)
946{
947 uint8_t val;
948
949 if (ch >= '0' && ch <= '9')
950 val = ch - '0';
951 else if (ch >= 'A' && ch <= 'F')
952 val = ch - 'A' + 10;
953 else if(ch >= 'a' && ch <= 'f')
954 val = ch - 'a' + 10;
955 else
956 val = 0xff;
957
958 return val;
959
960}
961
962
963static int efiParseDeviceString(PDEVEFI pThis, char* pszDeviceProps)
964{
965 int rc = 0;
966 uint32_t iStr, iHex, u32OutLen;
967 uint8_t u8Value = 0; /* (shut up gcc) */
968 bool fUpper = true;
969
970 u32OutLen = (uint32_t)RTStrNLen(pszDeviceProps, RTSTR_MAX) / 2 + 1;
971
972 pThis->pu8DeviceProps =
973 (uint8_t*)PDMDevHlpMMHeapAlloc(pThis->pDevIns, u32OutLen);
974 if (!pThis->pu8DeviceProps)
975 return VERR_NO_MEMORY;
976
977 for (iStr=0, iHex = 0; pszDeviceProps[iStr]; iStr++)
978 {
979 uint8_t u8Hb = efiGetHalfByte(pszDeviceProps[iStr]);
980 if (u8Hb > 0xf)
981 continue;
982
983 if (fUpper)
984 u8Value = u8Hb << 4;
985 else
986 pThis->pu8DeviceProps[iHex++] = u8Hb | u8Value;
987
988 Assert(iHex < u32OutLen);
989 fUpper = !fUpper;
990 }
991
992 Assert(iHex == 0 || fUpper);
993 pThis->u32DevicePropsLen = iHex;
994
995 return rc;
996}
997
998/**
999 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1000 */
1001static DECLCALLBACK(int) efiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1002{
1003 PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
1004 int rc;
1005
1006 Assert(iInstance == 0);
1007
1008 pThis->pDevIns = pDevIns;
1009
1010 /*
1011 * Validate and read the configuration.
1012 */
1013 if (!CFGMR3AreValuesValid(pCfg,
1014 "EfiRom\0"
1015 "RamSize\0"
1016 "RamHoleSize\0"
1017 "NumCPUs\0"
1018 "UUID\0"
1019 "IOAPIC\0"
1020 "DmiBIOSVendor\0"
1021 "DmiBIOSVersion\0"
1022 "DmiBIOSReleaseDate\0"
1023 "DmiBIOSReleaseMajor\0"
1024 "DmiBIOSReleaseMinor\0"
1025 "DmiBIOSFirmwareMajor\0"
1026 "DmiBIOSFirmwareMinor\0"
1027 "DmiSystemSKU\0"
1028 "DmiSystemFamily\0"
1029 "DmiSystemProduct\0"
1030 "DmiSystemSerial\0"
1031 "DmiSystemUuid\0"
1032 "DmiSystemVendor\0"
1033 "DmiSystemVersion\0"
1034 "DmiChassisVendor\0"
1035 "DmiChassisVersion\0"
1036 "DmiChassisSerial\0"
1037 "DmiChassisAssetTag\0"
1038#ifdef VBOX_WITH_DMI_OEMSTRINGS
1039 "DmiOEMVBoxVer\0"
1040 "DmiOEMVBoxRev\0"
1041#endif
1042 "DmiUseHostInfo\0"
1043 "DmiExposeMemoryTable\0"
1044 "DmiExposeProcInf\0"
1045 "64BitEntry\0"
1046 "BootArgs\0"
1047 "DeviceProps\0"
1048 "GopMode\0"
1049 "UgaHorizontalResolution\0"
1050 "UgaVerticalResolution\0"
1051 ))
1052 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
1053 N_("Configuration error: Invalid config value(s) for the EFI device"));
1054
1055 /* CPU count (optional). */
1056 rc = CFGMR3QueryU32Def(pCfg, "NumCPUs", &pThis->cCpus, 1);
1057 AssertLogRelRCReturn(rc, rc);
1058
1059 rc = CFGMR3QueryU8Def(pCfg, "IOAPIC", &pThis->u8IOAPIC, 1);
1060 if (RT_FAILURE (rc))
1061 return PDMDEV_SET_ERROR(pDevIns, rc,
1062 N_("Configuration error: Failed to read \"IOAPIC\""));
1063
1064 /*
1065 * Query the machine's UUID for SMBIOS/DMI use.
1066 */
1067 RTUUID uuid;
1068 rc = CFGMR3QueryBytes(pCfg, "UUID", &uuid, sizeof(uuid));
1069 if (RT_FAILURE(rc))
1070 return PDMDEV_SET_ERROR(pDevIns, rc,
1071 N_("Configuration error: Querying \"UUID\" failed"));
1072
1073 /*
1074 * Convert the UUID to network byte order. Not entirely straightforward as
1075 * parts are MSB already...
1076 */
1077 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
1078 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
1079 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
1080 memcpy(&pThis->aUuid, &uuid, sizeof pThis->aUuid);
1081
1082
1083 /*
1084 * RAM sizes
1085 */
1086 rc = CFGMR3QueryU64(pCfg, "RamSize", &pThis->cbRam);
1087 AssertLogRelRCReturn(rc, rc);
1088 rc = CFGMR3QueryU64(pCfg, "RamHoleSize", &pThis->cbRamHole);
1089 AssertLogRelRCReturn(rc, rc);
1090 pThis->cbBelow4GB = RT_MIN(pThis->cbRam, _4G - pThis->cbRamHole);
1091 pThis->cbAbove4GB = pThis->cbRam - pThis->cbBelow4GB;
1092
1093 /*
1094 * Get the system EFI ROM file name.
1095 */
1096 rc = CFGMR3QueryStringAlloc(pCfg, "EfiRom", &pThis->pszEfiRomFile);
1097 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1098 {
1099 pThis->pszEfiRomFile = (char *)PDMDevHlpMMHeapAlloc(pDevIns, RTPATH_MAX);
1100 if (!pThis->pszEfiRomFile)
1101 return VERR_NO_MEMORY;
1102
1103 rc = RTPathAppPrivateArchTop(pThis->pszEfiRomFile, RTPATH_MAX);
1104 AssertRCReturn(rc, rc);
1105 rc = RTPathAppend(pThis->pszEfiRomFile, RTPATH_MAX, "VBoxEFI32.fd");
1106 AssertRCReturn(rc, rc);
1107 }
1108 else if (RT_FAILURE(rc))
1109 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1110 N_("Configuration error: Querying \"EfiRom\" as a string failed"));
1111 else if (!*pThis->pszEfiRomFile)
1112 {
1113 MMR3HeapFree(pThis->pszEfiRomFile);
1114 pThis->pszEfiRomFile = NULL;
1115 }
1116
1117 /*
1118 * Get boot args.
1119 */
1120 rc = CFGMR3QueryString(pCfg, "BootArgs",
1121 pThis->szBootArgs, sizeof pThis->szBootArgs);
1122 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1123 {
1124 strcpy(pThis->szBootArgs, "");
1125 rc = VINF_SUCCESS;
1126 }
1127 if (RT_FAILURE(rc))
1128 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1129 N_("Configuration error: Querying \"BootArgs\" as a string failed"));
1130
1131 LogRel(("EFI boot args: %s\n", pThis->szBootArgs));
1132
1133 /*
1134 * Get device props.
1135 */
1136 char* pszDeviceProps;
1137 rc = CFGMR3QueryStringAlloc(pCfg, "DeviceProps", &pszDeviceProps);
1138 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1139 {
1140 pszDeviceProps = NULL;
1141 rc = VINF_SUCCESS;
1142 }
1143 if (RT_FAILURE(rc))
1144 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1145 N_("Configuration error: Querying \"DeviceProps\" as a string failed"));
1146 if (pszDeviceProps)
1147 {
1148 LogRel(("EFI device props: %s\n", pszDeviceProps));
1149 rc = efiParseDeviceString(pThis, pszDeviceProps);
1150 MMR3HeapFree(pszDeviceProps);
1151 if (RT_FAILURE(rc))
1152 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1153 N_("Configuration error: Cannot parse device properties"));
1154 }
1155 else
1156 {
1157 pThis->pu8DeviceProps = NULL;
1158 pThis->u32DevicePropsLen = 0;
1159 }
1160
1161 /*
1162 * CPU frequencies
1163 */
1164 // @todo: we need to have VMM API to access TSC increase speed, for now provide reasonable default
1165 pThis->u64TscFrequency = RTMpGetMaxFrequency(0) * 1024 * 1024;// TMCpuTicksPerSecond(PDMDevHlpGetVM(pDevIns));
1166 if (pThis->u64TscFrequency == 0)
1167 pThis->u64TscFrequency = UINT64_C(2500000000);
1168 /* Multiplier is read from MSR_IA32_PERF_STATUS, and now is hardcoded as 4 */
1169 pThis->u64FsbFrequency = pThis->u64TscFrequency / 4;
1170 pThis->u64CpuFrequency = pThis->u64TscFrequency;
1171
1172 /*
1173 * GOP graphics
1174 */
1175 rc = CFGMR3QueryU32(pCfg, "GopMode", &pThis->u32GopMode);
1176 AssertRC(rc);
1177 if (pThis->u32GopMode == UINT32_MAX)
1178 {
1179 pThis->u32GopMode = 2; /* 1024x768 */
1180 }
1181
1182 /*
1183 * Uga graphics
1184 */
1185 rc = CFGMR3QueryU32(pCfg, "UgaHorizontalResolution", &pThis->u32UgaHorisontal);
1186 AssertRC(rc);
1187 if (pThis->u32UgaHorisontal == 0)
1188 {
1189 pThis->u32UgaHorisontal = 1024; /* 1024x768 */
1190 }
1191 rc = CFGMR3QueryU32(pCfg, "UgaVerticalResolution", &pThis->u32UgaVertical);
1192 AssertRC(rc);
1193 if (pThis->u32UgaVertical == 0)
1194 {
1195 pThis->u32UgaVertical = 768; /* 1024x768 */
1196 }
1197
1198#ifdef DEVEFI_WITH_VBOXDBG_SCRIPT
1199 /*
1200 * Zap the debugger script
1201 */
1202 RTFileDelete("./DevEFI.VBoxDbg");
1203#endif
1204
1205 /*
1206 * Load firmware volume and thunk ROM.
1207 */
1208 rc = efiLoadRom(pThis, pCfg);
1209 if (RT_FAILURE(rc))
1210 return rc;
1211
1212 rc = efiLoadThunk(pThis, pCfg);
1213 if (RT_FAILURE(rc))
1214 return rc;
1215
1216 /*
1217 * Register our communication ports.
1218 */
1219 rc = PDMDevHlpIOPortRegister(pDevIns, EFI_PORT_BASE, EFI_PORT_COUNT, NULL,
1220 efiIOPortWrite, efiIOPortRead,
1221 NULL, NULL, "EFI communication ports");
1222 if (RT_FAILURE(rc))
1223 return rc;
1224
1225 /*
1226 * Plant DMI and MPS tables
1227 * XXX I wonder if we really need these tables as there is no SMBIOS header...
1228 */
1229 uint16_t cbDmiTablesDummy;
1230 rc = FwCommonPlantDMITable(pDevIns, pThis->au8DMIPage, VBOX_DMI_TABLE_SIZE, &pThis->aUuid,
1231 pDevIns->pCfg, pThis->cCpus, &cbDmiTablesDummy);
1232 AssertRCReturn(rc, rc);
1233 if (pThis->u8IOAPIC)
1234 FwCommonPlantMpsTable(pDevIns,
1235 pThis->au8DMIPage + VBOX_DMI_TABLE_SIZE,
1236 _4K - VBOX_DMI_TABLE_SIZE, pThis->cCpus);
1237 rc = PDMDevHlpROMRegister(pDevIns, VBOX_DMI_TABLE_BASE, _4K, pThis->au8DMIPage, _4K,
1238 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "DMI tables");
1239
1240 AssertRCReturn(rc, rc);
1241
1242 /*
1243 * Call reset to set things up.
1244 */
1245 efiReset(pDevIns);
1246
1247 return VINF_SUCCESS;
1248}
1249
1250/**
1251 * The device registration structure.
1252 */
1253const PDMDEVREG g_DeviceEFI =
1254{
1255 /* u32Version */
1256 PDM_DEVREG_VERSION,
1257 /* szName */
1258 "efi",
1259 /* szRCMod */
1260 "",
1261 /* szR0Mod */
1262 "",
1263 /* pszDescription */
1264 "Extensible Firmware Interface Device",
1265 /* fFlags */
1266 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64,
1267 /* fClass */
1268 PDM_DEVREG_CLASS_ARCH_BIOS,
1269 /* cMaxInstances */
1270 1,
1271 /* cbInstance */
1272 sizeof(DEVEFI),
1273 /* pfnConstruct */
1274 efiConstruct,
1275 /* pfnDestruct */
1276 efiDestruct,
1277 /* pfnRelocate */
1278 NULL,
1279 /* pfnIOCtl */
1280 NULL,
1281 /* pfnPowerOn */
1282 NULL,
1283 /* pfnReset */
1284 efiReset,
1285 /* pfnSuspend */
1286 NULL,
1287 /* pfnResume */
1288 NULL,
1289 /* pfnAttach */
1290 NULL,
1291 /* pfnDetach */
1292 NULL,
1293 /* pfnQueryInterface. */
1294 NULL,
1295 /* pfnInitComplete. */
1296 efiInitComplete,
1297 /* pfnPowerOff */
1298 NULL,
1299 /* pfnSoftReset */
1300 NULL,
1301 /* u32VersionEnd */
1302 PDM_DEVREG_VERSION
1303};
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