VirtualBox

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

Last change on this file since 44591 was 44591, checked in by vboxsync, 12 years ago

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

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.2 KB
Line 
1/* $Id: Nvram.cpp 44591 2013-02-08 04:48:00Z vboxsync $ */
2/** @file
3 * VBox NVRAM COM Class implementation.
4 */
5
6/*
7 * Copyright (C) 2012-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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 * Constructor/destructor
72 */
73Nvram::Nvram(Console *pConsole)
74 : mParent(pConsole),
75 mpDrv(NULL)
76{
77}
78
79Nvram::~Nvram()
80{
81 if (mpDrv)
82 {
83 mpDrv->pNvram = NULL;
84 mpDrv = NULL;
85 }
86}
87
88
89/**
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);
182 LogFlowFuncLeaveRC(rc);
183 return rc;
184}
185
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);
239 return rc;
240}
241
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)
264 return VERR_NOT_FOUND;
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;
294}
295
296
297/**
298 * @interface_method_impl(PDMIBASE,pfnQueryInterface)
299 */
300DECLCALLBACK(void *) Nvram::drvNvram_QueryInterface(PPDMIBASE pInterface, const char *pszIID)
301{
302 LogFlow(("%s pInterface:%p, pszIID:%s\n", __FUNCTION__, pInterface, pszIID));
303 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
304 PNVRAM pThis = PDMINS_2_DATA(pDrvIns, PNVRAM);
305
306 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
307 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINVRAMCONNECTOR, &pThis->INvramConnector);
308 return NULL;
309}
310
311
312/**
313 * @interface_method_impl(PDMDRVREG,pfnDestruct)
314 */
315DECLCALLBACK(void) Nvram::drvNvram_Destruct(PPDMDRVINS pDrvIns)
316{
317 LogFlow(("%s: iInstance/#d\n", __FUNCTION__, pDrvIns->iInstance));
318 PNVRAM pThis = PDMINS_2_DATA(pDrvIns, PNVRAM);
319 if (pThis->pNvram != NULL)
320 pThis->pNvram->mpDrv = NULL;
321}
322
323
324/**
325 * @interface_method_impl(PDMDRVREG,pfnConstruct)
326 */
327DECLCALLBACK(int) Nvram::drvNvram_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
328{
329 LogFlowFunc(("iInstance/#d, pCfg:%p, fFlags:%x\n", pDrvIns->iInstance, pCfg, fFlags));
330 PNVRAM pThis = PDMINS_2_DATA(pDrvIns, PNVRAM);
331
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 */
351 if (!CFGMR3AreValuesValid(pCfg, "Object\0"
352 "PermanentSave\0"))
353 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
354 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
355 ("Configuration error: Not possible to attach anything to this driver!\n"),
356 VERR_PDM_DRVINS_NO_ATTACH);
357
358 int rc = CFGMR3QueryPtr(pCfg, "Object", (void **)&pThis->pNvram);
359 AssertMsgRCReturn(rc, ("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc), rc);
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;
368
369 return VINF_SUCCESS;
370}
371
372
373const PDMDRVREG Nvram::DrvReg =
374{
375 /* u32Version */
376 PDM_DRVREG_VERSION,
377 /* szName[32] */
378 "NvramStorage",
379 /* szRCMod[32] */
380 "",
381 /* szR0Mod[32] */
382 "",
383 /* pszDescription */
384 "NVRAM Main Driver",
385 /* fFlags */
386 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
387 /* fClass */
388 PDM_DRVREG_CLASS_VMMDEV,
389 /* cMaxInstances */
390 1,
391 /* cbInstance */
392 sizeof(NVRAM),
393 /* pfnConstruct */
394 Nvram::drvNvram_Construct,
395 /* pfnDestruct */
396 Nvram::drvNvram_Destruct,
397 /* pfnRelocate */
398 NULL,
399 /* pfnIOCtl */
400 NULL,
401 /* pfnPowerOn */
402 NULL,
403 /* pfnReset */
404 NULL,
405 /* pfnSuspend */
406 NULL,
407 /* pfnResume */
408 NULL,
409 /* pfnAttach */
410 NULL,
411 /* pfnDetach */
412 NULL,
413 /* pfnPowerOff */
414 NULL,
415 /* pfnSoftReset */
416 NULL,
417 /* u32VersionEnd */
418 PDM_DRVREG_VERSION
419};
420/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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