VirtualBox

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

Last change on this file since 108800 was 108800, checked in by vboxsync, 5 weeks ago

Devices/EFI: Prepare for more debug points, bugref:4643

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

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