VirtualBox

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

Last change on this file since 98103 was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use