VirtualBox

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

Last change on this file since 90943 was 90447, checked in by vboxsync, 4 years ago

Dev*: Checked up all the PDMDevHlpCritSectEnter calls to make sure the status code is checked. bugref:6695

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 103.1 KB
Line 
1/* $Id: DevEFI.cpp 90447 2021-07-31 00:44:13Z vboxsync $ */
2/** @file
3 * DevEFI - EFI <-> VirtualBox Integration Framework.
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DEV_EFI
23
24#include <VBox/vmm/pdmdev.h>
25#include <VBox/vmm/pgm.h>
26#include <VBox/vmm/cpum.h>
27#include <VBox/vmm/mm.h>
28#include <VBox/log.h>
29#include <VBox/err.h>
30#include <VBox/param.h>
31#include <VBox/vmm/dbgf.h>
32#include <VBox/vmm/pdmnvram.h>
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/ctype.h>
37#include <iprt/file.h>
38#include <iprt/mem.h>
39#include <iprt/string.h>
40#include <iprt/uuid.h>
41#include <iprt/path.h>
42#include <iprt/string.h>
43#include <iprt/mp.h>
44#include <iprt/list.h>
45#if defined(DEBUG) && defined(IN_RING3)
46# include <iprt/stream.h>
47# define DEVEFI_WITH_VBOXDBG_SCRIPT
48#endif
49#include <iprt/utf16.h>
50
51#include "DevEFI.h"
52#include "FlashCore.h"
53#include "VBoxDD.h"
54#include "VBoxDD2.h"
55#include "../PC/DevFwCommon.h"
56
57/* EFI includes */
58#ifdef IN_RING3
59# ifdef _MSC_VER
60# pragma warning(push)
61# pragma warning(disable:4668)
62# endif
63# include <ProcessorBind.h>
64# ifdef _MSC_VER
65# pragma warning(pop)
66# endif
67# include <Common/UefiBaseTypes.h>
68# include <Common/PiFirmwareVolume.h>
69# include <Common/PiFirmwareFile.h>
70#endif
71
72
73/*********************************************************************************************************************************
74* Structures and Typedefs *
75*********************************************************************************************************************************/
76/**
77 * EFI NVRAM variable.
78 */
79typedef struct EFIVAR
80{
81 /** The list node for the variable. */
82 RTLISTNODE ListNode;
83 /** The unique sequence number of the variable.
84 * This is used to find pCurVar when restoring saved state and therefore only
85 * set when saving. */
86 uint32_t idUniqueSavedState;
87 /** The value attributess. */
88 uint32_t fAttributes;
89 /** The variable name length (not counting the terminator char). */
90 uint32_t cchName;
91 /** The size of the value. This cannot be zero. */
92 uint32_t cbValue;
93 /** The vendor UUID scoping the variable name. */
94 RTUUID uuid;
95 /** The variable name. */
96 char szName[EFI_VARIABLE_NAME_MAX];
97 /** The variable value bytes. */
98 uint8_t abValue[EFI_VARIABLE_VALUE_MAX];
99} EFIVAR;
100/** Pointer to an EFI NVRAM variable. */
101typedef EFIVAR *PEFIVAR;
102/** Pointer to a const EFI NVRAM variable. */
103typedef EFIVAR const *PCEFIVAR;
104/** Pointer to an EFI NVRAM variable pointer. */
105typedef PEFIVAR *PPEFIVAR;
106
107/**
108 * NVRAM state.
109 */
110typedef struct NVRAMDESC
111{
112 /** The current operation. */
113 EFIVAROP enmOp;
114 /** The current status. */
115 uint32_t u32Status;
116 /** The current */
117 uint32_t offOpBuffer;
118 /** The current number of variables. */
119 uint32_t cVariables;
120 /** The list of variables. */
121 RTLISTANCHOR VarList;
122
123 /** The unique variable sequence ID, for the saved state only.
124 * @todo It's part of this structure for hysterical raisins, consider remove it
125 * when changing the saved state format the next time. */
126 uint32_t idUniqueCurVar;
127 /** Variable buffered used both when adding and querying NVRAM variables.
128 * When querying a variable, a copy of it is stored in this buffer and read
129 * from it. When adding, updating or deleting a variable, this buffer is used
130 * to set up the parameters before taking action. */
131 EFIVAR VarOpBuf;
132 /** The current variable. This is only used by EFI_VARIABLE_OP_QUERY_NEXT,
133 * the attribute readers work against the copy in VarOpBuf. */
134 PEFIVAR pCurVar;
135} NVRAMDESC;
136
137
138/**
139 * The EFI device shared state structure.
140 */
141typedef struct DEVEFI
142{
143 /** The flash device containing the NVRAM. */
144 FLASHCORE Flash;
145 /** The 8 I/O ports at 0xEF10 (EFI_PORT_BASE). */
146 IOMIOPORTHANDLE hIoPorts;
147 /** The flash MMIO handle. */
148 IOMMMIOHANDLE hMmioFlash;
149} DEVEFI;
150/** Pointer to the shared EFI state. */
151typedef DEVEFI *PDEVEFI;
152
153/**
154 * The EFI device state structure for ring-3.
155 */
156typedef struct DEVEFIR3
157{
158 /** Pointer back to the device instance. */
159 PPDMDEVINS pDevIns;
160
161 /** EFI message buffer. */
162 char szMsg[VBOX_EFI_DEBUG_BUFFER];
163 /** EFI message buffer index. */
164 uint32_t iMsg;
165
166 /** EFI panic message buffer. */
167 char szPanicMsg[2048];
168 /** EFI panic message buffer index. */
169 uint32_t iPanicMsg;
170
171 struct
172 {
173 /** The current/last image event. */
174 uint8_t uEvt;
175 /** Module path/name offset. */
176 uint8_t offName;
177 /** The offset of the last component in the module path/name. */
178 uint8_t offNameLastComponent;
179 /** Alignment padding. */
180 uint8_t abPadding[5];
181 /** First address associated with the event (image address). */
182 uint64_t uAddr0;
183 /** Second address associated with the event (old image address). */
184 uint64_t uAddr1;
185 /** The size associated with the event (0 if none). */
186 uint64_t cb0;
187 /** The module name. */
188 char szName[256];
189 } ImageEvt;
190
191 /** The system EFI ROM data. */
192 uint8_t const *pu8EfiRom;
193 /** The system EFI ROM data pointer to be passed to RTFileReadAllFree. */
194 uint8_t *pu8EfiRomFree;
195 /** The size of the system EFI ROM. */
196 uint64_t cbEfiRom;
197 /** Offset into the actual ROM within EFI FW volume. */
198 uint64_t offEfiRom;
199 /** The name of the EFI ROM file. */
200 char *pszEfiRomFile;
201 /** Thunk page pointer. */
202 uint8_t *pu8EfiThunk;
203 /** First entry point of the EFI firmware. */
204 RTGCPHYS GCEntryPoint0;
205 /** Second Entry Point (PeiCore)*/
206 RTGCPHYS GCEntryPoint1;
207 /** EFI firmware physical load address. */
208 RTGCPHYS GCLoadAddress;
209 /** Current info selector. */
210 uint32_t iInfoSelector;
211 /** Current info position. */
212 int32_t offInfo;
213
214 /** Number of virtual CPUs. (Config) */
215 uint32_t cCpus;
216
217 /** The size of the DMI tables. */
218 uint16_t cbDmiTables;
219 /** Number of the DMI tables. */
220 uint16_t cNumDmiTables;
221 /** The DMI tables. */
222 uint8_t au8DMIPage[0x1000];
223
224 /** I/O-APIC enabled? */
225 uint8_t u8IOAPIC;
226
227 /** APIC mode to be set up by firmware. */
228 uint8_t u8APIC;
229
230 /** Boot parameters passed to the firmware. */
231 char szBootArgs[256];
232
233 /** Host UUID (for DMI). */
234 RTUUID aUuid;
235
236 /** Device properties buffer. */
237 R3PTRTYPE(uint8_t *) pbDeviceProps;
238 /** Device properties buffer size. */
239 uint32_t cbDeviceProps;
240
241 /** Virtual machine front side bus frequency. */
242 uint64_t u64FsbFrequency;
243 /** Virtual machine time stamp counter frequency. */
244 uint64_t u64TscFrequency;
245 /** Virtual machine CPU frequency. */
246 uint64_t u64CpuFrequency;
247 /** EFI Graphics mode (used as fallback if resolution is not known). */
248 uint32_t u32GraphicsMode;
249 /** EFI Graphics (GOP or UGA) horizontal resolution. */
250 uint32_t u32HorizontalResolution;
251 /** EFI Graphics (GOP or UGA) vertical resolution. */
252 uint32_t u32VerticalResolution;
253 /** Physical address of PCI config space MMIO region */
254 uint64_t u64McfgBase;
255 /** Length of PCI config space MMIO region */
256 uint64_t cbMcfgLength;
257 /** Size of the configured NVRAM device. */
258 uint32_t cbNvram;
259 /** Start address of the NVRAM flash. */
260 RTGCPHYS GCPhysNvram;
261
262 /** NVRAM state variables. */
263 NVRAMDESC NVRAM;
264 /** Filename of the file containing the NVRAM store. */
265 char *pszNvramFile;
266
267 /**
268 * NVRAM port - LUN\#0.
269 */
270 struct
271 {
272 /** The base interface we provide the NVRAM driver. */
273 PDMIBASE IBase;
274 /** The NVRAM driver base interface. */
275 PPDMIBASE pDrvBase;
276 /** The NVRAM interface provided by the driver. */
277 PPDMINVRAMCONNECTOR pNvramDrv;
278 } Lun0;
279} DEVEFIR3;
280/** Pointer to the ring-3 EFI state. */
281typedef DEVEFIR3 *PDEVEFIR3;
282
283
284/**
285 * The EFI device state structure for ring-0.
286 */
287typedef struct DEVEFIR0
288{
289 uint32_t uEmpty;
290} DEVEFIR0;
291/** Pointer to the ring-0 EFI state. */
292typedef DEVEFIR0 *PDEVEFIR0;
293
294
295/**
296 * The EFI device state structure for raw-mode.
297 */
298typedef struct DEVEFIRC
299{
300 uint32_t uEmpty;
301} DEVEFIRC;
302/** Pointer to the raw-mode EFI state. */
303typedef DEVEFIRC *PDEVEFIRC;
304
305
306/** @typedef DEVEFICC
307 * The instance data for the current context. */
308/** @typedef PDEVEFICC
309 * Pointer to the instance data for the current context. */
310#ifdef IN_RING3
311typedef DEVEFIR3 DEVEFICC;
312typedef PDEVEFIR3 PDEVEFICC;
313#elif defined(IN_RING0)
314typedef DEVEFIR0 DEVEFICC;
315typedef PDEVEFIR0 PDEVEFICC;
316#elif defined(IN_RC)
317typedef DEVEFIRC DEVEFICC;
318typedef PDEVEFIRC PDEVEFICC;
319#else
320# error "Not IN_RING3, IN_RING0 or IN_RC"
321#endif
322
323
324/*********************************************************************************************************************************
325* Defined Constants And Macros *
326*********************************************************************************************************************************/
327/** The saved state version. */
328#define EFI_SSM_VERSION 3
329/** The saved state version before working NVRAM support was implemented. */
330#define EFI_SSM_VERSION_PRE_PROPER_NVRAM 2
331/** The saved state version from VBox 4.2. */
332#define EFI_SSM_VERSION_4_2 1
333
334/** Non-volatile EFI variable. */
335#define VBOX_EFI_VARIABLE_NON_VOLATILE UINT32_C(0x00000001)
336/** Non-volatile EFI variable. */
337#define VBOX_EFI_VARIABLE_READ_ONLY UINT32_C(0x00000008)
338
339
340/*********************************************************************************************************************************
341* Global Variables *
342*********************************************************************************************************************************/
343#ifdef IN_RING3
344/** Saved state NVRAMDESC field descriptors. */
345static SSMFIELD const g_aEfiNvramDescField[] =
346{
347 SSMFIELD_ENTRY( NVRAMDESC, enmOp),
348 SSMFIELD_ENTRY( NVRAMDESC, u32Status),
349 SSMFIELD_ENTRY( NVRAMDESC, offOpBuffer),
350 SSMFIELD_ENTRY_IGNORE(NVRAMDESC, VarOpBuf),
351 SSMFIELD_ENTRY( NVRAMDESC, cVariables),
352 SSMFIELD_ENTRY_OLD( idUnquireLast, 4),
353 SSMFIELD_ENTRY_IGNORE(NVRAMDESC, VarList),
354 SSMFIELD_ENTRY( NVRAMDESC, idUniqueCurVar),
355 SSMFIELD_ENTRY_IGNORE(NVRAMDESC, pCurVar),
356 SSMFIELD_ENTRY_TERM()
357};
358
359/** Saved state EFIVAR field descriptors. */
360static SSMFIELD const g_aEfiVariableDescFields[] =
361{
362 SSMFIELD_ENTRY_IGNORE(EFIVAR, ListNode),
363 SSMFIELD_ENTRY( EFIVAR, idUniqueSavedState),
364 SSMFIELD_ENTRY( EFIVAR, uuid),
365 SSMFIELD_ENTRY( EFIVAR, szName),
366 SSMFIELD_ENTRY_OLD( cchName, 4),
367 SSMFIELD_ENTRY( EFIVAR, abValue),
368 SSMFIELD_ENTRY( EFIVAR, cbValue),
369 SSMFIELD_ENTRY( EFIVAR, fAttributes),
370 SSMFIELD_ENTRY_TERM()
371};
372
373/** The EfiSystemNvDataFv GUID for NVRAM storage. */
374static const RTUUID g_UuidNvDataFv = { { 0x8d, 0x2b, 0xf1, 0xff, 0x96, 0x76, 0x8b, 0x4c, 0xa9, 0x85, 0x27, 0x47, 0x07, 0x5b, 0x4f, 0x50} };
375
376# ifdef VBOX_WITH_EFI_IN_DD2
377/** Special file name value for indicating the 32-bit built-in EFI firmware. */
378static const char g_szEfiBuiltin32[] = "VBoxEFI32.fd";
379/** Special file name value for indicating the 64-bit built-in EFI firmware. */
380static const char g_szEfiBuiltin64[] = "VBoxEFI64.fd";
381# endif
382#endif /* IN_RING3 */
383
384
385#ifdef IN_RING3
386
387/**
388 * Flushes the variable list.
389 *
390 * @param pThisCC The EFI state for the current context.
391 */
392static void nvramFlushDeviceVariableList(PDEVEFIR3 pThisCC)
393{
394 while (!RTListIsEmpty(&pThisCC->NVRAM.VarList))
395 {
396 PEFIVAR pEfiVar = RTListNodeGetNext(&pThisCC->NVRAM.VarList, EFIVAR, ListNode);
397 RTListNodeRemove(&pEfiVar->ListNode);
398 RTMemFree(pEfiVar);
399 }
400
401 pThisCC->NVRAM.pCurVar = NULL;
402}
403
404/**
405 * This function looks up variable in NVRAM list.
406 */
407static int nvramLookupVariableByUuidAndName(PDEVEFIR3 pThisCC, char *pszVariableName, PCRTUUID pUuid, PPEFIVAR ppEfiVar)
408{
409 LogFlowFunc(("%RTuuid::'%s'\n", pUuid, pszVariableName));
410 size_t const cchVariableName = strlen(pszVariableName);
411 int rc = VERR_NOT_FOUND;
412
413 /*
414 * Start by checking the last variable queried.
415 */
416 if ( pThisCC->NVRAM.pCurVar
417 && pThisCC->NVRAM.pCurVar->cchName == cchVariableName
418 && memcmp(pThisCC->NVRAM.pCurVar->szName, pszVariableName, cchVariableName + 1) == 0
419 && RTUuidCompare(&pThisCC->NVRAM.pCurVar->uuid, pUuid) == 0
420 )
421 {
422 *ppEfiVar = pThisCC->NVRAM.pCurVar;
423 rc = VINF_SUCCESS;
424 }
425 else
426 {
427 /*
428 * Linear list search.
429 */
430 PEFIVAR pEfiVar;
431 RTListForEach(&pThisCC->NVRAM.VarList, pEfiVar, EFIVAR, ListNode)
432 {
433 Assert(strlen(pEfiVar->szName) == pEfiVar->cchName);
434 if ( pEfiVar->cchName == cchVariableName
435 && memcmp(pEfiVar->szName, pszVariableName, cchVariableName + 1) == 0
436 && RTUuidCompare(&pEfiVar->uuid, pUuid) == 0)
437 {
438 *ppEfiVar = pEfiVar;
439 rc = VINF_SUCCESS;
440 break;
441 }
442 }
443 }
444
445 LogFlowFunc(("rc=%Rrc pEfiVar=%p\n", rc, *ppEfiVar));
446 return rc;
447}
448
449
450/**
451 * Inserts the EFI variable into the list.
452 *
453 * This enforces the desired list ordering and/or insertion policy.
454 *
455 * @param pThisCC The EFI state for the current context.
456 * @param pEfiVar The variable to insert.
457 */
458static void nvramInsertVariable(PDEVEFIR3 pThisCC, PEFIVAR pEfiVar)
459{
460#if 1
461 /*
462 * Sorted by UUID and name.
463 */
464 PEFIVAR pCurVar;
465 RTListForEach(&pThisCC->NVRAM.VarList, pCurVar, EFIVAR, ListNode)
466 {
467 int iDiff = RTUuidCompare(&pEfiVar->uuid, &pCurVar->uuid);
468 if (!iDiff)
469 iDiff = strcmp(pEfiVar->szName, pCurVar->szName);
470 if (iDiff < 0)
471 {
472 RTListNodeInsertBefore(&pCurVar->ListNode, &pEfiVar->ListNode);
473 return;
474 }
475 }
476#endif
477
478 /*
479 * Add it at the end.
480 */
481 RTListAppend(&pThisCC->NVRAM.VarList, &pEfiVar->ListNode);
482}
483
484
485/**
486 * Creates an device internal list of variables.
487 *
488 * @returns VBox status code.
489 * @param pThisCC The EFI state for the current context.
490 */
491static int nvramLoad(PDEVEFIR3 pThisCC)
492{
493 int rc;
494 for (uint32_t iVar = 0; iVar < EFI_VARIABLE_MAX; iVar++)
495 {
496 PEFIVAR pEfiVar = (PEFIVAR)RTMemAllocZ(sizeof(EFIVAR));
497 AssertReturn(pEfiVar, VERR_NO_MEMORY);
498
499 pEfiVar->cchName = sizeof(pEfiVar->szName);
500 pEfiVar->cbValue = sizeof(pEfiVar->abValue);
501 rc = pThisCC->Lun0.pNvramDrv->pfnVarQueryByIndex(pThisCC->Lun0.pNvramDrv, iVar,
502 &pEfiVar->uuid, &pEfiVar->szName[0], &pEfiVar->cchName,
503 &pEfiVar->fAttributes, &pEfiVar->abValue[0], &pEfiVar->cbValue);
504 if (RT_SUCCESS(rc))
505 {
506 /* Some validations. */
507 rc = RTStrValidateEncoding(pEfiVar->szName);
508 size_t cchName = RTStrNLen(pEfiVar->szName, sizeof(pEfiVar->szName));
509 if (cchName != pEfiVar->cchName)
510 rc = VERR_INVALID_PARAMETER;
511 if (pEfiVar->cbValue == 0)
512 rc = VERR_NO_DATA;
513 if (RT_FAILURE(rc))
514 LogRel(("EFI/nvramLoad: Bad variable #%u: cbValue=%#x cchName=%#x (strlen=%#x) szName=%.*Rhxs\n",
515 iVar, pEfiVar->cbValue, pEfiVar->cchName, cchName, pEfiVar->cchName + 1, pEfiVar->szName));
516 }
517 if (RT_FAILURE(rc))
518 {
519 RTMemFree(pEfiVar);
520 if (rc == VERR_NOT_FOUND)
521 rc = VINF_SUCCESS;
522 AssertRC(rc);
523 return rc;
524 }
525
526 /* Append it. */
527 nvramInsertVariable(pThisCC, pEfiVar);
528 pThisCC->NVRAM.cVariables++;
529 }
530
531 AssertLogRelMsgFailed(("EFI: Too many variables.\n"));
532 return VERR_TOO_MUCH_DATA;
533}
534
535
536/**
537 * Let the NVRAM driver store the internal NVRAM variable list.
538 *
539 * @returns VBox status code.
540 * @param pThisCC The EFI state for the current context.
541 */
542static int nvramStore(PDEVEFIR3 pThisCC)
543{
544 /*
545 * Count the non-volatile variables and issue the begin call.
546 */
547 PEFIVAR pEfiVar;
548 uint32_t cNonVolatile = 0;
549 RTListForEach(&pThisCC->NVRAM.VarList, pEfiVar, EFIVAR, ListNode)
550 if (pEfiVar->fAttributes & VBOX_EFI_VARIABLE_NON_VOLATILE)
551 cNonVolatile++;
552 int rc = pThisCC->Lun0.pNvramDrv->pfnVarStoreSeqBegin(pThisCC->Lun0.pNvramDrv, cNonVolatile);
553 if (RT_SUCCESS(rc))
554 {
555 /*
556 * Store each non-volatile variable.
557 */
558 uint32_t idxVar = 0;
559 RTListForEach(&pThisCC->NVRAM.VarList, pEfiVar, EFIVAR, ListNode)
560 {
561 /* Skip volatile variables. */
562 if (!(pEfiVar->fAttributes & VBOX_EFI_VARIABLE_NON_VOLATILE))
563 continue;
564
565 int rc2 = pThisCC->Lun0.pNvramDrv->pfnVarStoreSeqPut(pThisCC->Lun0.pNvramDrv, idxVar,
566 &pEfiVar->uuid, pEfiVar->szName, pEfiVar->cchName,
567 pEfiVar->fAttributes, pEfiVar->abValue, pEfiVar->cbValue);
568 if (RT_FAILURE(rc2) && RT_SUCCESS_NP(rc))
569 {
570 LogRel(("EFI: pfnVarStoreVarByIndex failed: %Rrc\n", rc));
571 rc = rc2;
572 }
573 idxVar++;
574 }
575 Assert(idxVar == cNonVolatile);
576
577 /*
578 * Done.
579 */
580 rc = pThisCC->Lun0.pNvramDrv->pfnVarStoreSeqEnd(pThisCC->Lun0.pNvramDrv, rc);
581 }
582 else
583 LogRel(("EFI: pfnVarStoreBegin failed: %Rrc\n", rc));
584 return rc;
585}
586
587/**
588 * EFI_VARIABLE_OP_QUERY and EFI_VARIABLE_OP_QUERY_NEXT worker that copies the
589 * variable into the VarOpBuf, set pCurVar and u32Status.
590 *
591 * @param pThisCC The EFI state for the current context.
592 * @param pEfiVar The resulting variable. NULL if not found / end.
593 * @param fEnumQuery Set if enumeration query, clear if specific.
594 */
595static void nvramWriteVariableOpQueryCopyResult(PDEVEFIR3 pThisCC, PEFIVAR pEfiVar, bool fEnumQuery)
596{
597 RT_ZERO(pThisCC->NVRAM.VarOpBuf.abValue);
598 if (pEfiVar)
599 {
600 RT_ZERO(pThisCC->NVRAM.VarOpBuf.szName);
601 pThisCC->NVRAM.VarOpBuf.uuid = pEfiVar->uuid;
602 pThisCC->NVRAM.VarOpBuf.cchName = pEfiVar->cchName;
603 memcpy(pThisCC->NVRAM.VarOpBuf.szName, pEfiVar->szName, pEfiVar->cchName); /* no need for + 1. */
604 pThisCC->NVRAM.VarOpBuf.fAttributes = pEfiVar->fAttributes;
605 pThisCC->NVRAM.VarOpBuf.cbValue = pEfiVar->cbValue;
606 memcpy(pThisCC->NVRAM.VarOpBuf.abValue, pEfiVar->abValue, pEfiVar->cbValue);
607 pThisCC->NVRAM.pCurVar = pEfiVar;
608 pThisCC->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
609 LogFlow(("EFI: Variable query -> %RTuuid::'%s' (%d) abValue=%.*Rhxs\n", &pThisCC->NVRAM.VarOpBuf.uuid,
610 pThisCC->NVRAM.VarOpBuf.szName, pThisCC->NVRAM.VarOpBuf.cchName,
611 pThisCC->NVRAM.VarOpBuf.cbValue, pThisCC->NVRAM.VarOpBuf.abValue));
612 }
613 else
614 {
615 if (fEnumQuery)
616 LogFlow(("EFI: Variable query -> NOT_FOUND \n"));
617 else
618 LogFlow(("EFI: Variable query %RTuuid::'%s' -> NOT_FOUND \n",
619 &pThisCC->NVRAM.VarOpBuf.uuid, pThisCC->NVRAM.VarOpBuf.szName));
620 RT_ZERO(pThisCC->NVRAM.VarOpBuf.szName);
621 pThisCC->NVRAM.VarOpBuf.fAttributes = 0;
622 pThisCC->NVRAM.VarOpBuf.cbValue = 0;
623 pThisCC->NVRAM.VarOpBuf.cchName = 0;
624 pThisCC->NVRAM.pCurVar = NULL;
625 pThisCC->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_NOT_FOUND;
626 }
627}
628
629/**
630 * Implements EFI_VARIABLE_PARAM + EFI_VARIABLE_OP_QUERY.
631 *
632 * @returns IOM strict status code.
633 * @param pThisCC The EFI state for the current context.
634 */
635static int nvramWriteVariableOpQuery(PDEVEFIR3 pThisCC)
636{
637 Log(("EFI_VARIABLE_OP_QUERY: %RTuuid::'%s'\n", &pThisCC->NVRAM.VarOpBuf.uuid, pThisCC->NVRAM.VarOpBuf.szName));
638
639 PEFIVAR pEfiVar;
640 int rc = nvramLookupVariableByUuidAndName(pThisCC,
641 pThisCC->NVRAM.VarOpBuf.szName,
642 &pThisCC->NVRAM.VarOpBuf.uuid,
643 &pEfiVar);
644 nvramWriteVariableOpQueryCopyResult(pThisCC, RT_SUCCESS(rc) ? pEfiVar : NULL, false /*fEnumQuery*/);
645 return VINF_SUCCESS;
646}
647
648/**
649 * Implements EFI_VARIABLE_PARAM + EFI_VARIABLE_OP_QUERY_NEXT.
650 *
651 * This simply walks the list.
652 *
653 * @returns IOM strict status code.
654 * @param pThisCC The EFI state for the current context.
655 */
656static int nvramWriteVariableOpQueryNext(PDEVEFIR3 pThisCC)
657{
658 Log(("EFI_VARIABLE_OP_QUERY_NEXT: pCurVar=%p\n", pThisCC->NVRAM.pCurVar));
659 PEFIVAR pEfiVar = pThisCC->NVRAM.pCurVar;
660 if (pEfiVar)
661 pEfiVar = RTListGetNext(&pThisCC->NVRAM.VarList, pEfiVar, EFIVAR, ListNode);
662 else
663 pEfiVar = RTListGetFirst(&pThisCC->NVRAM.VarList, EFIVAR, ListNode);
664 nvramWriteVariableOpQueryCopyResult(pThisCC, pEfiVar, true /* fEnumQuery */);
665 return VINF_SUCCESS;
666}
667
668/**
669 * Implements EFI_VARIABLE_PARAM + EFI_VARIABLE_OP_ADD.
670 *
671 * @returns IOM strict status code.
672 * @param pThisCC The EFI state for the current context.
673 */
674static int nvramWriteVariableOpAdd(PDEVEFIR3 pThisCC)
675{
676 Log(("EFI_VARIABLE_OP_ADD: %RTuuid::'%s' fAttributes=%#x abValue=%.*Rhxs\n",
677 &pThisCC->NVRAM.VarOpBuf.uuid, pThisCC->NVRAM.VarOpBuf.szName, pThisCC->NVRAM.VarOpBuf.fAttributes,
678 pThisCC->NVRAM.VarOpBuf.cbValue, pThisCC->NVRAM.VarOpBuf.abValue));
679
680 /*
681 * Validate and adjust the input a little before we start.
682 */
683 int rc = RTStrValidateEncoding(pThisCC->NVRAM.VarOpBuf.szName);
684 if (RT_FAILURE(rc))
685 LogRel(("EFI: Badly encoded variable name: %.*Rhxs\n", pThisCC->NVRAM.VarOpBuf.cchName + 1, pThisCC->NVRAM.VarOpBuf.szName));
686 if (RT_FAILURE(rc))
687 {
688 pThisCC->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
689 return VINF_SUCCESS;
690 }
691 pThisCC->NVRAM.VarOpBuf.cchName = (uint32_t)RTStrNLen(pThisCC->NVRAM.VarOpBuf.szName, sizeof(pThisCC->NVRAM.VarOpBuf.szName));
692
693 /*
694 * Look it up and see what to do.
695 */
696 PEFIVAR pEfiVar;
697 rc = nvramLookupVariableByUuidAndName(pThisCC,
698 pThisCC->NVRAM.VarOpBuf.szName,
699 &pThisCC->NVRAM.VarOpBuf.uuid,
700 &pEfiVar);
701 if (RT_SUCCESS(rc))
702 {
703 LogFlowFunc(("Old abValue=%.*Rhxs\n", pEfiVar->cbValue, pEfiVar->abValue));
704#if 0 /** @todo Implement read-only EFI variables. */
705 if (pEfiVar->fAttributes & EFI_VARIABLE_XXXXXXX)
706 {
707 pThisCC->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_RO;
708 break;
709 }
710#endif
711
712 if (pThisCC->NVRAM.VarOpBuf.cbValue == 0)
713 {
714 /*
715 * Delete it.
716 */
717 LogRel(("EFI: Deleting variable %RTuuid::'%s'\n", &pThisCC->NVRAM.VarOpBuf.uuid, pThisCC->NVRAM.VarOpBuf.szName));
718 RTListNodeRemove(&pEfiVar->ListNode);
719 pThisCC->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
720 pThisCC->NVRAM.cVariables--;
721
722 if (pThisCC->NVRAM.pCurVar == pEfiVar)
723 pThisCC->NVRAM.pCurVar = NULL;
724 RTMemFree(pEfiVar);
725 pEfiVar = NULL;
726 }
727 else
728 {
729 /*
730 * Update/replace it. (The name and UUID are unchanged, of course.)
731 */
732 LogRel(("EFI: Replacing variable %RTuuid::'%s' fAttrib=%#x cbValue=%#x\n", &pThisCC->NVRAM.VarOpBuf.uuid,
733 pThisCC->NVRAM.VarOpBuf.szName, pThisCC->NVRAM.VarOpBuf.fAttributes, pThisCC->NVRAM.VarOpBuf.cbValue));
734 pEfiVar->fAttributes = pThisCC->NVRAM.VarOpBuf.fAttributes;
735 pEfiVar->cbValue = pThisCC->NVRAM.VarOpBuf.cbValue;
736 memcpy(pEfiVar->abValue, pThisCC->NVRAM.VarOpBuf.abValue, pEfiVar->cbValue);
737 pThisCC->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
738 }
739 }
740 else if (pThisCC->NVRAM.VarOpBuf.cbValue == 0)
741 {
742 /* delete operation, but nothing to delete. */
743 LogFlow(("nvramWriteVariableOpAdd: Delete (not found)\n"));
744 pThisCC->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
745 }
746 else if (pThisCC->NVRAM.cVariables < EFI_VARIABLE_MAX)
747 {
748 /*
749 * Add a new variable.
750 */
751 LogRel(("EFI: Adding variable %RTuuid::'%s' fAttrib=%#x cbValue=%#x\n", &pThisCC->NVRAM.VarOpBuf.uuid,
752 pThisCC->NVRAM.VarOpBuf.szName, pThisCC->NVRAM.VarOpBuf.fAttributes, pThisCC->NVRAM.VarOpBuf.cbValue));
753 pEfiVar = (PEFIVAR)RTMemAllocZ(sizeof(EFIVAR));
754 if (pEfiVar)
755 {
756 pEfiVar->uuid = pThisCC->NVRAM.VarOpBuf.uuid;
757 pEfiVar->cchName = pThisCC->NVRAM.VarOpBuf.cchName;
758 memcpy(pEfiVar->szName, pThisCC->NVRAM.VarOpBuf.szName, pEfiVar->cchName); /* The buffer is zeroed, so skip '\0'. */
759 pEfiVar->fAttributes = pThisCC->NVRAM.VarOpBuf.fAttributes;
760 pEfiVar->cbValue = pThisCC->NVRAM.VarOpBuf.cbValue;
761 memcpy(pEfiVar->abValue, pThisCC->NVRAM.VarOpBuf.abValue, pEfiVar->cbValue);
762
763 nvramInsertVariable(pThisCC, pEfiVar);
764 pThisCC->NVRAM.cVariables++;
765 pThisCC->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
766 }
767 else
768 pThisCC->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
769 }
770 else
771 {
772 /*
773 * Too many variables.
774 */
775 LogRelMax(5, ("EFI: Too many variables (%RTuuid::'%s' fAttrib=%#x cbValue=%#x)\n", &pThisCC->NVRAM.VarOpBuf.uuid,
776 pThisCC->NVRAM.VarOpBuf.szName, pThisCC->NVRAM.VarOpBuf.fAttributes, pThisCC->NVRAM.VarOpBuf.cbValue));
777 pThisCC->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
778 Log(("nvramWriteVariableOpAdd: Too many variabled.\n"));
779 }
780
781 /*
782 * Log the value of bugcheck variables.
783 */
784 if ( ( pThisCC->NVRAM.VarOpBuf.cbValue == 4
785 || pThisCC->NVRAM.VarOpBuf.cbValue == 8)
786 && ( strcmp(pThisCC->NVRAM.VarOpBuf.szName, "BugCheckCode") == 0
787 || strcmp(pThisCC->NVRAM.VarOpBuf.szName, "BugCheckParameter0") == 0
788 || strcmp(pThisCC->NVRAM.VarOpBuf.szName, "BugCheckParameter1") == 0
789 || strcmp(pThisCC->NVRAM.VarOpBuf.szName, "BugCheckParameter2") == 0
790 || strcmp(pThisCC->NVRAM.VarOpBuf.szName, "BugCheckParameter3") == 0
791 || strcmp(pThisCC->NVRAM.VarOpBuf.szName, "BugCheckProgress") == 0 ) )
792 {
793 if (pThisCC->NVRAM.VarOpBuf.cbValue == 4)
794 LogRel(("EFI: %RTuuid::'%s' = %#010RX32\n", &pThisCC->NVRAM.VarOpBuf.uuid, pThisCC->NVRAM.VarOpBuf.szName,
795 RT_MAKE_U32_FROM_U8(pThisCC->NVRAM.VarOpBuf.abValue[0], pThisCC->NVRAM.VarOpBuf.abValue[1],
796 pThisCC->NVRAM.VarOpBuf.abValue[2], pThisCC->NVRAM.VarOpBuf.abValue[3])));
797 else
798 LogRel(("EFI: %RTuuid::'%s' = %#018RX64\n", &pThisCC->NVRAM.VarOpBuf.uuid, pThisCC->NVRAM.VarOpBuf.szName,
799 RT_MAKE_U64_FROM_U8(pThisCC->NVRAM.VarOpBuf.abValue[0], pThisCC->NVRAM.VarOpBuf.abValue[1],
800 pThisCC->NVRAM.VarOpBuf.abValue[2], pThisCC->NVRAM.VarOpBuf.abValue[3],
801 pThisCC->NVRAM.VarOpBuf.abValue[4], pThisCC->NVRAM.VarOpBuf.abValue[5],
802 pThisCC->NVRAM.VarOpBuf.abValue[6], pThisCC->NVRAM.VarOpBuf.abValue[7])));
803 }
804
805
806 LogFunc(("cVariables=%u u32Status=%#x\n", pThisCC->NVRAM.cVariables, pThisCC->NVRAM.u32Status));
807 return VINF_SUCCESS;
808}
809
810/**
811 * Implements EFI_VARIABLE_PARAM writes.
812 *
813 * @returns IOM strict status code.
814 * @param pThisCC The EFI state for the current context.
815 * @param u32Value The value being written.
816 */
817static int nvramWriteVariableParam(PDEVEFIR3 pThisCC, uint32_t u32Value)
818{
819 int rc = VINF_SUCCESS;
820 switch (pThisCC->NVRAM.enmOp)
821 {
822 case EFI_VM_VARIABLE_OP_START:
823 switch (u32Value)
824 {
825 case EFI_VARIABLE_OP_QUERY:
826 rc = nvramWriteVariableOpQuery(pThisCC);
827 break;
828
829 case EFI_VARIABLE_OP_QUERY_NEXT:
830 rc = nvramWriteVariableOpQueryNext(pThisCC);
831 break;
832
833 case EFI_VARIABLE_OP_QUERY_REWIND:
834 Log2(("EFI_VARIABLE_OP_QUERY_REWIND\n"));
835 pThisCC->NVRAM.pCurVar = NULL;
836 pThisCC->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
837 break;
838
839 case EFI_VARIABLE_OP_ADD:
840 rc = nvramWriteVariableOpAdd(pThisCC);
841 break;
842
843 default:
844 pThisCC->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
845 LogRel(("EFI: Unknown EFI_VM_VARIABLE_OP_START value %#x\n", u32Value));
846 break;
847 }
848 break;
849
850 case EFI_VM_VARIABLE_OP_GUID:
851 Log2(("EFI_VM_VARIABLE_OP_GUID[%#x]=%#x\n", pThisCC->NVRAM.offOpBuffer, u32Value));
852 if (pThisCC->NVRAM.offOpBuffer < sizeof(pThisCC->NVRAM.VarOpBuf.uuid))
853 pThisCC->NVRAM.VarOpBuf.uuid.au8[pThisCC->NVRAM.offOpBuffer++] = (uint8_t)u32Value;
854 else
855 {
856 LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_GUID write (%#x).\n", u32Value));
857 pThisCC->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
858 }
859 break;
860
861 case EFI_VM_VARIABLE_OP_ATTRIBUTE:
862 Log2(("EFI_VM_VARIABLE_OP_ATTRIBUTE=%#x\n", u32Value));
863 pThisCC->NVRAM.VarOpBuf.fAttributes = u32Value;
864 break;
865
866 case EFI_VM_VARIABLE_OP_NAME:
867 Log2(("EFI_VM_VARIABLE_OP_NAME[%#x]=%#x\n", pThisCC->NVRAM.offOpBuffer, u32Value));
868 if (pThisCC->NVRAM.offOpBuffer < pThisCC->NVRAM.VarOpBuf.cchName)
869 pThisCC->NVRAM.VarOpBuf.szName[pThisCC->NVRAM.offOpBuffer++] = (uint8_t)u32Value;
870 else if (u32Value == 0)
871 Assert(pThisCC->NVRAM.VarOpBuf.szName[sizeof(pThisCC->NVRAM.VarOpBuf.szName) - 1] == 0);
872 else
873 {
874 LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_NAME write (%#x).\n", u32Value));
875 pThisCC->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
876 }
877 break;
878
879 case EFI_VM_VARIABLE_OP_NAME_LENGTH:
880 Log2(("EFI_VM_VARIABLE_OP_NAME_LENGTH=%#x\n", u32Value));
881 RT_ZERO(pThisCC->NVRAM.VarOpBuf.szName);
882 if (u32Value < sizeof(pThisCC->NVRAM.VarOpBuf.szName))
883 pThisCC->NVRAM.VarOpBuf.cchName = u32Value;
884 else
885 {
886 LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_NAME_LENGTH write (%#x, max %#x).\n",
887 u32Value, sizeof(pThisCC->NVRAM.VarOpBuf.szName) - 1));
888 pThisCC->NVRAM.VarOpBuf.cchName = sizeof(pThisCC->NVRAM.VarOpBuf.szName) - 1;
889 pThisCC->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
890 }
891 Assert(pThisCC->NVRAM.offOpBuffer == 0);
892 break;
893
894 case EFI_VM_VARIABLE_OP_NAME_UTF16:
895 {
896 Log2(("EFI_VM_VARIABLE_OP_NAME_UTF16[%#x]=%#x\n", pThisCC->NVRAM.offOpBuffer, u32Value));
897 /* Currently simplifying this to UCS2, i.e. no surrogates. */
898 if (pThisCC->NVRAM.offOpBuffer == 0)
899 RT_ZERO(pThisCC->NVRAM.VarOpBuf.szName);
900 uint32_t cbUtf8 = (uint32_t)RTStrCpSize(u32Value);
901 if (pThisCC->NVRAM.offOpBuffer + cbUtf8 < sizeof(pThisCC->NVRAM.VarOpBuf.szName))
902 {
903 RTStrPutCp(&pThisCC->NVRAM.VarOpBuf.szName[pThisCC->NVRAM.offOpBuffer], u32Value);
904 pThisCC->NVRAM.offOpBuffer += cbUtf8;
905 }
906 else if (u32Value == 0)
907 Assert(pThisCC->NVRAM.VarOpBuf.szName[sizeof(pThisCC->NVRAM.VarOpBuf.szName) - 1] == 0);
908 else
909 {
910 LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_NAME_UTF16 write (%#x).\n", u32Value));
911 pThisCC->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
912 }
913 break;
914 }
915
916 case EFI_VM_VARIABLE_OP_VALUE:
917 Log2(("EFI_VM_VARIABLE_OP_VALUE[%#x]=%#x\n", pThisCC->NVRAM.offOpBuffer, u32Value));
918 if (pThisCC->NVRAM.offOpBuffer < pThisCC->NVRAM.VarOpBuf.cbValue)
919 pThisCC->NVRAM.VarOpBuf.abValue[pThisCC->NVRAM.offOpBuffer++] = (uint8_t)u32Value;
920 else
921 {
922 LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_VALUE write (%#x).\n", u32Value));
923 pThisCC->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
924 }
925 break;
926
927 case EFI_VM_VARIABLE_OP_VALUE_LENGTH:
928 Log2(("EFI_VM_VARIABLE_OP_VALUE_LENGTH=%#x\n", u32Value));
929 RT_ZERO(pThisCC->NVRAM.VarOpBuf.abValue);
930 if (u32Value <= sizeof(pThisCC->NVRAM.VarOpBuf.abValue))
931 pThisCC->NVRAM.VarOpBuf.cbValue = u32Value;
932 else
933 {
934 LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_VALUE_LENGTH write (%#x, max %#x).\n",
935 u32Value, sizeof(pThisCC->NVRAM.VarOpBuf.abValue)));
936 pThisCC->NVRAM.VarOpBuf.cbValue = sizeof(pThisCC->NVRAM.VarOpBuf.abValue);
937 pThisCC->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
938 }
939 Assert(pThisCC->NVRAM.offOpBuffer == 0);
940 break;
941
942 default:
943 pThisCC->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
944 LogRel(("EFI: Unexpected variable operation %#x\n", pThisCC->NVRAM.enmOp));
945 break;
946 }
947 return VINF_SUCCESS;
948}
949
950/**
951 * Implements EFI_VARIABLE_OP reads.
952 *
953 * @returns IOM strict status code.
954 * @param pThisCC The EFI state for the current context.
955 * @param u32Value The value being written.
956 */
957static int nvramReadVariableOp(PDEVEFIR3 pThisCC, uint32_t *pu32, unsigned cb)
958{
959 switch (pThisCC->NVRAM.enmOp)
960 {
961 case EFI_VM_VARIABLE_OP_START:
962 *pu32 = pThisCC->NVRAM.u32Status;
963 break;
964
965 case EFI_VM_VARIABLE_OP_GUID:
966 if (pThisCC->NVRAM.offOpBuffer < sizeof(pThisCC->NVRAM.VarOpBuf.uuid) && cb == 1)
967 *pu32 = pThisCC->NVRAM.VarOpBuf.uuid.au8[pThisCC->NVRAM.offOpBuffer++];
968 else
969 {
970 if (cb == 1)
971 LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_GUID read.\n"));
972 else
973 LogRel(("EFI: Invalid EFI_VM_VARIABLE_OP_GUID read size (%d).\n", cb));
974 *pu32 = UINT32_MAX;
975 }
976 break;
977
978 case EFI_VM_VARIABLE_OP_ATTRIBUTE:
979 *pu32 = pThisCC->NVRAM.VarOpBuf.fAttributes;
980 break;
981
982 case EFI_VM_VARIABLE_OP_NAME:
983 /* allow reading terminator char */
984 if (pThisCC->NVRAM.offOpBuffer <= pThisCC->NVRAM.VarOpBuf.cchName && cb == 1)
985 *pu32 = pThisCC->NVRAM.VarOpBuf.szName[pThisCC->NVRAM.offOpBuffer++];
986 else
987 {
988 if (cb == 1)
989 LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_NAME read.\n"));
990 else
991 LogRel(("EFI: Invalid EFI_VM_VARIABLE_OP_NAME read size (%d).\n", cb));
992 *pu32 = UINT32_MAX;
993 }
994 break;
995
996 case EFI_VM_VARIABLE_OP_NAME_LENGTH:
997 *pu32 = pThisCC->NVRAM.VarOpBuf.cchName;
998 break;
999
1000 case EFI_VM_VARIABLE_OP_NAME_UTF16:
1001 /* Lazy bird: ASSUME no surrogate pairs. */
1002 if (pThisCC->NVRAM.offOpBuffer <= pThisCC->NVRAM.VarOpBuf.cchName && cb == 2)
1003 {
1004 char const *psz1 = &pThisCC->NVRAM.VarOpBuf.szName[pThisCC->NVRAM.offOpBuffer];
1005 char const *psz2 = psz1;
1006 RTUNICP Cp;
1007 RTStrGetCpEx(&psz2, &Cp);
1008 *pu32 = Cp;
1009 Log2(("EFI_VM_VARIABLE_OP_NAME_UTF16[%u] => %#x (+%d)\n", pThisCC->NVRAM.offOpBuffer, *pu32, psz2 - psz1));
1010 pThisCC->NVRAM.offOpBuffer += psz2 - psz1;
1011 }
1012 else
1013 {
1014 if (cb == 2)
1015 LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_NAME_UTF16 read.\n"));
1016 else
1017 LogRel(("EFI: Invalid EFI_VM_VARIABLE_OP_NAME_UTF16 read size (%d).\n", cb));
1018 *pu32 = UINT32_MAX;
1019 }
1020 break;
1021
1022 case EFI_VM_VARIABLE_OP_NAME_LENGTH_UTF16:
1023 /* Lazy bird: ASSUME no surrogate pairs. */
1024 *pu32 = (uint32_t)RTStrUniLen(pThisCC->NVRAM.VarOpBuf.szName);
1025 break;
1026
1027 case EFI_VM_VARIABLE_OP_VALUE:
1028 if (pThisCC->NVRAM.offOpBuffer < pThisCC->NVRAM.VarOpBuf.cbValue && cb == 1)
1029 *pu32 = pThisCC->NVRAM.VarOpBuf.abValue[pThisCC->NVRAM.offOpBuffer++];
1030 else
1031 {
1032 if (cb == 1)
1033 LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_VALUE read.\n"));
1034 else
1035 LogRel(("EFI: Invalid EFI_VM_VARIABLE_OP_VALUE read size (%d).\n", cb));
1036 *pu32 = UINT32_MAX;
1037 }
1038 break;
1039
1040 case EFI_VM_VARIABLE_OP_VALUE_LENGTH:
1041 *pu32 = pThisCC->NVRAM.VarOpBuf.cbValue;
1042 break;
1043
1044 default:
1045 *pu32 = UINT32_MAX;
1046 break;
1047 }
1048 return VINF_SUCCESS;
1049}
1050
1051
1052/**
1053 * Checks if the EFI variable value looks like a printable UTF-8 string.
1054 *
1055 * @returns true if it is, false if not.
1056 * @param pEfiVar The variable.
1057 * @param pfZeroTerm Where to return whether the string is zero
1058 * terminated.
1059 */
1060static bool efiInfoNvramIsUtf8(PCEFIVAR pEfiVar, bool *pfZeroTerm)
1061{
1062 if (pEfiVar->cbValue < 2)
1063 return false;
1064 const char *pachValue = (const char *)&pEfiVar->abValue[0];
1065 *pfZeroTerm = pachValue[pEfiVar->cbValue - 1] == 0;
1066
1067 /* Check the length. */
1068 size_t cchValue = RTStrNLen((const char *)pEfiVar->abValue, pEfiVar->cbValue);
1069 if (cchValue != pEfiVar->cbValue - *pfZeroTerm)
1070 return false; /* stray zeros in the value, forget it. */
1071
1072 /* Check that the string is valid UTF-8 and printable. */
1073 const char *pchCur = pachValue;
1074 while ((uintptr_t)(pchCur - pachValue) < cchValue)
1075 {
1076 RTUNICP uc;
1077 int rc = RTStrGetCpEx(&pachValue, &uc);
1078 if (RT_FAILURE(rc))
1079 return false;
1080 /** @todo Missing RTUniCpIsPrintable. */
1081 if (uc < 128 && !RT_C_IS_PRINT(uc))
1082 return false;
1083 }
1084
1085 return true;
1086}
1087
1088
1089/**
1090 * Checks if the EFI variable value looks like a printable UTF-16 string.
1091 *
1092 * @returns true if it is, false if not.
1093 * @param pEfiVar The variable.
1094 * @param pfZeroTerm Where to return whether the string is zero
1095 * terminated.
1096 */
1097static bool efiInfoNvramIsUtf16(PCEFIVAR pEfiVar, bool *pfZeroTerm)
1098{
1099 if (pEfiVar->cbValue < 4 || (pEfiVar->cbValue & 1))
1100 return false;
1101
1102 PCRTUTF16 pwcValue = (PCRTUTF16)&pEfiVar->abValue[0];
1103 size_t cwcValue = pEfiVar->cbValue / sizeof(RTUTF16);
1104 *pfZeroTerm = pwcValue[cwcValue - 1] == 0;
1105 if (!*pfZeroTerm && RTUtf16IsHighSurrogate(pwcValue[cwcValue - 1]))
1106 return false; /* Catch bad string early, before reading a char too many. */
1107 cwcValue -= *pfZeroTerm;
1108 if (cwcValue < 2)
1109 return false;
1110
1111 /* Check that the string is valid UTF-16, printable and spans the whole
1112 value length. */
1113 size_t cAscii = 0;
1114 PCRTUTF16 pwcCur = pwcValue;
1115 while ((uintptr_t)(pwcCur - pwcValue) < cwcValue)
1116 {
1117 RTUNICP uc;
1118 int rc = RTUtf16GetCpEx(&pwcCur, &uc);
1119 if (RT_FAILURE(rc))
1120 return false;
1121 /** @todo Missing RTUniCpIsPrintable. */
1122 if (uc < 128 && !RT_C_IS_PRINT(uc))
1123 return false;
1124 cAscii += uc < 128;
1125 }
1126 if (cAscii < 2)
1127 return false;
1128
1129 return true;
1130}
1131
1132
1133/**
1134 * @implement_callback_method{FNDBGFHANDLERDEV}
1135 */
1136static DECLCALLBACK(void) efiInfoNvram(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
1137{
1138 RT_NOREF(pszArgs);
1139 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
1140 int const rcLock = PDMDevHlpCritSectEnter(pDevIns, pDevIns->pCritSectRoR3, VERR_IGNORED);
1141 PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(pDevIns, pDevIns->pCritSectRoR3, rcLock); \
1142
1143 pHlp->pfnPrintf(pHlp, "NVRAM variables: %u\n", pThisCC->NVRAM.cVariables);
1144 PCEFIVAR pEfiVar;
1145 RTListForEach(&pThisCC->NVRAM.VarList, pEfiVar, EFIVAR, ListNode)
1146 {
1147 /* Detect UTF-8 and UTF-16 strings. */
1148 bool fZeroTerm = false;
1149 if (efiInfoNvramIsUtf8(pEfiVar, &fZeroTerm))
1150 pHlp->pfnPrintf(pHlp,
1151 "Variable - fAttr=%#04x - '%RTuuid:%s' - cb=%#04x\n"
1152 "String value (UTF-8%s): \"%.*s\"\n",
1153 pEfiVar->fAttributes, &pEfiVar->uuid, pEfiVar->szName, pEfiVar->cbValue,
1154 fZeroTerm ? "" : ",nz", pEfiVar->cbValue, pEfiVar->abValue);
1155 else if (efiInfoNvramIsUtf16(pEfiVar, &fZeroTerm))
1156 pHlp->pfnPrintf(pHlp,
1157 "Variable - fAttr=%#04x - '%RTuuid:%s' - cb=%#04x\n"
1158 "String value (UTF-16%s): \"%.*ls\"\n",
1159 pEfiVar->fAttributes, &pEfiVar->uuid, pEfiVar->szName, pEfiVar->cbValue,
1160 fZeroTerm ? "" : ",nz", pEfiVar->cbValue, pEfiVar->abValue);
1161 else
1162 pHlp->pfnPrintf(pHlp,
1163 "Variable - fAttr=%#04x - '%RTuuid:%s' - cb=%#04x\n"
1164 "%.*Rhxd\n",
1165 pEfiVar->fAttributes, &pEfiVar->uuid, pEfiVar->szName, pEfiVar->cbValue,
1166 pEfiVar->cbValue, pEfiVar->abValue);
1167
1168 }
1169
1170 PDMDevHlpCritSectLeave(pDevIns, pDevIns->pCritSectRoR3);
1171}
1172
1173
1174
1175/**
1176 * Gets the info item size.
1177 *
1178 * @returns Size in bytes, UINT32_MAX on error.
1179 * @param pThisCC The EFI state for the current context.
1180 */
1181static uint32_t efiInfoSize(PDEVEFIR3 pThisCC)
1182{
1183 switch (pThisCC->iInfoSelector)
1184 {
1185 case EFI_INFO_INDEX_VOLUME_BASE:
1186 case EFI_INFO_INDEX_VOLUME_SIZE:
1187 case EFI_INFO_INDEX_TEMPMEM_BASE:
1188 case EFI_INFO_INDEX_TEMPMEM_SIZE:
1189 case EFI_INFO_INDEX_STACK_BASE:
1190 case EFI_INFO_INDEX_STACK_SIZE:
1191 case EFI_INFO_INDEX_GRAPHICS_MODE:
1192 case EFI_INFO_INDEX_VERTICAL_RESOLUTION:
1193 case EFI_INFO_INDEX_HORIZONTAL_RESOLUTION:
1194 return 4;
1195 case EFI_INFO_INDEX_BOOT_ARGS:
1196 return (uint32_t)RTStrNLen(pThisCC->szBootArgs, sizeof(pThisCC->szBootArgs)) + 1;
1197 case EFI_INFO_INDEX_DEVICE_PROPS:
1198 return pThisCC->cbDeviceProps;
1199 case EFI_INFO_INDEX_FSB_FREQUENCY:
1200 case EFI_INFO_INDEX_CPU_FREQUENCY:
1201 case EFI_INFO_INDEX_TSC_FREQUENCY:
1202 case EFI_INFO_INDEX_MCFG_BASE:
1203 case EFI_INFO_INDEX_MCFG_SIZE:
1204 return 8;
1205 case EFI_INFO_INDEX_APIC_MODE:
1206 return 1;
1207 }
1208 return UINT32_MAX;
1209}
1210
1211
1212/**
1213 * efiInfoNextByte for a uint8_t value.
1214 *
1215 * @returns Next (current) byte.
1216 * @param pThisCC The EFI state for the current context.
1217 * @param u8 The value.
1218 */
1219static uint8_t efiInfoNextByteU8(PDEVEFIR3 pThisCC, uint8_t u8)
1220{
1221 uint32_t off = pThisCC->offInfo;
1222 if (off >= 1)
1223 return 0;
1224 return (uint8_t)u8;
1225}
1226
1227
1228/**
1229 * efiInfoNextByte for a uint64_t value.
1230 *
1231 * @returns Next (current) byte.
1232 * @param pThisCC The EFI state for the current context.
1233 * @param u64 The value.
1234 */
1235static uint8_t efiInfoNextByteU64(PDEVEFIR3 pThisCC, uint64_t u64)
1236{
1237 uint64_t off = pThisCC->offInfo;
1238 if (off >= 8)
1239 return 0;
1240 return (uint8_t)(u64 >> (off * 8));
1241}
1242
1243/**
1244 * efiInfoNextByte for a uint32_t value.
1245 *
1246 * @returns Next (current) byte.
1247 * @param pThisCC The EFI state for the current context.
1248 * @param u32 The value.
1249 */
1250static uint8_t efiInfoNextByteU32(PDEVEFIR3 pThisCC, uint32_t u32)
1251{
1252 uint32_t off = pThisCC->offInfo;
1253 if (off >= 4)
1254 return 0;
1255 return (uint8_t)(u32 >> (off * 8));
1256}
1257
1258/**
1259 * efiInfoNextByte for a buffer.
1260 *
1261 * @returns Next (current) byte.
1262 * @param pThisCC The EFI state for the current context.
1263 * @param pvBuf The buffer.
1264 * @param cbBuf The buffer size.
1265 */
1266static uint8_t efiInfoNextByteBuf(PDEVEFIR3 pThisCC, void const *pvBuf, size_t cbBuf)
1267{
1268 uint32_t off = pThisCC->offInfo;
1269 if (off >= cbBuf)
1270 return 0;
1271 return ((uint8_t const *)pvBuf)[off];
1272}
1273
1274/**
1275 * Gets the next info byte.
1276 *
1277 * @returns Next (current) byte.
1278 * @param pThisCC The EFI state for the current context.
1279 */
1280static uint8_t efiInfoNextByte(PDEVEFIR3 pThisCC)
1281{
1282 switch (pThisCC->iInfoSelector)
1283 {
1284
1285 case EFI_INFO_INDEX_VOLUME_BASE: return efiInfoNextByteU64(pThisCC, pThisCC->GCLoadAddress);
1286 case EFI_INFO_INDEX_VOLUME_SIZE: return efiInfoNextByteU64(pThisCC, pThisCC->cbEfiRom);
1287 case EFI_INFO_INDEX_TEMPMEM_BASE: return efiInfoNextByteU32(pThisCC, VBOX_EFI_TOP_OF_STACK); /* just after stack */
1288 case EFI_INFO_INDEX_TEMPMEM_SIZE: return efiInfoNextByteU32(pThisCC, _512K);
1289 case EFI_INFO_INDEX_FSB_FREQUENCY: return efiInfoNextByteU64(pThisCC, pThisCC->u64FsbFrequency);
1290 case EFI_INFO_INDEX_TSC_FREQUENCY: return efiInfoNextByteU64(pThisCC, pThisCC->u64TscFrequency);
1291 case EFI_INFO_INDEX_CPU_FREQUENCY: return efiInfoNextByteU64(pThisCC, pThisCC->u64CpuFrequency);
1292 case EFI_INFO_INDEX_BOOT_ARGS: return efiInfoNextByteBuf(pThisCC, pThisCC->szBootArgs, sizeof(pThisCC->szBootArgs));
1293 case EFI_INFO_INDEX_DEVICE_PROPS: return efiInfoNextByteBuf(pThisCC, pThisCC->pbDeviceProps, pThisCC->cbDeviceProps);
1294 case EFI_INFO_INDEX_GRAPHICS_MODE: return efiInfoNextByteU32(pThisCC, pThisCC->u32GraphicsMode);
1295 case EFI_INFO_INDEX_HORIZONTAL_RESOLUTION: return efiInfoNextByteU32(pThisCC, pThisCC->u32HorizontalResolution);
1296 case EFI_INFO_INDEX_VERTICAL_RESOLUTION: return efiInfoNextByteU32(pThisCC, pThisCC->u32VerticalResolution);
1297
1298 /* Keep in sync with value in EfiThunk.asm */
1299 case EFI_INFO_INDEX_STACK_BASE: return efiInfoNextByteU32(pThisCC, VBOX_EFI_TOP_OF_STACK - _128K); /* 2M - 128 K */
1300 case EFI_INFO_INDEX_STACK_SIZE: return efiInfoNextByteU32(pThisCC, _128K);
1301 case EFI_INFO_INDEX_MCFG_BASE: return efiInfoNextByteU64(pThisCC, pThisCC->u64McfgBase);
1302 case EFI_INFO_INDEX_MCFG_SIZE: return efiInfoNextByteU64(pThisCC, pThisCC->cbMcfgLength);
1303 case EFI_INFO_INDEX_APIC_MODE: return efiInfoNextByteU8(pThisCC, pThisCC->u8APIC);
1304
1305 default:
1306 PDMDevHlpDBGFStop(pThisCC->pDevIns, RT_SRC_POS, "%#x", pThisCC->iInfoSelector);
1307 return 0;
1308 }
1309}
1310
1311
1312#ifdef IN_RING3
1313static void efiVBoxDbgScript(const char *pszFormat, ...)
1314{
1315# ifdef DEVEFI_WITH_VBOXDBG_SCRIPT
1316 PRTSTREAM pStrm;
1317 int rc2 = RTStrmOpen("./DevEFI.VBoxDbg", "a", &pStrm);
1318 if (RT_SUCCESS(rc2))
1319 {
1320 va_list va;
1321 va_start(va, pszFormat);
1322 RTStrmPrintfV(pStrm, pszFormat, va);
1323 va_end(va);
1324 RTStrmClose(pStrm);
1325 }
1326# else
1327 RT_NOREF(pszFormat);
1328# endif
1329}
1330#endif /* IN_RING3 */
1331
1332
1333/**
1334 * Handles writes to the image event port.
1335 *
1336 * @returns VBox status suitable for I/O port write handler.
1337 *
1338 * @param pThisCC The EFI state for the current context.
1339 * @param u32 The value being written.
1340 * @param cb The size of the value.
1341 */
1342static int efiPortImageEventWrite(PDEVEFIR3 pThisCC, uint32_t u32, unsigned cb)
1343{
1344 RT_NOREF(cb);
1345 switch (u32 & EFI_IMAGE_EVT_CMD_MASK)
1346 {
1347 case EFI_IMAGE_EVT_CMD_START_LOAD32:
1348 case EFI_IMAGE_EVT_CMD_START_LOAD64:
1349 case EFI_IMAGE_EVT_CMD_START_UNLOAD32:
1350 case EFI_IMAGE_EVT_CMD_START_UNLOAD64:
1351 case EFI_IMAGE_EVT_CMD_START_RELOC32:
1352 case EFI_IMAGE_EVT_CMD_START_RELOC64:
1353 AssertBreak(EFI_IMAGE_EVT_GET_PAYLOAD(u32) == 0);
1354
1355 /* Reset the state. */
1356 RT_ZERO(pThisCC->ImageEvt);
1357 pThisCC->ImageEvt.uEvt = (uint8_t)u32; Assert(pThisCC->ImageEvt.uEvt == u32);
1358 return VINF_SUCCESS;
1359
1360 case EFI_IMAGE_EVT_CMD_COMPLETE:
1361 {
1362# ifdef IN_RING3
1363 AssertBreak(EFI_IMAGE_EVT_GET_PAYLOAD(u32) == 0);
1364
1365 /* For now, just log it. */
1366 static uint64_t s_cImageEvtLogged = 0;
1367 if (s_cImageEvtLogged < 2048)
1368 {
1369 s_cImageEvtLogged++;
1370 switch (pThisCC->ImageEvt.uEvt)
1371 {
1372 /* ASSUMES the name ends with .pdb and the image file ends with .efi! */
1373 case EFI_IMAGE_EVT_CMD_START_LOAD32:
1374 LogRel(("EFI: VBoxDbg> loadimage32 '%.*s.efi' %#llx LB %#llx\n",
1375 pThisCC->ImageEvt.offName - 4, pThisCC->ImageEvt.szName, pThisCC->ImageEvt.uAddr0, pThisCC->ImageEvt.cb0));
1376 if (pThisCC->ImageEvt.offName > 4)
1377 efiVBoxDbgScript("loadimage32 '%.*s.efi' %#llx\n",
1378 pThisCC->ImageEvt.offName - 4, pThisCC->ImageEvt.szName, pThisCC->ImageEvt.uAddr0);
1379 break;
1380 case EFI_IMAGE_EVT_CMD_START_LOAD64:
1381 LogRel(("EFI: VBoxDbg> loadimage64 '%.*s.efi' %#llx LB %#llx\n",
1382 pThisCC->ImageEvt.offName - 4, pThisCC->ImageEvt.szName, pThisCC->ImageEvt.uAddr0, pThisCC->ImageEvt.cb0));
1383 if (pThisCC->ImageEvt.offName > 4)
1384 efiVBoxDbgScript("loadimage64 '%.*s.efi' %#llx\n",
1385 pThisCC->ImageEvt.offName - 4, pThisCC->ImageEvt.szName, pThisCC->ImageEvt.uAddr0);
1386 break;
1387 case EFI_IMAGE_EVT_CMD_START_UNLOAD32:
1388 case EFI_IMAGE_EVT_CMD_START_UNLOAD64:
1389 {
1390 LogRel(("EFI: VBoxDbg> unload '%.*s.efi' # %#llx LB %#llx\n",
1391 pThisCC->ImageEvt.offName - 4 - pThisCC->ImageEvt.offNameLastComponent,
1392 &pThisCC->ImageEvt.szName[pThisCC->ImageEvt.offNameLastComponent],
1393 pThisCC->ImageEvt.uAddr0, pThisCC->ImageEvt.cb0));
1394 if (pThisCC->ImageEvt.offName > 4)
1395 efiVBoxDbgScript("unload '%.*s.efi'\n",
1396 pThisCC->ImageEvt.offName - 4 - pThisCC->ImageEvt.offNameLastComponent,
1397 &pThisCC->ImageEvt.szName[pThisCC->ImageEvt.offNameLastComponent]);
1398 break;
1399 }
1400 case EFI_IMAGE_EVT_CMD_START_RELOC32:
1401 case EFI_IMAGE_EVT_CMD_START_RELOC64:
1402 {
1403 LogRel(("EFI: relocate module to %#llx from %#llx\n",
1404 pThisCC->ImageEvt.uAddr0, pThisCC->ImageEvt.uAddr1));
1405 break;
1406 }
1407 }
1408 }
1409 return VINF_SUCCESS;
1410# else
1411 return VINF_IOM_R3_IOPORT_WRITE;
1412# endif
1413 }
1414
1415 case EFI_IMAGE_EVT_CMD_ADDR0:
1416 AssertBreak(EFI_IMAGE_EVT_GET_PAYLOAD(u32) <= UINT16_MAX);
1417 pThisCC->ImageEvt.uAddr0 <<= 16;
1418 pThisCC->ImageEvt.uAddr0 |= EFI_IMAGE_EVT_GET_PAYLOAD_U16(u32);
1419 return VINF_SUCCESS;
1420
1421 case EFI_IMAGE_EVT_CMD_ADDR1:
1422 AssertBreak(EFI_IMAGE_EVT_GET_PAYLOAD(u32) <= UINT16_MAX);
1423 pThisCC->ImageEvt.uAddr1 <<= 16;
1424 pThisCC->ImageEvt.uAddr1 |= EFI_IMAGE_EVT_GET_PAYLOAD_U16(u32);
1425 return VINF_SUCCESS;
1426
1427 case EFI_IMAGE_EVT_CMD_SIZE0:
1428 AssertBreak(EFI_IMAGE_EVT_GET_PAYLOAD(u32) <= UINT16_MAX);
1429 pThisCC->ImageEvt.cb0 <<= 16;
1430 pThisCC->ImageEvt.cb0 |= EFI_IMAGE_EVT_GET_PAYLOAD_U16(u32);
1431 return VINF_SUCCESS;
1432
1433 case EFI_IMAGE_EVT_CMD_NAME:
1434 AssertBreak(EFI_IMAGE_EVT_GET_PAYLOAD(u32) <= 0x7f);
1435 if (pThisCC->ImageEvt.offName < sizeof(pThisCC->ImageEvt.szName) - 1)
1436 {
1437 char ch = EFI_IMAGE_EVT_GET_PAYLOAD_U8(u32);
1438 if (ch == '\\')
1439 ch = '/';
1440 pThisCC->ImageEvt.szName[pThisCC->ImageEvt.offName++] = ch;
1441 if (ch == '/' || ch == ':')
1442 pThisCC->ImageEvt.offNameLastComponent = pThisCC->ImageEvt.offName;
1443 }
1444 else
1445 Log(("EFI: Image name overflow\n"));
1446 return VINF_SUCCESS;
1447 }
1448
1449 Log(("EFI: Unknown image event: %#x (cb=%d)\n", u32, cb));
1450 return VINF_SUCCESS;
1451}
1452
1453
1454/**
1455 * @callback_method_impl{FNIOMIOPORTNEWIN}
1456 *
1457 * @note The @a offPort parameter is absolute!
1458 */
1459static DECLCALLBACK(VBOXSTRICTRC) efiR3IoPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
1460{
1461 RT_NOREF(pvUser);
1462 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
1463 Log4(("EFI in: %x %x\n", offPort, cb));
1464
1465 switch (offPort)
1466 {
1467 case EFI_INFO_PORT:
1468 if (pThisCC->offInfo == -1 && cb == 4)
1469 {
1470 pThisCC->offInfo = 0;
1471 uint32_t cbInfo = *pu32 = efiInfoSize(pThisCC);
1472 if (cbInfo == UINT32_MAX)
1473 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "iInfoSelector=%#x (%d)\n",
1474 pThisCC->iInfoSelector, pThisCC->iInfoSelector);
1475 }
1476 else
1477 {
1478 if (cb != 1)
1479 return VERR_IOM_IOPORT_UNUSED;
1480 *pu32 = efiInfoNextByte(pThisCC);
1481 pThisCC->offInfo++;
1482 }
1483 return VINF_SUCCESS;
1484
1485 case EFI_PANIC_PORT:
1486# ifdef IN_RING3
1487 LogRel(("EFI panic port read!\n"));
1488 /* Insert special code here on panic reads */
1489 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "EFI Panic: panic port read!\n");
1490# else
1491 /* Reschedule to R3 */
1492 return VINF_IOM_R3_IOPORT_READ;
1493# endif
1494
1495 case EFI_PORT_VARIABLE_OP:
1496 return nvramReadVariableOp(pThisCC, pu32, cb);
1497
1498 case EFI_PORT_VARIABLE_PARAM:
1499 case EFI_PORT_DEBUG_POINT:
1500 case EFI_PORT_IMAGE_EVENT:
1501 *pu32 = UINT32_MAX;
1502 return VINF_SUCCESS;
1503 }
1504
1505 return VERR_IOM_IOPORT_UNUSED;
1506}
1507
1508
1509/**
1510 * Translates a debug point value into a string for logging.
1511 *
1512 * @returns read-only string
1513 * @param enmDbgPoint Valid debug point value.
1514 */
1515static const char *efiDbgPointName(EFIDBGPOINT enmDbgPoint)
1516{
1517 switch (enmDbgPoint)
1518 {
1519 case EFIDBGPOINT_SEC_PREMEM: return "SEC_PREMEM";
1520 case EFIDBGPOINT_SEC_POSTMEM: return "SEC_POSTMEM";
1521 case EFIDBGPOINT_DXE_CORE: return "DXE_CORE";
1522 case EFIDBGPOINT_SMM: return "SMM";
1523 case EFIDBGPOINT_SMI_ENTER: return "SMI_ENTER";
1524 case EFIDBGPOINT_SMI_EXIT: return "SMI_EXIT";
1525 case EFIDBGPOINT_GRAPHICS: return "GRAPHICS";
1526 case EFIDBGPOINT_DXE_AP: return "DXE_AP";
1527 default:
1528 AssertFailed();
1529 return "Unknown";
1530 }
1531}
1532
1533
1534/**
1535 * @callback_method_impl{FNIOMIOPORTNEWOUT}
1536 *
1537 * @note The @a offPort parameter is absolute!
1538 */
1539static DECLCALLBACK(VBOXSTRICTRC) efiR3IoPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
1540{
1541 RT_NOREF(pvUser);
1542 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
1543 VBOXSTRICTRC rc = VINF_SUCCESS;
1544 Log4(("efi: out %x %x %d\n", offPort, u32, cb));
1545
1546 switch (offPort)
1547 {
1548 case EFI_INFO_PORT:
1549 Log2(("EFI_INFO_PORT: iInfoSelector=%#x\n", u32));
1550 pThisCC->iInfoSelector = u32;
1551 pThisCC->offInfo = -1;
1552 break;
1553
1554 case EFI_DEBUG_PORT:
1555 {
1556 /* The raw version. */
1557 switch (u32)
1558 {
1559 case '\r': Log3(("efi: <return>\n")); break;
1560 case '\n': Log3(("efi: <newline>\n")); break;
1561 case '\t': Log3(("efi: <tab>\n")); break;
1562 default: Log3(("efi: %c (%02x)\n", u32, u32)); break;
1563 }
1564 /* The readable, buffered version. */
1565 if (u32 == '\n' || u32 == '\r')
1566 {
1567 Assert(pThisCC->iMsg < sizeof(pThisCC->szMsg));
1568 pThisCC->szMsg[pThisCC->iMsg] = '\0';
1569 if (pThisCC->iMsg)
1570 LogRel2(("efi: %s\n", pThisCC->szMsg));
1571 pThisCC->iMsg = 0;
1572 }
1573 else
1574 {
1575 if (pThisCC->iMsg >= sizeof(pThisCC->szMsg) - 1)
1576 {
1577 pThisCC->szMsg[pThisCC->iMsg] = '\0';
1578 LogRel2(("efi: %s\n", pThisCC->szMsg));
1579 pThisCC->iMsg = 0;
1580 }
1581 pThisCC->szMsg[pThisCC->iMsg] = (char)u32;
1582 pThisCC->szMsg[++pThisCC->iMsg] = '\0';
1583 }
1584 break;
1585 }
1586
1587 case EFI_PANIC_PORT:
1588 {
1589 switch (u32)
1590 {
1591 case EFI_PANIC_CMD_BAD_ORG: /* Legacy */
1592 case EFI_PANIC_CMD_THUNK_TRAP:
1593#ifdef IN_RING3
1594 LogRel(("EFI: Panic! Unexpected trap!!\n"));
1595# ifdef VBOX_STRICT
1596 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "EFI Panic: Unexpected trap during early bootstrap!\n");
1597# else
1598 AssertReleaseMsgFailed(("Unexpected trap during early EFI bootstrap!!\n"));
1599# endif
1600 break;
1601#else
1602 return VINF_IOM_R3_IOPORT_WRITE;
1603#endif
1604
1605 case EFI_PANIC_CMD_START_MSG:
1606 LogRel(("Receiving EFI panic...\n"));
1607 pThisCC->iPanicMsg = 0;
1608 pThisCC->szPanicMsg[0] = '\0';
1609 break;
1610
1611 case EFI_PANIC_CMD_END_MSG:
1612#ifdef IN_RING3
1613 LogRel(("EFI: Panic! %s\n", pThisCC->szPanicMsg));
1614# ifdef VBOX_STRICT
1615 return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "EFI Panic: %s\n", pThisCC->szPanicMsg);
1616# else
1617 return VERR_INTERNAL_ERROR;
1618# endif
1619#else
1620 return VINF_IOM_R3_IOPORT_WRITE;
1621#endif
1622
1623
1624 default:
1625 if ( u32 >= EFI_PANIC_CMD_MSG_FIRST
1626 && u32 <= EFI_PANIC_CMD_MSG_LAST)
1627 {
1628 /* Add the message char to the buffer. */
1629 uint32_t i = pThisCC->iPanicMsg;
1630 if (i + 1 < sizeof(pThisCC->szPanicMsg))
1631 {
1632 char ch = EFI_PANIC_CMD_MSG_GET_CHAR(u32);
1633 if ( ch == '\n'
1634 && i > 0
1635 && pThisCC->szPanicMsg[i - 1] == '\r')
1636 i--;
1637 pThisCC->szPanicMsg[i] = ch;
1638 pThisCC->szPanicMsg[i + 1] = '\0';
1639 pThisCC->iPanicMsg = i + 1;
1640 }
1641 }
1642 else
1643 Log(("EFI: Unknown panic command: %#x (cb=%d)\n", u32, cb));
1644 break;
1645 }
1646 break;
1647 }
1648
1649 case EFI_PORT_VARIABLE_OP:
1650 {
1651 /* clear buffer index */
1652 if (u32 >= (uint32_t)EFI_VM_VARIABLE_OP_MAX)
1653 {
1654 Log(("EFI: Invalid variable op %#x\n", u32));
1655 u32 = EFI_VM_VARIABLE_OP_ERROR;
1656 }
1657 pThisCC->NVRAM.offOpBuffer = 0;
1658 pThisCC->NVRAM.enmOp = (EFIVAROP)u32;
1659 Log2(("EFI_VARIABLE_OP: enmOp=%#x (%d)\n", u32, u32));
1660 break;
1661 }
1662
1663 case EFI_PORT_VARIABLE_PARAM:
1664 rc = nvramWriteVariableParam(pThisCC, u32);
1665 break;
1666
1667 case EFI_PORT_DEBUG_POINT:
1668# ifdef IN_RING3
1669 if (u32 > EFIDBGPOINT_INVALID && u32 < EFIDBGPOINT_END)
1670 {
1671 /* For now, just log it. */
1672 LogRelMax(1024, ("EFI: debug point %s\n", efiDbgPointName((EFIDBGPOINT)u32)));
1673 rc = VINF_SUCCESS;
1674 }
1675 else
1676 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "Invalid debug point %#x\n", u32);
1677 break;
1678# else
1679 return VINF_IOM_R3_IOPORT_WRITE;
1680# endif
1681
1682 case EFI_PORT_IMAGE_EVENT:
1683 rc = efiPortImageEventWrite(pThisCC, u32, cb);
1684 break;
1685
1686 default:
1687 Log(("EFI: Write to reserved port %RTiop: %#x (cb=%d)\n", offPort, u32, cb));
1688 break;
1689 }
1690 return rc;
1691}
1692
1693#endif /* IN_RING3 */
1694
1695/**
1696 * @callback_method_impl{FNIOMMMIONEWWRITE, Flash memory write}
1697 */
1698static DECLCALLBACK(VBOXSTRICTRC) efiR3NvMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
1699{
1700 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
1701 RT_NOREF(pvUser);
1702
1703 return flashWrite(&pThis->Flash, off, pv, cb);
1704}
1705
1706
1707/**
1708 * @callback_method_impl{FNIOMMMIONEWREAD, Flash memory read}
1709 */
1710static DECLCALLBACK(VBOXSTRICTRC) efiR3NvMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
1711{
1712 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
1713 RT_NOREF(pvUser);
1714
1715 return flashRead(&pThis->Flash, off, pv, cb);
1716}
1717
1718#ifdef IN_RING3
1719
1720static DECLCALLBACK(int) efiSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1721{
1722 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
1723 LogFlow(("efiSaveExec:\n"));
1724
1725 return flashR3SaveExec(&pThis->Flash, pDevIns, pSSM);
1726}
1727
1728static DECLCALLBACK(int) efiLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1729{
1730 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
1731 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
1732 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
1733 LogFlow(("efiLoadExec: uVersion=%d uPass=%d\n", uVersion, uPass));
1734
1735 /*
1736 * Validate input.
1737 */
1738 if (uPass != SSM_PASS_FINAL)
1739 return VERR_SSM_UNEXPECTED_PASS;
1740 if ( uVersion != EFI_SSM_VERSION
1741 && uVersion != EFI_SSM_VERSION_PRE_PROPER_NVRAM
1742 && uVersion != EFI_SSM_VERSION_4_2
1743 )
1744 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1745
1746 int rc;
1747 if (uVersion > EFI_SSM_VERSION_PRE_PROPER_NVRAM)
1748 rc = flashR3LoadExec(&pThis->Flash, pDevIns, pSSM);
1749 else
1750 {
1751 /*
1752 * Kill the current variables before loading anything.
1753 */
1754 nvramFlushDeviceVariableList(pThisCC);
1755
1756 /*
1757 * Load the NVRAM state.
1758 */
1759 rc = pHlp->pfnSSMGetStructEx(pSSM, &pThisCC->NVRAM, sizeof(NVRAMDESC), 0, g_aEfiNvramDescField, NULL);
1760 AssertRCReturn(rc, rc);
1761 pThisCC->NVRAM.pCurVar = NULL;
1762
1763 rc = pHlp->pfnSSMGetStructEx(pSSM, &pThisCC->NVRAM.VarOpBuf, sizeof(EFIVAR), 0, g_aEfiVariableDescFields, NULL);
1764 AssertRCReturn(rc, rc);
1765
1766 /*
1767 * Load variables.
1768 */
1769 pThisCC->NVRAM.pCurVar = NULL;
1770 Assert(RTListIsEmpty(&pThisCC->NVRAM.VarList));
1771 RTListInit(&pThisCC->NVRAM.VarList);
1772 for (uint32_t i = 0; i < pThisCC->NVRAM.cVariables; i++)
1773 {
1774 PEFIVAR pEfiVar = (PEFIVAR)RTMemAllocZ(sizeof(EFIVAR));
1775 AssertReturn(pEfiVar, VERR_NO_MEMORY);
1776
1777 rc = pHlp->pfnSSMGetStructEx(pSSM, pEfiVar, sizeof(EFIVAR), 0, g_aEfiVariableDescFields, NULL);
1778 if (RT_SUCCESS(rc))
1779 {
1780 if ( pEfiVar->cbValue > sizeof(pEfiVar->abValue)
1781 || pEfiVar->cbValue == 0)
1782 {
1783 rc = VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1784 LogRel(("EFI: Loaded invalid variable value length %#x\n", pEfiVar->cbValue));
1785 }
1786 uint32_t cchVarName = (uint32_t)RTStrNLen(pEfiVar->szName, sizeof(pEfiVar->szName));
1787 if (cchVarName >= sizeof(pEfiVar->szName))
1788 {
1789 rc = VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1790 LogRel(("EFI: Loaded variable name is unterminated.\n"));
1791 }
1792 if (pEfiVar->cchName > cchVarName) /* No check for 0 here, busted load code in 4.2, so now storing 0 here. */
1793 {
1794 rc = VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
1795 LogRel(("EFI: Loaded invalid variable name length %#x (cchVarName=%#x)\n", pEfiVar->cchName, cchVarName));
1796 }
1797 if (RT_SUCCESS(rc))
1798 pEfiVar->cchName = cchVarName;
1799 }
1800 AssertRCReturnStmt(rc, RTMemFree(pEfiVar), rc);
1801
1802 /* Add it (not using nvramInsertVariable to preserve saved order),
1803 updating the current variable pointer while we're here. */
1804#if 1
1805 RTListAppend(&pThisCC->NVRAM.VarList, &pEfiVar->ListNode);
1806#else
1807 nvramInsertVariable(pThisCC, pEfiVar);
1808#endif
1809 if (pThisCC->NVRAM.idUniqueCurVar == pEfiVar->idUniqueSavedState)
1810 pThisCC->NVRAM.pCurVar = pEfiVar;
1811 }
1812 }
1813
1814 return rc;
1815}
1816
1817
1818/**
1819 * @copydoc(PDMIBASE::pfnQueryInterface)
1820 */
1821static DECLCALLBACK(void *) devEfiQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1822{
1823 LogFlowFunc(("ENTER: pIBase=%p pszIID=%p\n", pInterface, pszIID));
1824 PDEVEFIR3 pThisCC = RT_FROM_MEMBER(pInterface, DEVEFIR3, Lun0.IBase);
1825
1826 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->Lun0.IBase);
1827 return NULL;
1828}
1829
1830
1831/**
1832 * Write to CMOS memory.
1833 * This is used by the init complete code.
1834 */
1835static void cmosWrite(PPDMDEVINS pDevIns, unsigned off, uint32_t u32Val)
1836{
1837 Assert(off < 128);
1838 Assert(u32Val < 256);
1839
1840 int rc = PDMDevHlpCMOSWrite(pDevIns, off, u32Val);
1841 AssertRC(rc);
1842}
1843
1844/**
1845 * Init complete notification.
1846 *
1847 * @returns VBOX status code.
1848 * @param pDevIns The device instance.
1849 */
1850static DECLCALLBACK(int) efiInitComplete(PPDMDEVINS pDevIns)
1851{
1852 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
1853
1854 PVM pVM = PDMDevHlpGetVM(pDevIns);
1855 uint64_t const cbRamSize = MMR3PhysGetRamSize(pVM);
1856 uint32_t const cbBelow4GB = MMR3PhysGetRamSizeBelow4GB(pVM);
1857 uint64_t const cbAbove4GB = MMR3PhysGetRamSizeAbove4GB(pVM);
1858 NOREF(cbAbove4GB);
1859
1860 /*
1861 * Memory sizes.
1862 */
1863 uint32_t u32Low = 0;
1864 uint32_t u32Chunks = 0;
1865 if (cbRamSize > 16 * _1M)
1866 {
1867 u32Low = RT_MIN(cbBelow4GB, UINT32_C(0xfe000000));
1868 u32Chunks = (u32Low - 16U * _1M) / _64K;
1869 }
1870 cmosWrite(pDevIns, 0x34, RT_BYTE1(u32Chunks));
1871 cmosWrite(pDevIns, 0x35, RT_BYTE2(u32Chunks));
1872
1873 if (u32Low < cbRamSize)
1874 {
1875 uint64_t u64 = cbRamSize - u32Low;
1876 u32Chunks = (uint32_t)(u64 / _64K);
1877 cmosWrite(pDevIns, 0x5b, RT_BYTE1(u32Chunks));
1878 cmosWrite(pDevIns, 0x5c, RT_BYTE2(u32Chunks));
1879 cmosWrite(pDevIns, 0x5d, RT_BYTE3(u32Chunks));
1880 cmosWrite(pDevIns, 0x5e, RT_BYTE4(u32Chunks));
1881 }
1882
1883 /*
1884 * Number of CPUs.
1885 */
1886 cmosWrite(pDevIns, 0x60, pThisCC->cCpus & 0xff);
1887
1888 return VINF_SUCCESS;
1889}
1890
1891
1892/**
1893 * @interface_method_impl{PDMDEVREG,pfnMemSetup}
1894 */
1895static DECLCALLBACK(void) efiMemSetup(PPDMDEVINS pDevIns, PDMDEVMEMSETUPCTX enmCtx)
1896{
1897 RT_NOREF(enmCtx);
1898 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
1899
1900 /*
1901 * Re-shadow the Firmware Volume and make it RAM/RAM.
1902 */
1903 uint32_t cPages = RT_ALIGN_64(pThisCC->cbEfiRom, PAGE_SIZE) >> PAGE_SHIFT;
1904 RTGCPHYS GCPhys = pThisCC->GCLoadAddress;
1905 while (cPages > 0)
1906 {
1907 uint8_t abPage[PAGE_SIZE];
1908
1909 /* Read the (original) ROM page and write it back to the RAM page. */
1910 int rc = PDMDevHlpROMProtectShadow(pDevIns, GCPhys, PAGE_SIZE, PGMROMPROT_READ_ROM_WRITE_RAM);
1911 AssertLogRelRC(rc);
1912
1913 rc = PDMDevHlpPhysRead(pDevIns, GCPhys, abPage, PAGE_SIZE);
1914 AssertLogRelRC(rc);
1915 if (RT_FAILURE(rc))
1916 memset(abPage, 0xcc, sizeof(abPage));
1917
1918 rc = PDMDevHlpPhysWrite(pDevIns, GCPhys, abPage, PAGE_SIZE);
1919 AssertLogRelRC(rc);
1920
1921 /* Switch to the RAM/RAM mode. */
1922 rc = PDMDevHlpROMProtectShadow(pDevIns, GCPhys, PAGE_SIZE, PGMROMPROT_READ_RAM_WRITE_RAM);
1923 AssertLogRelRC(rc);
1924
1925 /* Advance */
1926 GCPhys += PAGE_SIZE;
1927 cPages--;
1928 }
1929}
1930
1931
1932/**
1933 * @interface_method_impl{PDMDEVREG,pfnReset}
1934 */
1935static DECLCALLBACK(void) efiReset(PPDMDEVINS pDevIns)
1936{
1937 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
1938 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
1939 LogFlow(("efiReset\n"));
1940
1941 pThisCC->iInfoSelector = 0;
1942 pThisCC->offInfo = -1;
1943
1944 pThisCC->iMsg = 0;
1945 pThisCC->szMsg[0] = '\0';
1946 pThisCC->iPanicMsg = 0;
1947 pThisCC->szPanicMsg[0] = '\0';
1948
1949 flashR3Reset(&pThis->Flash);
1950
1951#ifdef DEVEFI_WITH_VBOXDBG_SCRIPT
1952 /*
1953 * Zap the debugger script
1954 */
1955 RTFileDelete("./DevEFI.VBoxDbg");
1956#endif
1957}
1958
1959
1960/**
1961 * @interface_method_impl{PDMDEVREG,pfnPowerOff}
1962 */
1963static DECLCALLBACK(void) efiPowerOff(PPDMDEVINS pDevIns)
1964{
1965 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
1966
1967 if (pThisCC->Lun0.pNvramDrv)
1968 nvramStore(pThisCC);
1969}
1970
1971
1972
1973/**
1974 * Destruct a device instance.
1975 *
1976 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
1977 * resources can be freed correctly.
1978 *
1979 * @param pDevIns The device instance data.
1980 */
1981static DECLCALLBACK(int) efiDestruct(PPDMDEVINS pDevIns)
1982{
1983 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
1984 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
1985 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
1986
1987 nvramFlushDeviceVariableList(pThisCC);
1988
1989 if (pThisCC->pszNvramFile)
1990 {
1991 int rc = flashR3SaveToFile(&pThis->Flash, pDevIns, pThisCC->pszNvramFile);
1992 if (RT_FAILURE(rc))
1993 LogRel(("EFI: Failed to save flash file to '%s': %Rrc\n", pThisCC->pszNvramFile, rc));
1994 }
1995
1996 flashR3Destruct(&pThis->Flash, pDevIns);
1997
1998 if (pThisCC->pszNvramFile)
1999 {
2000 PDMDevHlpMMHeapFree(pDevIns, pThisCC->pszNvramFile);
2001 pThisCC->pszNvramFile = NULL;
2002 }
2003
2004 if (pThisCC->pu8EfiRomFree)
2005 {
2006 RTFileReadAllFree(pThisCC->pu8EfiRomFree, (size_t)pThisCC->cbEfiRom + pThisCC->offEfiRom);
2007 pThisCC->pu8EfiRomFree = NULL;
2008 }
2009
2010 /*
2011 * Free MM heap pointers (waste of time, but whatever).
2012 */
2013 if (pThisCC->pszEfiRomFile)
2014 {
2015 PDMDevHlpMMHeapFree(pDevIns, pThisCC->pszEfiRomFile);
2016 pThisCC->pszEfiRomFile = NULL;
2017 }
2018
2019 if (pThisCC->pu8EfiThunk)
2020 {
2021 PDMDevHlpMMHeapFree(pDevIns, pThisCC->pu8EfiThunk);
2022 pThisCC->pu8EfiThunk = NULL;
2023 }
2024
2025 if (pThisCC->pbDeviceProps)
2026 {
2027 PDMDevHlpMMHeapFree(pDevIns, pThisCC->pbDeviceProps);
2028 pThisCC->pbDeviceProps = NULL;
2029 pThisCC->cbDeviceProps = 0;
2030 }
2031
2032 return VINF_SUCCESS;
2033}
2034
2035
2036#if 0 /* unused */
2037/**
2038 * Helper that searches for a FFS file of a given type.
2039 *
2040 * @returns Pointer to the FFS file header if found, NULL if not.
2041 *
2042 * @param pFfsFile Pointer to the FFS file header to start searching at.
2043 * @param pbEnd The end of the firmware volume.
2044 * @param FileType The file type to look for.
2045 * @param pcbFfsFile Where to store the FFS file size (includes header).
2046 */
2047DECLINLINE(EFI_FFS_FILE_HEADER const *)
2048efiFwVolFindFileByType(EFI_FFS_FILE_HEADER const *pFfsFile, uint8_t const *pbEnd, EFI_FV_FILETYPE FileType, uint32_t *pcbFile)
2049{
2050# define FFS_SIZE(hdr) RT_MAKE_U32_FROM_U8((hdr)->Size[0], (hdr)->Size[1], (hdr)->Size[2], 0)
2051 while ((uintptr_t)pFfsFile < (uintptr_t)pbEnd)
2052 {
2053 if (pFfsFile->Type == FileType)
2054 {
2055 *pcbFile = FFS_SIZE(pFfsFile);
2056 LogFunc(("Found %RTuuid of type:%d\n", &pFfsFile->Name, FileType));
2057 return pFfsFile;
2058 }
2059 pFfsFile = (EFI_FFS_FILE_HEADER *)((uintptr_t)pFfsFile + RT_ALIGN(FFS_SIZE(pFfsFile), 8));
2060 }
2061# undef FFS_SIZE
2062 return NULL;
2063}
2064#endif /* unused */
2065
2066
2067/**
2068 * Parse EFI ROM headers and find entry points.
2069 *
2070 * @returns VBox status code.
2071 * @param pDevIns The device instance.
2072 * @param pThis The shared device state.
2073 * @param pThisCC The device state for the current context.
2074 */
2075static int efiParseFirmware(PPDMDEVINS pDevIns, PDEVEFI pThis, PDEVEFIR3 pThisCC)
2076{
2077 EFI_FIRMWARE_VOLUME_HEADER const *pFwVolHdr = (EFI_FIRMWARE_VOLUME_HEADER const *)pThisCC->pu8EfiRom;
2078
2079 /*
2080 * Validate firmware volume header.
2081 */
2082 AssertLogRelMsgReturn(pFwVolHdr->Signature == RT_MAKE_U32_FROM_U8('_', 'F', 'V', 'H'),
2083 ("%#x, expected %#x\n", pFwVolHdr->Signature, RT_MAKE_U32_FROM_U8('_', 'F', 'V', 'H')),
2084 VERR_INVALID_MAGIC);
2085 AssertLogRelMsgReturn(pFwVolHdr->Revision == EFI_FVH_REVISION,
2086 ("%#x, expected %#x\n", pFwVolHdr->Signature, EFI_FVH_REVISION),
2087 VERR_VERSION_MISMATCH);
2088 /** @todo check checksum, see PE spec vol. 3 */
2089 AssertLogRelMsgReturn(pFwVolHdr->FvLength <= pThisCC->cbEfiRom,
2090 ("%#llx, expected %#llx\n", pFwVolHdr->FvLength, pThisCC->cbEfiRom),
2091 VERR_INVALID_PARAMETER);
2092 AssertLogRelMsgReturn( pFwVolHdr->BlockMap[0].Length > 0
2093 && pFwVolHdr->BlockMap[0].NumBlocks > 0,
2094 ("%#x, %x\n", pFwVolHdr->BlockMap[0].Length, pFwVolHdr->BlockMap[0].NumBlocks),
2095 VERR_INVALID_PARAMETER);
2096
2097 AssertLogRelMsgReturn(!(pThisCC->cbEfiRom & PAGE_OFFSET_MASK), ("%RX64\n", pThisCC->cbEfiRom), VERR_INVALID_PARAMETER);
2098
2099 LogRel(("Found EFI FW Volume, %u bytes (%u %u-byte blocks)\n", pFwVolHdr->FvLength, pFwVolHdr->BlockMap[0].NumBlocks, pFwVolHdr->BlockMap[0].Length));
2100
2101 /** @todo Make this more dynamic, this assumes that the NV storage area comes first (always the case for our builds). */
2102 AssertLogRelMsgReturn(!memcmp(&pFwVolHdr->FileSystemGuid, &g_UuidNvDataFv, sizeof(g_UuidNvDataFv)),
2103 ("Expected EFI_SYSTEM_NV_DATA_FV_GUID as an identifier"),
2104 VERR_INVALID_MAGIC);
2105
2106 /* Found NVRAM storage, configure flash device. */
2107 pThisCC->offEfiRom = pFwVolHdr->FvLength;
2108 pThisCC->cbNvram = pFwVolHdr->FvLength;
2109 pThisCC->GCPhysNvram = UINT32_C(0xfffff000) - pThisCC->cbEfiRom + PAGE_SIZE;
2110 pThisCC->cbEfiRom -= pThisCC->cbNvram;
2111
2112 int rc = flashR3Init(&pThis->Flash, pThisCC->pDevIns, 0xA289 /*Intel*/, pThisCC->cbNvram, pFwVolHdr->BlockMap[0].Length);
2113 if (RT_FAILURE(rc))
2114 return rc;
2115
2116 /* If the file does not exist we initialize the NVRAM from the loaded ROM file. */
2117 if (!pThisCC->pszNvramFile || !RTPathExists(pThisCC->pszNvramFile))
2118 rc = flashR3LoadFromBuf(&pThis->Flash, pThisCC->pu8EfiRom, pThisCC->cbNvram);
2119 else
2120 rc = flashR3LoadFromFile(&pThis->Flash, pDevIns, pThisCC->pszNvramFile);
2121 if (RT_FAILURE(rc))
2122 return rc;
2123
2124 pThisCC->GCLoadAddress = pThisCC->GCPhysNvram + pThisCC->cbNvram;
2125
2126 return VINF_SUCCESS;
2127}
2128
2129/**
2130 * Load EFI ROM file into the memory.
2131 *
2132 * @returns VBox status code.
2133 * @param pDevIns The device instance.
2134 * @param pThis The shared Efi state.
2135 * @param pThisCC The device state for the current context.
2136 * @param pCfg Configuration node handle for the device.
2137 */
2138static int efiLoadRom(PPDMDEVINS pDevIns, PDEVEFI pThis, PDEVEFIR3 pThisCC, PCFGMNODE pCfg)
2139{
2140 RT_NOREF(pCfg);
2141
2142 /*
2143 * Read the entire firmware volume into memory.
2144 */
2145 int rc;
2146#ifdef VBOX_WITH_EFI_IN_DD2
2147 if (RTStrCmp(pThisCC->pszEfiRomFile, g_szEfiBuiltin32) == 0)
2148 {
2149 pThisCC->pu8EfiRomFree = NULL;
2150 pThisCC->pu8EfiRom = g_abEfiFirmware32;
2151 pThisCC->cbEfiRom = g_cbEfiFirmware32;
2152 }
2153 else if (RTStrCmp(pThisCC->pszEfiRomFile, g_szEfiBuiltin64) == 0)
2154 {
2155 pThisCC->pu8EfiRomFree = NULL;
2156 pThisCC->pu8EfiRom = g_abEfiFirmware64;
2157 pThisCC->cbEfiRom = g_cbEfiFirmware64;
2158 }
2159 else
2160#endif
2161 {
2162 void *pvFile;
2163 size_t cbFile;
2164 rc = RTFileReadAllEx(pThisCC->pszEfiRomFile,
2165 0 /*off*/,
2166 RTFOFF_MAX /*cbMax*/,
2167 RTFILE_RDALL_O_DENY_WRITE,
2168 &pvFile,
2169 &cbFile);
2170 if (RT_FAILURE(rc))
2171 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
2172 N_("Loading the EFI firmware volume '%s' failed with rc=%Rrc"),
2173 pThisCC->pszEfiRomFile, rc);
2174 pThisCC->pu8EfiRomFree = (uint8_t *)pvFile;
2175 pThisCC->pu8EfiRom = (uint8_t *)pvFile;
2176 pThisCC->cbEfiRom = cbFile;
2177 }
2178
2179 /*
2180 * Validate firmware volume and figure out the load address as well as the SEC entry point.
2181 */
2182 rc = efiParseFirmware(pDevIns, pThis, pThisCC);
2183 if (RT_FAILURE(rc))
2184 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
2185 N_("Parsing the EFI firmware volume '%s' failed with rc=%Rrc"),
2186 pThisCC->pszEfiRomFile, rc);
2187
2188 /*
2189 * Map the firmware volume into memory as shadowed ROM.
2190 *
2191 * This is a little complicated due to saved state legacy. We used to have a
2192 * 2MB image w/o any flash portion, divided into four 512KB mappings.
2193 *
2194 * We've now increased the size of the firmware to 4MB, but for saved state
2195 * compatibility reasons need to use the same mappings and names (!!) for the
2196 * top 2MB.
2197 */
2198 /** @todo fix PGMR3PhysRomRegister so it doesn't mess up in SUPLib when mapping a big ROM image. */
2199#if 1
2200 static const char * const s_apszNames[16] =
2201 {
2202 "EFI Firmware Volume", "EFI Firmware Volume (Part 2)", "EFI Firmware Volume (Part 3)", "EFI Firmware Volume (Part 4)",
2203 "EFI Firmware Volume (Part 5)", "EFI Firmware Volume (Part 6)", "EFI Firmware Volume (Part 7)", "EFI Firmware Volume (Part 8)",
2204 "EFI Firmware Volume (Part 9)", "EFI Firmware Volume (Part 10)", "EFI Firmware Volume (Part 11)", "EFI Firmware Volume (Part 12)",
2205 "EFI Firmware Volume (Part 13)", "EFI Firmware Volume (Part 14)", "EFI Firmware Volume (Part 15)", "EFI Firmware Volume (Part 16)",
2206 };
2207 AssertLogRelMsgReturn(pThisCC->cbEfiRom < RT_ELEMENTS(s_apszNames) * _512K,
2208 ("EFI firmware image too big: %#RX64, max %#zx\n",
2209 pThisCC->cbEfiRom, RT_ELEMENTS(s_apszNames) * _512K),
2210 VERR_IMAGE_TOO_BIG);
2211
2212 uint32_t const cbChunk = pThisCC->cbNvram + pThisCC->cbEfiRom >= _2M ? _512K
2213 : (uint32_t)RT_ALIGN_64((pThisCC->cbNvram + pThisCC->cbEfiRom) / 4, PAGE_SIZE);
2214 uint32_t cbLeft = pThisCC->cbEfiRom; /* ASSUMES NVRAM comes first! */
2215 uint32_t off = pThisCC->offEfiRom + cbLeft; /* ASSUMES NVRAM comes first! */
2216 RTGCPHYS64 GCPhys = pThisCC->GCLoadAddress + cbLeft;
2217 AssertLogRelMsg(GCPhys == _4G, ("%RGp\n", GCPhys));
2218
2219 /* Compatibility mappings at the top (note that this isn't entirely the same
2220 algorithm, but it will produce the same results for a power of two sized image): */
2221 unsigned i = 4;
2222 while (i-- > 0)
2223 {
2224 uint32_t const cb = RT_MIN(cbLeft, cbChunk);
2225 cbLeft -= cb;
2226 GCPhys -= cb;
2227 off -= cb;
2228 rc = PDMDevHlpROMRegister(pDevIns, GCPhys, cb, pThisCC->pu8EfiRom + off, cb,
2229 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, s_apszNames[i]);
2230 AssertRCReturn(rc, rc);
2231 }
2232
2233 /* The rest (if any) is mapped in descending order of address and increasing name order: */
2234 if (cbLeft > 0)
2235 {
2236 Assert(cbChunk == _512K);
2237 for (i = 4; cbLeft > 0; i++)
2238 {
2239 uint32_t const cb = RT_MIN(cbLeft, cbChunk);
2240 cbLeft -= cb;
2241 GCPhys -= cb;
2242 off -= cb;
2243 /** @todo Add flag to prevent saved state loading from bitching about these regions. */
2244 rc = PDMDevHlpROMRegister(pDevIns, GCPhys, cb, pThisCC->pu8EfiRom + off, cb,
2245 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY
2246 | PGMPHYS_ROM_FLAGS_MAYBE_MISSING_FROM_STATE, s_apszNames[i]);
2247 AssertRCReturn(rc, rc);
2248 }
2249 Assert(i <= RT_ELEMENTS(s_apszNames));
2250 }
2251
2252 /* Not sure what the purpose of this one is... */
2253 rc = PDMDevHlpROMProtectShadow(pDevIns, pThisCC->GCLoadAddress, (uint32_t)cbChunk, PGMROMPROT_READ_RAM_WRITE_IGNORE);
2254 AssertRCReturn(rc, rc);
2255
2256#else
2257 RTGCPHYS cbQuart = RT_ALIGN_64(pThisCC->cbEfiRom / 4, PAGE_SIZE);
2258 rc = PDMDevHlpROMRegister(pDevIns,
2259 pThisCC->GCLoadAddress,
2260 cbQuart,
2261 pThisCC->pu8EfiRom + pThisCC->uEfiRomOfs,
2262 cbQuart,
2263 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
2264 "EFI Firmware Volume");
2265 AssertRCReturn(rc, rc);
2266 rc = PDMDevHlpROMProtectShadow(pDevIns, pThisCC->GCLoadAddress, (uint32_t)cbQuart, PGMROMPROT_READ_RAM_WRITE_IGNORE);
2267 AssertRCReturn(rc, rc);
2268 rc = PDMDevHlpROMRegister(pDevIns,
2269 pThisCC->GCLoadAddress + cbQuart,
2270 cbQuart,
2271 pThisCC->pu8EfiRom + pThisCC->uEfiRomOfs + cbQuart,
2272 cbQuart,
2273 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
2274 "EFI Firmware Volume (Part 2)");
2275 if (RT_FAILURE(rc))
2276 return rc;
2277 rc = PDMDevHlpROMRegister(pDevIns,
2278 pThisCC->GCLoadAddress + cbQuart * 2,
2279 cbQuart,
2280 pThisCC->pu8EfiRom + pThisCC->uEfiRomOfs + cbQuart * 2,
2281 cbQuart,
2282 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
2283 "EFI Firmware Volume (Part 3)");
2284 if (RT_FAILURE(rc))
2285 return rc;
2286 rc = PDMDevHlpROMRegister(pDevIns,
2287 pThisCC->GCLoadAddress + cbQuart * 3,
2288 pThisCC->cbEfiRom - cbQuart * 3,
2289 pThisCC->pu8EfiRom + pThisCC->uEfiRomOfs + cbQuart * 3,
2290 pThisCC->cbEfiRom - cbQuart * 3,
2291 PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY,
2292 "EFI Firmware Volume (Part 4)");
2293 if (RT_FAILURE(rc))
2294 return rc;
2295#endif
2296
2297 /*
2298 * Register MMIO region for flash device.
2299 */
2300 rc = PDMDevHlpMmioCreateEx(pDevIns, pThisCC->cbNvram, IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
2301 NULL /*pPciDev*/, UINT32_MAX, efiR3NvMmioWrite, efiR3NvMmioRead, NULL, NULL /*pvUser*/,
2302 "Flash Memory", &pThis->hMmioFlash);
2303 AssertRCReturn(rc, rc);
2304 rc = PDMDevHlpMmioMap(pDevIns, pThis->hMmioFlash, pThisCC->GCPhysNvram);
2305 AssertRCReturn(rc, rc);
2306
2307 LogRel(("EFI: Registered %uKB flash at %RGp\n", pThisCC->cbNvram / _1K, pThisCC->GCPhysNvram));
2308 return VINF_SUCCESS;
2309}
2310
2311static uint8_t efiGetHalfByte(char ch)
2312{
2313 uint8_t val;
2314
2315 if (ch >= '0' && ch <= '9')
2316 val = ch - '0';
2317 else if (ch >= 'A' && ch <= 'F')
2318 val = ch - 'A' + 10;
2319 else if(ch >= 'a' && ch <= 'f')
2320 val = ch - 'a' + 10;
2321 else
2322 val = 0xff;
2323
2324 return val;
2325}
2326
2327
2328/**
2329 * Converts a hex string into a binary data blob located at
2330 * pThisCC->pbDeviceProps, size returned as pThisCC->cbDeviceProps.
2331 *
2332 * @returns VERR_NO_MEMORY or VINF_SUCCESS.
2333 * @param pThisCC The device state for the current context.
2334 * @param pszDeviceProps The device property hex string to decode.
2335 */
2336static int efiParseDeviceString(PDEVEFIR3 pThisCC, const char *pszDeviceProps)
2337{
2338 uint32_t const cbOut = (uint32_t)RTStrNLen(pszDeviceProps, RTSTR_MAX) / 2 + 1;
2339 pThisCC->pbDeviceProps = (uint8_t *)PDMDevHlpMMHeapAlloc(pThisCC->pDevIns, cbOut);
2340 if (!pThisCC->pbDeviceProps)
2341 return VERR_NO_MEMORY;
2342
2343 uint32_t iHex = 0;
2344 bool fUpper = true;
2345 uint8_t u8Value = 0; /* (shut up gcc) */
2346 for (uint32_t iStr = 0; pszDeviceProps[iStr]; iStr++)
2347 {
2348 uint8_t u8Hb = efiGetHalfByte(pszDeviceProps[iStr]);
2349 if (u8Hb > 0xf)
2350 continue;
2351
2352 if (fUpper)
2353 u8Value = u8Hb << 4;
2354 else
2355 pThisCC->pbDeviceProps[iHex++] = u8Hb | u8Value;
2356
2357 Assert(iHex < cbOut);
2358 fUpper = !fUpper;
2359 }
2360
2361 Assert(iHex == 0 || fUpper);
2362 pThisCC->cbDeviceProps = iHex;
2363
2364 return VINF_SUCCESS;
2365}
2366
2367
2368/**
2369 * @interface_method_impl{PDMDEVREG,pfnConstruct}
2370 */
2371static DECLCALLBACK(int) efiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
2372{
2373 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2374 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
2375 PDEVEFIR3 pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVEFIR3);
2376 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
2377 int rc;
2378
2379 RT_NOREF(iInstance);
2380 Assert(iInstance == 0);
2381
2382 /*
2383 * Initalize the basic variables so that the destructor always works.
2384 */
2385 pThisCC->pDevIns = pDevIns;
2386 RTListInit(&pThisCC->NVRAM.VarList);
2387 pThisCC->Lun0.IBase.pfnQueryInterface = devEfiQueryInterface;
2388
2389 /*
2390 * Validate and read the configuration.
2391 */
2392 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns,
2393 "EfiRom|"
2394 "NumCPUs|"
2395 "McfgBase|"
2396 "McfgLength|"
2397 "UUID|"
2398 "UuidLe|"
2399 "IOAPIC|"
2400 "APIC|"
2401 "DmiBIOSFirmwareMajor|"
2402 "DmiBIOSFirmwareMinor|"
2403 "DmiBIOSReleaseDate|"
2404 "DmiBIOSReleaseMajor|"
2405 "DmiBIOSReleaseMinor|"
2406 "DmiBIOSVendor|"
2407 "DmiBIOSVersion|"
2408 "DmiSystemFamily|"
2409 "DmiSystemProduct|"
2410 "DmiSystemSerial|"
2411 "DmiSystemSKU|"
2412 "DmiSystemUuid|"
2413 "DmiSystemVendor|"
2414 "DmiSystemVersion|"
2415 "DmiBoardAssetTag|"
2416 "DmiBoardBoardType|"
2417 "DmiBoardLocInChass|"
2418 "DmiBoardProduct|"
2419 "DmiBoardSerial|"
2420 "DmiBoardVendor|"
2421 "DmiBoardVersion|"
2422 "DmiChassisAssetTag|"
2423 "DmiChassisSerial|"
2424 "DmiChassisType|"
2425 "DmiChassisVendor|"
2426 "DmiChassisVersion|"
2427 "DmiProcManufacturer|"
2428 "DmiProcVersion|"
2429 "DmiOEMVBoxVer|"
2430 "DmiOEMVBoxRev|"
2431 "DmiUseHostInfo|"
2432 "DmiExposeMemoryTable|"
2433 "DmiExposeProcInf|"
2434 "64BitEntry|"
2435 "BootArgs|"
2436 "DeviceProps|"
2437 "GopMode|" // legacy
2438 "GraphicsMode|"
2439 "UgaHorizontalResolution|" // legacy
2440 "UgaVerticalResolution|" // legacy
2441 "GraphicsResolution|"
2442 "NvramFile", "");
2443
2444 /* CPU count (optional). */
2445 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "NumCPUs", &pThisCC->cCpus, 1);
2446 AssertLogRelRCReturn(rc, rc);
2447
2448 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "McfgBase", &pThisCC->u64McfgBase, 0);
2449 if (RT_FAILURE(rc))
2450 return PDMDEV_SET_ERROR(pDevIns, rc,
2451 N_("Configuration error: Querying \"\" as integer failed"));
2452 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "McfgLength", &pThisCC->cbMcfgLength, 0);
2453 if (RT_FAILURE(rc))
2454 return PDMDEV_SET_ERROR(pDevIns, rc,
2455 N_("Configuration error: Querying \"McfgLength\" as integer failed"));
2456
2457 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "IOAPIC", &pThisCC->u8IOAPIC, 1);
2458 if (RT_FAILURE (rc))
2459 return PDMDEV_SET_ERROR(pDevIns, rc,
2460 N_("Configuration error: Failed to read \"IOAPIC\""));
2461
2462 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "APIC", &pThisCC->u8APIC, 1);
2463 if (RT_FAILURE (rc))
2464 return PDMDEV_SET_ERROR(pDevIns, rc,
2465 N_("Configuration error: Failed to read \"APIC\""));
2466
2467 /*
2468 * Query the machine's UUID for SMBIOS/DMI use.
2469 */
2470 RTUUID uuid;
2471 rc = pHlp->pfnCFGMQueryBytes(pCfg, "UUID", &uuid, sizeof(uuid));
2472 if (RT_FAILURE(rc))
2473 return PDMDEV_SET_ERROR(pDevIns, rc,
2474 N_("Configuration error: Querying \"UUID\" failed"));
2475
2476 bool fUuidLe;
2477 rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "UuidLe", &fUuidLe, false);
2478 if (RT_FAILURE(rc))
2479 return PDMDEV_SET_ERROR(pDevIns, rc,
2480 N_("Configuration error: Querying \"UuidLe\" failed"));
2481
2482 if (!fUuidLe)
2483 {
2484 /*
2485 * UUIDs are stored little endian actually (see chapter 7.2.1 System — UUID
2486 * of the DMI/SMBIOS spec) but to not force reactivation of existing guests we have
2487 * to carry this bug along... (see also DevPcBios.cpp when changing this)
2488 *
2489 * Convert the UUID to network byte order. Not entirely straightforward as
2490 * parts are MSB already...
2491 */
2492 uuid.Gen.u32TimeLow = RT_H2BE_U32(uuid.Gen.u32TimeLow);
2493 uuid.Gen.u16TimeMid = RT_H2BE_U16(uuid.Gen.u16TimeMid);
2494 uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
2495 }
2496 memcpy(&pThisCC->aUuid, &uuid, sizeof pThisCC->aUuid);
2497
2498 /*
2499 * Get the system EFI ROM file name.
2500 */
2501#ifdef VBOX_WITH_EFI_IN_DD2
2502 rc = pHlp->pfnCFGMQueryStringAllocDef(pCfg, "EfiRom", &pThisCC->pszEfiRomFile, g_szEfiBuiltin32);
2503 if (RT_FAILURE(rc))
2504#else
2505 rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "EfiRom", &pThisCC->pszEfiRomFile);
2506 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
2507 {
2508 pThisCC->pszEfiRomFile = (char *)PDMDevHlpMMHeapAlloc(pDevIns, RTPATH_MAX);
2509 AssertReturn(pThisCC->pszEfiRomFile, VERR_NO_MEMORY);
2510 rc = RTPathAppPrivateArchTop(pThisCC->pszEfiRomFile, RTPATH_MAX);
2511 AssertRCReturn(rc, rc);
2512 rc = RTPathAppend(pThisCC->pszEfiRomFile, RTPATH_MAX, "VBoxEFI32.fd");
2513 AssertRCReturn(rc, rc);
2514 }
2515 else if (RT_FAILURE(rc))
2516#endif
2517 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
2518 N_("Configuration error: Querying \"EfiRom\" as a string failed"));
2519
2520 /*
2521 * NVRAM processing.
2522 */
2523 rc = PDMDevHlpSSMRegister(pDevIns, EFI_SSM_VERSION, sizeof(*pThisCC), efiSaveExec, efiLoadExec);
2524 AssertRCReturn(rc, rc);
2525
2526 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThisCC->Lun0.IBase, &pThisCC->Lun0.pDrvBase, "NvramStorage");
2527 if (RT_SUCCESS(rc))
2528 {
2529 pThisCC->Lun0.pNvramDrv = PDMIBASE_QUERY_INTERFACE(pThisCC->Lun0.pDrvBase, PDMINVRAMCONNECTOR);
2530 AssertPtrReturn(pThisCC->Lun0.pNvramDrv, VERR_PDM_MISSING_INTERFACE_BELOW);
2531
2532 rc = nvramLoad(pThisCC);
2533 AssertRCReturn(rc, rc);
2534 }
2535 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2536 {
2537 pThisCC->Lun0.pNvramDrv = NULL;
2538 rc = VINF_SUCCESS; /* Missing driver is no error condition. */
2539 }
2540 else
2541 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("Can't attach Nvram Storage driver"));
2542
2543 /*
2544 * Get boot args.
2545 */
2546 rc = pHlp->pfnCFGMQueryStringDef(pCfg, "BootArgs", pThisCC->szBootArgs, sizeof(pThisCC->szBootArgs), "");
2547 if (RT_FAILURE(rc))
2548 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
2549 N_("Configuration error: Querying \"BootArgs\" as a string failed"));
2550
2551 //strcpy(pThisCC->szBootArgs, "-v keepsyms=1 io=0xf debug=0x2a");
2552 //strcpy(pThisCC->szBootArgs, "-v keepsyms=1 debug=0x2a");
2553 LogRel(("EFI: boot args = %s\n", pThisCC->szBootArgs));
2554
2555 /*
2556 * Get device props.
2557 */
2558 char *pszDeviceProps;
2559 rc = pHlp->pfnCFGMQueryStringAllocDef(pCfg, "DeviceProps", &pszDeviceProps, NULL);
2560 if (RT_FAILURE(rc))
2561 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
2562 N_("Configuration error: Querying \"DeviceProps\" as a string failed"));
2563 if (pszDeviceProps)
2564 {
2565 LogRel(("EFI: device props = %s\n", pszDeviceProps));
2566 rc = efiParseDeviceString(pThisCC, pszDeviceProps);
2567 PDMDevHlpMMHeapFree(pDevIns, pszDeviceProps);
2568 if (RT_FAILURE(rc))
2569 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
2570 N_("Configuration error: Cannot parse device properties"));
2571 }
2572 else
2573 {
2574 pThisCC->pbDeviceProps = NULL;
2575 pThisCC->cbDeviceProps = 0;
2576 }
2577
2578 /*
2579 * CPU frequencies.
2580 */
2581 pThisCC->u64TscFrequency = TMCpuTicksPerSecond(PDMDevHlpGetVM(pDevIns));
2582 pThisCC->u64CpuFrequency = pThisCC->u64TscFrequency;
2583 pThisCC->u64FsbFrequency = CPUMGetGuestScalableBusFrequency(PDMDevHlpGetVM(pDevIns));
2584
2585 /*
2586 * EFI graphics mode (with new EFI VGA code used only as a fallback, for
2587 * old EFI VGA code the only way to select the GOP mode).
2588 */
2589 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "GraphicsMode", &pThisCC->u32GraphicsMode, UINT32_MAX);
2590 if (RT_FAILURE(rc))
2591 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
2592 N_("Configuration error: Querying \"GraphicsMode\" as a 32-bit int failed"));
2593 if (pThisCC->u32GraphicsMode == UINT32_MAX)
2594 {
2595 /* get the legacy value if nothing else was specified */
2596 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "GopMode", &pThisCC->u32GraphicsMode, UINT32_MAX);
2597 if (RT_FAILURE(rc))
2598 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
2599 N_("Configuration error: Querying \"GopMode\" as a 32-bit int failed"));
2600 }
2601 if (pThisCC->u32GraphicsMode == UINT32_MAX)
2602 pThisCC->u32GraphicsMode = 2; /* 1024x768, at least typically */
2603
2604 /*
2605 * EFI graphics resolution, defaults to 1024x768 (used to be UGA only, now
2606 * is the main config setting as the mode number is so hard to predict).
2607 */
2608 char szResolution[16];
2609 rc = pHlp->pfnCFGMQueryStringDef(pCfg, "GraphicsResolution", szResolution, sizeof(szResolution), "");
2610 if (RT_FAILURE(rc))
2611 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
2612 N_("Configuration error: Querying \"GraphicsResolution\" as a string failed"));
2613 if (szResolution[0])
2614 {
2615 const char *pszX = RTStrStr(szResolution, "x");
2616 if (pszX)
2617 {
2618 pThisCC->u32HorizontalResolution = RTStrToUInt32(szResolution);
2619 pThisCC->u32VerticalResolution = RTStrToUInt32(pszX + 1);
2620 }
2621 }
2622 else
2623 {
2624 /* get the legacy values if nothing else was specified */
2625 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "UgaHorizontalResolution", &pThisCC->u32HorizontalResolution, 0);
2626 AssertRCReturn(rc, rc);
2627 rc = pHlp->pfnCFGMQueryU32Def(pCfg, "UgaVerticalResolution", &pThisCC->u32VerticalResolution, 0);
2628 AssertRCReturn(rc, rc);
2629 }
2630 if (pThisCC->u32HorizontalResolution == 0 || pThisCC->u32VerticalResolution == 0)
2631 {
2632 pThisCC->u32HorizontalResolution = 1024;
2633 pThisCC->u32VerticalResolution = 768;
2634 }
2635
2636 pThisCC->pszNvramFile = NULL;
2637 rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "NvramFile", &pThisCC->pszNvramFile);
2638 if (RT_FAILURE(rc) && rc != VERR_CFGM_VALUE_NOT_FOUND)
2639 return PDMDEV_SET_ERROR(pDevIns, rc,
2640 N_("Configuration error: Querying \"NvramFile\" as a string failed"));
2641
2642 /*
2643 * Load firmware volume and thunk ROM.
2644 */
2645 rc = efiLoadRom(pDevIns, pThis, pThisCC, pCfg);
2646 if (RT_FAILURE(rc))
2647 return rc;
2648
2649 /*
2650 * Register our I/O ports.
2651 */
2652 rc = PDMDevHlpIoPortCreateFlagsAndMap(pDevIns, EFI_PORT_BASE, EFI_PORT_COUNT, IOM_IOPORT_F_ABS,
2653 efiR3IoPortWrite, efiR3IoPortRead,
2654 "EFI communication ports", NULL /*paExtDescs*/, &pThis->hIoPorts);
2655 AssertRCReturn(rc, rc);
2656
2657 /*
2658 * Plant DMI and MPS tables in the ROM region.
2659 */
2660 rc = FwCommonPlantDMITable(pDevIns, pThisCC->au8DMIPage, VBOX_DMI_TABLE_SIZE, &pThisCC->aUuid,
2661 pDevIns->pCfg, pThisCC->cCpus, &pThisCC->cbDmiTables, &pThisCC->cNumDmiTables,
2662 true /*fUefi*/);
2663 AssertRCReturn(rc, rc);
2664
2665 /*
2666 * NB: VBox/Devices/EFI/Firmware/VBoxPkg/VBoxSysTables/VBoxSysTables.c scans memory for
2667 * the SMBIOS header. The header must be placed in a range that EFI will scan.
2668 */
2669 FwCommonPlantSmbiosAndDmiHdrs(pDevIns, pThisCC->au8DMIPage + VBOX_DMI_TABLE_SIZE,
2670 pThisCC->cbDmiTables, pThisCC->cNumDmiTables);
2671
2672 if (pThisCC->u8IOAPIC)
2673 {
2674 FwCommonPlantMpsTable(pDevIns,
2675 pThisCC->au8DMIPage /* aka VBOX_DMI_TABLE_BASE */ + VBOX_DMI_TABLE_SIZE + VBOX_DMI_HDR_SIZE,
2676 _4K - VBOX_DMI_TABLE_SIZE - VBOX_DMI_HDR_SIZE, pThisCC->cCpus);
2677 FwCommonPlantMpsFloatPtr(pDevIns, VBOX_DMI_TABLE_BASE + VBOX_DMI_TABLE_SIZE + VBOX_DMI_HDR_SIZE);
2678 }
2679
2680 rc = PDMDevHlpROMRegister(pDevIns, VBOX_DMI_TABLE_BASE, _4K, pThisCC->au8DMIPage, _4K,
2681 PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "DMI tables");
2682
2683 AssertRCReturn(rc, rc);
2684
2685 /*
2686 * Register info handlers.
2687 */
2688 rc = PDMDevHlpDBGFInfoRegister(pDevIns, "nvram", "Dumps the NVRAM variables.\n", efiInfoNvram);
2689 AssertRCReturn(rc, rc);
2690
2691 /*
2692 * Call reset to set things up.
2693 */
2694 efiReset(pDevIns);
2695
2696 return VINF_SUCCESS;
2697}
2698
2699#else /* IN_RING3 */
2700
2701
2702/**
2703 * @callback_method_impl{PDMDEVREGR0,pfnConstruct}
2704 */
2705static DECLCALLBACK(int) efiRZConstruct(PPDMDEVINS pDevIns)
2706{
2707 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2708 PDEVEFI pThis = PDMDEVINS_2_DATA(pDevIns, PDEVEFI);
2709
2710# if 1
2711 int rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmioFlash, efiR3NvMmioWrite, efiR3NvMmioRead, NULL /*pvUser*/);
2712 AssertRCReturn(rc, rc);
2713# else
2714 RT_NOREF(pDevIns, pThis); (void)&efiR3NvMmioRead; (void)&efiR3NvMmioWrite;
2715# endif
2716
2717 return VINF_SUCCESS;
2718}
2719
2720
2721#endif /* IN_RING3 */
2722
2723/**
2724 * The device registration structure.
2725 */
2726const PDMDEVREG g_DeviceEFI =
2727{
2728 /* .u32Version = */ PDM_DEVREG_VERSION,
2729 /* .uReserved0 = */ 0,
2730 /* .szName = */ "efi",
2731 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
2732 /* .fClass = */ PDM_DEVREG_CLASS_ARCH_BIOS,
2733 /* .cMaxInstances = */ 1,
2734 /* .uSharedVersion = */ 42,
2735 /* .cbInstanceShared = */ sizeof(DEVEFI),
2736 /* .cbInstanceCC = */ sizeof(DEVEFICC),
2737 /* .cbInstanceRC = */ sizeof(DEVEFIRC),
2738 /* .cMaxPciDevices = */ 0,
2739 /* .cMaxMsixVectors = */ 0,
2740 /* .pszDescription = */ "Extensible Firmware Interface Device.\n"
2741 "LUN#0 - NVRAM port",
2742#if defined(IN_RING3)
2743 /* .pszRCMod = */ "VBoxDDRC.rc",
2744 /* .pszR0Mod = */ "VBoxDDR0.r0",
2745 /* .pfnConstruct = */ efiConstruct,
2746 /* .pfnDestruct = */ efiDestruct,
2747 /* .pfnRelocate = */ NULL,
2748 /* .pfnMemSetup = */ efiMemSetup,
2749 /* .pfnPowerOn = */ NULL,
2750 /* .pfnReset = */ efiReset,
2751 /* .pfnSuspend = */ NULL,
2752 /* .pfnResume = */ NULL,
2753 /* .pfnAttach = */ NULL,
2754 /* .pfnDetach = */ NULL,
2755 /* .pfnQueryInterface = */ NULL,
2756 /* .pfnInitComplete = */ efiInitComplete,
2757 /* .pfnPowerOff = */ efiPowerOff,
2758 /* .pfnSoftReset = */ NULL,
2759 /* .pfnReserved0 = */ NULL,
2760 /* .pfnReserved1 = */ NULL,
2761 /* .pfnReserved2 = */ NULL,
2762 /* .pfnReserved3 = */ NULL,
2763 /* .pfnReserved4 = */ NULL,
2764 /* .pfnReserved5 = */ NULL,
2765 /* .pfnReserved6 = */ NULL,
2766 /* .pfnReserved7 = */ NULL,
2767#elif defined(IN_RING0)
2768 /* .pfnEarlyConstruct = */ NULL,
2769 /* .pfnConstruct = */ efiRZConstruct,
2770 /* .pfnDestruct = */ NULL,
2771 /* .pfnFinalDestruct = */ NULL,
2772 /* .pfnRequest = */ NULL,
2773 /* .pfnReserved0 = */ NULL,
2774 /* .pfnReserved1 = */ NULL,
2775 /* .pfnReserved2 = */ NULL,
2776 /* .pfnReserved3 = */ NULL,
2777 /* .pfnReserved4 = */ NULL,
2778 /* .pfnReserved5 = */ NULL,
2779 /* .pfnReserved6 = */ NULL,
2780 /* .pfnReserved7 = */ NULL,
2781#elif defined(IN_RC)
2782 /* .pfnConstruct = */ efiRZConstruct,
2783 /* .pfnReserved0 = */ NULL,
2784 /* .pfnReserved1 = */ NULL,
2785 /* .pfnReserved2 = */ NULL,
2786 /* .pfnReserved3 = */ NULL,
2787 /* .pfnReserved4 = */ NULL,
2788 /* .pfnReserved5 = */ NULL,
2789 /* .pfnReserved6 = */ NULL,
2790 /* .pfnReserved7 = */ NULL,
2791#else
2792# error "Not in IN_RING3, IN_RING0 or IN_RC!"
2793#endif
2794 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
2795};
2796
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