VirtualBox

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

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

VMM,Devices: Add callbacks to required MMR3* APIs to the helper callbacks tables and convert devices and drivers to make use of those, bugref:10074

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

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