VirtualBox

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

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

EFI,Main: managing graphic modes via VBoxInternal2 extradata variables.

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

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