VirtualBox

Changeset 44591 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Feb 8, 2013 4:48:00 AM (12 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
83669
Message:

DevEFI,Nvram.cpp: Cleaning up. (partly tested)

Location:
trunk/src/VBox
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/EFI/DevEFI.cpp

    r44582 r44591  
    6060*   Structures and Typedefs                                                    *
    6161*******************************************************************************/
    62 typedef struct {
    63         RTLISTNODE List;
    64         int      idxVariable;
    65         RTUUID   uuid;
    66         char     szVariableName[EFI_VARIABLE_NAME_MAX];
    67         uint32_t cbVariableName;
    68         uint8_t  au8Value[EFI_VARIABLE_VALUE_MAX];
    69         uint32_t cbValue;
    70         uint32_t u32Attribute;
    71 } EFIVAR, *PEFIVAR;
    72 
     62/**
     63 * EFI NVRAM variable.
     64 */
     65typedef struct EFIVAR
     66{
     67    /** The list node for the variable. */
     68    RTLISTNODE      ListNode;
     69    /** The unique sequence number of the variable.
     70     * This is used to find pCurVar when restoring saved state and therefore only
     71     * set when saving. */
     72    uint32_t        idUniqueSavedState;
     73    /** The value attributess. */
     74    uint32_t        fAttributes;
     75    /** The variable name length (not counting the terminator char). */
     76    uint32_t        cchName;
     77    /** The size of the value. This cannot be zero. */
     78    uint32_t        cbValue;
     79    /** The vendor UUID scoping the variable name. */
     80    RTUUID          uuid;
     81    /** The variable name. */
     82    char            szName[EFI_VARIABLE_NAME_MAX];
     83    /** The variable value bytes.  */
     84    uint8_t         abValue[EFI_VARIABLE_VALUE_MAX];
     85} EFIVAR;
     86/** Pointer to an EFI NVRAM variable. */
     87typedef EFIVAR *PEFIVAR;
     88/** Pointer to an EFI NVRAM variable pointer. */
    7389typedef PEFIVAR *PPEFIVAR;
    7490
    75 typedef struct {
     91/**
     92 * NVRAM state.
     93 */
     94typedef struct NVRAMDESC
     95{
     96    /** The current operation. */
    7697    EFIVAROP        enmOp;
     98    /** The current status. */
    7799    uint32_t        u32Status;
    78     uint32_t        idxOpBuffer;
    79     EFIVAR          OperationVarOp;
    80     int             cNvramVariables;
    81     int             iNvramLastIndex;
    82     EFIVAR          NvramVariableList;
    83     int             idxCurrentVar;
    84     PEFIVAR         pCurrentVarOp;
     100    /** The current  */
     101    uint32_t        offOpBuffer;
     102    /** The current number of variables. */
     103    uint32_t        cVariables;
     104    /** The list of variables. */
     105    RTLISTANCHOR    VarList;
     106
     107    /** The unique variable sequence ID, for the saved state only.
     108     * @todo It's part of this structure for hysterical raisins, consider remove it
     109     *       when changing the saved state format the next time. */
     110    uint32_t        idUniqueCurVar;
     111    /** Variable buffered used both when adding and querying NVRAM variables.
     112     * When querying a variable, a copy of it is stored in this buffer and read
     113     * from it.  When adding, updating or deleting a variable, this buffer is used
     114     * to set up the parameters before taking action. */
     115    EFIVAR          VarOpBuf;
     116    /** The current variable. This is only used by EFI_VARIABLE_OP_QUERY_NEXT,
     117     * the attribute readers work against the copy in VarOpBuf. */
     118    PEFIVAR         pCurVar;
    85119} NVRAMDESC;
    86120
     121
     122/**
     123 * The EFI device state structure.
     124 */
    87125typedef struct DEVEFI
    88126{
    89127    /** Pointer back to the device instance. */
    90     PPDMDEVINS      pDevIns;
     128    PPDMDEVINS              pDevIns;
    91129    /** EFI message buffer. */
    92     char            szMsg[VBOX_EFI_DEBUG_BUFFER];
     130    char                    szMsg[VBOX_EFI_DEBUG_BUFFER];
    93131    /** EFI message buffer index. */
    94     uint32_t        iMsg;
     132    uint32_t                iMsg;
    95133    /** EFI panic message buffer. */
    96     char            szPanicMsg[2048];
     134    char                    szPanicMsg[2048];
    97135    /** EFI panic message buffer index. */
    98     uint32_t        iPanicMsg;
     136    uint32_t                iPanicMsg;
    99137    /** The system EFI ROM data. */
    100     uint8_t        *pu8EfiRom;
     138    uint8_t                *pu8EfiRom;
    101139    /** The size of the system EFI ROM. */
    102     uint64_t        cbEfiRom;
     140    uint64_t                cbEfiRom;
    103141    /** The name of the EFI ROM file. */
    104     char           *pszEfiRomFile;
     142    char                   *pszEfiRomFile;
    105143    /** Thunk page pointer. */
    106     uint8_t        *pu8EfiThunk;
     144    uint8_t                *pu8EfiThunk;
    107145    /** First entry point of the EFI firmware. */
    108     RTGCPHYS        GCEntryPoint0;
     146    RTGCPHYS                GCEntryPoint0;
    109147    /** Second Entry Point (PeiCore)*/
    110     RTGCPHYS        GCEntryPoint1;
     148    RTGCPHYS                GCEntryPoint1;
    111149    /** EFI firmware physical load address. */
    112     RTGCPHYS        GCLoadAddress;
     150    RTGCPHYS                GCLoadAddress;
    113151    /** Current info selector. */
    114     uint32_t        iInfoSelector;
     152    uint32_t                iInfoSelector;
    115153    /** Current info position. */
    116     int32_t         offInfo;
     154    int32_t                 offInfo;
    117155
    118156    /** Number of virtual CPUs. (Config) */
    119     uint32_t        cCpus;
     157    uint32_t                cCpus;
    120158    /** RAM below 4GB (in bytes). (Config) */
    121     uint32_t        cbBelow4GB;
     159    uint32_t                cbBelow4GB;
    122160    /** RAM above 4GB (in bytes). (Config) */
    123     uint64_t        cbAbove4GB;
     161    uint64_t                cbAbove4GB;
    124162    /** The total amount of memory. */
    125     uint64_t        cbRam;
     163    uint64_t                cbRam;
    126164    /** The size of the RAM hole below 4GB. */
    127     uint64_t        cbRamHole;
     165    uint64_t                cbRamHole;
    128166
    129167    /** The size of the DMI tables. */
    130     uint16_t        cbDmiTables;
     168    uint16_t                cbDmiTables;
    131169    /** The DMI tables. */
    132     uint8_t         au8DMIPage[0x1000];
     170    uint8_t                 au8DMIPage[0x1000];
    133171
    134172    /** I/O-APIC enabled? */
    135     uint8_t         u8IOAPIC;
     173    uint8_t                 u8IOAPIC;
    136174
    137175    /** Boot parameters passed to the firmware. */
    138     char            szBootArgs[256];
     176    char                    szBootArgs[256];
    139177
    140178    /** Host UUID (for DMI). */
    141     RTUUID          aUuid;
     179    RTUUID                  aUuid;
    142180
    143181    /** Device properties buffer. */
     
    155193    uint32_t                u32GopMode;
    156194    /** Uga mode horisontal resolution. */
    157     uint32_t        cxUgaResolution;
     195    uint32_t                cxUgaResolution;
    158196    /** Uga mode vertical resolution. */
    159     uint32_t        cyUgaResolution;
    160 
    161     NVRAMDESC       NVRAM;
     197    uint32_t                cyUgaResolution;
     198
     199
     200    /** NVRAM state variables. */
     201    NVRAMDESC               NVRAM;
     202
     203    /**
     204     * NVRAM port - LUN\#0.
     205     */
    162206    struct
    163207    {
    164         PPDMIBASE    pDrvBase;
    165         PDMIBASE     IBase;
    166         PPDMINVRAM   pNvramDown;
     208        /** The base interface we provide the NVRAM driver. */
     209        PDMIBASE            IBase;
     210        /** The NVRAM driver base interface. */
     211        PPDMIBASE           pDrvBase;
     212        /** The NVRAM interface provided by the driver. */
     213        PPDMINVRAMCONNECTOR pNvramDrv;
    167214    } Lun0;
    168215} DEVEFI;
     
    174221*******************************************************************************/
    175222/** The saved state version. */
    176 #define EFI_SSM_VERSION 1
     223#define EFI_SSM_VERSION 2
     224/** The saved state version from VBox 4.2. */
     225#define EFI_SSM_VERSION_4_2 1
    177226
    178227
     
    183232static SSMFIELD const g_aEfiNvramDescField[] =
    184233{
    185         SSMFIELD_ENTRY          (NVRAMDESC, enmOp),
    186         SSMFIELD_ENTRY          (NVRAMDESC, u32Status),
    187         SSMFIELD_ENTRY          (NVRAMDESC, idxOpBuffer),
    188         SSMFIELD_ENTRY_IGNORE   (NVRAMDESC, OperationVarOp),
    189         SSMFIELD_ENTRY          (NVRAMDESC, cNvramVariables),
    190         SSMFIELD_ENTRY          (NVRAMDESC, iNvramLastIndex),
    191         SSMFIELD_ENTRY_IGNORE   (NVRAMDESC, NvramVariableList),
    192         SSMFIELD_ENTRY          (NVRAMDESC, idxCurrentVar),
    193         SSMFIELD_ENTRY_IGNORE   (NVRAMDESC, pCurrentVarOp),
     234        SSMFIELD_ENTRY(       NVRAMDESC, enmOp),
     235        SSMFIELD_ENTRY(       NVRAMDESC, u32Status),
     236        SSMFIELD_ENTRY(       NVRAMDESC, offOpBuffer),
     237        SSMFIELD_ENTRY_IGNORE(NVRAMDESC, VarOpBuf),
     238        SSMFIELD_ENTRY(       NVRAMDESC, cVariables),
     239        SSMFIELD_ENTRY_OLD(   idUnquireLast, 4),
     240        SSMFIELD_ENTRY_IGNORE(NVRAMDESC, VarList),
     241        SSMFIELD_ENTRY(       NVRAMDESC, idUniqueCurVar),
     242        SSMFIELD_ENTRY_IGNORE(NVRAMDESC, pCurVar),
    194243        SSMFIELD_ENTRY_TERM()
    195244};
     
    198247static SSMFIELD const g_aEfiVariableDescFields[] =
    199248{
    200         SSMFIELD_ENTRY_IGNORE   (EFIVAR, List),
    201         SSMFIELD_ENTRY          (EFIVAR, idxVariable),
    202         SSMFIELD_ENTRY          (EFIVAR, uuid),
    203         SSMFIELD_ENTRY          (EFIVAR, szVariableName),
    204         SSMFIELD_ENTRY          (EFIVAR, cbVariableName),
    205         SSMFIELD_ENTRY          (EFIVAR, au8Value),
    206         SSMFIELD_ENTRY          (EFIVAR, cbValue),
    207         SSMFIELD_ENTRY          (EFIVAR, u32Attribute),
     249        SSMFIELD_ENTRY_IGNORE(EFIVAR, ListNode),
     250        SSMFIELD_ENTRY(       EFIVAR, idUniqueSavedState),
     251        SSMFIELD_ENTRY(       EFIVAR, uuid),
     252        SSMFIELD_ENTRY(       EFIVAR, szName),
     253        SSMFIELD_ENTRY_OLD(   cchName, 4),
     254        SSMFIELD_ENTRY(       EFIVAR, abValue),
     255        SSMFIELD_ENTRY(       EFIVAR, cbValue),
     256        SSMFIELD_ENTRY(       EFIVAR, fAttributes),
    208257        SSMFIELD_ENTRY_TERM()
    209258};
     
    211260
    212261
    213 /**
    214  * Write to CMOS memory.
    215  * This is used by the init complete code.
    216  */
    217 static void cmosWrite(PPDMDEVINS pDevIns, int off, uint32_t u32Val)
    218 {
    219     Assert(off < 128);
    220     Assert(u32Val < 256);
    221 
    222     int rc = PDMDevHlpCMOSWrite(pDevIns, off, u32Val);
    223     AssertRC(rc);
    224 }
    225 
    226 DECLINLINE(void) nvramFlushDeviceVariableList(PDEVEFI pThis)
    227 {
    228     PEFIVAR pEfiVar = NULL;
    229     while (!RTListIsEmpty(&pThis->NVRAM.NvramVariableList.List))
    230     {
    231         pEfiVar = RTListNodeGetNext(&pThis->NVRAM.NvramVariableList.List, EFIVAR, List);
    232         RTListNodeRemove(&pEfiVar->List);
     262
     263/**
     264 * Flushes the variable list.
     265 *
     266 * @param   pThis               The EFI state.
     267 */
     268static void nvramFlushDeviceVariableList(PDEVEFI pThis)
     269{
     270    while (!RTListIsEmpty(&pThis->NVRAM.VarList))
     271    {
     272        PEFIVAR pEfiVar = RTListNodeGetNext(&pThis->NVRAM.VarList, EFIVAR, ListNode);
     273        RTListNodeRemove(&pEfiVar->ListNode);
    233274        RTMemFree(pEfiVar);
    234275    }
    235 }
    236 
    237 /**
    238  * This function looks up variable in NVRAM list
     276
     277    pThis->NVRAM.pCurVar = NULL;
     278}
     279
     280/**
     281 * This function looks up variable in NVRAM list.
    239282 */
    240283static int nvramLookupVariableByUuidAndName(PDEVEFI pThis, char *pszVariableName, PCRTUUID pUuid, PPEFIVAR ppEfiVar)
    241284{
    242     int rc = VERR_NOT_FOUND;
    243     PEFIVAR pEfiVar = NULL;
    244     LogFlowFunc(("pszVariableName:%s, pUuid:%RTuuid\n", pszVariableName, pUuid));
    245     int idxVar = 0;
    246     RTListForEach((PRTLISTNODE)&pThis->NVRAM.NvramVariableList.List, pEfiVar, EFIVAR, List)
     285    LogFlowFunc(("%RTuuid::'%s'\n", pUuid, pszVariableName));
     286
     287    int      rc         = VERR_NOT_FOUND;
     288    uint32_t cVariables = 0;
     289    PEFIVAR  pEfiVar;
     290    RTListForEach(&pThis->NVRAM.VarList, pEfiVar, EFIVAR, ListNode)
    247291    {
    248292        LogFlowFunc(("pEfiVar:%p\n", pEfiVar));
    249         idxVar++;
     293        cVariables++;
    250294        if (   pEfiVar
    251295            && RTUuidCompare(pUuid, &pEfiVar->uuid) == 0
    252             && RTStrCmp(pszVariableName, pEfiVar->szVariableName) == 0)
     296            && RTStrCmp(pszVariableName, pEfiVar->szName) == 0) /** @todo case sensitive or insensitive? */
    253297        {
    254298            *ppEfiVar = pEfiVar;
     
    257301        }
    258302    }
    259     Assert(pThis->NVRAM.cNvramVariables >= idxVar);
    260     LogFlowFuncLeaveRC(rc);
     303    Assert(pThis->NVRAM.cVariables >= cVariables);
     304
     305    LogFlowFunc(("rc=%Rrc pEfiVar=%p\n", rc, *ppEfiVar));
    261306    return rc;
    262307}
    263308
     309/**
     310 * Creates an device internal list of variables.
     311 *
     312 * @returns VBox status code.
     313 * @param   pThis           The EFI state.
     314 */
    264315static int nvramLoad(PDEVEFI pThis)
    265316{
    266     int rc = VINF_SUCCESS;
    267     PEFIVAR pEfiVar = NULL;
    268     int idxValue = 0;
    269     while(idxValue < 100)
    270     {
    271         pEfiVar = (PEFIVAR)RTMemAllocZ(sizeof(EFIVAR));
    272         if (!pEfiVar)
     317    int rc;
     318    for (uint32_t iVar = 0; iVar < EFI_VARIABLE_MAX; iVar++)
     319    {
     320        PEFIVAR pEfiVar = (PEFIVAR)RTMemAllocZ(sizeof(EFIVAR));
     321        AssertReturn(pEfiVar, VERR_NO_MEMORY);
     322
     323        pEfiVar->cchName = sizeof(pEfiVar->szName);
     324        pEfiVar->cbValue = sizeof(pEfiVar->abValue);
     325        rc = pThis->Lun0.pNvramDrv->pfnVarQueryByIndex(pThis->Lun0.pNvramDrv, iVar,
     326                                                       &pEfiVar->uuid, &pEfiVar->szName[0], &pEfiVar->cchName,
     327                                                       &pEfiVar->fAttributes, &pEfiVar->abValue[0], &pEfiVar->cbValue);
     328        if (RT_SUCCESS(rc))
    273329        {
    274             LogRel(("EFI: Can't allocate space for stored EFI variable\n"));
    275             return VERR_NO_MEMORY;
     330            /* Some validations. */
     331            rc = RTStrValidateEncoding(pEfiVar->szName);
     332            size_t cchName = RTStrNLen(pEfiVar->szName, sizeof(pEfiVar->szName));
     333            if (cchName != pEfiVar->cchName)
     334                rc = VERR_INVALID_PARAMETER;
     335            if (pEfiVar->cbValue == 0)
     336                rc = VERR_NO_DATA;
     337            if (RT_FAILURE(rc))
     338                LogRel(("EFI/nvramLoad: Bad variable #%u: cbValue=%#x cchName=%#x (strlen=%#x) szName=%.*Rhxs\n",
     339                        pEfiVar->cbValue, pEfiVar->cchName, cchName, pEfiVar->cchName + 1, pEfiVar->szName));
    276340        }
    277         pEfiVar->cbVariableName = EFI_VARIABLE_NAME_MAX;
    278         pEfiVar->cbValue = EFI_VARIABLE_VALUE_MAX;
    279         rc = pThis->Lun0.pNvramDown->pfnLoadNvramValue(pThis->Lun0.pNvramDown,
    280                                                        idxValue,
    281                                                        &pEfiVar->uuid,
    282                                                        pEfiVar->szVariableName,
    283                                                        (size_t *)&pEfiVar->cbVariableName,
    284                                                        pEfiVar->au8Value,
    285                                                        (size_t *)&pEfiVar->cbValue);
    286         idxValue++;
    287341        if (RT_FAILURE(rc))
    288342        {
    289343            RTMemFree(pEfiVar);
    290             break;
     344            if (rc == VERR_NOT_FOUND)
     345                rc = VINF_SUCCESS;
     346            AssertRC(rc);
     347            return rc;
    291348        }
    292         pThis->NVRAM.cNvramVariables++;
    293         RTListAppend((PRTLISTNODE)&pThis->NVRAM.NvramVariableList.List, &pEfiVar->List);
    294     }
    295     if (   RT_FAILURE(rc)
    296         && rc == VERR_NOT_FOUND)
    297         rc  = VINF_SUCCESS;
    298     AssertRCReturn(rc, rc);
     349
     350        /* Append it. */
     351        RTListAppend((PRTLISTNODE)&pThis->NVRAM.VarList, &pEfiVar->ListNode);
     352        pThis->NVRAM.cVariables++;
     353    }
     354
     355    AssertLogRelMsgFailed(("EFI: Too many variables.\n"));
     356    return VERR_TOO_MUCH_DATA;
     357}
     358
     359
     360/**
     361 * Let the NVRAM driver store the internal NVRAM variable list.
     362 *
     363 * @returns VBox status code.
     364 * @param   pThis               The EFI state.
     365 */
     366static int nvramStore(PDEVEFI pThis)
     367{
     368    int rc = pThis->Lun0.pNvramDrv->pfnVarStoreSeqBegin(pThis->Lun0.pNvramDrv, pThis->NVRAM.cVariables);
     369    if (RT_SUCCESS(rc))
     370    {
     371        uint32_t    idxVar  = 0;
     372        PEFIVAR     pEfiVar;
     373        RTListForEach(&pThis->NVRAM.VarList, pEfiVar, EFIVAR, ListNode)
     374        {
     375            int rc2 = pThis->Lun0.pNvramDrv->pfnVarStoreSeqPut(pThis->Lun0.pNvramDrv, idxVar,
     376                                                               &pEfiVar->uuid, pEfiVar->szName,  pEfiVar->cchName,
     377                                                               pEfiVar->fAttributes, pEfiVar->abValue, pEfiVar->cbValue);
     378            if (RT_FAILURE(rc2) && RT_SUCCESS_NP(rc))
     379            {
     380                LogRel(("EFI: pfnVarStoreVarByIndex failed: %Rrc\n", rc));
     381                rc = rc2;
     382            }
     383            idxVar++;
     384        }
     385        Assert((pThis->NVRAM.cVariables == idxVar));
     386        rc = pThis->Lun0.pNvramDrv->pfnVarStoreSeqEnd(pThis->Lun0.pNvramDrv, rc);
     387    }
     388    else
     389        LogRel(("EFI: pfnVarStoreBegin failed: %Rrc\n", rc));
    299390    return rc;
    300391}
    301392
    302 static int nvramStore(PDEVEFI pThis)
     393/**
     394 * EFI_VARIABLE_OP_QUERY and EFI_VARIABLE_OP_QUERY_NEXT worker that copies the
     395 * variable into the VarOpBuf, set pCurVar and u32Status.
     396 *
     397 * @param   pThis               The EFI state.
     398 * @param   pEfiVar             The resulting variable. NULL if not found / end.
     399 */
     400static void nvramWriteVariableOpQueryCopyResult(PDEVEFI pThis, PEFIVAR pEfiVar)
     401{
     402    RT_ZERO(pThis->NVRAM.VarOpBuf.szName);
     403    RT_ZERO(pThis->NVRAM.VarOpBuf.abValue);
     404    if (pEfiVar)
     405    {
     406        pThis->NVRAM.VarOpBuf.uuid        = pEfiVar->uuid;
     407        pThis->NVRAM.VarOpBuf.cchName     = pEfiVar->cchName;
     408        memcpy(pThis->NVRAM.VarOpBuf.szName, pEfiVar->szName, pEfiVar->cchName); /* no need for + 1. */
     409        pThis->NVRAM.VarOpBuf.fAttributes = pEfiVar->fAttributes;
     410        pThis->NVRAM.VarOpBuf.cbValue     = pEfiVar->cbValue;
     411        memcpy(pThis->NVRAM.VarOpBuf.abValue, pEfiVar->abValue, pEfiVar->cbValue);
     412        pThis->NVRAM.pCurVar              = pEfiVar;
     413        pThis->NVRAM.u32Status            = EFI_VARIABLE_OP_STATUS_OK;
     414        LogFlow(("EFI: Variable query -> %RTuuid::'%s' abValue=%.*Rhxs\n", &pThis->NVRAM.VarOpBuf.uuid,
     415                 pThis->NVRAM.VarOpBuf.szName, pThis->NVRAM.VarOpBuf.cbValue, pThis->NVRAM.VarOpBuf.abValue));
     416    }
     417    else
     418    {
     419        pThis->NVRAM.VarOpBuf.fAttributes = 0;
     420        pThis->NVRAM.VarOpBuf.cbValue     = 0;
     421        pThis->NVRAM.VarOpBuf.cchName     = 0;
     422        pThis->NVRAM.pCurVar              = NULL;
     423        pThis->NVRAM.u32Status            = EFI_VARIABLE_OP_STATUS_NOT_FOUND;
     424        LogFlow(("EFI: Variable query -> NOT_FOUND\n"));
     425    }
     426}
     427
     428/**
     429 * Implements EFI_VARIABLE_PARAM + EFI_VARIABLE_OP_QUERY.
     430 *
     431 * @returns IOM strict status code.
     432 * @param   pThis               The EFI state.
     433 */
     434static int nvramWriteVariableOpQuery(PDEVEFI pThis)
     435{
     436    LogRel(("EFI: Querying Variable %RTuuid::'%s'\n",
     437            &pThis->NVRAM.VarOpBuf.uuid, pThis->NVRAM.VarOpBuf.szName));
     438
     439    PEFIVAR pEfiVar;
     440    int rc = nvramLookupVariableByUuidAndName(pThis,
     441                                              pThis->NVRAM.VarOpBuf.szName,
     442                                              &pThis->NVRAM.VarOpBuf.uuid,
     443                                              &pEfiVar);
     444    nvramWriteVariableOpQueryCopyResult(pThis, RT_SUCCESS(rc) ? pEfiVar : NULL);
     445    return VINF_SUCCESS;
     446}
     447
     448/**
     449 * Implements EFI_VARIABLE_PARAM + EFI_VARIABLE_OP_QUERY_NEXT.
     450 *
     451 * This simply walks the list.
     452 *
     453 * @returns IOM strict status code.
     454 * @param   pThis               The EFI state.
     455 */
     456static int nvramWriteVariableOpQueryNext(PDEVEFI pThis)
     457{
     458    Log(("EFI: Querying next variable...\n"));
     459    PEFIVAR pEfiVar = pThis->NVRAM.pCurVar;
     460    if (pEfiVar)
     461        pEfiVar = RTListGetNext(&pThis->NVRAM.VarList, pEfiVar, EFIVAR, ListNode);
     462    nvramWriteVariableOpQueryCopyResult(pThis, pEfiVar);
     463    return VINF_SUCCESS;
     464}
     465
     466/**
     467 * Implements EFI_VARIABLE_PARAM + EFI_VARIABLE_OP_ADD.
     468 *
     469 * @returns IOM strict status code.
     470 * @param   pThis               The EFI state.
     471 */
     472static int nvramWriteVariableOpAdd(PDEVEFI pThis)
     473{
     474    LogRel(("EFI: Adding variable %RTuuid::'%s'\n", &pThis->NVRAM.VarOpBuf.uuid, pThis->NVRAM.VarOpBuf.szName));
     475    LogFlowFunc(("fAttributes=%#x abValue=%.*Rhxs\n", pThis->NVRAM.VarOpBuf.fAttributes,
     476                 pThis->NVRAM.VarOpBuf.cbValue, pThis->NVRAM.VarOpBuf.abValue));
     477
     478    /*
     479     * Validate the input a little.
     480     */
     481    int rc = RTStrValidateEncoding(pThis->NVRAM.VarOpBuf.szName);
     482    if (RT_FAILURE(rc))
     483        LogRel(("EFI: Badly encoded variable name: %.*Rhxs\n", pThis->NVRAM.VarOpBuf.cchName + 1, pThis->NVRAM.VarOpBuf.szName));
     484    size_t cchName = RTStrNLen(pThis->NVRAM.VarOpBuf.szName, sizeof(pThis->NVRAM.VarOpBuf.szName));
     485    if (cchName != pThis->NVRAM.VarOpBuf.cchName)
     486    {
     487        LogRel(("EFI: Bad name length %#x, expected %#x: %.*Rhxs\n",
     488                cchName, pThis->NVRAM.VarOpBuf.cchName, pThis->NVRAM.VarOpBuf.cchName + 1, pThis->NVRAM.VarOpBuf.szName));
     489        rc = VERR_INVALID_PARAMETER;
     490    }
     491    if (RT_FAILURE(rc))
     492    {
     493        pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
     494        return VINF_SUCCESS;
     495    }
     496
     497    /*
     498     * Look it up and see what to do.
     499     */
     500    PEFIVAR pEfiVar;
     501    rc = nvramLookupVariableByUuidAndName(pThis,
     502                                          pThis->NVRAM.VarOpBuf.szName,
     503                                          &pThis->NVRAM.VarOpBuf.uuid,
     504                                          &pEfiVar);
     505    if (RT_SUCCESS(rc))
     506    {
     507        LogFlowFunc(("Old abValue=%.*Rhxs\n", pEfiVar->cbValue, pEfiVar->abValue));
     508#if 0 /** @todo Implement read-only EFI variables. */
     509        if (pEfiVar->fAttributes & EFI_VARIABLE_XXXXXXX)
     510        {
     511            pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_RO;
     512            break;
     513        }
     514#endif
     515
     516        if (pThis->NVRAM.VarOpBuf.cbValue == 0)
     517        {
     518            /*
     519             * Delete it.
     520             */
     521            LogFlow(("nvramWriteVariableOpAdd: Delete\n"));
     522            RTListNodeRemove(&pEfiVar->ListNode);
     523            pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
     524            pThis->NVRAM.cVariables--;
     525
     526            if (pThis->NVRAM.pCurVar == pEfiVar)
     527                pThis->NVRAM.pCurVar = NULL;
     528            RTMemFree(pEfiVar);
     529            pEfiVar = NULL;
     530        }
     531        else
     532        {
     533            /*
     534             * Update/replace it. (The name and UUID are unchanged, of course.)
     535             */
     536            LogFlow(("nvramWriteVariableOpAdd: Replace\n"));
     537            pEfiVar->fAttributes   = pThis->NVRAM.VarOpBuf.fAttributes;
     538            pEfiVar->cbValue       = pThis->NVRAM.VarOpBuf.cbValue;
     539            memcpy(pEfiVar->abValue, pThis->NVRAM.VarOpBuf.abValue, pEfiVar->cbValue);
     540            pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
     541        }
     542    }
     543    else if (pThis->NVRAM.VarOpBuf.cbValue == 0)
     544    {
     545        /* delete operation, but nothing to delete. */
     546        LogFlow(("nvramWriteVariableOpAdd: Delete (not found)\n"));
     547        pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
     548    }
     549    else if (pThis->NVRAM.cVariables < EFI_VARIABLE_MAX)
     550    {
     551        /*
     552         * Add a new variable.
     553         */
     554        LogFlow(("nvramWriteVariableOpAdd: New\n"));
     555        pEfiVar = (PEFIVAR)RTMemAllocZ(sizeof(EFIVAR));
     556        if (pEfiVar)
     557        {
     558            pEfiVar->uuid          = pThis->NVRAM.VarOpBuf.uuid;
     559            pEfiVar->cchName       = pThis->NVRAM.VarOpBuf.cchName;
     560            memcpy(pEfiVar->szName, pThis->NVRAM.VarOpBuf.szName, pEfiVar->cchName); /* The buffer is zeroed, so skip '\0'. */
     561            pEfiVar->fAttributes   = pThis->NVRAM.VarOpBuf.fAttributes;
     562            pEfiVar->cbValue       = pThis->NVRAM.VarOpBuf.cbValue;
     563            memcpy(pEfiVar->abValue, pThis->NVRAM.VarOpBuf.abValue, pEfiVar->cbValue);
     564
     565            RTListAppend(&pThis->NVRAM.VarList, &pEfiVar->ListNode);
     566            pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
     567            pThis->NVRAM.cVariables++;
     568        }
     569        else
     570            pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
     571    }
     572    else
     573    {
     574        /*
     575         * Too many variables.
     576         */
     577        static unsigned s_cWarnings = 0;
     578        if (s_cWarnings++ < 5)
     579            LogRel(("EFI: Too many variables.\n"));
     580        pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
     581        Log(("nvramWriteVariableOpAdd: Too many variabled.\n"));
     582    }
     583
     584    LogFunc(("cVariables=%u u32Status=%#x\n", pThis->NVRAM.cVariables, pThis->NVRAM.u32Status));
     585    return VINF_SUCCESS;
     586}
     587
     588/**
     589 * Implements EFI_VARIABLE_PARAM writes.
     590 *
     591 * @returns IOM strict status code.
     592 * @param   pThis               The EFI state.
     593 * @param   u32Value            The value being written.
     594 */
     595static int nvramWriteVariableParam(PDEVEFI pThis, uint32_t u32Value)
    303596{
    304597    int rc = VINF_SUCCESS;
    305     PEFIVAR pEfiVar = NULL;
    306     int idxVar = 0;
    307     pThis->Lun0.pNvramDown->pfnFlushNvramStorage(pThis->Lun0.pNvramDown);
    308 
    309     RTListForEach((PRTLISTNODE)&pThis->NVRAM.NvramVariableList.List, pEfiVar, EFIVAR, List)
    310     {
    311         pThis->Lun0.pNvramDown->pfnStoreNvramValue(pThis->Lun0.pNvramDown,
    312                                                    idxVar,
    313                                                    &pEfiVar->uuid,
    314                                                    pEfiVar->szVariableName,
    315                                                    pEfiVar->cbVariableName,
    316                                                    pEfiVar->au8Value,
    317                                                    pEfiVar->cbValue);
    318         idxVar++;
    319     }
    320     Assert((pThis->NVRAM.cNvramVariables == idxVar));
     598    switch (pThis->NVRAM.enmOp)
     599    {
     600        case EFI_VM_VARIABLE_OP_START:
     601            switch (u32Value)
     602            {
     603                case EFI_VARIABLE_OP_QUERY:
     604                    rc = nvramWriteVariableOpQuery(pThis);
     605                    break;
     606
     607                case EFI_VARIABLE_OP_QUERY_NEXT:
     608                    rc = nvramWriteVariableOpQueryNext(pThis);
     609                    break;
     610
     611                case EFI_VARIABLE_OP_ADD:
     612                    rc = nvramWriteVariableOpAdd(pThis);
     613                    break;
     614
     615                default:
     616                    pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
     617                    LogRel(("EFI: Unknown  EFI_VM_VARIABLE_OP_START value %#x\n", u32Value));
     618                    break;
     619            }
     620            break;
     621
     622        case EFI_VM_VARIABLE_OP_GUID:
     623            Log2(("EFI_VM_VARIABLE_OP_GUID[%#x]=%#x\n", pThis->NVRAM.offOpBuffer, u32Value));
     624            if (pThis->NVRAM.offOpBuffer < sizeof(pThis->NVRAM.VarOpBuf.uuid))
     625                pThis->NVRAM.VarOpBuf.uuid.au8[pThis->NVRAM.offOpBuffer++] = (uint8_t)u32Value;
     626            else
     627            {
     628                LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_GUID write (%#x).\n", u32Value));
     629                pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
     630            }
     631            break;
     632
     633        case EFI_VM_VARIABLE_OP_ATTRIBUTE:
     634            Log2(("EFI_VM_VARIABLE_OP_ATTRIBUTE=%#x\n", u32Value));
     635            pThis->NVRAM.VarOpBuf.fAttributes = u32Value;
     636            break;
     637
     638        case EFI_VM_VARIABLE_OP_NAME:
     639            Log2(("EFI_VM_VARIABLE_OP_NAME[%#x]=%#x\n", pThis->NVRAM.offOpBuffer, u32Value));
     640            if (pThis->NVRAM.offOpBuffer < pThis->NVRAM.VarOpBuf.cchName)
     641                pThis->NVRAM.VarOpBuf.szName[pThis->NVRAM.offOpBuffer++] = (uint8_t)u32Value;
     642            else if (u32Value == 0)
     643                Assert(pThis->NVRAM.VarOpBuf.szName[sizeof(pThis->NVRAM.VarOpBuf.szName) - 1] == 0);
     644            else
     645            {
     646                LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_NAME write (%#x).\n", u32Value));
     647                pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
     648            }
     649            break;
     650
     651        case EFI_VM_VARIABLE_OP_NAME_LENGTH:
     652            Log2(("EFI_VM_VARIABLE_OP_NAME_LENGTH=%#x\n", u32Value));
     653            RT_ZERO(pThis->NVRAM.VarOpBuf.szName);
     654            if (u32Value < sizeof(pThis->NVRAM.VarOpBuf.szName))
     655                pThis->NVRAM.VarOpBuf.cchName = u32Value;
     656            else
     657            {
     658                LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_NAME_LENGTH write (%#x, max %#x).\n",
     659                        u32Value, sizeof(pThis->NVRAM.VarOpBuf.szName) - 1));
     660                pThis->NVRAM.VarOpBuf.cchName = sizeof(pThis->NVRAM.VarOpBuf.szName) - 1;
     661                pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
     662            }
     663            Assert(pThis->NVRAM.offOpBuffer == 0);
     664            break;
     665
     666        case EFI_VM_VARIABLE_OP_NAME_UTF16:
     667        {
     668            Log2(("EFI_VM_VARIABLE_OP_NAME_UTF16[%#x]=%#x\n", pThis->NVRAM.offOpBuffer, u32Value));
     669            /* Currently simplifying this to UCS2, i.e. no surrogates. */
     670            if (pThis->NVRAM.offOpBuffer == 0)
     671                RT_ZERO(pThis->NVRAM.VarOpBuf.szName);
     672            size_t cbUtf8 = RTStrCpSize(u32Value);
     673            if (pThis->NVRAM.offOpBuffer + cbUtf8 < sizeof(pThis->NVRAM.VarOpBuf.szName))
     674            {
     675                RTStrPutCp(&pThis->NVRAM.VarOpBuf.szName[pThis->NVRAM.offOpBuffer], u32Value);
     676                pThis->NVRAM.offOpBuffer += cbUtf8;
     677            }
     678            else if (u32Value == 0)
     679                Assert(pThis->NVRAM.VarOpBuf.szName[sizeof(pThis->NVRAM.VarOpBuf.szName) - 1] == 0);
     680            else
     681            {
     682                LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_NAME_UTF16 write (%#x).\n", u32Value));
     683                pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
     684            }
     685            break;
     686        }
     687
     688        case EFI_VM_VARIABLE_OP_VALUE:
     689            Log2(("EFI_VM_VARIABLE_OP_VALUE[%#x]=%#x\n", pThis->NVRAM.offOpBuffer, u32Value));
     690            if (pThis->NVRAM.offOpBuffer < pThis->NVRAM.VarOpBuf.cbValue)
     691                pThis->NVRAM.VarOpBuf.abValue[pThis->NVRAM.offOpBuffer++] = (uint8_t)u32Value;
     692            else
     693            {
     694                LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_VALUE write (%#x).\n", u32Value));
     695                pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
     696            }
     697            break;
     698
     699        case EFI_VM_VARIABLE_OP_VALUE_LENGTH:
     700            Log2(("EFI_VM_VARIABLE_OP_VALUE_LENGTH=%#x\n", u32Value));
     701            RT_ZERO(pThis->NVRAM.VarOpBuf.abValue);
     702            if (u32Value <= sizeof(pThis->NVRAM.VarOpBuf.abValue))
     703                pThis->NVRAM.VarOpBuf.cbValue = u32Value;
     704            else
     705            {
     706                LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_VALUE_LENGTH write (%#x, max %#x).\n",
     707                        u32Value, sizeof(pThis->NVRAM.VarOpBuf.abValue)));
     708                pThis->NVRAM.VarOpBuf.cbValue = sizeof(pThis->NVRAM.VarOpBuf.abValue);
     709                pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
     710            }
     711            Assert(pThis->NVRAM.offOpBuffer == 0);
     712            break;
     713
     714        default:
     715            pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
     716            LogRel(("EFI: Unexpected variable operation %#x\n", pThis->NVRAM.enmOp));
     717            break;
     718    }
    321719    return VINF_SUCCESS;
    322720}
     721
     722/**
     723 * Implements EFI_VARIABLE_OP reads.
     724 *
     725 * @returns IOM strict status code.
     726 * @param   pThis               The EFI state.
     727 * @param   u32Value            The value being written.
     728 */
     729static int nvramReadVariableOp(PDEVEFI pThis,  uint32_t *pu32, unsigned cb)
     730{
     731    switch (pThis->NVRAM.enmOp)
     732    {
     733        case EFI_VM_VARIABLE_OP_START:
     734            *pu32 = pThis->NVRAM.u32Status;
     735            break;
     736
     737        case EFI_VM_VARIABLE_OP_GUID:
     738            if (pThis->NVRAM.offOpBuffer < sizeof(pThis->NVRAM.VarOpBuf.uuid) && cb == 1)
     739                *pu32 = pThis->NVRAM.VarOpBuf.uuid.au8[pThis->NVRAM.offOpBuffer++];
     740            else
     741            {
     742                if (cb == 1)
     743                    LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_GUID read.\n"));
     744                else
     745                    LogRel(("EFI: Invalid EFI_VM_VARIABLE_OP_GUID read size (%d).\n", cb));
     746                *pu32 = UINT32_MAX;
     747            }
     748            break;
     749
     750        case EFI_VM_VARIABLE_OP_ATTRIBUTE:
     751            *pu32 = pThis->NVRAM.VarOpBuf.fAttributes;
     752            break;
     753
     754        case EFI_VM_VARIABLE_OP_NAME:
     755            /* allow reading terminator char */
     756            if (pThis->NVRAM.offOpBuffer <= pThis->NVRAM.VarOpBuf.cchName && cb == 1)
     757                *pu32 = pThis->NVRAM.VarOpBuf.szName[pThis->NVRAM.offOpBuffer++];
     758            else
     759            {
     760                if (cb == 1)
     761                    LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_NAME read.\n"));
     762                else
     763                    LogRel(("EFI: Invalid EFI_VM_VARIABLE_OP_NAME read size (%d).\n", cb));
     764                *pu32 = UINT32_MAX;
     765            }
     766            break;
     767
     768        case EFI_VM_VARIABLE_OP_NAME_LENGTH:
     769            *pu32 = pThis->NVRAM.VarOpBuf.cchName;
     770            break;
     771
     772        case EFI_VM_VARIABLE_OP_NAME_UTF16:
     773            /* Lazy bird: ASSUME no surrogate pairs. */
     774            if (pThis->NVRAM.offOpBuffer < pThis->NVRAM.VarOpBuf.cchName)
     775            {
     776                char const *psz1 = &pThis->NVRAM.VarOpBuf.szName[pThis->NVRAM.offOpBuffer];
     777                char const *psz2 = psz2;
     778                RTUNICP Cp;
     779                RTStrGetCpEx(&psz2, &Cp);
     780                *pu32 = Cp;
     781                pThis->NVRAM.offOpBuffer += psz2 - psz1;
     782            }
     783            else if (pThis->NVRAM.offOpBuffer == pThis->NVRAM.VarOpBuf.cchName)
     784            {
     785                *pu32 = 0;
     786                pThis->NVRAM.offOpBuffer++;
     787            }
     788            else
     789            {
     790                if (cb == 1)
     791                    LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_NAME_UTF16 read.\n"));
     792                else
     793                    LogRel(("EFI: Invalid EFI_VM_VARIABLE_OP_NAME_UTF16 read size (%d).\n", cb));
     794                *pu32 = UINT32_MAX;
     795            }
     796            break;
     797
     798        case EFI_VM_VARIABLE_OP_NAME_LENGTH_UTF16:
     799            /* Lazy bird: ASSUME no surrogate pairs. */
     800            *pu32 = RTStrUniLen(pThis->NVRAM.VarOpBuf.szName);
     801            break;
     802
     803        case EFI_VM_VARIABLE_OP_VALUE:
     804            if (pThis->NVRAM.offOpBuffer < pThis->NVRAM.VarOpBuf.cbValue && cb == 1)
     805                *pu32 = pThis->NVRAM.VarOpBuf.abValue[pThis->NVRAM.offOpBuffer++];
     806            else
     807            {
     808                if (cb == 1)
     809                    LogRel(("EFI: Out of bounds EFI_VM_VARIABLE_OP_VALUE read.\n"));
     810                else
     811                    LogRel(("EFI: Invalid EFI_VM_VARIABLE_OP_VALUE read size (%d).\n", cb));
     812                *pu32 = UINT32_MAX;
     813            }
     814            break;
     815
     816        case EFI_VM_VARIABLE_OP_VALUE_LENGTH:
     817            *pu32 = pThis->NVRAM.VarOpBuf.cbValue;
     818            break;
     819
     820        default:
     821            *pu32 = UINT32_MAX;
     822            break;
     823    }
     824    return VINF_SUCCESS;
     825}
     826
     827/**
     828 * @implement_callback_method{FNDBGFHANDLERDEV}
     829 */
     830static DECLCALLBACK(void) efiInfoNvram(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
     831{
     832    PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
     833    PDMCritSectEnter(pDevIns->pCritSectRoR3, VERR_IGNORED);
     834
     835    pHlp->pfnPrintf(pHlp, "NVRAM variables: %u\n", pThis->NVRAM.cVariables);
     836    PEFIVAR pEfiVar;
     837    RTListForEach(&pThis->NVRAM.VarList, pEfiVar, EFIVAR, ListNode)
     838    {
     839        pHlp->pfnPrintf(pHlp, "%RTuuid::'%s' = %.*Rhxs (attr=%#x)\n",
     840                        &pEfiVar->uuid, pEfiVar->szName, pEfiVar->cbValue, pEfiVar->abValue, pEfiVar->fAttributes);
     841    }
     842
     843    PDMCritSectLeave(pDevIns->pCritSectRoR3);
     844}
     845
    323846
    324847
     
    436959}
    437960
    438 static DECLCALLBACK(int) efiSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
    439 {
    440     int rc = VINF_SUCCESS;
    441     PEFIVAR pEfiVar = NULL;
    442     LogFlowFuncEnter();
    443     PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
    444     rc = SSMR3PutStructEx(pSSM, &pThis->NVRAM, sizeof(NVRAMDESC), 0, g_aEfiNvramDescField, NULL);
    445     AssertRCReturn(rc, rc);
    446     rc = SSMR3PutStructEx(pSSM, &pThis->NVRAM.OperationVarOp, sizeof(EFIVAR), 0, g_aEfiVariableDescFields, NULL);
    447     AssertRCReturn(rc, rc);
    448     int idxV = 0;
    449     RTListForEach(&pThis->NVRAM.NvramVariableList.List, pEfiVar, EFIVAR, List)
    450     {
    451         rc = SSMR3PutStructEx(pSSM, pEfiVar, sizeof(EFIVAR), 0, g_aEfiVariableDescFields, NULL);
    452         AssertRCReturn(rc, rc);
    453         idxV++;
    454     }
    455     Assert((pThis->NVRAM.cNvramVariables == idxV));
    456     Log2(("idxV: %d\n", idxV));
    457     LogFlowFuncLeaveRC(rc);
    458     return rc;
    459 }
    460 
    461 static DECLCALLBACK(int) efiLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
    462 {
    463     int rc = VINF_SUCCESS;
    464     NOREF(uPass);
    465     LogFlowFunc(("ENTER: uVersion:%d, uPass:%d\n", uVersion, uPass));
    466     PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
    467     if (uPass != SSM_PASS_FINAL)
    468         return rc;
    469     /* we should clean up the loaded values */
    470     nvramFlushDeviceVariableList(pThis);
    471     if (uVersion == 1)
    472     {
    473         rc = SSMR3GetStructEx(pSSM, &pThis->NVRAM, sizeof(NVRAMDESC), 0, g_aEfiNvramDescField, NULL);
    474         AssertRCReturn(rc, rc);
    475         rc = SSMR3GetStructEx(pSSM, &pThis->NVRAM.OperationVarOp, sizeof(EFIVAR), 0, g_aEfiVariableDescFields, NULL);
    476         AssertRCReturn(rc, rc);
    477         int idxVariable = 0;
    478         Assert(RTListIsEmpty(&pThis->NVRAM.NvramVariableList.List));
    479         RTListInit(&pThis->NVRAM.NvramVariableList.List);
    480         for (idxVariable = 0; idxVariable < pThis->NVRAM.cNvramVariables; ++idxVariable)
    481         {
    482             PEFIVAR pEfiVar = (PEFIVAR)RTMemAllocZ(sizeof(EFIVAR));
    483             AssertPtrReturn(pEfiVar, VERR_NO_MEMORY);
    484 
    485             rc = SSMR3GetStructEx(pSSM, pEfiVar, sizeof(EFIVAR), 0, g_aEfiVariableDescFields, NULL);
    486             AssertRCReturn(rc, rc);
    487 
    488             RTListInit(&pEfiVar->List);
    489             RTListAppend(&pThis->NVRAM.NvramVariableList.List, &pEfiVar->List);
    490 
    491             if (pThis->NVRAM.idxCurrentVar == pEfiVar->idxVariable)
    492                 pThis->NVRAM.pCurrentVarOp = pEfiVar;
    493         }
    494     }
    495     LogFlowFuncLeaveRC(rc);
    496     return rc;
    497 }
    498 
    499 #if 0
    500 static DECLCALLBACK(int) efiLoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
    501 {
    502     int rc = VINF_SUCCESS;
    503     PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
    504     LogFlowFuncEnter();
    505     if (RTListIsEmpty(&pThis->NVRAM.NvramVariableList.List))
    506         nvramLoad(pThis);
    507     LogFlowFuncLeaveRC(rc);
    508     return rc;
    509 }
    510 #endif
    511 
    512961/**
    513962 * Port I/O Handler for IN operations.
     
    5551004           return VINF_IOM_R3_IOPORT_READ;
    5561005#endif
     1006
    5571007        case EFI_VARIABLE_OP:
    558             switch (pThis->NVRAM.enmOp)
    559             {
    560                 case EFI_VM_VARIABLE_OP_START:
    561                 /* @todo: nop ? */
    562                     *pu32 = pThis->NVRAM.u32Status;
    563                 break;
    564                 case EFI_VM_VARIABLE_OP_END:
    565                 break;
    566                 case EFI_VM_VARIABLE_OP_INDEX:
    567                 break;
    568                 case EFI_VM_VARIABLE_OP_GUID:
    569                     *pu32 = pThis->NVRAM.OperationVarOp.uuid.au8[pThis->NVRAM.idxOpBuffer];
    570                     pThis->NVRAM.idxOpBuffer++;
    571                 break;
    572                 case EFI_VM_VARIABLE_OP_ATTRIBUTE:
    573                     *pu32 = pThis->NVRAM.OperationVarOp.u32Attribute;
    574                 break;
    575                 case EFI_VM_VARIABLE_OP_NAME:
    576                     *pu32 = pThis->NVRAM.OperationVarOp.szVariableName[pThis->NVRAM.idxOpBuffer];
    577                     pThis->NVRAM.idxOpBuffer++;
    578                 break;
    579                 case EFI_VM_VARIABLE_OP_NAME_LENGTH:
    580                     *pu32 = pThis->NVRAM.OperationVarOp.cbVariableName;
    581                 break;
    582                 case EFI_VM_VARIABLE_OP_VALUE:
    583                     *pu32 = pThis->NVRAM.OperationVarOp.au8Value[pThis->NVRAM.idxOpBuffer];
    584                     pThis->NVRAM.idxOpBuffer++;
    585                 break;
    586                 case EFI_VM_VARIABLE_OP_VALUE_LENGTH:
    587                     *pu32 = pThis->NVRAM.OperationVarOp.cbValue;
    588                 break;
    589                 default:
    590                 break;
    591             }
     1008            return nvramReadVariableOp(pThis, pu32, cb);
     1009
     1010        case EFI_VARIABLE_PARAM:
     1011            *pu32 = UINT32_MAX;
    5921012            return VINF_SUCCESS;
    593         case EFI_VARIABLE_PARAM:
    594         {
    595             break;
    596         }
    597         return VINF_SUCCESS;
    5981013    }
    5991014
     
    6161031{
    6171032    PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
     1033    int     rc    = VINF_SUCCESS;
    6181034    Log4(("efi: out %x %x %d\n", Port, u32, cb));
    6191035
     
    6211037    {
    6221038        case EFI_INFO_PORT:
     1039            Log2(("EFI_INFO_PORT: iInfoSelector=%#x\n", u32));
    6231040            pThis->iInfoSelector = u32;
    6241041            pThis->offInfo       = -1;
    6251042            break;
     1043
    6261044        case EFI_DEBUG_PORT:
    6271045        {
     
    6481066
    6491067                        PRTSTREAM pStrm;
    650                         int rc = RTStrmOpen("./DevEFI.VBoxDbg", "a", &pStrm);
    651                         if (RT_SUCCESS(rc))
     1068                        int rc2 = RTStrmOpen("./DevEFI.VBoxDbg", "a", &pStrm);
     1069                        if (RT_SUCCESS(rc2))
    6521070                        {
    6531071                            RTStrmPutStr(pStrm, pszVBoxDbg);
     
    7251143            break;
    7261144        }
     1145
    7271146        case EFI_VARIABLE_OP:
    7281147        {
    7291148            /* clear buffer index */
    730             Assert(u32 < EFI_VM_VARIABLE_OP_MAX);
    731             if (u32 >= EFI_VM_VARIABLE_OP_MAX)
    732             {
    733                 u32 = EFI_VARIABLE_OP_STATUS_ERROR;
    734                 break;
    735             }
    736             pThis->NVRAM.idxOpBuffer = 0;
     1149            if (u32 >= (uint32_t)EFI_VM_VARIABLE_OP_MAX)
     1150            {
     1151                Log(("EFI: Invalid variable op %#x\n", u32));
     1152                u32 = EFI_VM_VARIABLE_OP_ERROR;
     1153            }
     1154            pThis->NVRAM.offOpBuffer = 0;
    7371155            pThis->NVRAM.enmOp = (EFIVAROP)u32;
     1156            Log2(("EFI_VARIABLE_OP: enmOp=%#x (%d)\n", u32));
     1157            break;
    7381158        }
    739         break;
     1159
    7401160        case EFI_VARIABLE_PARAM:
    741         {
    742             switch (pThis->NVRAM.enmOp)
    743             {
    744                 case EFI_VM_VARIABLE_OP_START:
    745                 {
    746                     pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_BSY;
    747                     switch (u32)
    748                     {
    749                         case EFI_VARIABLE_OP_QUERY:
    750                         {
    751                             LogRel(("EFI: variable lookup %RTuuid, %s\n",
    752                                     &pThis->NVRAM.OperationVarOp.uuid,
    753                                     pThis->NVRAM.OperationVarOp.szVariableName));
    754                             pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_BSY;
    755                             PEFIVAR pEfiVar = NULL;
    756                             memset(pThis->NVRAM.OperationVarOp.au8Value, 0, EFI_VARIABLE_NAME_MAX);
    757                             int nvramRc = nvramLookupVariableByUuidAndName(
    758                                                 pThis,
    759                                                 pThis->NVRAM.OperationVarOp.szVariableName,
    760                                                 &pThis->NVRAM.OperationVarOp.uuid,
    761                                                 &pEfiVar);
    762                             if (RT_SUCCESS(nvramRc))
    763                             {
    764                                 pThis->NVRAM.OperationVarOp.u32Attribute = pEfiVar->u32Attribute;
    765                                 pThis->NVRAM.OperationVarOp.cbVariableName = pEfiVar->cbVariableName;
    766                                 pThis->NVRAM.OperationVarOp.cbValue = pEfiVar->cbValue;
    767                                 memcpy(pThis->NVRAM.OperationVarOp.au8Value,
    768                                        pEfiVar->au8Value, pEfiVar->cbValue);
    769                                 pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
    770                                 pThis->NVRAM.pCurrentVarOp = pEfiVar;
    771                                 pThis->NVRAM.idxCurrentVar = pEfiVar->idxVariable;
    772                                 LogFlowFunc(("OperationVar: au8Value:%.*Rhxs\n",
    773                                               pThis->NVRAM.OperationVarOp.cbValue,
    774                                               pThis->NVRAM.OperationVarOp.au8Value));
    775                             }
    776                             else
    777                                 pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_NOT_FOUND;
    778                         }
    779                         break;
    780                         case EFI_VARIABLE_OP_ADD:
    781                         {
    782                             LogRel(("EFI: variable add %RTuuid, %s\n", &pThis->NVRAM.OperationVarOp.uuid, pThis->NVRAM.OperationVarOp.szVariableName));
    783                             PEFIVAR pEfiVar = NULL;
    784                             LogFlowFunc(("OperationVar: au8Value:%.*Rhxs\n",
    785                                           pThis->NVRAM.OperationVarOp.cbValue,
    786                                           pThis->NVRAM.OperationVarOp.au8Value));
    787                             int nvramRc = nvramLookupVariableByUuidAndName(
    788                                                 pThis,
    789                                                 pThis->NVRAM.OperationVarOp.szVariableName,
    790                                                 &pThis->NVRAM.OperationVarOp.uuid,
    791                                                 &pEfiVar);
    792                             if (RT_SUCCESS(nvramRc))
    793                             {
    794                                 /* delete or update ? */
    795                                 /* @todo: check whether pEfiVar is WP */
    796                                 LogFlowFunc(("pEfiVar: au8Value:%.*Rhxs\n",
    797                                              pEfiVar->cbValue,
    798                                              pEfiVar->au8Value));
    799                                 if (pThis->NVRAM.OperationVarOp.cbValue == 0)
    800                                 {
    801                                     /* delete */
    802                                     RTListNodeRemove(&pEfiVar->List);
    803                                     RTMemFree(pEfiVar);
    804                                     pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
    805                                     pThis->NVRAM.cNvramVariables--;
    806                                 }
    807                                 else
    808                                 {
    809                                     /* update */
    810                                     pEfiVar->cbValue = pThis->NVRAM.OperationVarOp.cbValue;
    811                                     memcpy(pEfiVar->au8Value, pThis->NVRAM.OperationVarOp.au8Value, pEfiVar->cbValue);
    812                                     pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
    813                                 }
    814                             }
    815                             else
    816                             {
    817                                 if (pThis->NVRAM.OperationVarOp.cbValue != 0)
    818                                 {
    819                                     pEfiVar = (PEFIVAR)RTMemAllocZ(sizeof(EFIVAR));
    820                                     if (!pEfiVar)
    821                                     {
    822                                         pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_ERROR;
    823                                         break;
    824                                     }
    825                                 }
    826                                 else
    827                                 {
    828                                     pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
    829                                     break;
    830                                 }
    831 
    832                                 memcpy(pEfiVar, &pThis->NVRAM.OperationVarOp, sizeof(EFIVAR));
    833                                 RTListInit(&pEfiVar->List);
    834                                 RTListAppend(&pThis->NVRAM.NvramVariableList.List, &pEfiVar->List);
    835                                 pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
    836                                 pThis->NVRAM.cNvramVariables++;
    837                                 pEfiVar->idxVariable = pThis->NVRAM.iNvramLastIndex;
    838                                 pThis->NVRAM.iNvramLastIndex++;
    839                             }
    840                         }
    841                         LogFunc(("cNvramVariables:%d, iNvramLastIndex:%d\n", pThis->NVRAM.cNvramVariables, pThis->NVRAM.iNvramLastIndex));
    842                         break;
    843                         case EFI_VARIABLE_OP_QUERY_NEXT:
    844                         {
    845                             PEFIVAR pEfiVar = RTListNodeGetNext(&pThis->NVRAM.pCurrentVarOp->List, EFIVAR, List);
    846                             if (pEfiVar)
    847                             {
    848                                 memcpy(&pThis->NVRAM.OperationVarOp, pEfiVar, sizeof(EFIVAR));
    849                                 pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_OK;
    850                             }
    851                             else
    852                                 pThis->NVRAM.u32Status = EFI_VARIABLE_OP_STATUS_NOT_FOUND;
    853                         }
    854                         break;
    855                         default:
    856                             /* @todo: return error */
    857                             break;
    858                     }
    859                 }
    860                 case EFI_VM_VARIABLE_OP_END:
    861                 break;
    862                 case EFI_VM_VARIABLE_OP_INDEX:
    863                 break;
    864                 case EFI_VM_VARIABLE_OP_GUID:
    865                     pThis->NVRAM.OperationVarOp.uuid.au8[pThis->NVRAM.idxOpBuffer] = (uint8_t)u32;
    866                     pThis->NVRAM.idxOpBuffer++;
    867                 break;
    868                 case EFI_VM_VARIABLE_OP_ATTRIBUTE:
    869                     pThis->NVRAM.OperationVarOp.u32Attribute = u32;
    870                 break;
    871                 case EFI_VM_VARIABLE_OP_NAME:
    872                     pThis->NVRAM.OperationVarOp.szVariableName[pThis->NVRAM.idxOpBuffer] = (uint8_t)u32;
    873                     pThis->NVRAM.idxOpBuffer++;
    874                 break;
    875                 case EFI_VM_VARIABLE_OP_NAME_LENGTH:
    876                     pThis->NVRAM.OperationVarOp.cbVariableName = u32;
    877                     memset(pThis->NVRAM.OperationVarOp.szVariableName, 0, EFI_VARIABLE_NAME_MAX);
    878                 break;
    879                 case EFI_VM_VARIABLE_OP_VALUE:
    880                     pThis->NVRAM.OperationVarOp.au8Value[pThis->NVRAM.idxOpBuffer] = (uint8_t)u32;
    881                     pThis->NVRAM.idxOpBuffer++;
    882                 break;
    883                 case EFI_VM_VARIABLE_OP_VALUE_LENGTH:
    884                     pThis->NVRAM.OperationVarOp.cbValue = u32;
    885                     memset(pThis->NVRAM.OperationVarOp.au8Value, 0, EFI_VARIABLE_VALUE_MAX);
    886                 break;
    887                 default:
    888                 break;
    889             }
    890         }
    891         break;
     1161            rc = nvramWriteVariableParam(pThis, u32);
     1162            break;
    8921163
    8931164        default:
     
    8951166            break;
    8961167    }
     1168    return rc;
     1169}
     1170
     1171static DECLCALLBACK(int) efiSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
     1172{
     1173    PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
     1174    LogFlow(("efiSaveExec:\n"));
     1175
     1176    /*
     1177     * Set variables only used when saving state.
     1178     */
     1179    uint32_t idUniqueSavedState = 0;
     1180    PEFIVAR pEfiVar;
     1181    RTListForEach(&pThis->NVRAM.VarList, pEfiVar, EFIVAR, ListNode)
     1182    {
     1183        pEfiVar->idUniqueSavedState = idUniqueSavedState++;
     1184    }
     1185    Assert(idUniqueSavedState == pThis->NVRAM.cVariables);
     1186
     1187    pThis->NVRAM.idUniqueCurVar = pThis->NVRAM.pCurVar
     1188                                ? pThis->NVRAM.pCurVar->idUniqueSavedState
     1189                                : UINT32_MAX;
     1190
     1191    /*
     1192     * Save the NVRAM state.
     1193     */
     1194    SSMR3PutStructEx(pSSM, &pThis->NVRAM,          sizeof(NVRAMDESC), 0, g_aEfiNvramDescField,     NULL);
     1195    SSMR3PutStructEx(pSSM, &pThis->NVRAM.VarOpBuf, sizeof(EFIVAR),    0, g_aEfiVariableDescFields, NULL);
     1196
     1197    /*
     1198     * Save the list variables (we saved the length above).
     1199     */
     1200    RTListForEach(&pThis->NVRAM.VarList, pEfiVar, EFIVAR, ListNode)
     1201    {
     1202        SSMR3PutStructEx(pSSM, pEfiVar, sizeof(EFIVAR), 0, g_aEfiVariableDescFields, NULL);
     1203    }
     1204
     1205    return VINF_SUCCESS; /* SSM knows */
     1206}
     1207
     1208static DECLCALLBACK(int) efiLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
     1209{
     1210    PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
     1211    LogFlow(("efiLoadExec: uVersion=%d uPass=%d\n", uVersion, uPass));
     1212
     1213    /*
     1214     * Validate input.
     1215     */
     1216    if (uPass != SSM_PASS_FINAL)
     1217        return VERR_SSM_UNEXPECTED_PASS;
     1218    if (   uVersion != EFI_SSM_VERSION
     1219        && uVersion != EFI_SSM_VERSION_4_2
     1220        )
     1221        return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
     1222
     1223    /*
     1224     * Kill the current variables before loading anything.
     1225     */
     1226    nvramFlushDeviceVariableList(pThis);
     1227
     1228    /*
     1229     * Load the NVRAM state.
     1230     */
     1231    int rc = SSMR3GetStructEx(pSSM, &pThis->NVRAM, sizeof(NVRAMDESC), 0, g_aEfiNvramDescField, NULL);
     1232    AssertRCReturn(rc, rc);
     1233    pThis->NVRAM.pCurVar = NULL;
     1234
     1235    rc = SSMR3GetStructEx(pSSM, &pThis->NVRAM.VarOpBuf, sizeof(EFIVAR), 0, g_aEfiVariableDescFields, NULL);
     1236    AssertRCReturn(rc, rc);
     1237
     1238    /*
     1239     * Load variables.
     1240     */
     1241    pThis->NVRAM.pCurVar = NULL;
     1242    Assert(RTListIsEmpty(&pThis->NVRAM.VarList));
     1243    RTListInit(&pThis->NVRAM.VarList);
     1244    for (uint32_t i = 0; i < pThis->NVRAM.cVariables; i++)
     1245    {
     1246        PEFIVAR pEfiVar = (PEFIVAR)RTMemAllocZ(sizeof(EFIVAR));
     1247        AssertPtrReturn(pEfiVar, VERR_NO_MEMORY);
     1248
     1249        rc = SSMR3GetStructEx(pSSM, pEfiVar, sizeof(EFIVAR), 0, g_aEfiVariableDescFields, NULL);
     1250        if (RT_SUCCESS(rc))
     1251        {
     1252            if (   pEfiVar->cbValue > sizeof(pEfiVar->abValue)
     1253                || pEfiVar->cbValue == 0)
     1254            {
     1255                rc = VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
     1256                LogRel(("EFI: Loaded invalid variable value length %#x\n", pEfiVar->cbValue));
     1257            }
     1258            size_t cchVarName = RTStrNLen(pEfiVar->szName, sizeof(pEfiVar->szName));
     1259            if (cchVarName >= sizeof(pEfiVar->szName))
     1260            {
     1261                rc = VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
     1262                LogRel(("EFI: Loaded variable name is unterminated.\n"));
     1263            }
     1264            if (pEfiVar->cchName > cchVarName) /* No check for 0 here, busted load code in 4.2, so now storing 0 here. */
     1265            {
     1266                rc = VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
     1267                LogRel(("EFI: Loaded invalid variable name length %#x (cchVarName=%#x)\n", pEfiVar->cchName, cchVarName));
     1268            }
     1269            if (RT_SUCCESS(rc))
     1270                pEfiVar->cchName = cchVarName;
     1271        }
     1272        AssertRCReturnStmt(rc, RTMemFree(pEfiVar), rc);
     1273
     1274        /* Add it, updating the current variable pointer while we're here. */
     1275        RTListAppend(&pThis->NVRAM.VarList, &pEfiVar->ListNode);
     1276        if (pThis->NVRAM.idUniqueCurVar == pEfiVar->idUniqueSavedState)
     1277            pThis->NVRAM.pCurVar = pEfiVar;
     1278    }
     1279
    8971280    return VINF_SUCCESS;
     1281}
     1282
     1283
     1284/**
     1285 * @copydoc(PDMIBASE::pfnQueryInterface)
     1286 */
     1287static DECLCALLBACK(void *) devEfiQueryInterface(PPDMIBASE pInterface, const char *pszIID)
     1288{
     1289    LogFlowFunc(("ENTER: pIBase: %p, pszIID:%p\n", __FUNCTION__, pInterface, pszIID));
     1290    PDEVEFI  pThis = RT_FROM_MEMBER(pInterface, DEVEFI, Lun0.IBase);
     1291
     1292    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Lun0.IBase);
     1293    return NULL;
     1294}
     1295
     1296
     1297/**
     1298 * Write to CMOS memory.
     1299 * This is used by the init complete code.
     1300 */
     1301static void cmosWrite(PPDMDEVINS pDevIns, unsigned off, uint32_t u32Val)
     1302{
     1303    Assert(off < 128);
     1304    Assert(u32Val < 256);
     1305
     1306    int rc = PDMDevHlpCMOSWrite(pDevIns, off, u32Val);
     1307    AssertRC(rc);
    8981308}
    8991309
     
    9991409{
    10001410    PDEVEFI  pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
     1411
    10011412    nvramStore(pThis);
    10021413    nvramFlushDeviceVariableList(pThis);
    10031414
    1004     /*
    1005      * Free MM heap pointers.
    1006      */
    10071415    if (pThis->pu8EfiRom)
    10081416    {
     
    10111419    }
    10121420
     1421    /*
     1422     * Free MM heap pointers (waste of time, but whatever).
     1423     */
    10131424    if (pThis->pszEfiRomFile)
    10141425    {
     
    12321643
    12331644/**
    1234  * @copydoc(PDMIBASE::pfnQueryInterface)
    1235  */
    1236 static DECLCALLBACK(void *) devEfiQueryInterface(PPDMIBASE pInterface, const char *pszIID)
    1237 {
    1238     LogFlowFunc(("ENTER: pIBase: %p, pszIID:%p\n", __FUNCTION__, pInterface, pszIID));
    1239     PDEVEFI  pThis = RT_FROM_MEMBER(pInterface, DEVEFI, Lun0.IBase);
    1240 
    1241     PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Lun0.IBase);
    1242     return NULL;
    1243 }
    1244 
    1245 /**
    12461645 * @interface_method_impl{PDMDEVREG,pfnConstruct}
    12471646 */
     
    12531652    Assert(iInstance == 0);
    12541653
     1654    /*
     1655     * Initalize the basic variables so that the destructor always works.
     1656     */
    12551657    pThis->pDevIns = pDevIns;
     1658    RTListInit(&pThis->NVRAM.VarList);
     1659    pThis->Lun0.IBase.pfnQueryInterface = devEfiQueryInterface;
     1660
    12561661
    12571662    /*
     
    13321737    uuid.Gen.u16TimeHiAndVersion = RT_H2BE_U16(uuid.Gen.u16TimeHiAndVersion);
    13331738    memcpy(&pThis->aUuid, &uuid, sizeof pThis->aUuid);
    1334     RTListInit((PRTLISTNODE)&pThis->NVRAM.NvramVariableList.List);
    1335 
    13361739
    13371740    /*
     
    13721775     * NVRAM processing.
    13731776     */
    1374     pThis->Lun0.IBase.pfnQueryInterface = devEfiQueryInterface;
    1375 
    1376 #if 0
    1377     rc = PDMDevHlpSSMRegisterEx(pDevIns, EFI_SSM_VERSION, sizeof(*pThis), NULL /*pszBefore*/,
    1378                                               NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/,  NULL /*pfnLiveDone*/,
    1379                                               NULL /*pfnSavePrep*/, efiSaveExec,           NULL /*pfnSaveDone*/,
    1380                                               NULL /*pfnLoadPrep*/, efiLoadExec,           efiLoadDone);
    1381 #else
    13821777    rc = PDMDevHlpSSMRegister(pDevIns, EFI_SSM_VERSION, sizeof(*pThis), efiSaveExec, efiLoadExec);
    1383 #endif
    13841778    AssertRCReturn(rc, rc);
    13851779
     
    13881782        return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("Can't attach Nvram Storage driver"));
    13891783
    1390     pThis->Lun0.pNvramDown = (PPDMINVRAM)pThis->Lun0.pDrvBase->pfnQueryInterface(pThis->Lun0.pDrvBase, PDMINVRAM_IID);
    1391     AssertPtrReturn(pThis->Lun0.pNvramDown, VERR_PDM_MISSING_INTERFACE_BELOW);
    1392 
    1393     nvramLoad(pThis);
     1784    pThis->Lun0.pNvramDrv = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pDrvBase, PDMINVRAMCONNECTOR);
     1785    AssertPtrReturn(pThis->Lun0.pNvramDrv, VERR_PDM_MISSING_INTERFACE_BELOW);
     1786
     1787    rc = nvramLoad(pThis);
     1788    AssertRCReturn(rc, rc);
    13941789
    13951790    /*
    13961791     * Get boot args.
    13971792     */
    1398     rc = CFGMR3QueryString(pCfg, "BootArgs",
    1399                            pThis->szBootArgs, sizeof pThis->szBootArgs);
    1400     if (rc == VERR_CFGM_VALUE_NOT_FOUND)
    1401     {
    1402         strcpy(pThis->szBootArgs, "");
    1403         rc = VINF_SUCCESS;
    1404     }
     1793    rc = CFGMR3QueryStringDef(pCfg, "BootArgs", pThis->szBootArgs, sizeof(pThis->szBootArgs), "");
    14051794    if (RT_FAILURE(rc))
    14061795        return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
     
    14121801     * Get device props.
    14131802     */
    1414     char* pszDeviceProps;
    1415     rc = CFGMR3QueryStringAlloc(pCfg, "DeviceProps", &pszDeviceProps);
    1416     if (rc == VERR_CFGM_VALUE_NOT_FOUND)
    1417     {
    1418         pszDeviceProps = NULL;
    1419         rc = VINF_SUCCESS;
    1420     }
     1803    char *pszDeviceProps;
     1804    rc = CFGMR3QueryStringAllocDef(pCfg, "DeviceProps", &pszDeviceProps, NULL);
    14211805    if (RT_FAILURE(rc))
    14221806        return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
     
    14401824     * CPU frequencies
    14411825     */
    1442     /// @todo: we need to have VMM API to access TSC increase speed, for now provide reasonable default
     1826    /// @todo we need to have VMM API to access TSC increase speed, for now provide reasonable default
    14431827    pThis->u64TscFrequency = RTMpGetMaxFrequency(0) * 1000 * 1000;// TMCpuTicksPerSecond(PDMDevHlpGetVM(pDevIns));
    14441828    if (pThis->u64TscFrequency == 0)
     
    14511835     * GOP graphics
    14521836     */
    1453     rc = CFGMR3QueryU32(pCfg, "GopMode", &pThis->u32GopMode);
    1454     AssertRC(rc);
     1837    rc = CFGMR3QueryU32Def(pCfg, "GopMode", &pThis->u32GopMode, 2 /* 1024x768 */);
     1838    if (RT_FAILURE(rc))
     1839        return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
     1840                                   N_("Configuration error: Querying \"GopMode\" as a 32-bit int failed"));
    14551841    if (pThis->u32GopMode == UINT32_MAX)
    1456     {
    14571842        pThis->u32GopMode = 2; /* 1024x768 */
    1458     }
    1459 
    1460     /*
    1461      * Uga graphics
     1843
     1844    /*
     1845     * Uga graphics.
    14621846     */
    14631847    rc = CFGMR3QueryU32Def(pCfg, "UgaHorizontalResolution", &pThis->cxUgaResolution, 0); AssertRC(rc);
     
    14831867
    14841868    /*
    1485      * Register our communication ports.
     1869     * Register our I/O ports.
    14861870     */
    14871871    rc = PDMDevHlpIOPortRegister(pDevIns, EFI_PORT_BASE, EFI_PORT_COUNT, NULL,
     
    14921876
    14931877    /*
    1494      * Plant DMI and MPS tables
     1878     * Plant DMI and MPS tables.
    14951879     */
    14961880    /** @todo XXX I wonder if we really need these tables as there is no SMBIOS header... */
     
    15081892
    15091893    /*
     1894     * Register info handlers.
     1895     */
     1896    rc = PDMDevHlpDBGFInfoRegister(pDevIns, "nvram", "Dumps the NVRAM variables.\n", efiInfoNvram);
     1897    AssertRCReturn(rc, rc);
     1898
     1899    /*
    15101900     * Call reset to set things up.
    15111901     */
     
    15291919    "",
    15301920    /* pszDescription */
    1531     "Extensible Firmware Interface Device",
     1921    "Extensible Firmware Interface Device. "
     1922    "LUN#0 - NVRAM port",
    15321923    /* fFlags */
    15331924    PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64,
  • trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Include/DevEFI.h

    r44575 r44591  
    120120#define EFI_VARIABLE_OP_STATUS_BSY        0xcafe0010
    121121
    122 #define EFI_VARIABLE_NAME_MAX   1024
    123 #define EFI_VARIABLE_VALUE_MAX   1024
     122/** The max number of variables allowed. */
     123#define EFI_VARIABLE_MAX            128
     124/** The max variable name length (in bytes, including the zero terminator). */
     125#define EFI_VARIABLE_NAME_MAX       1024
     126/** The max value length (in bytes). */
     127#define EFI_VARIABLE_VALUE_MAX      1024
    124128
    125 typedef enum {
     129typedef enum
     130{
    126131    EFI_VM_VARIABLE_OP_START = 0,
    127     EFI_VM_VARIABLE_OP_END,
    128     EFI_VM_VARIABLE_OP_INDEX,
     132    EFI_VM_VARIABLE_OP_END, /**< @todo r=bird: What's the point of this one? */
     133    EFI_VM_VARIABLE_OP_RESERVED_USED_TO_BE_INDEX,
    129134    EFI_VM_VARIABLE_OP_GUID,
    130135    EFI_VM_VARIABLE_OP_ATTRIBUTE,
     
    133138    EFI_VM_VARIABLE_OP_VALUE,
    134139    EFI_VM_VARIABLE_OP_VALUE_LENGTH,
    135     EFI_VM_VARIABLE_OP_MAX
     140    EFI_VM_VARIABLE_OP_ERROR,
     141    EFI_VM_VARIABLE_OP_NAME_UTF16,
     142    EFI_VM_VARIABLE_OP_NAME_LENGTH_UTF16,
     143    EFI_VM_VARIABLE_OP_MAX,
     144    EFI_VM_VARIABLE_OP_32BIT_HACK = 0x7fffffff
    136145} EFIVAROP;
    137146
  • trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/VBoxVariable/InitVariable.c

    r43212 r44591  
    4545
    4646
    47 static inline UINT32 VBoxReadNVRAM(UINT8 *pu8Buffer, UINT32 cbBuffer)
     47static UINT32 VBoxReadNVRAM(UINT8 *pu8Buffer, UINT32 cbBuffer)
    4848{
    4949    UINT32 idxBuffer = 0;
     
    5959}
    6060
    61 static inline UINT32 VBoxWriteNVRAMByteArrayParam(const UINT8 *pu8Param, UINT32 cbParam)
     61static UINT32 VBoxWriteNVRAMByteArrayParam(const UINT8 *pbParam, UINT32 cbParam)
    6262{
    6363    UINT32 idxParam = 0;
    6464    for (idxParam = 0; idxParam < cbParam; ++idxParam)
    65         ASMOutU8(EFI_VARIABLE_PARAM, pu8Param[idxParam]);
     65        ASMOutU8(EFI_VARIABLE_PARAM, pbParam[idxParam]);
    6666    return idxParam;
    6767}
    6868
    69 static inline UINT32 VBoxWriteNVRAMStringParam(const CHAR16 *ps16VariableName)
    70 {
    71     CHAR8 szVarName[512];
    72     UINT32 cbVarName = StrLen(ps16VariableName);
    73     LogFlowFuncEnter();
    74     ASSERT (cbVarName < 512);
    75     if (cbVarName > 512)
    76     {
    77         LogFlowFuncMarkVar(cbVarName, "%d");
    78         LogFlowFuncLeave();
    79         return 0;
    80     }
    81     UnicodeStrToAsciiStr(ps16VariableName, szVarName);
    82 
    83     VBoxWriteNVRAMU32Param(EFI_VM_VARIABLE_OP_NAME_LENGTH, cbVarName);
    84 
    85     ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_NAME);
    86     cbVarName = VBoxWriteNVRAMByteArrayParam((UINT8 *)szVarName, cbVarName);
    87 
    88     LogFlowFuncMarkVar(cbVarName, "%d");
    89     LogFlowFuncLeave();
    90     return cbVarName;
     69static void VBoxWriteNVRAMNameParam(const CHAR16 *pwszName)
     70{
     71    UINT32 i;
     72    UINT32 cwcName = StrLen(pwszName);
     73
     74    ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_NAME_UTF16);
     75    for (i = 0; i <= cwcName; i++)
     76        ASMOutU16(EFI_VARIABLE_PARAM, pwszName[i]);
    9177}
    9278
     
    9783}
    9884
    99 static inline UINT32 VBoxWriteNVRAMDoOp(UINT32 u32Operation)
     85static UINT32 VBoxWriteNVRAMDoOp(UINT32 u32Operation)
    10086{
    10187    UINT32 u32Rc;
     
    10490    VBoxWriteNVRAMU32Param(EFI_VM_VARIABLE_OP_START, u32Operation);
    10591
    106     while((u32Rc = ASMInU32(EFI_VARIABLE_OP)) == EFI_VARIABLE_OP_STATUS_BSY)
     92    while ((u32Rc = ASMInU32(EFI_VARIABLE_OP)) == EFI_VARIABLE_OP_STATUS_BSY)
    10793    {
    10894#if 0
    10995        MicroSecondDelay (400);
    11096#endif
    111         /* @todo: sleep here */
     97        /* @todo: sleep here. bird: won't ever happen, so don't bother. */
    11298    }
    11399    LogFlowFuncMarkVar(u32Rc, "%x");
     
    154140          );
    155141#else
    156     UINT32 VarLen;
    157     UINT32 u32Rc = 0;
     142    EFI_STATUS rc;
     143    UINT32 u32Rc;
    158144
    159145    LogFlowFuncEnter();
    160     /* set uuid */
     146
     147    /*
     148     * Tell DevEFI to look for the specified variable.
     149     */
    161150    ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_GUID);
    162151    VBoxWriteNVRAMGuidParam(VendorGuid);
    163 
    164     /* set name */
    165     VBoxWriteNVRAMStringParam(VariableName);
    166 
    167     /* start operation */
     152    VBoxWriteNVRAMNameParam(VariableName);
     153
    168154    u32Rc = VBoxWriteNVRAMDoOp(EFI_VARIABLE_OP_QUERY);
    169 
    170     ASSERT (u32Rc != EFI_VARIABLE_OP_STATUS_ERROR);
    171     switch(u32Rc)
     155    if (u32Rc == EFI_VARIABLE_OP_STATUS_OK)
    172156    {
    173         case EFI_VARIABLE_OP_STATUS_ERROR: /* for release build */
    174         case EFI_VARIABLE_OP_STATUS_NOT_FOUND:
    175             LogFlowFuncLeaveRC(EFI_NOT_FOUND);
    176             return EFI_NOT_FOUND;
    177         case EFI_VARIABLE_OP_STATUS_OK:
     157        /*
     158         * Check if we got enought space for the value.
     159         */
     160        UINT32 VarLen;
     161        ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_VALUE_LENGTH);
     162        VarLen = ASMInU32(EFI_VARIABLE_OP);
     163        LogFlowFuncMarkVar(*DataSize, "%d");
     164        LogFlowFuncMarkVar(VarLen, "%d");
     165        if (   VarLen <= *DataSize
     166            && Data)
    178167        {
    179             ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_VALUE_LENGTH);
    180             VarLen = ASMInU32(EFI_VARIABLE_OP);
    181             LogFlowFuncMarkVar(*DataSize, "%d");
    182             LogFlowFuncMarkVar(VarLen, "%d");
    183             if (   VarLen > *DataSize
    184                 || !Data)
    185             {
    186                 *DataSize = VarLen;
    187                 /* @todo: should we end op ? */
    188                 LogFlowFuncLeave();
    189                 return EFI_BUFFER_TOO_SMALL;
    190             }
     168            /*
     169             * We do, then read it and, if requrest, the attribute.
     170             */
     171            *DataSize = VarLen;
    191172            ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_VALUE);
    192             *DataSize = VBoxReadNVRAM((UINT8 *)Data, VarLen);
     173            VBoxReadNVRAM((UINT8 *)Data, VarLen);
     174
    193175            if (Attributes)
    194176            {
     
    197179                LogFlowFuncMarkVar(Attributes, "%x");
    198180            }
    199             LogFlowFuncLeaveRC((EFI_SUCCESS));
    200             return EFI_SUCCESS;
     181
     182            rc = EFI_SUCCESS;
     183        }
     184        else
     185        {
     186            *DataSize = VarLen;
     187            rc = EFI_BUFFER_TOO_SMALL;
    201188        }
    202189    }
    203 #endif
    204     return EFI_SUCCESS;
     190    else
     191    {
     192        rc = EFI_NOT_FOUND;
     193    }
     194
     195    LogFlowFuncLeaveRC(rc);
     196    return rc;
     197#endif
    205198}
    206199
     
    235228          );
    236229#else
    237     uint32_t u32Rc = 0;
    238     EFI_STATUS rc = EFI_NOT_FOUND;
    239     CHAR8   szVariableName[512];
    240     int cbVarName = 0;
    241 
     230    uint32_t    u32Rc;
     231    EFI_STATUS  rc;
    242232    LogFlowFuncEnter();
    243233
    244     SetMem(szVariableName, 512, 0);
    245     u32Rc = VBoxWriteNVRAMDoOp(EFI_VARIABLE_OP_QUERY_NEXT);
    246     switch (u32Rc)
     234    /*
     235     * Tell DevEFI which the current variable is, then ask for the next one.
     236     */
     237    ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_GUID);
     238    VBoxWriteNVRAMGuidParam(VendorGuid);
     239    VBoxWriteNVRAMNameParam(VariableName);
     240
     241    u32Rc = VBoxWriteNVRAMDoOp(EFI_VARIABLE_OP_QUERY);
     242    if (u32Rc == EFI_VARIABLE_OP_STATUS_OK)
     243        u32Rc = VBoxWriteNVRAMDoOp(EFI_VARIABLE_OP_QUERY_NEXT);
     244
     245    if (u32Rc == EFI_VARIABLE_OP_STATUS_OK)
    247246    {
    248         case EFI_VARIABLE_OP_STATUS_OK:
     247        /*
     248         * Output buffer check.
     249         */
     250        UINT32      cwcName;
     251        ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_NAME_LENGTH_UTF16);
     252        cwcName = ASMInU32(EFI_VARIABLE_OP);
     253        if (cwcName * 2 < *VariableNameSize) /* ASSUMES byte size is specified */
    249254        {
    250             ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_NAME_LENGTH);
    251             cbVarName = ASMInU32(EFI_VARIABLE_OP);
    252 
     255            UINT32 i;
     256
     257            /*
     258             * Read back the result.
     259             */
    253260            ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_GUID);
    254261            VBoxReadNVRAM((UINT8 *)VendorGuid, sizeof(EFI_GUID));
    255262
    256             ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_NAME);
    257             VBoxReadNVRAM((UINT8 *)szVariableName, cbVarName);
    258 
    259             if (cbVarName < *VariableNameSize)
    260             {
    261                 UnicodeSPrintAsciiFormat(VariableName, cbVarName, "%a", szVariableName);
    262                 LogFlowFuncMarkVar(*VariableNameSize, "%d");
    263                 LogFlowFuncMarkVar(VariableName, "%s");
    264                 LogFlowFuncMarkVar(VendorGuid, "%g");
    265                 *VariableNameSize = cbVarName;
    266                 LogFlowFuncMarkVar(*VariableNameSize, "%d");
    267                 rc = EFI_SUCCESS;
    268             }
    269             else
    270                 rc = EFI_BUFFER_TOO_SMALL;
     263            ASMOutU32(EFI_VARIABLE_OP, EFI_VM_VARIABLE_OP_NAME_UTF16);
     264            for (i = 0; i < cwcName; i++)
     265                VariableName[i] = ASMInU16(EFI_VARIABLE_OP);
     266            VariableName[i] = '\0';
     267
     268            *VariableNameSize = cwcName * 2;
     269            rc = EFI_SUCCESS;
    271270        }
    272         case EFI_VARIABLE_OP_STATUS_ERROR:
    273         case EFI_VARIABLE_OP_STATUS_NOT_FOUND:
    274         case EFI_VARIABLE_OP_STATUS_NOT_WP:
    275             rc = EFI_NOT_FOUND;
     271        else
     272        {
     273            rc = EFI_BUFFER_TOO_SMALL;
     274            *VariableNameSize = (cwcName + 1) * 2;
     275        }
    276276    }
     277    else
     278        rc = EFI_NOT_FOUND; /* whatever */
     279
    277280    LogFlowFuncLeaveRC(rc);
    278281    return rc;
     
    328331    VBoxWriteNVRAMGuidParam(VendorGuid);
    329332    /* set name */
    330     VBoxWriteNVRAMStringParam(VariableName);
     333    VBoxWriteNVRAMNameParam(VariableName);
    331334    /* set attribute */
    332335    VBoxWriteNVRAMU32Param(EFI_VM_VARIABLE_OP_ATTRIBUTE, Attributes);
     
    340343    /* process errors */
    341344    LogFlowFuncLeave();
    342     switch(u32Rc)
     345    switch (u32Rc)
    343346    {
    344347        case EFI_VARIABLE_OP_STATUS_OK:
  • trunk/src/VBox/Main/include/Nvram.h

    r43133 r44591  
    3131    Nvram(Console *console);
    3232    virtual ~Nvram();
     33
     34    Console *getParent(void) { return mParent; }
     35
    3336    static const PDMDRVREG DrvReg;
    34     Console *getParent(void) { return mParent; }
    35     struct NVRAM *mpDrv;
    3637
    3738private:
     
    4041    static DECLCALLBACK(void)   drvNvram_Destruct(PPDMDRVINS pDrvIns);
    4142
     43    /** Pointer to the parent object. */
    4244    Console * const mParent;
     45    /** Pointer to the driver instance data.
     46     *  Can be NULL during init and termination. */
     47    struct NVRAM *mpDrv;
    4348};
    4449
  • trunk/src/VBox/Main/src-client/Nvram.cpp

    r43256 r44591  
    55
    66/*
    7  * Copyright (C) 2012 Oracle Corporation
     7 * Copyright (C) 2012-2013 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2121#include "Nvram.h"
    2222#include "ConsoleImpl.h"
     23#include "Global.h"
    2324
    2425#include <VBox/vmm/pdm.h>
     
    4546typedef struct NVRAM *PNVRAM;
    4647
     48/**
     49 * Intstance data associated with PDMDRVINS.
     50 */
    4751struct NVRAM
    4852{
    49     Nvram *pNvram;
    50     PDMINVRAM INvram;
    51     int cLoadedVariables;
    52     bool fPermanentSave;
     53    /** Pointer to the associated class instance. */
     54    Nvram              *pNvram;
     55    /** The NVRAM connector interface we provide to DevEFI. */
     56    PDMINVRAMCONNECTOR  INvramConnector;
     57    /** The root of the 'Vars' child of the driver config (i.e.
     58     * VBoxInternal/Devices/efi/0/LUN#0/Config/Vars/).
     59     * This node has one child node per NVRAM variable. */
     60    PCFGMNODE           pCfgVarRoot;
     61    /** The variable node used in the privous drvNvram_VarQueryByIndex call. */
     62    PCFGMNODE           pLastVarNode;
     63    /** The index pLastVarNode corresponds to. */
     64    uint32_t            idxLastVar;
     65    /** Whether to permanently save the variables or not. */
     66    bool                fPermanentSave;
    5367};
    5468
     
    5771 * Constructor/destructor
    5872 */
    59 Nvram::Nvram(Console *console)
    60     : mpDrv(NULL),
    61       mParent(console)
     73Nvram::Nvram(Console *pConsole)
     74    : mParent(pConsole),
     75      mpDrv(NULL)
    6276{
    6377}
     
    7488
    7589/**
    76  * @interface_method_impl(PDMINVRAM,pfnStoreNvramValue)
    77  */
    78 DECLCALLBACK(int) drvNvram_pfnStoreNvramValue(PPDMINVRAM pInterface,
    79                                               int idxVariable,
    80                                               RTUUID *pVendorUuid,
    81                                               const char *pcszVariableName,
    82                                               size_t cbVariableName,
    83                                               uint8_t *pu8Value,
    84                                               size_t cbValue)
    85 {
    86     int rc = VINF_SUCCESS;
    87     char szExtraDataKey[256];
    88     char szExtraDataValue[1024];
    89     LogFlowFunc(("ENTER: pVendorUuid:%RTuuid, pcszVariableName:%s, cbVariableName:%d, pu8Value:%.*Rhxs, cbValue:%d\n",
    90                         pVendorUuid,
    91                         pcszVariableName,
    92                         cbVariableName,
    93                         cbValue,
    94                         pu8Value,
    95                         cbValue));
    96     PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvram);
    97     if (!pThis->fPermanentSave)
    98     {
    99         LogFlowFuncLeaveRC(rc);
    100         return rc;
    101     }
    102 
    103     bool fFlushVariable = (!pu8Value);
    104 
    105     RT_ZERO(szExtraDataKey);
    106     RT_ZERO(szExtraDataValue);
    107     RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VariableName", idxVariable);
    108     if (!fFlushVariable)
    109         RTStrPrintf(szExtraDataValue, 1024, "%s", pcszVariableName);
    110     pThis->pNvram->getParent()->machine()->SetExtraData(Bstr(szExtraDataKey).raw(), Bstr(szExtraDataValue).raw());
    111 
    112     RT_ZERO(szExtraDataKey);
    113     RT_ZERO(szExtraDataValue);
    114     RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VendorGuid", idxVariable);
    115     if (!fFlushVariable)
    116         RTUuidToStr(pVendorUuid, szExtraDataValue, 1024);
    117     pThis->pNvram->getParent()->machine()->SetExtraData(Bstr(szExtraDataKey).raw(), Bstr(szExtraDataValue).raw());
    118 
    119     RT_ZERO(szExtraDataKey);
    120     RT_ZERO(szExtraDataValue);
    121     RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VariableValueLength", idxVariable);
    122     if (!fFlushVariable)
    123         RTStrPrintf(szExtraDataValue, 1024, "%d", cbValue);
    124     pThis->pNvram->getParent()->machine()->SetExtraData(Bstr(szExtraDataKey).raw(), Bstr(szExtraDataValue).raw());
    125 
    126     RT_ZERO(szExtraDataKey);
    127     RT_ZERO(szExtraDataValue);
    128     RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VariableValue", idxVariable);
    129     size_t cbActualSize;
    130     if (pu8Value)
    131         rc = RTBase64Encode(pu8Value, cbValue, szExtraDataValue, 1024, &cbActualSize);
    132     AssertRCReturn(rc, rc);
    133     pThis->pNvram->getParent()->machine()->SetExtraData(Bstr(szExtraDataKey).raw(), Bstr(szExtraDataValue).raw());
    134 
     90 * @interface_method_impl(PDMINVRAM,pfnVarStoreSeqEnd)
     91 */
     92DECLCALLBACK(int) drvNvram_VarStoreSeqEnd(PPDMINVRAMCONNECTOR pInterface, int rc)
     93{
     94    NOREF(pInterface);
     95    return rc;
     96}
     97
     98/**
     99 * Converts the binary to a CFGM overlay binary string.
     100 *
     101 * @returns Pointer to a heap buffer (hand it to RTMemFree when done).
     102 * @param   pvBuf               The binary data to convert.
     103 * @param   cbBuf               The number of bytes to convert.
     104 */
     105static char *drvNvram_binaryToCfgmString(void const *pvBuf, size_t cbBuf)
     106{
     107    static char s_szPrefix[] = "bytes:";
     108    size_t cbStr   = RTBase64EncodedLength(cbBuf) + sizeof(s_szPrefix);
     109    char   *pszStr = (char *)RTMemAlloc(cbStr);
     110    if (pszStr)
     111    {
     112        memcpy(pszStr, s_szPrefix, sizeof(s_szPrefix) - 1);
     113        int rc = RTBase64Encode(pvBuf, cbBuf, &pszStr[sizeof(s_szPrefix) - 1], cbBuf - sizeof(s_szPrefix) + 1, NULL);
     114        if (RT_FAILURE(rc))
     115        {
     116            RTMemFree(pszStr);
     117            pszStr = NULL;
     118        }
     119    }
     120    return pszStr;
     121}
     122
     123/**
     124 * @interface_method_impl(PDMINVRAM,pfnVarStoreSeqPut)
     125 */
     126DECLCALLBACK(int) drvNvram_VarStoreSeqPut(PPDMINVRAMCONNECTOR pInterface, int idxVariable,
     127                                          PCRTUUID pVendorUuid, const char *pszName, size_t cchName,
     128                                          uint32_t fAttributes, uint8_t const *pbValue, size_t cbValue)
     129{
     130    PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvramConnector);
     131    int    rc    = VINF_SUCCESS;
     132
     133    if (pThis->fPermanentSave && pThis->pNvram)
     134    {
     135        char    szExtraName[256];
     136        size_t  offValueNm = RTStrPrintf(szExtraName, sizeof(szExtraName) - 16,
     137                                         "VBoxInternal/Devices/efi/0/LUN#0/Config/Vars/%4u/", idxVariable);
     138
     139        char    szAttribs[32];
     140        RTStrPrintf(szAttribs, sizeof(szAttribs), "%#x", fAttributes);
     141
     142        char    szUuid[RTUUID_STR_LENGTH];
     143        int rc2 = RTUuidToStr(pVendorUuid, szUuid, sizeof(szUuid)); AssertRC(rc2);
     144
     145        char   *pszValue = drvNvram_binaryToCfgmString(pbValue, cbValue);
     146        if (pszValue)
     147        {
     148            const char *apszTodo[] =
     149            {
     150                "Name",     pszName,
     151                "Uuid",     szUuid,
     152                "Attribs",  szAttribs,
     153                "Value",    pszValue,
     154            };
     155            for (unsigned i = 0; i < RT_ELEMENTS(apszTodo); i += 2)
     156            {
     157                Assert(strlen(apszTodo[i]) < 16);
     158                strcpy(szExtraName + offValueNm, apszTodo[i]);
     159                try
     160                {
     161                    HRESULT hrc = pThis->pNvram->getParent()->machine()->SetExtraData(Bstr(szExtraName).raw(),
     162                                                                                      Bstr(apszTodo[i + 1]).raw());
     163                    if (FAILED(hrc))
     164                    {
     165                        LogRel(("drvNvram_deleteVar: SetExtraData(%s,%s) returned %Rhrc\n", szExtraName, apszTodo[i + 1], hrc));
     166                        rc = Global::vboxStatusCodeFromCOM(hrc);
     167                    }
     168                }
     169                catch (...)
     170                {
     171                    LogRel(("drvNvram_deleteVar: SetExtraData(%s,%s) threw exception\n", szExtraName, apszTodo[i + 1]));
     172                    rc = VERR_UNEXPECTED_EXCEPTION;
     173                }
     174            }
     175        }
     176        else
     177            rc = VERR_NO_MEMORY;
     178        RTMemFree(pszValue);
     179    }
     180
     181    NOREF(cchName);
    135182    LogFlowFuncLeaveRC(rc);
    136183    return rc;
    137184}
    138185
    139 
    140 /**
    141  * @interface_method_impl(PDMINVRAM,pfnFlushNvramStorage)
    142  */
    143 DECLCALLBACK(int) drvNvram_pfnFlushNvramStorage(PPDMINVRAM pInterface)
    144 {
    145     int rc = VINF_SUCCESS;
    146     LogFlowFuncEnter();
    147     PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvram);
    148     if (!pThis->fPermanentSave)
    149     {
    150         LogFlowFuncLeaveRC(rc);
    151         return rc;
    152     }
    153 
    154     for (int idxVariable = 0; idxVariable < pThis->cLoadedVariables; ++idxVariable)
    155     {
    156         drvNvram_pfnStoreNvramValue(pInterface, idxVariable, NULL, NULL, 0, NULL, 0);
    157     }
    158     LogFlowFuncLeaveRC(rc);
     186/**
     187 * Deletes a variable.
     188 *
     189 * @param   pThis           The NVRAM driver instance data.
     190 * @param   pszVarNodeNm    The variable node name.
     191 */
     192static void drvNvram_deleteVar(PNVRAM pThis, const char *pszVarNodeNm)
     193{
     194    char   szExtraName[256];
     195    size_t offValue = RTStrPrintf(szExtraName, sizeof(szExtraName) - 16,
     196                                  "VBoxInternal/Devices/efi/0/LUN#0/Config/Vars/%s/", pszVarNodeNm);
     197    static const char *s_apszValueNames[] = { "Name", "Attribs", "Value" };
     198    for (unsigned i = 0; i < RT_ELEMENTS(s_apszValueNames); i++)
     199    {
     200        Assert(strlen(s_apszValueNames[i]) < 16);
     201        strcpy(szExtraName + offValue, s_apszValueNames[i]);
     202        try
     203        {
     204            HRESULT hrc = pThis->pNvram->getParent()->machine()->SetExtraData(Bstr(szExtraName).raw(), Bstr().raw());
     205            if (FAILED(hrc))
     206                LogRel(("drvNvram_deleteVar: SetExtraData(%s,) returned %Rhrc\n", szExtraName, hrc));
     207        }
     208        catch (...)
     209        {
     210            LogRel(("drvNvram_deleteVar: SetExtraData(%s,) threw exception\n", szExtraName));
     211        }
     212    }
     213}
     214
     215/**
     216 * @interface_method_impl(PDMINVRAM,pfnVarStoreSeqBegin)
     217 */
     218DECLCALLBACK(int) drvNvram_VarStoreSeqBegin(PPDMINVRAMCONNECTOR pInterface, uint32_t cVariables)
     219{
     220    PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvramConnector);
     221    int    rc    = VINF_SUCCESS;
     222    if (pThis->fPermanentSave && pThis->pNvram)
     223    {
     224        /*
     225         * Remove all existing variables.
     226         */
     227        for (PCFGMNODE pVarNode = CFGMR3GetFirstChild(pThis->pCfgVarRoot); pVarNode; pVarNode = CFGMR3GetNextChild(pVarNode))
     228        {
     229            char szName[128];
     230            rc = CFGMR3GetName(pVarNode, szName, sizeof(szName));
     231            if (RT_SUCCESS(rc))
     232                drvNvram_deleteVar(pThis, szName);
     233            else
     234                LogRel(("drvNvram_VarStoreSeqBegin: CFGMR3GetName -> %Rrc\n", rc));
     235        }
     236    }
     237
     238    NOREF(cVariables);
    159239    return rc;
    160240}
    161241
    162 
    163 /**
    164  * @interface_method_impl(PDMINVRAM,pfnStoreNvramValue)
    165  */
    166 DECLCALLBACK(int) drvNvram_pfnLoadNvramValue(PPDMINVRAM pInterface,
    167                                              int idxVariable,
    168                                              RTUUID *pVendorUuid,
    169                                              char *pcszVariableName,
    170                                              size_t *pcbVariableName,
    171                                              uint8_t *pu8Value,
    172                                              size_t *pcbValue)
    173 {
    174     int rc = VINF_SUCCESS;
    175     char szExtraDataKey[256];
    176     Bstr bstrValue;
    177     HRESULT hrc;
    178     LogFlowFunc(("ENTER: idxVariable:%d, *pcbVariableName:%d, *pcbValue:%d\n",
    179                         idxVariable,
    180                         *pcbVariableName,
    181                         *pcbValue));
    182     PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvram);
    183     if (!pThis->fPermanentSave)
    184     {
    185         rc = VERR_NOT_FOUND;
    186         LogFlowFuncLeaveRC(rc);
    187         return rc;
    188     }
    189 
    190 
    191     RT_ZERO(szExtraDataKey);
    192     RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VariableName", idxVariable);
    193     hrc = pThis->pNvram->getParent()->machine()->GetExtraData(Bstr(szExtraDataKey).raw(), bstrValue.asOutParam());
    194     if (!SUCCEEDED(hrc))
     242/**
     243 * @interface_method_impl(PDMINVRAMCONNECTOR,pfnVarQueryByIndex)
     244 */
     245DECLCALLBACK(int) drvNvram_VarQueryByIndex(PPDMINVRAMCONNECTOR pInterface, uint32_t idxVariable,
     246                                           PRTUUID pVendorUuid, char *pszName, uint32_t *pcchName,
     247                                           uint32_t *pfAttributes, uint8_t *pbValue, uint32_t *pcbValue)
     248{
     249    PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvramConnector);
     250
     251    /*
     252     * Find the requested variable node.
     253     */
     254    PCFGMNODE pVarNode;
     255    if (pThis->idxLastVar + 1 == idxVariable && pThis->pLastVarNode)
     256        pVarNode = CFGMR3GetNextChild(pThis->pLastVarNode);
     257    else
     258    {
     259        pVarNode = CFGMR3GetFirstChild(pThis->pLastVarNode);
     260        for (uint32_t i = 0; i < idxVariable && pVarNode; i++)
     261            pVarNode = CFGMR3GetNextChild(pVarNode);
     262    }
     263    if (!pVarNode)
    195264        return VERR_NOT_FOUND;
    196     *pcbVariableName = RTStrCopy(pcszVariableName, 1024, Utf8Str(bstrValue).c_str());
    197 
    198     RT_ZERO(szExtraDataKey);
    199     RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VendorGuid", idxVariable);
    200     hrc = pThis->pNvram->getParent()->machine()->GetExtraData(Bstr(szExtraDataKey).raw(), bstrValue.asOutParam());
    201     RTUuidFromStr(pVendorUuid, Utf8Str(bstrValue).c_str());
    202 
    203 #if 0
    204     RT_ZERO(szExtraDataKey);
    205     RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VariableValueLength", idxVariable);
    206     hrc = pThis->pNvram->getParent()->machine()->GetExtraData(Bstr(szExtraDataKey).raw(), bstrValue.asOutParam());
    207     *pcbValue = Utf8Str(bstrValue).toUInt32();
    208 #endif
    209 
    210     RT_ZERO(szExtraDataKey);
    211     RTStrPrintf(szExtraDataKey, 256, "VBoxInternal/Devices/efi/0/LUN#0/Config/NVRAM/%d/VariableValue", idxVariable);
    212     hrc = pThis->pNvram->getParent()->machine()->GetExtraData(Bstr(szExtraDataKey).raw(), bstrValue.asOutParam());
    213     rc = RTBase64Decode(Utf8Str(bstrValue).c_str(), pu8Value, 1024, pcbValue, NULL);
    214     AssertRCReturn(rc, rc);
    215 
    216     pThis->cLoadedVariables++;
    217     LogFlowFuncLeaveRC(rc);
    218     return rc;
     265
     266    /* cache it */
     267    pThis->pLastVarNode = pVarNode;
     268    pThis->idxLastVar   = idxVariable;
     269
     270    /*
     271     * Read the variable node.
     272     */
     273    int rc = CFGMR3QueryString(pVarNode, "Name", pszName, *pcchName);
     274    AssertRCReturn(rc, rc);
     275    *pcchName = strlen(pszName);
     276
     277    char    szUuid[RTUUID_STR_LENGTH];
     278    rc = CFGMR3QueryString(pVarNode, "Uuid", szUuid, sizeof(szUuid));
     279    AssertRCReturn(rc, rc);
     280    rc = RTUuidFromStr(pVendorUuid, szUuid);
     281    AssertRCReturn(rc, rc);
     282
     283    rc = CFGMR3QueryU32(pVarNode, "Attribs", pfAttributes);
     284    AssertRCReturn(rc, rc);
     285
     286    size_t cbValue;
     287    rc = CFGMR3QuerySize(pVarNode, "Value", &cbValue);
     288    AssertRCReturn(rc, rc);
     289    AssertReturn(cbValue <= *pcbValue, VERR_BUFFER_OVERFLOW);
     290    rc = CFGMR3QueryBytes(pVarNode, "Value", pbValue, cbValue);
     291    AssertRCReturn(rc, rc);
     292
     293    return VINF_SUCCESS;
    219294}
    220295
     
    230305
    231306    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
    232     PDMIBASE_RETURN_INTERFACE(pszIID, PDMINVRAM, &pThis->INvram);
     307    PDMIBASE_RETURN_INTERFACE(pszIID, PDMINVRAMCONNECTOR, &pThis->INvramConnector);
    233308    return NULL;
    234309}
     
    242317    LogFlow(("%s: iInstance/#d\n", __FUNCTION__, pDrvIns->iInstance));
    243318    PNVRAM pThis = PDMINS_2_DATA(pDrvIns, PNVRAM);
     319    if (pThis->pNvram != NULL)
     320        pThis->pNvram->mpDrv = NULL;
    244321}
    245322
     
    253330    PNVRAM pThis = PDMINS_2_DATA(pDrvIns, PNVRAM);
    254331
     332    /*
     333     * Initalize instance data variables first.
     334     */
     335    //pThis->pNvram                               = NULL;
     336    //pThis->cLoadedVariables                     = 0;
     337    //pThis->fPermanentSave                       = false;
     338    pThis->pCfgVarRoot                          = CFGMR3GetChild(pCfg, "Vars");
     339    //pThis->pLastVarNode                         = NULL;
     340    pThis->idxLastVar                           = UINT32_MAX / 2;
     341
     342    pDrvIns->IBase.pfnQueryInterface            = Nvram::drvNvram_QueryInterface;
     343    pThis->INvramConnector.pfnVarQueryByIndex   = drvNvram_VarQueryByIndex;
     344    pThis->INvramConnector.pfnVarStoreSeqBegin  = drvNvram_VarStoreSeqBegin;
     345    pThis->INvramConnector.pfnVarStoreSeqPut    = drvNvram_VarStoreSeqPut;
     346    pThis->INvramConnector.pfnVarStoreSeqEnd    = drvNvram_VarStoreSeqEnd;
     347
     348    /*
     349     * Validate and read configuration.
     350     */
    255351    if (!CFGMR3AreValuesValid(pCfg, "Object\0"
    256352                                    "PermanentSave\0"))
     
    260356                    VERR_PDM_DRVINS_NO_ATTACH);
    261357
    262     void *pv;
    263     int rc = CFGMR3QueryPtr(pCfg, "Object", &pv);
     358    int rc = CFGMR3QueryPtr(pCfg, "Object", (void **)&pThis->pNvram);
    264359    AssertMsgRCReturn(rc, ("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc), rc);
    265     pThis->pNvram = (Nvram *)pv;
    266 
    267     bool fPermanentSave = false;
    268     rc = CFGMR3QueryBool(pCfg, "PermanentSave", &fPermanentSave);
    269     if (   RT_SUCCESS(rc)
    270         || rc == VERR_CFGM_VALUE_NOT_FOUND)
    271         pThis->fPermanentSave = fPermanentSave;
    272     else
    273         AssertRCReturn(rc, rc);
    274 
    275     pDrvIns->IBase.pfnQueryInterface = Nvram::drvNvram_QueryInterface;
    276     pThis->INvram.pfnFlushNvramStorage = drvNvram_pfnFlushNvramStorage;
    277     pThis->INvram.pfnStoreNvramValue = drvNvram_pfnStoreNvramValue;
    278     pThis->INvram.pfnLoadNvramValue = drvNvram_pfnLoadNvramValue;
     360
     361    rc = CFGMR3QueryBoolDef(pCfg, "PermanentSave", &pThis->fPermanentSave, false);
     362    AssertRCReturn(rc, rc);
     363
     364    /*
     365     * Let the associated class instance know about us.
     366     */
     367    pThis->pNvram->mpDrv = pThis;
    279368
    280369    return VINF_SUCCESS;
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette