summaryrefslogtreecommitdiff
path: root/src/VBox/Main/src-client/Nvram.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Main/src-client/Nvram.cpp')
-rw-r--r--src/VBox/Main/src-client/Nvram.cpp378
1 files changed, 242 insertions, 136 deletions
diff --git a/src/VBox/Main/src-client/Nvram.cpp b/src/VBox/Main/src-client/Nvram.cpp
index d1c2a8a4..d3d4200f 100644
--- a/src/VBox/Main/src-client/Nvram.cpp
+++ b/src/VBox/Main/src-client/Nvram.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2012 Oracle Corporation
+ * Copyright (C) 2012-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;
@@ -20,6 +20,7 @@
*******************************************************************************/
#include "Nvram.h"
#include "ConsoleImpl.h"
+#include "Global.h"
#include <VBox/vmm/pdm.h>
#include <VBox/vmm/pdmdrv.h>
@@ -44,21 +45,43 @@
typedef struct NVRAM NVRAM;
typedef struct NVRAM *PNVRAM;
+/**
+ * Intstance data associated with PDMDRVINS.
+ */
struct NVRAM
{
- Nvram *pNvram;
- PDMINVRAM INvram;
- int cLoadedVariables;
- bool fPermanentSave;
+ /** Pointer to the associated class instance. */
+ Nvram *pNvram;
+ /** The NVRAM connector interface we provide to DevEFI. */
+ PDMINVRAMCONNECTOR INvramConnector;
+ /** The root of the 'Vars' child of the driver config (i.e.
+ * VBoxInternal/Devices/efi/0/LUN#0/Config/Vars/).
+ * This node has one child node per NVRAM variable. */
+ PCFGMNODE pCfgVarRoot;
+ /** The variable node used in the privous drvNvram_VarQueryByIndex call. */
+ PCFGMNODE pLastVarNode;
+ /** The index pLastVarNode corresponds to. */
+ uint32_t idxLastVar;
+ /** Whether to permanently save the variables or not. */
+ bool fPermanentSave;
};
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+/** The default NVRAM attribute value (non-volatile, boot servier access,
+ runtime access). */
+#define NVRAM_DEFAULT_ATTRIB UINT32_C(0x7)
+/** The CFGM overlay path of the NVRAM variables. */
+#define NVRAM_CFGM_OVERLAY_PATH "VBoxInternal/Devices/efi/0/LUN#0/Config/Vars"
+
/**
* Constructor/destructor
*/
-Nvram::Nvram(Console *console)
- : mpDrv(NULL),
- mParent(console)
+Nvram::Nvram(Console *pConsole)
+ : mParent(pConsole),
+ mpDrv(NULL)
{
}
@@ -73,149 +96,216 @@ Nvram::~Nvram()
/**
- * @interface_method_impl(PDMINVRAM,pfnStoreNvramValue)
+ * @interface_method_impl(PDMINVRAM,pfnVarStoreSeqEnd)
+ */
+DECLCALLBACK(int) drvNvram_VarStoreSeqEnd(PPDMINVRAMCONNECTOR pInterface, int rc)
+{
+ NOREF(pInterface);
+ return rc;
+}
+
+/**
+ * Converts the binary to a CFGM overlay binary string.
+ *
+ * @returns Pointer to a heap buffer (hand it to RTMemFree when done).
+ * @param pvBuf The binary data to convert.
+ * @param cbBuf The number of bytes to convert.
*/
-DECLCALLBACK(int) drvNvram_pfnStoreNvramValue(PPDMINVRAM pInterface,
- int idxVariable,
- RTUUID *pVendorUuid,
- const char *pcszVariableName,
- size_t cbVariableName,
- uint8_t *pu8Value,
- size_t cbValue)
+static char *drvNvram_binaryToCfgmString(void const *pvBuf, size_t cbBuf)
{
- int rc = VINF_SUCCESS;
- char szExtraDataKey[256];
- char szExtraDataValue[1024];
- LogFlowFunc(("ENTER: pVendorUuid:%RTuuid, pcszVariableName:%s, cbVariableName:%d, pu8Value:%.*Rhxs, cbValue:%d\n",
- pVendorUuid,
- pcszVariableName,
- cbVariableName,
- cbValue,
- pu8Value,
- cbValue));
- PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvram);
- if (!pThis->fPermanentSave)
+ static char s_szPrefix[] = "bytes:";
+ size_t cbStr = RTBase64EncodedLength(cbBuf) + sizeof(s_szPrefix);
+ char *pszStr = (char *)RTMemAlloc(cbStr);
+ if (pszStr)
{
- LogFlowFuncLeaveRC(rc);
- return rc;
+ memcpy(pszStr, s_szPrefix, sizeof(s_szPrefix) - 1);
+ int rc = RTBase64Encode(pvBuf, cbBuf, &pszStr[sizeof(s_szPrefix) - 1], cbStr - sizeof(s_szPrefix) + 1, NULL);
+ if (RT_FAILURE(rc))
+ {
+ RTMemFree(pszStr);
+ pszStr = NULL;
+ }
}
+ return pszStr;
+}
- bool fFlushVariable = (!pu8Value);
-
- RT_ZERO(szExtraDataKey);
- RT_ZERO(szExtraDataValue);
- RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VariableName", idxVariable);
- if (!fFlushVariable)
- RTStrPrintf(szExtraDataValue, 1024, "%s", pcszVariableName);
- pThis->pNvram->getParent()->machine()->SetExtraData(Bstr(szExtraDataKey).raw(), Bstr(szExtraDataValue).raw());
-
- RT_ZERO(szExtraDataKey);
- RT_ZERO(szExtraDataValue);
- RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VendorGuid", idxVariable);
- if (!fFlushVariable)
- RTUuidToStr(pVendorUuid, szExtraDataValue, 1024);
- pThis->pNvram->getParent()->machine()->SetExtraData(Bstr(szExtraDataKey).raw(), Bstr(szExtraDataValue).raw());
-
- RT_ZERO(szExtraDataKey);
- RT_ZERO(szExtraDataValue);
- RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VariableValueLength", idxVariable);
- if (!fFlushVariable)
- RTStrPrintf(szExtraDataValue, 1024, "%d", cbValue);
- pThis->pNvram->getParent()->machine()->SetExtraData(Bstr(szExtraDataKey).raw(), Bstr(szExtraDataValue).raw());
-
- RT_ZERO(szExtraDataKey);
- RT_ZERO(szExtraDataValue);
- RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VariableValue", idxVariable);
- size_t cbActualSize;
- if (pu8Value)
- rc = RTBase64Encode(pu8Value, cbValue, szExtraDataValue, 1024, &cbActualSize);
- AssertRCReturn(rc, rc);
- pThis->pNvram->getParent()->machine()->SetExtraData(Bstr(szExtraDataKey).raw(), Bstr(szExtraDataValue).raw());
+/**
+ * @interface_method_impl(PDMINVRAM,pfnVarStoreSeqPut)
+ */
+DECLCALLBACK(int) drvNvram_VarStoreSeqPut(PPDMINVRAMCONNECTOR pInterface, int idxVariable,
+ PCRTUUID pVendorUuid, const char *pszName, size_t cchName,
+ uint32_t fAttributes, uint8_t const *pbValue, size_t cbValue)
+{
+ PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvramConnector);
+ int rc = VINF_SUCCESS;
+ if (pThis->fPermanentSave && pThis->pNvram)
+ {
+ char szExtraName[256];
+ size_t offValueNm = RTStrPrintf(szExtraName, sizeof(szExtraName) - 16,
+ NVRAM_CFGM_OVERLAY_PATH "/%04u/", idxVariable);
+
+ char szUuid[RTUUID_STR_LENGTH];
+ int rc2 = RTUuidToStr(pVendorUuid, szUuid, sizeof(szUuid)); AssertRC(rc2);
+
+ char szAttribs[32];
+ if (fAttributes != NVRAM_DEFAULT_ATTRIB)
+ RTStrPrintf(szAttribs, sizeof(szAttribs), "%#x", fAttributes);
+ else
+ szAttribs[0] = '\0';
+
+ char *pszValue = drvNvram_binaryToCfgmString(pbValue, cbValue);
+ if (pszValue)
+ {
+ const char *apszTodo[] =
+ {
+ "Name", pszName,
+ "Uuid", szUuid,
+ "Value", pszValue,
+ "Attribs", szAttribs,
+ };
+ for (unsigned i = 0; i < RT_ELEMENTS(apszTodo); i += 2)
+ {
+ if (!apszTodo[i + 1][0])
+ continue;
+
+ Assert(strlen(apszTodo[i]) < 16);
+ strcpy(szExtraName + offValueNm, apszTodo[i]);
+ try
+ {
+ HRESULT hrc = pThis->pNvram->getParent()->machine()->SetExtraData(Bstr(szExtraName).raw(),
+ Bstr(apszTodo[i + 1]).raw());
+ if (FAILED(hrc))
+ {
+ LogRel(("drvNvram_deleteVar: SetExtraData(%s,%s) returned %Rhrc\n", szExtraName, apszTodo[i + 1], hrc));
+ rc = Global::vboxStatusCodeFromCOM(hrc);
+ }
+ }
+ catch (...)
+ {
+ LogRel(("drvNvram_deleteVar: SetExtraData(%s,%s) threw exception\n", szExtraName, apszTodo[i + 1]));
+ rc = VERR_UNEXPECTED_EXCEPTION;
+ }
+ }
+ }
+ else
+ rc = VERR_NO_MEMORY;
+ RTMemFree(pszValue);
+ }
+
+ NOREF(cchName);
LogFlowFuncLeaveRC(rc);
return rc;
}
-
/**
- * @interface_method_impl(PDMINVRAM,pfnFlushNvramStorage)
+ * Deletes a variable.
+ *
+ * @param pThis The NVRAM driver instance data.
+ * @param pszVarNodeNm The variable node name.
*/
-DECLCALLBACK(int) drvNvram_pfnFlushNvramStorage(PPDMINVRAM pInterface)
+static void drvNvram_deleteVar(PNVRAM pThis, const char *pszVarNodeNm)
{
- int rc = VINF_SUCCESS;
- LogFlowFuncEnter();
- PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvram);
- if (!pThis->fPermanentSave)
+ char szExtraName[256];
+ size_t offValue = RTStrPrintf(szExtraName, sizeof(szExtraName) - 16, NVRAM_CFGM_OVERLAY_PATH "/%s/", pszVarNodeNm);
+ static const char *s_apszValueNames[] = { "Name", "Uuid", "Value", "Attribs" };
+ for (unsigned i = 0; i < RT_ELEMENTS(s_apszValueNames); i++)
{
- LogFlowFuncLeaveRC(rc);
- return rc;
+ Assert(strlen(s_apszValueNames[i]) < 16);
+ strcpy(szExtraName + offValue, s_apszValueNames[i]);
+ try
+ {
+ HRESULT hrc = pThis->pNvram->getParent()->machine()->SetExtraData(Bstr(szExtraName).raw(), Bstr().raw());
+ if (FAILED(hrc))
+ LogRel(("drvNvram_deleteVar: SetExtraData(%s,) returned %Rhrc\n", szExtraName, hrc));
+ }
+ catch (...)
+ {
+ LogRel(("drvNvram_deleteVar: SetExtraData(%s,) threw exception\n", szExtraName));
+ }
}
+}
- for (int idxVariable = 0; idxVariable < pThis->cLoadedVariables; ++idxVariable)
+/**
+ * @interface_method_impl(PDMINVRAM,pfnVarStoreSeqBegin)
+ */
+DECLCALLBACK(int) drvNvram_VarStoreSeqBegin(PPDMINVRAMCONNECTOR pInterface, uint32_t cVariables)
+{
+ PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvramConnector);
+ int rc = VINF_SUCCESS;
+ if (pThis->fPermanentSave && pThis->pNvram)
{
- drvNvram_pfnStoreNvramValue(pInterface, idxVariable, NULL, NULL, 0, NULL, 0);
+ /*
+ * Remove all existing variables.
+ */
+ for (PCFGMNODE pVarNode = CFGMR3GetFirstChild(pThis->pCfgVarRoot); pVarNode; pVarNode = CFGMR3GetNextChild(pVarNode))
+ {
+ char szName[128];
+ rc = CFGMR3GetName(pVarNode, szName, sizeof(szName));
+ if (RT_SUCCESS(rc))
+ drvNvram_deleteVar(pThis, szName);
+ else
+ LogRel(("drvNvram_VarStoreSeqBegin: CFGMR3GetName -> %Rrc\n", rc));
+ }
}
- LogFlowFuncLeaveRC(rc);
+
+ NOREF(cVariables);
return rc;
}
-
/**
- * @interface_method_impl(PDMINVRAM,pfnStoreNvramValue)
+ * @interface_method_impl(PDMINVRAMCONNECTOR,pfnVarQueryByIndex)
*/
-DECLCALLBACK(int) drvNvram_pfnLoadNvramValue(PPDMINVRAM pInterface,
- int idxVariable,
- RTUUID *pVendorUuid,
- char *pcszVariableName,
- size_t *pcbVariableName,
- uint8_t *pu8Value,
- size_t *pcbValue)
+DECLCALLBACK(int) drvNvram_VarQueryByIndex(PPDMINVRAMCONNECTOR pInterface, uint32_t idxVariable,
+ PRTUUID pVendorUuid, char *pszName, uint32_t *pcchName,
+ uint32_t *pfAttributes, uint8_t *pbValue, uint32_t *pcbValue)
{
- int rc = VINF_SUCCESS;
- char szExtraDataKey[256];
- Bstr bstrValue;
- HRESULT hrc;
- LogFlowFunc(("ENTER: idxVariable:%d, *pcbVariableName:%d, *pcbValue:%d\n",
- idxVariable,
- *pcbVariableName,
- *pcbValue));
- PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvram);
- if (!pThis->fPermanentSave)
+ PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvramConnector);
+
+ /*
+ * Find the requested variable node.
+ */
+ PCFGMNODE pVarNode;
+ if (pThis->idxLastVar + 1 == idxVariable && pThis->pLastVarNode)
+ pVarNode = CFGMR3GetNextChild(pThis->pLastVarNode);
+ else
{
- rc = VERR_NOT_FOUND;
- LogFlowFuncLeaveRC(rc);
- return rc;
+ pVarNode = CFGMR3GetFirstChild(pThis->pCfgVarRoot);
+ for (uint32_t i = 0; i < idxVariable && pVarNode; i++)
+ pVarNode = CFGMR3GetNextChild(pVarNode);
}
+ if (!pVarNode)
+ return VERR_NOT_FOUND;
+ /* cache it */
+ pThis->pLastVarNode = pVarNode;
+ pThis->idxLastVar = idxVariable;
- RT_ZERO(szExtraDataKey);
- RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VariableName", idxVariable);
- hrc = pThis->pNvram->getParent()->machine()->GetExtraData(Bstr(szExtraDataKey).raw(), bstrValue.asOutParam());
- if (!SUCCEEDED(hrc))
- return VERR_NOT_FOUND;
- *pcbVariableName = RTStrCopy(pcszVariableName, 1024, Utf8Str(bstrValue).c_str());
-
- RT_ZERO(szExtraDataKey);
- RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VendorGuid", idxVariable);
- hrc = pThis->pNvram->getParent()->machine()->GetExtraData(Bstr(szExtraDataKey).raw(), bstrValue.asOutParam());
- RTUuidFromStr(pVendorUuid, Utf8Str(bstrValue).c_str());
-
-#if 0
- RT_ZERO(szExtraDataKey);
- RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VariableValueLength", idxVariable);
- hrc = pThis->pNvram->getParent()->machine()->GetExtraData(Bstr(szExtraDataKey).raw(), bstrValue.asOutParam());
- *pcbValue = Utf8Str(bstrValue).toUInt32();
-#endif
-
- RT_ZERO(szExtraDataKey);
- RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VariableValue", idxVariable);
- hrc = pThis->pNvram->getParent()->machine()->GetExtraData(Bstr(szExtraDataKey).raw(), bstrValue.asOutParam());
- rc = RTBase64Decode(Utf8Str(bstrValue).c_str(), pu8Value, 1024, pcbValue, NULL);
+ /*
+ * Read the variable node.
+ */
+ int rc = CFGMR3QueryString(pVarNode, "Name", pszName, *pcchName);
AssertRCReturn(rc, rc);
+ *pcchName = (uint32_t)strlen(pszName);
- pThis->cLoadedVariables++;
- LogFlowFuncLeaveRC(rc);
- return rc;
+ char szUuid[RTUUID_STR_LENGTH];
+ rc = CFGMR3QueryString(pVarNode, "Uuid", szUuid, sizeof(szUuid));
+ AssertRCReturn(rc, rc);
+ rc = RTUuidFromStr(pVendorUuid, szUuid);
+ AssertRCReturn(rc, rc);
+
+ rc = CFGMR3QueryU32Def(pVarNode, "Attribs", pfAttributes, NVRAM_DEFAULT_ATTRIB);
+ AssertRCReturn(rc, rc);
+
+ size_t cbValue;
+ rc = CFGMR3QuerySize(pVarNode, "Value", &cbValue);
+ AssertRCReturn(rc, rc);
+ AssertReturn(cbValue <= *pcbValue, VERR_BUFFER_OVERFLOW);
+ rc = CFGMR3QueryBytes(pVarNode, "Value", pbValue, cbValue);
+ AssertRCReturn(rc, rc);
+ *pcbValue = (uint32_t)cbValue;
+
+ return VINF_SUCCESS;
}
@@ -229,7 +319,7 @@ DECLCALLBACK(void *) Nvram::drvNvram_QueryInterface(PPDMIBASE pInterface, const
PNVRAM pThis = PDMINS_2_DATA(pDrvIns, PNVRAM);
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMINVRAM, &pThis->INvram);
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMINVRAMCONNECTOR, &pThis->INvramConnector);
return NULL;
}
@@ -239,8 +329,11 @@ DECLCALLBACK(void *) Nvram::drvNvram_QueryInterface(PPDMIBASE pInterface, const
*/
DECLCALLBACK(void) Nvram::drvNvram_Destruct(PPDMDRVINS pDrvIns)
{
+ PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
LogFlow(("%s: iInstance/#d\n", __FUNCTION__, pDrvIns->iInstance));
PNVRAM pThis = PDMINS_2_DATA(pDrvIns, PNVRAM);
+ if (pThis->pNvram != NULL)
+ pThis->pNvram->mpDrv = NULL;
}
@@ -249,9 +342,29 @@ DECLCALLBACK(void) Nvram::drvNvram_Destruct(PPDMDRVINS pDrvIns)
*/
DECLCALLBACK(int) Nvram::drvNvram_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
{
+ PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
LogFlowFunc(("iInstance/#d, pCfg:%p, fFlags:%x\n", pDrvIns->iInstance, pCfg, fFlags));
PNVRAM pThis = PDMINS_2_DATA(pDrvIns, PNVRAM);
+ /*
+ * Initalize instance data variables first.
+ */
+ //pThis->pNvram = NULL;
+ //pThis->cLoadedVariables = 0;
+ //pThis->fPermanentSave = false;
+ pThis->pCfgVarRoot = CFGMR3GetChild(pCfg, "Vars");
+ //pThis->pLastVarNode = NULL;
+ pThis->idxLastVar = UINT32_MAX / 2;
+
+ pDrvIns->IBase.pfnQueryInterface = Nvram::drvNvram_QueryInterface;
+ pThis->INvramConnector.pfnVarQueryByIndex = drvNvram_VarQueryByIndex;
+ pThis->INvramConnector.pfnVarStoreSeqBegin = drvNvram_VarStoreSeqBegin;
+ pThis->INvramConnector.pfnVarStoreSeqPut = drvNvram_VarStoreSeqPut;
+ pThis->INvramConnector.pfnVarStoreSeqEnd = drvNvram_VarStoreSeqEnd;
+
+ /*
+ * Validate and read configuration.
+ */
if (!CFGMR3AreValuesValid(pCfg, "Object\0"
"PermanentSave\0"))
return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
@@ -259,23 +372,16 @@ DECLCALLBACK(int) Nvram::drvNvram_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg,
("Configuration error: Not possible to attach anything to this driver!\n"),
VERR_PDM_DRVINS_NO_ATTACH);
- void *pv;
- int rc = CFGMR3QueryPtr(pCfg, "Object", &pv);
+ int rc = CFGMR3QueryPtr(pCfg, "Object", (void **)&pThis->pNvram);
AssertMsgRCReturn(rc, ("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc), rc);
- pThis->pNvram = (Nvram *)pv;
- bool fPermanentSave = false;
- rc = CFGMR3QueryBool(pCfg, "PermanentSave", &fPermanentSave);
- if ( RT_SUCCESS(rc)
- || rc == VERR_CFGM_VALUE_NOT_FOUND)
- pThis->fPermanentSave = fPermanentSave;
- else
- AssertRCReturn(rc, rc);
+ rc = CFGMR3QueryBoolDef(pCfg, "PermanentSave", &pThis->fPermanentSave, false);
+ AssertRCReturn(rc, rc);
- pDrvIns->IBase.pfnQueryInterface = Nvram::drvNvram_QueryInterface;
- pThis->INvram.pfnFlushNvramStorage = drvNvram_pfnFlushNvramStorage;
- pThis->INvram.pfnStoreNvramValue = drvNvram_pfnStoreNvramValue;
- pThis->INvram.pfnLoadNvramValue = drvNvram_pfnLoadNvramValue;
+ /*
+ * Let the associated class instance know about us.
+ */
+ pThis->pNvram->mpDrv = pThis;
return VINF_SUCCESS;
}