VirtualBox

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

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

EFI: dbg break on panic port read

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