VirtualBox

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

Last change on this file since 108014 was 107849, checked in by vboxsync, 6 weeks ago

src/VBox/Main/src-all/NvramStoreImpl.cpp: Extend the gross hack to work with ARM VMs (really need to think about a beter solution), bugref:10780

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 63.0 KB
Line 
1/* $Id: NvramStoreImpl.cpp 107849 2025-01-17 15:09:27Z vboxsync $ */
2/** @file
3 * VirtualBox COM NVRAM store class implementation
4 */
5
6/*
7 * Copyright (C) 2021-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#define LOG_GROUP LOG_GROUP_MAIN_NVRAMSTORE
29#include "LoggingNew.h"
30
31#include "NvramStoreImpl.h"
32#ifdef VBOX_COM_INPROC
33# include "ConsoleImpl.h"
34#else
35# include "MachineImpl.h"
36# include "GuestOSTypeImpl.h"
37# include "AutoStateDep.h"
38#endif
39#include "UefiVariableStoreImpl.h"
40#include "VirtualBoxImpl.h"
41
42#include "AutoCaller.h"
43
44#include <VBox/com/array.h>
45#include <VBox/vmm/pdmdrv.h>
46#include <VBox/err.h>
47
48#include <iprt/cpp/utils.h>
49#include <iprt/efi.h>
50#include <iprt/file.h>
51#include <iprt/path.h>
52#include <iprt/vfs.h>
53#include <iprt/zip.h>
54
55
56// defines
57////////////////////////////////////////////////////////////////////////////////
58
59/** Version of the NVRAM saved state unit. */
60#define NVRAM_STORE_SAVED_STATE_VERSION 1
61
62
63// globals
64////////////////////////////////////////////////////////////////////////////////
65
66/**
67 * NVRAM store driver instance data.
68 */
69typedef struct DRVMAINNVRAMSTORE
70{
71 /** Pointer to the keyboard object. */
72 NvramStore *pNvramStore;
73 /** Pointer to the driver instance structure. */
74 PPDMDRVINS pDrvIns;
75 /** Our VFS connector interface. */
76 PDMIVFSCONNECTOR IVfs;
77} DRVMAINNVRAMSTORE, *PDRVMAINNVRAMSTORE;
78
79/** The NVRAM store map keyed by namespace/entity. */
80typedef std::map<Utf8Str, RTVFSFILE> NvramStoreMap;
81/** The NVRAM store map iterator. */
82typedef std::map<Utf8Str, RTVFSFILE>::iterator NvramStoreIter;
83
84struct BackupableNvramStoreData
85{
86 BackupableNvramStoreData()
87 { }
88
89 /** The NVRAM file path. */
90 com::Utf8Str strNvramPath;
91#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
92 /** The key id used for encrypting the NVRAM file */
93 com::Utf8Str strKeyId;
94 /** The key store containing the encrypting DEK */
95 com::Utf8Str strKeyStore;
96#endif
97};
98
99/////////////////////////////////////////////////////////////////////////////
100// NvramStore::Data structure
101/////////////////////////////////////////////////////////////////////////////
102
103struct NvramStore::Data
104{
105 Data()
106 : pParent(NULL)
107#ifdef VBOX_COM_INPROC
108 , cRefs(0)
109 , fSsmSaved(false)
110#endif
111#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
112 , mpKeyStore(NULL)
113#endif
114 { }
115
116#ifdef VBOX_COM_INPROC
117 /** The Console owning this NVRAM store. */
118 Console * const pParent;
119 /** Number of references held to this NVRAM store from the various devices/drivers. */
120 volatile uint32_t cRefs;
121 /** Flag whether the NVRAM data was saved during a save state operation
122 * preventing it from getting written to the backing file. */
123 bool fSsmSaved;
124#else
125 /** The Machine object owning this NVRAM store. */
126 Machine * const pParent;
127 /** The peer NVRAM store object. */
128 ComObjPtr<NvramStore> pPeer;
129 /** The UEFI variable store. */
130 const ComObjPtr<UefiVariableStore> pUefiVarStore;
131#endif
132
133#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
134 /* Store for secret keys. */
135 SecretKeyStore *mpKeyStore;
136#endif
137
138 Backupable<BackupableNvramStoreData> bd;
139
140 /** The NVRAM store. */
141 NvramStoreMap mapNvram;
142};
143
144// constructor / destructor
145////////////////////////////////////////////////////////////////////////////////
146
147DEFINE_EMPTY_CTOR_DTOR(NvramStore)
148
149HRESULT NvramStore::FinalConstruct()
150{
151 return BaseFinalConstruct();
152}
153
154void NvramStore::FinalRelease()
155{
156 uninit();
157 BaseFinalRelease();
158}
159
160// public initializer/uninitializer for internal purposes only
161/////////////////////////////////////////////////////////////////////////////
162
163/**
164 * Initialization stuff shared across the different methods.
165 *
166 * @returns COM result indicator
167 */
168int NvramStore::initImpl()
169{
170 m = new Data();
171
172#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
173# ifdef VBOX_COM_INPROC
174 bool fNonPageable = true;
175# else
176 /* Non-pageable memory is not accessible for non-VM process */
177 bool fNonPageable = false;
178# endif
179
180 m->mpKeyStore = new SecretKeyStore(fNonPageable /* fKeyBufNonPageable */);
181 AssertReturn(m->mpKeyStore, VERR_NO_MEMORY);
182#endif
183
184 return VINF_SUCCESS;
185}
186
187
188#if !defined(VBOX_COM_INPROC)
189/**
190 * Initializes the NVRAM store object.
191 *
192 * @returns COM result indicator
193 */
194HRESULT NvramStore::init(Machine *aParent)
195{
196 LogFlowThisFuncEnter();
197 LogFlowThisFunc(("aParent: %p\n", aParent));
198
199 ComAssertRet(aParent, E_INVALIDARG);
200
201 /* Enclose the state transition NotReady->InInit->Ready */
202 AutoInitSpan autoInitSpan(this);
203 AssertReturn(autoInitSpan.isOk(), E_FAIL);
204
205 int vrc = initImpl();
206 if (RT_FAILURE(vrc))
207 return E_FAIL;
208
209 /* share the parent weakly */
210 unconst(m->pParent) = aParent;
211
212 m->bd.allocate();
213
214 autoInitSpan.setSucceeded();
215
216 LogFlowThisFuncLeave();
217 return S_OK;
218}
219
220/**
221 * Initializes the NVRAM store object given another NVRAM store object
222 * (a kind of copy constructor). This object shares data with
223 * the object passed as an argument.
224 *
225 * @note This object must be destroyed before the original object
226 * it shares data with is destroyed.
227 */
228HRESULT NvramStore::init(Machine *aParent, NvramStore *that)
229{
230 LogFlowThisFuncEnter();
231 LogFlowThisFunc(("aParent: %p, that: %p\n", aParent, that));
232
233 ComAssertRet(aParent && that, E_INVALIDARG);
234
235 /* Enclose the state transition NotReady->InInit->Ready */
236 AutoInitSpan autoInitSpan(this);
237 AssertReturn(autoInitSpan.isOk(), E_FAIL);
238
239 initImpl();
240
241 unconst(m->pParent) = aParent;
242 m->pPeer = that;
243
244 AutoWriteLock thatlock(that COMMA_LOCKVAL_SRC_POS);
245 m->bd.share(that->m->bd);
246
247 autoInitSpan.setSucceeded();
248
249 LogFlowThisFuncLeave();
250 return S_OK;
251}
252
253/**
254 * Initializes the guest object given another guest object
255 * (a kind of copy constructor). This object makes a private copy of data
256 * of the original object passed as an argument.
257 */
258HRESULT NvramStore::initCopy(Machine *aParent, NvramStore *that)
259{
260 LogFlowThisFuncEnter();
261 LogFlowThisFunc(("aParent: %p, that: %p\n", aParent, that));
262
263 ComAssertRet(aParent && that, E_INVALIDARG);
264
265 /* Enclose the state transition NotReady->InInit->Ready */
266 AutoInitSpan autoInitSpan(this);
267 AssertReturn(autoInitSpan.isOk(), E_FAIL);
268
269 initImpl();
270
271 unconst(m->pParent) = aParent;
272 // mPeer is left null
273
274 AutoWriteLock thatlock(that COMMA_LOCKVAL_SRC_POS);
275 m->bd.attachCopy(that->m->bd);
276
277 autoInitSpan.setSucceeded();
278
279 LogFlowThisFuncLeave();
280 return S_OK;
281}
282
283#else
284
285/**
286 * Initializes the NVRAM store object.
287 *
288 * @returns COM result indicator
289 * @param aParent Handle of our parent object
290 * @param strNonVolatileStorageFile The NVRAM file path.
291 */
292HRESULT NvramStore::init(Console *aParent, const com::Utf8Str &strNonVolatileStorageFile)
293{
294 LogFlowThisFunc(("aParent=%p\n", aParent));
295
296 ComAssertRet(aParent, E_INVALIDARG);
297
298 /* Enclose the state transition NotReady->InInit->Ready */
299 AutoInitSpan autoInitSpan(this);
300 AssertReturn(autoInitSpan.isOk(), E_FAIL);
301
302 initImpl();
303
304 unconst(m->pParent) = aParent;
305
306 m->bd.allocate();
307 m->bd->strNvramPath = strNonVolatileStorageFile;
308
309 /* Confirm a successful initialization */
310 autoInitSpan.setSucceeded();
311
312 return S_OK;
313}
314#endif /* VBOX_COM_INPROC */
315
316
317/**
318 * Uninitializes the instance and sets the ready flag to FALSE.
319 * Called either from FinalRelease() or by the parent when it gets destroyed.
320 */
321void NvramStore::uninit()
322{
323 LogFlowThisFuncEnter();
324
325 /* Enclose the state transition Ready->InUninit->NotReady */
326 AutoUninitSpan autoUninitSpan(this);
327 if (autoUninitSpan.uninitDone())
328 return;
329
330 unconst(m->pParent) = NULL;
331#ifndef VBOX_COM_INPROC
332 unconst(m->pUefiVarStore) = NULL;
333#endif
334
335 /* Delete the NVRAM content. */
336 NvramStoreIter it = m->mapNvram.begin();
337 while (it != m->mapNvram.end())
338 {
339 RTVfsFileRelease(it->second);
340 it++;
341 }
342
343 m->mapNvram.clear();
344 m->bd.free();
345
346#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
347 if (m->mpKeyStore != NULL)
348 delete m->mpKeyStore;
349#endif
350
351 delete m;
352 m = NULL;
353
354 LogFlowThisFuncLeave();
355}
356
357HRESULT NvramStore::getNonVolatileStorageFile(com::Utf8Str &aNonVolatileStorageFile)
358{
359 int vrc = i_getNonVolatileStorageFile(aNonVolatileStorageFile);
360 if (RT_FAILURE(vrc))
361 return setError(E_FAIL, tr("This machine does not have an NVRAM store file"));
362
363 return S_OK;
364}
365
366
367HRESULT NvramStore::getUefiVariableStore(ComPtr<IUefiVariableStore> &aUefiVarStore)
368{
369#ifndef VBOX_COM_INPROC
370 Utf8Str strPath;
371 int vrc = i_getNonVolatileStorageFile(strPath);
372 if (RT_FAILURE(vrc))
373 return setError(E_FAIL, tr("No NVRAM store file found"));
374
375 /* We need a write lock because of the lazy initialization. */
376 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
377
378 /* Check if we have to create the UEFI variable store object */
379 HRESULT hrc = S_OK;
380 if (!m->pUefiVarStore)
381 {
382 /* Load the NVRAM file first if it isn't already. */
383 if (!m->mapNvram.size())
384 {
385 vrc = i_loadStore(strPath.c_str());
386 if (RT_FAILURE(vrc))
387 hrc = setError(E_FAIL, tr("Loading the NVRAM store failed (%Rrc)\n"), vrc);
388 }
389
390 if (SUCCEEDED(hrc))
391 {
392 NvramStoreIter it = m->mapNvram.find("efi/nvram");
393 if (it != m->mapNvram.end())
394 {
395 unconst(m->pUefiVarStore).createObject();
396 m->pUefiVarStore->init(this, m->pParent);
397 }
398 else
399 hrc = setError(VBOX_E_OBJECT_NOT_FOUND, tr("The UEFI NVRAM file is not existing for this machine"));
400 }
401 }
402
403 if (SUCCEEDED(hrc))
404 {
405 m->pUefiVarStore.queryInterfaceTo(aUefiVarStore.asOutParam());
406 /* The "modified" state is handled by i_retainUefiVarStore. */
407 }
408
409 return hrc;
410#else
411 NOREF(aUefiVarStore);
412 return E_NOTIMPL;
413#endif
414}
415
416
417HRESULT NvramStore::getKeyId(com::Utf8Str &aKeyId)
418{
419 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
420
421#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
422 aKeyId = m->bd->strKeyId;
423#else
424 aKeyId = com::Utf8Str::Empty;
425#endif
426
427 return S_OK;
428}
429
430
431HRESULT NvramStore::getKeyStore(com::Utf8Str &aKeyStore)
432{
433 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
434
435#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
436 aKeyStore = m->bd->strKeyStore;
437#else
438 aKeyStore = com::Utf8Str::Empty;
439#endif
440
441 return S_OK;
442}
443
444
445HRESULT NvramStore::initUefiVariableStore(ULONG aSize)
446{
447#ifndef VBOX_COM_INPROC
448 if (aSize != 0)
449 return setError(E_NOTIMPL, tr("Supporting another NVRAM size apart from the default one is not supported right now"));
450
451 /* the machine needs to be mutable */
452 AutoMutableStateDependency adep(m->pParent);
453 if (FAILED(adep.hrc())) return adep.hrc();
454
455 Utf8Str strPath = i_getNonVolatileStorageFile();
456
457 /* We need a write lock because of the lazy initialization. */
458 AutoReadLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
459 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
460
461 if (m->pParent->i_getFirmwareType() == FirmwareType_BIOS)
462 return setError(VBOX_E_NOT_SUPPORTED, tr("The selected firmware type doesn't support a UEFI variable store"));
463
464 /* Load the NVRAM file first if it isn't already. */
465 HRESULT hrc = S_OK;
466 if (!m->mapNvram.size())
467 {
468 int vrc = i_loadStore(strPath.c_str());
469 if (RT_FAILURE(vrc))
470 hrc = setError(E_FAIL, tr("Loading the NVRAM store failed (%Rrc)\n"), vrc);
471 }
472
473 if (SUCCEEDED(hrc))
474 {
475 int vrc = VINF_SUCCESS;
476 RTVFSFILE hVfsUefiVarStore = NIL_RTVFSFILE;
477 NvramStoreIter it = m->mapNvram.find("efi/nvram");
478 if (it != m->mapNvram.end())
479 hVfsUefiVarStore = it->second;
480 else
481 {
482 /* Create a new file. */
483 vrc = RTVfsMemFileCreate(NIL_RTVFSIOSTREAM, 0 /*cbEstimate*/, &hVfsUefiVarStore);
484 if (RT_SUCCESS(vrc))
485 {
486 /** @todo The size is hardcoded to match what the firmware image uses right now which is a gross hack... */
487 uint64_t cbUefi = m->pParent->i_getPlatform()->i_getArchitecture() == PlatformArchitecture_ARM ? 786432 : 540672;
488 vrc = RTVfsFileSetSize(hVfsUefiVarStore, cbUefi, RTVFSFILE_SIZE_F_NORMAL);
489 if (RT_SUCCESS(vrc))
490 m->mapNvram["efi/nvram"] = hVfsUefiVarStore;
491 else
492 RTVfsFileRelease(hVfsUefiVarStore);
493 }
494 }
495
496 if (RT_SUCCESS(vrc))
497 {
498 vrc = RTEfiVarStoreCreate(hVfsUefiVarStore, 0 /*offStore*/, 0 /*cbStore*/, RTEFIVARSTORE_CREATE_F_DEFAULT, 0 /*cbBlock*/,
499 NULL /*pErrInfo*/);
500 if (RT_FAILURE(vrc))
501 return setError(E_FAIL, tr("Failed to initialize the UEFI variable store (%Rrc)"), vrc);
502 }
503 else
504 return setError(E_FAIL, tr("Failed to initialize the UEFI variable store (%Rrc)"), vrc);
505
506 m->pParent->i_setModified(Machine::IsModified_NvramStore);
507 }
508
509 return hrc;
510#else
511 NOREF(aSize);
512 return E_NOTIMPL;
513#endif
514}
515
516
517/**
518 * Returns the path of the non-volatile storage file.
519 *
520 * @returns VBox status code.
521 * @retval VERR_FILE_NOT_FOUND if the storage file was not found.
522 * @param aNonVolatileStorageFile Returns path to non-volatile stroage file on success.
523 */
524int NvramStore::i_getNonVolatileStorageFile(com::Utf8Str &aNonVolatileStorageFile)
525{
526#ifndef VBOX_COM_INPROC
527 Utf8Str strTmp;
528 {
529 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
530 strTmp = m->bd->strNvramPath;
531 }
532
533 AutoReadLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
534 if (strTmp.isEmpty())
535 strTmp = m->pParent->i_getDefaultNVRAMFilename();
536 if (strTmp.isNotEmpty())
537 m->pParent->i_calculateFullPath(strTmp, aNonVolatileStorageFile);
538#else
539 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
540 aNonVolatileStorageFile = m->bd->strNvramPath;
541#endif
542
543 if (aNonVolatileStorageFile.isEmpty())
544 return VERR_FILE_NOT_FOUND;
545
546 return VINF_SUCCESS;
547}
548
549
550/**
551 * Returns the path of the non-volatile stroage file.
552 *
553 * @returns Path to non-volatile stroage file. Empty if not supported / found.
554 *
555 * @note Convenience function for machine object or other callers.
556 */
557Utf8Str NvramStore::i_getNonVolatileStorageFile()
558{
559 AutoCaller autoCaller(this);
560 AssertReturn(autoCaller.isOk(), Utf8Str::Empty);
561
562 Utf8Str strTmp;
563 /* rc ignored */ i_getNonVolatileStorageFile(strTmp);
564 return strTmp;
565}
566
567
568/**
569 * Loads the NVRAM store from the given TAR filesystem stream.
570 *
571 * @returns IPRT status code.
572 * @param hVfsFssTar Handle to the tar filesystem stream.
573 */
574int NvramStore::i_loadStoreFromTar(RTVFSFSSTREAM hVfsFssTar)
575{
576 int vrc = VINF_SUCCESS;
577
578 /*
579 * Process the stream.
580 */
581 for (;;)
582 {
583 /*
584 * Retrieve the next object.
585 */
586 char *pszName;
587 RTVFSOBJ hVfsObj;
588 vrc = RTVfsFsStrmNext(hVfsFssTar, &pszName, NULL, &hVfsObj);
589 if (RT_FAILURE(vrc))
590 {
591 if (vrc == VERR_EOF)
592 vrc = VINF_SUCCESS;
593 break;
594 }
595
596 RTFSOBJINFO UnixInfo;
597 vrc = RTVfsObjQueryInfo(hVfsObj, &UnixInfo, RTFSOBJATTRADD_UNIX);
598 if (RT_SUCCESS(vrc))
599 {
600 switch (UnixInfo.Attr.fMode & RTFS_TYPE_MASK)
601 {
602 case RTFS_TYPE_FILE:
603 {
604 LogRel(("NvramStore: Loading '%s' from archive\n", pszName));
605 RTVFSIOSTREAM hVfsIosEntry = RTVfsObjToIoStream(hVfsObj);
606 Assert(hVfsIosEntry != NIL_RTVFSIOSTREAM);
607
608 RTVFSFILE hVfsFileEntry;
609 vrc = RTVfsMemorizeIoStreamAsFile(hVfsIosEntry, RTFILE_O_READ | RTFILE_O_WRITE, &hVfsFileEntry);
610 if (RT_FAILURE(vrc))
611 break;
612 RTVfsIoStrmRelease(hVfsIosEntry);
613
614 m->mapNvram[Utf8Str(pszName)] = hVfsFileEntry;
615 break;
616 }
617 case RTFS_TYPE_DIRECTORY:
618 break;
619 default:
620 vrc = VERR_NOT_SUPPORTED;
621 break;
622 }
623 }
624
625 /*
626 * Release the current object and string.
627 */
628 RTVfsObjRelease(hVfsObj);
629 RTStrFree(pszName);
630
631 if (RT_FAILURE(vrc))
632 break;
633 }
634
635 return vrc;
636}
637
638#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
639
640/**
641 * Sets up the encryption or decryption machinery.
642 *
643 * @returns VBox status code.
644 * @param hVfsIosInOut Handle to the input stream to be decrypted or the destination to the encrypted
645 * output is written to.
646 * @param fEncrypt Flag whether to setup encryption or decryption.
647 * @param ppCryptoIf Where to store the pointer to the cryptographic interface which needs to be released
648 * when done.
649 * @param ppKey Where to store the pointer to the secret key buffer which needs to be released when done.
650 * @param phVfsIos Where to store the handle to the plaintext I/O stream (either input or output) on success.
651 */
652int NvramStore::i_setupEncryptionOrDecryption(RTVFSIOSTREAM hVfsIosInOut, bool fEncrypt,
653 PCVBOXCRYPTOIF *ppCryptoIf, SecretKey **ppKey,
654 PRTVFSIOSTREAM phVfsIos)
655{
656 int vrc = VINF_SUCCESS;
657 PCVBOXCRYPTOIF pCryptoIf = NULL;
658 SecretKey *pKey = NULL;
659 const char *pszPassword = NULL;
660
661 vrc = i_retainCryptoIf(&pCryptoIf);
662 if (RT_SUCCESS(vrc))
663 {
664 vrc = m->mpKeyStore->retainSecretKey(m->bd->strKeyId, &pKey);
665 if (RT_SUCCESS(vrc))
666 {
667 pszPassword = (const char *)pKey->getKeyBuffer();
668 if (fEncrypt)
669 vrc = pCryptoIf->pfnCryptoIoStrmFromVfsIoStrmEncrypt(hVfsIosInOut, m->bd->strKeyStore.c_str(), pszPassword,
670 phVfsIos);
671 else
672 vrc = pCryptoIf->pfnCryptoIoStrmFromVfsIoStrmDecrypt(hVfsIosInOut, m->bd->strKeyStore.c_str(), pszPassword,
673 phVfsIos);
674 if (RT_SUCCESS(vrc))
675 {
676 *ppCryptoIf = pCryptoIf;
677 *ppKey = pKey;
678 return VINF_SUCCESS;
679 }
680 else
681 LogRelMax(10, ("Failed to decrypt the NVRAM store using secret key ID '%s' with %Rrc\n",
682 m->bd->strKeyId.c_str(), vrc));
683
684 m->mpKeyStore->releaseSecretKey(m->bd->strKeyId);
685 }
686 else
687 LogRelMax(10, ("Failed to retain the secret key ID '%s' with %Rrc\n",
688 m->bd->strKeyId.c_str(), vrc));
689
690 i_releaseCryptoIf(pCryptoIf);
691 }
692 else
693 LogRelMax(10, ("Failed to retain the cryptographic interface with %Rrc\n", vrc));
694
695 return vrc;
696}
697
698/**
699 * Releases all resources acquired in NvramStore::i_setupEncryptionOrDecryption().
700 *
701 * @param hVfsIos Handle to the I/O stream previously created.
702 * @param pCryptoIf Pointer to the cryptographic interface being released.
703 * @param pKey Pointer to the key buffer being released.
704 */
705void NvramStore::i_releaseEncryptionOrDecryptionResources(RTVFSIOSTREAM hVfsIos, PCVBOXCRYPTOIF pCryptoIf,
706 SecretKey *pKey)
707{
708 Assert(hVfsIos != NIL_RTVFSIOSTREAM);
709 AssertPtr(pCryptoIf);
710 AssertPtr(pKey);
711
712 i_releaseCryptoIf(pCryptoIf);
713 pKey->release();
714 RTVfsIoStrmRelease(hVfsIos);
715}
716
717#endif /* VBOX_WITH_FULL_VM_ENCRYPTION */
718
719/**
720 * Loads the NVRAM store from the given VFS directory handle.
721 *
722 * @returns IPRT status code.
723 * @param hVfsDir Handle to the NVRAM root VFS directory.
724 * @param pszNamespace The namespace to load the content for.
725 */
726int NvramStore::i_loadStoreFromDir(RTVFSDIR hVfsDir, const char *pszNamespace)
727{
728 int vrc = VINF_SUCCESS;
729
730 RTVFSDIR hNamespaceDir = NIL_RTVFSDIR;
731 vrc = RTVfsDirOpenDir(hVfsDir, pszNamespace, 0 /*fFlags*/, &hNamespaceDir);
732 if (RT_SUCCESS(vrc))
733 {
734 for (;;)
735 {
736 RTDIRENTRYEX DirEntry; /* ASSUMES that no entry has a longer name than what RTDIRENTRYEX provides by default. */
737 size_t cbDir = sizeof(DirEntry);
738 vrc = RTVfsDirReadEx(hNamespaceDir, &DirEntry, &cbDir, RTFSOBJATTRADD_NOTHING);
739 if (RT_FAILURE(vrc))
740 {
741 if (vrc == VERR_NO_MORE_FILES)
742 vrc = VINF_SUCCESS;
743 break;
744 }
745
746 if (RT_SUCCESS(vrc))
747 {
748 switch (DirEntry.Info.Attr.fMode & RTFS_TYPE_MASK)
749 {
750 case RTFS_TYPE_FILE:
751 {
752 LogRel(("NvramStore: Loading '%s' from directory '%s'\n", DirEntry.szName, pszNamespace));
753
754 RTVFSIOSTREAM hVfsIosEntry;
755 vrc = RTVfsDirOpenFileAsIoStream(hNamespaceDir, DirEntry.szName, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE, &hVfsIosEntry);
756 if (RT_SUCCESS(vrc))
757 {
758 RTVFSIOSTREAM hVfsIosDecrypted = NIL_RTVFSIOSTREAM;
759
760#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
761 PCVBOXCRYPTOIF pCryptoIf = NULL;
762 SecretKey *pKey = NULL;
763
764 if ( m->bd->strKeyId.isNotEmpty()
765 && m->bd->strKeyStore.isNotEmpty())
766 vrc = i_setupEncryptionOrDecryption(hVfsIosEntry, false /*fEncrypt*/,
767 &pCryptoIf, &pKey, &hVfsIosDecrypted);
768#endif
769 if (RT_SUCCESS(vrc))
770 {
771 RTVFSFILE hVfsFileEntry;
772 vrc = RTVfsMemorizeIoStreamAsFile(hVfsIosDecrypted != NIL_RTVFSIOSTREAM
773 ? hVfsIosDecrypted
774 : hVfsIosEntry,
775 RTFILE_O_READ | RTFILE_O_WRITE, &hVfsFileEntry);
776 if (RT_SUCCESS(vrc))
777 m->mapNvram[Utf8StrFmt("%s/%s", pszNamespace, DirEntry.szName)] = hVfsFileEntry;
778 }
779
780#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
781 if (hVfsIosDecrypted != NIL_RTVFSIOSTREAM)
782 i_releaseEncryptionOrDecryptionResources(hVfsIosDecrypted, pCryptoIf, pKey);
783#endif
784
785 RTVfsIoStrmRelease(hVfsIosEntry);
786 }
787 else
788 LogRel(("Failed to open '%s' in NVRAM store '%s', vrc=%Rrc\n", DirEntry.szName, pszNamespace, vrc));
789
790 break;
791 }
792 case RTFS_TYPE_DIRECTORY:
793 break;
794 default:
795 vrc = VERR_NOT_SUPPORTED;
796 break;
797 }
798 }
799
800 if (RT_FAILURE(vrc))
801 break;
802 }
803
804 RTVfsDirRelease(hNamespaceDir);
805 }
806
807 return vrc;
808}
809
810
811/**
812 * Loads the NVRAM store.
813 *
814 * @returns IPRT status code.
815 */
816int NvramStore::i_loadStore(const char *pszPath)
817{
818 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
819 AssertReturn(*pszPath, VERR_PATH_ZERO_LENGTH); /* IPRT below doesn't like empty strings. */
820
821 uint64_t cbStore = 0;
822 int vrc = RTFileQuerySizeByPath(pszPath, &cbStore);
823 if (RT_SUCCESS(vrc))
824 {
825 if (cbStore <= _1M) /* Arbitrary limit to fend off bogus files because the file will be read into memory completely. */
826 {
827 /*
828 * Old NVRAM files just consist of the EFI variable store whereas starting
829 * with VirtualBox 7.0 and the introduction of the TPM the need to handle multiple
830 * independent NVRAM files came up. For those scenarios all NVRAM states are collected
831 * in a tar archive.
832 *
833 * Here we detect whether the file is the new tar archive format or whether it is just
834 * the plain EFI variable store file.
835 */
836 RTVFSIOSTREAM hVfsIosNvram;
837 vrc = RTVfsIoStrmOpenNormal(pszPath, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE,
838 &hVfsIosNvram);
839 if (RT_SUCCESS(vrc))
840 {
841 RTVFSIOSTREAM hVfsIosDecrypted = NIL_RTVFSIOSTREAM;
842
843#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
844 PCVBOXCRYPTOIF pCryptoIf = NULL;
845 SecretKey *pKey = NULL;
846
847 if ( m->bd->strKeyId.isNotEmpty()
848 && m->bd->strKeyStore.isNotEmpty())
849 vrc = i_setupEncryptionOrDecryption(hVfsIosNvram, false /*fEncrypt*/,
850 &pCryptoIf, &pKey, &hVfsIosDecrypted);
851#endif
852 if (RT_SUCCESS(vrc))
853 {
854 /* Read the content. */
855 RTVFSFILE hVfsFileNvram;
856 vrc = RTVfsMemorizeIoStreamAsFile( hVfsIosDecrypted != NIL_RTVFSIOSTREAM
857 ? hVfsIosDecrypted
858 : hVfsIosNvram,
859 RTFILE_O_READ, &hVfsFileNvram);
860 if (RT_SUCCESS(vrc))
861 {
862 if (RT_SUCCESS(vrc))
863 {
864 /* Try to parse it as an EFI variable store. */
865 RTERRINFOSTATIC ErrInfo;
866 RTVFS hVfsEfiVarStore;
867 vrc = RTEfiVarStoreOpenAsVfs(hVfsFileNvram, RTVFSMNT_F_READ_ONLY, 0 /*fVarStoreFlags*/,
868 &hVfsEfiVarStore, RTErrInfoInitStatic(&ErrInfo));
869 if (RT_SUCCESS(vrc))
870 {
871 vrc = RTVfsFileSeek(hVfsFileNvram, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
872 AssertRC(vrc);
873
874 RTVfsFileRetain(hVfsFileNvram); /* Retain a new reference for the map. */
875 m->mapNvram[Utf8Str("efi/nvram")] = hVfsFileNvram;
876
877 RTVfsRelease(hVfsEfiVarStore);
878 }
879 else if (vrc == VERR_VFS_UNKNOWN_FORMAT)
880 {
881 /* Check for the new style tar archive. */
882 vrc = RTVfsFileSeek(hVfsFileNvram, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
883 AssertRC(vrc);
884
885 RTVFSIOSTREAM hVfsIosTar = RTVfsFileToIoStream(hVfsFileNvram);
886 Assert(hVfsIosTar != NIL_RTVFSIOSTREAM);
887
888 RTVFSFSSTREAM hVfsFssTar;
889 vrc = RTZipTarFsStreamFromIoStream(hVfsIosTar, 0 /*fFlags*/, &hVfsFssTar);
890 RTVfsIoStrmRelease(hVfsIosTar);
891 if (RT_SUCCESS(vrc))
892 {
893 vrc = i_loadStoreFromTar(hVfsFssTar);
894 RTVfsFsStrmRelease(hVfsFssTar);
895 }
896 else
897 LogRel(("The given NVRAM file is neither a raw UEFI variable store nor a tar archive (opening failed with %Rrc)\n", vrc));
898 }
899 else
900 LogRel(("Opening the UEFI variable store '%s' failed with %Rrc%RTeim\n", pszPath, vrc, &ErrInfo.Core));
901
902 RTVfsFileRelease(hVfsFileNvram);
903 }
904 else
905 LogRel(("Failed to memorize NVRAM store '%s' with %Rrc\n", pszPath, vrc));
906 }
907 }
908
909#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
910 if (hVfsIosDecrypted != NIL_RTVFSIOSTREAM)
911 i_releaseEncryptionOrDecryptionResources(hVfsIosDecrypted, pCryptoIf, pKey);
912#endif
913
914 RTVfsIoStrmRelease(hVfsIosNvram);
915 }
916 else
917 LogRelMax(10, ("NVRAM store '%s' couldn't be opened with %Rrc\n", pszPath, vrc));
918 }
919 else
920 {
921 LogRelMax(10, ("NVRAM store '%s' exceeds limit of %u bytes, actual size is %u\n",
922 pszPath, _1M, cbStore));
923 vrc = VERR_OUT_OF_RANGE;
924 }
925 }
926 else if (vrc == VERR_IS_A_DIRECTORY) /* Valid if the NVRAM was saved with VBoxInternal2/SaveNvramContentAsDirectory 1. */
927 {
928 RTVFSDIR hNvramDir = NIL_RTVFSDIR;
929 vrc = RTVfsDirOpenNormal(pszPath, 0 /*fFlags*/, &hNvramDir);
930 if (RT_SUCCESS(vrc))
931 {
932 for (;;)
933 {
934 RTDIRENTRYEX DirEntry; /* ASSUMES that no entry has a longer name than what RTDIRENTRYEX provides by default. */
935 size_t cbDir = sizeof(DirEntry);
936
937 vrc = RTVfsDirReadEx(hNvramDir, &DirEntry, &cbDir, RTFSOBJATTRADD_NOTHING);
938 if (RT_FAILURE(vrc))
939 {
940 if (vrc == VERR_NO_MORE_FILES)
941 vrc = VINF_SUCCESS;
942 break;
943 }
944
945 /* This ASSUMES that the structure follows the <namespace>/<file> naming scheme. */
946 if (RT_SUCCESS(vrc))
947 {
948 switch (DirEntry.Info.Attr.fMode & RTFS_TYPE_MASK)
949 {
950 case RTFS_TYPE_FILE:
951 break;
952 case RTFS_TYPE_DIRECTORY:
953 {
954 if ( (DirEntry.szName[0] == '.' && DirEntry.szName[1] == '\0')
955 || (DirEntry.szName[0] == '.' && DirEntry.szName[1] == '.' && DirEntry.szName[2] == '\0'))
956 break;
957
958 vrc = i_loadStoreFromDir(hNvramDir, DirEntry.szName);
959 break;
960 }
961 default:
962 vrc = VERR_NOT_SUPPORTED;
963 break;
964 }
965 }
966
967 if (RT_FAILURE(vrc))
968 break;
969 }
970
971 RTVfsDirRelease(hNvramDir);
972 }
973 else
974 LogRelMax(10, ("NVRAM store '%s' couldn't be opened as a directory, vrc=%Rrc\n", pszPath, vrc));
975
976 }
977 else if (vrc == VERR_FILE_NOT_FOUND) /* Valid for the first run where no NVRAM file is there. */
978 vrc = VINF_SUCCESS;
979
980 return vrc;
981}
982
983
984/**
985 * Saves the NVRAM store as a tar archive.
986 */
987int NvramStore::i_saveStoreAsTar(const char *pszPath)
988{
989 uint32_t offError = 0;
990 RTERRINFOSTATIC ErrInfo;
991 RTVFSIOSTREAM hVfsIos;
992
993 int vrc = RTVfsChainOpenIoStream(pszPath, RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE,
994 &hVfsIos, &offError, RTErrInfoInitStatic(&ErrInfo));
995 if (RT_SUCCESS(vrc))
996 {
997 RTVFSIOSTREAM hVfsIosEncrypted = NIL_RTVFSIOSTREAM;
998
999#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
1000 PCVBOXCRYPTOIF pCryptoIf = NULL;
1001 SecretKey *pKey = NULL;
1002
1003 if ( m->bd->strKeyId.isNotEmpty()
1004 && m->bd->strKeyStore.isNotEmpty())
1005 vrc = i_setupEncryptionOrDecryption(hVfsIos, true /*fEncrypt*/,
1006 &pCryptoIf, &pKey, &hVfsIosEncrypted);
1007#endif
1008
1009 if (RT_SUCCESS(vrc))
1010 {
1011 RTVFSFSSTREAM hVfsFss;
1012 vrc = RTZipTarFsStreamToIoStream( hVfsIosEncrypted != NIL_RTVFSIOSTREAM
1013 ? hVfsIosEncrypted
1014 : hVfsIos,
1015 RTZIPTARFORMAT_GNU, 0 /*fFlags*/, &hVfsFss);
1016 if (RT_SUCCESS(vrc))
1017 {
1018 NvramStoreIter it = m->mapNvram.begin();
1019
1020 while (it != m->mapNvram.end())
1021 {
1022 RTVFSFILE hVfsFile = it->second;
1023
1024 vrc = RTVfsFileSeek(hVfsFile, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
1025 AssertRC(vrc);
1026
1027 RTVFSOBJ hVfsObj = RTVfsObjFromFile(hVfsFile);
1028 vrc = RTVfsFsStrmAdd(hVfsFss, it->first.c_str(), hVfsObj, 0 /*fFlags*/);
1029 RTVfsObjRelease(hVfsObj);
1030 if (RT_FAILURE(vrc))
1031 break;
1032
1033 it++;
1034 }
1035
1036 RTVfsFsStrmRelease(hVfsFss);
1037 }
1038
1039#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
1040 if (hVfsIosEncrypted != NIL_RTVFSIOSTREAM)
1041 i_releaseEncryptionOrDecryptionResources(hVfsIosEncrypted, pCryptoIf, pKey);
1042#endif
1043 }
1044
1045 RTVfsIoStrmRelease(hVfsIos);
1046 }
1047
1048 return vrc;
1049}
1050
1051
1052/**
1053 * Saves the NVRAM store as a directory tree.
1054 */
1055int NvramStore::i_saveStoreAsDir(const char *pszPath)
1056{
1057 int vrc = VINF_SUCCESS;
1058 if (RTDirExists(pszPath))
1059 vrc = RTDirRemoveRecursive(pszPath, RTDIRRMREC_F_CONTENT_AND_DIR);
1060 else if (RTPathExists(pszPath))
1061 vrc = RTPathUnlink(pszPath, 0 /*fUnlink*/);
1062 if (RT_FAILURE(vrc))
1063 {
1064 LogRel(("Failed to delete existing NVRAM store '%s': %Rrc\n", pszPath, vrc));
1065 return vrc;
1066 }
1067
1068 vrc = RTDirCreate(pszPath, 0700 /*fMode*/, RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_NOT_CRITICAL);
1069 if (RT_SUCCESS(vrc))
1070 {
1071 NvramStoreIter it = m->mapNvram.begin();
1072
1073 while (it != m->mapNvram.end())
1074 {
1075 /** @todo r=aeichner This is pretty in-efficient but not called often (not at all by default)
1076 * and there aren't many entries anyway. */
1077 char szPathOut[RTPATH_MAX];
1078 char szPathFile[RTPATH_MAX];
1079
1080 /* Construct the path excluding the filename. */
1081 vrc = RTStrCopy(szPathFile, sizeof(szPathFile), it->first.c_str());
1082 if (RT_FAILURE(vrc))
1083 break;
1084 RTPathStripFilename(szPathFile);
1085 vrc = RTPathJoin(szPathOut, sizeof(szPathOut), pszPath, szPathFile);
1086 if (RT_FAILURE(vrc))
1087 break;
1088
1089 /* Create the directory structure. */
1090 vrc = RTDirCreateFullPathEx(szPathOut, 0700 /*fMode*/, RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_NOT_CRITICAL);
1091 if (RT_FAILURE(vrc))
1092 break;
1093
1094 vrc = RTVfsFileSeek(it->second, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
1095 AssertRC(vrc);
1096
1097 /* Construct path, including the filename now. */
1098 vrc = RTPathJoin(szPathOut, sizeof(szPathOut), pszPath, it->first.c_str());
1099 if (RT_FAILURE(vrc))
1100 break;
1101
1102 /* Write the file, encrypting it if required. */
1103 RTVFSFILE hVfsFile;
1104 vrc = RTVfsFileOpenNormal(szPathOut, RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE,
1105 &hVfsFile);
1106 if (RT_SUCCESS(vrc))
1107 {
1108 RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(hVfsFile);
1109 RTVFSIOSTREAM hVfsIosEncrypted = NIL_RTVFSIOSTREAM;
1110
1111#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
1112 PCVBOXCRYPTOIF pCryptoIf = NULL;
1113 SecretKey *pKey = NULL;
1114
1115 if ( m->bd->strKeyId.isNotEmpty()
1116 && m->bd->strKeyStore.isNotEmpty())
1117 vrc = i_setupEncryptionOrDecryption(hVfsIos, true /*fEncrypt*/,
1118 &pCryptoIf, &pKey, &hVfsIosEncrypted);
1119#endif
1120
1121 if (RT_SUCCESS(vrc))
1122 {
1123 RTVFSIOSTREAM hVfsIosSrc = RTVfsFileToIoStream(it->second);
1124 vrc = RTVfsUtilPumpIoStreams(hVfsIosSrc,
1125 hVfsIosEncrypted != NIL_RTVFSIOSTREAM
1126 ? hVfsIosEncrypted
1127 : hVfsIos, 0 /*cbBufHint*/);
1128 RTVfsIoStrmRelease(hVfsIosSrc);
1129#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
1130 if (hVfsIosEncrypted != NIL_RTVFSIOSTREAM)
1131 i_releaseEncryptionOrDecryptionResources(hVfsIosEncrypted, pCryptoIf, pKey);
1132#endif
1133 }
1134
1135 RTVfsIoStrmRelease(hVfsIos);
1136 RTVfsFileRelease(hVfsFile);
1137 }
1138
1139 it++;
1140 }
1141
1142 /* Cleanup in case of error. */
1143 if (RT_FAILURE(vrc))
1144 {
1145 int vrc2 = RTDirRemoveRecursive(pszPath, RTDIRRMREC_F_CONTENT_AND_DIR);
1146 if (RT_FAILURE(vrc2))
1147 LogRel(("Cleaning up NVRAM store '%s' failed with %Rrc (after creation failed with %Rrc)\n", pszPath, vrc2, vrc));
1148 }
1149 }
1150 else
1151 LogRel(("NVRAM store '%s' directory creation failed: %Rrc\n", pszPath, vrc));
1152
1153 return vrc;
1154}
1155
1156
1157int NvramStore::i_retainCryptoIf(PCVBOXCRYPTOIF *ppCryptoIf)
1158{
1159#ifdef VBOX_COM_INPROC
1160 return m->pParent->i_retainCryptoIf(ppCryptoIf);
1161#else
1162 HRESULT hrc = m->pParent->i_getVirtualBox()->i_retainCryptoIf(ppCryptoIf);
1163 if (SUCCEEDED(hrc))
1164 return VINF_SUCCESS;
1165
1166 return VERR_COM_IPRT_ERROR;
1167#endif
1168}
1169
1170
1171int NvramStore::i_releaseCryptoIf(PCVBOXCRYPTOIF pCryptoIf)
1172{
1173#ifdef VBOX_COM_INPROC
1174 return m->pParent->i_releaseCryptoIf(pCryptoIf);
1175#else
1176 HRESULT hrc = m->pParent->i_getVirtualBox()->i_releaseCryptoIf(pCryptoIf);
1177 if (SUCCEEDED(hrc))
1178 return VINF_SUCCESS;
1179
1180 return VERR_COM_IPRT_ERROR;
1181#endif
1182}
1183
1184
1185/**
1186 * Saves the NVRAM store.
1187 *
1188 * @returns IPRT status code.
1189 */
1190int NvramStore::i_saveStore(void)
1191{
1192 int vrc = VINF_SUCCESS;
1193
1194 Utf8Str strPath = i_getNonVolatileStorageFile();
1195
1196 /*
1197 * Only store the NVRAM content if the path is not empty, if it is
1198 * this means the VM was just created and the store was not saved yet,
1199 * see @bugref{10191}.
1200 */
1201 if (strPath.isNotEmpty())
1202 {
1203 /*
1204 * Skip creating the tar archive if only the UEFI NVRAM content is available in order
1205 * to maintain backwards compatibility. As soon as there is more than one entry or
1206 * it doesn't belong to the UEFI the tar archive will be created.
1207 */
1208 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1209 if ( m->mapNvram.size() == 1
1210 && m->mapNvram.begin()->first == "efi/nvram")
1211 {
1212 RTVFSFILE hVfsFileNvram = m->mapNvram.begin()->second;
1213
1214 vrc = RTVfsFileSeek(hVfsFileNvram, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
1215 AssertLogRelRC(vrc);
1216
1217 RTVFSIOSTREAM hVfsIosDst;
1218 vrc = RTVfsIoStrmOpenNormal(strPath.c_str(), RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE,
1219 &hVfsIosDst);
1220 if (RT_SUCCESS(vrc))
1221 {
1222 RTVFSIOSTREAM hVfsIosSrc = RTVfsFileToIoStream(hVfsFileNvram);
1223 Assert(hVfsIosSrc != NIL_RTVFSIOSTREAM);
1224
1225 RTVFSIOSTREAM hVfsIosEncrypted = NIL_RTVFSIOSTREAM;
1226
1227#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
1228 PCVBOXCRYPTOIF pCryptoIf = NULL;
1229 SecretKey *pKey = NULL;
1230
1231 if ( m->bd->strKeyId.isNotEmpty()
1232 && m->bd->strKeyStore.isNotEmpty())
1233 vrc = i_setupEncryptionOrDecryption(hVfsIosDst, true /*fEncrypt*/,
1234 &pCryptoIf, &pKey, &hVfsIosEncrypted);
1235#endif
1236 if (RT_SUCCESS(vrc))
1237 vrc = RTVfsUtilPumpIoStreams(hVfsIosSrc,
1238 hVfsIosEncrypted != NIL_RTVFSIOSTREAM
1239 ? hVfsIosEncrypted
1240 : hVfsIosDst
1241 , 0 /*cbBufHint*/);
1242#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
1243 if (hVfsIosEncrypted != NIL_RTVFSIOSTREAM)
1244 i_releaseEncryptionOrDecryptionResources(hVfsIosEncrypted, pCryptoIf, pKey);
1245#endif
1246
1247 RTVfsIoStrmRelease(hVfsIosSrc);
1248 RTVfsIoStrmRelease(hVfsIosDst);
1249 }
1250 }
1251 else if (m->mapNvram.size())
1252 {
1253 /* Check whether the NVRAM content is supposed to be saved under a directory. */
1254#ifndef VBOX_COM_INPROC
1255 Machine * const pMachine = m->pParent;
1256#else
1257 const ComPtr<IMachine> &pMachine = m->pParent->i_machine();
1258#endif
1259
1260 Bstr bstrName("VBoxInternal2/SaveNvramContentAsDirectory");
1261 Bstr bstrValue;
1262 HRESULT hrc = pMachine->GetExtraData(bstrName.raw(), bstrValue.asOutParam());
1263 if (FAILED(hrc))
1264 throw hrc;
1265
1266 bool fSaveAsDir = bstrValue == "1";
1267
1268 if (fSaveAsDir)
1269 vrc = i_saveStoreAsDir(strPath.c_str());
1270 else
1271 vrc = i_saveStoreAsTar(strPath.c_str());
1272 }
1273 /* else: No NVRAM content to store so we are done here. */
1274 }
1275
1276 return vrc;
1277}
1278
1279
1280#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
1281HRESULT NvramStore::i_updateEncryptionSettings(const com::Utf8Str &strKeyId,
1282 const com::Utf8Str &strKeyStore)
1283{
1284 /* sanity */
1285 AutoCaller autoCaller(this);
1286 AssertComRCReturnRC(autoCaller.hrc());
1287
1288 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1289
1290 m->bd.backup();
1291 m->bd->strKeyId = strKeyId;
1292 m->bd->strKeyStore = strKeyStore;
1293
1294 /* clear all passwords because they are invalid now */
1295 m->mpKeyStore->deleteAllSecretKeys(false, true);
1296
1297 alock.release();
1298 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
1299#ifndef VBOX_COM_INPROC
1300 m->pParent->i_setModified(Machine::IsModified_NvramStore);
1301#endif
1302 return S_OK;
1303}
1304
1305
1306HRESULT NvramStore::i_getEncryptionSettings(com::Utf8Str &strKeyId,
1307 com::Utf8Str &strKeyStore)
1308{
1309 AutoCaller autoCaller(this);
1310 AssertComRCReturnRC(autoCaller.hrc());
1311
1312 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1313
1314 strKeyId = m->bd->strKeyId;
1315 strKeyStore = m->bd->strKeyStore;
1316
1317 return S_OK;
1318}
1319
1320
1321int NvramStore::i_addPassword(const Utf8Str &strKeyId, const Utf8Str &strPassword)
1322{
1323 AutoCaller autoCaller(this);
1324 AssertComRCReturn(autoCaller.hrc(), VERR_INVALID_STATE);
1325
1326 /* keep only required password */
1327 if (strKeyId != m->bd->strKeyId)
1328 return VINF_SUCCESS;
1329
1330 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1331 return m->mpKeyStore->addSecretKey(strKeyId, (const uint8_t *)strPassword.c_str(), strPassword.length() + 1);
1332}
1333
1334
1335int NvramStore::i_removePassword(const Utf8Str &strKeyId)
1336{
1337 AutoCaller autoCaller(this);
1338 AssertComRCReturn(autoCaller.hrc(), VERR_INVALID_STATE);
1339
1340 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1341 return m->mpKeyStore->deleteSecretKey(strKeyId);
1342}
1343
1344
1345int NvramStore::i_removeAllPasswords()
1346{
1347 AutoCaller autoCaller(this);
1348 AssertComRCReturn(autoCaller.hrc(), VERR_INVALID_STATE);
1349
1350 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1351 m->mpKeyStore->deleteAllSecretKeys(false, true);
1352 return VINF_SUCCESS;
1353}
1354#endif
1355
1356
1357#ifndef VBOX_COM_INPROC
1358
1359HRESULT NvramStore::i_retainUefiVarStore(PRTVFS phVfs, bool fReadonly)
1360{
1361 /* the machine needs to be mutable unless fReadonly is set */
1362 AutoMutableStateDependency adep(fReadonly ? NULL : m->pParent);
1363 if (FAILED(adep.hrc())) return adep.hrc();
1364
1365 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
1366
1367 HRESULT hrc = S_OK;
1368 NvramStoreIter it = m->mapNvram.find("efi/nvram");
1369 if (it != m->mapNvram.end())
1370 {
1371 RTVFSFILE hVfsFileNvram = it->second;
1372 RTVFS hVfsEfiVarStore;
1373 uint32_t fMntFlags = fReadonly ? RTVFSMNT_F_READ_ONLY : 0;
1374
1375 int vrc = RTEfiVarStoreOpenAsVfs(hVfsFileNvram, fMntFlags, 0 /*fVarStoreFlags*/, &hVfsEfiVarStore,
1376 NULL /*pErrInfo*/);
1377 if (RT_SUCCESS(vrc))
1378 {
1379 *phVfs = hVfsEfiVarStore;
1380 if (!fReadonly)
1381 m->pParent->i_setModified(Machine::IsModified_NvramStore);
1382 }
1383 else
1384 hrc = setError(E_FAIL, tr("Opening the UEFI variable store failed (%Rrc)"), vrc);
1385 }
1386 else
1387 hrc = setError(VBOX_E_OBJECT_NOT_FOUND, tr("The UEFI NVRAM file is not existing for this machine"));
1388
1389 return hrc;
1390}
1391
1392
1393HRESULT NvramStore::i_releaseUefiVarStore(RTVFS hVfs)
1394{
1395 RTVfsRelease(hVfs);
1396 return S_OK;
1397}
1398
1399
1400/**
1401 * Loads settings from the given machine node.
1402 * May be called once right after this object creation.
1403 *
1404 * @param data Configuration settings.
1405 *
1406 * @note Locks this object for writing.
1407 */
1408HRESULT NvramStore::i_loadSettings(const settings::NvramSettings &data)
1409{
1410 LogFlowThisFuncEnter();
1411
1412 AutoCaller autoCaller(this);
1413 AssertComRCReturnRC(autoCaller.hrc());
1414
1415 AutoReadLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
1416 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1417
1418 m->bd->strNvramPath = data.strNvramPath;
1419#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
1420 m->bd->strKeyId = data.strKeyId;
1421 m->bd->strKeyStore = data.strKeyStore;
1422#endif
1423
1424 Utf8Str strTmp(m->bd->strNvramPath);
1425 if (strTmp.isNotEmpty())
1426 m->pParent->i_copyPathRelativeToMachine(strTmp, m->bd->strNvramPath);
1427 if ( m->pParent->i_getFirmwareType() == FirmwareType_BIOS
1428 || m->bd->strNvramPath == m->pParent->i_getDefaultNVRAMFilename())
1429 m->bd->strNvramPath.setNull();
1430
1431 LogFlowThisFuncLeave();
1432 return S_OK;
1433}
1434
1435/**
1436 * Saves settings to the given machine node.
1437 *
1438 * @param data Configuration settings.
1439 *
1440 * @note Locks this object for writing.
1441 */
1442HRESULT NvramStore::i_saveSettings(settings::NvramSettings &data)
1443{
1444 AutoCaller autoCaller(this);
1445 AssertComRCReturnRC(autoCaller.hrc());
1446
1447 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
1448
1449 data.strNvramPath = m->bd->strNvramPath;
1450#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
1451 data.strKeyId = m->bd->strKeyId;
1452 data.strKeyStore = m->bd->strKeyStore;
1453#endif
1454
1455 int vrc = i_saveStore();
1456 if (RT_FAILURE(vrc))
1457 return setError(E_FAIL, tr("Failed to save the NVRAM content to disk (%Rrc)"), vrc);
1458
1459 return S_OK;
1460}
1461
1462void NvramStore::i_rollback()
1463{
1464 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1465 m->bd.rollback();
1466}
1467
1468void NvramStore::i_commit()
1469{
1470 /* sanity */
1471 AutoCaller autoCaller(this);
1472 AssertReturnVoid(autoCaller.isOk());
1473
1474 /* sanity too */
1475 AutoCaller peerCaller(m->pPeer);
1476 AssertReturnVoid(peerCaller.isOk());
1477
1478 /* lock both for writing since we modify both (mPeer is "master" so locked
1479 * first) */
1480 AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
1481
1482 if (m->bd.isBackedUp())
1483 {
1484 m->bd.commit();
1485 if (m->pPeer)
1486 {
1487 /* attach new data to the peer and reshare it */
1488 AutoWriteLock peerlock(m->pPeer COMMA_LOCKVAL_SRC_POS);
1489 m->pPeer->m->bd.attach(m->bd);
1490 }
1491 }
1492}
1493
1494void NvramStore::i_copyFrom(NvramStore *aThat)
1495{
1496 AssertReturnVoid(aThat != NULL);
1497
1498 /* sanity */
1499 AutoCaller autoCaller(this);
1500 AssertReturnVoid(autoCaller.isOk());
1501
1502 /* sanity too */
1503 AutoCaller thatCaller(aThat);
1504 AssertReturnVoid(thatCaller.isOk());
1505
1506 /* peer is not modified, lock it for reading (aThat is "master" so locked
1507 * first) */
1508 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
1509 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
1510
1511 /* this will back up current data */
1512 m->bd.assignCopy(aThat->m->bd);
1513
1514 // Intentionally "forget" the NVRAM file since it must be unique and set
1515 // to the correct value before the copy of the settings makes sense.
1516 m->bd->strNvramPath.setNull();
1517}
1518
1519HRESULT NvramStore::i_applyDefaults(GuestOSType *aOSType)
1520{
1521 HRESULT hrc = S_OK;
1522
1523 if (aOSType->i_recommendedEFISecureBoot())
1524 {
1525 /* Initialize the UEFI variable store and enroll default keys. */
1526 hrc = initUefiVariableStore(0 /*aSize*/);
1527 if (SUCCEEDED(hrc))
1528 {
1529 ComPtr<IUefiVariableStore> pVarStore;
1530
1531 hrc = getUefiVariableStore(pVarStore);
1532 if (SUCCEEDED(hrc))
1533 {
1534 hrc = pVarStore->EnrollOraclePlatformKey();
1535 if (SUCCEEDED(hrc))
1536 hrc = pVarStore->EnrollDefaultMsSignatures();
1537 }
1538 }
1539 }
1540
1541 return hrc;
1542}
1543
1544void NvramStore::i_updateNonVolatileStorageFile(const Utf8Str &aNonVolatileStorageFile)
1545{
1546 /* sanity */
1547 AutoCaller autoCaller(this);
1548 AssertComRCReturnVoid(autoCaller.hrc());
1549
1550 AutoReadLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
1551 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1552
1553 Utf8Str strTmp(aNonVolatileStorageFile);
1554 if (strTmp == m->pParent->i_getDefaultNVRAMFilename())
1555 strTmp.setNull();
1556
1557 if (strTmp == m->bd->strNvramPath)
1558 return;
1559
1560 m->bd.backup();
1561 m->bd->strNvramPath = strTmp;
1562}
1563
1564#else /* VBOX_COM_INPROC */
1565
1566//
1567// private methods
1568//
1569/*static*/
1570DECLCALLBACK(int) NvramStore::i_nvramStoreQuerySize(PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath,
1571 uint64_t *pcb)
1572{
1573 PDRVMAINNVRAMSTORE pThis = RT_FROM_MEMBER(pInterface, DRVMAINNVRAMSTORE, IVfs);
1574
1575 Utf8Str strKey;
1576 int vrc = strKey.printfNoThrow("%s/%s", pszNamespace, pszPath);
1577 AssertRCReturn(vrc, vrc);
1578
1579 AutoReadLock rlock(pThis->pNvramStore COMMA_LOCKVAL_SRC_POS);
1580 NvramStoreIter it = pThis->pNvramStore->m->mapNvram.find(strKey);
1581 if (it != pThis->pNvramStore->m->mapNvram.end())
1582 {
1583 RTVFSFILE hVfsFile = it->second;
1584 return RTVfsFileQuerySize(hVfsFile, pcb);
1585 }
1586
1587 return VERR_NOT_FOUND;
1588}
1589
1590
1591/*static*/
1592DECLCALLBACK(int) NvramStore::i_nvramStoreReadAll(PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath,
1593 void *pvBuf, size_t cbRead)
1594{
1595 PDRVMAINNVRAMSTORE pThis = RT_FROM_MEMBER(pInterface, DRVMAINNVRAMSTORE, IVfs);
1596
1597 Utf8Str strKey;
1598 int vrc = strKey.printfNoThrow("%s/%s", pszNamespace, pszPath);
1599 AssertRCReturn(vrc, vrc);
1600
1601 AutoReadLock rlock(pThis->pNvramStore COMMA_LOCKVAL_SRC_POS);
1602 NvramStoreIter it = pThis->pNvramStore->m->mapNvram.find(strKey);
1603 if (it != pThis->pNvramStore->m->mapNvram.end())
1604 {
1605 RTVFSFILE hVfsFile = it->second;
1606
1607 vrc = RTVfsFileSeek(hVfsFile, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
1608 AssertLogRelRC(vrc);
1609
1610 return RTVfsFileRead(hVfsFile, pvBuf, cbRead, NULL /*pcbRead*/);
1611 }
1612
1613 return VERR_NOT_FOUND;
1614}
1615
1616
1617/*static*/
1618DECLCALLBACK(int) NvramStore::i_nvramStoreWriteAll(PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath,
1619 const void *pvBuf, size_t cbWrite)
1620{
1621 PDRVMAINNVRAMSTORE pThis = RT_FROM_MEMBER(pInterface, DRVMAINNVRAMSTORE, IVfs);
1622
1623 Utf8Str strKey;
1624 int vrc = strKey.printfNoThrow("%s/%s", pszNamespace, pszPath);
1625 AssertRCReturn(vrc, vrc);
1626
1627 AutoWriteLock wlock(pThis->pNvramStore COMMA_LOCKVAL_SRC_POS);
1628
1629 NvramStoreIter it = pThis->pNvramStore->m->mapNvram.find(strKey);
1630 if (it != pThis->pNvramStore->m->mapNvram.end())
1631 {
1632 RTVFSFILE hVfsFile = it->second;
1633
1634 vrc = RTVfsFileSeek(hVfsFile, 0 /*offSeek*/, RTFILE_SEEK_BEGIN, NULL /*poffActual*/);
1635 AssertLogRelRC(vrc);
1636 vrc = RTVfsFileSetSize(hVfsFile, cbWrite, RTVFSFILE_SIZE_F_NORMAL);
1637 if (RT_SUCCESS(vrc))
1638 vrc = RTVfsFileWrite(hVfsFile, pvBuf, cbWrite, NULL /*pcbWritten*/);
1639 }
1640 else
1641 {
1642 /* Create a new entry. */
1643 RTVFSFILE hVfsFile = NIL_RTVFSFILE;
1644 vrc = RTVfsFileFromBuffer(RTFILE_O_READ | RTFILE_O_WRITE, pvBuf, cbWrite, &hVfsFile);
1645 if (RT_SUCCESS(vrc))
1646 {
1647 try
1648 {
1649 pThis->pNvramStore->m->mapNvram[strKey] = hVfsFile;
1650 }
1651 catch (...)
1652 {
1653 AssertLogRelFailed();
1654 RTVfsFileRelease(hVfsFile);
1655 vrc = VERR_UNEXPECTED_EXCEPTION;
1656 }
1657 }
1658 }
1659
1660 return vrc;
1661}
1662
1663
1664/*static*/
1665DECLCALLBACK(int) NvramStore::i_nvramStoreDelete(PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath)
1666{
1667 PDRVMAINNVRAMSTORE pThis = RT_FROM_MEMBER(pInterface, DRVMAINNVRAMSTORE, IVfs);
1668
1669 Utf8Str strKey;
1670 int vrc = strKey.printfNoThrow("%s/%s", pszNamespace, pszPath);
1671 AssertRCReturn(vrc, vrc);
1672
1673 AutoWriteLock wlock(pThis->pNvramStore COMMA_LOCKVAL_SRC_POS);
1674 NvramStoreIter it = pThis->pNvramStore->m->mapNvram.find(strKey);
1675 if (it != pThis->pNvramStore->m->mapNvram.end())
1676 {
1677 RTVFSFILE hVfsFile = it->second;
1678 pThis->pNvramStore->m->mapNvram.erase(it);
1679 RTVfsFileRelease(hVfsFile);
1680 return VINF_SUCCESS;
1681 }
1682
1683 return VERR_NOT_FOUND;
1684}
1685
1686
1687/*static*/
1688DECLCALLBACK(int) NvramStore::i_SsmSaveExec(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
1689{
1690 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1691 PDRVMAINNVRAMSTORE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINNVRAMSTORE);
1692 PCPDMDRVHLPR3 pHlp = pDrvIns->pHlpR3;
1693
1694 AutoWriteLock wlock(pThis->pNvramStore COMMA_LOCKVAL_SRC_POS);
1695
1696 size_t cEntries = pThis->pNvramStore->m->mapNvram.size();
1697 AssertReturn(cEntries < 32, VERR_OUT_OF_RANGE); /* Some sanity checking. */
1698 pHlp->pfnSSMPutU32(pSSM, (uint32_t)cEntries);
1699
1700 void *pvData = NULL;
1701 size_t cbDataMax = 0;
1702 int vrc = i_SsmSaveExecInner(pThis, pHlp, pSSM, &pvData, &cbDataMax);
1703 if (pvData)
1704 RTMemFree(pvData);
1705 AssertRCReturn(vrc, vrc);
1706
1707 pThis->pNvramStore->m->fSsmSaved = true;
1708 return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX); /* sanity/terminator */
1709}
1710
1711
1712/*static*/
1713int NvramStore::i_SsmSaveExecInner(PDRVMAINNVRAMSTORE pThis, PCPDMDRVHLPR3 pHlp, PSSMHANDLE pSSM,
1714 void **ppvData, size_t *pcbDataMax) RT_NOEXCEPT
1715{
1716 for (NvramStoreIter it = pThis->pNvramStore->m->mapNvram.begin(); it != pThis->pNvramStore->m->mapNvram.end(); ++it)
1717 {
1718 RTVFSFILE hVfsFile = it->second;
1719
1720 uint64_t cbFile;
1721 int vrc = RTVfsFileQuerySize(hVfsFile, &cbFile);
1722 AssertRCReturn(vrc, vrc);
1723 AssertReturn(cbFile < _1M, VERR_OUT_OF_RANGE);
1724
1725 if (*pcbDataMax < cbFile)
1726 {
1727 void *pvNew = RTMemRealloc(*ppvData, cbFile);
1728 AssertPtrReturn(pvNew, VERR_NO_MEMORY);
1729 *ppvData = pvNew;
1730 *pcbDataMax = cbFile;
1731 }
1732
1733 vrc = RTVfsFileReadAt(hVfsFile, 0 /*off*/, *ppvData, cbFile, NULL /*pcbRead*/);
1734 AssertRCReturn(vrc, vrc);
1735
1736 pHlp->pfnSSMPutStrZ(pSSM, it->first.c_str());
1737 pHlp->pfnSSMPutU64(pSSM, cbFile);
1738 pHlp->pfnSSMPutMem(pSSM, *ppvData, cbFile);
1739 }
1740 return VINF_SUCCESS;
1741}
1742
1743
1744/*static*/
1745DECLCALLBACK(int) NvramStore::i_SsmLoadExec(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1746{
1747 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1748 PDRVMAINNVRAMSTORE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINNVRAMSTORE);
1749 PCPDMDRVHLPR3 pHlp = pDrvIns->pHlpR3;
1750
1751 AssertMsgReturn(uVersion >= NVRAM_STORE_SAVED_STATE_VERSION, ("%d\n", uVersion),
1752 VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
1753
1754 if (uPass == SSM_PASS_FINAL)
1755 {
1756 AutoWriteLock wlock(pThis->pNvramStore COMMA_LOCKVAL_SRC_POS);
1757
1758 /* Clear any content first. */
1759 NvramStoreIter it = pThis->pNvramStore->m->mapNvram.begin();
1760 while (it != pThis->pNvramStore->m->mapNvram.end())
1761 {
1762 RTVfsFileRelease(it->second);
1763 it++;
1764 }
1765
1766 pThis->pNvramStore->m->mapNvram.clear();
1767
1768 uint32_t cEntries = 0;
1769 int vrc = pHlp->pfnSSMGetU32(pSSM, &cEntries);
1770 AssertRCReturn(vrc, vrc);
1771 AssertReturn(cEntries < 32, VERR_OUT_OF_RANGE);
1772
1773 void *pvData = NULL;
1774 size_t cbDataMax = 0;
1775 vrc = i_SsmLoadExecInner(pThis, pHlp, pSSM, cEntries, &pvData, &cbDataMax);
1776 if (pvData)
1777 RTMemFree(pvData);
1778 AssertRCReturn(vrc, vrc);
1779
1780 /* The marker. */
1781 uint32_t u32;
1782 vrc = pHlp->pfnSSMGetU32(pSSM, &u32);
1783 AssertRCReturn(vrc, vrc);
1784 AssertMsgReturn(u32 == UINT32_MAX, ("%#x\n", u32), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
1785 }
1786
1787 return VINF_SUCCESS;
1788}
1789
1790
1791/*static*/
1792int NvramStore::i_SsmLoadExecInner(PDRVMAINNVRAMSTORE pThis, PCPDMDRVHLPR3 pHlp, PSSMHANDLE pSSM,
1793 uint32_t cEntries, void **ppvData, size_t *pcbDataMax) RT_NOEXCEPT
1794{
1795 while (cEntries-- > 0)
1796 {
1797 char szId[_1K]; /* Lazy developer */
1798 int vrc = pHlp->pfnSSMGetStrZ(pSSM, &szId[0], sizeof(szId));
1799 AssertRCReturn(vrc, vrc);
1800
1801 uint64_t cbFile = 0;
1802 vrc = pHlp->pfnSSMGetU64(pSSM, &cbFile);
1803 AssertRCReturn(vrc, vrc);
1804 AssertReturn(cbFile < _1M, VERR_OUT_OF_RANGE);
1805
1806 if (*pcbDataMax < cbFile)
1807 {
1808 void *pvNew = RTMemRealloc(*ppvData, cbFile);
1809 AssertPtrReturn(pvNew, VERR_NO_MEMORY);
1810 *ppvData = pvNew;
1811 *pcbDataMax = cbFile;
1812 }
1813
1814 vrc = pHlp->pfnSSMGetMem(pSSM, *ppvData, cbFile);
1815 AssertRCReturn(vrc, vrc);
1816
1817 RTVFSFILE hVfsFile;
1818 vrc = RTVfsFileFromBuffer(RTFILE_O_READWRITE, *ppvData, cbFile, &hVfsFile);
1819 AssertRCReturn(vrc, vrc);
1820
1821 try
1822 {
1823 pThis->pNvramStore->m->mapNvram[Utf8Str(szId)] = hVfsFile;
1824 }
1825 catch (...)
1826 {
1827 AssertLogRelFailed();
1828 RTVfsFileRelease(hVfsFile);
1829 return VERR_UNEXPECTED_EXCEPTION;
1830 }
1831 }
1832
1833 return VINF_SUCCESS;
1834}
1835
1836
1837/**
1838 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
1839 */
1840DECLCALLBACK(void *) NvramStore::i_drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
1841{
1842 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
1843 PDRVMAINNVRAMSTORE pDrv = PDMINS_2_DATA(pDrvIns, PDRVMAINNVRAMSTORE);
1844
1845 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
1846 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIVFSCONNECTOR, &pDrv->IVfs);
1847 return NULL;
1848}
1849
1850
1851/**
1852 * Destruct a NVRAM store driver instance.
1853 *
1854 * @returns VBox status code.
1855 * @param pDrvIns The driver instance data.
1856 */
1857DECLCALLBACK(void) NvramStore::i_drvDestruct(PPDMDRVINS pDrvIns)
1858{
1859 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
1860 PDRVMAINNVRAMSTORE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINNVRAMSTORE);
1861 LogFlow(("NvramStore::drvDestruct: iInstance=%d\n", pDrvIns->iInstance));
1862
1863 if (pThis->pNvramStore)
1864 {
1865 uint32_t cRefs = ASMAtomicDecU32(&pThis->pNvramStore->m->cRefs);
1866 if ( !cRefs
1867 && !pThis->pNvramStore->m->fSsmSaved)
1868 {
1869 try
1870 {
1871 int vrc = pThis->pNvramStore->i_saveStore();
1872 AssertLogRelRC(vrc); /** @todo Disk full error? */
1873 }
1874 catch (...)
1875 {
1876 AssertLogRelFailed();
1877 }
1878 }
1879 }
1880}
1881
1882
1883/**
1884 * Construct a NVRAM store driver instance.
1885 *
1886 * @copydoc FNPDMDRVCONSTRUCT
1887 */
1888DECLCALLBACK(int) NvramStore::i_drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
1889{
1890 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1891 RT_NOREF(fFlags, pCfg);
1892 PDRVMAINNVRAMSTORE pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINNVRAMSTORE);
1893 LogFlow(("NvramStore::drvConstruct: iInstance=%d\n", pDrvIns->iInstance));
1894
1895 /*
1896 * Validate configuration.
1897 */
1898 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "", "");
1899 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
1900 ("Configuration error: Not possible to attach anything to this driver!\n"),
1901 VERR_PDM_DRVINS_NO_ATTACH);
1902
1903 /*
1904 * IBase.
1905 */
1906 pDrvIns->IBase.pfnQueryInterface = NvramStore::i_drvQueryInterface;
1907
1908 pThis->IVfs.pfnQuerySize = NvramStore::i_nvramStoreQuerySize;
1909 pThis->IVfs.pfnReadAll = NvramStore::i_nvramStoreReadAll;
1910 pThis->IVfs.pfnWriteAll = NvramStore::i_nvramStoreWriteAll;
1911 pThis->IVfs.pfnDelete = NvramStore::i_nvramStoreDelete;
1912
1913 /*
1914 * Get the NVRAM store object pointer.
1915 */
1916 com::Guid uuid(COM_IIDOF(INvramStore));
1917 pThis->pNvramStore = (NvramStore *)PDMDrvHlpQueryGenericUserObject(pDrvIns, uuid.raw());
1918 if (!pThis->pNvramStore)
1919 {
1920 AssertMsgFailed(("Configuration error: No/bad NVRAM store object!\n"));
1921 return VERR_NOT_FOUND;
1922 }
1923
1924 /*
1925 * Only the first instance will register the SSM handlers and will do the work on behalf
1926 * of all other NVRAM store driver instances when it comes to SSM.
1927 */
1928 if (pDrvIns->iInstance == 0)
1929 {
1930 int vrc = PDMDrvHlpSSMRegister(pDrvIns, NVRAM_STORE_SAVED_STATE_VERSION, 0 /*cbGuess*/,
1931 NvramStore::i_SsmSaveExec, NvramStore::i_SsmLoadExec);
1932 if (RT_FAILURE(vrc))
1933 return PDMDrvHlpVMSetError(pDrvIns, vrc, RT_SRC_POS,
1934 N_("Failed to register the saved state unit for the NVRAM store"));
1935 }
1936
1937 uint32_t cRefs = ASMAtomicIncU32(&pThis->pNvramStore->m->cRefs);
1938 if (cRefs == 1)
1939 {
1940 int vrc;
1941 try
1942 {
1943 vrc = pThis->pNvramStore->i_loadStore(pThis->pNvramStore->m->bd->strNvramPath.c_str());
1944 }
1945 catch (...)
1946 {
1947 vrc = VERR_UNEXPECTED_EXCEPTION;
1948 }
1949 if (RT_FAILURE(vrc))
1950 {
1951 ASMAtomicDecU32(&pThis->pNvramStore->m->cRefs);
1952 return PDMDrvHlpVMSetError(pDrvIns, vrc, RT_SRC_POS,
1953 N_("Failed to load the NVRAM store from the file"));
1954 }
1955 }
1956
1957 return VINF_SUCCESS;
1958}
1959
1960
1961/**
1962 * NVRAM store driver registration record.
1963 */
1964const PDMDRVREG NvramStore::DrvReg =
1965{
1966 /* u32Version */
1967 PDM_DRVREG_VERSION,
1968 /* szName */
1969 "NvramStore",
1970 /* szRCMod */
1971 "",
1972 /* szR0Mod */
1973 "",
1974 /* pszDescription */
1975 "Main NVRAM store driver (Main as in the API).",
1976 /* fFlags */
1977 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1978 /* fClass. */
1979 PDM_DRVREG_CLASS_STATUS,
1980 /* cMaxInstances */
1981 ~0U,
1982 /* cbInstance */
1983 sizeof(DRVMAINNVRAMSTORE),
1984 /* pfnConstruct */
1985 NvramStore::i_drvConstruct,
1986 /* pfnDestruct */
1987 NvramStore::i_drvDestruct,
1988 /* pfnRelocate */
1989 NULL,
1990 /* pfnIOCtl */
1991 NULL,
1992 /* pfnPowerOn */
1993 NULL,
1994 /* pfnReset */
1995 NULL,
1996 /* pfnSuspend */
1997 NULL,
1998 /* pfnResume */
1999 NULL,
2000 /* pfnAttach */
2001 NULL,
2002 /* pfnDetach */
2003 NULL,
2004 /* pfnPowerOff */
2005 NULL,
2006 /* pfnSoftReset */
2007 NULL,
2008 /* u32EndVersion */
2009 PDM_DRVREG_VERSION
2010};
2011
2012#endif /* VBOX_COM_INPROC */
2013
2014/* 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