VirtualBox

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

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