VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/Nvram.cpp@ 56994

Last change on this file since 56994 was 56994, checked in by vboxsync, 9 years ago

Main: Log and assert formatting fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.0 KB
Line 
1/* $Id: Nvram.cpp 56994 2015-07-18 23:15:01Z vboxsync $ */
2/** @file
3 * VBox NVRAM COM Class implementation.
4 */
5
6/*
7 * Copyright (C) 2012-2014 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#include "Nvram.h"
22#include "ConsoleImpl.h"
23#include "Global.h"
24
25#include <VBox/vmm/pdm.h>
26#include <VBox/vmm/pdmdrv.h>
27#include <VBox/vmm/pdmnvram.h>
28#include <VBox/vmm/cfgm.h>
29#include <VBox/log.h>
30#include <VBox/err.h>
31#include <iprt/assert.h>
32#include <iprt/critsect.h>
33#include <iprt/mem.h>
34#include <iprt/string.h>
35#include <iprt/uuid.h>
36#include <iprt/base64.h>
37#include <VBox/version.h>
38#include <iprt/file.h>
39#include <iprt/semaphore.h>
40
41
42/*******************************************************************************
43* Structures and Typedefs *
44*******************************************************************************/
45typedef struct NVRAM NVRAM;
46typedef struct NVRAM *PNVRAM;
47
48/**
49 * Intstance data associated with PDMDRVINS.
50 */
51struct NVRAM
52{
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;
67};
68
69
70/*******************************************************************************
71* Defined Constants And Macros *
72*******************************************************************************/
73/** The default NVRAM attribute value (non-volatile, boot servier access,
74 runtime access). */
75#define NVRAM_DEFAULT_ATTRIB UINT32_C(0x7)
76/** The CFGM overlay path of the NVRAM variables. */
77#define NVRAM_CFGM_OVERLAY_PATH "VBoxInternal/Devices/efi/0/LUN#0/Config/Vars"
78
79/**
80 * Constructor/destructor
81 */
82Nvram::Nvram(Console *pConsole)
83 : mParent(pConsole),
84 mpDrv(NULL)
85{
86}
87
88Nvram::~Nvram()
89{
90 if (mpDrv)
91 {
92 mpDrv->pNvram = NULL;
93 mpDrv = NULL;
94 }
95}
96
97
98/**
99 * @interface_method_impl(PDMINVRAM,pfnVarStoreSeqEnd)
100 */
101DECLCALLBACK(int) drvNvram_VarStoreSeqEnd(PPDMINVRAMCONNECTOR pInterface, int rc)
102{
103 NOREF(pInterface);
104 return rc;
105}
106
107/**
108 * Converts the binary to a CFGM overlay binary string.
109 *
110 * @returns Pointer to a heap buffer (hand it to RTMemFree when done).
111 * @param pvBuf The binary data to convert.
112 * @param cbBuf The number of bytes to convert.
113 */
114static char *drvNvram_binaryToCfgmString(void const *pvBuf, size_t cbBuf)
115{
116 static char s_szPrefix[] = "bytes:";
117 size_t cbStr = RTBase64EncodedLength(cbBuf) + sizeof(s_szPrefix);
118 char *pszStr = (char *)RTMemAlloc(cbStr);
119 if (pszStr)
120 {
121 memcpy(pszStr, s_szPrefix, sizeof(s_szPrefix) - 1);
122 int rc = RTBase64Encode(pvBuf, cbBuf, &pszStr[sizeof(s_szPrefix) - 1], cbStr - sizeof(s_szPrefix) + 1, NULL);
123 if (RT_FAILURE(rc))
124 {
125 RTMemFree(pszStr);
126 pszStr = NULL;
127 }
128 }
129 return pszStr;
130}
131
132/**
133 * @interface_method_impl(PDMINVRAM,pfnVarStoreSeqPut)
134 */
135DECLCALLBACK(int) drvNvram_VarStoreSeqPut(PPDMINVRAMCONNECTOR pInterface, int idxVariable,
136 PCRTUUID pVendorUuid, const char *pszName, size_t cchName,
137 uint32_t fAttributes, uint8_t const *pbValue, size_t cbValue)
138{
139 PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvramConnector);
140 int rc = VINF_SUCCESS;
141
142 if (pThis->fPermanentSave && pThis->pNvram)
143 {
144 char szExtraName[256];
145 size_t offValueNm = RTStrPrintf(szExtraName, sizeof(szExtraName) - 16,
146 NVRAM_CFGM_OVERLAY_PATH "/%04u/", idxVariable);
147
148 char szUuid[RTUUID_STR_LENGTH];
149 int rc2 = RTUuidToStr(pVendorUuid, szUuid, sizeof(szUuid)); AssertRC(rc2);
150
151 char szAttribs[32];
152 if (fAttributes != NVRAM_DEFAULT_ATTRIB)
153 RTStrPrintf(szAttribs, sizeof(szAttribs), "%#x", fAttributes);
154 else
155 szAttribs[0] = '\0';
156
157 char *pszValue = drvNvram_binaryToCfgmString(pbValue, cbValue);
158 if (pszValue)
159 {
160 const char *apszTodo[] =
161 {
162 "Name", pszName,
163 "Uuid", szUuid,
164 "Value", pszValue,
165 "Attribs", szAttribs,
166 };
167 for (unsigned i = 0; i < RT_ELEMENTS(apszTodo); i += 2)
168 {
169 if (!apszTodo[i + 1][0])
170 continue;
171
172 Assert(strlen(apszTodo[i]) < 16);
173 strcpy(szExtraName + offValueNm, apszTodo[i]);
174 try
175 {
176 HRESULT hrc = pThis->pNvram->getParent()->i_machine()->SetExtraData(Bstr(szExtraName).raw(),
177 Bstr(apszTodo[i + 1]).raw());
178 if (FAILED(hrc))
179 {
180 LogRel(("drvNvram_deleteVar: SetExtraData(%s,%s) returned %Rhrc\n", szExtraName, apszTodo[i + 1], hrc));
181 rc = Global::vboxStatusCodeFromCOM(hrc);
182 }
183 }
184 catch (...)
185 {
186 LogRel(("drvNvram_deleteVar: SetExtraData(%s,%s) threw exception\n", szExtraName, apszTodo[i + 1]));
187 rc = VERR_UNEXPECTED_EXCEPTION;
188 }
189 }
190 }
191 else
192 rc = VERR_NO_MEMORY;
193 RTMemFree(pszValue);
194 }
195
196 NOREF(cchName);
197 LogFlowFuncLeaveRC(rc);
198 return rc;
199}
200
201/**
202 * Deletes a variable.
203 *
204 * @param pThis The NVRAM driver instance data.
205 * @param pszVarNodeNm The variable node name.
206 */
207static void drvNvram_deleteVar(PNVRAM pThis, const char *pszVarNodeNm)
208{
209 char szExtraName[256];
210 size_t offValue = RTStrPrintf(szExtraName, sizeof(szExtraName) - 16, NVRAM_CFGM_OVERLAY_PATH "/%s/", pszVarNodeNm);
211 static const char *s_apszValueNames[] = { "Name", "Uuid", "Value", "Attribs" };
212 for (unsigned i = 0; i < RT_ELEMENTS(s_apszValueNames); i++)
213 {
214 Assert(strlen(s_apszValueNames[i]) < 16);
215 strcpy(szExtraName + offValue, s_apszValueNames[i]);
216 try
217 {
218 HRESULT hrc = pThis->pNvram->getParent()->i_machine()->SetExtraData(Bstr(szExtraName).raw(), Bstr().raw());
219 if (FAILED(hrc))
220 LogRel(("drvNvram_deleteVar: SetExtraData(%s,) returned %Rhrc\n", szExtraName, hrc));
221 }
222 catch (...)
223 {
224 LogRel(("drvNvram_deleteVar: SetExtraData(%s,) threw exception\n", szExtraName));
225 }
226 }
227}
228
229/**
230 * @interface_method_impl(PDMINVRAM,pfnVarStoreSeqBegin)
231 */
232DECLCALLBACK(int) drvNvram_VarStoreSeqBegin(PPDMINVRAMCONNECTOR pInterface, uint32_t cVariables)
233{
234 PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvramConnector);
235 int rc = VINF_SUCCESS;
236 if (pThis->fPermanentSave && pThis->pNvram)
237 {
238 /*
239 * Remove all existing variables.
240 */
241 for (PCFGMNODE pVarNode = CFGMR3GetFirstChild(pThis->pCfgVarRoot); pVarNode; pVarNode = CFGMR3GetNextChild(pVarNode))
242 {
243 char szName[128];
244 rc = CFGMR3GetName(pVarNode, szName, sizeof(szName));
245 if (RT_SUCCESS(rc))
246 drvNvram_deleteVar(pThis, szName);
247 else
248 LogRel(("drvNvram_VarStoreSeqBegin: CFGMR3GetName -> %Rrc\n", rc));
249 }
250 }
251
252 NOREF(cVariables);
253 return rc;
254}
255
256/**
257 * @interface_method_impl(PDMINVRAMCONNECTOR,pfnVarQueryByIndex)
258 */
259DECLCALLBACK(int) drvNvram_VarQueryByIndex(PPDMINVRAMCONNECTOR pInterface, uint32_t idxVariable,
260 PRTUUID pVendorUuid, char *pszName, uint32_t *pcchName,
261 uint32_t *pfAttributes, uint8_t *pbValue, uint32_t *pcbValue)
262{
263 PNVRAM pThis = RT_FROM_MEMBER(pInterface, NVRAM, INvramConnector);
264
265 /*
266 * Find the requested variable node.
267 */
268 PCFGMNODE pVarNode;
269 if (pThis->idxLastVar + 1 == idxVariable && pThis->pLastVarNode)
270 pVarNode = CFGMR3GetNextChild(pThis->pLastVarNode);
271 else
272 {
273 pVarNode = CFGMR3GetFirstChild(pThis->pCfgVarRoot);
274 for (uint32_t i = 0; i < idxVariable && pVarNode; i++)
275 pVarNode = CFGMR3GetNextChild(pVarNode);
276 }
277 if (!pVarNode)
278 return VERR_NOT_FOUND;
279
280 /* cache it */
281 pThis->pLastVarNode = pVarNode;
282 pThis->idxLastVar = idxVariable;
283
284 /*
285 * Read the variable node.
286 */
287 int rc = CFGMR3QueryString(pVarNode, "Name", pszName, *pcchName);
288 AssertRCReturn(rc, rc);
289 *pcchName = (uint32_t)strlen(pszName);
290
291 char szUuid[RTUUID_STR_LENGTH];
292 rc = CFGMR3QueryString(pVarNode, "Uuid", szUuid, sizeof(szUuid));
293 AssertRCReturn(rc, rc);
294 rc = RTUuidFromStr(pVendorUuid, szUuid);
295 AssertRCReturn(rc, rc);
296
297 rc = CFGMR3QueryU32Def(pVarNode, "Attribs", pfAttributes, NVRAM_DEFAULT_ATTRIB);
298 AssertRCReturn(rc, rc);
299
300 size_t cbValue;
301 rc = CFGMR3QuerySize(pVarNode, "Value", &cbValue);
302 AssertRCReturn(rc, rc);
303 AssertReturn(cbValue <= *pcbValue, VERR_BUFFER_OVERFLOW);
304 rc = CFGMR3QueryBytes(pVarNode, "Value", pbValue, cbValue);
305 AssertRCReturn(rc, rc);
306 *pcbValue = (uint32_t)cbValue;
307
308 return VINF_SUCCESS;
309}
310
311
312/**
313 * @interface_method_impl(PDMIBASE,pfnQueryInterface)
314 */
315DECLCALLBACK(void *) Nvram::drvNvram_QueryInterface(PPDMIBASE pInterface, const char *pszIID)
316{
317 LogFlowFunc(("pInterface=%p pszIID=%s\n", pInterface, pszIID));
318 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
319 PNVRAM pThis = PDMINS_2_DATA(pDrvIns, PNVRAM);
320
321 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
322 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINVRAMCONNECTOR, &pThis->INvramConnector);
323 return NULL;
324}
325
326
327/**
328 * @interface_method_impl(PDMDRVREG,pfnDestruct)
329 */
330DECLCALLBACK(void) Nvram::drvNvram_Destruct(PPDMDRVINS pDrvIns)
331{
332 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
333 LogFlowFunc(("iInstance/#%d\n", pDrvIns->iInstance));
334 PNVRAM pThis = PDMINS_2_DATA(pDrvIns, PNVRAM);
335 if (pThis->pNvram != NULL)
336 pThis->pNvram->mpDrv = NULL;
337}
338
339
340/**
341 * @interface_method_impl(PDMDRVREG,pfnConstruct)
342 */
343DECLCALLBACK(int) Nvram::drvNvram_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
344{
345 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
346 LogFlowFunc(("iInstance/#%d pCfg=%p fFlags=%x\n", pDrvIns->iInstance, pCfg, fFlags));
347 PNVRAM pThis = PDMINS_2_DATA(pDrvIns, PNVRAM);
348
349 /*
350 * Initalize instance data variables first.
351 */
352 //pThis->pNvram = NULL;
353 //pThis->cLoadedVariables = 0;
354 //pThis->fPermanentSave = false;
355 pThis->pCfgVarRoot = CFGMR3GetChild(pCfg, "Vars");
356 //pThis->pLastVarNode = NULL;
357 pThis->idxLastVar = UINT32_MAX / 2;
358
359 pDrvIns->IBase.pfnQueryInterface = Nvram::drvNvram_QueryInterface;
360 pThis->INvramConnector.pfnVarQueryByIndex = drvNvram_VarQueryByIndex;
361 pThis->INvramConnector.pfnVarStoreSeqBegin = drvNvram_VarStoreSeqBegin;
362 pThis->INvramConnector.pfnVarStoreSeqPut = drvNvram_VarStoreSeqPut;
363 pThis->INvramConnector.pfnVarStoreSeqEnd = drvNvram_VarStoreSeqEnd;
364
365 /*
366 * Validate and read configuration.
367 */
368 if (!CFGMR3AreValuesValid(pCfg, "Object\0"
369 "PermanentSave\0"))
370 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
371 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
372 ("Configuration error: Not possible to attach anything to this driver!\n"),
373 VERR_PDM_DRVINS_NO_ATTACH);
374
375 int rc = CFGMR3QueryPtr(pCfg, "Object", (void **)&pThis->pNvram);
376 AssertMsgRCReturn(rc, ("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc), rc);
377
378 rc = CFGMR3QueryBoolDef(pCfg, "PermanentSave", &pThis->fPermanentSave, false);
379 AssertRCReturn(rc, rc);
380
381 /*
382 * Let the associated class instance know about us.
383 */
384 pThis->pNvram->mpDrv = pThis;
385
386 return VINF_SUCCESS;
387}
388
389
390const PDMDRVREG Nvram::DrvReg =
391{
392 /* u32Version */
393 PDM_DRVREG_VERSION,
394 /* szName[32] */
395 "NvramStorage",
396 /* szRCMod[32] */
397 "",
398 /* szR0Mod[32] */
399 "",
400 /* pszDescription */
401 "NVRAM Main Driver",
402 /* fFlags */
403 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
404 /* fClass */
405 PDM_DRVREG_CLASS_VMMDEV,
406 /* cMaxInstances */
407 1,
408 /* cbInstance */
409 sizeof(NVRAM),
410 /* pfnConstruct */
411 Nvram::drvNvram_Construct,
412 /* pfnDestruct */
413 Nvram::drvNvram_Destruct,
414 /* pfnRelocate */
415 NULL,
416 /* pfnIOCtl */
417 NULL,
418 /* pfnPowerOn */
419 NULL,
420 /* pfnReset */
421 NULL,
422 /* pfnSuspend */
423 NULL,
424 /* pfnResume */
425 NULL,
426 /* pfnAttach */
427 NULL,
428 /* pfnDetach */
429 NULL,
430 /* pfnPowerOff */
431 NULL,
432 /* pfnSoftReset */
433 NULL,
434 /* u32VersionEnd */
435 PDM_DRVREG_VERSION
436};
437/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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