VirtualBox

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

Last change on this file was 100495, checked in by vboxsync, 9 months ago

Devices/EFI: Use our firmware volume definitions to get rid of the header dependency from the EFI firmware sources, bugref:4643

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 69.5 KB
Line 
1/* $Id: DevEFI.cpp 100495 2023-07-11 06:43:42Z 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 }
1229 else if (RT_FAILURE(rc))
1230 return rc;
1231 }
1232 else
1233 {
1234 /* If the file does not exist we initialize the NVRAM from the loaded ROM file. */
1235 if (!pThisCC->pszNvramFile || !RTPathExists(pThisCC->pszNvramFile))
1236 rc = flashR3LoadFromBuf(&pThis->Flash, pThisCC->pu8EfiRom, pThisCC->cbNvram);
1237 else
1238 rc = flashR3LoadFromFile(&pThis->Flash, pDevIns, pThisCC->pszNvramFile);
1239 if (RT_FAILURE(rc))
1240 return rc;
1241 }
1242
1243 pThisCC->GCLoadAddress = pThisCC->GCPhysNvram + pThisCC->cbNvram;
1244
1245 return VINF_SUCCESS;
1246}
1247
1248/**
1249 * Load EFI ROM file into the memory.
1250 *
1251 * @returns VBox status code.
1252 * @param pDevIns The device instance.
1253 * @param pThis The shared Efi state.
1254 * @param pThisCC The device state for the current context.
1255 * @param pCfg Configuration node handle for the device.
1256 */
1257static int efiLoadRom(PPDMDEVINS pDevIns, PDEVEFI pThis, PDEVEFIR3 pThisCC, PCFGMNODE pCfg)
1258{
1259 RT_NOREF(pCfg);
1260
1261 /*
1262 * Read the entire firmware volume into memory.
1263 */
1264 int rc;
1265#ifdef VBOX_WITH_EFI_IN_DD2
1266 if (RTStrCmp(pThisCC->pszEfiRomFile, g_szEfiBuiltin32) == 0)
1267 {
1268 pThisCC->pu8EfiRomFree = NULL;
1269 pThisCC->pu8EfiRom = g_abEfiFirmware32;
1270 pThisCC->cbEfiRom = g_cbEfiFirmware32;
1271 }
1272 else if (RTStrCmp(pThisCC->pszEfiRomFile, g_szEfiBuiltin64) == 0)
1273 {
1274 pThisCC->pu8EfiRomFree = NULL;
1275 pThisCC->pu8EfiRom = g_abEfiFirmware64;
1276 pThisCC->cbEfiRom = g_cbEfiFirmware64;
1277 }
1278 else
1279#endif
1280 {
1281 void *pvFile;
1282 size_t cbFile;
1283 rc = RTFileReadAllEx(pThisCC->pszEfiRomFile,
1284 0 /*off*/,
1285 RTFOFF_MAX /*cbMax*/,
1286 RTFILE_RDALL_O_DENY_WRITE,
1287 &pvFile,
1288 &cbFile);
1289 if (RT_FAILURE(rc))
1290 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1291 N_("Loading the EFI firmware volume '%s' failed with rc=%Rrc"),
1292 pThisCC->pszEfiRomFile, rc);
1293 pThisCC->pu8EfiRomFree = (uint8_t *)pvFile;
1294 pThisCC->pu8EfiRom = (uint8_t *)pvFile;
1295 pThisCC->cbEfiRom = cbFile;
1296 }
1297
1298 /*
1299 * Validate firmware volume and figure out the load address as well as the SEC entry point.
1300 */
1301 rc = efiParseFirmware(pDevIns, pThis, pThisCC);
1302 if (RT_FAILURE(rc))
1303 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1304 N_("Parsing the EFI firmware volume '%s' failed with rc=%Rrc"),
1305 pThisCC->pszEfiRomFile, rc);
1306
1307 /*
1308 * Map the firmware volume into memory as shadowed ROM.
1309 *
1310 * This is a little complicated due to saved state legacy. We used to have a
1311 * 2MB image w/o any flash portion, divided into four 512KB mappings.
1312 *
1313 * We've now increased the size of the firmware to 4MB, but for saved state
1314 * compatibility reasons need to use the same mappings and names (!!) for the
1315 * top 2MB.
1316 */
1317 /** @todo fix PGMR3PhysRomRegister so it doesn't mess up in SUPLib when mapping a big ROM image. */
1318#if 1
1319 static const char * const s_apszNames[16] =
1320 {
1321 "EFI Firmware Volume", "EFI Firmware Volume (Part 2)", "EFI Firmware Volume (Part 3)", "EFI Firmware Volume (Part 4)",
1322 "EFI Firmware Volume (Part 5)", "EFI Firmware Volume (Part 6)", "EFI Firmware Volume (Part 7)", "EFI Firmware Volume (Part 8)",
1323 "EFI Firmware Volume (Part 9)", "EFI Firmware Volume (Part 10)", "EFI Firmware Volume (Part 11)", "EFI Firmware Volume (Part 12)",
1324 "EFI Firmware Volume (Part 13)", "EFI Firmware Volume (Part 14)", "EFI Firmware Volume (Part 15)", "EFI Firmware Volume (Part 16)",
1325 };
1326 AssertLogRelMsgReturn(pThisCC->cbEfiRom < RT_ELEMENTS(s_apszNames) * _512K,
1327 ("EFI firmware image too big: %#RX64, max %#zx\n",
1328 pThisCC->cbEfiRom, RT_ELEMENTS(s_apszNames) * _512K),
1329 VERR_IMAGE_TOO_BIG);
1330
1331 uint32_t const cbChunk = pThisCC->cbNvram + pThisCC->cbEfiRom >= _2M ? _512K
1332 : (uint32_t)RT_ALIGN_64((pThisCC->cbNvram + pThisCC->cbEfiRom) / 4, GUEST_PAGE_SIZE);
1333 uint32_t cbLeft = pThisCC->cbEfiRom; /* ASSUMES NVRAM comes first! */
1334 uint32_t off = pThisCC->offEfiRom + cbLeft; /* ASSUMES NVRAM comes first! */
1335 RTGCPHYS64 GCPhys = pThisCC->GCLoadAddress + cbLeft;
1336 AssertLogRelMsg(GCPhys == _4G, ("%RGp\n", GCPhys));
1337
1338 /* Compatibility mappings at the top (note that this isn't entirely the same
1339 algorithm, but it will produce the same results for a power of two sized image): */
1340 unsigned i = 4;
1341 while (i-- > 0)
1342 {
1343 uint32_t const cb = RT_MIN(cbLeft, cbChunk);
1344 cbLeft -= cb;
1345 GCPhys -= cb;
1346 off -= cb;
1347 rc = PDMDevHlpROMRegister(pDevIns, GCPhys, cb, pThisCC->pu8EfiRom + off, cb,
1348 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, s_apszNames[i]);
1349 AssertRCReturn(rc, rc);
1350 }
1351
1352 /* The rest (if any) is mapped in descending order of address and increasing name order: */
1353 if (cbLeft > 0)
1354 {
1355 Assert(cbChunk == _512K);
1356 for (i = 4; cbLeft > 0; i++)
1357 {
1358 uint32_t const cb = RT_MIN(cbLeft, cbChunk);
1359 cbLeft -= cb;
1360 GCPhys -= cb;
1361 off -= cb;
1362 /** @todo Add flag to prevent saved state loading from bitching about these regions. */
1363 rc = PDMDevHlpROMRegister(pDevIns, GCPhys, cb, pThisCC->pu8EfiRom + off, cb,
1364 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY
1365 | PGMPHYS_ROM_FLAGS_MAYBE_MISSING_FROM_STATE, s_apszNames[i]);
1366 AssertRCReturn(rc, rc);
1367 }
1368 Assert(i <= RT_ELEMENTS(s_apszNames));
1369 }
1370
1371 /* Not sure what the purpose of this one is... */
1372 rc = PDMDevHlpROMProtectShadow(pDevIns, pThisCC->GCLoadAddress, (uint32_t)cbChunk, PGMROMPROT_READ_RAM_WRITE_IGNORE);
1373 AssertRCReturn(rc, rc);
1374
1375#else
1376 RTGCPHYS cbQuart = RT_ALIGN_64(pThisCC->cbEfiRom / 4, GUEST_PAGE_SIZE);
1377 rc = PDMDevHlpROMRegister(pDevIns,
1378 pThisCC->GCLoadAddress,
1379 cbQuart,
1380 pThisCC->pu8EfiRom + pThisCC->uEfiRomOfs,
1381 cbQuart,
1382 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
1383 "EFI Firmware Volume");
1384 AssertRCReturn(rc, rc);
1385 rc = PDMDevHlpROMProtectShadow(pDevIns, pThisCC->GCLoadAddress, (uint32_t)cbQuart, PGMROMPROT_READ_RAM_WRITE_IGNORE);
1386 AssertRCReturn(rc, rc);
1387 rc = PDMDevHlpROMRegister(pDevIns,
1388 pThisCC->GCLoadAddress + cbQuart,
1389 cbQuart,
1390 pThisCC->pu8EfiRom + pThisCC->uEfiRomOfs + cbQuart,
1391 cbQuart,
1392 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
1393 "EFI Firmware Volume (Part 2)");
1394 if (RT_FAILURE(rc))
1395 return rc;
1396 rc = PDMDevHlpROMRegister(pDevIns,
1397 pThisCC->GCLoadAddress + cbQuart * 2,
1398 cbQuart,
1399 pThisCC->pu8EfiRom + pThisCC->uEfiRomOfs + cbQuart * 2,
1400 cbQuart,
1401 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
1402 "EFI Firmware Volume (Part 3)");
1403 if (RT_FAILURE(rc))
1404 return rc;
1405 rc = PDMDevHlpROMRegister(pDevIns,
1406 pThisCC->GCLoadAddress + cbQuart * 3,
1407 pThisCC->cbEfiRom - cbQuart * 3,
1408 pThisCC->pu8EfiRom + pThisCC->uEfiRomOfs + cbQuart * 3,
1409 pThisCC->cbEfiRom - cbQuart * 3,
1410 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
1411 "EFI Firmware Volume (Part 4)");
1412 if (RT_FAILURE(rc))
1413 return rc;
1414#endif
1415
1416 /*
1417 * Register MMIO region for flash device.
1418 */
1419 rc = PDMDevHlpMmioCreateEx(pDevIns, pThisCC->cbNvram, IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
1420 NULL /*pPciDev*/, UINT32_MAX, efiR3NvMmioWrite, efiR3NvMmioRead, NULL, NULL /*pvUser*/,
1421 "Flash Memory", &pThis->hMmioFlash);
1422 AssertRCReturn(rc, rc);
1423 rc = PDMDevHlpMmioMap(pDevIns, pThis->hMmioFlash, pThisCC->GCPhysNvram);
1424 AssertRCReturn(rc, rc);
1425
1426 LogRel(("EFI: Registered %uKB flash at %RGp\n", pThisCC->cbNvram / _1K, pThisCC->GCPhysNvram));
1427 return VINF_SUCCESS;
1428}
1429
1430static uint8_t efiGetHalfByte(char ch)
1431{
1432 uint8_t val;
1433
1434 if (ch >= '0' && ch <= '9')
1435 val = ch - '0';
1436 else if (ch >= 'A' && ch <= 'F')
1437 val = ch - 'A' + 10;
1438 else if(ch >= 'a' && ch <= 'f')
1439 val = ch - 'a' + 10;
1440 else
1441 val = 0xff;
1442
1443 return val;
1444}
1445
1446
1447/**
1448 * Converts a hex string into a binary data blob located at
1449 * pThisCC->pbDeviceProps, size returned as pThisCC->cbDeviceProps.
1450 *
1451 * @returns VERR_NO_MEMORY or VINF_SUCCESS.
1452 * @param pThisCC The device state for the current context.
1453 * @param pszDeviceProps The device property hex string to decode.
1454 */
1455static int efiParseDeviceString(PDEVEFIR3 pThisCC, const char *pszDeviceProps)
1456{
1457 uint32_t const cbOut = (uint32_t)RTStrNLen(pszDeviceProps, RTSTR_MAX) / 2 + 1;
1458 pThisCC->pbDeviceProps = (uint8_t *)PDMDevHlpMMHeapAlloc(pThisCC->pDevIns, cbOut);
1459 if (!pThisCC->pbDeviceProps)
1460 return VERR_NO_MEMORY;
1461
1462 uint32_t iHex = 0;
1463 bool fUpper = true;
1464 uint8_t u8Value = 0; /* (shut up gcc) */
1465 for (uint32_t iStr = 0; pszDeviceProps[iStr]; iStr++)
1466 {
1467 uint8_t u8Hb = efiGetHalfByte(pszDeviceProps[iStr]);
1468 if (u8Hb > 0xf)
1469 continue;
1470
1471 if (fUpper)
1472 u8Value = u8Hb << 4;
1473 else
1474 pThisCC->pbDeviceProps[iHex++] = u8Hb | u8Value;
1475
1476 Assert(iHex < cbOut);
1477 fUpper = !fUpper;
1478 }
1479
1480 Assert(iHex == 0 || fUpper);
1481 pThisCC->cbDeviceProps = iHex;
1482
1483 return VINF_SUCCESS;
1484}
1485
1486
1487/**
1488 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1489 */
1490static DECLCALLBACK(int) efiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1491{
1492 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1493 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
1494 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
1495 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1496 int rc;
1497
1498 RT_NOREF(iInstance);
1499 Assert(iInstance == 0);
1500
1501 /*
1502 * Initalize the basic variables so that the destructor always works.
1503 */
1504 pThisCC->pDevIns = pDevIns;
1505 pThisCC->Lun0.IBase.pfnQueryInterface = devEfiQueryInterface;
1506
1507 /*
1508 * Validate and read the configuration.
1509 */
1510 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns,
1511 "EfiRom|"
1512 "NumCPUs|"
1513 "McfgBase|"
1514 "McfgLength|"
1515 "UUID|"
1516 "UuidLe|"
1517 "IOAPIC|"
1518 "APIC|"
1519 "DmiBIOSFirmwareMajor|"
1520 "DmiBIOSFirmwareMinor|"
1521 "DmiBIOSReleaseDate|"
1522 "DmiBIOSReleaseMajor|"
1523 "DmiBIOSReleaseMinor|"
1524 "DmiBIOSVendor|"
1525 "DmiBIOSVersion|"
1526 "DmiSystemFamily|"
1527 "DmiSystemProduct|"
1528 "DmiSystemSerial|"
1529 "DmiSystemSKU|"
1530 "DmiSystemUuid|"
1531 "DmiSystemVendor|"
1532 "DmiSystemVersion|"
1533 "DmiBoardAssetTag|"
1534 "DmiBoardBoardType|"
1535 "DmiBoardLocInChass|"
1536 "DmiBoardProduct|"
1537 "DmiBoardSerial|"
1538 "DmiBoardVendor|"
1539 "DmiBoardVersion|"
1540 "DmiChassisAssetTag|"
1541 "DmiChassisSerial|"
1542 "DmiChassisType|"
1543 "DmiChassisVendor|"
1544 "DmiChassisVersion|"
1545 "DmiProcManufacturer|"
1546 "DmiProcVersion|"
1547 "DmiOEMVBoxVer|"
1548 "DmiOEMVBoxRev|"
1549 "DmiUseHostInfo|"
1550 "DmiExposeMemoryTable|"
1551 "DmiExposeProcInf|"
1552 "64BitEntry|"
1553 "BootArgs|"
1554 "DeviceProps|"
1555 "GopMode|" // legacy
1556 "GraphicsMode|"
1557 "UgaHorizontalResolution|" // legacy
1558 "UgaVerticalResolution|" // legacy
1559 "GraphicsResolution|"
1560 "NvramFile", "");
1561
1562 /* CPU count (optional). */
1563 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "NumCPUs", &pThisCC->cCpus, 1);
1564 AssertLogRelRCReturn(rc, rc);
1565
1566 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "McfgBase", &pThisCC->u64McfgBase, 0);
1567 if (RT_FAILURE(rc))
1568 return PDMDEV_SET_ERROR(pDevIns, rc,
1569 N_("Configuration error: Querying \"\" as integer failed"));
1570 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "McfgLength", &pThisCC->cbMcfgLength, 0);
1571 if (RT_FAILURE(rc))
1572 return PDMDEV_SET_ERROR(pDevIns, rc,
1573 N_("Configuration error: Querying \"McfgLength\" as integer failed"));
1574
1575 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "IOAPIC", &pThisCC->u8IOAPIC, 1);
1576 if (RT_FAILURE (rc))
1577 return PDMDEV_SET_ERROR(pDevIns, rc,
1578 N_("Configuration error: Failed to read \"IOAPIC\""));
1579
1580 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "APIC", &pThisCC->u8APIC, 1);
1581 if (RT_FAILURE (rc))
1582 return PDMDEV_SET_ERROR(pDevIns, rc,
1583 N_("Configuration error: Failed to read \"APIC\""));
1584
1585 /*
1586 * Query the machine's UUID for SMBIOS/DMI use.
1587 */
1588 RTUUID uuid;
1589 rc = pHlp->pfnCFGMQueryBytes(pCfg, "UUID", &uuid, sizeof(uuid));
1590 if (RT_FAILURE(rc))
1591 return PDMDEV_SET_ERROR(pDevIns, rc,
1592 N_("Configuration error: Querying \"UUID\" failed"));
1593
1594 bool fUuidLe;
1595 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "UuidLe", &fUuidLe, false);
1596 if (RT_FAILURE(rc))
1597 return PDMDEV_SET_ERROR(pDevIns, rc,
1598 N_("Configuration error: Querying \"UuidLe\" failed"));
1599
1600 if (!fUuidLe)
1601 {
1602 /*
1603 * UUIDs are stored little endian actually (see chapter 7.2.1 System — UUID
1604 * of the DMI/SMBIOS spec) but to not force reactivation of existing guests we have
1605 * to carry this bug along... (see also DevPcBios.cpp when changing this)
1606 *
1607 * Convert the UUID to network byte order. Not entirely straightforward as
1608 * parts are MSB already...
1609 */
1610 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
1611 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
1612 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
1613 }
1614 memcpy(&pThisCC->aUuid, &uuid, sizeof pThisCC->aUuid);
1615
1616 /*
1617 * Get the system EFI ROM file name.
1618 */
1619#ifdef VBOX_WITH_EFI_IN_DD2
1620 rc = pHlp->pfnCFGMQueryStringAllocDef(pCfg, "EfiRom", &pThisCC->pszEfiRomFile, g_szEfiBuiltin32);
1621 if (RT_FAILURE(rc))
1622#else
1623 rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "EfiRom", &pThisCC->pszEfiRomFile);
1624 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1625 {
1626 pThisCC->pszEfiRomFile = (char *)PDMDevHlpMMHeapAlloc(pDevIns, RTPATH_MAX);
1627 AssertReturn(pThisCC->pszEfiRomFile, VERR_NO_MEMORY);
1628 rc = RTPathAppPrivateArchTop(pThisCC->pszEfiRomFile, RTPATH_MAX);
1629 AssertRCReturn(rc, rc);
1630 rc = RTPathAppend(pThisCC->pszEfiRomFile, RTPATH_MAX, "VBoxEFI32.fd");
1631 AssertRCReturn(rc, rc);
1632 }
1633 else if (RT_FAILURE(rc))
1634#endif
1635 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1636 N_("Configuration error: Querying \"EfiRom\" as a string failed"));
1637
1638 /*
1639 * Saved State handling.
1640 */
1641 rc = PDMDevHlpSSMRegister(pDevIns, EFI_SSM_VERSION, sizeof(*pThisCC), efiSaveExec, efiLoadExec);
1642 AssertRCReturn(rc, rc);
1643
1644 /*
1645 * NVRAM storage.
1646 */
1647 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThisCC->Lun0.IBase, &pThisCC->Lun0.pDrvBase, "NvramStorage");
1648 if (RT_SUCCESS(rc))
1649 {
1650 pThisCC->Lun0.pDrvVfs = PDMIBASE_QUERY_INTERFACE(pThisCC->Lun0.pDrvBase, PDMIVFSCONNECTOR);
1651 if (!pThisCC->Lun0.pDrvVfs)
1652 return PDMDevHlpVMSetError(pDevIns, VERR_PDM_MISSING_INTERFACE_BELOW, RT_SRC_POS, N_("NVRAM storage driver is missing VFS interface below"));
1653 }
1654 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1655 rc = VINF_SUCCESS; /* Missing driver is no error condition. */
1656 else
1657 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("Can't attach Nvram Storage driver"));
1658
1659 /*
1660 * Get boot args.
1661 */
1662 rc = pHlp->pfnCFGMQueryStringDef(pCfg, "BootArgs", pThisCC->szBootArgs, sizeof(pThisCC->szBootArgs), "");
1663 if (RT_FAILURE(rc))
1664 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1665 N_("Configuration error: Querying \"BootArgs\" as a string failed"));
1666
1667 //strcpy(pThisCC->szBootArgs, "-v keepsyms=1 io=0xf debug=0x2a");
1668 //strcpy(pThisCC->szBootArgs, "-v keepsyms=1 debug=0x2a");
1669 LogRel(("EFI: boot args = %s\n", pThisCC->szBootArgs));
1670
1671 /*
1672 * Get device props.
1673 */
1674 char *pszDeviceProps;
1675 rc = pHlp->pfnCFGMQueryStringAllocDef(pCfg, "DeviceProps", &pszDeviceProps, NULL);
1676 if (RT_FAILURE(rc))
1677 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1678 N_("Configuration error: Querying \"DeviceProps\" as a string failed"));
1679 if (pszDeviceProps)
1680 {
1681 LogRel(("EFI: device props = %s\n", pszDeviceProps));
1682 rc = efiParseDeviceString(pThisCC, pszDeviceProps);
1683 PDMDevHlpMMHeapFree(pDevIns, pszDeviceProps);
1684 if (RT_FAILURE(rc))
1685 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1686 N_("Configuration error: Cannot parse device properties"));
1687 }
1688 else
1689 {
1690 pThisCC->pbDeviceProps = NULL;
1691 pThisCC->cbDeviceProps = 0;
1692 }
1693
1694 /*
1695 * CPU frequencies.
1696 */
1697 pThisCC->u64TscFrequency = PDMDevHlpTMCpuTicksPerSecond(pDevIns);
1698 pThisCC->u64CpuFrequency = pThisCC->u64TscFrequency;
1699 pThisCC->u64FsbFrequency = PDMDevHlpCpuGetGuestScalableBusFrequency(pDevIns);
1700
1701 /*
1702 * EFI graphics mode (with new EFI VGA code used only as a fallback, for
1703 * old EFI VGA code the only way to select the GOP mode).
1704 */
1705 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "GraphicsMode", &pThisCC->u32GraphicsMode, UINT32_MAX);
1706 if (RT_FAILURE(rc))
1707 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1708 N_("Configuration error: Querying \"GraphicsMode\" as a 32-bit int failed"));
1709 if (pThisCC->u32GraphicsMode == UINT32_MAX)
1710 {
1711 /* get the legacy value if nothing else was specified */
1712 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "GopMode", &pThisCC->u32GraphicsMode, UINT32_MAX);
1713 if (RT_FAILURE(rc))
1714 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1715 N_("Configuration error: Querying \"GopMode\" as a 32-bit int failed"));
1716 }
1717 if (pThisCC->u32GraphicsMode == UINT32_MAX)
1718 pThisCC->u32GraphicsMode = 2; /* 1024x768, at least typically */
1719
1720 /*
1721 * EFI graphics resolution, defaults to 1024x768 (used to be UGA only, now
1722 * is the main config setting as the mode number is so hard to predict).
1723 */
1724 char szResolution[16];
1725 rc = pHlp->pfnCFGMQueryStringDef(pCfg, "GraphicsResolution", szResolution, sizeof(szResolution), "");
1726 if (RT_FAILURE(rc))
1727 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
1728 N_("Configuration error: Querying \"GraphicsResolution\" as a string failed"));
1729 if (szResolution[0])
1730 {
1731 const char *pszX = RTStrStr(szResolution, "x");
1732 if (pszX)
1733 {
1734 pThisCC->u32HorizontalResolution = RTStrToUInt32(szResolution);
1735 pThisCC->u32VerticalResolution = RTStrToUInt32(pszX + 1);
1736 }
1737 }
1738 else
1739 {
1740 /* get the legacy values if nothing else was specified */
1741 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "UgaHorizontalResolution", &pThisCC->u32HorizontalResolution, 0);
1742 AssertRCReturn(rc, rc);
1743 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "UgaVerticalResolution", &pThisCC->u32VerticalResolution, 0);
1744 AssertRCReturn(rc, rc);
1745 }
1746 if (pThisCC->u32HorizontalResolution == 0 || pThisCC->u32VerticalResolution == 0)
1747 {
1748 pThisCC->u32HorizontalResolution = 1024;
1749 pThisCC->u32VerticalResolution = 768;
1750 }
1751
1752 pThisCC->pszNvramFile = NULL;
1753 rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "NvramFile", &pThisCC->pszNvramFile);
1754 if (RT_FAILURE(rc) && rc != VERR_CFGM_VALUE_NOT_FOUND)
1755 return PDMDEV_SET_ERROR(pDevIns, rc,
1756 N_("Configuration error: Querying \"NvramFile\" as a string failed"));
1757
1758 /*
1759 * Load firmware volume and thunk ROM.
1760 */
1761 rc = efiLoadRom(pDevIns, pThis, pThisCC, pCfg);
1762 if (RT_FAILURE(rc))
1763 return rc;
1764
1765 /*
1766 * Register our I/O ports.
1767 */
1768 rc = PDMDevHlpIoPortCreateFlagsAndMap(pDevIns, EFI_PORT_BASE, EFI_PORT_COUNT, IOM_IOPORT_F_ABS,
1769 efiR3IoPortWrite, efiR3IoPortRead,
1770 "EFI communication ports", NULL /*paExtDescs*/, &pThis->hIoPorts);
1771 AssertRCReturn(rc, rc);
1772
1773 /*
1774 * Plant DMI and MPS tables in the ROM region.
1775 */
1776 rc = FwCommonPlantDMITable(pDevIns, pThisCC->au8DMIPage, VBOX_DMI_TABLE_SIZE, &pThisCC->aUuid,
1777 pDevIns->pCfg, pThisCC->cCpus, &pThisCC->cbDmiTables, &pThisCC->cNumDmiTables,
1778 true /*fUefi*/);
1779 AssertRCReturn(rc, rc);
1780
1781 /*
1782 * NB: VBox/Devices/EFI/Firmware/VBoxPkg/VBoxSysTables/VBoxSysTables.c scans memory for
1783 * the SMBIOS header. The header must be placed in a range that EFI will scan.
1784 */
1785 FwCommonPlantSmbiosAndDmiHdrs(pDevIns, pThisCC->au8DMIPage + VBOX_DMI_TABLE_SIZE,
1786 pThisCC->cbDmiTables, pThisCC->cNumDmiTables);
1787
1788 if (pThisCC->u8IOAPIC)
1789 {
1790 FwCommonPlantMpsTable(pDevIns,
1791 pThisCC->au8DMIPage /* aka VBOX_DMI_TABLE_BASE */ + VBOX_DMI_TABLE_SIZE + VBOX_DMI_HDR_SIZE,
1792 _4K - VBOX_DMI_TABLE_SIZE - VBOX_DMI_HDR_SIZE, pThisCC->cCpus);
1793 FwCommonPlantMpsFloatPtr(pDevIns, VBOX_DMI_TABLE_BASE + VBOX_DMI_TABLE_SIZE + VBOX_DMI_HDR_SIZE);
1794 }
1795
1796 rc = PDMDevHlpROMRegister(pDevIns, VBOX_DMI_TABLE_BASE, _4K, pThisCC->au8DMIPage, _4K,
1797 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "DMI tables");
1798
1799 AssertRCReturn(rc, rc);
1800
1801 /*
1802 * Call reset to set things up.
1803 */
1804 efiReset(pDevIns);
1805
1806 return VINF_SUCCESS;
1807}
1808
1809#else /* IN_RING3 */
1810
1811
1812/**
1813 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
1814 */
1815static DECLCALLBACK(int) efiRZConstruct(PPDMDEVINS pDevIns)
1816{
1817 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1818 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
1819
1820# if 1
1821 int rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmioFlash, efiR3NvMmioWrite, efiR3NvMmioRead, NULL /*pvUser*/);
1822 AssertRCReturn(rc, rc);
1823# else
1824 RT_NOREF(pDevIns, pThis); (void)&efiR3NvMmioRead; (void)&efiR3NvMmioWrite;
1825# endif
1826
1827 return VINF_SUCCESS;
1828}
1829
1830
1831#endif /* IN_RING3 */
1832
1833/**
1834 * The device registration structure.
1835 */
1836const PDMDEVREG g_DeviceEFI =
1837{
1838 /* .u32Version = */ PDM_DEVREG_VERSION,
1839 /* .uReserved0 = */ 0,
1840 /* .szName = */ "efi",
1841 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
1842 /* .fClass = */ PDM_DEVREG_CLASS_ARCH_BIOS,
1843 /* .cMaxInstances = */ 1,
1844 /* .uSharedVersion = */ 42,
1845 /* .cbInstanceShared = */ sizeof(DEVEFI),
1846 /* .cbInstanceCC = */ sizeof(DEVEFICC),
1847 /* .cbInstanceRC = */ sizeof(DEVEFIRC),
1848 /* .cMaxPciDevices = */ 0,
1849 /* .cMaxMsixVectors = */ 0,
1850 /* .pszDescription = */ "Extensible Firmware Interface Device.\n"
1851 "LUN#0 - NVRAM port",
1852#if defined(IN_RING3)
1853 /* .pszRCMod = */ "VBoxDDRC.rc",
1854 /* .pszR0Mod = */ "VBoxDDR0.r0",
1855 /* .pfnConstruct = */ efiConstruct,
1856 /* .pfnDestruct = */ efiDestruct,
1857 /* .pfnRelocate = */ NULL,
1858 /* .pfnMemSetup = */ efiMemSetup,
1859 /* .pfnPowerOn = */ NULL,
1860 /* .pfnReset = */ efiReset,
1861 /* .pfnSuspend = */ NULL,
1862 /* .pfnResume = */ NULL,
1863 /* .pfnAttach = */ NULL,
1864 /* .pfnDetach = */ NULL,
1865 /* .pfnQueryInterface = */ NULL,
1866 /* .pfnInitComplete = */ efiInitComplete,
1867 /* .pfnPowerOff = */ efiPowerOff,
1868 /* .pfnSoftReset = */ NULL,
1869 /* .pfnReserved0 = */ NULL,
1870 /* .pfnReserved1 = */ NULL,
1871 /* .pfnReserved2 = */ NULL,
1872 /* .pfnReserved3 = */ NULL,
1873 /* .pfnReserved4 = */ NULL,
1874 /* .pfnReserved5 = */ NULL,
1875 /* .pfnReserved6 = */ NULL,
1876 /* .pfnReserved7 = */ NULL,
1877#elif defined(IN_RING0)
1878 /* .pfnEarlyConstruct = */ NULL,
1879 /* .pfnConstruct = */ efiRZConstruct,
1880 /* .pfnDestruct = */ NULL,
1881 /* .pfnFinalDestruct = */ NULL,
1882 /* .pfnRequest = */ NULL,
1883 /* .pfnReserved0 = */ NULL,
1884 /* .pfnReserved1 = */ NULL,
1885 /* .pfnReserved2 = */ NULL,
1886 /* .pfnReserved3 = */ NULL,
1887 /* .pfnReserved4 = */ NULL,
1888 /* .pfnReserved5 = */ NULL,
1889 /* .pfnReserved6 = */ NULL,
1890 /* .pfnReserved7 = */ NULL,
1891#elif defined(IN_RC)
1892 /* .pfnConstruct = */ efiRZConstruct,
1893 /* .pfnReserved0 = */ NULL,
1894 /* .pfnReserved1 = */ NULL,
1895 /* .pfnReserved2 = */ NULL,
1896 /* .pfnReserved3 = */ NULL,
1897 /* .pfnReserved4 = */ NULL,
1898 /* .pfnReserved5 = */ NULL,
1899 /* .pfnReserved6 = */ NULL,
1900 /* .pfnReserved7 = */ NULL,
1901#else
1902# error "Not in IN_RING3, IN_RING0 or IN_RC!"
1903#endif
1904 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
1905};
1906
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use