VirtualBox

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

Last change on this file since 62485 was 62485, checked in by vboxsync, 8 years ago

(C) 2016

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