Index: trunk/src/VBox/Devices/EFI/DevEFI.cpp
===================================================================
--- trunk/src/VBox/Devices/EFI/DevEFI.cpp	(revision 44590)
+++ trunk/src/VBox/Devices/EFI/DevEFI.cpp	(revision 44591)
@@ -60,84 +60,122 @@
 *   Structures and Typedefs                                                    *
 *******************************************************************************/
-typedef struct {
-        RTLISTNODE List;
-        int      idxVariable;
-        RTUUID   uuid;
-        char     szVariableName[EFI_VARIABLE_NAME_MAX];
-        uint32_t cbVariableName;
-        uint8_t  au8Value[EFI_VARIABLE_VALUE_MAX];
-        uint32_t cbValue;
-        uint32_t u32Attribute;
-} EFIVAR, *PEFIVAR;
-
+/**
+ * EFI NVRAM variable.
+ */
+typedef struct EFIVAR
+{
+    /** The list node for the variable. */
+    RTLISTNODE      ListNode;
+    /** The unique sequence number of the variable.
+     * This is used to find pCurVar when restoring saved state and therefore only
+     * set when saving. */
+    uint32_t        idUniqueSavedState;
+    /** The value attributess. */
+    uint32_t        fAttributes;
+    /** The variable name length (not counting the terminator char). */
+    uint32_t        cchName;
+    /** The size of the value. This cannot be zero. */
+    uint32_t        cbValue;
+    /** The vendor UUID scoping the variable name. */
+    RTUUID          uuid;
+    /** The variable name. */
+    char            szName[EFI_VARIABLE_NAME_MAX];
+    /** The variable value bytes.  */
+    uint8_t         abValue[EFI_VARIABLE_VALUE_MAX];
+} EFIVAR;
+/** Pointer to an EFI NVRAM variable. */
+typedef EFIVAR *PEFIVAR;
+/** Pointer to an EFI NVRAM variable pointer. */
 typedef PEFIVAR *PPEFIVAR;
 
-typedef struct {
+/**
+ * NVRAM state.
+ */
+typedef struct NVRAMDESC
+{
+    /** The current operation. */
     EFIVAROP        enmOp;
+    /** The current status. */
     uint32_t        u32Status;
-    uint32_t        idxOpBuffer;
-    EFIVAR          OperationVarOp;
-    int             cNvramVariables;
-    int             iNvramLastIndex;
-    EFIVAR          NvramVariableList;
-    int             idxCurrentVar;
-    PEFIVAR         pCurrentVarOp;
+    /** The current  */
+    uint32_t        offOpBuffer;
+    /** The current number of variables. */
+    uint32_t        cVariables;
+    /** The list of variables. */
+    RTLISTANCHOR    VarList;
+
+    /** 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. */
+    uint32_t        idUniqueCurVar;
+    /** 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. */
+    EFIVAR          VarOpBuf;
+    /** The current variable. This is only used by EFI_VARIABLE_OP_QUERY_NEXT,
+     * the attribute readers work against the copy in VarOpBuf. */
+    PEFIVAR         pCurVar;
 } NVRAMDESC;
 
+
+/**
+ * The EFI device state structure.
+ */
 typedef struct DEVEFI
 {
     /** Pointer back to the device instance. */
-    PPDMDEVINS      pDevIns;
+    PPDMDEVINS              pDevIns;
     /** EFI message buffer. */
-    char            szMsg[VBOX_EFI_DEBUG_BUFFER];
+    char                    szMsg[VBOX_EFI_DEBUG_BUFFER];
     /** EFI message buffer index. */
-    uint32_t        iMsg;
+    uint32_t                iMsg;
     /** EFI panic message buffer. */
-    char            szPanicMsg[2048];
+    char                    szPanicMsg[2048];
     /** EFI panic message buffer index. */
-    uint32_t        iPanicMsg;
+    uint32_t                iPanicMsg;
     /** The system EFI ROM data. */
-    uint8_t        *pu8EfiRom;
+    uint8_t                *pu8EfiRom;
     /** The size of the system EFI ROM. */
-    uint64_t        cbEfiRom;
+    uint64_t                cbEfiRom;
     /** The name of the EFI ROM file. */
-    char           *pszEfiRomFile;
+    char                   *pszEfiRomFile;
     /** Thunk page pointer. */
-    uint8_t        *pu8EfiThunk;
+    uint8_t                *pu8EfiThunk;
     /** First entry point of the EFI firmware. */
-    RTGCPHYS        GCEntryPoint0;
+    RTGCPHYS                GCEntryPoint0;
     /** Second Entry Point (PeiCore)*/
-    RTGCPHYS        GCEntryPoint1;
+    RTGCPHYS                GCEntryPoint1;
     /** EFI firmware physical load address. */
-    RTGCPHYS        GCLoadAddress;
+    RTGCPHYS                GCLoadAddress;
     /** Current info selector. */
-    uint32_t        iInfoSelector;
+    uint32_t                iInfoSelector;
     /** Current info position. */
-    int32_t         offInfo;
+    int32_t                 offInfo;
 
     /** Number of virtual CPUs. (Config) */
-    uint32_t        cCpus;
+    uint32_t                cCpus;
     /** RAM below 4GB (in bytes). (Config) */
-    uint32_t        cbBelow4GB;
+    uint32_t                cbBelow4GB;
     /** RAM above 4GB (in bytes). (Config) */
-    uint64_t        cbAbove4GB;
+    uint64_t                cbAbove4GB;
     /** The total amount of memory. */
-    uint64_t        cbRam;
+    uint64_t                cbRam;
     /** The size of the RAM hole below 4GB. */
-    uint64_t        cbRamHole;
+    uint64_t                cbRamHole;
 
     /** The size of the DMI tables. */
-    uint16_t        cbDmiTables;
+    uint16_t                cbDmiTables;
     /** The DMI tables. */
-    uint8_t         au8DMIPage[0x1000];
+    uint8_t                 au8DMIPage[0x1000];
 
     /** I/O-APIC enabled? */
-    uint8_t         u8IOAPIC;
+    uint8_t                 u8IOAPIC;
 
     /** Boot parameters passed to the firmware. */
-    char            szBootArgs[256];
+    char                    szBootArgs[256];
 
     /** Host UUID (for DMI). */
-    RTUUID          aUuid;
+    RTUUID                  aUuid;
 
     /** Device properties buffer. */
@@ -155,14 +193,23 @@
     uint32_t                u32GopMode;
     /** Uga mode horisontal resolution. */
-    uint32_t        cxUgaResolution;
+    uint32_t                cxUgaResolution;
     /** Uga mode vertical resolution. */
-    uint32_t        cyUgaResolution;
-
-    NVRAMDESC       NVRAM;
+    uint32_t                cyUgaResolution;
+
+
+    /** NVRAM state variables. */
+    NVRAMDESC               NVRAM;
+
+    /**
+     * NVRAM port - LUN\#0.
+     */
     struct
     {
-        PPDMIBASE    pDrvBase;
-        PDMIBASE     IBase;
-        PPDMINVRAM   pNvramDown;
+        /** The base interface we provide the NVRAM driver. */
+        PDMIBASE            IBase;
+        /** The NVRAM driver base interface. */
+        PPDMIBASE           pDrvBase;
+        /** The NVRAM interface provided by the driver. */
+        PPDMINVRAMCONNECTOR pNvramDrv;
     } Lun0;
 } DEVEFI;
@@ -174,5 +221,7 @@
 *******************************************************************************/
 /** The saved state version. */
-#define EFI_SSM_VERSION 1
+#define EFI_SSM_VERSION 2
+/** The saved state version from VBox 4.2. */
+#define EFI_SSM_VERSION_4_2 1
 
 
@@ -183,13 +232,13 @@
 static SSMFIELD const g_aEfiNvramDescField[] =
 {
-        SSMFIELD_ENTRY          (NVRAMDESC, enmOp),
-        SSMFIELD_ENTRY          (NVRAMDESC, u32Status),
-        SSMFIELD_ENTRY          (NVRAMDESC, idxOpBuffer),
-        SSMFIELD_ENTRY_IGNORE   (NVRAMDESC, OperationVarOp),
-        SSMFIELD_ENTRY          (NVRAMDESC, cNvramVariables),
-        SSMFIELD_ENTRY          (NVRAMDESC, iNvramLastIndex),
-        SSMFIELD_ENTRY_IGNORE   (NVRAMDESC, NvramVariableList),
-        SSMFIELD_ENTRY          (NVRAMDESC, idxCurrentVar),
-        SSMFIELD_ENTRY_IGNORE   (NVRAMDESC, pCurrentVarOp),
+        SSMFIELD_ENTRY(       NVRAMDESC, enmOp),
+        SSMFIELD_ENTRY(       NVRAMDESC, u32Status),
+        SSMFIELD_ENTRY(       NVRAMDESC, offOpBuffer),
+        SSMFIELD_ENTRY_IGNORE(NVRAMDESC, VarOpBuf),
+        SSMFIELD_ENTRY(       NVRAMDESC, cVariables),
+        SSMFIELD_ENTRY_OLD(   idUnquireLast, 4),
+        SSMFIELD_ENTRY_IGNORE(NVRAMDESC, VarList),
+        SSMFIELD_ENTRY(       NVRAMDESC, idUniqueCurVar),
+        SSMFIELD_ENTRY_IGNORE(NVRAMDESC, pCurVar),
         SSMFIELD_ENTRY_TERM()
 };
@@ -198,12 +247,12 @@
 static SSMFIELD const g_aEfiVariableDescFields[] =
 {
-        SSMFIELD_ENTRY_IGNORE   (EFIVAR, List),
-        SSMFIELD_ENTRY          (EFIVAR, idxVariable),
-        SSMFIELD_ENTRY          (EFIVAR, uuid),
-        SSMFIELD_ENTRY          (EFIVAR, szVariableName),
-        SSMFIELD_ENTRY          (EFIVAR, cbVariableName),
-        SSMFIELD_ENTRY          (EFIVAR, au8Value),
-        SSMFIELD_ENTRY          (EFIVAR, cbValue),
-        SSMFIELD_ENTRY          (EFIVAR, u32Attribute),
+        SSMFIELD_ENTRY_IGNORE(EFIVAR, ListNode),
+        SSMFIELD_ENTRY(       EFIVAR, idUniqueSavedState),
+        SSMFIELD_ENTRY(       EFIVAR, uuid),
+        SSMFIELD_ENTRY(       EFIVAR, szName),
+        SSMFIELD_ENTRY_OLD(   cchName, 4),
+        SSMFIELD_ENTRY(       EFIVAR, abValue),
+        SSMFIELD_ENTRY(       EFIVAR, cbValue),
+        SSMFIELD_ENTRY(       EFIVAR, fAttributes),
         SSMFIELD_ENTRY_TERM()
 };
@@ -211,44 +260,39 @@
 
 
-/**
- * Write to CMOS memory.
- * This is used by the init complete code.
- */
-static void cmosWrite(PPDMDEVINS pDevIns, int off, uint32_t u32Val)
-{
-    Assert(off < 128);
-    Assert(u32Val < 256);
-
-    int rc = PDMDevHlpCMOSWrite(pDevIns, off, u32Val);
-    AssertRC(rc);
-}
-
-DECLINLINE(void) nvramFlushDeviceVariableList(PDEVEFI pThis)
-{
-    PEFIVAR pEfiVar = NULL;
-    while (!RTListIsEmpty(&pThis->NVRAM.NvramVariableList.List))
-    {
-        pEfiVar = RTListNodeGetNext(&pThis->NVRAM.NvramVariableList.List, EFIVAR, List);
-        RTListNodeRemove(&pEfiVar->List);
+
+/**
+ * Flushes the variable list.
+ *
+ * @param   pThis               The EFI state.
+ */
+static void nvramFlushDeviceVariableList(PDEVEFI pThis)
+{
+    while (!RTListIsEmpty(&pThis->NVRAM.VarList))
+    {
+        PEFIVAR pEfiVar = RTListNodeGetNext(&pThis->NVRAM.VarList, EFIVAR, ListNode);
+        RTListNodeRemove(&pEfiVar->ListNode);
         RTMemFree(pEfiVar);
     }
-}
-
-/**
- * This function looks up variable in NVRAM list
+
+    pThis->NVRAM.pCurVar = NULL;
+}
+
+/**
+ * This function looks up variable in NVRAM list.
  */
 static int nvramLookupVariableByUuidAndName(PDEVEFI pThis, char *pszVariableName, PCRTUUID pUuid, PPEFIVAR ppEfiVar)
 {
-    int rc = VERR_NOT_FOUND;
-    PEFIVAR pEfiVar = NULL;
-    LogFlowFunc(("pszVariableName:%s, pUuid:%RTuuid\n", pszVariableName, pUuid));
-    int idxVar = 0;
-    RTListForEach((PRTLISTNODE)&pThis->NVRAM.NvramVariableList.List, pEfiVar, EFIVAR, List)
+    LogFlowFunc(("%RTuuid::'%s'\n", pUuid, pszVariableName));
+
+    int      rc         = VERR_NOT_FOUND;
+    uint32_t cVariables = 0;
+    PEFIVAR  pEfiVar;
+    RTListForEach(&pThis->NVRAM.VarList, pEfiVar, EFIVAR, ListNode)
     {
         LogFlowFunc(("pEfiVar:%p\n", pEfiVar));
-        idxVar++;
+        cVariables++;
         if (   pEfiVar
             && RTUuidCompare(pUuid, &pEfiVar->uuid) == 0
-            && RTStrCmp(pszVariableName, pEfiVar->szVariableName) == 0)
+            && RTStrCmp(pszVariableName, pEfiVar->szName) == 0) /** @todo case sensitive or insensitive? */
         {
             *ppEfiVar = pEfiVar;
@@ -257,68 +301,547 @@
         }
     }
-    Assert(pThis->NVRAM.cNvramVariables >= idxVar);
-    LogFlowFuncLeaveRC(rc);
+    Assert(pThis->NVRAM.cVariables >= cVariables);
+
+    LogFlowFunc(("rc=%Rrc pEfiVar=%p\n", rc, *ppEfiVar));
     return rc;
 }
 
+/**
+ * Creates an device internal list of variables.
+ *
+ * @returns VBox status code.
+ * @param   pThis           The EFI state.
+ */
 static int nvramLoad(PDEVEFI pThis)
 {
-    int rc = VINF_SUCCESS;
-    PEFIVAR pEfiVar = NULL;
-    int idxValue = 0;
-    while(idxValue < 100)
-    {
-        pEfiVar = (PEFIVAR)RTMemAllocZ(sizeof(EFIVAR));
-        if (!pEfiVar)
+    int rc;
+    for (uint32_t iVar = 0; iVar < EFI_VARIABLE_MAX; iVar++)
+    {
+        PEFIVAR pEfiVar = (PEFIVAR)RTMemAllocZ(sizeof(EFIVAR));
+        AssertReturn(pEfiVar, VERR_NO_MEMORY);
+
+        pEfiVar->cchName = sizeof(pEfiVar->szName);
+        pEfiVar->cbValue = sizeof(pEfiVar->abValue);
+        rc = pThis->Lun0.pNvramDrv->pfnVarQueryByIndex(pThis->Lun0.pNvramDrv, iVar,
+                                                       &pEfiVar->uuid, &pEfiVar->szName[0], &pEfiVar->cchName,
+                                                       &pEfiVar->fAttributes, &pEfiVar->abValue[0], &pEfiVar->cbValue);
+        if (RT_SUCCESS(rc))
         {
-            LogRel(("EFI: Can't allocate space for stored EFI variable\n"));
-            return VERR_NO_MEMORY;
+            /* Some validations. */
+            rc = RTStrValidateEncoding(pEfiVar->szName);
+            size_t cchName = RTStrNLen(pEfiVar->szName, sizeof(pEfiVar->szName));
+            if (cchName != pEfiVar->cchName)
+                rc = VERR_INVALID_PARAMETER;
+            if (pEfiVar->cbValue == 0)
+                rc = VERR_NO_DATA;
+            if (RT_FAILURE(rc))
+                LogRel(("EFI/nvramLoad: Bad variable #%u: cbValue=%#x cchName=%#x (strlen=%#x) szName=%.*Rhxs\n",
+                        pEfiVar->cbValue, pEfiVar->cchName, cchName, pEfiVar->cchName + 1, pEfiVar->szName));
         }
-        pEfiVar->cbVariableName = EFI_VARIABLE_NAME_MAX;
-        pEfiVar->cbValue = EFI_VARIABLE_VALUE_MAX;
-        rc = pThis->Lun0.pNvramDown->pfnLoadNvramValue(pThis->Lun0.pNvramDown,
-                                                       idxValue,
-                                                       &pEfiVar->uuid,
-                                                       pEfiVar->szVariableName,
-                                                       (size_t *)&pEfiVar->cbVariableName,
-                                                       pEfiVar->au8Value,
-                                                       (size_t *)&pEfiVar->cbValue);
-        idxValue++;
         if (RT_FAILURE(rc))
         {
             RTMemFree(pEfiVar);
-            break;
+            if (rc == VERR_NOT_FOUND)
+                rc = VINF_SUCCESS;
+            AssertRC(rc);
+            return rc;
         }
-        pThis->NVRAM.cNvramVariables++;
-        RTListAppend((PRTLISTNODE)&pThis->NVRAM.NvramVariableList.List, &pEfiVar->List);
-    }
-    if (   RT_FAILURE(rc)
-        && rc == VERR_NOT_FOUND)
-        rc  = VINF_SUCCESS;
-    AssertRCReturn(rc, rc);
+
+        /* Append it. */
+        RTListAppend((PRTLISTNODE)&pThis->NVRAM.VarList, &pEfiVar->ListNode);
+        pThis->NVRAM.cVariables++;
+    }
+
+    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.
+ */
+static int nvramStore(PDEVEFI pThis)
+{
+    int rc = pThis->Lun0.pNvramDrv->pfnVarStoreSeqBegin(pThis->Lun0.pNvramDrv, pThis->NVRAM.cVariables);
+    if (RT_SUCCESS(rc))
+    {
+        uint32_t    idxVar  = 0;
+        PEFIVAR     pEfiVar;
+        RTListForEach(&pThis->NVRAM.VarList, pEfiVar, EFIVAR, ListNode)
+        {
+            int rc2 = pThis->Lun0.pNvramDrv->pfnVarStoreSeqPut(pThis->Lun0.pNvramDrv, idxVar,
+                                                               &pEfiVar->uuid, pEfiVar->szName,  pEfiVar->cchName,
+                                                               pEfiVar->fAttributes, pEfiVar->abValue, pEfiVar->cbValue);
+            if (RT_FAILURE(rc2) && RT_SUCCESS_NP(rc))
+            {
+                LogRel(("EFI: pfnVarStoreVarByIndex failed: %Rrc\n", rc));
+                rc = rc2;
+            }
+            idxVar++;
+        }
+        Assert((pThis->NVRAM.cVariables == idxVar));
+        rc = pThis->Lun0.pNvramDrv->pfnVarStoreSeqEnd(pThis->Lun0.pNvramDrv, rc);
+    }
+    else
+        LogRel(("EFI: pfnVarStoreBegin failed: %Rrc\n", rc));
     return rc;
 }
 
-static int nvramStore(PDEVEFI pThis)
+/**
+ * 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.
+ */
+static void nvramWriteVariableOpQueryCopyResult(PDEVEFI pThis, PEFIVAR pEfiVar)
+{
+    RT_ZERO(pThis->NVRAM.VarOpBuf.szName);
+    RT_ZERO(pThis->NVRAM.VarOpBuf.abValue);
+    if (pEfiVar)
+    {
+        pThis->NVRAM.VarOpBuf.uuid        = pEfiVar->uuid;
+        pThis->NVRAM.VarOpBuf.cchName     = pEfiVar->cchName;
+        memcpy(pThis->NVRAM.VarOpBuf.szName, pEfiVar->szName, pEfiVar->cchName); /* no need for + 1. */
+        pThis->NVRAM.VarOpBuf.fAttributes = pEfiVar->fAttributes;
+        pThis->NVRAM.VarOpBuf.cbValue     = pEfiVar->cbValue;
+        memcpy(pThis->NVRAM.VarOpBuf.abValue, pEfiVar->abValue, pEfiVar->cbValue);
+        pThis->NVRAM.pCurVar              = pEfiVar;
+        pThis->NVRAM.u32Status            = EFI_VARIABLE_OP_STATUS_OK;
+        LogFlow(("EFI: Variable query -> %RTuuid::'%s' abValue=%.*Rhxs\n", &pThis->NVRAM.VarOpBuf.uuid,
+                 pThis->NVRAM.VarOpBuf.szName, pThis->NVRAM.VarOpBuf.cbValue, pThis->NVRAM.VarOpBuf.abValue));
+    }
+    else
+    {
+        pThis->NVRAM.VarOpBuf.fAttributes = 0;
+        pThis->NVRAM.VarOpBuf.cbValue     = 0;
+        pThis->NVRAM.VarOpBuf.cchName     = 0;
+        pThis->NVRAM.pCurVar              = NULL;
+        pThis->NVRAM.u32Status            = EFI_VARIABLE_OP_STATUS_NOT_FOUND;
+        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.
+ */
+static int nvramWriteVariableOpQuery(PDEVEFI pThis)
+{
+    LogRel(("EFI: Querying Variable %RTuuid::'%s'\n",
+            &pThis->NVRAM.VarOpBuf.uuid, pThis->NVRAM.VarOpBuf.szName));
+
+    PEFIVAR pEfiVar;
+    int rc = nvramLookupVariableByUuidAndName(pThis,
+                                              pThis->NVRAM.VarOpBuf.szName,
+                                              &pThis->NVRAM.VarOpBuf.uuid,
+                                              &pEfiVar);
+    nvramWriteVariableOpQueryCopyResult(pThis, RT_SUCCESS(rc) ? pEfiVar : NULL);
+    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.
+ */
+static int nvramWriteVariableOpQueryNext(PDEVEFI pThis)
+{
+    Log(("EFI: Querying next variable...\n"));
+    PEFIVAR pEfiVar = pThis->NVRAM.pCurVar;
+    if (pEfiVar)
+        pEfiVar = RTListGetNext(&pThis->NVRAM.VarList, pEfiVar, EFIVAR, ListNode);
+    nvramWriteVariableOpQueryCopyResult(pThis, pEfiVar);
+    return VINF_SUCCESS;
+}
+
+/**
+ * Implements EFI_VARIABLE_PARAM + EFI_VARIABLE_OP_ADD.
+ *
+ * @returns IOM strict status code.
+ * @param   pThis               The EFI state.
+ */
+static int nvramWriteVariableOpAdd(PDEVEFI pThis)
+{
+    LogRel(("EFI: Adding variable %RTuuid::'%s'\n", &pThis->NVRAM.VarOpBuf.uuid, pThis->NVRAM.VarOpBuf.szName));
+    LogFlowFunc(("fAttributes=%#x abValue=%.*Rhxs\n", pThis->NVRAM.VarOpBuf.fAttributes,
+                 pThis->NVRAM.VarOpBuf.cbValue, pThis->NVRAM.VarOpBuf.abValue));
+
+    /*
+     * Validate the input a little.
+     */
+    int rc = RTStrValidateEncoding(pThis->NVRAM.VarOpBuf.szName);
+    if (RT_FAILURE(rc))
+        LogRel(("EFI: Badly encoded variable name: %.*Rhxs\n", pThis->NVRAM.VarOpBuf.cchName + 1, pThis->NVRAM.VarOpBuf.szName));
+    size_t cchName = RTStrNLen(pThis->NVRAM.VarOpBuf.szName, sizeof(pThis->NVRAM.VarOpBuf.szName));
+    if (cchName != pThis->NVRAM.VarOpBuf.cchName)
+    {
+        LogRel(("EFI: Bad name length %#x, expected %#x: %.*Rhxs\n",
+                cchName, pThis->NVRAM.VarOpBuf.cchName, pThis->NVRAM.VarOpBuf.cchName + 1, pThis->NVRAM.VarOpBuf.szName));
+        rc = VERR_INVALID_PARAMETER;
+    }
+    if (RT_FAILURE(rc))
+    {
+        pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
+        return VINF_SUCCESS;
+    }
+
+    /*
+     * Look it up and see what to do.
+     */
+    PEFIVAR pEfiVar;
+    rc = nvramLookupVariableByUuidAndName(pThis,
+                                          pThis->NVRAM.VarOpBuf.szName,
+                                          &pThis->NVRAM.VarOpBuf.uuid,
+                                          &pEfiVar);
+    if (RT_SUCCESS(rc))
+    {
+        LogFlowFunc(("Old abValue=%.*Rhxs\n", pEfiVar->cbValue, pEfiVar->abValue));
+#if 0 /** @todo Implement read-only EFI variables. */
+        if (pEfiVar->fAttributes & EFI_VARIABLE_XXXXXXX)
+        {
+            pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_RO;
+            break;
+        }
+#endif
+
+        if (pThis->NVRAM.VarOpBuf.cbValue == 0)
+        {
+            /*
+             * Delete it.
+             */
+            LogFlow(("nvramWriteVariableOpAdd: Delete\n"));
+            RTListNodeRemove(&pEfiVar->ListNode);
+            pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
+            pThis->NVRAM.cVariables--;
+
+            if (pThis->NVRAM.pCurVar == pEfiVar)
+                pThis->NVRAM.pCurVar = NULL;
+            RTMemFree(pEfiVar);
+            pEfiVar = NULL;
+        }
+        else
+        {
+            /*
+             * Update/replace it. (The name and UUID are unchanged, of course.)
+             */
+            LogFlow(("nvramWriteVariableOpAdd: Replace\n"));
+            pEfiVar->fAttributes   = pThis->NVRAM.VarOpBuf.fAttributes;
+            pEfiVar->cbValue       = pThis->NVRAM.VarOpBuf.cbValue;
+            memcpy(pEfiVar->abValue, pThis->NVRAM.VarOpBuf.abValue, pEfiVar->cbValue);
+            pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
+        }
+    }
+    else if (pThis->NVRAM.VarOpBuf.cbValue == 0)
+    {
+        /* delete operation, but nothing to delete. */
+        LogFlow(("nvramWriteVariableOpAdd: Delete (not found)\n"));
+        pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
+    }
+    else if (pThis->NVRAM.cVariables < EFI_VARIABLE_MAX)
+    {
+        /*
+         * Add a new variable.
+         */
+        LogFlow(("nvramWriteVariableOpAdd: New\n"));
+        pEfiVar = (PEFIVAR)RTMemAllocZ(sizeof(EFIVAR));
+        if (pEfiVar)
+        {
+            pEfiVar->uuid          = pThis->NVRAM.VarOpBuf.uuid;
+            pEfiVar->cchName       = pThis->NVRAM.VarOpBuf.cchName;
+            memcpy(pEfiVar->szName, pThis->NVRAM.VarOpBuf.szName, pEfiVar->cchName); /* The buffer is zeroed, so skip '\0'. */
+            pEfiVar->fAttributes   = pThis->NVRAM.VarOpBuf.fAttributes;
+            pEfiVar->cbValue       = pThis->NVRAM.VarOpBuf.cbValue;
+            memcpy(pEfiVar->abValue, pThis->NVRAM.VarOpBuf.abValue, pEfiVar->cbValue);
+
+            RTListAppend(&pThis->NVRAM.VarList, &pEfiVar->ListNode);
+            pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
+            pThis->NVRAM.cVariables++;
+        }
+        else
+            pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
+    }
+    else
+    {
+        /*
+         * Too many variables.
+         */
+        static unsigned s_cWarnings = 0;
+        if (s_cWarnings++ < 5)
+            LogRel(("EFI: Too many variables.\n"));
+        pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
+        Log(("nvramWriteVariableOpAdd: Too many variabled.\n"));
+    }
+
+    LogFunc(("cVariables=%u u32Status=%#x\n", pThis->NVRAM.cVariables, pThis->NVRAM.u32Status));
+    return VINF_SUCCESS;
+}
+
+/**
+ * Implements EFI_VARIABLE_PARAM writes.
+ *
+ * @returns IOM strict status code.
+ * @param   pThis               The EFI state.
+ * @param   u32Value            The value being written.
+ */
+static int nvramWriteVariableParam(PDEVEFI pThis, uint32_t u32Value)
 {
     int rc = VINF_SUCCESS;
-    PEFIVAR pEfiVar = NULL;
-    int idxVar = 0;
-    pThis->Lun0.pNvramDown->pfnFlushNvramStorage(pThis->Lun0.pNvramDown);
-
-    RTListForEach((PRTLISTNODE)&pThis->NVRAM.NvramVariableList.List, pEfiVar, EFIVAR, List)
-    {
-        pThis->Lun0.pNvramDown->pfnStoreNvramValue(pThis->Lun0.pNvramDown,
-                                                   idxVar,
-                                                   &pEfiVar->uuid,
-                                                   pEfiVar->szVariableName,
-                                                   pEfiVar->cbVariableName,
-                                                   pEfiVar->au8Value,
-                                                   pEfiVar->cbValue);
-        idxVar++;
-    }
-    Assert((pThis->NVRAM.cNvramVariables == idxVar));
+    switch (pThis->NVRAM.enmOp)
+    {
+        case EFI_VM_VARIABLE_OP_START:
+            switch (u32Value)
+            {
+                case EFI_VARIABLE_OP_QUERY:
+                    rc = nvramWriteVariableOpQuery(pThis);
+                    break;
+
+                case EFI_VARIABLE_OP_QUERY_NEXT:
+                    rc = nvramWriteVariableOpQueryNext(pThis);
+                    break;
+
+                case EFI_VARIABLE_OP_ADD:
+                    rc = nvramWriteVariableOpAdd(pThis);
+                    break;
+
+                default:
+                    pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
+                    LogRel(("EFI: Unknown  EFI_VM_VARIABLE_OP_START value %#x\n", u32Value));
+                    break;
+            }
+            break;
+
+        case EFI_VM_VARIABLE_OP_GUID:
+            Log2(("EFI_VM_VARIABLE_OP_GUID[%#x]=%#x\n", pThis->NVRAM.offOpBuffer, u32Value));
+            if (pThis->NVRAM.offOpBuffer < sizeof(pThis->NVRAM.VarOpBuf.uuid))
+                pThis->NVRAM.VarOpBuf.uuid.au8[pThis->NVRAM.offOpBuffer++] = (uint8_t)u32Value;
+            else
+            {
+                LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_GUID write (%#x).\n", u32Value));
+                pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
+            }
+            break;
+
+        case EFI_VM_VARIABLE_OP_ATTRIBUTE:
+            Log2(("EFI_VM_VARIABLE_OP_ATTRIBUTE=%#x\n", u32Value));
+            pThis->NVRAM.VarOpBuf.fAttributes = u32Value;
+            break;
+
+        case EFI_VM_VARIABLE_OP_NAME:
+            Log2(("EFI_VM_VARIABLE_OP_NAME[%#x]=%#x\n", pThis->NVRAM.offOpBuffer, u32Value));
+            if (pThis->NVRAM.offOpBuffer < pThis->NVRAM.VarOpBuf.cchName)
+                pThis->NVRAM.VarOpBuf.szName[pThis->NVRAM.offOpBuffer++] = (uint8_t)u32Value;
+            else if (u32Value == 0)
+                Assert(pThis->NVRAM.VarOpBuf.szName[sizeof(pThis->NVRAM.VarOpBuf.szName) - 1] == 0);
+            else
+            {
+                LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_NAME write (%#x).\n", u32Value));
+                pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
+            }
+            break;
+
+        case EFI_VM_VARIABLE_OP_NAME_LENGTH:
+            Log2(("EFI_VM_VARIABLE_OP_NAME_LENGTH=%#x\n", u32Value));
+            RT_ZERO(pThis->NVRAM.VarOpBuf.szName);
+            if (u32Value < sizeof(pThis->NVRAM.VarOpBuf.szName))
+                pThis->NVRAM.VarOpBuf.cchName = u32Value;
+            else
+            {
+                LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_NAME_LENGTH write (%#x, max %#x).\n",
+                        u32Value, sizeof(pThis->NVRAM.VarOpBuf.szName) - 1));
+                pThis->NVRAM.VarOpBuf.cchName = sizeof(pThis->NVRAM.VarOpBuf.szName) - 1;
+                pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
+            }
+            Assert(pThis->NVRAM.offOpBuffer == 0);
+            break;
+
+        case EFI_VM_VARIABLE_OP_NAME_UTF16:
+        {
+            Log2(("EFI_VM_VARIABLE_OP_NAME_UTF16[%#x]=%#x\n", pThis->NVRAM.offOpBuffer, u32Value));
+            /* Currently simplifying this to UCS2, i.e. no surrogates. */
+            if (pThis->NVRAM.offOpBuffer == 0)
+                RT_ZERO(pThis->NVRAM.VarOpBuf.szName);
+            size_t cbUtf8 = RTStrCpSize(u32Value);
+            if (pThis->NVRAM.offOpBuffer + cbUtf8 < sizeof(pThis->NVRAM.VarOpBuf.szName))
+            {
+                RTStrPutCp(&pThis->NVRAM.VarOpBuf.szName[pThis->NVRAM.offOpBuffer], u32Value);
+                pThis->NVRAM.offOpBuffer += cbUtf8;
+            }
+            else if (u32Value == 0)
+                Assert(pThis->NVRAM.VarOpBuf.szName[sizeof(pThis->NVRAM.VarOpBuf.szName) - 1] == 0);
+            else
+            {
+                LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_NAME_UTF16 write (%#x).\n", u32Value));
+                pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
+            }
+            break;
+        }
+
+        case EFI_VM_VARIABLE_OP_VALUE:
+            Log2(("EFI_VM_VARIABLE_OP_VALUE[%#x]=%#x\n", pThis->NVRAM.offOpBuffer, u32Value));
+            if (pThis->NVRAM.offOpBuffer < pThis->NVRAM.VarOpBuf.cbValue)
+                pThis->NVRAM.VarOpBuf.abValue[pThis->NVRAM.offOpBuffer++] = (uint8_t)u32Value;
+            else
+            {
+                LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_VALUE write (%#x).\n", u32Value));
+                pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
+            }
+            break;
+
+        case EFI_VM_VARIABLE_OP_VALUE_LENGTH:
+            Log2(("EFI_VM_VARIABLE_OP_VALUE_LENGTH=%#x\n", u32Value));
+            RT_ZERO(pThis->NVRAM.VarOpBuf.abValue);
+            if (u32Value <= sizeof(pThis->NVRAM.VarOpBuf.abValue))
+                pThis->NVRAM.VarOpBuf.cbValue = u32Value;
+            else
+            {
+                LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_VALUE_LENGTH write (%#x, max %#x).\n",
+                        u32Value, sizeof(pThis->NVRAM.VarOpBuf.abValue)));
+                pThis->NVRAM.VarOpBuf.cbValue = sizeof(pThis->NVRAM.VarOpBuf.abValue);
+                pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
+            }
+            Assert(pThis->NVRAM.offOpBuffer == 0);
+            break;
+
+        default:
+            pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
+            LogRel(("EFI: Unexpected variable operation %#x\n", pThis->NVRAM.enmOp));
+            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.
+ */
+static int nvramReadVariableOp(PDEVEFI pThis,  uint32_t *pu32, unsigned cb)
+{
+    switch (pThis->NVRAM.enmOp)
+    {
+        case EFI_VM_VARIABLE_OP_START:
+            *pu32 = pThis->NVRAM.u32Status;
+            break;
+
+        case EFI_VM_VARIABLE_OP_GUID:
+            if (pThis->NVRAM.offOpBuffer < sizeof(pThis->NVRAM.VarOpBuf.uuid) && cb == 1)
+                *pu32 = pThis->NVRAM.VarOpBuf.uuid.au8[pThis->NVRAM.offOpBuffer++];
+            else
+            {
+                if (cb == 1)
+                    LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_GUID read.\n"));
+                else
+                    LogRel(("EFI: Invalid EFI_VM_VARIABLE_OP_GUID read size (%d).\n", cb));
+                *pu32 = UINT32_MAX;
+            }
+            break;
+
+        case EFI_VM_VARIABLE_OP_ATTRIBUTE:
+            *pu32 = pThis->NVRAM.VarOpBuf.fAttributes;
+            break;
+
+        case EFI_VM_VARIABLE_OP_NAME:
+            /* allow reading terminator char */
+            if (pThis->NVRAM.offOpBuffer <= pThis->NVRAM.VarOpBuf.cchName && cb == 1)
+                *pu32 = pThis->NVRAM.VarOpBuf.szName[pThis->NVRAM.offOpBuffer++];
+            else
+            {
+                if (cb == 1)
+                    LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_NAME read.\n"));
+                else
+                    LogRel(("EFI: Invalid EFI_VM_VARIABLE_OP_NAME read size (%d).\n", cb));
+                *pu32 = UINT32_MAX;
+            }
+            break;
+
+        case EFI_VM_VARIABLE_OP_NAME_LENGTH:
+            *pu32 = pThis->NVRAM.VarOpBuf.cchName;
+            break;
+
+        case EFI_VM_VARIABLE_OP_NAME_UTF16:
+            /* Lazy bird: ASSUME no surrogate pairs. */
+            if (pThis->NVRAM.offOpBuffer < pThis->NVRAM.VarOpBuf.cchName)
+            {
+                char const *psz1 = &pThis->NVRAM.VarOpBuf.szName[pThis->NVRAM.offOpBuffer];
+                char const *psz2 = psz2;
+                RTUNICP Cp;
+                RTStrGetCpEx(&psz2, &Cp);
+                *pu32 = Cp;
+                pThis->NVRAM.offOpBuffer += psz2 - psz1;
+            }
+            else if (pThis->NVRAM.offOpBuffer == pThis->NVRAM.VarOpBuf.cchName)
+            {
+                *pu32 = 0;
+                pThis->NVRAM.offOpBuffer++;
+            }
+            else
+            {
+                if (cb == 1)
+                    LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_NAME_UTF16 read.\n"));
+                else
+                    LogRel(("EFI: Invalid EFI_VM_VARIABLE_OP_NAME_UTF16 read size (%d).\n", cb));
+                *pu32 = UINT32_MAX;
+            }
+            break;
+
+        case EFI_VM_VARIABLE_OP_NAME_LENGTH_UTF16:
+            /* Lazy bird: ASSUME no surrogate pairs. */
+            *pu32 = RTStrUniLen(pThis->NVRAM.VarOpBuf.szName);
+            break;
+
+        case EFI_VM_VARIABLE_OP_VALUE:
+            if (pThis->NVRAM.offOpBuffer < pThis->NVRAM.VarOpBuf.cbValue && cb == 1)
+                *pu32 = pThis->NVRAM.VarOpBuf.abValue[pThis->NVRAM.offOpBuffer++];
+            else
+            {
+                if (cb == 1)
+                    LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_VALUE read.\n"));
+                else
+                    LogRel(("EFI: Invalid EFI_VM_VARIABLE_OP_VALUE read size (%d).\n", cb));
+                *pu32 = UINT32_MAX;
+            }
+            break;
+
+        case EFI_VM_VARIABLE_OP_VALUE_LENGTH:
+            *pu32 = pThis->NVRAM.VarOpBuf.cbValue;
+            break;
+
+        default:
+            *pu32 = UINT32_MAX;
+            break;
+    }
+    return VINF_SUCCESS;
+}
+
+/**
+ * @implement_callback_method{FNDBGFHANDLERDEV}
+ */
+static DECLCALLBACK(void) efiInfoNvram(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
+{
+    PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
+    PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
+
+    pHlp->pfnPrintf(pHlp, "NVRAM variables: %u\n", pThis->NVRAM.cVariables);
+    PEFIVAR pEfiVar;
+    RTListForEach(&pThis->NVRAM.VarList, pEfiVar, EFIVAR, ListNode)
+    {
+        pHlp->pfnPrintf(pHlp, "%RTuuid::'%s' = %.*Rhxs (attr=%#x)\n",
+                        &pEfiVar->uuid, pEfiVar->szName, pEfiVar->cbValue, pEfiVar->abValue, pEfiVar->fAttributes);
+    }
+
+    PDMCritSectLeave(pDevIns->pCritSectRoR3);
+}
+
 
 
@@ -436,78 +959,4 @@
 }
 
-static DECLCALLBACK(int) efiSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
-{
-    int rc = VINF_SUCCESS;
-    PEFIVAR pEfiVar = NULL;
-    LogFlowFuncEnter();
-    PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
-    rc = SSMR3PutStructEx(pSSM, &pThis->NVRAM, sizeof(NVRAMDESC), 0, g_aEfiNvramDescField, NULL);
-    AssertRCReturn(rc, rc);
-    rc = SSMR3PutStructEx(pSSM, &pThis->NVRAM.OperationVarOp, sizeof(EFIVAR), 0, g_aEfiVariableDescFields, NULL);
-    AssertRCReturn(rc, rc);
-    int idxV = 0;
-    RTListForEach(&pThis->NVRAM.NvramVariableList.List, pEfiVar, EFIVAR, List)
-    {
-        rc = SSMR3PutStructEx(pSSM, pEfiVar, sizeof(EFIVAR), 0, g_aEfiVariableDescFields, NULL);
-        AssertRCReturn(rc, rc);
-        idxV++;
-    }
-    Assert((pThis->NVRAM.cNvramVariables == idxV));
-    Log2(("idxV: %d\n", idxV));
-    LogFlowFuncLeaveRC(rc);
-    return rc;
-}
-
-static DECLCALLBACK(int) efiLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
-{
-    int rc = VINF_SUCCESS;
-    NOREF(uPass);
-    LogFlowFunc(("ENTER: uVersion:%d, uPass:%d\n", uVersion, uPass));
-    PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
-    if (uPass != SSM_PASS_FINAL)
-        return rc;
-    /* we should clean up the loaded values */
-    nvramFlushDeviceVariableList(pThis);
-    if (uVersion == 1)
-    {
-        rc = SSMR3GetStructEx(pSSM, &pThis->NVRAM, sizeof(NVRAMDESC), 0, g_aEfiNvramDescField, NULL);
-        AssertRCReturn(rc, rc);
-        rc = SSMR3GetStructEx(pSSM, &pThis->NVRAM.OperationVarOp, sizeof(EFIVAR), 0, g_aEfiVariableDescFields, NULL);
-        AssertRCReturn(rc, rc);
-        int idxVariable = 0;
-        Assert(RTListIsEmpty(&pThis->NVRAM.NvramVariableList.List));
-        RTListInit(&pThis->NVRAM.NvramVariableList.List);
-        for (idxVariable = 0; idxVariable < pThis->NVRAM.cNvramVariables; ++idxVariable)
-        {
-            PEFIVAR pEfiVar = (PEFIVAR)RTMemAllocZ(sizeof(EFIVAR));
-            AssertPtrReturn(pEfiVar, VERR_NO_MEMORY);
-
-            rc = SSMR3GetStructEx(pSSM, pEfiVar, sizeof(EFIVAR), 0, g_aEfiVariableDescFields, NULL);
-            AssertRCReturn(rc, rc);
-
-            RTListInit(&pEfiVar->List);
-            RTListAppend(&pThis->NVRAM.NvramVariableList.List, &pEfiVar->List);
-
-            if (pThis->NVRAM.idxCurrentVar == pEfiVar->idxVariable)
-                pThis->NVRAM.pCurrentVarOp = pEfiVar;
-        }
-    }
-    LogFlowFuncLeaveRC(rc);
-    return rc;
-}
-
-#if 0
-static DECLCALLBACK(int) efiLoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
-{
-    int rc = VINF_SUCCESS;
-    PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
-    LogFlowFuncEnter();
-    if (RTListIsEmpty(&pThis->NVRAM.NvramVariableList.List))
-        nvramLoad(pThis);
-    LogFlowFuncLeaveRC(rc);
-    return rc;
-}
-#endif
-
 /**
  * Port I/O Handler for IN operations.
@@ -555,45 +1004,11 @@
            return VINF_IOM_R3_IOPORT_READ;
 #endif
+
         case EFI_VARIABLE_OP:
-            switch (pThis->NVRAM.enmOp)
-            {
-                case EFI_VM_VARIABLE_OP_START:
-                /* @todo: nop ? */
-                    *pu32 = pThis->NVRAM.u32Status;
-                break;
-                case EFI_VM_VARIABLE_OP_END:
-                break;
-                case EFI_VM_VARIABLE_OP_INDEX:
-                break;
-                case EFI_VM_VARIABLE_OP_GUID:
-                    *pu32 = pThis->NVRAM.OperationVarOp.uuid.au8[pThis->NVRAM.idxOpBuffer];
-                    pThis->NVRAM.idxOpBuffer++;
-                break;
-                case EFI_VM_VARIABLE_OP_ATTRIBUTE:
-                    *pu32 = pThis->NVRAM.OperationVarOp.u32Attribute;
-                break;
-                case EFI_VM_VARIABLE_OP_NAME:
-                    *pu32 = pThis->NVRAM.OperationVarOp.szVariableName[pThis->NVRAM.idxOpBuffer];
-                    pThis->NVRAM.idxOpBuffer++;
-                break;
-                case EFI_VM_VARIABLE_OP_NAME_LENGTH:
-                    *pu32 = pThis->NVRAM.OperationVarOp.cbVariableName;
-                break;
-                case EFI_VM_VARIABLE_OP_VALUE:
-                    *pu32 = pThis->NVRAM.OperationVarOp.au8Value[pThis->NVRAM.idxOpBuffer];
-                    pThis->NVRAM.idxOpBuffer++;
-                break;
-                case EFI_VM_VARIABLE_OP_VALUE_LENGTH:
-                    *pu32 = pThis->NVRAM.OperationVarOp.cbValue;
-                break;
-                default:
-                break;
-            }
+            return nvramReadVariableOp(pThis, pu32, cb);
+
+        case EFI_VARIABLE_PARAM:
+            *pu32 = UINT32_MAX;
             return VINF_SUCCESS;
-        case EFI_VARIABLE_PARAM:
-        {
-            break;
-        }
-        return VINF_SUCCESS;
     }
 
@@ -616,4 +1031,5 @@
 {
     PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
+    int     rc    = VINF_SUCCESS;
     Log4(("efi: out %x %x %d\n", Port, u32, cb));
 
@@ -621,7 +1037,9 @@
     {
         case EFI_INFO_PORT:
+            Log2(("EFI_INFO_PORT: iInfoSelector=%#x\n", u32));
             pThis->iInfoSelector = u32;
             pThis->offInfo       = -1;
             break;
+
         case EFI_DEBUG_PORT:
         {
@@ -648,6 +1066,6 @@
 
                         PRTSTREAM pStrm;
-                        int rc = RTStrmOpen("./DevEFI.VBoxDbg", "a", &pStrm);
-                        if (RT_SUCCESS(rc))
+                        int rc2 = RTStrmOpen("./DevEFI.VBoxDbg", "a", &pStrm);
+                        if (RT_SUCCESS(rc2))
                         {
                             RTStrmPutStr(pStrm, pszVBoxDbg);
@@ -725,169 +1143,22 @@
             break;
         }
+
         case EFI_VARIABLE_OP:
         {
             /* clear buffer index */
-            Assert(u32 < EFI_VM_VARIABLE_OP_MAX);
-            if (u32 >= EFI_VM_VARIABLE_OP_MAX)
-            {
-                u32 = EFI_VARIABLE_OP_STATUS_ERROR;
-                break;
-            }
-            pThis->NVRAM.idxOpBuffer = 0;
+            if (u32 >= (uint32_t)EFI_VM_VARIABLE_OP_MAX)
+            {
+                Log(("EFI: Invalid variable op %#x\n", u32));
+                u32 = EFI_VM_VARIABLE_OP_ERROR;
+            }
+            pThis->NVRAM.offOpBuffer = 0;
             pThis->NVRAM.enmOp = (EFIVAROP)u32;
+            Log2(("EFI_VARIABLE_OP: enmOp=%#x (%d)\n", u32));
+            break;
         }
-        break;
+
         case EFI_VARIABLE_PARAM:
-        {
-            switch (pThis->NVRAM.enmOp)
-            {
-                case EFI_VM_VARIABLE_OP_START:
-                {
-                    pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_BSY;
-                    switch (u32)
-                    {
-                        case EFI_VARIABLE_OP_QUERY:
-                        {
-                            LogRel(("EFI: variable lookup %RTuuid, %s\n",
-                                    &pThis->NVRAM.OperationVarOp.uuid,
-                                    pThis->NVRAM.OperationVarOp.szVariableName));
-                            pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_BSY;
-                            PEFIVAR pEfiVar = NULL;
-                            memset(pThis->NVRAM.OperationVarOp.au8Value, 0, EFI_VARIABLE_NAME_MAX);
-                            int nvramRc = nvramLookupVariableByUuidAndName(
-                                                pThis,
-                                                pThis->NVRAM.OperationVarOp.szVariableName,
-                                                &pThis->NVRAM.OperationVarOp.uuid,
-                                                &pEfiVar);
-                            if (RT_SUCCESS(nvramRc))
-                            {
-                                pThis->NVRAM.OperationVarOp.u32Attribute = pEfiVar->u32Attribute;
-                                pThis->NVRAM.OperationVarOp.cbVariableName = pEfiVar->cbVariableName;
-                                pThis->NVRAM.OperationVarOp.cbValue = pEfiVar->cbValue;
-                                memcpy(pThis->NVRAM.OperationVarOp.au8Value,
-                                       pEfiVar->au8Value, pEfiVar->cbValue);
-                                pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
-                                pThis->NVRAM.pCurrentVarOp = pEfiVar;
-                                pThis->NVRAM.idxCurrentVar = pEfiVar->idxVariable;
-                                LogFlowFunc(("OperationVar: au8Value:%.*Rhxs\n",
-                                              pThis->NVRAM.OperationVarOp.cbValue,
-                                              pThis->NVRAM.OperationVarOp.au8Value));
-                            }
-                            else
-                                pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_NOT_FOUND;
-                        }
-                        break;
-                        case EFI_VARIABLE_OP_ADD:
-                        {
-                            LogRel(("EFI: variable add %RTuuid, %s\n", &pThis->NVRAM.OperationVarOp.uuid, pThis->NVRAM.OperationVarOp.szVariableName));
-                            PEFIVAR pEfiVar = NULL;
-                            LogFlowFunc(("OperationVar: au8Value:%.*Rhxs\n",
-                                          pThis->NVRAM.OperationVarOp.cbValue,
-                                          pThis->NVRAM.OperationVarOp.au8Value));
-                            int nvramRc = nvramLookupVariableByUuidAndName(
-                                                pThis,
-                                                pThis->NVRAM.OperationVarOp.szVariableName,
-                                                &pThis->NVRAM.OperationVarOp.uuid,
-                                                &pEfiVar);
-                            if (RT_SUCCESS(nvramRc))
-                            {
-                                /* delete or update ? */
-                                /* @todo: check whether pEfiVar is WP */
-                                LogFlowFunc(("pEfiVar: au8Value:%.*Rhxs\n",
-                                             pEfiVar->cbValue,
-                                             pEfiVar->au8Value));
-                                if (pThis->NVRAM.OperationVarOp.cbValue == 0)
-                                {
-                                    /* delete */
-                                    RTListNodeRemove(&pEfiVar->List);
-                                    RTMemFree(pEfiVar);
-                                    pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
-                                    pThis->NVRAM.cNvramVariables--;
-                                }
-                                else
-                                {
-                                    /* update */
-                                    pEfiVar->cbValue = pThis->NVRAM.OperationVarOp.cbValue;
-                                    memcpy(pEfiVar->au8Value, pThis->NVRAM.OperationVarOp.au8Value, pEfiVar->cbValue);
-                                    pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
-                                }
-                            }
-                            else
-                            {
-                                if (pThis->NVRAM.OperationVarOp.cbValue != 0)
-                                {
-                                    pEfiVar = (PEFIVAR)RTMemAllocZ(sizeof(EFIVAR));
-                                    if (!pEfiVar)
-                                    {
-                                        pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
-                                        break;
-                                    }
-                                }
-                                else
-                                {
-                                    pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
-                                    break;
-                                }
-
-                                memcpy(pEfiVar, &pThis->NVRAM.OperationVarOp, sizeof(EFIVAR));
-                                RTListInit(&pEfiVar->List);
-                                RTListAppend(&pThis->NVRAM.NvramVariableList.List, &pEfiVar->List);
-                                pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
-                                pThis->NVRAM.cNvramVariables++;
-                                pEfiVar->idxVariable = pThis->NVRAM.iNvramLastIndex;
-                                pThis->NVRAM.iNvramLastIndex++;
-                            }
-                        }
-                        LogFunc(("cNvramVariables:%d, iNvramLastIndex:%d\n", pThis->NVRAM.cNvramVariables, pThis->NVRAM.iNvramLastIndex));
-                        break;
-                        case EFI_VARIABLE_OP_QUERY_NEXT:
-                        {
-                            PEFIVAR pEfiVar = RTListNodeGetNext(&pThis->NVRAM.pCurrentVarOp->List, EFIVAR, List);
-                            if (pEfiVar)
-                            {
-                                memcpy(&pThis->NVRAM.OperationVarOp, pEfiVar, sizeof(EFIVAR));
-                                pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
-                            }
-                            else
-                                pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_NOT_FOUND;
-                        }
-                        break;
-                        default:
-                            /* @todo: return error */
-                            break;
-                    }
-                }
-                case EFI_VM_VARIABLE_OP_END:
-                break;
-                case EFI_VM_VARIABLE_OP_INDEX:
-                break;
-                case EFI_VM_VARIABLE_OP_GUID:
-                    pThis->NVRAM.OperationVarOp.uuid.au8[pThis->NVRAM.idxOpBuffer] = (uint8_t)u32;
-                    pThis->NVRAM.idxOpBuffer++;
-                break;
-                case EFI_VM_VARIABLE_OP_ATTRIBUTE:
-                    pThis->NVRAM.OperationVarOp.u32Attribute = u32;
-                break;
-                case EFI_VM_VARIABLE_OP_NAME:
-                    pThis->NVRAM.OperationVarOp.szVariableName[pThis->NVRAM.idxOpBuffer] = (uint8_t)u32;
-                    pThis->NVRAM.idxOpBuffer++;
-                break;
-                case EFI_VM_VARIABLE_OP_NAME_LENGTH:
-                    pThis->NVRAM.OperationVarOp.cbVariableName = u32;
-                    memset(pThis->NVRAM.OperationVarOp.szVariableName, 0, EFI_VARIABLE_NAME_MAX);
-                break;
-                case EFI_VM_VARIABLE_OP_VALUE:
-                    pThis->NVRAM.OperationVarOp.au8Value[pThis->NVRAM.idxOpBuffer] = (uint8_t)u32;
-                    pThis->NVRAM.idxOpBuffer++;
-                break;
-                case EFI_VM_VARIABLE_OP_VALUE_LENGTH:
-                    pThis->NVRAM.OperationVarOp.cbValue = u32;
-                    memset(pThis->NVRAM.OperationVarOp.au8Value, 0, EFI_VARIABLE_VALUE_MAX);
-                break;
-                default:
-                break;
-            }
-        }
-        break;
+            rc = nvramWriteVariableParam(pThis, u32);
+            break;
 
         default:
@@ -895,5 +1166,144 @@
             break;
     }
+    return rc;
+}
+
+static DECLCALLBACK(int) efiSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
+{
+    PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
+    LogFlow(("efiSaveExec:\n"));
+
+    /*
+     * Set variables only used when saving state.
+     */
+    uint32_t idUniqueSavedState = 0;
+    PEFIVAR pEfiVar;
+    RTListForEach(&pThis->NVRAM.VarList, pEfiVar, EFIVAR, ListNode)
+    {
+        pEfiVar->idUniqueSavedState = idUniqueSavedState++;
+    }
+    Assert(idUniqueSavedState == pThis->NVRAM.cVariables);
+
+    pThis->NVRAM.idUniqueCurVar = pThis->NVRAM.pCurVar
+                                ? pThis->NVRAM.pCurVar->idUniqueSavedState
+                                : UINT32_MAX;
+
+    /*
+     * Save the NVRAM state.
+     */
+    SSMR3PutStructEx(pSSM, &pThis->NVRAM,          sizeof(NVRAMDESC), 0, g_aEfiNvramDescField,     NULL);
+    SSMR3PutStructEx(pSSM, &pThis->NVRAM.VarOpBuf, sizeof(EFIVAR),    0, g_aEfiVariableDescFields, NULL);
+
+    /*
+     * Save the list variables (we saved the length above).
+     */
+    RTListForEach(&pThis->NVRAM.VarList, pEfiVar, EFIVAR, ListNode)
+    {
+        SSMR3PutStructEx(pSSM, pEfiVar, sizeof(EFIVAR), 0, g_aEfiVariableDescFields, NULL);
+    }
+
+    return VINF_SUCCESS; /* SSM knows */
+}
+
+static DECLCALLBACK(int) efiLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
+{
+    PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
+    LogFlow(("efiLoadExec: uVersion=%d uPass=%d\n", uVersion, uPass));
+
+    /*
+     * Validate input.
+     */
+    if (uPass != SSM_PASS_FINAL)
+        return VERR_SSM_UNEXPECTED_PASS;
+    if (   uVersion != EFI_SSM_VERSION
+        && uVersion != EFI_SSM_VERSION_4_2
+        )
+        return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
+
+    /*
+     * Kill the current variables before loading anything.
+     */
+    nvramFlushDeviceVariableList(pThis);
+
+    /*
+     * Load the NVRAM state.
+     */
+    int rc = SSMR3GetStructEx(pSSM, &pThis->NVRAM, sizeof(NVRAMDESC), 0, g_aEfiNvramDescField, NULL);
+    AssertRCReturn(rc, rc);
+    pThis->NVRAM.pCurVar = NULL;
+
+    rc = SSMR3GetStructEx(pSSM, &pThis->NVRAM.VarOpBuf, sizeof(EFIVAR), 0, g_aEfiVariableDescFields, NULL);
+    AssertRCReturn(rc, rc);
+
+    /*
+     * Load variables.
+     */
+    pThis->NVRAM.pCurVar = NULL;
+    Assert(RTListIsEmpty(&pThis->NVRAM.VarList));
+    RTListInit(&pThis->NVRAM.VarList);
+    for (uint32_t i = 0; i < pThis->NVRAM.cVariables; i++)
+    {
+        PEFIVAR pEfiVar = (PEFIVAR)RTMemAllocZ(sizeof(EFIVAR));
+        AssertPtrReturn(pEfiVar, VERR_NO_MEMORY);
+
+        rc = SSMR3GetStructEx(pSSM, pEfiVar, sizeof(EFIVAR), 0, g_aEfiVariableDescFields, NULL);
+        if (RT_SUCCESS(rc))
+        {
+            if (   pEfiVar->cbValue > sizeof(pEfiVar->abValue)
+                || pEfiVar->cbValue == 0)
+            {
+                rc = VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
+                LogRel(("EFI: Loaded invalid variable value length %#x\n", pEfiVar->cbValue));
+            }
+            size_t cchVarName = RTStrNLen(pEfiVar->szName, sizeof(pEfiVar->szName));
+            if (cchVarName >= sizeof(pEfiVar->szName))
+            {
+                rc = VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
+                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. */
+            {
+                rc = VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
+                LogRel(("EFI: Loaded invalid variable name length %#x (cchVarName=%#x)\n", pEfiVar->cchName, cchVarName));
+            }
+            if (RT_SUCCESS(rc))
+                pEfiVar->cchName = cchVarName;
+        }
+        AssertRCReturnStmt(rc, RTMemFree(pEfiVar), rc);
+
+        /* Add it, updating the current variable pointer while we're here. */
+        RTListAppend(&pThis->NVRAM.VarList, &pEfiVar->ListNode);
+        if (pThis->NVRAM.idUniqueCurVar == pEfiVar->idUniqueSavedState)
+            pThis->NVRAM.pCurVar = pEfiVar;
+    }
+
     return VINF_SUCCESS;
+}
+
+
+/**
+ * @copydoc(PDMIBASE::pfnQueryInterface)
+ */
+static DECLCALLBACK(void *) devEfiQueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+    LogFlowFunc(("ENTER: pIBase: %p, pszIID:%p\n", __FUNCTION__, pInterface, pszIID));
+    PDEVEFI  pThis = RT_FROM_MEMBER(pInterface, DEVEFI, Lun0.IBase);
+
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Lun0.IBase);
+    return NULL;
+}
+
+
+/**
+ * Write to CMOS memory.
+ * This is used by the init complete code.
+ */
+static void cmosWrite(PPDMDEVINS pDevIns, unsigned off, uint32_t u32Val)
+{
+    Assert(off < 128);
+    Assert(u32Val < 256);
+
+    int rc = PDMDevHlpCMOSWrite(pDevIns, off, u32Val);
+    AssertRC(rc);
 }
 
@@ -999,10 +1409,8 @@
 {
     PDEVEFI  pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
+
     nvramStore(pThis);
     nvramFlushDeviceVariableList(pThis);
 
-    /*
-     * Free MM heap pointers.
-     */
     if (pThis->pu8EfiRom)
     {
@@ -1011,4 +1419,7 @@
     }
 
+    /*
+     * Free MM heap pointers (waste of time, but whatever).
+     */
     if (pThis->pszEfiRomFile)
     {
@@ -1232,16 +1643,4 @@
 
 /**
- * @copydoc(PDMIBASE::pfnQueryInterface)
- */
-static DECLCALLBACK(void *) devEfiQueryInterface(PPDMIBASE pInterface, const char *pszIID)
-{
-    LogFlowFunc(("ENTER: pIBase: %p, pszIID:%p\n", __FUNCTION__, pInterface, pszIID));
-    PDEVEFI  pThis = RT_FROM_MEMBER(pInterface, DEVEFI, Lun0.IBase);
-
-    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Lun0.IBase);
-    return NULL;
-}
-
-/**
  * @interface_method_impl{PDMDEVREG,pfnConstruct}
  */
@@ -1253,5 +1652,11 @@
     Assert(iInstance == 0);
 
+    /*
+     * Initalize the basic variables so that the destructor always works.
+     */
     pThis->pDevIns = pDevIns;
+    RTListInit(&pThis->NVRAM.VarList);
+    pThis->Lun0.IBase.pfnQueryInterface = devEfiQueryInterface;
+
 
     /*
@@ -1332,6 +1737,4 @@
     uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
     memcpy(&pThis->aUuid, &uuid, sizeof pThis->aUuid);
-    RTListInit((PRTLISTNODE)&pThis->NVRAM.NvramVariableList.List);
-
 
     /*
@@ -1372,14 +1775,5 @@
      * NVRAM processing.
      */
-    pThis->Lun0.IBase.pfnQueryInterface = devEfiQueryInterface;
-
-#if 0
-    rc = PDMDevHlpSSMRegisterEx(pDevIns, EFI_SSM_VERSION, sizeof(*pThis), NULL /*pszBefore*/,
-                                              NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/,  NULL /*pfnLiveDone*/,
-                                              NULL /*pfnSavePrep*/, efiSaveExec,           NULL /*pfnSaveDone*/,
-                                              NULL /*pfnLoadPrep*/, efiLoadExec,           efiLoadDone);
-#else
     rc = PDMDevHlpSSMRegister(pDevIns, EFI_SSM_VERSION, sizeof(*pThis), efiSaveExec, efiLoadExec);
-#endif
     AssertRCReturn(rc, rc);
 
@@ -1388,19 +1782,14 @@
         return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("Can't attach Nvram Storage driver"));
 
-    pThis->Lun0.pNvramDown = (PPDMINVRAM)pThis->Lun0.pDrvBase->pfnQueryInterface(pThis->Lun0.pDrvBase, PDMINVRAM_IID);
-    AssertPtrReturn(pThis->Lun0.pNvramDown, VERR_PDM_MISSING_INTERFACE_BELOW);
-
-    nvramLoad(pThis);
+    pThis->Lun0.pNvramDrv = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pDrvBase, PDMINVRAMCONNECTOR);
+    AssertPtrReturn(pThis->Lun0.pNvramDrv, VERR_PDM_MISSING_INTERFACE_BELOW);
+
+    rc = nvramLoad(pThis);
+    AssertRCReturn(rc, rc);
 
     /*
      * Get boot args.
      */
-    rc = CFGMR3QueryString(pCfg, "BootArgs",
-                           pThis->szBootArgs, sizeof pThis->szBootArgs);
-    if (rc == VERR_CFGM_VALUE_NOT_FOUND)
-    {
-        strcpy(pThis->szBootArgs, "");
-        rc = VINF_SUCCESS;
-    }
+    rc = CFGMR3QueryStringDef(pCfg, "BootArgs", pThis->szBootArgs, sizeof(pThis->szBootArgs), "");
     if (RT_FAILURE(rc))
         return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
@@ -1412,11 +1801,6 @@
      * Get device props.
      */
-    char* pszDeviceProps;
-    rc = CFGMR3QueryStringAlloc(pCfg, "DeviceProps", &pszDeviceProps);
-    if (rc == VERR_CFGM_VALUE_NOT_FOUND)
-    {
-        pszDeviceProps = NULL;
-        rc = VINF_SUCCESS;
-    }
+    char *pszDeviceProps;
+    rc = CFGMR3QueryStringAllocDef(pCfg, "DeviceProps", &pszDeviceProps, NULL);
     if (RT_FAILURE(rc))
         return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
@@ -1440,5 +1824,5 @@
      * CPU frequencies
      */
-    /// @todo: we need to have VMM API to access TSC increase speed, for now provide reasonable default
+    /// @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)
@@ -1451,13 +1835,13 @@
      * GOP graphics
      */
-    rc = CFGMR3QueryU32(pCfg, "GopMode", &pThis->u32GopMode);
-    AssertRC(rc);
+    rc = CFGMR3QueryU32Def(pCfg, "GopMode", &pThis->u32GopMode, 2 /* 1024x768 */);
+    if (RT_FAILURE(rc))
+        return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
+                                   N_("Configuration error: Querying \"GopMode\" as a 32-bit int failed"));
     if (pThis->u32GopMode == UINT32_MAX)
-    {
         pThis->u32GopMode = 2; /* 1024x768 */
-    }
-
-    /*
-     * Uga graphics
+
+    /*
+     * Uga graphics.
      */
     rc = CFGMR3QueryU32Def(pCfg, "UgaHorizontalResolution", &pThis->cxUgaResolution, 0); AssertRC(rc);
@@ -1483,5 +1867,5 @@
 
     /*
-     * Register our communication ports.
+     * Register our I/O ports.
      */
     rc = PDMDevHlpIOPortRegister(pDevIns, EFI_PORT_BASE, EFI_PORT_COUNT, NULL,
@@ -1492,5 +1876,5 @@
 
     /*
-     * Plant DMI and MPS tables
+     * Plant DMI and MPS tables.
      */
     /** @todo XXX I wonder if we really need these tables as there is no SMBIOS header... */
@@ -1508,4 +1892,10 @@
 
     /*
+     * Register info handlers.
+     */
+    rc = PDMDevHlpDBGFInfoRegister(pDevIns, "nvram", "Dumps the NVRAM variables.\n", efiInfoNvram);
+    AssertRCReturn(rc, rc);
+
+    /*
      * Call reset to set things up.
      */
@@ -1529,5 +1919,6 @@
     "",
     /* pszDescription */
-    "Extensible Firmware Interface Device",
+    "Extensible Firmware Interface Device. "
+    "LUN#0 - NVRAM port",
     /* fFlags */
     PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64,
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Include/DevEFI.h
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Include/DevEFI.h	(revision 44590)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Include/DevEFI.h	(revision 44591)
@@ -120,11 +120,16 @@
 #define EFI_VARIABLE_OP_STATUS_BSY        0xcafe0010
 
-#define EFI_VARIABLE_NAME_MAX   1024
-#define EFI_VARIABLE_VALUE_MAX   1024
+/** The max number of variables allowed. */
+#define EFI_VARIABLE_MAX            128
+/** The max variable name length (in bytes, including the zero terminator). */
+#define EFI_VARIABLE_NAME_MAX       1024
+/** The max value length (in bytes). */
+#define EFI_VARIABLE_VALUE_MAX      1024
 
-typedef enum {
+typedef enum
+{
     EFI_VM_VARIABLE_OP_START = 0,
-    EFI_VM_VARIABLE_OP_END,
-    EFI_VM_VARIABLE_OP_INDEX,
+    EFI_VM_VARIABLE_OP_END, /**< @todo r=bird: What's the point of this one? */
+    EFI_VM_VARIABLE_OP_RESERVED_USED_TO_BE_INDEX,
     EFI_VM_VARIABLE_OP_GUID,
     EFI_VM_VARIABLE_OP_ATTRIBUTE,
@@ -133,5 +138,9 @@
     EFI_VM_VARIABLE_OP_VALUE,
     EFI_VM_VARIABLE_OP_VALUE_LENGTH,
-    EFI_VM_VARIABLE_OP_MAX
+    EFI_VM_VARIABLE_OP_ERROR,
+    EFI_VM_VARIABLE_OP_NAME_UTF16,
+    EFI_VM_VARIABLE_OP_NAME_LENGTH_UTF16,
+    EFI_VM_VARIABLE_OP_MAX,
+    EFI_VM_VARIABLE_OP_32BIT_HACK = 0x7fffffff
 } EFIVAROP;
 
Index: trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxVariable/InitVariable.c
===================================================================
--- trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxVariable/InitVariable.c	(revision 44590)
+++ trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxVariable/InitVariable.c	(revision 44591)
@@ -45,5 +45,5 @@
 
 
-static inline UINT32 VBoxReadNVRAM(UINT8 *pu8Buffer, UINT32 cbBuffer)
+static UINT32 VBoxReadNVRAM(UINT8 *pu8Buffer, UINT32 cbBuffer)
 {
     UINT32 idxBuffer = 0;
@@ -59,34 +59,20 @@
 }
 
-static inline UINT32 VBoxWriteNVRAMByteArrayParam(const UINT8 *pu8Param, UINT32 cbParam)
+static UINT32 VBoxWriteNVRAMByteArrayParam(const UINT8 *pbParam, UINT32 cbParam)
 {
     UINT32 idxParam = 0;
     for (idxParam = 0; idxParam < cbParam; ++idxParam)
-        ASMOutU8(EFI_VARIABLE_PARAM, pu8Param[idxParam]);
+        ASMOutU8(EFI_VARIABLE_PARAM, pbParam[idxParam]);
     return idxParam;
 }
 
-static inline UINT32 VBoxWriteNVRAMStringParam(const CHAR16 *ps16VariableName)
-{
-    CHAR8 szVarName[512];
-    UINT32 cbVarName = StrLen(ps16VariableName);
-    LogFlowFuncEnter();
-    ASSERT (cbVarName < 512);
-    if (cbVarName > 512)
-    {
-        LogFlowFuncMarkVar(cbVarName, "%d");
-        LogFlowFuncLeave();
-        return 0;
-    }
-    UnicodeStrToAsciiStr(ps16VariableName, szVarName);
-
-    VBoxWriteNVRAMU32Param(EFI_VM_VARIABLE_OP_NAME_LENGTH, cbVarName);
-
-    ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_NAME);
-    cbVarName = VBoxWriteNVRAMByteArrayParam((UINT8 *)szVarName, cbVarName);
-
-    LogFlowFuncMarkVar(cbVarName, "%d");
-    LogFlowFuncLeave();
-    return cbVarName;
+static void VBoxWriteNVRAMNameParam(const CHAR16 *pwszName)
+{
+    UINT32 i;
+    UINT32 cwcName = StrLen(pwszName);
+
+    ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_NAME_UTF16);
+    for (i = 0; i <= cwcName; i++)
+        ASMOutU16(EFI_VARIABLE_PARAM, pwszName[i]);
 }
 
@@ -97,5 +83,5 @@
 }
 
-static inline UINT32 VBoxWriteNVRAMDoOp(UINT32 u32Operation)
+static UINT32 VBoxWriteNVRAMDoOp(UINT32 u32Operation)
 {
     UINT32 u32Rc;
@@ -104,10 +90,10 @@
     VBoxWriteNVRAMU32Param(EFI_VM_VARIABLE_OP_START, u32Operation);
 
-    while((u32Rc = ASMInU32(EFI_VARIABLE_OP)) == EFI_VARIABLE_OP_STATUS_BSY)
+    while ((u32Rc = ASMInU32(EFI_VARIABLE_OP)) == EFI_VARIABLE_OP_STATUS_BSY)
     {
 #if 0
         MicroSecondDelay (400);
 #endif
-        /* @todo: sleep here */
+        /* @todo: sleep here. bird: won't ever happen, so don't bother. */
     }
     LogFlowFuncMarkVar(u32Rc, "%x");
@@ -154,41 +140,37 @@
           );
 #else
-    UINT32 VarLen;
-    UINT32 u32Rc = 0;
+    EFI_STATUS rc;
+    UINT32 u32Rc;
 
     LogFlowFuncEnter();
-    /* set uuid */
+
+    /*
+     * Tell DevEFI to look for the specified variable.
+     */
     ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_GUID);
     VBoxWriteNVRAMGuidParam(VendorGuid);
-
-    /* set name */
-    VBoxWriteNVRAMStringParam(VariableName);
-
-    /* start operation */
+    VBoxWriteNVRAMNameParam(VariableName);
+
     u32Rc = VBoxWriteNVRAMDoOp(EFI_VARIABLE_OP_QUERY);
-
-    ASSERT (u32Rc != EFI_VARIABLE_OP_STATUS_ERROR);
-    switch(u32Rc)
+    if (u32Rc == EFI_VARIABLE_OP_STATUS_OK)
     {
-        case EFI_VARIABLE_OP_STATUS_ERROR: /* for release build */
-        case EFI_VARIABLE_OP_STATUS_NOT_FOUND:
-            LogFlowFuncLeaveRC(EFI_NOT_FOUND);
-            return EFI_NOT_FOUND;
-        case EFI_VARIABLE_OP_STATUS_OK:
+        /*
+         * Check if we got enought space for the value.
+         */
+        UINT32 VarLen;
+        ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_VALUE_LENGTH);
+        VarLen = ASMInU32(EFI_VARIABLE_OP);
+        LogFlowFuncMarkVar(*DataSize, "%d");
+        LogFlowFuncMarkVar(VarLen, "%d");
+        if (   VarLen <= *DataSize
+            && Data)
         {
-            ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_VALUE_LENGTH);
-            VarLen = ASMInU32(EFI_VARIABLE_OP);
-            LogFlowFuncMarkVar(*DataSize, "%d");
-            LogFlowFuncMarkVar(VarLen, "%d");
-            if (   VarLen > *DataSize
-                || !Data)
-            {
-                *DataSize = VarLen;
-                /* @todo: should we end op ? */
-                LogFlowFuncLeave();
-                return EFI_BUFFER_TOO_SMALL;
-            }
+            /*
+             * We do, then read it and, if requrest, the attribute.
+             */
+            *DataSize = VarLen;
             ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_VALUE);
-            *DataSize = VBoxReadNVRAM((UINT8 *)Data, VarLen);
+            VBoxReadNVRAM((UINT8 *)Data, VarLen);
+
             if (Attributes)
             {
@@ -197,10 +179,21 @@
                 LogFlowFuncMarkVar(Attributes, "%x");
             }
-            LogFlowFuncLeaveRC((EFI_SUCCESS));
-            return EFI_SUCCESS;
+
+            rc = EFI_SUCCESS;
+        }
+        else
+        {
+            *DataSize = VarLen;
+            rc = EFI_BUFFER_TOO_SMALL;
         }
     }
-#endif
-    return EFI_SUCCESS;
+    else
+    {
+        rc = EFI_NOT_FOUND;
+    }
+
+    LogFlowFuncLeaveRC(rc);
+    return rc;
+#endif
 }
 
@@ -235,44 +228,54 @@
           );
 #else
-    uint32_t u32Rc = 0;
-    EFI_STATUS rc = EFI_NOT_FOUND;
-    CHAR8   szVariableName[512];
-    int cbVarName = 0;
-
+    uint32_t    u32Rc;
+    EFI_STATUS  rc;
     LogFlowFuncEnter();
 
-    SetMem(szVariableName, 512, 0);
-    u32Rc = VBoxWriteNVRAMDoOp(EFI_VARIABLE_OP_QUERY_NEXT);
-    switch (u32Rc)
+    /* 
+     * Tell DevEFI which the current variable is, then ask for the next one.
+     */
+    ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_GUID);
+    VBoxWriteNVRAMGuidParam(VendorGuid);
+    VBoxWriteNVRAMNameParam(VariableName);
+
+    u32Rc = VBoxWriteNVRAMDoOp(EFI_VARIABLE_OP_QUERY);
+    if (u32Rc == EFI_VARIABLE_OP_STATUS_OK)
+        u32Rc = VBoxWriteNVRAMDoOp(EFI_VARIABLE_OP_QUERY_NEXT);
+
+    if (u32Rc == EFI_VARIABLE_OP_STATUS_OK)
     {
-        case EFI_VARIABLE_OP_STATUS_OK:
+        /* 
+         * Output buffer check.
+         */
+        UINT32      cwcName;
+        ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_NAME_LENGTH_UTF16);
+        cwcName = ASMInU32(EFI_VARIABLE_OP);
+        if (cwcName * 2 < *VariableNameSize) /* ASSUMES byte size is specified */
         {
-            ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_NAME_LENGTH);
-            cbVarName = ASMInU32(EFI_VARIABLE_OP);
-
+            UINT32 i;
+
+            /* 
+             * Read back the result.
+             */
             ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_GUID);
             VBoxReadNVRAM((UINT8 *)VendorGuid, sizeof(EFI_GUID));
 
-            ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_NAME);
-            VBoxReadNVRAM((UINT8 *)szVariableName, cbVarName);
-
-            if (cbVarName < *VariableNameSize)
-            {
-                UnicodeSPrintAsciiFormat(VariableName, cbVarName, "%a", szVariableName);
-                LogFlowFuncMarkVar(*VariableNameSize, "%d");
-                LogFlowFuncMarkVar(VariableName, "%s");
-                LogFlowFuncMarkVar(VendorGuid, "%g");
-                *VariableNameSize = cbVarName;
-                LogFlowFuncMarkVar(*VariableNameSize, "%d");
-                rc = EFI_SUCCESS;
-            }
-            else
-                rc = EFI_BUFFER_TOO_SMALL;
+            ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_NAME_UTF16);
+            for (i = 0; i < cwcName; i++)
+                VariableName[i] = ASMInU16(EFI_VARIABLE_OP);
+            VariableName[i] = '\0';
+
+            *VariableNameSize = cwcName * 2;
+            rc = EFI_SUCCESS;
         }
-        case EFI_VARIABLE_OP_STATUS_ERROR:
-        case EFI_VARIABLE_OP_STATUS_NOT_FOUND:
-        case EFI_VARIABLE_OP_STATUS_NOT_WP:
-            rc = EFI_NOT_FOUND;
+        else
+        {
+            rc = EFI_BUFFER_TOO_SMALL;
+            *VariableNameSize = (cwcName + 1) * 2;
+        }
     }
+    else
+        rc = EFI_NOT_FOUND; /* whatever */
+
     LogFlowFuncLeaveRC(rc);
     return rc;
@@ -328,5 +331,5 @@
     VBoxWriteNVRAMGuidParam(VendorGuid);
     /* set name */
-    VBoxWriteNVRAMStringParam(VariableName);
+    VBoxWriteNVRAMNameParam(VariableName);
     /* set attribute */
     VBoxWriteNVRAMU32Param(EFI_VM_VARIABLE_OP_ATTRIBUTE, Attributes);
@@ -340,5 +343,5 @@
     /* process errors */
     LogFlowFuncLeave();
-    switch(u32Rc)
+    switch (u32Rc)
     {
         case EFI_VARIABLE_OP_STATUS_OK:
Index: trunk/src/VBox/Main/include/Nvram.h
===================================================================
--- trunk/src/VBox/Main/include/Nvram.h	(revision 44590)
+++ trunk/src/VBox/Main/include/Nvram.h	(revision 44591)
@@ -31,7 +31,8 @@
     Nvram(Console *console);
     virtual ~Nvram();
+
+    Console *getParent(void) { return mParent; }
+
     static const PDMDRVREG DrvReg;
-    Console *getParent(void) { return mParent; }
-    struct NVRAM *mpDrv;
 
 private:
@@ -40,5 +41,9 @@
     static DECLCALLBACK(void)   drvNvram_Destruct(PPDMDRVINS pDrvIns);
 
+    /** Pointer to the parent object. */
     Console * const mParent;
+    /** Pointer to the driver instance data.
+     *  Can be NULL during init and termination. */
+    struct NVRAM *mpDrv;
 };
 
Index: trunk/src/VBox/Main/src-client/Nvram.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/Nvram.cpp	(revision 44590)
+++ trunk/src/VBox/Main/src-client/Nvram.cpp	(revision 44591)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2012 Oracle Corporation
+ * Copyright (C) 2012-2013 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -21,4 +21,5 @@
 #include "Nvram.h"
 #include "ConsoleImpl.h"
+#include "Global.h"
 
 #include <VBox/vmm/pdm.h>
@@ -45,10 +46,23 @@
 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;
 };
 
@@ -57,7 +71,7 @@
  * Constructor/destructor
  */
-Nvram::Nvram(Console *console)
-    : mpDrv(NULL),
-      mParent(console)
+Nvram::Nvram(Console *pConsole)
+    : mParent(pConsole),
+      mpDrv(NULL)
 {
 }
@@ -74,147 +88,208 @@
 
 /**
- * @interface_method_impl(PDMINVRAM,pfnStoreNvramValue)
- */
-DECLCALLBACK(int) drvNvram_pfnStoreNvramValue(PPDMINVRAM pInterface,
-                                              int idxVariable,
-                                              RTUUID *pVendorUuid,
-                                              const char *pcszVariableName,
-                                              size_t cbVariableName,
-                                              uint8_t *pu8Value,
-                                              size_t cbValue)
-{
-    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)
-    {
-        LogFlowFuncLeaveRC(rc);
-        return rc;
-    }
-
-    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,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.
+ */
+static char *drvNvram_binaryToCfgmString(void const *pvBuf, size_t cbBuf)
+{
+    static char s_szPrefix[] = "bytes:";
+    size_t cbStr   = RTBase64EncodedLength(cbBuf) + sizeof(s_szPrefix);
+    char   *pszStr = (char *)RTMemAlloc(cbStr);
+    if (pszStr)
+    {
+        memcpy(pszStr, s_szPrefix, sizeof(s_szPrefix) - 1);
+        int rc = RTBase64Encode(pvBuf, cbBuf, &pszStr[sizeof(s_szPrefix) - 1], cbBuf - sizeof(s_szPrefix) + 1, NULL);
+        if (RT_FAILURE(rc))
+        {
+            RTMemFree(pszStr);
+            pszStr = NULL;
+        }
+    }
+    return pszStr;
+}
+
+/**
+ * @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,
+                                         "VBoxInternal/Devices/efi/0/LUN#0/Config/Vars/%4u/", idxVariable);
+
+        char    szAttribs[32];
+        RTStrPrintf(szAttribs, sizeof(szAttribs), "%#x", fAttributes);
+
+        char    szUuid[RTUUID_STR_LENGTH];
+        int rc2 = RTUuidToStr(pVendorUuid, szUuid, sizeof(szUuid)); AssertRC(rc2);
+
+        char   *pszValue = drvNvram_binaryToCfgmString(pbValue, cbValue);
+        if (pszValue)
+        {
+            const char *apszTodo[] =
+            {
+                "Name",     pszName,
+                "Uuid",     szUuid,
+                "Attribs",  szAttribs,
+                "Value",    pszValue,
+            };
+            for (unsigned i = 0; i < RT_ELEMENTS(apszTodo); i += 2)
+            {
+                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)
- */
-DECLCALLBACK(int) drvNvram_pfnFlushNvramStorage(PPDMINVRAM pInterface)
-{
-    int rc = VINF_SUCCESS;
-    LogFlowFuncEnter();
-    PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvram);
-    if (!pThis->fPermanentSave)
-    {
-        LogFlowFuncLeaveRC(rc);
-        return rc;
-    }
-
-    for (int idxVariable = 0; idxVariable < pThis->cLoadedVariables; ++idxVariable)
-    {
-        drvNvram_pfnStoreNvramValue(pInterface, idxVariable, NULL, NULL, 0, NULL, 0);
-    }
-    LogFlowFuncLeaveRC(rc);
+/**
+ * Deletes a variable.
+ *
+ * @param   pThis           The NVRAM driver instance data.
+ * @param   pszVarNodeNm    The variable node name.
+ */
+static void drvNvram_deleteVar(PNVRAM pThis, const char *pszVarNodeNm)
+{
+    char   szExtraName[256];
+    size_t offValue = RTStrPrintf(szExtraName, sizeof(szExtraName) - 16,
+                                  "VBoxInternal/Devices/efi/0/LUN#0/Config/Vars/%s/", pszVarNodeNm);
+    static const char *s_apszValueNames[] = { "Name", "Attribs", "Value" };
+    for (unsigned i = 0; i < RT_ELEMENTS(s_apszValueNames); i++)
+    {
+        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));
+        }
+    }
+}
+
+/**
+ * @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)
+    {
+        /*
+         * 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));
+        }
+    }
+
+    NOREF(cVariables);
     return rc;
 }
 
-
-/**
- * @interface_method_impl(PDMINVRAM,pfnStoreNvramValue)
- */
-DECLCALLBACK(int) drvNvram_pfnLoadNvramValue(PPDMINVRAM pInterface,
-                                             int idxVariable,
-                                             RTUUID *pVendorUuid,
-                                             char *pcszVariableName,
-                                             size_t *pcbVariableName,
-                                             uint8_t *pu8Value,
-                                             size_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)
-    {
-        rc = VERR_NOT_FOUND;
-        LogFlowFuncLeaveRC(rc);
-        return rc;
-    }
-
-
-    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))
+/**
+ * @interface_method_impl(PDMINVRAMCONNECTOR,pfnVarQueryByIndex)
+ */
+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)
+{
+    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
+    {
+        pVarNode = CFGMR3GetFirstChild(pThis->pLastVarNode);
+        for (uint32_t i = 0; i < idxVariable && pVarNode; i++)
+            pVarNode = CFGMR3GetNextChild(pVarNode);
+    }
+    if (!pVarNode)
         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);
-    AssertRCReturn(rc, rc);
-
-    pThis->cLoadedVariables++;
-    LogFlowFuncLeaveRC(rc);
-    return rc;
+
+    /* cache it */
+    pThis->pLastVarNode = pVarNode;
+    pThis->idxLastVar   = idxVariable;
+
+    /*
+     * Read the variable node.
+     */
+    int rc = CFGMR3QueryString(pVarNode, "Name", pszName, *pcchName);
+    AssertRCReturn(rc, rc);
+    *pcchName = strlen(pszName);
+
+    char    szUuid[RTUUID_STR_LENGTH];
+    rc = CFGMR3QueryString(pVarNode, "Uuid", szUuid, sizeof(szUuid));
+    AssertRCReturn(rc, rc);
+    rc = RTUuidFromStr(pVendorUuid, szUuid);
+    AssertRCReturn(rc, rc);
+
+    rc = CFGMR3QueryU32(pVarNode, "Attribs", pfAttributes);
+    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);
+
+    return VINF_SUCCESS;
 }
 
@@ -230,5 +305,5 @@
 
     PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
-    PDMIBASE_RETURN_INTERFACE(pszIID, PDMINVRAM, &pThis->INvram);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMINVRAMCONNECTOR, &pThis->INvramConnector);
     return NULL;
 }
@@ -242,4 +317,6 @@
     LogFlow(("%s: iInstance/#d\n", __FUNCTION__, pDrvIns->iInstance));
     PNVRAM pThis = PDMINS_2_DATA(pDrvIns, PNVRAM);
+    if (pThis->pNvram != NULL)
+        pThis->pNvram->mpDrv = NULL;
 }
 
@@ -253,4 +330,23 @@
     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"))
@@ -260,21 +356,14 @@
                     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);
-
-    pDrvIns->IBase.pfnQueryInterface = Nvram::drvNvram_QueryInterface;
-    pThis->INvram.pfnFlushNvramStorage = drvNvram_pfnFlushNvramStorage;
-    pThis->INvram.pfnStoreNvramValue = drvNvram_pfnStoreNvramValue;
-    pThis->INvram.pfnLoadNvramValue = drvNvram_pfnLoadNvramValue;
+
+    rc = CFGMR3QueryBoolDef(pCfg, "PermanentSave", &pThis->fPermanentSave, false);
+    AssertRCReturn(rc, rc);
+
+    /*
+     * Let the associated class instance know about us.
+     */
+    pThis->pNvram->mpDrv = pThis;
 
     return VINF_SUCCESS;
