VirtualBox

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

Last change on this file since 98131 was 98131, checked in by vboxsync, 16 months ago

Devices/EFI: Make EFI produce a VMBootFail event if no guest could be booted, disables the EFI Shell as a default boot option (can still be selected from the boot manager), bugref:7249

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

© 2023 Oracle
ContactPrivacy policyTerms of Use