VirtualBox

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

Last change on this file since 107139 was 107139, checked in by vboxsync, 8 weeks ago

Devices,Main,Installer,/Makefile.kmk: Take ARM EFI firmwares from the same build box as the x86 & amd64 ones (efi2). Renamed the firmware images and internal variables to include full arch (kbuild style) for x86 & amd64 as well. jiraref:VBP-1458

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

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