VirtualBox

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

Last change on this file since 69500 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use