VirtualBox

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

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

DevPcBios: always copy the BIOS to RAM and patch the DMI table field length after planting the DMI table

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette