DevEFI.cpp revision c4ccc0915f8ac8c1d8eb0565a17043dda0a666dd
/* $Id$ */
/** @file
* DevEFI - EFI <-> VirtualBox Integration Framework.
*/
/*
* Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_DEV_EFI
#ifdef DEBUG
# define DEVEFI_WITH_VBOXDBG_SCRIPT
#endif
#include "VBoxDD.h"
#include "VBoxDD2.h"
#include "../PC/DevFwCommon.h"
/* EFI includes */
#include <ProcessorBind.h>
#include <Common/UefiBaseTypes.h>
#include <Common/PiFirmwareVolume.h>
#include <Common/PiFirmwareFile.h>
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* EFI NVRAM variable.
*/
typedef struct EFIVAR
{
/** The list node for the variable. */
/** The unique sequence number of the variable.
* This is used to find pCurVar when restoring saved state and therefore only
* set when saving. */
/** The value attributess. */
/** The variable name length (not counting the terminator char). */
/** The size of the value. This cannot be zero. */
/** The vendor UUID scoping the variable name. */
/** The variable name. */
char szName[EFI_VARIABLE_NAME_MAX];
/** The variable value bytes. */
} EFIVAR;
/** Pointer to an EFI NVRAM variable. */
/** Pointer to an EFI NVRAM variable pointer. */
/**
* NVRAM state.
*/
typedef struct NVRAMDESC
{
/** The current operation. */
/** The current status. */
/** The current */
/** The current number of variables. */
/** The list of variables. */
/** The unique variable sequence ID, for the saved state only.
* @todo It's part of this structure for hysterical raisins, consider remove it
* when changing the saved state format the next time. */
/** Variable buffered used both when adding and querying NVRAM variables.
* When querying a variable, a copy of it is stored in this buffer and read
* from it. When adding, updating or deleting a variable, this buffer is used
* to set up the parameters before taking action. */
/** The current variable. This is only used by EFI_VARIABLE_OP_QUERY_NEXT,
* the attribute readers work against the copy in VarOpBuf. */
} NVRAMDESC;
/**
* The EFI device state structure.
*/
typedef struct DEVEFI
{
/** Pointer back to the device instance. */
/** EFI message buffer. */
char szMsg[VBOX_EFI_DEBUG_BUFFER];
/** EFI message buffer index. */
/** EFI panic message buffer. */
char szPanicMsg[2048];
/** EFI panic message buffer index. */
/** The system EFI ROM data. */
/** The size of the system EFI ROM. */
/** The name of the EFI ROM file. */
char *pszEfiRomFile;
/** Thunk page pointer. */
/** First entry point of the EFI firmware. */
/** Second Entry Point (PeiCore)*/
/** EFI firmware physical load address. */
/** Current info selector. */
/** Current info position. */
/** Number of virtual CPUs. (Config) */
/** RAM below 4GB (in bytes). (Config) */
/** RAM above 4GB (in bytes). (Config) */
/** The total amount of memory. */
/** The size of the RAM hole below 4GB. */
/** The size of the DMI tables. */
/** The DMI tables. */
/** Boot parameters passed to the firmware. */
char szBootArgs[256];
/** Host UUID (for DMI). */
/** Device properties buffer. */
/** Device properties buffer size. */
/** Virtual machine front side bus frequency. */
/** Virtual machine time stamp counter frequency. */
/** Virtual machine CPU frequency. */
/** GOP mode. */
/** Uga mode horisontal resolution. */
/** Uga mode vertical resolution. */
/** NVRAM state variables. */
/**
* NVRAM port - LUN\#0.
*/
struct
{
/** The base interface we provide the NVRAM driver. */
/** The NVRAM driver base interface. */
/** The NVRAM interface provided by the driver. */
} Lun0;
} DEVEFI;
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** The saved state version. */
#define EFI_SSM_VERSION 2
/** The saved state version from VBox 4.2. */
#define EFI_SSM_VERSION_4_2 1
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** Saved state NVRAMDESC field descriptors. */
static SSMFIELD const g_aEfiNvramDescField[] =
{
};
/** Saved state EFIVAR field descriptors. */
static SSMFIELD const g_aEfiVariableDescFields[] =
{
};
/**
* Flushes the variable list.
*
* @param pThis The EFI state.
*/
{
{
}
}
/**
* This function looks up variable in NVRAM list.
*/
static int nvramLookupVariableByUuidAndName(PDEVEFI pThis, char *pszVariableName, PCRTUUID pUuid, PPEFIVAR ppEfiVar)
{
int rc = VERR_NOT_FOUND;
uint32_t cVariables = 0;
{
cVariables++;
if ( pEfiVar
{
rc = VINF_SUCCESS;
break;
}
}
return rc;
}
/**
* Creates an device internal list of variables.
*
* @returns VBox status code.
* @param pThis The EFI state.
*/
{
int rc;
{
if (RT_SUCCESS(rc))
{
/* Some validations. */
rc = VERR_NO_DATA;
if (RT_FAILURE(rc))
}
if (RT_FAILURE(rc))
{
if (rc == VERR_NOT_FOUND)
rc = VINF_SUCCESS;
return rc;
}
/* Append it. */
}
AssertLogRelMsgFailed(("EFI: Too many variables.\n"));
return VERR_TOO_MUCH_DATA;
}
/**
* Let the NVRAM driver store the internal NVRAM variable list.
*
* @returns VBox status code.
* @param pThis The EFI state.
*/
{
int rc = pThis->Lun0.pNvramDrv->pfnVarStoreSeqBegin(pThis->Lun0.pNvramDrv, pThis->NVRAM.cVariables);
if (RT_SUCCESS(rc))
{
{
{
}
idxVar++;
}
}
else
return rc;
}
/**
* EFI_VARIABLE_OP_QUERY and EFI_VARIABLE_OP_QUERY_NEXT worker that copies the
* variable into the VarOpBuf, set pCurVar and u32Status.
*
* @param pThis The EFI state.
* @param pEfiVar The resulting variable. NULL if not found / end.
*/
{
if (pEfiVar)
{
}
else
{
LogFlow(("EFI: Variable query -> NOT_FOUND\n"));
}
}
/**
* Implements EFI_VARIABLE_PARAM + EFI_VARIABLE_OP_QUERY.
*
* @returns IOM strict status code.
* @param pThis The EFI state.
*/
{
LogRel(("EFI: Querying Variable %RTuuid::'%s'\n",
&pEfiVar);
return VINF_SUCCESS;
}
/**
* Implements EFI_VARIABLE_PARAM + EFI_VARIABLE_OP_QUERY_NEXT.
*
* This simply walks the list.
*
* @returns IOM strict status code.
* @param pThis The EFI state.
*/
{
Log(("EFI: Querying next variable...\n"));
if (pEfiVar)
return VINF_SUCCESS;
}
/**
* Implements EFI_VARIABLE_PARAM + EFI_VARIABLE_OP_ADD.
*
* @returns IOM strict status code.
* @param pThis The EFI state.
*/
{
LogRel(("EFI: Adding variable %RTuuid::'%s'\n", &pThis->NVRAM.VarOpBuf.uuid, pThis->NVRAM.VarOpBuf.szName));
/*
* Validate the input a little.
*/
if (RT_FAILURE(rc))
LogRel(("EFI: Badly encoded variable name: %.*Rhxs\n", pThis->NVRAM.VarOpBuf.cchName + 1, pThis->NVRAM.VarOpBuf.szName));
{
LogRel(("EFI: Bad name length %#x, expected %#x: %.*Rhxs\n",
cchName, pThis->NVRAM.VarOpBuf.cchName, pThis->NVRAM.VarOpBuf.cchName + 1, pThis->NVRAM.VarOpBuf.szName));
}
if (RT_FAILURE(rc))
{
return VINF_SUCCESS;
}
/*
* Look it up and see what to do.
*/
&pEfiVar);
if (RT_SUCCESS(rc))
{
#if 0 /** @todo Implement read-only EFI variables. */
{
break;
}
#endif
{
/*
* Delete it.
*/
LogFlow(("nvramWriteVariableOpAdd: Delete\n"));
}
else
{
/*
*/
LogFlow(("nvramWriteVariableOpAdd: Replace\n"));
}
}
{
/* delete operation, but nothing to delete. */
LogFlow(("nvramWriteVariableOpAdd: Delete (not found)\n"));
}
{
/*
* Add a new variable.
*/
LogFlow(("nvramWriteVariableOpAdd: New\n"));
if (pEfiVar)
{
memcpy(pEfiVar->szName, pThis->NVRAM.VarOpBuf.szName, pEfiVar->cchName); /* The buffer is zeroed, so skip '\0'. */
}
else
}
else
{
/*
* Too many variables.
*/
static unsigned s_cWarnings = 0;
if (s_cWarnings++ < 5)
LogRel(("EFI: Too many variables.\n"));
Log(("nvramWriteVariableOpAdd: Too many variabled.\n"));
}
return VINF_SUCCESS;
}
/**
* Implements EFI_VARIABLE_PARAM writes.
*
* @returns IOM strict status code.
* @param pThis The EFI state.
* @param u32Value The value being written.
*/
{
int rc = VINF_SUCCESS;
{
case EFI_VM_VARIABLE_OP_START:
switch (u32Value)
{
case EFI_VARIABLE_OP_QUERY:
break;
break;
case EFI_VARIABLE_OP_ADD:
break;
default:
break;
}
break;
case EFI_VM_VARIABLE_OP_GUID:
else
{
}
break;
break;
case EFI_VM_VARIABLE_OP_NAME:
else if (u32Value == 0)
else
{
}
break;
else
{
LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_NAME_LENGTH write (%#x, max %#x).\n",
}
break;
{
/* Currently simplifying this to UCS2, i.e. no surrogates. */
{
}
else if (u32Value == 0)
else
{
}
break;
}
case EFI_VM_VARIABLE_OP_VALUE:
else
{
}
break;
else
{
LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_VALUE_LENGTH write (%#x, max %#x).\n",
}
break;
default:
break;
}
return VINF_SUCCESS;
}
/**
* Implements EFI_VARIABLE_OP reads.
*
* @returns IOM strict status code.
* @param pThis The EFI state.
* @param u32Value The value being written.
*/
{
{
case EFI_VM_VARIABLE_OP_START:
break;
case EFI_VM_VARIABLE_OP_GUID:
else
{
if (cb == 1)
LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_GUID read.\n"));
else
*pu32 = UINT32_MAX;
}
break;
break;
case EFI_VM_VARIABLE_OP_NAME:
/* allow reading terminator char */
else
{
if (cb == 1)
LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_NAME read.\n"));
else
*pu32 = UINT32_MAX;
}
break;
break;
/* Lazy bird: ASSUME no surrogate pairs. */
{
}
{
*pu32 = 0;
}
else
{
if (cb == 1)
LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_NAME_UTF16 read.\n"));
else
*pu32 = UINT32_MAX;
}
break;
/* Lazy bird: ASSUME no surrogate pairs. */
break;
case EFI_VM_VARIABLE_OP_VALUE:
else
{
if (cb == 1)
LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_VALUE read.\n"));
else
*pu32 = UINT32_MAX;
}
break;
break;
default:
*pu32 = UINT32_MAX;
break;
}
return VINF_SUCCESS;
}
/**
* @implement_callback_method{FNDBGFHANDLERDEV}
*/
{
{
}
}
/**
* Gets the info item size.
*
* @returns Size in bytes, UINT32_MAX on error.
* @param pThis .
*/
{
switch (pThis->iInfoSelector)
{
case EFI_INFO_INDEX_GOP_MODE:
return 4;
case EFI_INFO_INDEX_BOOT_ARGS:
return pThis->cbDeviceProps;
return 8;
}
return UINT32_MAX;
}
/**
* efiInfoNextByte for a uint64_t value.
*
* @returns Next (current) byte.
* @param pThis The EFI instance data.
* @param u64 The value.
*/
{
if (off >= 4)
return 0;
}
/**
* efiInfoNextByte for a uint32_t value.
*
* @returns Next (current) byte.
* @param pThis The EFI instance data.
* @param u32 The value.
*/
{
if (off >= 4)
return 0;
}
/**
* efiInfoNextByte for a buffer.
*
* @returns Next (current) byte.
* @param pThis The EFI instance data.
* @param pvBuf The buffer.
* @param cbBuf The buffer size.
*/
{
return 0;
}
/**
* Gets the next info byte.
*
* @returns Next (current) byte.
* @param pThis The EFI instance data.
*/
{
switch (pThis->iInfoSelector)
{
case EFI_INFO_INDEX_TEMPMEM_BASE: return efiInfoNextByteU32(pThis, VBOX_EFI_TOP_OF_STACK); /* just after stack */
case EFI_INFO_INDEX_BOOT_ARGS: return efiInfoNextByteBuf(pThis, pThis->szBootArgs, sizeof(pThis->szBootArgs));
case EFI_INFO_INDEX_DEVICE_PROPS: return efiInfoNextByteBuf(pThis, pThis->pbDeviceProps, pThis->cbDeviceProps);
case EFI_INFO_INDEX_UGA_HORISONTAL_RESOLUTION: return efiInfoNextByteU32(pThis, pThis->cxUgaResolution);
case EFI_INFO_INDEX_UGA_VERTICAL_RESOLUTION: return efiInfoNextByteU32(pThis, pThis->cyUgaResolution);
/* Keep in sync with value in EfiThunk.asm */
case EFI_INFO_INDEX_STACK_BASE: return efiInfoNextByteU32(pThis, VBOX_EFI_TOP_OF_STACK - _128K); /* 2M - 128 K */
default:
return 0;
}
}
/**
* Port I/O Handler for IN operations.
*
* @returns VBox status code.
*
* @param pDevIns The device instance.
* @param pvUser User argument - ignored.
* @param Port Port number used for the IN operation.
* @param pu32 Where to store the result.
* @param cb Number of bytes read.
*/
static DECLCALLBACK(int) efiIOPortRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
{
switch (Port)
{
case EFI_INFO_PORT:
{
if (cbInfo == UINT32_MAX)
}
else
{
if (cb != 1)
return VERR_IOM_IOPORT_UNUSED;
}
return VINF_SUCCESS;
case EFI_PANIC_PORT:
#ifdef IN_RING3
LogRel(("EFI panic port read!\n"));
/* Insert special code here on panic reads */
#else
/* Reschedule to R3 */
return VINF_IOM_R3_IOPORT_READ;
#endif
case EFI_VARIABLE_OP:
case EFI_VARIABLE_PARAM:
*pu32 = UINT32_MAX;
return VINF_SUCCESS;
}
return VERR_IOM_IOPORT_UNUSED;
}
/**
* Port I/O Handler for OUT operations.
*
* @returns VBox status code.
*
* @param pDevIns The device instance.
* @param pvUser User argument - ignored.
* @param Port Port number used for the IN operation.
* @param u32 The value to output.
* @param cb The value size in bytes.
*/
static DECLCALLBACK(int) efiIOPortWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
{
int rc = VINF_SUCCESS;
switch (Port)
{
case EFI_INFO_PORT:
break;
case EFI_DEBUG_PORT:
{
/* The raw version. */
switch (u32)
{
}
/* The readable, buffered version. */
{
{
#ifdef DEVEFI_WITH_VBOXDBG_SCRIPT
if (pszVBoxDbg)
{
if (RT_SUCCESS(rc2))
{
}
}
#endif
}
}
else
{
{
}
}
break;
}
case EFI_PANIC_PORT:
{
switch (u32)
{
case EFI_PANIC_CMD_BAD_ORG: /* Legacy */
case EFI_PANIC_CMD_THUNK_TRAP:
LogRel(("EFI Panic: Unexpected trap!!\n"));
#ifdef VBOX_STRICT
return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "EFI Panic: Unexpected trap during early bootstrap!\n");
#else
AssertReleaseMsgFailed(("Unexpected trap during early EFI bootstrap!!\n"));
#endif
break;
case EFI_PANIC_CMD_START_MSG:
break;
case EFI_PANIC_CMD_END_MSG:
#ifdef VBOX_STRICT
#else
return VERR_INTERNAL_ERROR;
#endif
default:
if ( u32 >= EFI_PANIC_CMD_MSG_FIRST
&& u32 <= EFI_PANIC_CMD_MSG_LAST)
{
/* Add the message char to the buffer. */
{
if ( ch == '\n'
&& i > 0
i--;
}
}
else
break;
}
break;
}
case EFI_VARIABLE_OP:
{
/* clear buffer index */
{
}
break;
}
case EFI_VARIABLE_PARAM:
break;
default:
break;
}
return rc;
}
{
LogFlow(("efiSaveExec:\n"));
/*
* Set variables only used when saving state.
*/
{
}
: UINT32_MAX;
/*
* Save the NVRAM state.
*/
/*
* Save the list variables (we saved the length above).
*/
{
}
return VINF_SUCCESS; /* SSM knows */
}
static DECLCALLBACK(int) efiLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
{
/*
* Validate input.
*/
if (uPass != SSM_PASS_FINAL)
return VERR_SSM_UNEXPECTED_PASS;
if ( uVersion != EFI_SSM_VERSION
&& uVersion != EFI_SSM_VERSION_4_2
)
/*
* Kill the current variables before loading anything.
*/
/*
* Load the NVRAM state.
*/
rc = SSMR3GetStructEx(pSSM, &pThis->NVRAM.VarOpBuf, sizeof(EFIVAR), 0, g_aEfiVariableDescFields, NULL);
/*
* Load variables.
*/
{
if (RT_SUCCESS(rc))
{
{
}
{
LogRel(("EFI: Loaded variable name is unterminated.\n"));
}
if (pEfiVar->cchName > cchVarName) /* No check for 0 here, busted load code in 4.2, so now storing 0 here. */
{
LogRel(("EFI: Loaded invalid variable name length %#x (cchVarName=%#x)\n", pEfiVar->cchName, cchVarName));
}
if (RT_SUCCESS(rc))
}
/* Add it, updating the current variable pointer while we're here. */
}
return VINF_SUCCESS;
}
/**
* @copydoc(PDMIBASE::pfnQueryInterface)
*/
{
return NULL;
}
/**
* Write to CMOS memory.
* This is used by the init complete code.
*/
{
}
/**
* Init complete notification.
*
* @returns VBOX status code.
* @param pDevIns The device instance.
*/
{
/* PC Bios */
/*
* Memory sizes.
*/
u32 = (uint32_t)( (RT_MIN(RT_MIN(pThis->cbRam, offRamHole), UINT32_C(0xffe00000)) - 16U * _1M) / _64K );
else
u32 = 0;
/*
* Number of CPUs.
*/
return VINF_SUCCESS;
}
/**
* Reset notification.
*
* @returns VBox status.
* @param pDevIns The device instance data.
*/
{
int rc;
LogFlow(("efiReset\n"));
pThis->iInfoSelector = 0;
/*
* Plan some structures in RAM.
*/
/*
*/
while (cPages > 0)
{
/* Read the (original) ROM page and write it back to the RAM page. */
if (RT_FAILURE(rc))
/* Advance */
cPages--;
}
}
/**
* Destruct a device instance.
*
* Most VM resources are freed by the VM. This callback is provided so that any non-VM
* resources can be freed correctly.
*
* @param pDevIns The device instance data.
*/
{
{
}
/*
* Free MM heap pointers (waste of time, but whatever).
*/
if (pThis->pszEfiRomFile)
{
}
if (pThis->pu8EfiThunk)
{
}
if (pThis->pbDeviceProps)
{
pThis->cbDeviceProps = 0;
}
return VINF_SUCCESS;
}
/**
* Helper that searches for a FFS file of a given type.
*
* @returns Pointer to the FFS file header if found, NULL if not.
*
* @param pFfsFile Pointer to the FFS file header to start searching at.
* @param pbEnd The end of the firmware volume.
* @param FileType The file type to look for.
* @param pcbFfsFile Where to store the FFS file size (includes header).
*/
DECLINLINE(EFI_FFS_FILE_HEADER const *)
efiFwVolFindFileByType(EFI_FFS_FILE_HEADER const *pFfsFile, uint8_t const *pbEnd, EFI_FV_FILETYPE FileType, uint32_t *pcbFile)
{
{
{
return pFfsFile;
}
}
return NULL;
}
/**
* Parse EFI ROM headers and find entry points.
*
* @returns VBox status.
* @param pThis The device instance data.
*/
{
/*
* Validate firmware volume header.
*/
/** @todo check checksum, see PE spec vol. 3 */
AssertLogRelMsgReturn(!(pThis->cbEfiRom & PAGE_OFFSET_MASK), ("%RX64\n", pThis->cbEfiRom), VERR_INVALID_PARAMETER);
return VINF_SUCCESS;
}
/**
* Load EFI ROM file into the memory.
*
* @returns VBox status.
* @param pThis The device instance data.
* @param pCfg Configuration node handle for the device.
*/
{
/*
* Read the entire firmware volume into memory.
*/
void *pvFile;
0 /*off*/,
RTFOFF_MAX /*cbMax*/,
&pvFile,
&cbFile);
if (RT_FAILURE(rc))
N_("Loading the EFI firmware volume '%s' failed with rc=%Rrc"),
/*
* Validate firmware volume and figure out the load address as well as the SEC entry point.
*/
if (RT_FAILURE(rc))
N_("Parsing the EFI firmware volume '%s' failed with rc=%Rrc"),
/*
* Map the firmware volume into memory as shadowed ROM.
*/
/** @todo fix PGMR3PhysRomRegister so it doesn't mess up in SUPLib when mapping a big ROM image. */
"EFI Firmware Volume");
rc = PDMDevHlpROMProtectShadow(pThis->pDevIns, pThis->GCLoadAddress, (uint32_t)cbQuart, PGMROMPROT_READ_RAM_WRITE_IGNORE);
"EFI Firmware Volume (Part 2)");
if (RT_FAILURE(rc))
return rc;
"EFI Firmware Volume (Part 3)");
if (RT_FAILURE(rc))
return rc;
"EFI Firmware Volume (Part 4)");
if (RT_FAILURE(rc))
return rc;
return VINF_SUCCESS;
}
{
else
val = 0xff;
return val;
}
{
int rc = 0;
bool fUpper = true;
if (!pThis->pbDeviceProps)
return VERR_NO_MEMORY;
{
if (u8Hb > 0xf)
continue;
if (fUpper)
else
}
return rc;
}
/**
* @interface_method_impl{PDMDEVREG,pfnConstruct}
*/
{
int rc;
/*
* Initalize the basic variables so that the destructor always works.
*/
/*
* Validate and read the configuration.
*/
if (!CFGMR3AreValuesValid(pCfg,
"EfiRom\0"
"RamSize\0"
"RamHoleSize\0"
"NumCPUs\0"
"UUID\0"
"IOAPIC\0"
"DmiBIOSFirmwareMajor\0"
"DmiBIOSFirmwareMinor\0"
"DmiBIOSReleaseDate\0"
"DmiBIOSReleaseMajor\0"
"DmiBIOSReleaseMinor\0"
"DmiBIOSVendor\0"
"DmiBIOSVersion\0"
"DmiSystemFamily\0"
"DmiSystemProduct\0"
"DmiSystemSerial\0"
"DmiSystemSKU\0"
"DmiSystemUuid\0"
"DmiSystemVendor\0"
"DmiSystemVersion\0"
"DmiBoardAssetTag\0"
"DmiBoardBoardType\0"
"DmiBoardLocInChass\0"
"DmiBoardProduct\0"
"DmiBoardSerial\0"
"DmiBoardVendor\0"
"DmiBoardVersion\0"
"DmiChassisAssetTag\0"
"DmiChassisSerial\0"
"DmiChassisVendor\0"
"DmiChassisVersion\0"
"DmiProcManufacturer\0"
"DmiProcVersion\0"
"DmiOEMVBoxVer\0"
"DmiOEMVBoxRev\0"
"DmiUseHostInfo\0"
"DmiExposeMemoryTable\0"
"DmiExposeProcInf\0"
"64BitEntry\0"
"BootArgs\0"
"DeviceProps\0"
"GopMode\0"
"UgaHorizontalResolution\0"
"UgaVerticalResolution\0"))
N_("Configuration error: Invalid config value(s) for the EFI device"));
/* CPU count (optional). */
if (RT_FAILURE (rc))
N_("Configuration error: Failed to read \"IOAPIC\""));
/*
*/
if (RT_FAILURE(rc))
N_("Configuration error: Querying \"UUID\" failed"));
/*
* Convert the UUID to network byte order. Not entirely straightforward as
* parts are MSB already...
*/
/*
* RAM sizes
*/
/*
* Get the system EFI ROM file name.
*/
if (rc == VERR_CFGM_VALUE_NOT_FOUND)
{
if (!pThis->pszEfiRomFile)
return VERR_NO_MEMORY;
}
else if (RT_FAILURE(rc))
N_("Configuration error: Querying \"EfiRom\" as a string failed"));
else if (!*pThis->pszEfiRomFile)
{
}
/*
* NVRAM processing.
*/
if (RT_FAILURE(rc))
/*
* Get boot args.
*/
if (RT_FAILURE(rc))
N_("Configuration error: Querying \"BootArgs\" as a string failed"));
/*
* Get device props.
*/
char *pszDeviceProps;
if (RT_FAILURE(rc))
N_("Configuration error: Querying \"DeviceProps\" as a string failed"));
if (pszDeviceProps)
{
if (RT_FAILURE(rc))
N_("Configuration error: Cannot parse device properties"));
}
else
{
pThis->cbDeviceProps = 0;
}
/*
* CPU frequencies
*/
/// @todo we need to have VMM API to access TSC increase speed, for now provide reasonable default
pThis->u64TscFrequency = RTMpGetMaxFrequency(0) * 1000 * 1000;// TMCpuTicksPerSecond(PDMDevHlpGetVM(pDevIns));
if (pThis->u64TscFrequency == 0)
/* Multiplier is read from MSR_IA32_PERF_STATUS, and now is hardcoded as 4 */
/*
* GOP graphics
*/
if (RT_FAILURE(rc))
N_("Configuration error: Querying \"GopMode\" as a 32-bit int failed"));
/*
* Uga graphics.
*/
if (pThis->cxUgaResolution == 0)
if (pThis->cyUgaResolution == 0)
#ifdef DEVEFI_WITH_VBOXDBG_SCRIPT
/*
* Zap the debugger script
*/
RTFileDelete("./DevEFI.VBoxDbg");
#endif
/*
* Load firmware volume and thunk ROM.
*/
if (RT_FAILURE(rc))
return rc;
/*
* Register our I/O ports.
*/
if (RT_FAILURE(rc))
return rc;
/*
* Plant DMI and MPS tables.
*/
/** @todo XXX I wonder if we really need these tables as there is no SMBIOS header... */
PGMPHYS_ROM_FLAGS_PERMANENT_BINARY, "DMI tables");
/*
* Register info handlers.
*/
/*
* Call reset to set things up.
*/
return VINF_SUCCESS;
}
/**
* The device registration structure.
*/
const PDMDEVREG g_DeviceEFI =
{
/* u32Version */
/* szName */
"efi",
/* szRCMod */
"",
/* szR0Mod */
"",
/* pszDescription */
"Extensible Firmware Interface Device. "
"LUN#0 - NVRAM port",
/* fFlags */
/* fClass */
/* cMaxInstances */
1,
/* cbInstance */
sizeof(DEVEFI),
/* pfnConstruct */
/* pfnDestruct */
/* pfnRelocate */
NULL,
/* pfnIOCtl */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
/* pfnSuspend */
NULL,
/* pfnResume */
NULL,
/* pfnAttach */
NULL,
/* pfnDetach */
NULL,
/* pfnQueryInterface. */
NULL,
/* pfnInitComplete. */
/* pfnPowerOff */
NULL,
/* pfnSoftReset */
NULL,
/* u32VersionEnd */
};