VirtualBox

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

最後變更 在這個檔案從91801是 91689,由 vboxsync 提交於 3 年 前

Devices/EFI: Don't dump the whole image path to the release log when an executable is loaded but only the filename

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 67.8 KB
 
1/* $Id: DevEFI.cpp 91689 2021-10-12 12:45:40Z 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.alldomusa.eu.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.offNameLastComponent,
494 &pThisCC->ImageEvt.szName[pThisCC->ImageEvt.offNameLastComponent],
495 pThisCC->ImageEvt.uAddr0, pThisCC->ImageEvt.cb0));
496 if (pThisCC->ImageEvt.offName > 4)
497 efiVBoxDbgScript("loadimage32 '%.*s.efi' %#llx\n",
498 pThisCC->ImageEvt.offName - 4 - pThisCC->ImageEvt.offNameLastComponent,
499 &pThisCC->ImageEvt.szName[pThisCC->ImageEvt.offNameLastComponent],
500 pThisCC->ImageEvt.uAddr0);
501 break;
502 case EFI_IMAGE_EVT_CMD_START_LOAD64:
503 LogRel(("EFI: VBoxDbg> loadimage64 '%.*s.efi' %#llx LB %#llx\n",
504 pThisCC->ImageEvt.offName - 4 - pThisCC->ImageEvt.offNameLastComponent,
505 &pThisCC->ImageEvt.szName[pThisCC->ImageEvt.offNameLastComponent],
506 pThisCC->ImageEvt.uAddr0, pThisCC->ImageEvt.cb0));
507 if (pThisCC->ImageEvt.offName > 4)
508 efiVBoxDbgScript("loadimage64 '%.*s.efi' %#llx\n",
509 pThisCC->ImageEvt.offName - 4 - pThisCC->ImageEvt.offNameLastComponent,
510 &pThisCC->ImageEvt.szName[pThisCC->ImageEvt.offNameLastComponent],
511 pThisCC->ImageEvt.uAddr0);
512 break;
513 case EFI_IMAGE_EVT_CMD_START_UNLOAD32:
514 case EFI_IMAGE_EVT_CMD_START_UNLOAD64:
515 {
516 LogRel(("EFI: VBoxDbg> unload '%.*s.efi' # %#llx LB %#llx\n",
517 pThisCC->ImageEvt.offName - 4 - pThisCC->ImageEvt.offNameLastComponent,
518 &pThisCC->ImageEvt.szName[pThisCC->ImageEvt.offNameLastComponent],
519 pThisCC->ImageEvt.uAddr0, pThisCC->ImageEvt.cb0));
520 if (pThisCC->ImageEvt.offName > 4)
521 efiVBoxDbgScript("unload '%.*s.efi'\n",
522 pThisCC->ImageEvt.offName - 4 - pThisCC->ImageEvt.offNameLastComponent,
523 &pThisCC->ImageEvt.szName[pThisCC->ImageEvt.offNameLastComponent]);
524 break;
525 }
526 case EFI_IMAGE_EVT_CMD_START_RELOC32:
527 case EFI_IMAGE_EVT_CMD_START_RELOC64:
528 {
529 LogRel(("EFI: relocate module to %#llx from %#llx\n",
530 pThisCC->ImageEvt.uAddr0, pThisCC->ImageEvt.uAddr1));
531 break;
532 }
533 }
534 }
535 return VINF_SUCCESS;
536# else
537 return VINF_IOM_R3_IOPORT_WRITE;
538# endif
539 }
540
541 case EFI_IMAGE_EVT_CMD_ADDR0:
542 AssertBreak(EFI_IMAGE_EVT_GET_PAYLOAD(u32) <= UINT16_MAX);
543 pThisCC->ImageEvt.uAddr0 <<= 16;
544 pThisCC->ImageEvt.uAddr0 |= EFI_IMAGE_EVT_GET_PAYLOAD_U16(u32);
545 return VINF_SUCCESS;
546
547 case EFI_IMAGE_EVT_CMD_ADDR1:
548 AssertBreak(EFI_IMAGE_EVT_GET_PAYLOAD(u32) <= UINT16_MAX);
549 pThisCC->ImageEvt.uAddr1 <<= 16;
550 pThisCC->ImageEvt.uAddr1 |= EFI_IMAGE_EVT_GET_PAYLOAD_U16(u32);
551 return VINF_SUCCESS;
552
553 case EFI_IMAGE_EVT_CMD_SIZE0:
554 AssertBreak(EFI_IMAGE_EVT_GET_PAYLOAD(u32) <= UINT16_MAX);
555 pThisCC->ImageEvt.cb0 <<= 16;
556 pThisCC->ImageEvt.cb0 |= EFI_IMAGE_EVT_GET_PAYLOAD_U16(u32);
557 return VINF_SUCCESS;
558
559 case EFI_IMAGE_EVT_CMD_NAME:
560 AssertBreak(EFI_IMAGE_EVT_GET_PAYLOAD(u32) <= 0x7f);
561 if (pThisCC->ImageEvt.offName < sizeof(pThisCC->ImageEvt.szName) - 1)
562 {
563 char ch = EFI_IMAGE_EVT_GET_PAYLOAD_U8(u32);
564 if (ch == '\\')
565 ch = '/';
566 pThisCC->ImageEvt.szName[pThisCC->ImageEvt.offName++] = ch;
567 if (ch == '/' || ch == ':')
568 pThisCC->ImageEvt.offNameLastComponent = pThisCC->ImageEvt.offName;
569 }
570 else
571 Log(("EFI: Image name overflow\n"));
572 return VINF_SUCCESS;
573 }
574
575 Log(("EFI: Unknown image event: %#x (cb=%d)\n", u32, cb));
576 return VINF_SUCCESS;
577}
578
579
580/**
581 * @callback_method_impl{FNIOMIOPORTNEWIN}
582 *
583 * @note The @a offPort parameter is absolute!
584 */
585static DECLCALLBACK(VBOXSTRICTRC) efiR3IoPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
586{
587 RT_NOREF(pvUser);
588 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
589 Log4(("EFI in: %x %x\n", offPort, cb));
590
591 switch (offPort)
592 {
593 case EFI_INFO_PORT:
594 if (pThisCC->offInfo == -1 && cb == 4)
595 {
596 pThisCC->offInfo = 0;
597 uint32_t cbInfo = *pu32 = efiInfoSize(pThisCC);
598 if (cbInfo == UINT32_MAX)
599 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "iInfoSelector=%#x (%d)\n",
600 pThisCC->iInfoSelector, pThisCC->iInfoSelector);
601 }
602 else
603 {
604 if (cb != 1)
605 return VERR_IOM_IOPORT_UNUSED;
606 *pu32 = efiInfoNextByte(pThisCC);
607 pThisCC->offInfo++;
608 }
609 return VINF_SUCCESS;
610
611 case EFI_PANIC_PORT:
612# ifdef IN_RING3
613 LogRel(("EFI panic port read!\n"));
614 /* Insert special code here on panic reads */
615 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "EFI Panic: panic port read!\n");
616# else
617 /* Reschedule to R3 */
618 return VINF_IOM_R3_IOPORT_READ;
619# endif
620
621 case EFI_PORT_VARIABLE_OP: /* Obsolete */
622 case EFI_PORT_VARIABLE_PARAM:
623 case EFI_PORT_DEBUG_POINT:
624 case EFI_PORT_IMAGE_EVENT:
625 *pu32 = UINT32_MAX;
626 return VINF_SUCCESS;
627 }
628
629 return VERR_IOM_IOPORT_UNUSED;
630}
631
632
633/**
634 * Translates a debug point value into a string for logging.
635 *
636 * @returns read-only string
637 * @param enmDbgPoint Valid debug point value.
638 */
639static const char *efiDbgPointName(EFIDBGPOINT enmDbgPoint)
640{
641 switch (enmDbgPoint)
642 {
643 case EFIDBGPOINT_SEC_PREMEM: return "SEC_PREMEM";
644 case EFIDBGPOINT_SEC_POSTMEM: return "SEC_POSTMEM";
645 case EFIDBGPOINT_DXE_CORE: return "DXE_CORE";
646 case EFIDBGPOINT_SMM: return "SMM";
647 case EFIDBGPOINT_SMI_ENTER: return "SMI_ENTER";
648 case EFIDBGPOINT_SMI_EXIT: return "SMI_EXIT";
649 case EFIDBGPOINT_GRAPHICS: return "GRAPHICS";
650 case EFIDBGPOINT_DXE_AP: return "DXE_AP";
651 default:
652 AssertFailed();
653 return "Unknown";
654 }
655}
656
657
658/**
659 * @callback_method_impl{FNIOMIOPORTNEWOUT}
660 *
661 * @note The @a offPort parameter is absolute!
662 */
663static DECLCALLBACK(VBOXSTRICTRC) efiR3IoPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
664{
665 RT_NOREF(pvUser);
666 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
667 VBOXSTRICTRC rc = VINF_SUCCESS;
668 Log4(("efi: out %x %x %d\n", offPort, u32, cb));
669
670 switch (offPort)
671 {
672 case EFI_INFO_PORT:
673 Log2(("EFI_INFO_PORT: iInfoSelector=%#x\n", u32));
674 pThisCC->iInfoSelector = u32;
675 pThisCC->offInfo = -1;
676 break;
677
678 case EFI_DEBUG_PORT:
679 {
680 /* The raw version. */
681 switch (u32)
682 {
683 case '\r': Log3(("efi: <return>\n")); break;
684 case '\n': Log3(("efi: <newline>\n")); break;
685 case '\t': Log3(("efi: <tab>\n")); break;
686 default: Log3(("efi: %c (%02x)\n", u32, u32)); break;
687 }
688 /* The readable, buffered version. */
689 if (u32 == '\n' || u32 == '\r')
690 {
691 Assert(pThisCC->iMsg < sizeof(pThisCC->szMsg));
692 pThisCC->szMsg[pThisCC->iMsg] = '\0';
693 if (pThisCC->iMsg)
694 LogRel2(("efi: %s\n", pThisCC->szMsg));
695 pThisCC->iMsg = 0;
696 }
697 else
698 {
699 if (pThisCC->iMsg >= sizeof(pThisCC->szMsg) - 1)
700 {
701 pThisCC->szMsg[pThisCC->iMsg] = '\0';
702 LogRel2(("efi: %s\n", pThisCC->szMsg));
703 pThisCC->iMsg = 0;
704 }
705 pThisCC->szMsg[pThisCC->iMsg] = (char)u32;
706 pThisCC->szMsg[++pThisCC->iMsg] = '\0';
707 }
708 break;
709 }
710
711 case EFI_PANIC_PORT:
712 {
713 switch (u32)
714 {
715 case EFI_PANIC_CMD_BAD_ORG: /* Legacy */
716 case EFI_PANIC_CMD_THUNK_TRAP:
717#ifdef IN_RING3
718 LogRel(("EFI: Panic! Unexpected trap!!\n"));
719# ifdef VBOX_STRICT
720 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "EFI Panic: Unexpected trap during early bootstrap!\n");
721# else
722 AssertReleaseMsgFailed(("Unexpected trap during early EFI bootstrap!!\n"));
723# endif
724 break;
725#else
726 return VINF_IOM_R3_IOPORT_WRITE;
727#endif
728
729 case EFI_PANIC_CMD_START_MSG:
730 LogRel(("Receiving EFI panic...\n"));
731 pThisCC->iPanicMsg = 0;
732 pThisCC->szPanicMsg[0] = '\0';
733 break;
734
735 case EFI_PANIC_CMD_END_MSG:
736#ifdef IN_RING3
737 LogRel(("EFI: Panic! %s\n", pThisCC->szPanicMsg));
738# ifdef VBOX_STRICT
739 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "EFI Panic: %s\n", pThisCC->szPanicMsg);
740# else
741 return VERR_INTERNAL_ERROR;
742# endif
743#else
744 return VINF_IOM_R3_IOPORT_WRITE;
745#endif
746
747
748 default:
749 if ( u32 >= EFI_PANIC_CMD_MSG_FIRST
750 && u32 <= EFI_PANIC_CMD_MSG_LAST)
751 {
752 /* Add the message char to the buffer. */
753 uint32_t i = pThisCC->iPanicMsg;
754 if (i + 1 < sizeof(pThisCC->szPanicMsg))
755 {
756 char ch = EFI_PANIC_CMD_MSG_GET_CHAR(u32);
757 if ( ch == '\n'
758 && i > 0
759 && pThisCC->szPanicMsg[i - 1] == '\r')
760 i--;
761 pThisCC->szPanicMsg[i] = ch;
762 pThisCC->szPanicMsg[i + 1] = '\0';
763 pThisCC->iPanicMsg = i + 1;
764 }
765 }
766 else
767 Log(("EFI: Unknown panic command: %#x (cb=%d)\n", u32, cb));
768 break;
769 }
770 break;
771 }
772
773 case EFI_PORT_VARIABLE_OP:
774 case EFI_PORT_VARIABLE_PARAM:
775 {
776 /* Ignore access to the obsolete variable handling port. */
777 Log(("EFI: Write to obsolete variable handling port %RTiop: %#x (cb=%d)\n", offPort, u32, cb));
778 break;
779 }
780
781 case EFI_PORT_DEBUG_POINT:
782# ifdef IN_RING3
783 if (u32 > EFIDBGPOINT_INVALID && u32 < EFIDBGPOINT_END)
784 {
785 /* For now, just log it. */
786 LogRelMax(1024, ("EFI: debug point %s\n", efiDbgPointName((EFIDBGPOINT)u32)));
787 rc = VINF_SUCCESS;
788 }
789 else
790 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "Invalid debug point %#x\n", u32);
791 break;
792# else
793 return VINF_IOM_R3_IOPORT_WRITE;
794# endif
795
796 case EFI_PORT_IMAGE_EVENT:
797 rc = efiPortImageEventWrite(pThisCC, u32, cb);
798 break;
799
800 default:
801 Log(("EFI: Write to reserved port %RTiop: %#x (cb=%d)\n", offPort, u32, cb));
802 break;
803 }
804 return rc;
805}
806
807#endif /* IN_RING3 */
808
809/**
810 * @callback_method_impl{FNIOMMMIONEWWRITE, Flash memory write}
811 */
812static DECLCALLBACK(VBOXSTRICTRC) efiR3NvMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
813{
814 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
815 RT_NOREF(pvUser);
816
817 return flashWrite(&pThis->Flash, off, pv, cb);
818}
819
820
821/**
822 * @callback_method_impl{FNIOMMMIONEWREAD, Flash memory read}
823 */
824static DECLCALLBACK(VBOXSTRICTRC) efiR3NvMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
825{
826 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
827 RT_NOREF(pvUser);
828
829 return flashRead(&pThis->Flash, off, pv, cb);
830}
831
832#ifdef IN_RING3
833
834static DECLCALLBACK(int) efiSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
835{
836 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
837 LogFlow(("efiSaveExec:\n"));
838
839 return flashR3SaveExec(&pThis->Flash, pDevIns, pSSM);
840}
841
842static DECLCALLBACK(int) efiLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
843{
844 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
845 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
846 LogFlow(("efiLoadExec: uVersion=%d uPass=%d\n", uVersion, uPass));
847
848 /*
849 * Validate input.
850 */
851 if (uPass != SSM_PASS_FINAL)
852 return VERR_SSM_UNEXPECTED_PASS;
853 if ( uVersion != EFI_SSM_VERSION
854 && uVersion != EFI_SSM_VERSION_PRE_PROPER_NVRAM
855 && uVersion != EFI_SSM_VERSION_4_2
856 )
857 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
858
859 int rc;
860 if (uVersion > EFI_SSM_VERSION_PRE_PROPER_NVRAM)
861 rc = flashR3LoadExec(&pThis->Flash, pDevIns, pSSM);
862 else
863 {
864 /*
865 * Ignore the old NVRAM state.
866 */
867 rc = pHlp->pfnSSMSkipToEndOfUnit(pSSM);
868 }
869
870 return rc;
871}
872
873
874/**
875 * @copydoc(PDMIBASE::pfnQueryInterface)
876 */
877static DECLCALLBACK(void *) devEfiQueryInterface(PPDMIBASE pInterface, const char *pszIID)
878{
879 LogFlowFunc(("ENTER: pIBase=%p pszIID=%p\n", pInterface, pszIID));
880 PDEVEFIR3 pThisCC = RT_FROM_MEMBER(pInterface, DEVEFIR3, Lun0.IBase);
881
882 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->Lun0.IBase);
883 return NULL;
884}
885
886
887/**
888 * Write to CMOS memory.
889 * This is used by the init complete code.
890 */
891static void cmosWrite(PPDMDEVINS pDevIns, unsigned off, uint32_t u32Val)
892{
893 Assert(off < 128);
894 Assert(u32Val < 256);
895
896 int rc = PDMDevHlpCMOSWrite(pDevIns, off, u32Val);
897 AssertRC(rc);
898}
899
900/**
901 * Init complete notification.
902 *
903 * @returns VBOX status code.
904 * @param pDevIns The device instance.
905 */
906static DECLCALLBACK(int) efiInitComplete(PPDMDEVINS pDevIns)
907{
908 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
909
910 PVM pVM = PDMDevHlpGetVM(pDevIns);
911 uint64_t const cbRamSize = MMR3PhysGetRamSize(pVM);
912 uint32_t const cbBelow4GB = MMR3PhysGetRamSizeBelow4GB(pVM);
913 uint64_t const cbAbove4GB = MMR3PhysGetRamSizeAbove4GB(pVM);
914 NOREF(cbAbove4GB);
915
916 /*
917 * Memory sizes.
918 */
919 uint32_t u32Low = 0;
920 uint32_t u32Chunks = 0;
921 if (cbRamSize > 16 * _1M)
922 {
923 u32Low = RT_MIN(cbBelow4GB, UINT32_C(0xfe000000));
924 u32Chunks = (u32Low - 16U * _1M) / _64K;
925 }
926 cmosWrite(pDevIns, 0x34, RT_BYTE1(u32Chunks));
927 cmosWrite(pDevIns, 0x35, RT_BYTE2(u32Chunks));
928
929 if (u32Low < cbRamSize)
930 {
931 uint64_t u64 = cbRamSize - u32Low;
932 u32Chunks = (uint32_t)(u64 / _64K);
933 cmosWrite(pDevIns, 0x5b, RT_BYTE1(u32Chunks));
934 cmosWrite(pDevIns, 0x5c, RT_BYTE2(u32Chunks));
935 cmosWrite(pDevIns, 0x5d, RT_BYTE3(u32Chunks));
936 cmosWrite(pDevIns, 0x5e, RT_BYTE4(u32Chunks));
937 }
938
939 /*
940 * Number of CPUs.
941 */
942 cmosWrite(pDevIns, 0x60, pThisCC->cCpus & 0xff);
943
944 return VINF_SUCCESS;
945}
946
947
948/**
949 * @interface_method_impl{PDMDEVREG,pfnMemSetup}
950 */
951static DECLCALLBACK(void) efiMemSetup(PPDMDEVINS pDevIns, PDMDEVMEMSETUPCTX enmCtx)
952{
953 RT_NOREF(enmCtx);
954 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
955
956 /*
957 * Re-shadow the Firmware Volume and make it RAM/RAM.
958 */
959 uint32_t cPages = RT_ALIGN_64(pThisCC->cbEfiRom, PAGE_SIZE) >> PAGE_SHIFT;
960 RTGCPHYS GCPhys = pThisCC->GCLoadAddress;
961 while (cPages > 0)
962 {
963 uint8_t abPage[PAGE_SIZE];
964
965 /* Read the (original) ROM page and write it back to the RAM page. */
966 int rc = PDMDevHlpROMProtectShadow(pDevIns, GCPhys, PAGE_SIZE, PGMROMPROT_READ_ROM_WRITE_RAM);
967 AssertLogRelRC(rc);
968
969 rc = PDMDevHlpPhysRead(pDevIns, GCPhys, abPage, PAGE_SIZE);
970 AssertLogRelRC(rc);
971 if (RT_FAILURE(rc))
972 memset(abPage, 0xcc, sizeof(abPage));
973
974 rc = PDMDevHlpPhysWrite(pDevIns, GCPhys, abPage, PAGE_SIZE);
975 AssertLogRelRC(rc);
976
977 /* Switch to the RAM/RAM mode. */
978 rc = PDMDevHlpROMProtectShadow(pDevIns, GCPhys, PAGE_SIZE, PGMROMPROT_READ_RAM_WRITE_RAM);
979 AssertLogRelRC(rc);
980
981 /* Advance */
982 GCPhys += PAGE_SIZE;
983 cPages--;
984 }
985}
986
987
988/**
989 * @interface_method_impl{PDMDEVREG,pfnReset}
990 */
991static DECLCALLBACK(void) efiReset(PPDMDEVINS pDevIns)
992{
993 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
994 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
995 LogFlow(("efiReset\n"));
996
997 pThisCC->iInfoSelector = 0;
998 pThisCC->offInfo = -1;
999
1000 pThisCC->iMsg = 0;
1001 pThisCC->szMsg[0] = '\0';
1002 pThisCC->iPanicMsg = 0;
1003 pThisCC->szPanicMsg[0] = '\0';
1004
1005 flashR3Reset(&pThis->Flash);
1006
1007#ifdef DEVEFI_WITH_VBOXDBG_SCRIPT
1008 /*
1009 * Zap the debugger script
1010 */
1011 RTFileDelete("./DevEFI.VBoxDbg");
1012#endif
1013}
1014
1015
1016/**
1017 * @interface_method_impl{PDMDEVREG,pfnPowerOff}
1018 */
1019static DECLCALLBACK(void) efiPowerOff(PPDMDEVINS pDevIns)
1020{
1021 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
1022 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
1023
1024 if (pThisCC->Lun0.pDrvVfs)
1025 {
1026 int rc = flashR3SaveToVfs(&pThis->Flash, pDevIns, pThisCC->Lun0.pDrvVfs,
1027 pDevIns->pReg->szName, "nvram");
1028 if (RT_FAILURE(rc))
1029 LogRel(("EFI: Failed to save flash file to NVRAM store: %Rrc\n", rc));
1030 }
1031 else if (pThisCC->pszNvramFile)
1032 {
1033 int rc = flashR3SaveToFile(&pThis->Flash, pDevIns, pThisCC->pszNvramFile);
1034 if (RT_FAILURE(rc))
1035 LogRel(("EFI: Failed to save flash file to '%s': %Rrc\n", pThisCC->pszNvramFile, rc));
1036 }
1037}
1038
1039
1040
1041/**
1042 * Destruct a device instance.
1043 *
1044 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
1045 * resources can be freed correctly.
1046 *
1047 * @param pDevIns The device instance data.
1048 */
1049static DECLCALLBACK(int) efiDestruct(PPDMDEVINS pDevIns)
1050{
1051 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
1052 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
1053 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
1054
1055 flashR3Destruct(&pThis->Flash, pDevIns);
1056
1057 if (pThisCC->pszNvramFile)
1058 {
1059 PDMDevHlpMMHeapFree(pDevIns, pThisCC->pszNvramFile);
1060 pThisCC->pszNvramFile = NULL;
1061 }
1062
1063 if (pThisCC->pu8EfiRomFree)
1064 {
1065 RTFileReadAllFree(pThisCC->pu8EfiRomFree, (size_t)pThisCC->cbEfiRom + pThisCC->offEfiRom);
1066 pThisCC->pu8EfiRomFree = NULL;
1067 }
1068
1069 /*
1070 * Free MM heap pointers (waste of time, but whatever).
1071 */
1072 if (pThisCC->pszEfiRomFile)
1073 {
1074 PDMDevHlpMMHeapFree(pDevIns, pThisCC->pszEfiRomFile);
1075 pThisCC->pszEfiRomFile = NULL;
1076 }
1077
1078 if (pThisCC->pu8EfiThunk)
1079 {
1080 PDMDevHlpMMHeapFree(pDevIns, pThisCC->pu8EfiThunk);
1081 pThisCC->pu8EfiThunk = NULL;
1082 }
1083
1084 if (pThisCC->pbDeviceProps)
1085 {
1086 PDMDevHlpMMHeapFree(pDevIns, pThisCC->pbDeviceProps);
1087 pThisCC->pbDeviceProps = NULL;
1088 pThisCC->cbDeviceProps = 0;
1089 }
1090
1091 return VINF_SUCCESS;
1092}
1093
1094
1095#if 0 /* unused */
1096/**
1097 * Helper that searches for a FFS file of a given type.
1098 *
1099 * @returns Pointer to the FFS file header if found, NULL if not.
1100 *
1101 * @param pFfsFile Pointer to the FFS file header to start searching at.
1102 * @param pbEnd The end of the firmware volume.
1103 * @param FileType The file type to look for.
1104 * @param pcbFfsFile Where to store the FFS file size (includes header).
1105 */
1106DECLINLINE(EFI_FFS_FILE_HEADER const *)
1107efiFwVolFindFileByType(EFI_FFS_FILE_HEADER const *pFfsFile, uint8_t const *pbEnd, EFI_FV_FILETYPE FileType, uint32_t *pcbFile)
1108{
1109# define FFS_SIZE(hdr) RT_MAKE_U32_FROM_U8((hdr)->Size[0], (hdr)->Size[1], (hdr)->Size[2], 0)
1110 while ((uintptr_t)pFfsFile < (uintptr_t)pbEnd)
1111 {
1112 if (pFfsFile->Type == FileType)
1113 {
1114 *pcbFile = FFS_SIZE(pFfsFile);
1115 LogFunc(("Found %RTuuid of type:%d\n", &pFfsFile->Name, FileType));
1116 return pFfsFile;
1117 }
1118 pFfsFile = (EFI_FFS_FILE_HEADER *)((uintptr_t)pFfsFile + RT_ALIGN(FFS_SIZE(pFfsFile), 8));
1119 }
1120# undef FFS_SIZE
1121 return NULL;
1122}
1123#endif /* unused */
1124
1125
1126/**
1127 * Parse EFI ROM headers and find entry points.
1128 *
1129 * @returns VBox status code.
1130 * @param pDevIns The device instance.
1131 * @param pThis The shared device state.
1132 * @param pThisCC The device state for the current context.
1133 */
1134static int efiParseFirmware(PPDMDEVINS pDevIns, PDEVEFI pThis, PDEVEFIR3 pThisCC)
1135{
1136 EFI_FIRMWARE_VOLUME_HEADER const *pFwVolHdr = (EFI_FIRMWARE_VOLUME_HEADER const *)pThisCC->pu8EfiRom;
1137
1138 /*
1139 * Validate firmware volume header.
1140 */
1141 AssertLogRelMsgReturn(pFwVolHdr->Signature == RT_MAKE_U32_FROM_U8('_', 'F', 'V', 'H'),
1142 ("%#x, expected %#x\n", pFwVolHdr->Signature, RT_MAKE_U32_FROM_U8('_', 'F', 'V', 'H')),
1143 VERR_INVALID_MAGIC);
1144 AssertLogRelMsgReturn(pFwVolHdr->Revision == EFI_FVH_REVISION,
1145 ("%#x, expected %#x\n", pFwVolHdr->Signature, EFI_FVH_REVISION),
1146 VERR_VERSION_MISMATCH);
1147 /** @todo check checksum, see PE spec vol. 3 */
1148 AssertLogRelMsgReturn(pFwVolHdr->FvLength <= pThisCC->cbEfiRom,
1149 ("%#llx, expected %#llx\n", pFwVolHdr->FvLength, pThisCC->cbEfiRom),
1150 VERR_INVALID_PARAMETER);
1151 AssertLogRelMsgReturn( pFwVolHdr->BlockMap[0].Length > 0
1152 && pFwVolHdr->BlockMap[0].NumBlocks > 0,
1153 ("%#x, %x\n", pFwVolHdr->BlockMap[0].Length, pFwVolHdr->BlockMap[0].NumBlocks),
1154 VERR_INVALID_PARAMETER);
1155
1156 AssertLogRelMsgReturn(!(pThisCC->cbEfiRom & PAGE_OFFSET_MASK), ("%RX64\n", pThisCC->cbEfiRom), VERR_INVALID_PARAMETER);
1157
1158 LogRel(("Found EFI FW Volume, %u bytes (%u %u-byte blocks)\n", pFwVolHdr->FvLength, pFwVolHdr->BlockMap[0].NumBlocks, pFwVolHdr->BlockMap[0].Length));
1159
1160 /** @todo Make this more dynamic, this assumes that the NV storage area comes first (always the case for our builds). */
1161 AssertLogRelMsgReturn(!memcmp(&pFwVolHdr->FileSystemGuid, &g_UuidNvDataFv, sizeof(g_UuidNvDataFv)),
1162 ("Expected EFI_SYSTEM_NV_DATA_FV_GUID as an identifier"),
1163 VERR_INVALID_MAGIC);
1164
1165 /* Found NVRAM storage, configure flash device. */
1166 pThisCC->offEfiRom = pFwVolHdr->FvLength;
1167 pThisCC->cbNvram = pFwVolHdr->FvLength;
1168 pThisCC->GCPhysNvram = UINT32_C(0xfffff000) - pThisCC->cbEfiRom + PAGE_SIZE;
1169 pThisCC->cbEfiRom -= pThisCC->cbNvram;
1170
1171 int rc = flashR3Init(&pThis->Flash, pThisCC->pDevIns, 0xA289 /*Intel*/, pThisCC->cbNvram, pFwVolHdr->BlockMap[0].Length);
1172 if (RT_FAILURE(rc))
1173 return rc;
1174
1175 if (pThisCC->Lun0.pDrvVfs)
1176 {
1177 rc = flashR3LoadFromVfs(&pThis->Flash, pDevIns, pThisCC->Lun0.pDrvVfs,
1178 pDevIns->pReg->szName, "nvram");
1179 if (rc == VERR_NOT_FOUND)
1180 {
1181 /* Initialize the NVRAM content from the loaded ROM file as the NVRAM wasn't initialized yet. */
1182 rc = flashR3LoadFromBuf(&pThis->Flash, pThisCC->pu8EfiRom, pThisCC->cbNvram);
1183 }
1184 else if (RT_FAILURE(rc))
1185 return rc;
1186 }
1187 else
1188 {
1189 /* If the file does not exist we initialize the NVRAM from the loaded ROM file. */
1190 if (!pThisCC->pszNvramFile || !RTPathExists(pThisCC->pszNvramFile))
1191 rc = flashR3LoadFromBuf(&pThis->Flash, pThisCC->pu8EfiRom, pThisCC->cbNvram);
1192 else
1193 rc = flashR3LoadFromFile(&pThis->Flash, pDevIns, pThisCC->pszNvramFile);
1194 if (RT_FAILURE(rc))
1195 return rc;
1196 }
1197
1198 pThisCC->GCLoadAddress = pThisCC->GCPhysNvram + pThisCC->cbNvram;
1199
1200 return VINF_SUCCESS;
1201}
1202
1203/**
1204 * Load EFI ROM file into the memory.
1205 *
1206 * @returns VBox status code.
1207 * @param pDevIns The device instance.
1208 * @param pThis The shared Efi state.
1209 * @param pThisCC The device state for the current context.
1210 * @param pCfg Configuration node handle for the device.
1211 */
1212static int efiLoadRom(PPDMDEVINS pDevIns, PDEVEFI pThis, PDEVEFIR3 pThisCC, PCFGMNODE pCfg)
1213{
1214 RT_NOREF(pCfg);
1215
1216 /*
1217 * Read the entire firmware volume into memory.
1218 */
1219 int rc;
1220#ifdef VBOX_WITH_EFI_IN_DD2
1221 if (RTStrCmp(pThisCC->pszEfiRomFile, g_szEfiBuiltin32) == 0)
1222 {
1223 pThisCC->pu8EfiRomFree = NULL;
1224 pThisCC->pu8EfiRom = g_abEfiFirmware32;
1225 pThisCC->cbEfiRom = g_cbEfiFirmware32;
1226 }
1227 else if (RTStrCmp(pThisCC->pszEfiRomFile, g_szEfiBuiltin64) == 0)
1228 {
1229 pThisCC->pu8EfiRomFree = NULL;
1230 pThisCC->pu8EfiRom = g_abEfiFirmware64;
1231 pThisCC->cbEfiRom = g_cbEfiFirmware64;
1232 }
1233 else
1234#endif
1235 {
1236 void *pvFile;
1237 size_t cbFile;
1238 rc = RTFileReadAllEx(pThisCC->pszEfiRomFile,
1239 0 /*off*/,
1240 RTFOFF_MAX /*cbMax*/,
1241 RTFILE_RDALL_O_DENY_WRITE,
1242 &pvFile,
1243 &cbFile);
1244 if (RT_FAILURE(rc))
1245 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1246 N_("Loading the EFI firmware volume '%s' failed with rc=%Rrc"),
1247 pThisCC->pszEfiRomFile, rc);
1248 pThisCC->pu8EfiRomFree = (uint8_t *)pvFile;
1249 pThisCC->pu8EfiRom = (uint8_t *)pvFile;
1250 pThisCC->cbEfiRom = cbFile;
1251 }
1252
1253 /*
1254 * Validate firmware volume and figure out the load address as well as the SEC entry point.
1255 */
1256 rc = efiParseFirmware(pDevIns, pThis, pThisCC);
1257 if (RT_FAILURE(rc))
1258 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1259 N_("Parsing the EFI firmware volume '%s' failed with rc=%Rrc"),
1260 pThisCC->pszEfiRomFile, rc);
1261
1262 /*
1263 * Map the firmware volume into memory as shadowed ROM.
1264 *
1265 * This is a little complicated due to saved state legacy. We used to have a
1266 * 2MB image w/o any flash portion, divided into four 512KB mappings.
1267 *
1268 * We've now increased the size of the firmware to 4MB, but for saved state
1269 * compatibility reasons need to use the same mappings and names (!!) for the
1270 * top 2MB.
1271 */
1272 /** @todo fix PGMR3PhysRomRegister so it doesn't mess up in SUPLib when mapping a big ROM image. */
1273#if 1
1274 static const char * const s_apszNames[16] =
1275 {
1276 "EFI Firmware Volume", "EFI Firmware Volume (Part 2)", "EFI Firmware Volume (Part 3)", "EFI Firmware Volume (Part 4)",
1277 "EFI Firmware Volume (Part 5)", "EFI Firmware Volume (Part 6)", "EFI Firmware Volume (Part 7)", "EFI Firmware Volume (Part 8)",
1278 "EFI Firmware Volume (Part 9)", "EFI Firmware Volume (Part 10)", "EFI Firmware Volume (Part 11)", "EFI Firmware Volume (Part 12)",
1279 "EFI Firmware Volume (Part 13)", "EFI Firmware Volume (Part 14)", "EFI Firmware Volume (Part 15)", "EFI Firmware Volume (Part 16)",
1280 };
1281 AssertLogRelMsgReturn(pThisCC->cbEfiRom < RT_ELEMENTS(s_apszNames) * _512K,
1282 ("EFI firmware image too big: %#RX64, max %#zx\n",
1283 pThisCC->cbEfiRom, RT_ELEMENTS(s_apszNames) * _512K),
1284 VERR_IMAGE_TOO_BIG);
1285
1286 uint32_t const cbChunk = pThisCC->cbNvram + pThisCC->cbEfiRom >= _2M ? _512K
1287 : (uint32_t)RT_ALIGN_64((pThisCC->cbNvram + pThisCC->cbEfiRom) / 4, PAGE_SIZE);
1288 uint32_t cbLeft = pThisCC->cbEfiRom; /* ASSUMES NVRAM comes first! */
1289 uint32_t off = pThisCC->offEfiRom + cbLeft; /* ASSUMES NVRAM comes first! */
1290 RTGCPHYS64 GCPhys = pThisCC->GCLoadAddress + cbLeft;
1291 AssertLogRelMsg(GCPhys == _4G, ("%RGp\n", GCPhys));
1292
1293 /* Compatibility mappings at the top (note that this isn't entirely the same
1294 algorithm, but it will produce the same results for a power of two sized image): */
1295 unsigned i = 4;
1296 while (i-- > 0)
1297 {
1298 uint32_t const cb = RT_MIN(cbLeft, cbChunk);
1299 cbLeft -= cb;
1300 GCPhys -= cb;
1301 off -= cb;
1302 rc = PDMDevHlpROMRegister(pDevIns, GCPhys, cb, pThisCC->pu8EfiRom + off, cb,
1303 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, s_apszNames[i]);
1304 AssertRCReturn(rc, rc);
1305 }
1306
1307 /* The rest (if any) is mapped in descending order of address and increasing name order: */
1308 if (cbLeft > 0)
1309 {
1310 Assert(cbChunk == _512K);
1311 for (i = 4; cbLeft > 0; i++)
1312 {
1313 uint32_t const cb = RT_MIN(cbLeft, cbChunk);
1314 cbLeft -= cb;
1315 GCPhys -= cb;
1316 off -= cb;
1317 /** @todo Add flag to prevent saved state loading from bitching about these regions. */
1318 rc = PDMDevHlpROMRegister(pDevIns, GCPhys, cb, pThisCC->pu8EfiRom + off, cb,
1319 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY
1320 | PGMPHYS_ROM_FLAGS_MAYBE_MISSING_FROM_STATE, s_apszNames[i]);
1321 AssertRCReturn(rc, rc);
1322 }
1323 Assert(i <= RT_ELEMENTS(s_apszNames));
1324 }
1325
1326 /* Not sure what the purpose of this one is... */
1327 rc = PDMDevHlpROMProtectShadow(pDevIns, pThisCC->GCLoadAddress, (uint32_t)cbChunk, PGMROMPROT_READ_RAM_WRITE_IGNORE);
1328 AssertRCReturn(rc, rc);
1329
1330#else
1331 RTGCPHYS cbQuart = RT_ALIGN_64(pThisCC->cbEfiRom / 4, PAGE_SIZE);
1332 rc = PDMDevHlpROMRegister(pDevIns,
1333 pThisCC->GCLoadAddress,
1334 cbQuart,
1335 pThisCC->pu8EfiRom + pThisCC->uEfiRomOfs,
1336 cbQuart,
1337 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
1338 "EFI Firmware Volume");
1339 AssertRCReturn(rc, rc);
1340 rc = PDMDevHlpROMProtectShadow(pDevIns, pThisCC->GCLoadAddress, (uint32_t)cbQuart, PGMROMPROT_READ_RAM_WRITE_IGNORE);
1341 AssertRCReturn(rc, rc);
1342 rc = PDMDevHlpROMRegister(pDevIns,
1343 pThisCC->GCLoadAddress + cbQuart,
1344 cbQuart,
1345 pThisCC->pu8EfiRom + pThisCC->uEfiRomOfs + cbQuart,
1346 cbQuart,
1347 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
1348 "EFI Firmware Volume (Part 2)");
1349 if (RT_FAILURE(rc))
1350 return rc;
1351 rc = PDMDevHlpROMRegister(pDevIns,
1352 pThisCC->GCLoadAddress + cbQuart * 2,
1353 cbQuart,
1354 pThisCC->pu8EfiRom + pThisCC->uEfiRomOfs + cbQuart * 2,
1355 cbQuart,
1356 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
1357 "EFI Firmware Volume (Part 3)");
1358 if (RT_FAILURE(rc))
1359 return rc;
1360 rc = PDMDevHlpROMRegister(pDevIns,
1361 pThisCC->GCLoadAddress + cbQuart * 3,
1362 pThisCC->cbEfiRom - cbQuart * 3,
1363 pThisCC->pu8EfiRom + pThisCC->uEfiRomOfs + cbQuart * 3,
1364 pThisCC->cbEfiRom - cbQuart * 3,
1365 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
1366 "EFI Firmware Volume (Part 4)");
1367 if (RT_FAILURE(rc))
1368 return rc;
1369#endif
1370
1371 /*
1372 * Register MMIO region for flash device.
1373 */
1374 rc = PDMDevHlpMmioCreateEx(pDevIns, pThisCC->cbNvram, IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
1375 NULL /*pPciDev*/, UINT32_MAX, efiR3NvMmioWrite, efiR3NvMmioRead, NULL, NULL /*pvUser*/,
1376 "Flash Memory", &pThis->hMmioFlash);
1377 AssertRCReturn(rc, rc);
1378 rc = PDMDevHlpMmioMap(pDevIns, pThis->hMmioFlash, pThisCC->GCPhysNvram);
1379 AssertRCReturn(rc, rc);
1380
1381 LogRel(("EFI: Registered %uKB flash at %RGp\n", pThisCC->cbNvram / _1K, pThisCC->GCPhysNvram));
1382 return VINF_SUCCESS;
1383}
1384
1385static uint8_t efiGetHalfByte(char ch)
1386{
1387 uint8_t val;
1388
1389 if (ch >= '0' && ch <= '9')
1390 val = ch - '0';
1391 else if (ch >= 'A' && ch <= 'F')
1392 val = ch - 'A' + 10;
1393 else if(ch >= 'a' && ch <= 'f')
1394 val = ch - 'a' + 10;
1395 else
1396 val = 0xff;
1397
1398 return val;
1399}
1400
1401
1402/**
1403 * Converts a hex string into a binary data blob located at
1404 * pThisCC->pbDeviceProps, size returned as pThisCC->cbDeviceProps.
1405 *
1406 * @returns VERR_NO_MEMORY or VINF_SUCCESS.
1407 * @param pThisCC The device state for the current context.
1408 * @param pszDeviceProps The device property hex string to decode.
1409 */
1410static int efiParseDeviceString(PDEVEFIR3 pThisCC, const char *pszDeviceProps)
1411{
1412 uint32_t const cbOut = (uint32_t)RTStrNLen(pszDeviceProps, RTSTR_MAX) / 2 + 1;
1413 pThisCC->pbDeviceProps = (uint8_t *)PDMDevHlpMMHeapAlloc(pThisCC->pDevIns, cbOut);
1414 if (!pThisCC->pbDeviceProps)
1415 return VERR_NO_MEMORY;
1416
1417 uint32_t iHex = 0;
1418 bool fUpper = true;
1419 uint8_t u8Value = 0; /* (shut up gcc) */
1420 for (uint32_t iStr = 0; pszDeviceProps[iStr]; iStr++)
1421 {
1422 uint8_t u8Hb = efiGetHalfByte(pszDeviceProps[iStr]);
1423 if (u8Hb > 0xf)
1424 continue;
1425
1426 if (fUpper)
1427 u8Value = u8Hb << 4;
1428 else
1429 pThisCC->pbDeviceProps[iHex++] = u8Hb | u8Value;
1430
1431 Assert(iHex < cbOut);
1432 fUpper = !fUpper;
1433 }
1434
1435 Assert(iHex == 0 || fUpper);
1436 pThisCC->cbDeviceProps = iHex;
1437
1438 return VINF_SUCCESS;
1439}
1440
1441
1442/**
1443 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1444 */
1445static DECLCALLBACK(int) efiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1446{
1447 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1448 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
1449 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
1450 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1451 int rc;
1452
1453 RT_NOREF(iInstance);
1454 Assert(iInstance == 0);
1455
1456 /*
1457 * Initalize the basic variables so that the destructor always works.
1458 */
1459 pThisCC->pDevIns = pDevIns;
1460 pThisCC->Lun0.IBase.pfnQueryInterface = devEfiQueryInterface;
1461
1462 /*
1463 * Validate and read the configuration.
1464 */
1465 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns,
1466 "EfiRom|"
1467 "NumCPUs|"
1468 "McfgBase|"
1469 "McfgLength|"
1470 "UUID|"
1471 "UuidLe|"
1472 "IOAPIC|"
1473 "APIC|"
1474 "DmiBIOSFirmwareMajor|"
1475 "DmiBIOSFirmwareMinor|"
1476 "DmiBIOSReleaseDate|"
1477 "DmiBIOSReleaseMajor|"
1478 "DmiBIOSReleaseMinor|"
1479 "DmiBIOSVendor|"
1480 "DmiBIOSVersion|"
1481 "DmiSystemFamily|"
1482 "DmiSystemProduct|"
1483 "DmiSystemSerial|"
1484 "DmiSystemSKU|"
1485 "DmiSystemUuid|"
1486 "DmiSystemVendor|"
1487 "DmiSystemVersion|"
1488 "DmiBoardAssetTag|"
1489 "DmiBoardBoardType|"
1490 "DmiBoardLocInChass|"
1491 "DmiBoardProduct|"
1492 "DmiBoardSerial|"
1493 "DmiBoardVendor|"
1494 "DmiBoardVersion|"
1495 "DmiChassisAssetTag|"
1496 "DmiChassisSerial|"
1497 "DmiChassisType|"
1498 "DmiChassisVendor|"
1499 "DmiChassisVersion|"
1500 "DmiProcManufacturer|"
1501 "DmiProcVersion|"
1502 "DmiOEMVBoxVer|"
1503 "DmiOEMVBoxRev|"
1504 "DmiUseHostInfo|"
1505 "DmiExposeMemoryTable|"
1506 "DmiExposeProcInf|"
1507 "64BitEntry|"
1508 "BootArgs|"
1509 "DeviceProps|"
1510 "GopMode|" // legacy
1511 "GraphicsMode|"
1512 "UgaHorizontalResolution|" // legacy
1513 "UgaVerticalResolution|" // legacy
1514 "GraphicsResolution|"
1515 "NvramFile", "");
1516
1517 /* CPU count (optional). */
1518 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "NumCPUs", &pThisCC->cCpus, 1);
1519 AssertLogRelRCReturn(rc, rc);
1520
1521 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "McfgBase", &pThisCC->u64McfgBase, 0);
1522 if (RT_FAILURE(rc))
1523 return PDMDEV_SET_ERROR(pDevIns, rc,
1524 N_("Configuration error: Querying \"\" as integer failed"));
1525 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "McfgLength", &pThisCC->cbMcfgLength, 0);
1526 if (RT_FAILURE(rc))
1527 return PDMDEV_SET_ERROR(pDevIns, rc,
1528 N_("Configuration error: Querying \"McfgLength\" as integer failed"));
1529
1530 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "IOAPIC", &pThisCC->u8IOAPIC, 1);
1531 if (RT_FAILURE (rc))
1532 return PDMDEV_SET_ERROR(pDevIns, rc,
1533 N_("Configuration error: Failed to read \"IOAPIC\""));
1534
1535 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "APIC", &pThisCC->u8APIC, 1);
1536 if (RT_FAILURE (rc))
1537 return PDMDEV_SET_ERROR(pDevIns, rc,
1538 N_("Configuration error: Failed to read \"APIC\""));
1539
1540 /*
1541 * Query the machine's UUID for SMBIOS/DMI use.
1542 */
1543 RTUUID uuid;
1544 rc = pHlp->pfnCFGMQueryBytes(pCfg, "UUID", &uuid, sizeof(uuid));
1545 if (RT_FAILURE(rc))
1546 return PDMDEV_SET_ERROR(pDevIns, rc,
1547 N_("Configuration error: Querying \"UUID\" failed"));
1548
1549 bool fUuidLe;
1550 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "UuidLe", &fUuidLe, false);
1551 if (RT_FAILURE(rc))
1552 return PDMDEV_SET_ERROR(pDevIns, rc,
1553 N_("Configuration error: Querying \"UuidLe\" failed"));
1554
1555 if (!fUuidLe)
1556 {
1557 /*
1558 * UUIDs are stored little endian actually (see chapter 7.2.1 System — UUID
1559 * of the DMI/SMBIOS spec) but to not force reactivation of existing guests we have
1560 * to carry this bug along... (see also DevPcBios.cpp when changing this)
1561 *
1562 * Convert the UUID to network byte order. Not entirely straightforward as
1563 * parts are MSB already...
1564 */
1565 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
1566 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
1567 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
1568 }
1569 memcpy(&pThisCC->aUuid, &uuid, sizeof pThisCC->aUuid);
1570
1571 /*
1572 * Get the system EFI ROM file name.
1573 */
1574#ifdef VBOX_WITH_EFI_IN_DD2
1575 rc = pHlp->pfnCFGMQueryStringAllocDef(pCfg, "EfiRom", &pThisCC->pszEfiRomFile, g_szEfiBuiltin32);
1576 if (RT_FAILURE(rc))
1577#else
1578 rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "EfiRom", &pThisCC->pszEfiRomFile);
1579 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1580 {
1581 pThisCC->pszEfiRomFile = (char *)PDMDevHlpMMHeapAlloc(pDevIns, RTPATH_MAX);
1582 AssertReturn(pThisCC->pszEfiRomFile, VERR_NO_MEMORY);
1583 rc = RTPathAppPrivateArchTop(pThisCC->pszEfiRomFile, RTPATH_MAX);
1584 AssertRCReturn(rc, rc);
1585 rc = RTPathAppend(pThisCC->pszEfiRomFile, RTPATH_MAX, "VBoxEFI32.fd");
1586 AssertRCReturn(rc, rc);
1587 }
1588 else if (RT_FAILURE(rc))
1589#endif
1590 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1591 N_("Configuration error: Querying \"EfiRom\" as a string failed"));
1592
1593 /*
1594 * Saved State handling.
1595 */
1596 rc = PDMDevHlpSSMRegister(pDevIns, EFI_SSM_VERSION, sizeof(*pThisCC), efiSaveExec, efiLoadExec);
1597 AssertRCReturn(rc, rc);
1598
1599 /*
1600 * NVRAM storage.
1601 */
1602 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThisCC->Lun0.IBase, &pThisCC->Lun0.pDrvBase, "NvramStorage");
1603 if (RT_SUCCESS(rc))
1604 {
1605 pThisCC->Lun0.pDrvVfs = PDMIBASE_QUERY_INTERFACE(pThisCC->Lun0.pDrvBase, PDMIVFSCONNECTOR);
1606 if (!pThisCC->Lun0.pDrvVfs)
1607 return PDMDevHlpVMSetError(pDevIns, VERR_PDM_MISSING_INTERFACE_BELOW, RT_SRC_POS, N_("NVRAM storage driver is missing VFS interface below"));
1608 }
1609 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1610 rc = VINF_SUCCESS; /* Missing driver is no error condition. */
1611 else
1612 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("Can't attach Nvram Storage driver"));
1613
1614 /*
1615 * Get boot args.
1616 */
1617 rc = pHlp->pfnCFGMQueryStringDef(pCfg, "BootArgs", pThisCC->szBootArgs, sizeof(pThisCC->szBootArgs), "");
1618 if (RT_FAILURE(rc))
1619 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1620 N_("Configuration error: Querying \"BootArgs\" as a string failed"));
1621
1622 //strcpy(pThisCC->szBootArgs, "-v keepsyms=1 io=0xf debug=0x2a");
1623 //strcpy(pThisCC->szBootArgs, "-v keepsyms=1 debug=0x2a");
1624 LogRel(("EFI: boot args = %s\n", pThisCC->szBootArgs));
1625
1626 /*
1627 * Get device props.
1628 */
1629 char *pszDeviceProps;
1630 rc = pHlp->pfnCFGMQueryStringAllocDef(pCfg, "DeviceProps", &pszDeviceProps, NULL);
1631 if (RT_FAILURE(rc))
1632 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1633 N_("Configuration error: Querying \"DeviceProps\" as a string failed"));
1634 if (pszDeviceProps)
1635 {
1636 LogRel(("EFI: device props = %s\n", pszDeviceProps));
1637 rc = efiParseDeviceString(pThisCC, pszDeviceProps);
1638 PDMDevHlpMMHeapFree(pDevIns, pszDeviceProps);
1639 if (RT_FAILURE(rc))
1640 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1641 N_("Configuration error: Cannot parse device properties"));
1642 }
1643 else
1644 {
1645 pThisCC->pbDeviceProps = NULL;
1646 pThisCC->cbDeviceProps = 0;
1647 }
1648
1649 /*
1650 * CPU frequencies.
1651 */
1652 pThisCC->u64TscFrequency = TMCpuTicksPerSecond(PDMDevHlpGetVM(pDevIns));
1653 pThisCC->u64CpuFrequency = pThisCC->u64TscFrequency;
1654 pThisCC->u64FsbFrequency = CPUMGetGuestScalableBusFrequency(PDMDevHlpGetVM(pDevIns));
1655
1656 /*
1657 * EFI graphics mode (with new EFI VGA code used only as a fallback, for
1658 * old EFI VGA code the only way to select the GOP mode).
1659 */
1660 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "GraphicsMode", &pThisCC->u32GraphicsMode, UINT32_MAX);
1661 if (RT_FAILURE(rc))
1662 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1663 N_("Configuration error: Querying \"GraphicsMode\" as a 32-bit int failed"));
1664 if (pThisCC->u32GraphicsMode == UINT32_MAX)
1665 {
1666 /* get the legacy value if nothing else was specified */
1667 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "GopMode", &pThisCC->u32GraphicsMode, UINT32_MAX);
1668 if (RT_FAILURE(rc))
1669 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1670 N_("Configuration error: Querying \"GopMode\" as a 32-bit int failed"));
1671 }
1672 if (pThisCC->u32GraphicsMode == UINT32_MAX)
1673 pThisCC->u32GraphicsMode = 2; /* 1024x768, at least typically */
1674
1675 /*
1676 * EFI graphics resolution, defaults to 1024x768 (used to be UGA only, now
1677 * is the main config setting as the mode number is so hard to predict).
1678 */
1679 char szResolution[16];
1680 rc = pHlp->pfnCFGMQueryStringDef(pCfg, "GraphicsResolution", szResolution, sizeof(szResolution), "");
1681 if (RT_FAILURE(rc))
1682 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1683 N_("Configuration error: Querying \"GraphicsResolution\" as a string failed"));
1684 if (szResolution[0])
1685 {
1686 const char *pszX = RTStrStr(szResolution, "x");
1687 if (pszX)
1688 {
1689 pThisCC->u32HorizontalResolution = RTStrToUInt32(szResolution);
1690 pThisCC->u32VerticalResolution = RTStrToUInt32(pszX + 1);
1691 }
1692 }
1693 else
1694 {
1695 /* get the legacy values if nothing else was specified */
1696 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "UgaHorizontalResolution", &pThisCC->u32HorizontalResolution, 0);
1697 AssertRCReturn(rc, rc);
1698 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "UgaVerticalResolution", &pThisCC->u32VerticalResolution, 0);
1699 AssertRCReturn(rc, rc);
1700 }
1701 if (pThisCC->u32HorizontalResolution == 0 || pThisCC->u32VerticalResolution == 0)
1702 {
1703 pThisCC->u32HorizontalResolution = 1024;
1704 pThisCC->u32VerticalResolution = 768;
1705 }
1706
1707 pThisCC->pszNvramFile = NULL;
1708 rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "NvramFile", &pThisCC->pszNvramFile);
1709 if (RT_FAILURE(rc) && rc != VERR_CFGM_VALUE_NOT_FOUND)
1710 return PDMDEV_SET_ERROR(pDevIns, rc,
1711 N_("Configuration error: Querying \"NvramFile\" as a string failed"));
1712
1713 /*
1714 * Load firmware volume and thunk ROM.
1715 */
1716 rc = efiLoadRom(pDevIns, pThis, pThisCC, pCfg);
1717 if (RT_FAILURE(rc))
1718 return rc;
1719
1720 /*
1721 * Register our I/O ports.
1722 */
1723 rc = PDMDevHlpIoPortCreateFlagsAndMap(pDevIns, EFI_PORT_BASE, EFI_PORT_COUNT, IOM_IOPORT_F_ABS,
1724 efiR3IoPortWrite, efiR3IoPortRead,
1725 "EFI communication ports", NULL /*paExtDescs*/, &pThis->hIoPorts);
1726 AssertRCReturn(rc, rc);
1727
1728 /*
1729 * Plant DMI and MPS tables in the ROM region.
1730 */
1731 rc = FwCommonPlantDMITable(pDevIns, pThisCC->au8DMIPage, VBOX_DMI_TABLE_SIZE, &pThisCC->aUuid,
1732 pDevIns->pCfg, pThisCC->cCpus, &pThisCC->cbDmiTables, &pThisCC->cNumDmiTables,
1733 true /*fUefi*/);
1734 AssertRCReturn(rc, rc);
1735
1736 /*
1737 * NB: VBox/Devices/EFI/Firmware/VBoxPkg/VBoxSysTables/VBoxSysTables.c scans memory for
1738 * the SMBIOS header. The header must be placed in a range that EFI will scan.
1739 */
1740 FwCommonPlantSmbiosAndDmiHdrs(pDevIns, pThisCC->au8DMIPage + VBOX_DMI_TABLE_SIZE,
1741 pThisCC->cbDmiTables, pThisCC->cNumDmiTables);
1742
1743 if (pThisCC->u8IOAPIC)
1744 {
1745 FwCommonPlantMpsTable(pDevIns,
1746 pThisCC->au8DMIPage /* aka VBOX_DMI_TABLE_BASE */ + VBOX_DMI_TABLE_SIZE + VBOX_DMI_HDR_SIZE,
1747 _4K - VBOX_DMI_TABLE_SIZE - VBOX_DMI_HDR_SIZE, pThisCC->cCpus);
1748 FwCommonPlantMpsFloatPtr(pDevIns, VBOX_DMI_TABLE_BASE + VBOX_DMI_TABLE_SIZE + VBOX_DMI_HDR_SIZE);
1749 }
1750
1751 rc = PDMDevHlpROMRegister(pDevIns, VBOX_DMI_TABLE_BASE, _4K, pThisCC->au8DMIPage, _4K,
1752 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "DMI tables");
1753
1754 AssertRCReturn(rc, rc);
1755
1756 /*
1757 * Call reset to set things up.
1758 */
1759 efiReset(pDevIns);
1760
1761 return VINF_SUCCESS;
1762}
1763
1764#else /* IN_RING3 */
1765
1766
1767/**
1768 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
1769 */
1770static DECLCALLBACK(int) efiRZConstruct(PPDMDEVINS pDevIns)
1771{
1772 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1773 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
1774
1775# if 1
1776 int rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmioFlash, efiR3NvMmioWrite, efiR3NvMmioRead, NULL /*pvUser*/);
1777 AssertRCReturn(rc, rc);
1778# else
1779 RT_NOREF(pDevIns, pThis); (void)&efiR3NvMmioRead; (void)&efiR3NvMmioWrite;
1780# endif
1781
1782 return VINF_SUCCESS;
1783}
1784
1785
1786#endif /* IN_RING3 */
1787
1788/**
1789 * The device registration structure.
1790 */
1791const PDMDEVREG g_DeviceEFI =
1792{
1793 /* .u32Version = */ PDM_DEVREG_VERSION,
1794 /* .uReserved0 = */ 0,
1795 /* .szName = */ "efi",
1796 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
1797 /* .fClass = */ PDM_DEVREG_CLASS_ARCH_BIOS,
1798 /* .cMaxInstances = */ 1,
1799 /* .uSharedVersion = */ 42,
1800 /* .cbInstanceShared = */ sizeof(DEVEFI),
1801 /* .cbInstanceCC = */ sizeof(DEVEFICC),
1802 /* .cbInstanceRC = */ sizeof(DEVEFIRC),
1803 /* .cMaxPciDevices = */ 0,
1804 /* .cMaxMsixVectors = */ 0,
1805 /* .pszDescription = */ "Extensible Firmware Interface Device.\n"
1806 "LUN#0 - NVRAM port",
1807#if defined(IN_RING3)
1808 /* .pszRCMod = */ "VBoxDDRC.rc",
1809 /* .pszR0Mod = */ "VBoxDDR0.r0",
1810 /* .pfnConstruct = */ efiConstruct,
1811 /* .pfnDestruct = */ efiDestruct,
1812 /* .pfnRelocate = */ NULL,
1813 /* .pfnMemSetup = */ efiMemSetup,
1814 /* .pfnPowerOn = */ NULL,
1815 /* .pfnReset = */ efiReset,
1816 /* .pfnSuspend = */ NULL,
1817 /* .pfnResume = */ NULL,
1818 /* .pfnAttach = */ NULL,
1819 /* .pfnDetach = */ NULL,
1820 /* .pfnQueryInterface = */ NULL,
1821 /* .pfnInitComplete = */ efiInitComplete,
1822 /* .pfnPowerOff = */ efiPowerOff,
1823 /* .pfnSoftReset = */ NULL,
1824 /* .pfnReserved0 = */ NULL,
1825 /* .pfnReserved1 = */ NULL,
1826 /* .pfnReserved2 = */ NULL,
1827 /* .pfnReserved3 = */ NULL,
1828 /* .pfnReserved4 = */ NULL,
1829 /* .pfnReserved5 = */ NULL,
1830 /* .pfnReserved6 = */ NULL,
1831 /* .pfnReserved7 = */ NULL,
1832#elif defined(IN_RING0)
1833 /* .pfnEarlyConstruct = */ NULL,
1834 /* .pfnConstruct = */ efiRZConstruct,
1835 /* .pfnDestruct = */ NULL,
1836 /* .pfnFinalDestruct = */ NULL,
1837 /* .pfnRequest = */ NULL,
1838 /* .pfnReserved0 = */ NULL,
1839 /* .pfnReserved1 = */ NULL,
1840 /* .pfnReserved2 = */ NULL,
1841 /* .pfnReserved3 = */ NULL,
1842 /* .pfnReserved4 = */ NULL,
1843 /* .pfnReserved5 = */ NULL,
1844 /* .pfnReserved6 = */ NULL,
1845 /* .pfnReserved7 = */ NULL,
1846#elif defined(IN_RC)
1847 /* .pfnConstruct = */ efiRZConstruct,
1848 /* .pfnReserved0 = */ NULL,
1849 /* .pfnReserved1 = */ NULL,
1850 /* .pfnReserved2 = */ NULL,
1851 /* .pfnReserved3 = */ NULL,
1852 /* .pfnReserved4 = */ NULL,
1853 /* .pfnReserved5 = */ NULL,
1854 /* .pfnReserved6 = */ NULL,
1855 /* .pfnReserved7 = */ NULL,
1856#else
1857# error "Not in IN_RING3, IN_RING0 or IN_RC!"
1858#endif
1859 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
1860};
1861
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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