VirtualBox

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

Last change on this file since 104587 was 104587, checked in by vboxsync, 4 months ago

Devices/EFI/DevEFI.cpp: Return if flashR3LoadFromBuf() fails (not the case currently), bugref:3409

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