VirtualBox

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

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

Automated rebranding to Oracle copyright/license strings via filemuncher

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.1 KB
Line 
1/* $Id: DevEFI.cpp 28800 2010-04-27 08:22:32Z 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/assert.h>
32#include <iprt/alloc.h>
33#include <iprt/file.h>
34#include <iprt/string.h>
35#include <iprt/uuid.h>
36#include <iprt/path.h>
37#include <iprt/string.h>
38#include <iprt/mp.h>
39#ifdef DEBUG
40# include <iprt/stream.h>
41# define DEVEFI_WITH_VBOXDBG_SCRIPT
42#endif
43
44#include "Firmware2/VBoxPkg/Include/DevEFI.h"
45#include "../Builtins.h"
46#include "../Builtins2.h"
47#include "../PC/DevFwCommon.h"
48
49/* EFI includes */
50#include <ProcessorBind.h>
51#include <Common/UefiBaseTypes.h>
52#include <Common/PiFirmwareVolume.h>
53#include <Common/PiFirmwareFile.h>
54#include <IndustryStandard/PeImage.h>
55
56/*******************************************************************************
57* Structures and Typedefs *
58*******************************************************************************/
59typedef struct DEVEFI
60{
61 /** Pointer back to the device instance. */
62 PPDMDEVINS pDevIns;
63 /** EFI message buffer. */
64 char szMsg[VBOX_EFI_DEBUG_BUFFER];
65 /** EFI message buffer index. */
66 uint32_t iMsg;
67 /** EFI panic message buffer. */
68 char szPanicMsg[2048];
69 /** EFI panic message buffer index. */
70 uint32_t iPanicMsg;
71 /** The system EFI ROM data. */
72 uint8_t *pu8EfiRom;
73 /** The size of the system EFI ROM. */
74 uint64_t cbEfiRom;
75 /** The name of the EFI ROM file. */
76 char *pszEfiRomFile;
77 /** Thunk page pointer. */
78 uint8_t *pu8EfiThunk;
79 /** First entry point of the EFI firmware */
80 RTGCPHYS GCEntryPoint0;
81 /* Second Entry Point (PeiCore)*/
82 RTGCPHYS GCEntryPoint1;
83 /** EFI firmware physical load address */
84 RTGCPHYS GCLoadAddress;
85 /** Current info selector */
86 uint32_t iInfoSelector;
87 /** Current info position */
88 int32_t iInfoPosition;
89
90 /** Number of virtual CPUs. (Config) */
91 uint32_t cCpus;
92 /** RAM below 4GB (in bytes). (Config) */
93 uint32_t cbBelow4GB;
94 /** RAM above 4GB (in bytes). (Config) */
95 uint64_t cbAbove4GB;
96
97 uint64_t cbRam;
98
99 uint64_t cbRamHole;
100
101 /** The DMI tables. */
102 uint8_t au8DMIPage[0x1000];
103
104 /** I/O-APIC enabled? */
105 uint8_t u8IOAPIC;
106
107 /* Boot parameters passed to the firmware */
108 char szBootArgs[256];
109
110 /* Host UUID (for DMI) */
111 RTUUID aUuid;
112
113 /* Device properties buffer */
114 uint8_t* pu8DeviceProps;
115 /* Device properties buffer size */
116 uint32_t u32DevicePropsLen;
117
118 /* Virtual machine front side bus frequency */
119 uint64_t u64FsbFrequency;
120 /* Virtual machine time stamp counter frequency */
121 uint64_t u64TscFrequency;
122 /* Virtual machine CPU frequency */
123 uint64_t u64CpuFrequency;
124 /* GOP mode */
125 uint32_t u32GopMode;
126 /* Uga mode resolutions */
127 uint32_t u32UgaHorisontal;
128 uint32_t u32UgaVertical;
129} DEVEFI;
130typedef DEVEFI *PDEVEFI;
131
132/**
133 * Write to CMOS memory.
134 * This is used by the init complete code.
135 */
136static void cmosWrite(PPDMDEVINS pDevIns, int off, uint32_t u32Val)
137{
138 Assert(off < 128);
139 Assert(u32Val < 256);
140
141 int rc = PDMDevHlpCMOSWrite(pDevIns, off, u32Val);
142 AssertRC(rc);
143}
144
145
146static uint32_t efiInfoSize(PDEVEFI pThis)
147{
148 switch (pThis->iInfoSelector)
149 {
150 case EFI_INFO_INDEX_VOLUME_BASE:
151 case EFI_INFO_INDEX_VOLUME_SIZE:
152 case EFI_INFO_INDEX_TEMPMEM_BASE:
153 case EFI_INFO_INDEX_TEMPMEM_SIZE:
154 case EFI_INFO_INDEX_STACK_BASE:
155 case EFI_INFO_INDEX_STACK_SIZE:
156 case EFI_INFO_INDEX_GOP_MODE:
157 case EFI_INFO_INDEX_UGA_VERTICAL_RESOLUTION:
158 case EFI_INFO_INDEX_UGA_HORISONTAL_RESOLUTION:
159 return 4;
160 case EFI_INFO_INDEX_BOOT_ARGS:
161 return (uint32_t)RTStrNLen(pThis->szBootArgs,
162 sizeof pThis->szBootArgs) + 1;
163 case EFI_INFO_INDEX_DEVICE_PROPS:
164 return pThis->u32DevicePropsLen;
165 case EFI_INFO_INDEX_FSB_FREQUENCY:
166 case EFI_INFO_INDEX_CPU_FREQUENCY:
167 case EFI_INFO_INDEX_TSC_FREQUENCY:
168 return 8;
169 }
170 Assert(false);
171 return 0;
172}
173
174static uint8_t efiInfoNextByte(PDEVEFI pThis)
175{
176 union
177 {
178 uint32_t u32;
179 uint64_t u64;
180 } value;
181
182 switch (pThis->iInfoSelector)
183 {
184 case EFI_INFO_INDEX_VOLUME_BASE:
185 value.u32 = pThis->GCLoadAddress;
186 break;
187 case EFI_INFO_INDEX_VOLUME_SIZE:
188 value.u32 = pThis->cbEfiRom;
189 break;
190 case EFI_INFO_INDEX_TEMPMEM_BASE:
191 value.u32 = VBOX_EFI_TOP_OF_STACK; /* just after stack */
192 break;
193 case EFI_INFO_INDEX_TEMPMEM_SIZE:
194 value.u32 = 512 * 1024; /* 512 K */
195 break;
196 case EFI_INFO_INDEX_STACK_BASE:
197 /* Keep in sync with value in EfiThunk.asm */
198 value.u32 = VBOX_EFI_TOP_OF_STACK - 128*1024; /* 2M - 128 K */
199 break;
200 case EFI_INFO_INDEX_STACK_SIZE:
201 value.u32 = 128*1024; /* 128 K */
202 break;
203 case EFI_INFO_INDEX_FSB_FREQUENCY:
204 value.u64 = pThis->u64FsbFrequency;
205 break;
206 case EFI_INFO_INDEX_TSC_FREQUENCY:
207 value.u64 = pThis->u64TscFrequency;
208 break;
209 case EFI_INFO_INDEX_CPU_FREQUENCY:
210 value.u64 = pThis->u64CpuFrequency;
211 break;
212 case EFI_INFO_INDEX_BOOT_ARGS:
213 return pThis->szBootArgs[pThis->iInfoPosition];
214 case EFI_INFO_INDEX_DEVICE_PROPS:
215 return pThis->pu8DeviceProps[pThis->iInfoPosition];
216 case EFI_INFO_INDEX_GOP_MODE:
217 value.u32 = pThis->u32GopMode;
218 break;
219 case EFI_INFO_INDEX_UGA_HORISONTAL_RESOLUTION:
220 value.u32 = pThis->u32UgaHorisontal;
221 break;
222 case EFI_INFO_INDEX_UGA_VERTICAL_RESOLUTION:
223 value.u32 = pThis->u32UgaVertical;
224 break;
225 default:
226 Assert(false);
227 value.u64 = 0;
228 break;
229 }
230
231 return *((uint8_t*)&value+pThis->iInfoPosition);
232}
233
234/**
235 * Port I/O Handler for IN operations.
236 *
237 * @returns VBox status code.
238 *
239 * @param pDevIns The device instance.
240 * @param pvUser User argument - ignored.
241 * @param Port Port number used for the IN operation.
242 * @param pu32 Where to store the result.
243 * @param cb Number of bytes read.
244 */
245static DECLCALLBACK(int) efiIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
246{
247 PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
248 Log4(("EFI in: %x %x\n", Port, cb));
249
250 switch (Port)
251 {
252 case EFI_INFO_PORT:
253 if (pThis->iInfoPosition == -1 && cb == 4)
254 {
255 *pu32 = efiInfoSize(pThis);
256 pThis->iInfoPosition = 0;
257 }
258 else
259 {
260 /* So far */
261 if (cb != 1)
262 return VERR_IOM_IOPORT_UNUSED;
263 *pu32 = efiInfoNextByte(pThis);
264 pThis->iInfoPosition++;
265 }
266 return VINF_SUCCESS;
267
268 case EFI_PANIC_PORT:
269#ifdef IN_RING3
270 LogRel(("Panic port read!\n"));
271 /* Insert special code here on panic reads */
272 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "EFI Panic: panic port read!\n");
273#else
274 /* Reschedule to R3 */
275 return VINF_IOM_HC_IOPORT_READ;
276#endif
277 }
278
279 return VERR_IOM_IOPORT_UNUSED;
280}
281
282
283/**
284 * Port I/O Handler for OUT operations.
285 *
286 * @returns VBox status code.
287 *
288 * @param pDevIns The device instance.
289 * @param pvUser User argument - ignored.
290 * @param Port Port number used for the IN operation.
291 * @param u32 The value to output.
292 * @param cb The value size in bytes.
293 */
294static DECLCALLBACK(int) efiIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
295{
296 PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
297 Log4(("efi: out %x %x %d\n", Port, u32, cb));
298
299 switch (Port)
300 {
301 case EFI_INFO_PORT:
302 pThis->iInfoSelector = u32;
303 pThis->iInfoPosition = -1;
304 break;
305 case EFI_DEBUG_PORT:
306 {
307 /* The raw version. */
308 switch (u32)
309 {
310 case '\r': Log3(("efi: <return>\n")); break;
311 case '\n': Log3(("efi: <newline>\n")); break;
312 case '\t': Log3(("efi: <tab>\n")); break;
313 default: Log3(("efi: %c (%02x)\n", u32, u32)); break;
314 }
315 /* The readable, buffered version. */
316 if (u32 == '\n' || u32 == '\r')
317 {
318 pThis->szMsg[pThis->iMsg] = '\0';
319 if (pThis->iMsg)
320 {
321 Log(("efi: %s\n", pThis->szMsg));
322#ifdef DEVEFI_WITH_VBOXDBG_SCRIPT
323 const char *pszVBoxDbg = strstr(pThis->szMsg, "VBoxDbg> ");
324 if (pszVBoxDbg)
325 {
326 pszVBoxDbg += sizeof("VBoxDbg> ") - 1;
327
328 PRTSTREAM pStrm;
329 int rc = RTStrmOpen("./DevEFI.VBoxDbg", "a", &pStrm);
330 if (RT_SUCCESS(rc))
331 {
332 RTStrmPutStr(pStrm, pszVBoxDbg);
333 RTStrmPutCh(pStrm, '\n');
334 RTStrmClose(pStrm);
335 }
336 }
337#endif
338 }
339 pThis->iMsg = 0;
340 }
341 else
342 {
343 if (pThis->iMsg >= sizeof(pThis->szMsg)-1)
344 {
345 pThis->szMsg[pThis->iMsg] = '\0';
346 Log(("efi: %s\n", pThis->szMsg));
347 pThis->iMsg = 0;
348 }
349 pThis->szMsg[pThis->iMsg] = (char )u32;
350 pThis->szMsg[++pThis->iMsg] = '\0';
351 }
352 break;
353 }
354
355 case EFI_PANIC_PORT:
356 {
357 switch (u32)
358 {
359 case EFI_PANIC_CMD_BAD_ORG:
360 LogRel(("EFI Panic: You have to fix ORG offset in EfiThunk.asm! Must be 0x%x\n",
361 g_cbEfiThunkBinary));
362 RTAssertMsg2Weak("Fix ORG offset in EfiThunk.asm: must be 0x%x\n",
363 g_cbEfiThunkBinary);
364 break;
365
366 case EFI_PANIC_CMD_THUNK_TRAP:
367 LogRel(("EFI Panic: Unexpected trap!!\n"));
368#ifdef VBOX_STRICT
369 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "EFI Panic: Unexpected trap during early bootstrap!\n");
370#else
371 AssertReleaseMsgFailed(("Unexpected trap during early EFI bootstrap!!\n"));
372#endif
373 break;
374
375 case EFI_PANIC_CMD_START_MSG:
376 pThis->iPanicMsg = 0;
377 pThis->szPanicMsg[0] = '\0';
378 break;
379
380 case EFI_PANIC_CMD_END_MSG:
381 LogRel(("EFI Panic: %s\n", pThis->szPanicMsg));
382#ifdef VBOX_STRICT
383 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "EFI Panic: %s\n", pThis->szPanicMsg);
384#else
385 return VERR_INTERNAL_ERROR;
386#endif
387
388 default:
389 if ( u32 >= EFI_PANIC_CMD_MSG_FIRST
390 && u32 <= EFI_PANIC_CMD_MSG_LAST)
391 {
392 /* Add the message char to the buffer. */
393 uint32_t i = pThis->iPanicMsg;
394 if (i + 1 < sizeof(pThis->szPanicMsg))
395 {
396 char ch = EFI_PANIC_CMD_MSG_GET_CHAR(u32);
397 if ( ch == '\n'
398 && i > 0
399 && pThis->szPanicMsg[i - 1] == '\r')
400 i--;
401 pThis->szPanicMsg[i] = ch;
402 pThis->szPanicMsg[i + 1] = '\0';
403 pThis->iPanicMsg = i + 1;
404 }
405 }
406 else
407 Log(("EFI: Unknown panic command: %#x (cb=%d)\n", u32, cb));
408 break;
409 }
410 break;
411 }
412
413 default:
414 Log(("EFI: Write to reserved port %RTiop: %#x (cb=%d)\n", Port, u32, cb));
415 break;
416 }
417 return VINF_SUCCESS;
418}
419
420/**
421 * Init complete notification.
422 *
423 * @returns VBOX status code.
424 * @param pDevIns The device instance.
425 */
426static DECLCALLBACK(int) efiInitComplete(PPDMDEVINS pDevIns)
427{
428 /* PC Bios */
429 PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
430 uint32_t u32;
431
432 /*
433 * Memory sizes.
434 */
435 uint64_t const offRamHole = _4G - pThis->cbRamHole;
436 if (pThis->cbRam > 16 * _1M)
437 u32 = (uint32_t)( (RT_MIN(RT_MIN(pThis->cbRam, offRamHole), UINT32_C(0xffe00000)) - 16U * _1M) / _64K );
438 else
439 u32 = 0;
440 cmosWrite(pDevIns, 0x34, u32 & 0xff);
441 cmosWrite(pDevIns, 0x35, u32 >> 8);
442
443 /*
444 * Number of CPUs.
445 */
446 cmosWrite(pDevIns, 0x60, pThis->cCpus & 0xff);
447
448 return VINF_SUCCESS;
449}
450
451/**
452 * Reset notification.
453 *
454 * @returns VBox status.
455 * @param pDevIns The device instance data.
456 */
457static DECLCALLBACK(void) efiReset(PPDMDEVINS pDevIns)
458{
459 PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
460 int rc;
461
462 LogFlow(("efiReset\n"));
463
464 pThis->iInfoSelector = 0;
465 pThis->iInfoPosition = -1;
466
467 pThis->iMsg = 0;
468 pThis->szMsg[0] = '\0';
469 pThis->iPanicMsg = 0;
470 pThis->szPanicMsg[0] = '\0';
471
472 /*
473 * Plan some structures in RAM.
474 */
475 FwCommonPlantSmbiosAndDmiHdrs(pDevIns);
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 "DmiExposeMemoryTable\0"
1011 "64BitEntry\0"
1012 "BootArgs\0"
1013 "DeviceProps\0"
1014 "GopMode\0"
1015 "UgaHorizontalResolution\0"
1016 "UgaVerticalResolution\0"
1017 ))
1018 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
1019 N_("Configuration error: Invalid config value(s) for the EFI device"));
1020
1021 /* CPU count (optional). */
1022 rc = CFGMR3QueryU32Def(pCfg, "NumCPUs", &pThis->cCpus, 1);
1023 AssertLogRelRCReturn(rc, rc);
1024
1025 rc = CFGMR3QueryU8Def(pCfg, "IOAPIC", &pThis->u8IOAPIC, 1);
1026 if (RT_FAILURE (rc))
1027 return PDMDEV_SET_ERROR(pDevIns, rc,
1028 N_("Configuration error: Failed to read \"IOAPIC\""));
1029
1030 /*
1031 * Query the machine's UUID for SMBIOS/DMI use.
1032 */
1033 RTUUID uuid;
1034 rc = CFGMR3QueryBytes(pCfg, "UUID", &uuid, sizeof(uuid));
1035 if (RT_FAILURE(rc))
1036 return PDMDEV_SET_ERROR(pDevIns, rc,
1037 N_("Configuration error: Querying \"UUID\" failed"));
1038
1039 /*
1040 * Convert the UUID to network byte order. Not entirely straightforward as
1041 * parts are MSB already...
1042 */
1043 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
1044 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
1045 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
1046 memcpy(&pThis->aUuid, &uuid, sizeof pThis->aUuid);
1047
1048
1049 /*
1050 * RAM sizes
1051 */
1052 rc = CFGMR3QueryU64(pCfg, "RamSize", &pThis->cbRam);
1053 AssertLogRelRCReturn(rc, rc);
1054 rc = CFGMR3QueryU64(pCfg, "RamHoleSize", &pThis->cbRamHole);
1055 AssertLogRelRCReturn(rc, rc);
1056 pThis->cbBelow4GB = RT_MIN(pThis->cbRam, _4G - pThis->cbRamHole);
1057 pThis->cbAbove4GB = pThis->cbRam - pThis->cbBelow4GB;
1058
1059 /*
1060 * Get the system EFI ROM file name.
1061 */
1062 rc = CFGMR3QueryStringAlloc(pCfg, "EfiRom", &pThis->pszEfiRomFile);
1063 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1064 {
1065 pThis->pszEfiRomFile = (char *)PDMDevHlpMMHeapAlloc(pDevIns, RTPATH_MAX);
1066 if (!pThis->pszEfiRomFile)
1067 return VERR_NO_MEMORY;
1068
1069 rc = RTPathAppPrivateArch(pThis->pszEfiRomFile, RTPATH_MAX);
1070 AssertRCReturn(rc, rc);
1071 rc = RTPathAppend(pThis->pszEfiRomFile, RTPATH_MAX, "VBoxEFI32.fd");
1072 AssertRCReturn(rc, rc);
1073 }
1074 else if (RT_FAILURE(rc))
1075 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1076 N_("Configuration error: Querying \"EfiRom\" as a string failed"));
1077 else if (!*pThis->pszEfiRomFile)
1078 {
1079 MMR3HeapFree(pThis->pszEfiRomFile);
1080 pThis->pszEfiRomFile = NULL;
1081 }
1082
1083 /*
1084 * Get boot args.
1085 */
1086 rc = CFGMR3QueryString(pCfg, "BootArgs",
1087 pThis->szBootArgs, sizeof pThis->szBootArgs);
1088 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1089 {
1090 strcpy(pThis->szBootArgs, "");
1091 rc = VINF_SUCCESS;
1092 }
1093 if (RT_FAILURE(rc))
1094 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1095 N_("Configuration error: Querying \"BootArgs\" as a string failed"));
1096
1097 LogRel(("EFI boot args: %s\n", pThis->szBootArgs));
1098
1099 /*
1100 * Get device props.
1101 */
1102 char* pszDeviceProps;
1103 rc = CFGMR3QueryStringAlloc(pCfg, "DeviceProps", &pszDeviceProps);
1104 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1105 {
1106 pszDeviceProps = NULL;
1107 rc = VINF_SUCCESS;
1108 }
1109 if (RT_FAILURE(rc))
1110 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1111 N_("Configuration error: Querying \"DeviceProps\" as a string failed"));
1112 if (pszDeviceProps)
1113 {
1114 LogRel(("EFI device props: %s\n", pszDeviceProps));
1115 rc = efiParseDeviceString(pThis, pszDeviceProps);
1116 MMR3HeapFree(pszDeviceProps);
1117 if (RT_FAILURE(rc))
1118 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1119 N_("Configuration error: Cannot parse device properties"));
1120 }
1121 else
1122 {
1123 pThis->pu8DeviceProps = NULL;
1124 pThis->u32DevicePropsLen = 0;
1125 }
1126
1127 /*
1128 * CPU frequencies
1129 */
1130 // @todo: we need to have VMM API to access TSC increase speed, for now provide reasonable default
1131 pThis->u64TscFrequency = RTMpGetMaxFrequency(0) * 1024 * 1024;// TMCpuTicksPerSecond(PDMDevHlpGetVM(pDevIns));
1132 if (pThis->u64TscFrequency == 0)
1133 pThis->u64TscFrequency = UINT64_C(2500000000);
1134 /* Multiplier is read from MSR_IA32_PERF_STATUS, and now is hardcoded as 4 */
1135 pThis->u64FsbFrequency = pThis->u64TscFrequency / 4;
1136 pThis->u64CpuFrequency = pThis->u64TscFrequency;
1137
1138 /*
1139 * GOP graphics
1140 */
1141 rc = CFGMR3QueryU32(pCfg, "GopMode", &pThis->u32GopMode);
1142 AssertRC(rc);
1143 if (pThis->u32GopMode == UINT32_MAX)
1144 {
1145 pThis->u32GopMode = 2; /* 1024x768 */
1146 }
1147
1148 /*
1149 * Uga graphics
1150 */
1151 rc = CFGMR3QueryU32(pCfg, "UgaHorizontalResolution", &pThis->u32UgaHorisontal);
1152 AssertRC(rc);
1153 if (pThis->u32UgaHorisontal == 0)
1154 {
1155 pThis->u32UgaHorisontal = 1024; /* 1024x768 */
1156 }
1157 rc = CFGMR3QueryU32(pCfg, "UgaVerticalResolution", &pThis->u32UgaVertical);
1158 AssertRC(rc);
1159 if (pThis->u32UgaVertical == 0)
1160 {
1161 pThis->u32UgaVertical = 768; /* 1024x768 */
1162 }
1163
1164#ifdef DEVEFI_WITH_VBOXDBG_SCRIPT
1165 /*
1166 * Zap the debugger script
1167 */
1168 RTFileDelete("./DevEFI.VBoxDbg");
1169#endif
1170
1171 /*
1172 * Load firmware volume and thunk ROM.
1173 */
1174 rc = efiLoadRom(pThis, pCfg);
1175 if (RT_FAILURE(rc))
1176 return rc;
1177
1178 rc = efiLoadThunk(pThis, pCfg);
1179 if (RT_FAILURE(rc))
1180 return rc;
1181
1182 /*
1183 * Register our communication ports.
1184 */
1185 rc = PDMDevHlpIOPortRegister(pDevIns, EFI_PORT_BASE, EFI_PORT_COUNT, NULL,
1186 efiIOPortWrite, efiIOPortRead,
1187 NULL, NULL, "EFI communication ports");
1188 if (RT_FAILURE(rc))
1189 return rc;
1190
1191 /*
1192 * Plant DMI and MPS tables
1193 */
1194 rc = FwCommonPlantDMITable(pDevIns,
1195 pThis->au8DMIPage,
1196 VBOX_DMI_TABLE_SIZE,
1197 &pThis->aUuid,
1198 pDevIns->pCfg);
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