VirtualBox

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

Last change on this file since 81591 was 81591, checked in by vboxsync, 5 years ago

Devices: Use PDMDEVINS_2_DATA and PDMDEVINS_2_DATA. bugref:9218

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