VirtualBox

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

Last change on this file since 34906 was 34163, checked in by vboxsync, 14 years ago

PGMR3PhysRomRegister/PDMDevHlpROMRegister: Added cbBinary argument to allow specifying a binary smaller than the range (no alignment restrictions either). Untested.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.4 KB
Line 
1/* $Id: DevEFI.cpp 34163 2010-11-18 12:16:43Z 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 cbQuart,
804 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
805 "EFI Firmware Volume");
806 if (RT_FAILURE(rc))
807 return rc;
808 rc = PDMDevHlpROMRegister(pThis->pDevIns,
809 pThis->GCLoadAddress + cbQuart,
810 cbQuart,
811 pThis->pu8EfiRom + cbQuart,
812 cbQuart,
813 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
814 "EFI Firmware Volume (Part 2)");
815 if (RT_FAILURE(rc))
816 return rc;
817 rc = PDMDevHlpROMRegister(pThis->pDevIns,
818 pThis->GCLoadAddress + cbQuart * 2,
819 cbQuart,
820 pThis->pu8EfiRom + cbQuart * 2,
821 cbQuart,
822 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
823 "EFI Firmware Volume (Part 3)");
824 if (RT_FAILURE(rc))
825 return rc;
826 rc = PDMDevHlpROMRegister(pThis->pDevIns,
827 pThis->GCLoadAddress + cbQuart * 3,
828 pThis->cbEfiRom - cbQuart * 3,
829 pThis->pu8EfiRom + cbQuart * 3,
830 pThis->cbEfiRom - cbQuart * 3,
831 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
832 "EFI Firmware Volume (Part 4)");
833 if (RT_FAILURE(rc))
834 return rc;
835 return VINF_SUCCESS;
836}
837
838/**
839 * Patches and loads the EfiThunk ROM image.
840 *
841 * The thunk image is where the CPU starts and will switch it into
842 * 32-bit protected or long mode and invoke the SEC CORE image in the
843 * firmware volume. It also contains some static VM configuration data
844 * at the very beginning of the page, see DEVEFIINFO.
845 *
846 * @returns VBox status code.
847 * @param pThis The device instance data.
848 * @param pCfg Configuration node handle for the device.
849 */
850static int efiLoadThunk(PDEVEFI pThis, PCFGMNODE pCfg)
851{
852 uint8_t f64BitEntry = 0;
853 int rc;
854
855 rc = CFGMR3QueryU8Def(pCfg, "64BitEntry", &f64BitEntry, 0);
856 if (RT_FAILURE (rc))
857 return PDMDEV_SET_ERROR(pThis->pDevIns, rc,
858 N_("Configuration error: Failed to read \"64BitEntry\""));
859
860 /*
861 * Make a copy of the page and set the values of the DEVEFIINFO structure
862 * found at the beginning of it.
863 */
864
865 if (f64BitEntry)
866 LogRel(("Using 64-bit EFI firmware\n"));
867
868 /* Duplicate the page so we can change it. */
869 AssertRelease(g_cbEfiThunkBinary == PAGE_SIZE);
870 pThis->pu8EfiThunk = (uint8_t *)PDMDevHlpMMHeapAlloc(pThis->pDevIns, PAGE_SIZE);
871 if (pThis->pu8EfiThunk == NULL)
872 return VERR_NO_MEMORY;
873 memcpy(pThis->pu8EfiThunk, &g_abEfiThunkBinary[0], PAGE_SIZE);
874
875 /* Fill in the info. */
876 PDEVEFIINFO pEfiInfo = (PDEVEFIINFO)pThis->pu8EfiThunk;
877 pEfiInfo->pfnFirmwareEP = (uint32_t)pThis->GCEntryPoint0;
878 //AssertRelease(pEfiInfo->pfnFirmwareEP == pThis->GCEntryPoint0);
879 pEfiInfo->HighEPAddress = 0;
880 pEfiInfo->PhysFwVol = pThis->GCLoadAddress;
881 pEfiInfo->cbFwVol = (uint32_t)pThis->cbEfiRom;
882 AssertRelease(pEfiInfo->cbFwVol == (uint32_t)pThis->cbEfiRom);
883 pEfiInfo->cbBelow4GB = pThis->cbBelow4GB;
884 pEfiInfo->cbAbove4GB = pThis->cbAbove4GB;
885 /* zeroth bit controls use of 64-bit entry point in fw */
886 pEfiInfo->fFlags = f64BitEntry ? 1 : 0;
887 pEfiInfo->cCpus = pThis->cCpus;
888 pEfiInfo->pfnPeiEP = (uint32_t)pThis->GCEntryPoint1;
889 pEfiInfo->u32Reserved2 = 0;
890
891 /* Register the page as a ROM (data will be copied). */
892 rc = PDMDevHlpROMRegister(pThis->pDevIns, UINT32_C(0xfffff000), PAGE_SIZE,
893 pThis->pu8EfiThunk, PAGE_SIZE,
894 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "EFI Thunk");
895 if (RT_FAILURE(rc))
896 return rc;
897
898#if 1 /** @todo this is probably not necessary. */
899 /*
900 * Map thunk page also at low address, so that real->protected mode jump code can
901 * store GDT/IDT in code segment in low memory and load them during switch to the
902 * protected mode, while being in 16-bits mode.
903 *
904 * @todo: maybe need to unregister later or place somewhere else (although could
905 * be needed during reset)
906 */
907 rc = PDMDevHlpROMRegister(pThis->pDevIns, 0xff000, PAGE_SIZE,
908 pThis->pu8EfiThunk, PAGE_SIZE,
909 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "EFI Thunk (2)");
910 if (RT_FAILURE(rc))
911 return rc;
912#endif
913
914 return rc;
915}
916
917
918static uint8_t efiGetHalfByte(char ch)
919{
920 uint8_t val;
921
922 if (ch >= '0' && ch <= '9')
923 val = ch - '0';
924 else if (ch >= 'A' && ch <= 'F')
925 val = ch - 'A' + 10;
926 else if(ch >= 'a' && ch <= 'f')
927 val = ch - 'a' + 10;
928 else
929 val = 0xff;
930
931 return val;
932
933}
934
935
936static int efiParseDeviceString(PDEVEFI pThis, char* pszDeviceProps)
937{
938 int rc = 0;
939 uint32_t iStr, iHex, u32OutLen;
940 uint8_t u8Value = 0; /* (shut up gcc) */
941 bool fUpper = true;
942
943 u32OutLen = (uint32_t)RTStrNLen(pszDeviceProps, RTSTR_MAX) / 2 + 1;
944
945 pThis->pu8DeviceProps =
946 (uint8_t*)PDMDevHlpMMHeapAlloc(pThis->pDevIns, u32OutLen);
947 if (!pThis->pu8DeviceProps)
948 return VERR_NO_MEMORY;
949
950 for (iStr=0, iHex = 0; pszDeviceProps[iStr]; iStr++)
951 {
952 uint8_t u8Hb = efiGetHalfByte(pszDeviceProps[iStr]);
953 if (u8Hb > 0xf)
954 continue;
955
956 if (fUpper)
957 u8Value = u8Hb << 4;
958 else
959 pThis->pu8DeviceProps[iHex++] = u8Hb | u8Value;
960
961 Assert(iHex < u32OutLen);
962 fUpper = !fUpper;
963 }
964
965 Assert(iHex == 0 || fUpper);
966 pThis->u32DevicePropsLen = iHex;
967
968 return rc;
969}
970
971/**
972 * @interface_method_impl{PDMDEVREG,pfnConstruct}
973 */
974static DECLCALLBACK(int) efiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
975{
976 PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
977 int rc;
978
979 Assert(iInstance == 0);
980
981 pThis->pDevIns = pDevIns;
982
983 /*
984 * Validate and read the configuration.
985 */
986 if (!CFGMR3AreValuesValid(pCfg,
987 "EfiRom\0"
988 "RamSize\0"
989 "RamHoleSize\0"
990 "NumCPUs\0"
991 "UUID\0"
992 "IOAPIC\0"
993 "DmiBIOSVendor\0"
994 "DmiBIOSVersion\0"
995 "DmiBIOSReleaseDate\0"
996 "DmiBIOSReleaseMajor\0"
997 "DmiBIOSReleaseMinor\0"
998 "DmiBIOSFirmwareMajor\0"
999 "DmiBIOSFirmwareMinor\0"
1000 "DmiSystemSKU\0"
1001 "DmiSystemFamily\0"
1002 "DmiSystemProduct\0"
1003 "DmiSystemSerial\0"
1004 "DmiSystemUuid\0"
1005 "DmiSystemVendor\0"
1006 "DmiSystemVersion\0"
1007 "DmiChassisVendor\0"
1008 "DmiChassisVersion\0"
1009 "DmiChassisSerial\0"
1010 "DmiChassisAssetTag\0"
1011#ifdef VBOX_WITH_DMI_OEMSTRINGS
1012 "DmiOEMVBoxVer\0"
1013 "DmiOEMVBoxRev\0"
1014#endif
1015 "DmiUseHostInfo\0"
1016 "DmiExposeMemoryTable\0"
1017 "64BitEntry\0"
1018 "BootArgs\0"
1019 "DeviceProps\0"
1020 "GopMode\0"
1021 "UgaHorizontalResolution\0"
1022 "UgaVerticalResolution\0"
1023 ))
1024 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
1025 N_("Configuration error: Invalid config value(s) for the EFI device"));
1026
1027 /* CPU count (optional). */
1028 rc = CFGMR3QueryU32Def(pCfg, "NumCPUs", &pThis->cCpus, 1);
1029 AssertLogRelRCReturn(rc, rc);
1030
1031 rc = CFGMR3QueryU8Def(pCfg, "IOAPIC", &pThis->u8IOAPIC, 1);
1032 if (RT_FAILURE (rc))
1033 return PDMDEV_SET_ERROR(pDevIns, rc,
1034 N_("Configuration error: Failed to read \"IOAPIC\""));
1035
1036 /*
1037 * Query the machine's UUID for SMBIOS/DMI use.
1038 */
1039 RTUUID uuid;
1040 rc = CFGMR3QueryBytes(pCfg, "UUID", &uuid, sizeof(uuid));
1041 if (RT_FAILURE(rc))
1042 return PDMDEV_SET_ERROR(pDevIns, rc,
1043 N_("Configuration error: Querying \"UUID\" failed"));
1044
1045 /*
1046 * Convert the UUID to network byte order. Not entirely straightforward as
1047 * parts are MSB already...
1048 */
1049 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
1050 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
1051 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
1052 memcpy(&pThis->aUuid, &uuid, sizeof pThis->aUuid);
1053
1054
1055 /*
1056 * RAM sizes
1057 */
1058 rc = CFGMR3QueryU64(pCfg, "RamSize", &pThis->cbRam);
1059 AssertLogRelRCReturn(rc, rc);
1060 rc = CFGMR3QueryU64(pCfg, "RamHoleSize", &pThis->cbRamHole);
1061 AssertLogRelRCReturn(rc, rc);
1062 pThis->cbBelow4GB = RT_MIN(pThis->cbRam, _4G - pThis->cbRamHole);
1063 pThis->cbAbove4GB = pThis->cbRam - pThis->cbBelow4GB;
1064
1065 /*
1066 * Get the system EFI ROM file name.
1067 */
1068 rc = CFGMR3QueryStringAlloc(pCfg, "EfiRom", &pThis->pszEfiRomFile);
1069 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1070 {
1071 pThis->pszEfiRomFile = (char *)PDMDevHlpMMHeapAlloc(pDevIns, RTPATH_MAX);
1072 if (!pThis->pszEfiRomFile)
1073 return VERR_NO_MEMORY;
1074
1075 rc = RTPathAppPrivateArch(pThis->pszEfiRomFile, RTPATH_MAX);
1076 AssertRCReturn(rc, rc);
1077 rc = RTPathAppend(pThis->pszEfiRomFile, RTPATH_MAX, "VBoxEFI32.fd");
1078 AssertRCReturn(rc, rc);
1079 }
1080 else if (RT_FAILURE(rc))
1081 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1082 N_("Configuration error: Querying \"EfiRom\" as a string failed"));
1083 else if (!*pThis->pszEfiRomFile)
1084 {
1085 MMR3HeapFree(pThis->pszEfiRomFile);
1086 pThis->pszEfiRomFile = NULL;
1087 }
1088
1089 /*
1090 * Get boot args.
1091 */
1092 rc = CFGMR3QueryString(pCfg, "BootArgs",
1093 pThis->szBootArgs, sizeof pThis->szBootArgs);
1094 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1095 {
1096 strcpy(pThis->szBootArgs, "");
1097 rc = VINF_SUCCESS;
1098 }
1099 if (RT_FAILURE(rc))
1100 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1101 N_("Configuration error: Querying \"BootArgs\" as a string failed"));
1102
1103 LogRel(("EFI boot args: %s\n", pThis->szBootArgs));
1104
1105 /*
1106 * Get device props.
1107 */
1108 char* pszDeviceProps;
1109 rc = CFGMR3QueryStringAlloc(pCfg, "DeviceProps", &pszDeviceProps);
1110 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1111 {
1112 pszDeviceProps = NULL;
1113 rc = VINF_SUCCESS;
1114 }
1115 if (RT_FAILURE(rc))
1116 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1117 N_("Configuration error: Querying \"DeviceProps\" as a string failed"));
1118 if (pszDeviceProps)
1119 {
1120 LogRel(("EFI device props: %s\n", pszDeviceProps));
1121 rc = efiParseDeviceString(pThis, pszDeviceProps);
1122 MMR3HeapFree(pszDeviceProps);
1123 if (RT_FAILURE(rc))
1124 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1125 N_("Configuration error: Cannot parse device properties"));
1126 }
1127 else
1128 {
1129 pThis->pu8DeviceProps = NULL;
1130 pThis->u32DevicePropsLen = 0;
1131 }
1132
1133 /*
1134 * CPU frequencies
1135 */
1136 // @todo: we need to have VMM API to access TSC increase speed, for now provide reasonable default
1137 pThis->u64TscFrequency = RTMpGetMaxFrequency(0) * 1024 * 1024;// TMCpuTicksPerSecond(PDMDevHlpGetVM(pDevIns));
1138 if (pThis->u64TscFrequency == 0)
1139 pThis->u64TscFrequency = UINT64_C(2500000000);
1140 /* Multiplier is read from MSR_IA32_PERF_STATUS, and now is hardcoded as 4 */
1141 pThis->u64FsbFrequency = pThis->u64TscFrequency / 4;
1142 pThis->u64CpuFrequency = pThis->u64TscFrequency;
1143
1144 /*
1145 * GOP graphics
1146 */
1147 rc = CFGMR3QueryU32(pCfg, "GopMode", &pThis->u32GopMode);
1148 AssertRC(rc);
1149 if (pThis->u32GopMode == UINT32_MAX)
1150 {
1151 pThis->u32GopMode = 2; /* 1024x768 */
1152 }
1153
1154 /*
1155 * Uga graphics
1156 */
1157 rc = CFGMR3QueryU32(pCfg, "UgaHorizontalResolution", &pThis->u32UgaHorisontal);
1158 AssertRC(rc);
1159 if (pThis->u32UgaHorisontal == 0)
1160 {
1161 pThis->u32UgaHorisontal = 1024; /* 1024x768 */
1162 }
1163 rc = CFGMR3QueryU32(pCfg, "UgaVerticalResolution", &pThis->u32UgaVertical);
1164 AssertRC(rc);
1165 if (pThis->u32UgaVertical == 0)
1166 {
1167 pThis->u32UgaVertical = 768; /* 1024x768 */
1168 }
1169
1170#ifdef DEVEFI_WITH_VBOXDBG_SCRIPT
1171 /*
1172 * Zap the debugger script
1173 */
1174 RTFileDelete("./DevEFI.VBoxDbg");
1175#endif
1176
1177 /*
1178 * Load firmware volume and thunk ROM.
1179 */
1180 rc = efiLoadRom(pThis, pCfg);
1181 if (RT_FAILURE(rc))
1182 return rc;
1183
1184 rc = efiLoadThunk(pThis, pCfg);
1185 if (RT_FAILURE(rc))
1186 return rc;
1187
1188 /*
1189 * Register our communication ports.
1190 */
1191 rc = PDMDevHlpIOPortRegister(pDevIns, EFI_PORT_BASE, EFI_PORT_COUNT, NULL,
1192 efiIOPortWrite, efiIOPortRead,
1193 NULL, NULL, "EFI communication ports");
1194 if (RT_FAILURE(rc))
1195 return rc;
1196
1197 /*
1198 * Plant DMI and MPS tables
1199 */
1200 rc = FwCommonPlantDMITable(pDevIns,
1201 pThis->au8DMIPage,
1202 VBOX_DMI_TABLE_SIZE,
1203 &pThis->aUuid,
1204 pDevIns->pCfg);
1205 AssertRCReturn(rc, rc);
1206 if (pThis->u8IOAPIC)
1207 FwCommonPlantMpsTable(pDevIns,
1208 pThis->au8DMIPage + VBOX_DMI_TABLE_SIZE,
1209 _4K - VBOX_DMI_TABLE_SIZE,
1210 pThis->cCpus);
1211 rc = PDMDevHlpROMRegister(pDevIns, VBOX_DMI_TABLE_BASE, _4K, pThis->au8DMIPage, _4K,
1212 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "DMI tables");
1213
1214 AssertRCReturn(rc, rc);
1215
1216 /*
1217 * Call reset to set things up.
1218 */
1219 efiReset(pDevIns);
1220
1221 return VINF_SUCCESS;
1222}
1223
1224/**
1225 * The device registration structure.
1226 */
1227const PDMDEVREG g_DeviceEFI =
1228{
1229 /* u32Version */
1230 PDM_DEVREG_VERSION,
1231 /* szName */
1232 "efi",
1233 /* szRCMod */
1234 "",
1235 /* szR0Mod */
1236 "",
1237 /* pszDescription */
1238 "Extensible Firmware Interface Device",
1239 /* fFlags */
1240 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64,
1241 /* fClass */
1242 PDM_DEVREG_CLASS_ARCH_BIOS,
1243 /* cMaxInstances */
1244 1,
1245 /* cbInstance */
1246 sizeof(DEVEFI),
1247 /* pfnConstruct */
1248 efiConstruct,
1249 /* pfnDestruct */
1250 efiDestruct,
1251 /* pfnRelocate */
1252 NULL,
1253 /* pfnIOCtl */
1254 NULL,
1255 /* pfnPowerOn */
1256 NULL,
1257 /* pfnReset */
1258 efiReset,
1259 /* pfnSuspend */
1260 NULL,
1261 /* pfnResume */
1262 NULL,
1263 /* pfnAttach */
1264 NULL,
1265 /* pfnDetach */
1266 NULL,
1267 /* pfnQueryInterface. */
1268 NULL,
1269 /* pfnInitComplete. */
1270 efiInitComplete,
1271 /* pfnPowerOff */
1272 NULL,
1273 /* pfnSoftReset */
1274 NULL,
1275 /* u32VersionEnd */
1276 PDM_DEVREG_VERSION
1277};
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