VirtualBox

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

Last change on this file since 91645 was 91329, checked in by vboxsync, 3 years ago

Devices/DevEFI: Use the new NVRAM storage interface if it is available, bugref:10098

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 67.2 KB
Line 
1/* $Id: DevEFI.cpp 91329 2021-09-22 15:16:12Z vboxsync $ */
2/** @file
3 * DevEFI - EFI <-> VirtualBox Integration Framework.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DEV_EFI
23
24#include <VBox/vmm/pdmdev.h>
25#include <VBox/vmm/pgm.h>
26#include <VBox/vmm/cpum.h>
27#include <VBox/vmm/mm.h>
28#include <VBox/log.h>
29#include <VBox/err.h>
30#include <VBox/param.h>
31#include <VBox/vmm/dbgf.h>
32
33#include <iprt/asm.h>
34#include <iprt/assert.h>
35#include <iprt/ctype.h>
36#include <iprt/file.h>
37#include <iprt/mem.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#include <iprt/list.h>
44#if defined(DEBUG) && defined(IN_RING3)
45# include <iprt/stream.h>
46# define DEVEFI_WITH_VBOXDBG_SCRIPT
47#endif
48#include <iprt/utf16.h>
49
50#include "DevEFI.h"
51#include "FlashCore.h"
52#include "VBoxDD.h"
53#include "VBoxDD2.h"
54#include "../PC/DevFwCommon.h"
55
56/* EFI includes */
57#ifdef IN_RING3
58# ifdef _MSC_VER
59# pragma warning(push)
60# pragma warning(disable:4668)
61# endif
62# include <ProcessorBind.h>
63# ifdef _MSC_VER
64# pragma warning(pop)
65# endif
66# include <Common/UefiBaseTypes.h>
67# include <Common/PiFirmwareVolume.h>
68# include <Common/PiFirmwareFile.h>
69#endif
70
71
72/*********************************************************************************************************************************
73* Structures and Typedefs *
74*********************************************************************************************************************************/
75/**
76 * The EFI device shared state structure.
77 */
78typedef struct DEVEFI
79{
80 /** The flash device containing the NVRAM. */
81 FLASHCORE Flash;
82 /** The 8 I/O ports at 0xEF10 (EFI_PORT_BASE). */
83 IOMIOPORTHANDLE hIoPorts;
84 /** The flash MMIO handle. */
85 IOMMMIOHANDLE hMmioFlash;
86} DEVEFI;
87/** Pointer to the shared EFI state. */
88typedef DEVEFI *PDEVEFI;
89
90/**
91 * The EFI device state structure for ring-3.
92 */
93typedef struct DEVEFIR3
94{
95 /** Pointer back to the device instance. */
96 PPDMDEVINS pDevIns;
97
98 /** EFI message buffer. */
99 char szMsg[VBOX_EFI_DEBUG_BUFFER];
100 /** EFI message buffer index. */
101 uint32_t iMsg;
102
103 /** EFI panic message buffer. */
104 char szPanicMsg[2048];
105 /** EFI panic message buffer index. */
106 uint32_t iPanicMsg;
107
108 struct
109 {
110 /** The current/last image event. */
111 uint8_t uEvt;
112 /** Module path/name offset. */
113 uint8_t offName;
114 /** The offset of the last component in the module path/name. */
115 uint8_t offNameLastComponent;
116 /** Alignment padding. */
117 uint8_t abPadding[5];
118 /** First address associated with the event (image address). */
119 uint64_t uAddr0;
120 /** Second address associated with the event (old image address). */
121 uint64_t uAddr1;
122 /** The size associated with the event (0 if none). */
123 uint64_t cb0;
124 /** The module name. */
125 char szName[256];
126 } ImageEvt;
127
128 /** The system EFI ROM data. */
129 uint8_t const *pu8EfiRom;
130 /** The system EFI ROM data pointer to be passed to RTFileReadAllFree. */
131 uint8_t *pu8EfiRomFree;
132 /** The size of the system EFI ROM. */
133 uint64_t cbEfiRom;
134 /** Offset into the actual ROM within EFI FW volume. */
135 uint64_t offEfiRom;
136 /** The name of the EFI ROM file. */
137 char *pszEfiRomFile;
138 /** Thunk page pointer. */
139 uint8_t *pu8EfiThunk;
140 /** First entry point of the EFI firmware. */
141 RTGCPHYS GCEntryPoint0;
142 /** Second Entry Point (PeiCore)*/
143 RTGCPHYS GCEntryPoint1;
144 /** EFI firmware physical load address. */
145 RTGCPHYS GCLoadAddress;
146 /** Current info selector. */
147 uint32_t iInfoSelector;
148 /** Current info position. */
149 int32_t offInfo;
150
151 /** Number of virtual CPUs. (Config) */
152 uint32_t cCpus;
153
154 /** The size of the DMI tables. */
155 uint16_t cbDmiTables;
156 /** Number of the DMI tables. */
157 uint16_t cNumDmiTables;
158 /** The DMI tables. */
159 uint8_t au8DMIPage[0x1000];
160
161 /** I/O-APIC enabled? */
162 uint8_t u8IOAPIC;
163
164 /** APIC mode to be set up by firmware. */
165 uint8_t u8APIC;
166
167 /** Boot parameters passed to the firmware. */
168 char szBootArgs[256];
169
170 /** Host UUID (for DMI). */
171 RTUUID aUuid;
172
173 /** Device properties buffer. */
174 R3PTRTYPE(uint8_t *) pbDeviceProps;
175 /** Device properties buffer size. */
176 uint32_t cbDeviceProps;
177
178 /** Virtual machine front side bus frequency. */
179 uint64_t u64FsbFrequency;
180 /** Virtual machine time stamp counter frequency. */
181 uint64_t u64TscFrequency;
182 /** Virtual machine CPU frequency. */
183 uint64_t u64CpuFrequency;
184 /** EFI Graphics mode (used as fallback if resolution is not known). */
185 uint32_t u32GraphicsMode;
186 /** EFI Graphics (GOP or UGA) horizontal resolution. */
187 uint32_t u32HorizontalResolution;
188 /** EFI Graphics (GOP or UGA) vertical resolution. */
189 uint32_t u32VerticalResolution;
190 /** Physical address of PCI config space MMIO region */
191 uint64_t u64McfgBase;
192 /** Length of PCI config space MMIO region */
193 uint64_t cbMcfgLength;
194 /** Size of the configured NVRAM device. */
195 uint32_t cbNvram;
196 /** Start address of the NVRAM flash. */
197 RTGCPHYS GCPhysNvram;
198
199 /** Filename of the file containing the NVRAM store. */
200 char *pszNvramFile;
201
202 /**
203 * NVRAM port - LUN\#0.
204 */
205 struct
206 {
207 /** The base interface we provide the NVRAM driver. */
208 PDMIBASE IBase;
209 /** The NVRAM driver base interface. */
210 PPDMIBASE pDrvBase;
211 /** The VFS interface of the driver below for NVRAM state loading and storing. */
212 PPDMIVFSCONNECTOR pDrvVfs;
213 } Lun0;
214} DEVEFIR3;
215/** Pointer to the ring-3 EFI state. */
216typedef DEVEFIR3 *PDEVEFIR3;
217
218
219/**
220 * The EFI device state structure for ring-0.
221 */
222typedef struct DEVEFIR0
223{
224 uint32_t uEmpty;
225} DEVEFIR0;
226/** Pointer to the ring-0 EFI state. */
227typedef DEVEFIR0 *PDEVEFIR0;
228
229
230/**
231 * The EFI device state structure for raw-mode.
232 */
233typedef struct DEVEFIRC
234{
235 uint32_t uEmpty;
236} DEVEFIRC;
237/** Pointer to the raw-mode EFI state. */
238typedef DEVEFIRC *PDEVEFIRC;
239
240
241/** @typedef DEVEFICC
242 * The instance data for the current context. */
243/** @typedef PDEVEFICC
244 * Pointer to the instance data for the current context. */
245#ifdef IN_RING3
246typedef DEVEFIR3 DEVEFICC;
247typedef PDEVEFIR3 PDEVEFICC;
248#elif defined(IN_RING0)
249typedef DEVEFIR0 DEVEFICC;
250typedef PDEVEFIR0 PDEVEFICC;
251#elif defined(IN_RC)
252typedef DEVEFIRC DEVEFICC;
253typedef PDEVEFIRC PDEVEFICC;
254#else
255# error "Not IN_RING3, IN_RING0 or IN_RC"
256#endif
257
258
259/*********************************************************************************************************************************
260* Defined Constants And Macros *
261*********************************************************************************************************************************/
262/** The saved state version. */
263#define EFI_SSM_VERSION 3
264/** The saved state version before working NVRAM support was implemented. */
265#define EFI_SSM_VERSION_PRE_PROPER_NVRAM 2
266/** The saved state version from VBox 4.2. */
267#define EFI_SSM_VERSION_4_2 1
268
269/** Non-volatile EFI variable. */
270#define VBOX_EFI_VARIABLE_NON_VOLATILE UINT32_C(0x00000001)
271/** Non-volatile EFI variable. */
272#define VBOX_EFI_VARIABLE_READ_ONLY UINT32_C(0x00000008)
273
274
275/*********************************************************************************************************************************
276* Global Variables *
277*********************************************************************************************************************************/
278#ifdef IN_RING3
279/** The EfiSystemNvDataFv GUID for NVRAM storage. */
280static const RTUUID g_UuidNvDataFv = { { 0x8d, 0x2b, 0xf1, 0xff, 0x96, 0x76, 0x8b, 0x4c, 0xa9, 0x85, 0x27, 0x47, 0x07, 0x5b, 0x4f, 0x50} };
281
282# ifdef VBOX_WITH_EFI_IN_DD2
283/** Special file name value for indicating the 32-bit built-in EFI firmware. */
284static const char g_szEfiBuiltin32[] = "VBoxEFI32.fd";
285/** Special file name value for indicating the 64-bit built-in EFI firmware. */
286static const char g_szEfiBuiltin64[] = "VBoxEFI64.fd";
287# endif
288#endif /* IN_RING3 */
289
290
291#ifdef IN_RING3
292
293/**
294 * Gets the info item size.
295 *
296 * @returns Size in bytes, UINT32_MAX on error.
297 * @param pThisCC The EFI state for the current context.
298 */
299static uint32_t efiInfoSize(PDEVEFIR3 pThisCC)
300{
301 switch (pThisCC->iInfoSelector)
302 {
303 case EFI_INFO_INDEX_VOLUME_BASE:
304 case EFI_INFO_INDEX_VOLUME_SIZE:
305 case EFI_INFO_INDEX_TEMPMEM_BASE:
306 case EFI_INFO_INDEX_TEMPMEM_SIZE:
307 case EFI_INFO_INDEX_STACK_BASE:
308 case EFI_INFO_INDEX_STACK_SIZE:
309 case EFI_INFO_INDEX_GRAPHICS_MODE:
310 case EFI_INFO_INDEX_VERTICAL_RESOLUTION:
311 case EFI_INFO_INDEX_HORIZONTAL_RESOLUTION:
312 return 4;
313 case EFI_INFO_INDEX_BOOT_ARGS:
314 return (uint32_t)RTStrNLen(pThisCC->szBootArgs, sizeof(pThisCC->szBootArgs)) + 1;
315 case EFI_INFO_INDEX_DEVICE_PROPS:
316 return pThisCC->cbDeviceProps;
317 case EFI_INFO_INDEX_FSB_FREQUENCY:
318 case EFI_INFO_INDEX_CPU_FREQUENCY:
319 case EFI_INFO_INDEX_TSC_FREQUENCY:
320 case EFI_INFO_INDEX_MCFG_BASE:
321 case EFI_INFO_INDEX_MCFG_SIZE:
322 return 8;
323 case EFI_INFO_INDEX_APIC_MODE:
324 return 1;
325 }
326 return UINT32_MAX;
327}
328
329
330/**
331 * efiInfoNextByte for a uint8_t value.
332 *
333 * @returns Next (current) byte.
334 * @param pThisCC The EFI state for the current context.
335 * @param u8 The value.
336 */
337static uint8_t efiInfoNextByteU8(PDEVEFIR3 pThisCC, uint8_t u8)
338{
339 uint32_t off = pThisCC->offInfo;
340 if (off >= 1)
341 return 0;
342 return (uint8_t)u8;
343}
344
345
346/**
347 * efiInfoNextByte for a uint64_t value.
348 *
349 * @returns Next (current) byte.
350 * @param pThisCC The EFI state for the current context.
351 * @param u64 The value.
352 */
353static uint8_t efiInfoNextByteU64(PDEVEFIR3 pThisCC, uint64_t u64)
354{
355 uint64_t off = pThisCC->offInfo;
356 if (off >= 8)
357 return 0;
358 return (uint8_t)(u64 >> (off * 8));
359}
360
361/**
362 * efiInfoNextByte for a uint32_t value.
363 *
364 * @returns Next (current) byte.
365 * @param pThisCC The EFI state for the current context.
366 * @param u32 The value.
367 */
368static uint8_t efiInfoNextByteU32(PDEVEFIR3 pThisCC, uint32_t u32)
369{
370 uint32_t off = pThisCC->offInfo;
371 if (off >= 4)
372 return 0;
373 return (uint8_t)(u32 >> (off * 8));
374}
375
376/**
377 * efiInfoNextByte for a buffer.
378 *
379 * @returns Next (current) byte.
380 * @param pThisCC The EFI state for the current context.
381 * @param pvBuf The buffer.
382 * @param cbBuf The buffer size.
383 */
384static uint8_t efiInfoNextByteBuf(PDEVEFIR3 pThisCC, void const *pvBuf, size_t cbBuf)
385{
386 uint32_t off = pThisCC->offInfo;
387 if (off >= cbBuf)
388 return 0;
389 return ((uint8_t const *)pvBuf)[off];
390}
391
392/**
393 * Gets the next info byte.
394 *
395 * @returns Next (current) byte.
396 * @param pThisCC The EFI state for the current context.
397 */
398static uint8_t efiInfoNextByte(PDEVEFIR3 pThisCC)
399{
400 switch (pThisCC->iInfoSelector)
401 {
402
403 case EFI_INFO_INDEX_VOLUME_BASE: return efiInfoNextByteU64(pThisCC, pThisCC->GCLoadAddress);
404 case EFI_INFO_INDEX_VOLUME_SIZE: return efiInfoNextByteU64(pThisCC, pThisCC->cbEfiRom);
405 case EFI_INFO_INDEX_TEMPMEM_BASE: return efiInfoNextByteU32(pThisCC, VBOX_EFI_TOP_OF_STACK); /* just after stack */
406 case EFI_INFO_INDEX_TEMPMEM_SIZE: return efiInfoNextByteU32(pThisCC, _512K);
407 case EFI_INFO_INDEX_FSB_FREQUENCY: return efiInfoNextByteU64(pThisCC, pThisCC->u64FsbFrequency);
408 case EFI_INFO_INDEX_TSC_FREQUENCY: return efiInfoNextByteU64(pThisCC, pThisCC->u64TscFrequency);
409 case EFI_INFO_INDEX_CPU_FREQUENCY: return efiInfoNextByteU64(pThisCC, pThisCC->u64CpuFrequency);
410 case EFI_INFO_INDEX_BOOT_ARGS: return efiInfoNextByteBuf(pThisCC, pThisCC->szBootArgs, sizeof(pThisCC->szBootArgs));
411 case EFI_INFO_INDEX_DEVICE_PROPS: return efiInfoNextByteBuf(pThisCC, pThisCC->pbDeviceProps, pThisCC->cbDeviceProps);
412 case EFI_INFO_INDEX_GRAPHICS_MODE: return efiInfoNextByteU32(pThisCC, pThisCC->u32GraphicsMode);
413 case EFI_INFO_INDEX_HORIZONTAL_RESOLUTION: return efiInfoNextByteU32(pThisCC, pThisCC->u32HorizontalResolution);
414 case EFI_INFO_INDEX_VERTICAL_RESOLUTION: return efiInfoNextByteU32(pThisCC, pThisCC->u32VerticalResolution);
415
416 /* Keep in sync with value in EfiThunk.asm */
417 case EFI_INFO_INDEX_STACK_BASE: return efiInfoNextByteU32(pThisCC, VBOX_EFI_TOP_OF_STACK - _128K); /* 2M - 128 K */
418 case EFI_INFO_INDEX_STACK_SIZE: return efiInfoNextByteU32(pThisCC, _128K);
419 case EFI_INFO_INDEX_MCFG_BASE: return efiInfoNextByteU64(pThisCC, pThisCC->u64McfgBase);
420 case EFI_INFO_INDEX_MCFG_SIZE: return efiInfoNextByteU64(pThisCC, pThisCC->cbMcfgLength);
421 case EFI_INFO_INDEX_APIC_MODE: return efiInfoNextByteU8(pThisCC, pThisCC->u8APIC);
422
423 default:
424 PDMDevHlpDBGFStop(pThisCC->pDevIns, RT_SRC_POS, "%#x", pThisCC->iInfoSelector);
425 return 0;
426 }
427}
428
429
430#ifdef IN_RING3
431static void efiVBoxDbgScript(const char *pszFormat, ...)
432{
433# ifdef DEVEFI_WITH_VBOXDBG_SCRIPT
434 PRTSTREAM pStrm;
435 int rc2 = RTStrmOpen("./DevEFI.VBoxDbg", "a", &pStrm);
436 if (RT_SUCCESS(rc2))
437 {
438 va_list va;
439 va_start(va, pszFormat);
440 RTStrmPrintfV(pStrm, pszFormat, va);
441 va_end(va);
442 RTStrmClose(pStrm);
443 }
444# else
445 RT_NOREF(pszFormat);
446# endif
447}
448#endif /* IN_RING3 */
449
450
451/**
452 * Handles writes to the image event port.
453 *
454 * @returns VBox status suitable for I/O port write handler.
455 *
456 * @param pThisCC The EFI state for the current context.
457 * @param u32 The value being written.
458 * @param cb The size of the value.
459 */
460static int efiPortImageEventWrite(PDEVEFIR3 pThisCC, uint32_t u32, unsigned cb)
461{
462 RT_NOREF(cb);
463 switch (u32 & EFI_IMAGE_EVT_CMD_MASK)
464 {
465 case EFI_IMAGE_EVT_CMD_START_LOAD32:
466 case EFI_IMAGE_EVT_CMD_START_LOAD64:
467 case EFI_IMAGE_EVT_CMD_START_UNLOAD32:
468 case EFI_IMAGE_EVT_CMD_START_UNLOAD64:
469 case EFI_IMAGE_EVT_CMD_START_RELOC32:
470 case EFI_IMAGE_EVT_CMD_START_RELOC64:
471 AssertBreak(EFI_IMAGE_EVT_GET_PAYLOAD(u32) == 0);
472
473 /* Reset the state. */
474 RT_ZERO(pThisCC->ImageEvt);
475 pThisCC->ImageEvt.uEvt = (uint8_t)u32; Assert(pThisCC->ImageEvt.uEvt == u32);
476 return VINF_SUCCESS;
477
478 case EFI_IMAGE_EVT_CMD_COMPLETE:
479 {
480# ifdef IN_RING3
481 AssertBreak(EFI_IMAGE_EVT_GET_PAYLOAD(u32) == 0);
482
483 /* For now, just log it. */
484 static uint64_t s_cImageEvtLogged = 0;
485 if (s_cImageEvtLogged < 2048)
486 {
487 s_cImageEvtLogged++;
488 switch (pThisCC->ImageEvt.uEvt)
489 {
490 /* ASSUMES the name ends with .pdb and the image file ends with .efi! */
491 case EFI_IMAGE_EVT_CMD_START_LOAD32:
492 LogRel(("EFI: VBoxDbg> loadimage32 '%.*s.efi' %#llx LB %#llx\n",
493 pThisCC->ImageEvt.offName - 4, pThisCC->ImageEvt.szName, pThisCC->ImageEvt.uAddr0, pThisCC->ImageEvt.cb0));
494 if (pThisCC->ImageEvt.offName > 4)
495 efiVBoxDbgScript("loadimage32 '%.*s.efi' %#llx\n",
496 pThisCC->ImageEvt.offName - 4, pThisCC->ImageEvt.szName, pThisCC->ImageEvt.uAddr0);
497 break;
498 case EFI_IMAGE_EVT_CMD_START_LOAD64:
499 LogRel(("EFI: VBoxDbg> loadimage64 '%.*s.efi' %#llx LB %#llx\n",
500 pThisCC->ImageEvt.offName - 4, pThisCC->ImageEvt.szName, pThisCC->ImageEvt.uAddr0, pThisCC->ImageEvt.cb0));
501 if (pThisCC->ImageEvt.offName > 4)
502 efiVBoxDbgScript("loadimage64 '%.*s.efi' %#llx\n",
503 pThisCC->ImageEvt.offName - 4, pThisCC->ImageEvt.szName, pThisCC->ImageEvt.uAddr0);
504 break;
505 case EFI_IMAGE_EVT_CMD_START_UNLOAD32:
506 case EFI_IMAGE_EVT_CMD_START_UNLOAD64:
507 {
508 LogRel(("EFI: VBoxDbg> unload '%.*s.efi' # %#llx LB %#llx\n",
509 pThisCC->ImageEvt.offName - 4 - pThisCC->ImageEvt.offNameLastComponent,
510 &pThisCC->ImageEvt.szName[pThisCC->ImageEvt.offNameLastComponent],
511 pThisCC->ImageEvt.uAddr0, pThisCC->ImageEvt.cb0));
512 if (pThisCC->ImageEvt.offName > 4)
513 efiVBoxDbgScript("unload '%.*s.efi'\n",
514 pThisCC->ImageEvt.offName - 4 - pThisCC->ImageEvt.offNameLastComponent,
515 &pThisCC->ImageEvt.szName[pThisCC->ImageEvt.offNameLastComponent]);
516 break;
517 }
518 case EFI_IMAGE_EVT_CMD_START_RELOC32:
519 case EFI_IMAGE_EVT_CMD_START_RELOC64:
520 {
521 LogRel(("EFI: relocate module to %#llx from %#llx\n",
522 pThisCC->ImageEvt.uAddr0, pThisCC->ImageEvt.uAddr1));
523 break;
524 }
525 }
526 }
527 return VINF_SUCCESS;
528# else
529 return VINF_IOM_R3_IOPORT_WRITE;
530# endif
531 }
532
533 case EFI_IMAGE_EVT_CMD_ADDR0:
534 AssertBreak(EFI_IMAGE_EVT_GET_PAYLOAD(u32) <= UINT16_MAX);
535 pThisCC->ImageEvt.uAddr0 <<= 16;
536 pThisCC->ImageEvt.uAddr0 |= EFI_IMAGE_EVT_GET_PAYLOAD_U16(u32);
537 return VINF_SUCCESS;
538
539 case EFI_IMAGE_EVT_CMD_ADDR1:
540 AssertBreak(EFI_IMAGE_EVT_GET_PAYLOAD(u32) <= UINT16_MAX);
541 pThisCC->ImageEvt.uAddr1 <<= 16;
542 pThisCC->ImageEvt.uAddr1 |= EFI_IMAGE_EVT_GET_PAYLOAD_U16(u32);
543 return VINF_SUCCESS;
544
545 case EFI_IMAGE_EVT_CMD_SIZE0:
546 AssertBreak(EFI_IMAGE_EVT_GET_PAYLOAD(u32) <= UINT16_MAX);
547 pThisCC->ImageEvt.cb0 <<= 16;
548 pThisCC->ImageEvt.cb0 |= EFI_IMAGE_EVT_GET_PAYLOAD_U16(u32);
549 return VINF_SUCCESS;
550
551 case EFI_IMAGE_EVT_CMD_NAME:
552 AssertBreak(EFI_IMAGE_EVT_GET_PAYLOAD(u32) <= 0x7f);
553 if (pThisCC->ImageEvt.offName < sizeof(pThisCC->ImageEvt.szName) - 1)
554 {
555 char ch = EFI_IMAGE_EVT_GET_PAYLOAD_U8(u32);
556 if (ch == '\\')
557 ch = '/';
558 pThisCC->ImageEvt.szName[pThisCC->ImageEvt.offName++] = ch;
559 if (ch == '/' || ch == ':')
560 pThisCC->ImageEvt.offNameLastComponent = pThisCC->ImageEvt.offName;
561 }
562 else
563 Log(("EFI: Image name overflow\n"));
564 return VINF_SUCCESS;
565 }
566
567 Log(("EFI: Unknown image event: %#x (cb=%d)\n", u32, cb));
568 return VINF_SUCCESS;
569}
570
571
572/**
573 * @callback_method_impl{FNIOMIOPORTNEWIN}
574 *
575 * @note The @a offPort parameter is absolute!
576 */
577static DECLCALLBACK(VBOXSTRICTRC) efiR3IoPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
578{
579 RT_NOREF(pvUser);
580 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
581 Log4(("EFI in: %x %x\n", offPort, cb));
582
583 switch (offPort)
584 {
585 case EFI_INFO_PORT:
586 if (pThisCC->offInfo == -1 && cb == 4)
587 {
588 pThisCC->offInfo = 0;
589 uint32_t cbInfo = *pu32 = efiInfoSize(pThisCC);
590 if (cbInfo == UINT32_MAX)
591 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "iInfoSelector=%#x (%d)\n",
592 pThisCC->iInfoSelector, pThisCC->iInfoSelector);
593 }
594 else
595 {
596 if (cb != 1)
597 return VERR_IOM_IOPORT_UNUSED;
598 *pu32 = efiInfoNextByte(pThisCC);
599 pThisCC->offInfo++;
600 }
601 return VINF_SUCCESS;
602
603 case EFI_PANIC_PORT:
604# ifdef IN_RING3
605 LogRel(("EFI panic port read!\n"));
606 /* Insert special code here on panic reads */
607 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "EFI Panic: panic port read!\n");
608# else
609 /* Reschedule to R3 */
610 return VINF_IOM_R3_IOPORT_READ;
611# endif
612
613 case EFI_PORT_VARIABLE_OP: /* Obsolete */
614 case EFI_PORT_VARIABLE_PARAM:
615 case EFI_PORT_DEBUG_POINT:
616 case EFI_PORT_IMAGE_EVENT:
617 *pu32 = UINT32_MAX;
618 return VINF_SUCCESS;
619 }
620
621 return VERR_IOM_IOPORT_UNUSED;
622}
623
624
625/**
626 * Translates a debug point value into a string for logging.
627 *
628 * @returns read-only string
629 * @param enmDbgPoint Valid debug point value.
630 */
631static const char *efiDbgPointName(EFIDBGPOINT enmDbgPoint)
632{
633 switch (enmDbgPoint)
634 {
635 case EFIDBGPOINT_SEC_PREMEM: return "SEC_PREMEM";
636 case EFIDBGPOINT_SEC_POSTMEM: return "SEC_POSTMEM";
637 case EFIDBGPOINT_DXE_CORE: return "DXE_CORE";
638 case EFIDBGPOINT_SMM: return "SMM";
639 case EFIDBGPOINT_SMI_ENTER: return "SMI_ENTER";
640 case EFIDBGPOINT_SMI_EXIT: return "SMI_EXIT";
641 case EFIDBGPOINT_GRAPHICS: return "GRAPHICS";
642 case EFIDBGPOINT_DXE_AP: return "DXE_AP";
643 default:
644 AssertFailed();
645 return "Unknown";
646 }
647}
648
649
650/**
651 * @callback_method_impl{FNIOMIOPORTNEWOUT}
652 *
653 * @note The @a offPort parameter is absolute!
654 */
655static DECLCALLBACK(VBOXSTRICTRC) efiR3IoPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
656{
657 RT_NOREF(pvUser);
658 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
659 VBOXSTRICTRC rc = VINF_SUCCESS;
660 Log4(("efi: out %x %x %d\n", offPort, u32, cb));
661
662 switch (offPort)
663 {
664 case EFI_INFO_PORT:
665 Log2(("EFI_INFO_PORT: iInfoSelector=%#x\n", u32));
666 pThisCC->iInfoSelector = u32;
667 pThisCC->offInfo = -1;
668 break;
669
670 case EFI_DEBUG_PORT:
671 {
672 /* The raw version. */
673 switch (u32)
674 {
675 case '\r': Log3(("efi: <return>\n")); break;
676 case '\n': Log3(("efi: <newline>\n")); break;
677 case '\t': Log3(("efi: <tab>\n")); break;
678 default: Log3(("efi: %c (%02x)\n", u32, u32)); break;
679 }
680 /* The readable, buffered version. */
681 if (u32 == '\n' || u32 == '\r')
682 {
683 Assert(pThisCC->iMsg < sizeof(pThisCC->szMsg));
684 pThisCC->szMsg[pThisCC->iMsg] = '\0';
685 if (pThisCC->iMsg)
686 LogRel2(("efi: %s\n", pThisCC->szMsg));
687 pThisCC->iMsg = 0;
688 }
689 else
690 {
691 if (pThisCC->iMsg >= sizeof(pThisCC->szMsg) - 1)
692 {
693 pThisCC->szMsg[pThisCC->iMsg] = '\0';
694 LogRel2(("efi: %s\n", pThisCC->szMsg));
695 pThisCC->iMsg = 0;
696 }
697 pThisCC->szMsg[pThisCC->iMsg] = (char)u32;
698 pThisCC->szMsg[++pThisCC->iMsg] = '\0';
699 }
700 break;
701 }
702
703 case EFI_PANIC_PORT:
704 {
705 switch (u32)
706 {
707 case EFI_PANIC_CMD_BAD_ORG: /* Legacy */
708 case EFI_PANIC_CMD_THUNK_TRAP:
709#ifdef IN_RING3
710 LogRel(("EFI: Panic! Unexpected trap!!\n"));
711# ifdef VBOX_STRICT
712 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "EFI Panic: Unexpected trap during early bootstrap!\n");
713# else
714 AssertReleaseMsgFailed(("Unexpected trap during early EFI bootstrap!!\n"));
715# endif
716 break;
717#else
718 return VINF_IOM_R3_IOPORT_WRITE;
719#endif
720
721 case EFI_PANIC_CMD_START_MSG:
722 LogRel(("Receiving EFI panic...\n"));
723 pThisCC->iPanicMsg = 0;
724 pThisCC->szPanicMsg[0] = '\0';
725 break;
726
727 case EFI_PANIC_CMD_END_MSG:
728#ifdef IN_RING3
729 LogRel(("EFI: Panic! %s\n", pThisCC->szPanicMsg));
730# ifdef VBOX_STRICT
731 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "EFI Panic: %s\n", pThisCC->szPanicMsg);
732# else
733 return VERR_INTERNAL_ERROR;
734# endif
735#else
736 return VINF_IOM_R3_IOPORT_WRITE;
737#endif
738
739
740 default:
741 if ( u32 >= EFI_PANIC_CMD_MSG_FIRST
742 && u32 <= EFI_PANIC_CMD_MSG_LAST)
743 {
744 /* Add the message char to the buffer. */
745 uint32_t i = pThisCC->iPanicMsg;
746 if (i + 1 < sizeof(pThisCC->szPanicMsg))
747 {
748 char ch = EFI_PANIC_CMD_MSG_GET_CHAR(u32);
749 if ( ch == '\n'
750 && i > 0
751 && pThisCC->szPanicMsg[i - 1] == '\r')
752 i--;
753 pThisCC->szPanicMsg[i] = ch;
754 pThisCC->szPanicMsg[i + 1] = '\0';
755 pThisCC->iPanicMsg = i + 1;
756 }
757 }
758 else
759 Log(("EFI: Unknown panic command: %#x (cb=%d)\n", u32, cb));
760 break;
761 }
762 break;
763 }
764
765 case EFI_PORT_VARIABLE_OP:
766 case EFI_PORT_VARIABLE_PARAM:
767 {
768 /* Ignore access to the obsolete variable handling port. */
769 Log(("EFI: Write to obsolete variable handling port %RTiop: %#x (cb=%d)\n", offPort, u32, cb));
770 break;
771 }
772
773 case EFI_PORT_DEBUG_POINT:
774# ifdef IN_RING3
775 if (u32 > EFIDBGPOINT_INVALID && u32 < EFIDBGPOINT_END)
776 {
777 /* For now, just log it. */
778 LogRelMax(1024, ("EFI: debug point %s\n", efiDbgPointName((EFIDBGPOINT)u32)));
779 rc = VINF_SUCCESS;
780 }
781 else
782 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "Invalid debug point %#x\n", u32);
783 break;
784# else
785 return VINF_IOM_R3_IOPORT_WRITE;
786# endif
787
788 case EFI_PORT_IMAGE_EVENT:
789 rc = efiPortImageEventWrite(pThisCC, u32, cb);
790 break;
791
792 default:
793 Log(("EFI: Write to reserved port %RTiop: %#x (cb=%d)\n", offPort, u32, cb));
794 break;
795 }
796 return rc;
797}
798
799#endif /* IN_RING3 */
800
801/**
802 * @callback_method_impl{FNIOMMMIONEWWRITE, Flash memory write}
803 */
804static DECLCALLBACK(VBOXSTRICTRC) efiR3NvMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
805{
806 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
807 RT_NOREF(pvUser);
808
809 return flashWrite(&pThis->Flash, off, pv, cb);
810}
811
812
813/**
814 * @callback_method_impl{FNIOMMMIONEWREAD, Flash memory read}
815 */
816static DECLCALLBACK(VBOXSTRICTRC) efiR3NvMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
817{
818 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
819 RT_NOREF(pvUser);
820
821 return flashRead(&pThis->Flash, off, pv, cb);
822}
823
824#ifdef IN_RING3
825
826static DECLCALLBACK(int) efiSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
827{
828 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
829 LogFlow(("efiSaveExec:\n"));
830
831 return flashR3SaveExec(&pThis->Flash, pDevIns, pSSM);
832}
833
834static DECLCALLBACK(int) efiLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
835{
836 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
837 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
838 LogFlow(("efiLoadExec: uVersion=%d uPass=%d\n", uVersion, uPass));
839
840 /*
841 * Validate input.
842 */
843 if (uPass != SSM_PASS_FINAL)
844 return VERR_SSM_UNEXPECTED_PASS;
845 if ( uVersion != EFI_SSM_VERSION
846 && uVersion != EFI_SSM_VERSION_PRE_PROPER_NVRAM
847 && uVersion != EFI_SSM_VERSION_4_2
848 )
849 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
850
851 int rc;
852 if (uVersion > EFI_SSM_VERSION_PRE_PROPER_NVRAM)
853 rc = flashR3LoadExec(&pThis->Flash, pDevIns, pSSM);
854 else
855 {
856 /*
857 * Ignore the old NVRAM state.
858 */
859 rc = pHlp->pfnSSMSkipToEndOfUnit(pSSM);
860 }
861
862 return rc;
863}
864
865
866/**
867 * @copydoc(PDMIBASE::pfnQueryInterface)
868 */
869static DECLCALLBACK(void *) devEfiQueryInterface(PPDMIBASE pInterface, const char *pszIID)
870{
871 LogFlowFunc(("ENTER: pIBase=%p pszIID=%p\n", pInterface, pszIID));
872 PDEVEFIR3 pThisCC = RT_FROM_MEMBER(pInterface, DEVEFIR3, Lun0.IBase);
873
874 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->Lun0.IBase);
875 return NULL;
876}
877
878
879/**
880 * Write to CMOS memory.
881 * This is used by the init complete code.
882 */
883static void cmosWrite(PPDMDEVINS pDevIns, unsigned off, uint32_t u32Val)
884{
885 Assert(off < 128);
886 Assert(u32Val < 256);
887
888 int rc = PDMDevHlpCMOSWrite(pDevIns, off, u32Val);
889 AssertRC(rc);
890}
891
892/**
893 * Init complete notification.
894 *
895 * @returns VBOX status code.
896 * @param pDevIns The device instance.
897 */
898static DECLCALLBACK(int) efiInitComplete(PPDMDEVINS pDevIns)
899{
900 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
901
902 PVM pVM = PDMDevHlpGetVM(pDevIns);
903 uint64_t const cbRamSize = MMR3PhysGetRamSize(pVM);
904 uint32_t const cbBelow4GB = MMR3PhysGetRamSizeBelow4GB(pVM);
905 uint64_t const cbAbove4GB = MMR3PhysGetRamSizeAbove4GB(pVM);
906 NOREF(cbAbove4GB);
907
908 /*
909 * Memory sizes.
910 */
911 uint32_t u32Low = 0;
912 uint32_t u32Chunks = 0;
913 if (cbRamSize > 16 * _1M)
914 {
915 u32Low = RT_MIN(cbBelow4GB, UINT32_C(0xfe000000));
916 u32Chunks = (u32Low - 16U * _1M) / _64K;
917 }
918 cmosWrite(pDevIns, 0x34, RT_BYTE1(u32Chunks));
919 cmosWrite(pDevIns, 0x35, RT_BYTE2(u32Chunks));
920
921 if (u32Low < cbRamSize)
922 {
923 uint64_t u64 = cbRamSize - u32Low;
924 u32Chunks = (uint32_t)(u64 / _64K);
925 cmosWrite(pDevIns, 0x5b, RT_BYTE1(u32Chunks));
926 cmosWrite(pDevIns, 0x5c, RT_BYTE2(u32Chunks));
927 cmosWrite(pDevIns, 0x5d, RT_BYTE3(u32Chunks));
928 cmosWrite(pDevIns, 0x5e, RT_BYTE4(u32Chunks));
929 }
930
931 /*
932 * Number of CPUs.
933 */
934 cmosWrite(pDevIns, 0x60, pThisCC->cCpus & 0xff);
935
936 return VINF_SUCCESS;
937}
938
939
940/**
941 * @interface_method_impl{PDMDEVREG,pfnMemSetup}
942 */
943static DECLCALLBACK(void) efiMemSetup(PPDMDEVINS pDevIns, PDMDEVMEMSETUPCTX enmCtx)
944{
945 RT_NOREF(enmCtx);
946 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
947
948 /*
949 * Re-shadow the Firmware Volume and make it RAM/RAM.
950 */
951 uint32_t cPages = RT_ALIGN_64(pThisCC->cbEfiRom, PAGE_SIZE) >> PAGE_SHIFT;
952 RTGCPHYS GCPhys = pThisCC->GCLoadAddress;
953 while (cPages > 0)
954 {
955 uint8_t abPage[PAGE_SIZE];
956
957 /* Read the (original) ROM page and write it back to the RAM page. */
958 int rc = PDMDevHlpROMProtectShadow(pDevIns, GCPhys, PAGE_SIZE, PGMROMPROT_READ_ROM_WRITE_RAM);
959 AssertLogRelRC(rc);
960
961 rc = PDMDevHlpPhysRead(pDevIns, GCPhys, abPage, PAGE_SIZE);
962 AssertLogRelRC(rc);
963 if (RT_FAILURE(rc))
964 memset(abPage, 0xcc, sizeof(abPage));
965
966 rc = PDMDevHlpPhysWrite(pDevIns, GCPhys, abPage, PAGE_SIZE);
967 AssertLogRelRC(rc);
968
969 /* Switch to the RAM/RAM mode. */
970 rc = PDMDevHlpROMProtectShadow(pDevIns, GCPhys, PAGE_SIZE, PGMROMPROT_READ_RAM_WRITE_RAM);
971 AssertLogRelRC(rc);
972
973 /* Advance */
974 GCPhys += PAGE_SIZE;
975 cPages--;
976 }
977}
978
979
980/**
981 * @interface_method_impl{PDMDEVREG,pfnReset}
982 */
983static DECLCALLBACK(void) efiReset(PPDMDEVINS pDevIns)
984{
985 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
986 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
987 LogFlow(("efiReset\n"));
988
989 pThisCC->iInfoSelector = 0;
990 pThisCC->offInfo = -1;
991
992 pThisCC->iMsg = 0;
993 pThisCC->szMsg[0] = '\0';
994 pThisCC->iPanicMsg = 0;
995 pThisCC->szPanicMsg[0] = '\0';
996
997 flashR3Reset(&pThis->Flash);
998
999#ifdef DEVEFI_WITH_VBOXDBG_SCRIPT
1000 /*
1001 * Zap the debugger script
1002 */
1003 RTFileDelete("./DevEFI.VBoxDbg");
1004#endif
1005}
1006
1007
1008/**
1009 * @interface_method_impl{PDMDEVREG,pfnPowerOff}
1010 */
1011static DECLCALLBACK(void) efiPowerOff(PPDMDEVINS pDevIns)
1012{
1013 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
1014 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
1015
1016 if (pThisCC->Lun0.pDrvVfs)
1017 {
1018 int rc = flashR3SaveToVfs(&pThis->Flash, pDevIns, pThisCC->Lun0.pDrvVfs,
1019 pDevIns->pReg->szName, "nvram");
1020 if (RT_FAILURE(rc))
1021 LogRel(("EFI: Failed to save flash file to NVRAM store: %Rrc\n", rc));
1022 }
1023 else if (pThisCC->pszNvramFile)
1024 {
1025 int rc = flashR3SaveToFile(&pThis->Flash, pDevIns, pThisCC->pszNvramFile);
1026 if (RT_FAILURE(rc))
1027 LogRel(("EFI: Failed to save flash file to '%s': %Rrc\n", pThisCC->pszNvramFile, rc));
1028 }
1029}
1030
1031
1032
1033/**
1034 * Destruct a device instance.
1035 *
1036 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
1037 * resources can be freed correctly.
1038 *
1039 * @param pDevIns The device instance data.
1040 */
1041static DECLCALLBACK(int) efiDestruct(PPDMDEVINS pDevIns)
1042{
1043 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
1044 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
1045 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
1046
1047 flashR3Destruct(&pThis->Flash, pDevIns);
1048
1049 if (pThisCC->pszNvramFile)
1050 {
1051 PDMDevHlpMMHeapFree(pDevIns, pThisCC->pszNvramFile);
1052 pThisCC->pszNvramFile = NULL;
1053 }
1054
1055 if (pThisCC->pu8EfiRomFree)
1056 {
1057 RTFileReadAllFree(pThisCC->pu8EfiRomFree, (size_t)pThisCC->cbEfiRom + pThisCC->offEfiRom);
1058 pThisCC->pu8EfiRomFree = NULL;
1059 }
1060
1061 /*
1062 * Free MM heap pointers (waste of time, but whatever).
1063 */
1064 if (pThisCC->pszEfiRomFile)
1065 {
1066 PDMDevHlpMMHeapFree(pDevIns, pThisCC->pszEfiRomFile);
1067 pThisCC->pszEfiRomFile = NULL;
1068 }
1069
1070 if (pThisCC->pu8EfiThunk)
1071 {
1072 PDMDevHlpMMHeapFree(pDevIns, pThisCC->pu8EfiThunk);
1073 pThisCC->pu8EfiThunk = NULL;
1074 }
1075
1076 if (pThisCC->pbDeviceProps)
1077 {
1078 PDMDevHlpMMHeapFree(pDevIns, pThisCC->pbDeviceProps);
1079 pThisCC->pbDeviceProps = NULL;
1080 pThisCC->cbDeviceProps = 0;
1081 }
1082
1083 return VINF_SUCCESS;
1084}
1085
1086
1087#if 0 /* unused */
1088/**
1089 * Helper that searches for a FFS file of a given type.
1090 *
1091 * @returns Pointer to the FFS file header if found, NULL if not.
1092 *
1093 * @param pFfsFile Pointer to the FFS file header to start searching at.
1094 * @param pbEnd The end of the firmware volume.
1095 * @param FileType The file type to look for.
1096 * @param pcbFfsFile Where to store the FFS file size (includes header).
1097 */
1098DECLINLINE(EFI_FFS_FILE_HEADER const *)
1099efiFwVolFindFileByType(EFI_FFS_FILE_HEADER const *pFfsFile, uint8_t const *pbEnd, EFI_FV_FILETYPE FileType, uint32_t *pcbFile)
1100{
1101# define FFS_SIZE(hdr) RT_MAKE_U32_FROM_U8((hdr)->Size[0], (hdr)->Size[1], (hdr)->Size[2], 0)
1102 while ((uintptr_t)pFfsFile < (uintptr_t)pbEnd)
1103 {
1104 if (pFfsFile->Type == FileType)
1105 {
1106 *pcbFile = FFS_SIZE(pFfsFile);
1107 LogFunc(("Found %RTuuid of type:%d\n", &pFfsFile->Name, FileType));
1108 return pFfsFile;
1109 }
1110 pFfsFile = (EFI_FFS_FILE_HEADER *)((uintptr_t)pFfsFile + RT_ALIGN(FFS_SIZE(pFfsFile), 8));
1111 }
1112# undef FFS_SIZE
1113 return NULL;
1114}
1115#endif /* unused */
1116
1117
1118/**
1119 * Parse EFI ROM headers and find entry points.
1120 *
1121 * @returns VBox status code.
1122 * @param pDevIns The device instance.
1123 * @param pThis The shared device state.
1124 * @param pThisCC The device state for the current context.
1125 */
1126static int efiParseFirmware(PPDMDEVINS pDevIns, PDEVEFI pThis, PDEVEFIR3 pThisCC)
1127{
1128 EFI_FIRMWARE_VOLUME_HEADER const *pFwVolHdr = (EFI_FIRMWARE_VOLUME_HEADER const *)pThisCC->pu8EfiRom;
1129
1130 /*
1131 * Validate firmware volume header.
1132 */
1133 AssertLogRelMsgReturn(pFwVolHdr->Signature == RT_MAKE_U32_FROM_U8('_', 'F', 'V', 'H'),
1134 ("%#x, expected %#x\n", pFwVolHdr->Signature, RT_MAKE_U32_FROM_U8('_', 'F', 'V', 'H')),
1135 VERR_INVALID_MAGIC);
1136 AssertLogRelMsgReturn(pFwVolHdr->Revision == EFI_FVH_REVISION,
1137 ("%#x, expected %#x\n", pFwVolHdr->Signature, EFI_FVH_REVISION),
1138 VERR_VERSION_MISMATCH);
1139 /** @todo check checksum, see PE spec vol. 3 */
1140 AssertLogRelMsgReturn(pFwVolHdr->FvLength <= pThisCC->cbEfiRom,
1141 ("%#llx, expected %#llx\n", pFwVolHdr->FvLength, pThisCC->cbEfiRom),
1142 VERR_INVALID_PARAMETER);
1143 AssertLogRelMsgReturn( pFwVolHdr->BlockMap[0].Length > 0
1144 && pFwVolHdr->BlockMap[0].NumBlocks > 0,
1145 ("%#x, %x\n", pFwVolHdr->BlockMap[0].Length, pFwVolHdr->BlockMap[0].NumBlocks),
1146 VERR_INVALID_PARAMETER);
1147
1148 AssertLogRelMsgReturn(!(pThisCC->cbEfiRom & PAGE_OFFSET_MASK), ("%RX64\n", pThisCC->cbEfiRom), VERR_INVALID_PARAMETER);
1149
1150 LogRel(("Found EFI FW Volume, %u bytes (%u %u-byte blocks)\n", pFwVolHdr->FvLength, pFwVolHdr->BlockMap[0].NumBlocks, pFwVolHdr->BlockMap[0].Length));
1151
1152 /** @todo Make this more dynamic, this assumes that the NV storage area comes first (always the case for our builds). */
1153 AssertLogRelMsgReturn(!memcmp(&pFwVolHdr->FileSystemGuid, &g_UuidNvDataFv, sizeof(g_UuidNvDataFv)),
1154 ("Expected EFI_SYSTEM_NV_DATA_FV_GUID as an identifier"),
1155 VERR_INVALID_MAGIC);
1156
1157 /* Found NVRAM storage, configure flash device. */
1158 pThisCC->offEfiRom = pFwVolHdr->FvLength;
1159 pThisCC->cbNvram = pFwVolHdr->FvLength;
1160 pThisCC->GCPhysNvram = UINT32_C(0xfffff000) - pThisCC->cbEfiRom + PAGE_SIZE;
1161 pThisCC->cbEfiRom -= pThisCC->cbNvram;
1162
1163 int rc = flashR3Init(&pThis->Flash, pThisCC->pDevIns, 0xA289 /*Intel*/, pThisCC->cbNvram, pFwVolHdr->BlockMap[0].Length);
1164 if (RT_FAILURE(rc))
1165 return rc;
1166
1167 if (pThisCC->Lun0.pDrvVfs)
1168 {
1169 rc = flashR3LoadFromVfs(&pThis->Flash, pDevIns, pThisCC->Lun0.pDrvVfs,
1170 pDevIns->pReg->szName, "nvram");
1171 if (rc == VERR_NOT_FOUND)
1172 {
1173 /* Initialize the NVRAM content from the loaded ROM file as the NVRAM wasn't initialized yet. */
1174 rc = flashR3LoadFromBuf(&pThis->Flash, pThisCC->pu8EfiRom, pThisCC->cbNvram);
1175 }
1176 else if (RT_FAILURE(rc))
1177 return rc;
1178 }
1179 else
1180 {
1181 /* If the file does not exist we initialize the NVRAM from the loaded ROM file. */
1182 if (!pThisCC->pszNvramFile || !RTPathExists(pThisCC->pszNvramFile))
1183 rc = flashR3LoadFromBuf(&pThis->Flash, pThisCC->pu8EfiRom, pThisCC->cbNvram);
1184 else
1185 rc = flashR3LoadFromFile(&pThis->Flash, pDevIns, pThisCC->pszNvramFile);
1186 if (RT_FAILURE(rc))
1187 return rc;
1188 }
1189
1190 pThisCC->GCLoadAddress = pThisCC->GCPhysNvram + pThisCC->cbNvram;
1191
1192 return VINF_SUCCESS;
1193}
1194
1195/**
1196 * Load EFI ROM file into the memory.
1197 *
1198 * @returns VBox status code.
1199 * @param pDevIns The device instance.
1200 * @param pThis The shared Efi state.
1201 * @param pThisCC The device state for the current context.
1202 * @param pCfg Configuration node handle for the device.
1203 */
1204static int efiLoadRom(PPDMDEVINS pDevIns, PDEVEFI pThis, PDEVEFIR3 pThisCC, PCFGMNODE pCfg)
1205{
1206 RT_NOREF(pCfg);
1207
1208 /*
1209 * Read the entire firmware volume into memory.
1210 */
1211 int rc;
1212#ifdef VBOX_WITH_EFI_IN_DD2
1213 if (RTStrCmp(pThisCC->pszEfiRomFile, g_szEfiBuiltin32) == 0)
1214 {
1215 pThisCC->pu8EfiRomFree = NULL;
1216 pThisCC->pu8EfiRom = g_abEfiFirmware32;
1217 pThisCC->cbEfiRom = g_cbEfiFirmware32;
1218 }
1219 else if (RTStrCmp(pThisCC->pszEfiRomFile, g_szEfiBuiltin64) == 0)
1220 {
1221 pThisCC->pu8EfiRomFree = NULL;
1222 pThisCC->pu8EfiRom = g_abEfiFirmware64;
1223 pThisCC->cbEfiRom = g_cbEfiFirmware64;
1224 }
1225 else
1226#endif
1227 {
1228 void *pvFile;
1229 size_t cbFile;
1230 rc = RTFileReadAllEx(pThisCC->pszEfiRomFile,
1231 0 /*off*/,
1232 RTFOFF_MAX /*cbMax*/,
1233 RTFILE_RDALL_O_DENY_WRITE,
1234 &pvFile,
1235 &cbFile);
1236 if (RT_FAILURE(rc))
1237 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1238 N_("Loading the EFI firmware volume '%s' failed with rc=%Rrc"),
1239 pThisCC->pszEfiRomFile, rc);
1240 pThisCC->pu8EfiRomFree = (uint8_t *)pvFile;
1241 pThisCC->pu8EfiRom = (uint8_t *)pvFile;
1242 pThisCC->cbEfiRom = cbFile;
1243 }
1244
1245 /*
1246 * Validate firmware volume and figure out the load address as well as the SEC entry point.
1247 */
1248 rc = efiParseFirmware(pDevIns, pThis, pThisCC);
1249 if (RT_FAILURE(rc))
1250 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1251 N_("Parsing the EFI firmware volume '%s' failed with rc=%Rrc"),
1252 pThisCC->pszEfiRomFile, rc);
1253
1254 /*
1255 * Map the firmware volume into memory as shadowed ROM.
1256 *
1257 * This is a little complicated due to saved state legacy. We used to have a
1258 * 2MB image w/o any flash portion, divided into four 512KB mappings.
1259 *
1260 * We've now increased the size of the firmware to 4MB, but for saved state
1261 * compatibility reasons need to use the same mappings and names (!!) for the
1262 * top 2MB.
1263 */
1264 /** @todo fix PGMR3PhysRomRegister so it doesn't mess up in SUPLib when mapping a big ROM image. */
1265#if 1
1266 static const char * const s_apszNames[16] =
1267 {
1268 "EFI Firmware Volume", "EFI Firmware Volume (Part 2)", "EFI Firmware Volume (Part 3)", "EFI Firmware Volume (Part 4)",
1269 "EFI Firmware Volume (Part 5)", "EFI Firmware Volume (Part 6)", "EFI Firmware Volume (Part 7)", "EFI Firmware Volume (Part 8)",
1270 "EFI Firmware Volume (Part 9)", "EFI Firmware Volume (Part 10)", "EFI Firmware Volume (Part 11)", "EFI Firmware Volume (Part 12)",
1271 "EFI Firmware Volume (Part 13)", "EFI Firmware Volume (Part 14)", "EFI Firmware Volume (Part 15)", "EFI Firmware Volume (Part 16)",
1272 };
1273 AssertLogRelMsgReturn(pThisCC->cbEfiRom < RT_ELEMENTS(s_apszNames) * _512K,
1274 ("EFI firmware image too big: %#RX64, max %#zx\n",
1275 pThisCC->cbEfiRom, RT_ELEMENTS(s_apszNames) * _512K),
1276 VERR_IMAGE_TOO_BIG);
1277
1278 uint32_t const cbChunk = pThisCC->cbNvram + pThisCC->cbEfiRom >= _2M ? _512K
1279 : (uint32_t)RT_ALIGN_64((pThisCC->cbNvram + pThisCC->cbEfiRom) / 4, PAGE_SIZE);
1280 uint32_t cbLeft = pThisCC->cbEfiRom; /* ASSUMES NVRAM comes first! */
1281 uint32_t off = pThisCC->offEfiRom + cbLeft; /* ASSUMES NVRAM comes first! */
1282 RTGCPHYS64 GCPhys = pThisCC->GCLoadAddress + cbLeft;
1283 AssertLogRelMsg(GCPhys == _4G, ("%RGp\n", GCPhys));
1284
1285 /* Compatibility mappings at the top (note that this isn't entirely the same
1286 algorithm, but it will produce the same results for a power of two sized image): */
1287 unsigned i = 4;
1288 while (i-- > 0)
1289 {
1290 uint32_t const cb = RT_MIN(cbLeft, cbChunk);
1291 cbLeft -= cb;
1292 GCPhys -= cb;
1293 off -= cb;
1294 rc = PDMDevHlpROMRegister(pDevIns, GCPhys, cb, pThisCC->pu8EfiRom + off, cb,
1295 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, s_apszNames[i]);
1296 AssertRCReturn(rc, rc);
1297 }
1298
1299 /* The rest (if any) is mapped in descending order of address and increasing name order: */
1300 if (cbLeft > 0)
1301 {
1302 Assert(cbChunk == _512K);
1303 for (i = 4; cbLeft > 0; i++)
1304 {
1305 uint32_t const cb = RT_MIN(cbLeft, cbChunk);
1306 cbLeft -= cb;
1307 GCPhys -= cb;
1308 off -= cb;
1309 /** @todo Add flag to prevent saved state loading from bitching about these regions. */
1310 rc = PDMDevHlpROMRegister(pDevIns, GCPhys, cb, pThisCC->pu8EfiRom + off, cb,
1311 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY
1312 | PGMPHYS_ROM_FLAGS_MAYBE_MISSING_FROM_STATE, s_apszNames[i]);
1313 AssertRCReturn(rc, rc);
1314 }
1315 Assert(i <= RT_ELEMENTS(s_apszNames));
1316 }
1317
1318 /* Not sure what the purpose of this one is... */
1319 rc = PDMDevHlpROMProtectShadow(pDevIns, pThisCC->GCLoadAddress, (uint32_t)cbChunk, PGMROMPROT_READ_RAM_WRITE_IGNORE);
1320 AssertRCReturn(rc, rc);
1321
1322#else
1323 RTGCPHYS cbQuart = RT_ALIGN_64(pThisCC->cbEfiRom / 4, PAGE_SIZE);
1324 rc = PDMDevHlpROMRegister(pDevIns,
1325 pThisCC->GCLoadAddress,
1326 cbQuart,
1327 pThisCC->pu8EfiRom + pThisCC->uEfiRomOfs,
1328 cbQuart,
1329 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
1330 "EFI Firmware Volume");
1331 AssertRCReturn(rc, rc);
1332 rc = PDMDevHlpROMProtectShadow(pDevIns, pThisCC->GCLoadAddress, (uint32_t)cbQuart, PGMROMPROT_READ_RAM_WRITE_IGNORE);
1333 AssertRCReturn(rc, rc);
1334 rc = PDMDevHlpROMRegister(pDevIns,
1335 pThisCC->GCLoadAddress + cbQuart,
1336 cbQuart,
1337 pThisCC->pu8EfiRom + pThisCC->uEfiRomOfs + cbQuart,
1338 cbQuart,
1339 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
1340 "EFI Firmware Volume (Part 2)");
1341 if (RT_FAILURE(rc))
1342 return rc;
1343 rc = PDMDevHlpROMRegister(pDevIns,
1344 pThisCC->GCLoadAddress + cbQuart * 2,
1345 cbQuart,
1346 pThisCC->pu8EfiRom + pThisCC->uEfiRomOfs + cbQuart * 2,
1347 cbQuart,
1348 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
1349 "EFI Firmware Volume (Part 3)");
1350 if (RT_FAILURE(rc))
1351 return rc;
1352 rc = PDMDevHlpROMRegister(pDevIns,
1353 pThisCC->GCLoadAddress + cbQuart * 3,
1354 pThisCC->cbEfiRom - cbQuart * 3,
1355 pThisCC->pu8EfiRom + pThisCC->uEfiRomOfs + cbQuart * 3,
1356 pThisCC->cbEfiRom - cbQuart * 3,
1357 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
1358 "EFI Firmware Volume (Part 4)");
1359 if (RT_FAILURE(rc))
1360 return rc;
1361#endif
1362
1363 /*
1364 * Register MMIO region for flash device.
1365 */
1366 rc = PDMDevHlpMmioCreateEx(pDevIns, pThisCC->cbNvram, IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
1367 NULL /*pPciDev*/, UINT32_MAX, efiR3NvMmioWrite, efiR3NvMmioRead, NULL, NULL /*pvUser*/,
1368 "Flash Memory", &pThis->hMmioFlash);
1369 AssertRCReturn(rc, rc);
1370 rc = PDMDevHlpMmioMap(pDevIns, pThis->hMmioFlash, pThisCC->GCPhysNvram);
1371 AssertRCReturn(rc, rc);
1372
1373 LogRel(("EFI: Registered %uKB flash at %RGp\n", pThisCC->cbNvram / _1K, pThisCC->GCPhysNvram));
1374 return VINF_SUCCESS;
1375}
1376
1377static uint8_t efiGetHalfByte(char ch)
1378{
1379 uint8_t val;
1380
1381 if (ch >= '0' && ch <= '9')
1382 val = ch - '0';
1383 else if (ch >= 'A' && ch <= 'F')
1384 val = ch - 'A' + 10;
1385 else if(ch >= 'a' && ch <= 'f')
1386 val = ch - 'a' + 10;
1387 else
1388 val = 0xff;
1389
1390 return val;
1391}
1392
1393
1394/**
1395 * Converts a hex string into a binary data blob located at
1396 * pThisCC->pbDeviceProps, size returned as pThisCC->cbDeviceProps.
1397 *
1398 * @returns VERR_NO_MEMORY or VINF_SUCCESS.
1399 * @param pThisCC The device state for the current context.
1400 * @param pszDeviceProps The device property hex string to decode.
1401 */
1402static int efiParseDeviceString(PDEVEFIR3 pThisCC, const char *pszDeviceProps)
1403{
1404 uint32_t const cbOut = (uint32_t)RTStrNLen(pszDeviceProps, RTSTR_MAX) / 2 + 1;
1405 pThisCC->pbDeviceProps = (uint8_t *)PDMDevHlpMMHeapAlloc(pThisCC->pDevIns, cbOut);
1406 if (!pThisCC->pbDeviceProps)
1407 return VERR_NO_MEMORY;
1408
1409 uint32_t iHex = 0;
1410 bool fUpper = true;
1411 uint8_t u8Value = 0; /* (shut up gcc) */
1412 for (uint32_t iStr = 0; pszDeviceProps[iStr]; iStr++)
1413 {
1414 uint8_t u8Hb = efiGetHalfByte(pszDeviceProps[iStr]);
1415 if (u8Hb > 0xf)
1416 continue;
1417
1418 if (fUpper)
1419 u8Value = u8Hb << 4;
1420 else
1421 pThisCC->pbDeviceProps[iHex++] = u8Hb | u8Value;
1422
1423 Assert(iHex < cbOut);
1424 fUpper = !fUpper;
1425 }
1426
1427 Assert(iHex == 0 || fUpper);
1428 pThisCC->cbDeviceProps = iHex;
1429
1430 return VINF_SUCCESS;
1431}
1432
1433
1434/**
1435 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1436 */
1437static DECLCALLBACK(int) efiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1438{
1439 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1440 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
1441 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
1442 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1443 int rc;
1444
1445 RT_NOREF(iInstance);
1446 Assert(iInstance == 0);
1447
1448 /*
1449 * Initalize the basic variables so that the destructor always works.
1450 */
1451 pThisCC->pDevIns = pDevIns;
1452 pThisCC->Lun0.IBase.pfnQueryInterface = devEfiQueryInterface;
1453
1454 /*
1455 * Validate and read the configuration.
1456 */
1457 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns,
1458 "EfiRom|"
1459 "NumCPUs|"
1460 "McfgBase|"
1461 "McfgLength|"
1462 "UUID|"
1463 "UuidLe|"
1464 "IOAPIC|"
1465 "APIC|"
1466 "DmiBIOSFirmwareMajor|"
1467 "DmiBIOSFirmwareMinor|"
1468 "DmiBIOSReleaseDate|"
1469 "DmiBIOSReleaseMajor|"
1470 "DmiBIOSReleaseMinor|"
1471 "DmiBIOSVendor|"
1472 "DmiBIOSVersion|"
1473 "DmiSystemFamily|"
1474 "DmiSystemProduct|"
1475 "DmiSystemSerial|"
1476 "DmiSystemSKU|"
1477 "DmiSystemUuid|"
1478 "DmiSystemVendor|"
1479 "DmiSystemVersion|"
1480 "DmiBoardAssetTag|"
1481 "DmiBoardBoardType|"
1482 "DmiBoardLocInChass|"
1483 "DmiBoardProduct|"
1484 "DmiBoardSerial|"
1485 "DmiBoardVendor|"
1486 "DmiBoardVersion|"
1487 "DmiChassisAssetTag|"
1488 "DmiChassisSerial|"
1489 "DmiChassisType|"
1490 "DmiChassisVendor|"
1491 "DmiChassisVersion|"
1492 "DmiProcManufacturer|"
1493 "DmiProcVersion|"
1494 "DmiOEMVBoxVer|"
1495 "DmiOEMVBoxRev|"
1496 "DmiUseHostInfo|"
1497 "DmiExposeMemoryTable|"
1498 "DmiExposeProcInf|"
1499 "64BitEntry|"
1500 "BootArgs|"
1501 "DeviceProps|"
1502 "GopMode|" // legacy
1503 "GraphicsMode|"
1504 "UgaHorizontalResolution|" // legacy
1505 "UgaVerticalResolution|" // legacy
1506 "GraphicsResolution|"
1507 "NvramFile", "");
1508
1509 /* CPU count (optional). */
1510 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "NumCPUs", &pThisCC->cCpus, 1);
1511 AssertLogRelRCReturn(rc, rc);
1512
1513 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "McfgBase", &pThisCC->u64McfgBase, 0);
1514 if (RT_FAILURE(rc))
1515 return PDMDEV_SET_ERROR(pDevIns, rc,
1516 N_("Configuration error: Querying \"\" as integer failed"));
1517 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "McfgLength", &pThisCC->cbMcfgLength, 0);
1518 if (RT_FAILURE(rc))
1519 return PDMDEV_SET_ERROR(pDevIns, rc,
1520 N_("Configuration error: Querying \"McfgLength\" as integer failed"));
1521
1522 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "IOAPIC", &pThisCC->u8IOAPIC, 1);
1523 if (RT_FAILURE (rc))
1524 return PDMDEV_SET_ERROR(pDevIns, rc,
1525 N_("Configuration error: Failed to read \"IOAPIC\""));
1526
1527 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "APIC", &pThisCC->u8APIC, 1);
1528 if (RT_FAILURE (rc))
1529 return PDMDEV_SET_ERROR(pDevIns, rc,
1530 N_("Configuration error: Failed to read \"APIC\""));
1531
1532 /*
1533 * Query the machine's UUID for SMBIOS/DMI use.
1534 */
1535 RTUUID uuid;
1536 rc = pHlp->pfnCFGMQueryBytes(pCfg, "UUID", &uuid, sizeof(uuid));
1537 if (RT_FAILURE(rc))
1538 return PDMDEV_SET_ERROR(pDevIns, rc,
1539 N_("Configuration error: Querying \"UUID\" failed"));
1540
1541 bool fUuidLe;
1542 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "UuidLe", &fUuidLe, false);
1543 if (RT_FAILURE(rc))
1544 return PDMDEV_SET_ERROR(pDevIns, rc,
1545 N_("Configuration error: Querying \"UuidLe\" failed"));
1546
1547 if (!fUuidLe)
1548 {
1549 /*
1550 * UUIDs are stored little endian actually (see chapter 7.2.1 System — UUID
1551 * of the DMI/SMBIOS spec) but to not force reactivation of existing guests we have
1552 * to carry this bug along... (see also DevPcBios.cpp when changing this)
1553 *
1554 * Convert the UUID to network byte order. Not entirely straightforward as
1555 * parts are MSB already...
1556 */
1557 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
1558 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
1559 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
1560 }
1561 memcpy(&pThisCC->aUuid, &uuid, sizeof pThisCC->aUuid);
1562
1563 /*
1564 * Get the system EFI ROM file name.
1565 */
1566#ifdef VBOX_WITH_EFI_IN_DD2
1567 rc = pHlp->pfnCFGMQueryStringAllocDef(pCfg, "EfiRom", &pThisCC->pszEfiRomFile, g_szEfiBuiltin32);
1568 if (RT_FAILURE(rc))
1569#else
1570 rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "EfiRom", &pThisCC->pszEfiRomFile);
1571 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1572 {
1573 pThisCC->pszEfiRomFile = (char *)PDMDevHlpMMHeapAlloc(pDevIns, RTPATH_MAX);
1574 AssertReturn(pThisCC->pszEfiRomFile, VERR_NO_MEMORY);
1575 rc = RTPathAppPrivateArchTop(pThisCC->pszEfiRomFile, RTPATH_MAX);
1576 AssertRCReturn(rc, rc);
1577 rc = RTPathAppend(pThisCC->pszEfiRomFile, RTPATH_MAX, "VBoxEFI32.fd");
1578 AssertRCReturn(rc, rc);
1579 }
1580 else if (RT_FAILURE(rc))
1581#endif
1582 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1583 N_("Configuration error: Querying \"EfiRom\" as a string failed"));
1584
1585 /*
1586 * Saved State handling.
1587 */
1588 rc = PDMDevHlpSSMRegister(pDevIns, EFI_SSM_VERSION, sizeof(*pThisCC), efiSaveExec, efiLoadExec);
1589 AssertRCReturn(rc, rc);
1590
1591 /*
1592 * NVRAM storage.
1593 */
1594 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThisCC->Lun0.IBase, &pThisCC->Lun0.pDrvBase, "NvramStorage");
1595 if (RT_SUCCESS(rc))
1596 {
1597 pThisCC->Lun0.pDrvVfs = PDMIBASE_QUERY_INTERFACE(pThisCC->Lun0.pDrvBase, PDMIVFSCONNECTOR);
1598 if (!pThisCC->Lun0.pDrvVfs)
1599 return PDMDevHlpVMSetError(pDevIns, VERR_PDM_MISSING_INTERFACE_BELOW, RT_SRC_POS, N_("NVRAM storage driver is missing VFS interface below"));
1600 }
1601 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1602 rc = VINF_SUCCESS; /* Missing driver is no error condition. */
1603 else
1604 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("Can't attach Nvram Storage driver"));
1605
1606 /*
1607 * Get boot args.
1608 */
1609 rc = pHlp->pfnCFGMQueryStringDef(pCfg, "BootArgs", pThisCC->szBootArgs, sizeof(pThisCC->szBootArgs), "");
1610 if (RT_FAILURE(rc))
1611 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1612 N_("Configuration error: Querying \"BootArgs\" as a string failed"));
1613
1614 //strcpy(pThisCC->szBootArgs, "-v keepsyms=1 io=0xf debug=0x2a");
1615 //strcpy(pThisCC->szBootArgs, "-v keepsyms=1 debug=0x2a");
1616 LogRel(("EFI: boot args = %s\n", pThisCC->szBootArgs));
1617
1618 /*
1619 * Get device props.
1620 */
1621 char *pszDeviceProps;
1622 rc = pHlp->pfnCFGMQueryStringAllocDef(pCfg, "DeviceProps", &pszDeviceProps, NULL);
1623 if (RT_FAILURE(rc))
1624 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1625 N_("Configuration error: Querying \"DeviceProps\" as a string failed"));
1626 if (pszDeviceProps)
1627 {
1628 LogRel(("EFI: device props = %s\n", pszDeviceProps));
1629 rc = efiParseDeviceString(pThisCC, pszDeviceProps);
1630 PDMDevHlpMMHeapFree(pDevIns, pszDeviceProps);
1631 if (RT_FAILURE(rc))
1632 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1633 N_("Configuration error: Cannot parse device properties"));
1634 }
1635 else
1636 {
1637 pThisCC->pbDeviceProps = NULL;
1638 pThisCC->cbDeviceProps = 0;
1639 }
1640
1641 /*
1642 * CPU frequencies.
1643 */
1644 pThisCC->u64TscFrequency = TMCpuTicksPerSecond(PDMDevHlpGetVM(pDevIns));
1645 pThisCC->u64CpuFrequency = pThisCC->u64TscFrequency;
1646 pThisCC->u64FsbFrequency = CPUMGetGuestScalableBusFrequency(PDMDevHlpGetVM(pDevIns));
1647
1648 /*
1649 * EFI graphics mode (with new EFI VGA code used only as a fallback, for
1650 * old EFI VGA code the only way to select the GOP mode).
1651 */
1652 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "GraphicsMode", &pThisCC->u32GraphicsMode, UINT32_MAX);
1653 if (RT_FAILURE(rc))
1654 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1655 N_("Configuration error: Querying \"GraphicsMode\" as a 32-bit int failed"));
1656 if (pThisCC->u32GraphicsMode == UINT32_MAX)
1657 {
1658 /* get the legacy value if nothing else was specified */
1659 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "GopMode", &pThisCC->u32GraphicsMode, UINT32_MAX);
1660 if (RT_FAILURE(rc))
1661 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1662 N_("Configuration error: Querying \"GopMode\" as a 32-bit int failed"));
1663 }
1664 if (pThisCC->u32GraphicsMode == UINT32_MAX)
1665 pThisCC->u32GraphicsMode = 2; /* 1024x768, at least typically */
1666
1667 /*
1668 * EFI graphics resolution, defaults to 1024x768 (used to be UGA only, now
1669 * is the main config setting as the mode number is so hard to predict).
1670 */
1671 char szResolution[16];
1672 rc = pHlp->pfnCFGMQueryStringDef(pCfg, "GraphicsResolution", szResolution, sizeof(szResolution), "");
1673 if (RT_FAILURE(rc))
1674 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1675 N_("Configuration error: Querying \"GraphicsResolution\" as a string failed"));
1676 if (szResolution[0])
1677 {
1678 const char *pszX = RTStrStr(szResolution, "x");
1679 if (pszX)
1680 {
1681 pThisCC->u32HorizontalResolution = RTStrToUInt32(szResolution);
1682 pThisCC->u32VerticalResolution = RTStrToUInt32(pszX + 1);
1683 }
1684 }
1685 else
1686 {
1687 /* get the legacy values if nothing else was specified */
1688 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "UgaHorizontalResolution", &pThisCC->u32HorizontalResolution, 0);
1689 AssertRCReturn(rc, rc);
1690 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "UgaVerticalResolution", &pThisCC->u32VerticalResolution, 0);
1691 AssertRCReturn(rc, rc);
1692 }
1693 if (pThisCC->u32HorizontalResolution == 0 || pThisCC->u32VerticalResolution == 0)
1694 {
1695 pThisCC->u32HorizontalResolution = 1024;
1696 pThisCC->u32VerticalResolution = 768;
1697 }
1698
1699 pThisCC->pszNvramFile = NULL;
1700 rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "NvramFile", &pThisCC->pszNvramFile);
1701 if (RT_FAILURE(rc) && rc != VERR_CFGM_VALUE_NOT_FOUND)
1702 return PDMDEV_SET_ERROR(pDevIns, rc,
1703 N_("Configuration error: Querying \"NvramFile\" as a string failed"));
1704
1705 /*
1706 * Load firmware volume and thunk ROM.
1707 */
1708 rc = efiLoadRom(pDevIns, pThis, pThisCC, pCfg);
1709 if (RT_FAILURE(rc))
1710 return rc;
1711
1712 /*
1713 * Register our I/O ports.
1714 */
1715 rc = PDMDevHlpIoPortCreateFlagsAndMap(pDevIns, EFI_PORT_BASE, EFI_PORT_COUNT, IOM_IOPORT_F_ABS,
1716 efiR3IoPortWrite, efiR3IoPortRead,
1717 "EFI communication ports", NULL /*paExtDescs*/, &pThis->hIoPorts);
1718 AssertRCReturn(rc, rc);
1719
1720 /*
1721 * Plant DMI and MPS tables in the ROM region.
1722 */
1723 rc = FwCommonPlantDMITable(pDevIns, pThisCC->au8DMIPage, VBOX_DMI_TABLE_SIZE, &pThisCC->aUuid,
1724 pDevIns->pCfg, pThisCC->cCpus, &pThisCC->cbDmiTables, &pThisCC->cNumDmiTables,
1725 true /*fUefi*/);
1726 AssertRCReturn(rc, rc);
1727
1728 /*
1729 * NB: VBox/Devices/EFI/Firmware/VBoxPkg/VBoxSysTables/VBoxSysTables.c scans memory for
1730 * the SMBIOS header. The header must be placed in a range that EFI will scan.
1731 */
1732 FwCommonPlantSmbiosAndDmiHdrs(pDevIns, pThisCC->au8DMIPage + VBOX_DMI_TABLE_SIZE,
1733 pThisCC->cbDmiTables, pThisCC->cNumDmiTables);
1734
1735 if (pThisCC->u8IOAPIC)
1736 {
1737 FwCommonPlantMpsTable(pDevIns,
1738 pThisCC->au8DMIPage /* aka VBOX_DMI_TABLE_BASE */ + VBOX_DMI_TABLE_SIZE + VBOX_DMI_HDR_SIZE,
1739 _4K - VBOX_DMI_TABLE_SIZE - VBOX_DMI_HDR_SIZE, pThisCC->cCpus);
1740 FwCommonPlantMpsFloatPtr(pDevIns, VBOX_DMI_TABLE_BASE + VBOX_DMI_TABLE_SIZE + VBOX_DMI_HDR_SIZE);
1741 }
1742
1743 rc = PDMDevHlpROMRegister(pDevIns, VBOX_DMI_TABLE_BASE, _4K, pThisCC->au8DMIPage, _4K,
1744 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "DMI tables");
1745
1746 AssertRCReturn(rc, rc);
1747
1748 /*
1749 * Call reset to set things up.
1750 */
1751 efiReset(pDevIns);
1752
1753 return VINF_SUCCESS;
1754}
1755
1756#else /* IN_RING3 */
1757
1758
1759/**
1760 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
1761 */
1762static DECLCALLBACK(int) efiRZConstruct(PPDMDEVINS pDevIns)
1763{
1764 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1765 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
1766
1767# if 1
1768 int rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmioFlash, efiR3NvMmioWrite, efiR3NvMmioRead, NULL /*pvUser*/);
1769 AssertRCReturn(rc, rc);
1770# else
1771 RT_NOREF(pDevIns, pThis); (void)&efiR3NvMmioRead; (void)&efiR3NvMmioWrite;
1772# endif
1773
1774 return VINF_SUCCESS;
1775}
1776
1777
1778#endif /* IN_RING3 */
1779
1780/**
1781 * The device registration structure.
1782 */
1783const PDMDEVREG g_DeviceEFI =
1784{
1785 /* .u32Version = */ PDM_DEVREG_VERSION,
1786 /* .uReserved0 = */ 0,
1787 /* .szName = */ "efi",
1788 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
1789 /* .fClass = */ PDM_DEVREG_CLASS_ARCH_BIOS,
1790 /* .cMaxInstances = */ 1,
1791 /* .uSharedVersion = */ 42,
1792 /* .cbInstanceShared = */ sizeof(DEVEFI),
1793 /* .cbInstanceCC = */ sizeof(DEVEFICC),
1794 /* .cbInstanceRC = */ sizeof(DEVEFIRC),
1795 /* .cMaxPciDevices = */ 0,
1796 /* .cMaxMsixVectors = */ 0,
1797 /* .pszDescription = */ "Extensible Firmware Interface Device.\n"
1798 "LUN#0 - NVRAM port",
1799#if defined(IN_RING3)
1800 /* .pszRCMod = */ "VBoxDDRC.rc",
1801 /* .pszR0Mod = */ "VBoxDDR0.r0",
1802 /* .pfnConstruct = */ efiConstruct,
1803 /* .pfnDestruct = */ efiDestruct,
1804 /* .pfnRelocate = */ NULL,
1805 /* .pfnMemSetup = */ efiMemSetup,
1806 /* .pfnPowerOn = */ NULL,
1807 /* .pfnReset = */ efiReset,
1808 /* .pfnSuspend = */ NULL,
1809 /* .pfnResume = */ NULL,
1810 /* .pfnAttach = */ NULL,
1811 /* .pfnDetach = */ NULL,
1812 /* .pfnQueryInterface = */ NULL,
1813 /* .pfnInitComplete = */ efiInitComplete,
1814 /* .pfnPowerOff = */ efiPowerOff,
1815 /* .pfnSoftReset = */ NULL,
1816 /* .pfnReserved0 = */ NULL,
1817 /* .pfnReserved1 = */ NULL,
1818 /* .pfnReserved2 = */ NULL,
1819 /* .pfnReserved3 = */ NULL,
1820 /* .pfnReserved4 = */ NULL,
1821 /* .pfnReserved5 = */ NULL,
1822 /* .pfnReserved6 = */ NULL,
1823 /* .pfnReserved7 = */ NULL,
1824#elif defined(IN_RING0)
1825 /* .pfnEarlyConstruct = */ NULL,
1826 /* .pfnConstruct = */ efiRZConstruct,
1827 /* .pfnDestruct = */ NULL,
1828 /* .pfnFinalDestruct = */ NULL,
1829 /* .pfnRequest = */ NULL,
1830 /* .pfnReserved0 = */ NULL,
1831 /* .pfnReserved1 = */ NULL,
1832 /* .pfnReserved2 = */ NULL,
1833 /* .pfnReserved3 = */ NULL,
1834 /* .pfnReserved4 = */ NULL,
1835 /* .pfnReserved5 = */ NULL,
1836 /* .pfnReserved6 = */ NULL,
1837 /* .pfnReserved7 = */ NULL,
1838#elif defined(IN_RC)
1839 /* .pfnConstruct = */ efiRZConstruct,
1840 /* .pfnReserved0 = */ NULL,
1841 /* .pfnReserved1 = */ NULL,
1842 /* .pfnReserved2 = */ NULL,
1843 /* .pfnReserved3 = */ NULL,
1844 /* .pfnReserved4 = */ NULL,
1845 /* .pfnReserved5 = */ NULL,
1846 /* .pfnReserved6 = */ NULL,
1847 /* .pfnReserved7 = */ NULL,
1848#else
1849# error "Not in IN_RING3, IN_RING0 or IN_RC!"
1850#endif
1851 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
1852};
1853
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