VirtualBox

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

Last change on this file was 105042, checked in by vboxsync, 2 months ago

Devices/EFI/DevEFI: Add info item to convey the start of the PPI MMIO area to the firmware, bugref:10701

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

© 2024 Oracle
ContactPrivacy/Do Not Sell My InfoTerms of Use