VirtualBox

source: vbox/trunk/src/VBox/Main/src-all/NvramStoreImpl.cpp@ 91406

Last change on this file since 91406 was 91396, checked in by vboxsync, 3 years ago

Main: Add IUefiVariableStore interface to manage the content of the UEFI variable store for secure boot support, bugref:9580

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.2 KB
Line 
1/* $Id: NvramStoreImpl.cpp 91396 2021-09-27 13:40:35Z vboxsync $ */
2/** @file
3 * VirtualBox COM NVRAM store class implementation
4 */
5
6/*
7 * Copyright (C) 2021 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#define LOG_GROUP LOG_GROUP_MAIN_NVRAMSTORE
19#include "LoggingNew.h"
20
21#include "NvramStoreImpl.h"
22#ifdef VBOX_COM_INPROC
23# include "ConsoleImpl.h"
24#else
25# include "MachineImpl.h"
26# include "AutoStateDep.h"
27#endif
28#include "UefiVariableStoreImpl.h"
29
30#include "AutoCaller.h"
31
32#include <VBox/com/array.h>
33#include <VBox/vmm/pdmdrv.h>
34#include <VBox/err.h>
35
36#include <iprt/cpp/utils.h>
37#include <iprt/efi.h>
38#include <iprt/file.h>
39#include <iprt/vfs.h>
40#include <iprt/zip.h>
41
42
43// defines
44////////////////////////////////////////////////////////////////////////////////
45
46// globals
47////////////////////////////////////////////////////////////////////////////////
48
49/**
50 * NVRAM store driver instance data.
51 */
52typedef struct DRVMAINNVRAMSTORE
53{
54 /** Pointer to the keyboard object. */
55 NvramStore *pNvramStore;
56 /** Pointer to the driver instance structure. */
57 PPDMDRVINS pDrvIns;
58 /** Our VFS connector interface. */
59 PDMIVFSCONNECTOR IVfs;
60} DRVMAINNVRAMSTORE, *PDRVMAINNVRAMSTORE;
61
62/** The NVRAM store map keyed by namespace/entity. */
63typedef std::map<Utf8Str, RTVFSFILE> NvramStoreMap;
64/** The NVRAM store map iterator. */
65typedef std::map<Utf8Str, RTVFSFILE>::iterator NvramStoreIter;
66
67struct BackupableNvramStoreData
68{
69 BackupableNvramStoreData()
70 { }
71
72 /** The NVRAM file path. */
73 com::Utf8Str strNvramPath;
74 /** The NVRAM store. */
75 NvramStoreMap mapNvram;
76};
77
78/////////////////////////////////////////////////////////////////////////////
79// NvramStore::Data structure
80/////////////////////////////////////////////////////////////////////////////
81
82struct NvramStore::Data
83{
84 Data()
85 : pParent(NULL)
86#ifdef VBOX_COM_INPROC
87 , cRefs(0)
88#endif
89 { }
90
91#ifdef VBOX_COM_INPROC
92 /** The Console owning this NVRAM store. */
93 Console * const pParent;
94 /** Number of references held to this NVRAM store from the various devices/drivers. */
95 volatile uint32_t cRefs;
96#else
97 /** The Machine object owning this NVRAM store. */
98 Machine * const pParent;
99 /** The peer NVRAM store object. */
100 ComObjPtr<NvramStore> pPeer;
101 /** The UEFI variable store. */
102 const ComObjPtr<UefiVariableStore> pUefiVarStore;
103#endif
104
105 Backupable<BackupableNvramStoreData> bd;
106};
107
108// constructor / destructor
109////////////////////////////////////////////////////////////////////////////////
110
111DEFINE_EMPTY_CTOR_DTOR(NvramStore)
112
113HRESULT NvramStore::FinalConstruct()
114{
115 return BaseFinalConstruct();
116}
117
118void NvramStore::FinalRelease()
119{
120 uninit();
121 BaseFinalRelease();
122}
123
124// public initializer/uninitializer for internal purposes only
125/////////////////////////////////////////////////////////////////////////////
126
127#if !defined(VBOX_COM_INPROC)
128/**
129 * Initializes the NVRAM store object.
130 *
131 * @returns COM result indicator
132 */
133HRESULT NvramStore::init(Machine *aParent)
134{
135 LogFlowThisFuncEnter();
136 LogFlowThisFunc(("aParent: %p\n", aParent));
137
138 ComAssertRet(aParent, E_INVALIDARG);
139
140 /* Enclose the state transition NotReady->InInit->Ready */
141 AutoInitSpan autoInitSpan(this);
142 AssertReturn(autoInitSpan.isOk(), E_FAIL);
143
144 m = new Data();
145
146 /* share the parent weakly */
147 unconst(m->pParent) = aParent;
148
149 m->bd.allocate();
150
151 autoInitSpan.setSucceeded();
152
153 LogFlowThisFuncLeave();
154 return S_OK;
155}
156
157/**
158 * Initializes the NVRAM store object given another NVRAM store object
159 * (a kind of copy constructor). This object shares data with
160 * the object passed as an argument.
161 *
162 * @note This object must be destroyed before the original object
163 * it shares data with is destroyed.
164 */
165HRESULT NvramStore::init(Machine *aParent, NvramStore *that)
166{
167 LogFlowThisFuncEnter();
168 LogFlowThisFunc(("aParent: %p, that: %p\n", aParent, that));
169
170 ComAssertRet(aParent && that, E_INVALIDARG);
171
172 /* Enclose the state transition NotReady->InInit->Ready */
173 AutoInitSpan autoInitSpan(this);
174 AssertReturn(autoInitSpan.isOk(), E_FAIL);
175
176 m = new Data();
177
178 unconst(m->pParent) = aParent;
179 m->pPeer = that;
180
181 AutoWriteLock thatlock(that COMMA_LOCKVAL_SRC_POS);
182 m->bd.share(that->m->bd);
183
184 autoInitSpan.setSucceeded();
185
186 LogFlowThisFuncLeave();
187 return S_OK;
188}
189
190/**
191 * Initializes the guest object given another guest object
192 * (a kind of copy constructor). This object makes a private copy of data
193 * of the original object passed as an argument.
194 */
195HRESULT NvramStore::initCopy(Machine *aParent, NvramStore *that)
196{
197 LogFlowThisFuncEnter();
198 LogFlowThisFunc(("aParent: %p, that: %p\n", aParent, that));
199
200 ComAssertRet(aParent && that, E_INVALIDARG);
201
202 /* Enclose the state transition NotReady->InInit->Ready */
203 AutoInitSpan autoInitSpan(this);
204 AssertReturn(autoInitSpan.isOk(), E_FAIL);
205
206 m = new Data();
207
208 unconst(m->pParent) = aParent;
209 // mPeer is left null
210
211 AutoWriteLock thatlock(that COMMA_LOCKVAL_SRC_POS);
212 m->bd.attachCopy(that->m->bd);
213
214 autoInitSpan.setSucceeded();
215
216 LogFlowThisFuncLeave();
217 return S_OK;
218}
219
220#else
221
222/**
223 * Initializes the NVRAM store object.
224 *
225 * @returns COM result indicator
226 * @param aParent Handle of our parent object
227 * @param strNonVolatileStorageFile The NVRAM file path.
228 */
229HRESULT NvramStore::init(Console *aParent, const com::Utf8Str &strNonVolatileStorageFile)
230{
231 LogFlowThisFunc(("aParent=%p\n", aParent));
232
233 ComAssertRet(aParent, E_INVALIDARG);
234
235 /* Enclose the state transition NotReady->InInit->Ready */
236 AutoInitSpan autoInitSpan(this);
237 AssertReturn(autoInitSpan.isOk(), E_FAIL);
238
239 m = new Data();
240 unconst(m->pParent) = aParent;
241
242 m->bd.allocate();
243 m->bd->strNvramPath = strNonVolatileStorageFile;
244
245 /* Confirm a successful initialization */
246 autoInitSpan.setSucceeded();
247
248 return S_OK;
249}
250#endif /* VBOX_COM_INPROC */
251
252
253/**
254 * Uninitializes the instance and sets the ready flag to FALSE.
255 * Called either from FinalRelease() or by the parent when it gets destroyed.
256 */
257void NvramStore::uninit()
258{
259 LogFlowThisFuncEnter();
260
261 /* Enclose the state transition Ready->InUninit->NotReady */
262 AutoUninitSpan autoUninitSpan(this);
263 if (autoUninitSpan.uninitDone())
264 return;
265
266 unconst(m->pParent) = NULL;
267
268 /* Delete the NVRAM content. */
269 NvramStoreIter it = m->bd->mapNvram.begin();
270 while (it != m->bd->mapNvram.end())
271 {
272 RTVfsFileRelease(it->second);
273 it++;
274 }
275
276 m->bd->mapNvram.clear();
277
278 delete m;
279 m = NULL;
280
281 LogFlowThisFuncLeave();
282}
283
284
285HRESULT NvramStore::getNonVolatileStorageFile(com::Utf8Str &aNonVolatileStorageFile)
286{
287#ifndef VBOX_COM_INPROC
288 Utf8Str strTmp;
289 {
290 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
291 strTmp = m->bd->strNvramPath;
292 }
293
294 AutoReadLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
295 if (strTmp.isEmpty())
296 strTmp = m->pParent->i_getDefaultNVRAMFilename();
297 if (strTmp.isNotEmpty())
298 m->pParent->i_calculateFullPath(strTmp, aNonVolatileStorageFile);
299#else
300 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
301 aNonVolatileStorageFile = m->bd->strNvramPath;
302#endif
303
304 return S_OK;
305}
306
307
308HRESULT NvramStore::getUefiVariableStore(ComPtr<IUefiVariableStore> &aUefiVarStore)
309{
310#ifndef VBOX_COM_INPROC
311 /* the machine needs to be mutable */
312 AutoMutableStateDependency adep(m->pParent);
313 if (FAILED(adep.rc())) return adep.rc();
314
315 /* We need a write lock because of the lazy initialization. */
316 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
317
318 /* Check if we have to create the UEFI variabel store object */
319 HRESULT hrc = S_OK;
320 if (!m->pUefiVarStore)
321 {
322 /* Load the NVRAM file first if it isn't already. */
323 if (!m->bd->mapNvram.size())
324 {
325 int vrc = i_loadStore();
326 if (RT_FAILURE(vrc))
327 hrc = setError(E_FAIL, tr("Loading the NVRAM store failed (%Rrc)\n"), vrc);
328 }
329
330 if (SUCCEEDED(hrc))
331 {
332 NvramStoreIter it = m->bd->mapNvram.find("efi/nvram");
333 if (it != m->bd->mapNvram.end())
334 {
335 RTVFSFILE hVfsFileNvram = it->second;
336 RTVFS hVfsEfiVarStore;
337 int vrc = RTEfiVarStoreOpenAsVfs(hVfsFileNvram, 0 /*fMntFlags*/, 0 /*fVarStoreFlags*/, &hVfsEfiVarStore,
338 NULL /*pErrInfo*/);
339 if (RT_SUCCESS(vrc))
340 {
341 unconst(m->pUefiVarStore).createObject();
342 m->pUefiVarStore->init(this, m->pParent, hVfsEfiVarStore);
343 }
344 else
345 hrc = setError(E_FAIL, tr("Opening the UEFI variable store failed (%Rrc)."), vrc);
346 }
347 else
348 hrc = setError(VBOX_E_OBJECT_NOT_FOUND, tr("The UEFI NVRAM file is not existing for this machine."));
349 }
350 }
351
352 if (SUCCEEDED(hrc))
353 m->pUefiVarStore.queryInterfaceTo(aUefiVarStore.asOutParam());
354
355 return hrc;
356#else
357 NOREF(aUefiVarStore);
358 return E_NOTIMPL;
359#endif
360}
361
362
363HRESULT NvramStore::initUefiVariableStore(ULONG aSize)
364{
365 NOREF(aSize);
366 return E_NOTIMPL;
367}
368
369
370Utf8Str NvramStore::i_getNonVolatileStorageFile()
371{
372 AutoCaller autoCaller(this);
373 AssertComRCReturn(autoCaller.rc(), Utf8Str::Empty);
374
375 Utf8Str strTmp;
376 NvramStore::getNonVolatileStorageFile(strTmp);
377 return strTmp;
378}
379
380
381/**
382 * Loads the NVRAM store from the given TAR filesystem stream.
383 *
384 * @returns IPRT status code.
385 * @param hVfsFssTar Handle to the tar filesystem stream.
386 */
387int NvramStore::i_loadStoreFromTar(RTVFSFSSTREAM hVfsFssTar)
388{
389 int rc = VINF_SUCCESS;
390
391 /*
392 * Process the stream.
393 */
394 for (;;)
395 {
396 /*
397 * Retrieve the next object.
398 */
399 char *pszName;
400 RTVFSOBJ hVfsObj;
401 rc = RTVfsFsStrmNext(hVfsFssTar, &pszName, NULL, &hVfsObj);
402 if (RT_FAILURE(rc))
403 {
404 if (rc == VERR_EOF)
405 rc = VINF_SUCCESS;
406 break;
407 }
408
409 RTFSOBJINFO UnixInfo;
410 rc = RTVfsObjQueryInfo(hVfsObj, &UnixInfo, RTFSOBJATTRADD_UNIX);
411 if (RT_SUCCESS(rc))
412 {
413 switch (UnixInfo.Attr.fMode & RTFS_TYPE_MASK)
414 {
415 case RTFS_TYPE_FILE:
416 {
417 LogRel(("NvramStore: Loading '%s' from archive\n", pszName));
418 RTVFSIOSTREAM hVfsIosEntry = RTVfsObjToIoStream(hVfsObj);
419 Assert(hVfsIosEntry != NIL_RTVFSIOSTREAM);
420
421 RTVFSFILE hVfsFileEntry;
422 rc = RTVfsMemorizeIoStreamAsFile(hVfsIosEntry, RTFILE_O_READ | RTFILE_O_WRITE, &hVfsFileEntry);
423 if (RT_FAILURE(rc))
424 break;
425 RTVfsIoStrmRelease(hVfsIosEntry);
426
427 m->bd->mapNvram[Utf8Str(pszName)] = hVfsFileEntry;
428 break;
429 }
430 case RTFS_TYPE_DIRECTORY:
431 break;
432 default:
433 rc = VERR_NOT_SUPPORTED;
434 break;
435 }
436 }
437
438 /*
439 * Release the current object and string.
440 */
441 RTVfsObjRelease(hVfsObj);
442 RTStrFree(pszName);
443
444 if (RT_FAILURE(rc))
445 break;
446 }
447
448 return rc;
449}
450
451
452/**
453 * Loads the NVRAM store.
454 *
455 * @returns IPRT status code.
456 */
457int NvramStore::i_loadStore(void)
458{
459 uint64_t cbStore = 0;
460 int rc = RTFileQuerySizeByPath(m->bd->strNvramPath.c_str(), &cbStore);
461 if (RT_SUCCESS(rc))
462 {
463 if (cbStore <= _1M) /* Arbitrary limit to fend off bogus files because the file will be read into memory completely. */
464 {
465 /*
466 * Old NVRAM files just consist of the EFI variable store whereas starting
467 * with VirtualBox 7.0 and the introduction of the TPM the need to handle multiple
468 * independent NVRAM files came up. For those scenarios all NVRAM states are collected
469 * in a tar archive.
470 *
471 * Here we detect whether the file is the new tar archive format or whether it is just
472 * the plain EFI variable store file.
473 */
474 RTVFSIOSTREAM hVfsIosNvram;
475 rc = RTVfsIoStrmOpenNormal(m->bd->strNvramPath.c_str(), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE,
476 &hVfsIosNvram);
477 if (RT_SUCCESS(rc))
478 {
479 /* Read the content. */
480 RTVFSFILE hVfsFileNvram;
481 rc = RTVfsMemorizeIoStreamAsFile(hVfsIosNvram, RTFILE_O_READ, &hVfsFileNvram);
482 if (RT_SUCCESS(rc))
483 {
484 /* Try to parse it as an EFI variable store. */
485 RTVFS hVfsEfiVarStore;
486 rc = RTEfiVarStoreOpenAsVfs(hVfsFileNvram, RTVFSMNT_F_READ_ONLY, 0 /*fVarStoreFlags*/, &hVfsEfiVarStore,
487 NULL /*pErrInfo*/);
488 if (RT_SUCCESS(rc))
489 {
490 rc = RTVfsFileSeek(hVfsFileNvram, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
491 AssertRC(rc);
492
493 RTVfsFileRetain(hVfsFileNvram); /* Retain a new reference for the map. */
494 m->bd->mapNvram[Utf8Str("efi/nvram")] = hVfsFileNvram;
495
496 RTVfsRelease(hVfsEfiVarStore);
497 }
498 else if (rc == VERR_VFS_UNKNOWN_FORMAT)
499 {
500 /* Check for the new style tar archive. */
501 rc = RTVfsFileSeek(hVfsFileNvram, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
502 AssertRC(rc);
503
504 RTVFSIOSTREAM hVfsIosTar = RTVfsFileToIoStream(hVfsFileNvram);
505 Assert(hVfsIosTar != NIL_RTVFSIOSTREAM);
506
507 RTVFSFSSTREAM hVfsFssTar;
508 rc = RTZipTarFsStreamFromIoStream(hVfsIosTar, 0 /*fFlags*/, &hVfsFssTar);
509 RTVfsIoStrmRelease(hVfsIosTar);
510 if (RT_SUCCESS(rc))
511 {
512 rc = i_loadStoreFromTar(hVfsFssTar);
513 RTVfsFsStrmRelease(hVfsFssTar);
514 }
515 else
516 LogRel(("The given NVRAM file is neither a raw UEFI variable store nor a tar archive (opening failed with %Rrc)\n", rc));
517 }
518 else
519 LogRel(("Opening the UEFI variable store '%s' failed with %Rrc\n", m->bd->strNvramPath.c_str(), rc));
520
521 RTVfsFileRelease(hVfsFileNvram);
522 }
523 else
524 LogRel(("Failed to memorize NVRAM store '%s' with %Rrc\n", m->bd->strNvramPath.c_str(), rc));
525
526 RTVfsIoStrmRelease(hVfsIosNvram);
527 }
528 else
529 LogRelMax(10, ("NVRAM store '%s' couldn't be opened with %Rrc\n", m->bd->strNvramPath.c_str(), rc));
530 }
531 else
532 LogRelMax(10, ("NVRAM store '%s' exceeds limit of %u bytes, actual size is %u\n",
533 m->bd->strNvramPath.c_str(), _1M, cbStore));
534 }
535 else if (rc == VERR_FILE_NOT_FOUND) /* Valid for the first run where no NVRAM file is there. */
536 rc = VINF_SUCCESS;
537
538 return rc;
539}
540
541
542/**
543 * Saves the NVRAM store as a tar archive.
544 */
545int NvramStore::i_saveStoreAsTar(void)
546{
547 uint32_t offError = 0;
548 RTERRINFOSTATIC ErrInfo;
549 RTVFSIOSTREAM hVfsIos;
550
551 int rc = RTVfsChainOpenIoStream(m->bd->strNvramPath.c_str(), RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE,
552 &hVfsIos, &offError, RTErrInfoInitStatic(&ErrInfo));
553 if (RT_SUCCESS(rc))
554 {
555 RTVFSFSSTREAM hVfsFss;
556 rc = RTZipTarFsStreamToIoStream(hVfsIos, RTZIPTARFORMAT_GNU, 0 /*fFlags*/, &hVfsFss);
557 if (RT_SUCCESS(rc))
558 {
559 NvramStoreIter it = m->bd->mapNvram.begin();
560
561 while (it != m->bd->mapNvram.end())
562 {
563 RTVFSFILE hVfsFile = it->second;
564
565 rc = RTVfsFileSeek(hVfsFile, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
566 AssertRC(rc);
567
568 RTVFSOBJ hVfsObj = RTVfsObjFromFile(hVfsFile);
569 rc = RTVfsFsStrmAdd(hVfsFss, it->first.c_str(), hVfsObj, 0 /*fFlags*/);
570 RTVfsObjRelease(hVfsObj);
571 if (RT_FAILURE(rc))
572 break;
573
574 it++;
575 }
576
577 RTVfsFsStrmRelease(hVfsFss);
578 }
579
580 RTVfsIoStrmRelease(hVfsIos);
581 }
582
583 return rc;
584}
585
586
587/**
588 * Saves the NVRAM store.
589 *
590 * @returns IPRT status code.
591 */
592int NvramStore::i_saveStore(void)
593{
594 /*
595 * Skip creating the tar archive if only the UEFI NVRAM content is available in order
596 * to maintain backwards compatibility. As soon as there is more than one entry or
597 * it doesn't belong to the UEFI the tar archive will be created.
598 */
599 int rc = VINF_SUCCESS;
600
601 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
602 if ( m->bd->mapNvram.size() == 1
603 && m->bd->mapNvram.find(Utf8Str("efi/nvram")) != m->bd->mapNvram.end())
604 {
605 RTVFSFILE hVfsFileNvram = m->bd->mapNvram[Utf8Str("efi/nvram")];
606
607 rc = RTVfsFileSeek(hVfsFileNvram, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
608 AssertRC(rc); RT_NOREF(rc);
609
610 RTVFSIOSTREAM hVfsIosDst;
611 rc = RTVfsIoStrmOpenNormal(m->bd->strNvramPath.c_str(), RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE,
612 &hVfsIosDst);
613 if (RT_SUCCESS(rc))
614 {
615 RTVFSIOSTREAM hVfsIosSrc = RTVfsFileToIoStream(hVfsFileNvram);
616 Assert(hVfsIosSrc != NIL_RTVFSIOSTREAM);
617
618 rc = RTVfsUtilPumpIoStreams(hVfsIosSrc, hVfsIosDst, 0 /*cbBufHint*/);
619
620 RTVfsIoStrmRelease(hVfsIosSrc);
621 RTVfsIoStrmRelease(hVfsIosDst);
622 }
623 }
624 else if (m->bd->mapNvram.size())
625 rc = i_saveStoreAsTar();
626 /* else: No NVRAM content to store so we are done here. */
627
628 return rc;
629}
630
631
632#ifndef VBOX_COM_INPROC
633/**
634 * Loads settings from the given machine node.
635 * May be called once right after this object creation.
636 *
637 * @param data Configuration settings.
638 *
639 * @note Locks this object for writing.
640 */
641HRESULT NvramStore::i_loadSettings(const settings::NvramSettings &data)
642{
643 AutoCaller autoCaller(this);
644 AssertComRCReturnRC(autoCaller.rc());
645
646 AutoReadLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
647 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
648
649 m->bd->strNvramPath = data.strNvramPath;
650
651 Utf8Str strTmp(m->bd->strNvramPath);
652 if (strTmp.isNotEmpty())
653 m->pParent->i_copyPathRelativeToMachine(strTmp, m->bd->strNvramPath);
654 if ( m->pParent->i_getFirmwareType() == FirmwareType_BIOS
655 || m->bd->strNvramPath == m->pParent->i_getDefaultNVRAMFilename())
656 m->bd->strNvramPath.setNull();
657
658 return S_OK;
659}
660
661/**
662 * Saves settings to the given machine node.
663 *
664 * @param data Configuration settings.
665 *
666 * @note Locks this object for reading.
667 */
668HRESULT NvramStore::i_saveSettings(settings::NvramSettings &data)
669{
670 AutoCaller autoCaller(this);
671 AssertComRCReturnRC(autoCaller.rc());
672
673 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
674
675 data.strNvramPath = m->bd->strNvramPath;
676
677 return S_OK;
678}
679
680void NvramStore::i_rollback()
681{
682 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
683 m->bd.rollback();
684}
685
686void NvramStore::i_commit()
687{
688 /* sanity */
689 AutoCaller autoCaller(this);
690 AssertComRCReturnVoid(autoCaller.rc());
691
692 /* sanity too */
693 AutoCaller peerCaller(m->pPeer);
694 AssertComRCReturnVoid(peerCaller.rc());
695
696 /* lock both for writing since we modify both (mPeer is "master" so locked
697 * first) */
698 AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
699
700 if (m->bd.isBackedUp())
701 {
702 m->bd.commit();
703 if (m->pPeer)
704 {
705 /* attach new data to the peer and reshare it */
706 AutoWriteLock peerlock(m->pPeer COMMA_LOCKVAL_SRC_POS);
707 m->pPeer->m->bd.attach(m->bd);
708 }
709 }
710}
711
712void NvramStore::i_copyFrom(NvramStore *aThat)
713{
714 AssertReturnVoid(aThat != NULL);
715
716 /* sanity */
717 AutoCaller autoCaller(this);
718 AssertComRCReturnVoid(autoCaller.rc());
719
720 /* sanity too */
721 AutoCaller thatCaller(aThat);
722 AssertComRCReturnVoid(thatCaller.rc());
723
724 /* peer is not modified, lock it for reading (aThat is "master" so locked
725 * first) */
726 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
727 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
728
729 /* this will back up current data */
730 m->bd.assignCopy(aThat->m->bd);
731
732 // Intentionally "forget" the NVRAM file since it must be unique and set
733 // to the correct value before the copy of the settings makes sense.
734 m->bd->strNvramPath.setNull();
735}
736
737void NvramStore::i_updateNonVolatileStorageFile(const Utf8Str &aNonVolatileStorageFile)
738{
739 /* sanity */
740 AutoCaller autoCaller(this);
741 AssertComRCReturnVoid(autoCaller.rc());
742
743 AutoReadLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
744 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
745
746 Utf8Str strTmp(aNonVolatileStorageFile);
747 if (strTmp == m->pParent->i_getDefaultNVRAMFilename())
748 strTmp.setNull();
749
750 if (strTmp == m->bd->strNvramPath)
751 return;
752
753 m->bd.backup();
754 m->bd->strNvramPath = strTmp;
755}
756
757#else
758//
759// private methods
760//
761/*static*/
762DECLCALLBACK(int) NvramStore::i_nvramStoreQuerySize(PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath,
763 uint64_t *pcb)
764{
765 PDRVMAINNVRAMSTORE pThis = RT_FROM_MEMBER(pInterface, DRVMAINNVRAMSTORE, IVfs);
766
767 AutoReadLock rlock(pThis->pNvramStore COMMA_LOCKVAL_SRC_POS);
768 NvramStoreIter it = pThis->pNvramStore->m->bd->mapNvram.find(Utf8StrFmt("%s/%s", pszNamespace, pszPath));
769 if (it != pThis->pNvramStore->m->bd->mapNvram.end())
770 {
771 RTVFSFILE hVfsFile = it->second;
772 return RTVfsFileQuerySize(hVfsFile, pcb);
773 }
774
775 return VERR_NOT_FOUND;
776}
777
778
779/*static*/
780DECLCALLBACK(int) NvramStore::i_nvramStoreReadAll(PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath,
781 void *pvBuf, size_t cbRead)
782{
783 PDRVMAINNVRAMSTORE pThis = RT_FROM_MEMBER(pInterface, DRVMAINNVRAMSTORE, IVfs);
784
785 AutoReadLock rlock(pThis->pNvramStore COMMA_LOCKVAL_SRC_POS);
786 NvramStoreIter it = pThis->pNvramStore->m->bd->mapNvram.find(Utf8StrFmt("%s/%s", pszNamespace, pszPath));
787 if (it != pThis->pNvramStore->m->bd->mapNvram.end())
788 {
789 RTVFSFILE hVfsFile = it->second;
790
791 int rc = RTVfsFileSeek(hVfsFile, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
792 AssertRC(rc); RT_NOREF(rc);
793
794 return RTVfsFileRead(hVfsFile, pvBuf, cbRead, NULL /*pcbRead*/);
795 }
796
797 return VERR_NOT_FOUND;
798}
799
800
801/*static*/
802DECLCALLBACK(int) NvramStore::i_nvramStoreWriteAll(PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath,
803 const void *pvBuf, size_t cbWrite)
804{
805 PDRVMAINNVRAMSTORE pThis = RT_FROM_MEMBER(pInterface, DRVMAINNVRAMSTORE, IVfs);
806
807 AutoWriteLock wlock(pThis->pNvramStore COMMA_LOCKVAL_SRC_POS);
808
809 int rc = VINF_SUCCESS;
810 NvramStoreIter it = pThis->pNvramStore->m->bd->mapNvram.find(Utf8StrFmt("%s/%s", pszNamespace, pszPath));
811 if (it != pThis->pNvramStore->m->bd->mapNvram.end())
812 {
813 RTVFSFILE hVfsFile = it->second;
814
815 rc = RTVfsFileSeek(hVfsFile, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
816 AssertRC(rc);
817 rc = RTVfsFileSetSize(hVfsFile, cbWrite, RTVFSFILE_SIZE_F_NORMAL);
818 if (RT_SUCCESS(rc))
819 rc = RTVfsFileWrite(hVfsFile, pvBuf, cbWrite, NULL /*pcbWritten*/);
820 }
821 else
822 {
823 /* Create a new entry. */
824 RTVFSFILE hVfsFile = NIL_RTVFSFILE;
825 rc = RTVfsFileFromBuffer(RTFILE_O_READ | RTFILE_O_WRITE, pvBuf, cbWrite, &hVfsFile);
826 if (RT_SUCCESS(rc))
827 pThis->pNvramStore->m->bd->mapNvram[Utf8StrFmt("%s/%s", pszNamespace, pszPath)] = hVfsFile;
828 }
829
830 return rc;
831}
832
833
834/*static*/
835DECLCALLBACK(int) NvramStore::i_nvramStoreDelete(PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath)
836{
837 PDRVMAINNVRAMSTORE pThis = RT_FROM_MEMBER(pInterface, DRVMAINNVRAMSTORE, IVfs);
838
839 AutoWriteLock wlock(pThis->pNvramStore COMMA_LOCKVAL_SRC_POS);
840 NvramStoreIter it = pThis->pNvramStore->m->bd->mapNvram.find(Utf8StrFmt("%s/%s", pszNamespace, pszPath));
841 if (it != pThis->pNvramStore->m->bd->mapNvram.end())
842 {
843 RTVFSFILE hVfsFile = it->second;
844 pThis->pNvramStore->m->bd->mapNvram.erase(it);
845 RTVfsFileRelease(hVfsFile);
846 return VINF_SUCCESS;
847 }
848
849 return VERR_NOT_FOUND;
850}
851
852
853/**
854 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
855 */
856DECLCALLBACK(void *) NvramStore::i_drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
857{
858 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
859 PDRVMAINNVRAMSTORE pDrv = PDMINS_2_DATA(pDrvIns, PDRVMAINNVRAMSTORE);
860
861 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
862 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIVFSCONNECTOR, &pDrv->IVfs);
863 return NULL;
864}
865
866
867/**
868 * Destruct a NVRAM store driver instance.
869 *
870 * @returns VBox status code.
871 * @param pDrvIns The driver instance data.
872 */
873DECLCALLBACK(void) NvramStore::i_drvDestruct(PPDMDRVINS pDrvIns)
874{
875 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
876 PDRVMAINNVRAMSTORE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINNVRAMSTORE);
877 LogFlow(("NvramStore::drvDestruct: iInstance=%d\n", pDrvIns->iInstance));
878
879 if (pThis->pNvramStore)
880 {
881 uint32_t cRefs = ASMAtomicDecU32(&pThis->pNvramStore->m->cRefs);
882 if (!cRefs)
883 {
884 int rc = pThis->pNvramStore->i_saveStore();
885 AssertRC(rc); /** @todo Disk full error? */
886 }
887 }
888}
889
890
891/**
892 * Construct a NVRAM store driver instance.
893 *
894 * @copydoc FNPDMDRVCONSTRUCT
895 */
896DECLCALLBACK(int) NvramStore::i_drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
897{
898 RT_NOREF(fFlags);
899 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
900 PDRVMAINNVRAMSTORE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINNVRAMSTORE);
901 LogFlow(("NvramStore::drvConstruct: iInstance=%d\n", pDrvIns->iInstance));
902
903 /*
904 * Validate configuration.
905 */
906 if (!CFGMR3AreValuesValid(pCfg, ""))
907 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
908 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
909 ("Configuration error: Not possible to attach anything to this driver!\n"),
910 VERR_PDM_DRVINS_NO_ATTACH);
911
912 /*
913 * IBase.
914 */
915 pDrvIns->IBase.pfnQueryInterface = NvramStore::i_drvQueryInterface;
916
917 pThis->IVfs.pfnQuerySize = NvramStore::i_nvramStoreQuerySize;
918 pThis->IVfs.pfnReadAll = NvramStore::i_nvramStoreReadAll;
919 pThis->IVfs.pfnWriteAll = NvramStore::i_nvramStoreWriteAll;
920 pThis->IVfs.pfnDelete = NvramStore::i_nvramStoreDelete;
921
922 /*
923 * Get the NVRAM store object pointer.
924 */
925 com::Guid uuid(COM_IIDOF(INvramStore));
926 pThis->pNvramStore = (NvramStore *)PDMDrvHlpQueryGenericUserObject(pDrvIns, uuid.raw());
927 if (!pThis->pNvramStore)
928 {
929 AssertMsgFailed(("Configuration error: No/bad NVRAM store object!\n"));
930 return VERR_NOT_FOUND;
931 }
932
933 uint32_t cRefs = ASMAtomicIncU32(&pThis->pNvramStore->m->cRefs);
934 if (cRefs == 1)
935 {
936 int rc = pThis->pNvramStore->i_loadStore();
937 if (RT_FAILURE(rc))
938 {
939 ASMAtomicDecU32(&pThis->pNvramStore->m->cRefs);
940 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
941 N_("Failed to load the NVRAM store from the file"));
942 }
943 }
944
945 return VINF_SUCCESS;
946}
947
948
949/**
950 * NVRAM store driver registration record.
951 */
952const PDMDRVREG NvramStore::DrvReg =
953{
954 /* u32Version */
955 PDM_DRVREG_VERSION,
956 /* szName */
957 "NvramStore",
958 /* szRCMod */
959 "",
960 /* szR0Mod */
961 "",
962 /* pszDescription */
963 "Main NVRAM store driver (Main as in the API).",
964 /* fFlags */
965 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
966 /* fClass. */
967 PDM_DRVREG_CLASS_STATUS,
968 /* cMaxInstances */
969 ~0U,
970 /* cbInstance */
971 sizeof(DRVMAINNVRAMSTORE),
972 /* pfnConstruct */
973 NvramStore::i_drvConstruct,
974 /* pfnDestruct */
975 NvramStore::i_drvDestruct,
976 /* pfnRelocate */
977 NULL,
978 /* pfnIOCtl */
979 NULL,
980 /* pfnPowerOn */
981 NULL,
982 /* pfnReset */
983 NULL,
984 /* pfnSuspend */
985 NULL,
986 /* pfnResume */
987 NULL,
988 /* pfnAttach */
989 NULL,
990 /* pfnDetach */
991 NULL,
992 /* pfnPowerOff */
993 NULL,
994 /* pfnSoftReset */
995 NULL,
996 /* u32EndVersion */
997 PDM_DRVREG_VERSION
998};
999#endif /* !VBOX_COM_INPROC */
1000
1001/* 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