VirtualBox

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

Last change on this file since 28345 was 28203, checked in by vboxsync, 15 years ago

DevPcBios,DevEFI,DevFWCommon: Don't reconstruct the MPS table at reset, just replant the MPS table pointer.

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