VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/efi/efivarstorevfs.cpp@ 99965

最後變更 在這個檔案從99965是 99739,由 vboxsync 提交於 23 月 前

*: doxygen corrections (mostly about removing @returns from functions returning void).

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 90.3 KB
 
1/* $Id: efivarstorevfs.cpp 99739 2023-05-11 01:01:08Z vboxsync $ */
2/** @file
3 * IPRT - Expose a EFI variable store as a Virtual Filesystem.
4 */
5
6/*
7 * Copyright (C) 2021-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.alldomusa.eu.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 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP RTLOGGROUP_FS
42#include <iprt/efi.h>
43
44#include <iprt/asm.h>
45#include <iprt/assert.h>
46#include <iprt/crc.h>
47#include <iprt/file.h>
48#include <iprt/err.h>
49#include <iprt/log.h>
50#include <iprt/mem.h>
51#include <iprt/string.h>
52#include <iprt/uuid.h>
53#include <iprt/utf16.h>
54#include <iprt/vfs.h>
55#include <iprt/vfslowlevel.h>
56#include <iprt/formats/efi-fv.h>
57#include <iprt/formats/efi-varstore.h>
58
59
60/*********************************************************************************************************************************
61* Defined Constants And Macros *
62*********************************************************************************************************************************/
63
64
65/*********************************************************************************************************************************
66* Structures and Typedefs *
67*********************************************************************************************************************************/
68/** Pointer to the varstore filesystem data. */
69typedef struct RTEFIVARSTORE *PRTEFIVARSTORE;
70
71
72/**
73 * EFI variable entry.
74 */
75typedef struct RTEFIVAR
76{
77 /** Pointer to the owning variable store. */
78 PRTEFIVARSTORE pVarStore;
79 /** Offset of the variable data located in the backing image - 0 if not written yet. */
80 uint64_t offVarData;
81 /** Pointer to the in memory data, NULL if not yet read. */
82 void *pvData;
83 /** Monotonic counter value. */
84 uint64_t cMonotonic;
85 /** Size of the variable data in bytes. */
86 uint32_t cbData;
87 /** Index of the assoicated public key. */
88 uint32_t idPubKey;
89 /** Attributes for the variable. */
90 uint32_t fAttr;
91 /** Flag whether the variable was deleted. */
92 bool fDeleted;
93 /** Name of the variable. */
94 char *pszName;
95 /** The raw EFI timestamp as read from the header. */
96 EFI_TIME EfiTimestamp;
97 /** The creation/update time. */
98 RTTIMESPEC Time;
99 /** The vendor UUID of the variable. */
100 RTUUID Uuid;
101} RTEFIVAR;
102/** Pointer to an EFI variable. */
103typedef RTEFIVAR *PRTEFIVAR;
104
105
106/**
107 * EFI GUID entry.
108 */
109typedef struct RTEFIGUID
110{
111 /** The UUID representation of the GUID. */
112 RTUUID Uuid;
113 /** Pointer to the array of indices into RTEFIVARSTORE::paVars. */
114 uint32_t *paidxVars;
115 /** Number of valid indices in the array. */
116 uint32_t cVars;
117 /** Maximum number of indices the array can hold. */
118 uint32_t cVarsMax;
119} RTEFIGUID;
120/** Pointer to an EFI variable. */
121typedef RTEFIGUID *PRTEFIGUID;
122
123
124/**
125 * EFI variable store filesystem volume.
126 */
127typedef struct RTEFIVARSTORE
128{
129 /** Handle to itself. */
130 RTVFS hVfsSelf;
131 /** The file, partition, or whatever backing the volume has. */
132 RTVFSFILE hVfsBacking;
133 /** The size of the backing thingy. */
134 uint64_t cbBacking;
135
136 /** RTVFSMNT_F_XXX. */
137 uint32_t fMntFlags;
138 /** RTEFIVARSTOREVFS_F_XXX (currently none defined). */
139 uint32_t fVarStoreFlags;
140
141 /** Size of the variable store (minus the header). */
142 uint64_t cbVarStore;
143 /** Start offset into the backing image where the variable data starts. */
144 uint64_t offStoreData;
145 /** Flag whether the variable store uses authenticated variables. */
146 bool fAuth;
147 /** Number of bytes occupied by existing variables. */
148 uint64_t cbVarData;
149
150 /** Pointer to the array of variables sorted by start offset. */
151 PRTEFIVAR paVars;
152 /** Number of valid variables in the array. */
153 uint32_t cVars;
154 /** Maximum number of variables the array can hold. */
155 uint32_t cVarsMax;
156
157 /** Pointer to the array of vendor GUIDS. */
158 PRTEFIGUID paGuids;
159 /** Number of valid GUIDS in the array. */
160 uint32_t cGuids;
161 /** Maximum number of GUIDS the array can hold. */
162 uint32_t cGuidsMax;
163
164} RTEFIVARSTORE;
165
166
167/**
168 * Variable store directory type.
169 */
170typedef enum RTEFIVARSTOREDIRTYPE
171{
172 /** Invalid directory type. */
173 RTEFIVARSTOREDIRTYPE_INVALID = 0,
174 /** Root directory type. */
175 RTEFIVARSTOREDIRTYPE_ROOT,
176 /** 'by-name' directory. */
177 RTEFIVARSTOREDIRTYPE_BY_NAME,
178 /** 'by-uuid' directory. */
179 RTEFIVARSTOREDIRTYPE_BY_GUID,
180 /** 'raw' directory. */
181 RTEFIVARSTOREDIRTYPE_RAW,
182 /** Specific 'by-uuid/{...}' directory. */
183 RTEFIVARSTOREDIRTYPE_GUID,
184 /** Specific 'raw/{...}' directory. */
185 RTEFIVARSTOREDIRTYPE_RAW_ENTRY,
186 /** 32bit blowup hack. */
187 RTEFIVARSTOREDIRTYPE_32BIT_HACK = 0x7fffffff
188} RTEFIVARSTOREDIRTYPE;
189
190
191/**
192 * EFI variable store directory entry.
193 */
194typedef struct RTEFIVARSTOREDIRENTRY
195{
196 /** Name of the directory if constant. */
197 const char *pszName;
198 /** Size of the name. */
199 size_t cbName;
200 /** Entry type. */
201 RTEFIVARSTOREDIRTYPE enmType;
202 /** Parent entry type. */
203 RTEFIVARSTOREDIRTYPE enmParentType;
204} RTEFIVARSTOREDIRENTRY;
205/** Pointer to a EFI variable store directory entry. */
206typedef RTEFIVARSTOREDIRENTRY *PRTEFIVARSTOREDIRENTRY;
207/** Pointer to a const EFI variable store directory entry. */
208typedef const RTEFIVARSTOREDIRENTRY *PCRTEFIVARSTOREDIRENTRY;
209
210
211/**
212 * Variable store directory.
213 */
214typedef struct RTEFIVARSTOREDIR
215{
216 /* Flag whether we reached the end of directory entries. */
217 bool fNoMoreFiles;
218 /** The index of the next item to read. */
219 uint32_t idxNext;
220 /** Directory entry. */
221 PCRTEFIVARSTOREDIRENTRY pEntry;
222 /** The variable store associated with this directory. */
223 PRTEFIVARSTORE pVarStore;
224 /** Time when the directory was created. */
225 RTTIMESPEC Time;
226 /** Pointer to the GUID entry, only valid for RTEFIVARSTOREDIRTYPE_GUID. */
227 PRTEFIGUID pGuid;
228 /** The variable ID, only valid for RTEFIVARSTOREDIRTYPE_RAW_ENTRY. */
229 uint32_t idVar;
230} RTEFIVARSTOREDIR;
231/** Pointer to an Variable store directory. */
232typedef RTEFIVARSTOREDIR *PRTEFIVARSTOREDIR;
233
234
235/**
236 * File type.
237 */
238typedef enum RTEFIVARSTOREFILETYPE
239{
240 /** Invalid type, do not use. */
241 RTEFIVARSTOREFILETYPE_INVALID = 0,
242 /** File accesses the data portion of the variable. */
243 RTEFIVARSTOREFILETYPE_DATA,
244 /** File accesses the attributes of the variable. */
245 RTEFIVARSTOREFILETYPE_ATTR,
246 /** File accesses the UUID of the variable. */
247 RTEFIVARSTOREFILETYPE_UUID,
248 /** File accesses the public key index of the variable. */
249 RTEFIVARSTOREFILETYPE_PUBKEY,
250 /** File accesses the raw EFI Time of the variable. */
251 RTEFIVARSTOREFILETYPE_TIME,
252 /** The monotonic counter (deprecated). */
253 RTEFIVARSTOREFILETYPE_MONOTONIC,
254 /** 32bit hack. */
255 RTEFIVARSTOREFILETYPE_32BIT_HACK = 0x7fffffff
256} RTEFIVARSTOREFILETYPE;
257
258
259/**
260 * Raw file type entry.
261 */
262typedef struct RTEFIVARSTOREFILERAWENTRY
263{
264 /** Name of the entry. */
265 const char *pszName;
266 /** The associated file type. */
267 RTEFIVARSTOREFILETYPE enmType;
268 /** File size of the object, 0 if dynamic. */
269 size_t cbObject;
270 /** Offset of the item in the variable header. */
271 uint32_t offObject;
272} RTEFIVARSTOREFILERAWENTRY;
273/** Pointer to a raw file type entry. */
274typedef RTEFIVARSTOREFILERAWENTRY *PRTEFIVARSTOREFILERAWENTRY;
275/** Pointer to a const file type entry. */
276typedef const RTEFIVARSTOREFILERAWENTRY *PCRTEFIVARSTOREFILERAWENTRY;
277
278
279/**
280 * Open file instance.
281 */
282typedef struct RTEFIVARFILE
283{
284 /** The file type. */
285 PCRTEFIVARSTOREFILERAWENTRY pEntry;
286 /** Variable store this file belongs to. */
287 PRTEFIVARSTORE pVarStore;
288 /** The underlying variable structure. */
289 PRTEFIVAR pVar;
290 /** Current offset into the file for I/O. */
291 RTFOFF offFile;
292} RTEFIVARFILE;
293/** Pointer to an open file instance. */
294typedef RTEFIVARFILE *PRTEFIVARFILE;
295
296
297/**
298 * Directories.
299 */
300static const RTEFIVARSTOREDIRENTRY g_aDirs[] =
301{
302 { NULL, 0, RTEFIVARSTOREDIRTYPE_ROOT, RTEFIVARSTOREDIRTYPE_ROOT },
303 { RT_STR_TUPLE("by-name"), RTEFIVARSTOREDIRTYPE_BY_NAME, RTEFIVARSTOREDIRTYPE_ROOT },
304 { RT_STR_TUPLE("by-uuid"), RTEFIVARSTOREDIRTYPE_BY_GUID, RTEFIVARSTOREDIRTYPE_ROOT },
305 { RT_STR_TUPLE("raw"), RTEFIVARSTOREDIRTYPE_RAW, RTEFIVARSTOREDIRTYPE_ROOT },
306 { NULL, 0, RTEFIVARSTOREDIRTYPE_GUID, RTEFIVARSTOREDIRTYPE_BY_GUID },
307 { NULL, 0, RTEFIVARSTOREDIRTYPE_RAW_ENTRY, RTEFIVARSTOREDIRTYPE_RAW },
308};
309
310
311/**
312 * Raw files for accessing specific items in the variable header.
313 */
314static const RTEFIVARSTOREFILERAWENTRY g_aRawFiles[] =
315{
316 { "attr", RTEFIVARSTOREFILETYPE_ATTR, sizeof(uint32_t), RT_UOFFSETOF(RTEFIVAR, fAttr) },
317 { "data", RTEFIVARSTOREFILETYPE_DATA, 0, 0 },
318 { "uuid", RTEFIVARSTOREFILETYPE_UUID, sizeof(RTUUID), RT_UOFFSETOF(RTEFIVAR, Uuid) },
319 { "pubkey", RTEFIVARSTOREFILETYPE_PUBKEY, sizeof(uint32_t), RT_UOFFSETOF(RTEFIVAR, idPubKey) },
320 { "time", RTEFIVARSTOREFILETYPE_TIME, sizeof(EFI_TIME), RT_UOFFSETOF(RTEFIVAR, EfiTimestamp) },
321 { "monotonic", RTEFIVARSTOREFILETYPE_MONOTONIC, sizeof(uint64_t), RT_UOFFSETOF(RTEFIVAR, cMonotonic) }
322};
323
324#define RTEFIVARSTORE_FILE_ENTRY_DATA 1
325
326
327/*********************************************************************************************************************************
328* Internal Functions *
329*********************************************************************************************************************************/
330static int rtEfiVarStore_NewDirByType(PRTEFIVARSTORE pThis, RTEFIVARSTOREDIRTYPE enmDirType,
331 PRTEFIGUID pGuid, uint32_t idVar, PRTVFSOBJ phVfsObj);
332
333
334#ifdef LOG_ENABLED
335
336/**
337 * Logs a firmware volume header.
338 *
339 * @param pFvHdr The firmware volume header.
340 */
341static void rtEfiVarStoreFvHdr_Log(PCEFI_FIRMWARE_VOLUME_HEADER pFvHdr)
342{
343 if (LogIs2Enabled())
344 {
345 Log2(("EfiVarStore: Volume Header:\n"));
346 Log2(("EfiVarStore: abZeroVec %#.*Rhxs\n", sizeof(pFvHdr->abZeroVec), &pFvHdr->abZeroVec[0]));
347 Log2(("EfiVarStore: GuidFilesystem %#.*Rhxs\n", sizeof(pFvHdr->GuidFilesystem), &pFvHdr->GuidFilesystem));
348 Log2(("EfiVarStore: cbFv %#RX64\n", RT_LE2H_U64(pFvHdr->cbFv)));
349 Log2(("EfiVarStore: u32Signature %#RX32\n", RT_LE2H_U32(pFvHdr->u32Signature)));
350 Log2(("EfiVarStore: fAttr %#RX32\n", RT_LE2H_U32(pFvHdr->fAttr)));
351 Log2(("EfiVarStore: cbFvHdr %#RX16\n", RT_LE2H_U16(pFvHdr->cbFvHdr)));
352 Log2(("EfiVarStore: u16Chksum %#RX16\n", RT_LE2H_U16(pFvHdr->u16Chksum)));
353 Log2(("EfiVarStore: offExtHdr %#RX16\n", RT_LE2H_U16(pFvHdr->offExtHdr)));
354 Log2(("EfiVarStore: bRsvd %#RX8\n", pFvHdr->bRsvd));
355 Log2(("EfiVarStore: bRevision %#RX8\n", pFvHdr->bRevision));
356 }
357}
358
359
360/**
361 * Logs a variable store header.
362 *
363 * @param pStoreHdr The variable store header.
364 */
365static void rtEfiVarStoreHdr_Log(PCEFI_VARSTORE_HEADER pStoreHdr)
366{
367 if (LogIs2Enabled())
368 {
369 Log2(("EfiVarStore: Variable Store Header:\n"));
370 Log2(("EfiVarStore: GuidVarStore %#.*Rhxs\n", sizeof(pStoreHdr->GuidVarStore), &pStoreHdr->GuidVarStore));
371 Log2(("EfiVarStore: cbVarStore %#RX32\n", RT_LE2H_U32(pStoreHdr->cbVarStore)));
372 Log2(("EfiVarStore: bFmt %#RX8\n", pStoreHdr->bFmt));
373 Log2(("EfiVarStore: bState %#RX8\n", pStoreHdr->bState));
374 }
375}
376
377
378/**
379 * Logs a authenticated variable header.
380 *
381 * @param pVarHdr The authenticated variable header.
382 * @param offVar Offset of the authenticated variable header.
383 */
384static void rtEfiVarStoreAuthVarHdr_Log(PCEFI_AUTH_VAR_HEADER pVarHdr, uint64_t offVar)
385{
386 if (LogIs2Enabled())
387 {
388 Log2(("EfiVarStore: Authenticated Variable Header at offset %#RU64:\n", offVar));
389 Log2(("EfiVarStore: u16StartId %#RX16\n", RT_LE2H_U16(pVarHdr->u16StartId)));
390 Log2(("EfiVarStore: bState %#RX8\n", pVarHdr->bState));
391 Log2(("EfiVarStore: bRsvd %#RX8\n", pVarHdr->bRsvd));
392 Log2(("EfiVarStore: fAttr %#RX32\n", RT_LE2H_U32(pVarHdr->fAttr)));
393 Log2(("EfiVarStore: cMonotonic %#RX64\n", RT_LE2H_U64(pVarHdr->cMonotonic)));
394 Log2(("EfiVarStore: Timestamp.u16Year %#RX16\n", RT_LE2H_U16(pVarHdr->Timestamp.u16Year)));
395 Log2(("EfiVarStore: Timestamp.u8Month %#RX8\n", pVarHdr->Timestamp.u8Month));
396 Log2(("EfiVarStore: Timestamp.u8Day %#RX8\n", pVarHdr->Timestamp.u8Day));
397 Log2(("EfiVarStore: Timestamp.u8Hour %#RX8\n", pVarHdr->Timestamp.u8Hour));
398 Log2(("EfiVarStore: Timestamp.u8Minute %#RX8\n", pVarHdr->Timestamp.u8Minute));
399 Log2(("EfiVarStore: Timestamp.u8Second %#RX8\n", pVarHdr->Timestamp.u8Second));
400 Log2(("EfiVarStore: Timestamp.bPad0 %#RX8\n", pVarHdr->Timestamp.bPad0));
401 Log2(("EfiVarStore: Timestamp.u32Nanosecond %#RX32\n", RT_LE2H_U32(pVarHdr->Timestamp.u32Nanosecond)));
402 Log2(("EfiVarStore: Timestamp.iTimezone %#RI16\n", RT_LE2H_S16(pVarHdr->Timestamp.iTimezone)));
403 Log2(("EfiVarStore: Timestamp.u8Daylight %#RX8\n", pVarHdr->Timestamp.u8Daylight));
404 Log2(("EfiVarStore: Timestamp.bPad1 %#RX8\n", pVarHdr->Timestamp.bPad1));
405 Log2(("EfiVarStore: idPubKey %#RX32\n", RT_LE2H_U32(pVarHdr->idPubKey)));
406 Log2(("EfiVarStore: cbName %#RX32\n", RT_LE2H_U32(pVarHdr->cbName)));
407 Log2(("EfiVarStore: cbData %#RX32\n", RT_LE2H_U32(pVarHdr->cbData)));
408 Log2(("EfiVarStore: GuidVendor %#.*Rhxs\n", sizeof(pVarHdr->GuidVendor), &pVarHdr->GuidVendor));
409 }
410}
411
412#endif /* LOG_ENABLED */
413
414/**
415 * Worker for rtEfiVarStoreFile_QueryInfo() and rtEfiVarStoreDir_QueryInfo().
416 *
417 * @returns IPRT status code.
418 * @param cbObject Size of the object in bytes.
419 * @param fIsDir Flag whether the object is a directory or file.
420 * @param pTime The time to use.
421 * @param pObjInfo The FS object information structure to fill in.
422 * @param enmAddAttr What to fill in.
423 */
424static int rtEfiVarStore_QueryInfo(uint64_t cbObject, bool fIsDir, PCRTTIMESPEC pTime, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
425{
426 pObjInfo->cbObject = cbObject;
427 pObjInfo->cbAllocated = cbObject;
428 pObjInfo->AccessTime = *pTime;
429 pObjInfo->ModificationTime = *pTime;
430 pObjInfo->ChangeTime = *pTime;
431 pObjInfo->BirthTime = *pTime;
432 pObjInfo->Attr.fMode = fIsDir
433 ? RTFS_TYPE_DIRECTORY | RTFS_UNIX_ALL_ACCESS_PERMS
434 : RTFS_TYPE_FILE | RTFS_UNIX_IWOTH | RTFS_UNIX_IROTH
435 | RTFS_UNIX_IWGRP | RTFS_UNIX_IRGRP
436 | RTFS_UNIX_IWUSR | RTFS_UNIX_IRUSR;
437 pObjInfo->Attr.enmAdditional = enmAddAttr;
438
439 switch (enmAddAttr)
440 {
441 case RTFSOBJATTRADD_NOTHING: RT_FALL_THRU();
442 case RTFSOBJATTRADD_UNIX:
443 pObjInfo->Attr.u.Unix.uid = NIL_RTUID;
444 pObjInfo->Attr.u.Unix.gid = NIL_RTGID;
445 pObjInfo->Attr.u.Unix.cHardlinks = 1;
446 pObjInfo->Attr.u.Unix.INodeIdDevice = 0;
447 pObjInfo->Attr.u.Unix.INodeId = 0;
448 pObjInfo->Attr.u.Unix.fFlags = 0;
449 pObjInfo->Attr.u.Unix.GenerationId = 0;
450 pObjInfo->Attr.u.Unix.Device = 0;
451 break;
452 case RTFSOBJATTRADD_UNIX_OWNER:
453 pObjInfo->Attr.u.UnixOwner.uid = 0;
454 pObjInfo->Attr.u.UnixOwner.szName[0] = '\0';
455 break;
456 case RTFSOBJATTRADD_UNIX_GROUP:
457 pObjInfo->Attr.u.UnixGroup.gid = 0;
458 pObjInfo->Attr.u.UnixGroup.szName[0] = '\0';
459 break;
460 case RTFSOBJATTRADD_EASIZE:
461 pObjInfo->Attr.u.EASize.cb = 0;
462 break;
463 default:
464 return VERR_INVALID_PARAMETER;
465 }
466 return VINF_SUCCESS;
467}
468
469
470/**
471 * Tries to find and return the GUID entry for the given UUID.
472 *
473 * @returns Pointer to the GUID entry or NULL if not found.
474 * @param pThis The EFI variable store instance.
475 * @param pUuid The UUID to look for.
476 */
477static PRTEFIGUID rtEfiVarStore_GetGuid(PRTEFIVARSTORE pThis, PCRTUUID pUuid)
478{
479 for (uint32_t i = 0; i < pThis->cGuids; i++)
480 if (!RTUuidCompare(&pThis->paGuids[i].Uuid, pUuid))
481 return &pThis->paGuids[i];
482
483 return NULL;
484}
485
486
487/**
488 * Adds the given UUID to the array of known GUIDs.
489 *
490 * @returns Pointer to the GUID entry or NULL if out of memory.
491 * @param pThis The EFI variable store instance.
492 * @param pUuid The UUID to add.
493 */
494static PRTEFIGUID rtEfiVarStore_AddGuid(PRTEFIVARSTORE pThis, PCRTUUID pUuid)
495{
496 if (pThis->cGuids == pThis->cGuidsMax)
497 {
498 /* Grow the array. */
499 uint32_t cGuidsMaxNew = pThis->cGuidsMax + 10;
500 PRTEFIGUID paGuidsNew = (PRTEFIGUID)RTMemRealloc(pThis->paGuids, cGuidsMaxNew * sizeof(RTEFIGUID));
501 if (!paGuidsNew)
502 return NULL;
503
504 pThis->paGuids = paGuidsNew;
505 pThis->cGuidsMax = cGuidsMaxNew;
506 }
507
508 PRTEFIGUID pGuid = &pThis->paGuids[pThis->cGuids++];
509 pGuid->Uuid = *pUuid;
510 pGuid->paidxVars = NULL;
511 pGuid->cVars = 0;
512 pGuid->cVarsMax = 0;
513 return pGuid;
514}
515
516
517/**
518 * Adds the given variable to the GUID array.
519 *
520 * @returns IPRT status code.
521 * @param pThis The EFI variable store instance.
522 * @param pUuid The UUID of the variable.
523 * @param idVar The variable index into the array.
524 */
525static int rtEfiVarStore_AddVarByGuid(PRTEFIVARSTORE pThis, PCRTUUID pUuid, uint32_t idVar)
526{
527 PRTEFIGUID pGuid = rtEfiVarStore_GetGuid(pThis, pUuid);
528 if (!pGuid)
529 pGuid = rtEfiVarStore_AddGuid(pThis, pUuid);
530
531 if ( pGuid
532 && pGuid->cVars == pGuid->cVarsMax)
533 {
534 /* Grow the array. */
535 uint32_t cVarsMaxNew = pGuid->cVarsMax + 10;
536 uint32_t *paidxVarsNew = (uint32_t *)RTMemRealloc(pGuid->paidxVars, cVarsMaxNew * sizeof(uint32_t));
537 if (!paidxVarsNew)
538 return VERR_NO_MEMORY;
539
540 pGuid->paidxVars = paidxVarsNew;
541 pGuid->cVarsMax = cVarsMaxNew;
542 }
543
544 int rc = VINF_SUCCESS;
545 if (pGuid)
546 pGuid->paidxVars[pGuid->cVars++] = idVar;
547 else
548 rc = VERR_NO_MEMORY;
549
550 return rc;
551}
552
553
554/**
555 * Reads variable data from the given memory area.
556 *
557 * @returns IPRT status code.
558 * @param pThis The EFI variable file instance.
559 * @param pvData Pointer to the start of the data.
560 * @param cbData Size of the variable data in bytes.
561 * @param off Where to start reading relative from the data start offset.
562 * @param pSgBuf Where to store the read data.
563 * @param pcbRead Where to return the number of bytes read, optional.
564 */
565static int rtEfiVarStoreFile_ReadMem(PRTEFIVARFILE pThis, const void *pvData, size_t cbData,
566 RTFOFF off, PCRTSGBUF pSgBuf, size_t *pcbRead)
567{
568 int rc = VINF_SUCCESS;
569 size_t cbRead = pSgBuf->paSegs[0].cbSeg;
570 size_t cbThisRead = RT_MIN(cbData - off, cbRead);
571 const uint8_t *pbData = (const uint8_t *)pvData;
572 if (!pcbRead)
573 {
574 if (cbThisRead == cbRead)
575 memcpy(pSgBuf->paSegs[0].pvSeg, &pbData[off], cbThisRead);
576 else
577 rc = VERR_EOF;
578
579 if (RT_SUCCESS(rc))
580 pThis->offFile = off + cbThisRead;
581 Log6(("rtEfiVarStoreFile_ReadMem: off=%#RX64 cbSeg=%#x -> %Rrc\n", off, pSgBuf->paSegs[0].cbSeg, rc));
582 }
583 else
584 {
585 if ((uint64_t)off >= cbData)
586 {
587 *pcbRead = 0;
588 rc = VINF_EOF;
589 }
590 else
591 {
592 memcpy(pSgBuf->paSegs[0].pvSeg, &pbData[off], cbThisRead);
593 /* Return VINF_EOF if beyond end-of-file. */
594 if (cbThisRead < cbRead)
595 rc = VINF_EOF;
596 pThis->offFile = off + cbThisRead;
597 *pcbRead = cbThisRead;
598 }
599 Log6(("rtEfiVarStoreFile_ReadMem: off=%#RX64 cbSeg=%#x -> %Rrc *pcbRead=%#x\n", off, pSgBuf->paSegs[0].cbSeg, rc, *pcbRead));
600 }
601
602 return rc;
603}
604
605
606/**
607 * Writes variable data from the given memory area.
608 *
609 * @returns IPRT status code.
610 * @param pThis The EFI variable file instance.
611 * @param pvData Pointer to the start of the data.
612 * @param cbData Size of the variable data in bytes.
613 * @param off Where to start writing relative from the data start offset.
614 * @param pSgBuf The data to write.
615 * @param pcbWritten Where to return the number of bytes written, optional.
616 */
617static int rtEfiVarStoreFile_WriteMem(PRTEFIVARFILE pThis, void *pvData, size_t cbData,
618 RTFOFF off, PCRTSGBUF pSgBuf, size_t *pcbWritten)
619{
620 int rc = VINF_SUCCESS;
621 size_t cbWrite = pSgBuf->paSegs[0].cbSeg;
622 size_t cbThisWrite = RT_MIN(cbData - off, cbWrite);
623 uint8_t *pbData = (uint8_t *)pvData;
624 if (!pcbWritten)
625 {
626 if (cbThisWrite == cbWrite)
627 memcpy(&pbData[off], pSgBuf->paSegs[0].pvSeg, cbThisWrite);
628 else
629 rc = VERR_EOF;
630
631 if (RT_SUCCESS(rc))
632 pThis->offFile = off + cbThisWrite;
633 Log6(("rtEfiVarStoreFile_WriteMem: off=%#RX64 cbSeg=%#x -> %Rrc\n", off, pSgBuf->paSegs[0].cbSeg, rc));
634 }
635 else
636 {
637 if ((uint64_t)off >= cbData)
638 {
639 *pcbWritten = 0;
640 rc = VINF_EOF;
641 }
642 else
643 {
644 memcpy(&pbData[off], pSgBuf->paSegs[0].pvSeg, cbThisWrite);
645 /* Return VINF_EOF if beyond end-of-file. */
646 if (cbThisWrite < cbWrite)
647 rc = VINF_EOF;
648 pThis->offFile = off + cbThisWrite;
649 *pcbWritten = cbThisWrite;
650 }
651 Log6(("rtEfiVarStoreFile_WriteMem: off=%#RX64 cbSeg=%#x -> %Rrc *pcbWritten=%#x\n", off, pSgBuf->paSegs[0].cbSeg, rc, *pcbWritten));
652 }
653
654 return rc;
655}
656
657
658/**
659 * Reads variable data from the given range.
660 *
661 * @returns IPRT status code.
662 * @param pThis The EFI variable file instance.
663 * @param offData Where the data starts in the backing storage.
664 * @param cbData Size of the variable data in bytes.
665 * @param off Where to start reading relative from the data start offset.
666 * @param pSgBuf Where to store the read data.
667 * @param pcbRead Where to return the number of bytes read, optional.
668 */
669static int rtEfiVarStoreFile_ReadFile(PRTEFIVARFILE pThis, uint64_t offData, size_t cbData,
670 RTFOFF off, PCRTSGBUF pSgBuf, size_t *pcbRead)
671{
672 int rc;
673 PRTEFIVARSTORE pVarStore = pThis->pVarStore;
674 size_t cbRead = pSgBuf->paSegs[0].cbSeg;
675 size_t cbThisRead = RT_MIN(cbData - off, cbRead);
676 uint64_t offStart = offData + off;
677 if (!pcbRead)
678 {
679 if (cbThisRead == cbRead)
680 rc = RTVfsFileReadAt(pVarStore->hVfsBacking, offStart, pSgBuf->paSegs[0].pvSeg, cbThisRead, NULL);
681 else
682 rc = VERR_EOF;
683
684 if (RT_SUCCESS(rc))
685 pThis->offFile = off + cbThisRead;
686 Log6(("rtFsEfiVarStore_Read: off=%#RX64 cbSeg=%#x -> %Rrc\n", off, pSgBuf->paSegs[0].cbSeg, rc));
687 }
688 else
689 {
690 if ((uint64_t)off >= cbData)
691 {
692 *pcbRead = 0;
693 rc = VINF_EOF;
694 }
695 else
696 {
697 rc = RTVfsFileReadAt(pVarStore->hVfsBacking, offStart, pSgBuf->paSegs[0].pvSeg, cbThisRead, NULL);
698 if (RT_SUCCESS(rc))
699 {
700 /* Return VINF_EOF if beyond end-of-file. */
701 if (cbThisRead < cbRead)
702 rc = VINF_EOF;
703 pThis->offFile = off + cbThisRead;
704 *pcbRead = cbThisRead;
705 }
706 else
707 *pcbRead = 0;
708 }
709 Log6(("rtFsEfiVarStore_Read: off=%#RX64 cbSeg=%#x -> %Rrc *pcbRead=%#x\n", off, pSgBuf->paSegs[0].cbSeg, rc, *pcbRead));
710 }
711
712 return rc;
713}
714
715
716/**
717 * Ensures that the variable data is available before any modification.
718 *
719 * @returns IPRT status code.
720 * @param pVar The variable instance.
721 */
722static int rtEfiVarStore_VarReadData(PRTEFIVAR pVar)
723{
724 if (RT_LIKELY( !pVar->offVarData
725 || !pVar->cbData))
726 return VINF_SUCCESS;
727
728 Assert(!pVar->pvData);
729 pVar->pvData = RTMemAlloc(pVar->cbData);
730 if (RT_UNLIKELY(!pVar->pvData))
731 return VERR_NO_MEMORY;
732
733 PRTEFIVARSTORE pVarStore = pVar->pVarStore;
734 int rc = RTVfsFileReadAt(pVarStore->hVfsBacking, pVar->offVarData, pVar->pvData, pVar->cbData, NULL);
735 if (RT_SUCCESS(rc))
736 pVar->offVarData = 0; /* Marks the variable data as in memory. */
737 else
738 {
739 RTMemFree(pVar->pvData);
740 pVar->pvData = NULL;
741 }
742
743 return rc;
744}
745
746
747/**
748 * Ensures that the given variable has the given data size.
749 *
750 * @returns IPRT status code.
751 * @retval VERR_DISK_FULL if the new size would exceed the variable storage size.
752 * @param pVar The variable instance.
753 * @param cbData New number of bytes of data for the variable.
754 */
755static int rtEfiVarStore_VarEnsureDataSz(PRTEFIVAR pVar, size_t cbData)
756{
757 PRTEFIVARSTORE pVarStore = pVar->pVarStore;
758
759 if (pVar->cbData == cbData)
760 return VINF_SUCCESS;
761
762 if ((uint32_t)cbData != cbData)
763 return VERR_FILE_TOO_BIG;
764
765 int rc = VINF_SUCCESS;
766 if (cbData < pVar->cbData)
767 {
768 /* Shrink. */
769 void *pvNew = RTMemRealloc(pVar->pvData, cbData);
770 if (pvNew)
771 {
772 pVar->pvData = pvNew;
773 pVarStore->cbVarData -= pVar->cbData - cbData;
774 pVar->cbData = (uint32_t)cbData;
775 }
776 else
777 rc = VERR_NO_MEMORY;
778 }
779 else if (cbData > pVar->cbData)
780 {
781 /* Grow. */
782 if (pVarStore->cbVarStore - pVarStore->cbVarData >= cbData - pVar->cbData)
783 {
784 void *pvNew = RTMemRealloc(pVar->pvData, cbData);
785 if (pvNew)
786 {
787 pVar->pvData = pvNew;
788 pVarStore->cbVarData += cbData - pVar->cbData;
789 pVar->cbData = (uint32_t)cbData;
790 }
791 else
792 rc = VERR_NO_MEMORY;
793 }
794 else
795 rc = VERR_DISK_FULL;
796 }
797
798 return rc;
799}
800
801
802/**
803 * Flush the variable store to the backing storage. This will remove any
804 * deleted variables in the backing storage.
805 *
806 * @returns IPRT status code.
807 * @param pThis The EFI variable store instance.
808 */
809static int rtEfiVarStore_Flush(PRTEFIVARSTORE pThis)
810{
811 int rc = VINF_SUCCESS;
812 uint64_t offCur = pThis->offStoreData;
813
814 for (uint32_t i = 0; i < pThis->cVars && RT_SUCCESS(rc); i++)
815 {
816 PRTUTF16 pwszName = NULL;
817 size_t cwcLen = 0;
818 PRTEFIVAR pVar = &pThis->paVars[i];
819
820 if (!pVar->fDeleted)
821 {
822 rc = RTStrToUtf16Ex(pVar->pszName, RTSTR_MAX, &pwszName, 0, &cwcLen);
823 if (RT_SUCCESS(rc))
824 {
825 cwcLen++; /* Include the terminator. */
826
827 /* Read in the data of the variable if it exists. */
828 rc = rtEfiVarStore_VarReadData(pVar);
829 if (RT_SUCCESS(rc))
830 {
831 /* Write out the variable. */
832 EFI_AUTH_VAR_HEADER VarHdr;
833 size_t cbName = cwcLen * sizeof(RTUTF16);
834
835 VarHdr.u16StartId = RT_H2LE_U16(EFI_AUTH_VAR_HEADER_START);
836 VarHdr.bState = EFI_AUTH_VAR_HEADER_STATE_ADDED;
837 VarHdr.bRsvd = 0;
838 VarHdr.fAttr = RT_H2LE_U32(pVar->fAttr);
839 VarHdr.cMonotonic = RT_H2LE_U64(pVar->cMonotonic);
840 VarHdr.idPubKey = RT_H2LE_U32(pVar->idPubKey);
841 VarHdr.cbName = RT_H2LE_U32((uint32_t)cbName);
842 VarHdr.cbData = RT_H2LE_U32(pVar->cbData);
843 RTEfiGuidFromUuid(&VarHdr.GuidVendor, &pVar->Uuid);
844 memcpy(&VarHdr.Timestamp, &pVar->EfiTimestamp, sizeof(pVar->EfiTimestamp));
845
846 rc = RTVfsFileWriteAt(pThis->hVfsBacking, offCur, &VarHdr, sizeof(VarHdr), NULL);
847 if (RT_SUCCESS(rc))
848 rc = RTVfsFileWriteAt(pThis->hVfsBacking, offCur + sizeof(VarHdr), pwszName, cbName, NULL);
849 if (RT_SUCCESS(rc))
850 rc = RTVfsFileWriteAt(pThis->hVfsBacking, offCur + sizeof(VarHdr) + cbName, pVar->pvData, pVar->cbData, NULL);
851 if (RT_SUCCESS(rc))
852 {
853 offCur += sizeof(VarHdr) + cbName + pVar->cbData;
854 uint64_t offCurAligned = RT_ALIGN_64(offCur, sizeof(uint32_t));
855 if (offCurAligned > offCur)
856 {
857 /* Should be at most 3 bytes to align the next variable to a 32bit boundary. */
858 Assert(offCurAligned - offCur <= 3);
859 uint8_t abFill[3] = { 0xff };
860 rc = RTVfsFileWriteAt(pThis->hVfsBacking, offCur, &abFill[0], offCurAligned - offCur, NULL);
861 }
862
863 offCur = offCurAligned;
864 }
865 }
866
867 RTUtf16Free(pwszName);
868 }
869 }
870 }
871
872 if (RT_SUCCESS(rc))
873 {
874 /* Fill the remainder with 0xff as it would be the case for a real NAND flash device. */
875 uint8_t abFF[512];
876 memset(&abFF[0], 0xff, sizeof(abFF));
877
878 uint64_t offStart = offCur;
879 uint64_t offEnd = pThis->offStoreData + pThis->cbVarStore;
880 while ( offStart < offEnd
881 && RT_SUCCESS(rc))
882 {
883 size_t cbThisWrite = RT_MIN(sizeof(abFF), offEnd - offStart);
884 rc = RTVfsFileWriteAt(pThis->hVfsBacking, offStart, &abFF[0], cbThisWrite, NULL);
885 offStart += cbThisWrite;
886 }
887 }
888
889 return rc;
890}
891
892
893/**
894 * Tries to find a variable with the given name.
895 *
896 * @returns Pointer to the variable if found or NULL otherwise.
897 * @param pThis The variable store instance.
898 * @param pszName Name of the variable to look for.
899 * @param pidVar Where to store the index of the variable, optional.
900 */
901static PRTEFIVAR rtEfiVarStore_VarGet(PRTEFIVARSTORE pThis, const char *pszName, uint32_t *pidVar)
902{
903 for (uint32_t i = 0; i < pThis->cVars; i++)
904 if ( !pThis->paVars[i].fDeleted
905 && !strcmp(pszName, pThis->paVars[i].pszName))
906 {
907 if (pidVar)
908 *pidVar = i;
909 return &pThis->paVars[i];
910 }
911
912 return NULL;
913}
914
915
916/**
917 * Maybe grows the array of variables to hold more entries.
918 *
919 * @returns IPRT status code.
920 * @param pThis The variable store instance.
921 */
922static int rtEfiVarStore_VarMaybeGrowEntries(PRTEFIVARSTORE pThis)
923{
924 if (pThis->cVars == pThis->cVarsMax)
925 {
926 /* Grow the variable array. */
927 uint32_t cVarsMaxNew = pThis->cVarsMax + 10;
928 PRTEFIVAR paVarsNew = (PRTEFIVAR)RTMemRealloc(pThis->paVars, cVarsMaxNew * sizeof(RTEFIVAR));
929 if (!paVarsNew)
930 return VERR_NO_MEMORY;
931
932 pThis->paVars = paVarsNew;
933 pThis->cVarsMax = cVarsMaxNew;
934 }
935
936 return VINF_SUCCESS;
937}
938
939
940/**
941 * Add a variable with the given name.
942 *
943 * @returns Pointer to the entry or NULL if out of memory.
944 * @param pThis The variable store instance.
945 * @param pszName Name of the variable to add.
946 * @param pUuid The UUID of the variable owner.
947 * @param pidVar Where to store the variable index on success, optional
948 */
949static PRTEFIVAR rtEfiVarStore_VarAdd(PRTEFIVARSTORE pThis, const char *pszName, PCRTUUID pUuid, uint32_t *pidVar)
950{
951 Assert(!rtEfiVarStore_VarGet(pThis, pszName, NULL));
952
953 int rc = rtEfiVarStore_VarMaybeGrowEntries(pThis);
954 if (RT_SUCCESS(rc))
955 {
956 PRTEFIVAR pVar = &pThis->paVars[pThis->cVars];
957 RT_ZERO(*pVar);
958
959 pVar->pszName = RTStrDup(pszName);
960 if (pVar->pszName)
961 {
962 pVar->pVarStore = pThis;
963 pVar->offVarData = 0;
964 pVar->fDeleted = false;
965 pVar->Uuid = *pUuid;
966 RTTimeNow(&pVar->Time);
967
968 rc = rtEfiVarStore_AddVarByGuid(pThis, pUuid, pThis->cVars);
969 AssertRC(rc); /** @todo */
970
971 if (pidVar)
972 *pidVar = pThis->cVars;
973 pThis->cVars++;
974 return pVar;
975 }
976 }
977
978 return NULL;
979}
980
981
982/**
983 * Delete the given variable.
984 *
985 * @returns IPRT status code.
986 * @param pThis The variable store instance.
987 * @param pVar The variable.
988 */
989static int rtEfiVarStore_VarDel(PRTEFIVARSTORE pThis, PRTEFIVAR pVar)
990{
991 pVar->fDeleted = true;
992 if (pVar->pvData)
993 RTMemFree(pVar->pvData);
994 pVar->pvData = NULL;
995 pThis->cbVarData -= sizeof(EFI_AUTH_VAR_HEADER) + pVar->cbData;
996 /** @todo Delete from GUID entry. */
997 return VINF_SUCCESS;
998}
999
1000
1001/**
1002 * Delete the variable with the given index.
1003 *
1004 * @returns IPRT status code.
1005 * @param pThis The variable store instance.
1006 * @param idVar The variable index.
1007 */
1008static int rtEfiVarStore_VarDelById(PRTEFIVARSTORE pThis, uint32_t idVar)
1009{
1010 return rtEfiVarStore_VarDel(pThis, &pThis->paVars[idVar]);
1011}
1012
1013
1014/**
1015 * Delete the variable with the given name.
1016 *
1017 * @returns IPRT status code.
1018 * @param pThis The variable store instance.
1019 * @param pszName Name of the variable to delete.
1020 */
1021static int rtEfiVarStore_VarDelByName(PRTEFIVARSTORE pThis, const char *pszName)
1022{
1023 PRTEFIVAR pVar = rtEfiVarStore_VarGet(pThis, pszName, NULL);
1024 if (pVar)
1025 return rtEfiVarStore_VarDel(pThis, pVar);
1026
1027 return VERR_FILE_NOT_FOUND;
1028}
1029
1030
1031/*
1032 *
1033 * File operations.
1034 * File operations.
1035 * File operations.
1036 *
1037 */
1038
1039/**
1040 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
1041 */
1042static DECLCALLBACK(int) rtEfiVarStoreFile_Close(void *pvThis)
1043{
1044 PRTEFIVARFILE pThis = (PRTEFIVARFILE)pvThis;
1045 LogFlow(("rtEfiVarStoreFile_Close(%p/%p)\n", pThis, pThis->pVar));
1046 RT_NOREF(pThis);
1047 return VINF_SUCCESS;
1048}
1049
1050
1051/**
1052 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
1053 */
1054static DECLCALLBACK(int) rtEfiVarStoreFile_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1055{
1056 PRTEFIVARFILE pThis = (PRTEFIVARFILE)pvThis;
1057 uint64_t cbObject = pThis->pEntry->cbObject > 0
1058 ? pThis->pEntry->cbObject
1059 : pThis->pVar->cbData;
1060 return rtEfiVarStore_QueryInfo(cbObject, false /*fIsDir*/, &pThis->pVar->Time, pObjInfo, enmAddAttr);
1061}
1062
1063
1064/**
1065 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
1066 */
1067static DECLCALLBACK(int) rtEfiVarStoreFile_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
1068{
1069 PRTEFIVARFILE pThis = (PRTEFIVARFILE)pvThis;
1070 PRTEFIVAR pVar = pThis->pVar;
1071 AssertReturn(pSgBuf->cSegs == 1, VERR_INTERNAL_ERROR_3);
1072 RT_NOREF(fBlocking);
1073
1074 if (off == -1)
1075 off = pThis->offFile;
1076 else
1077 AssertReturn(off >= 0, VERR_INTERNAL_ERROR_3);
1078
1079 int rc;
1080 if (pThis->pEntry->cbObject)
1081 rc = rtEfiVarStoreFile_ReadMem(pThis, (const uint8_t *)pVar + pThis->pEntry->offObject, pThis->pEntry->cbObject, off, pSgBuf, pcbRead);
1082 else
1083 {
1084 /* Data section. */
1085 if (!pVar->offVarData)
1086 rc = rtEfiVarStoreFile_ReadMem(pThis, pVar->pvData, pVar->cbData, off, pSgBuf, pcbRead);
1087 else
1088 rc = rtEfiVarStoreFile_ReadFile(pThis, pVar->offVarData, pVar->cbData, off, pSgBuf, pcbRead);
1089 }
1090
1091 return rc;
1092}
1093
1094
1095/**
1096 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
1097 */
1098static DECLCALLBACK(int) rtEfiVarStoreFile_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
1099{
1100 PRTEFIVARFILE pThis = (PRTEFIVARFILE)pvThis;
1101 PRTEFIVARSTORE pVarStore = pThis->pVarStore;
1102 PRTEFIVAR pVar = pThis->pVar;
1103 AssertReturn(pSgBuf->cSegs == 1, VERR_INTERNAL_ERROR_3);
1104 RT_NOREF(fBlocking);
1105
1106 if (pVarStore->fMntFlags & RTVFSMNT_F_READ_ONLY)
1107 return VERR_WRITE_PROTECT;
1108
1109 if (off == -1)
1110 off = pThis->offFile;
1111 else
1112 AssertReturn(off >= 0, VERR_INTERNAL_ERROR_3);
1113
1114 int rc;
1115 if (pThis->pEntry->cbObject) /* These can't grow. */
1116 rc = rtEfiVarStoreFile_WriteMem(pThis, (uint8_t *)pVar + pThis->pEntry->offObject, pThis->pEntry->cbObject,
1117 off, pSgBuf, pcbWritten);
1118 else
1119 {
1120 /* Writing data section. */
1121 rc = rtEfiVarStore_VarReadData(pVar);
1122 if (RT_SUCCESS(rc))
1123 {
1124 if (off + pSgBuf->paSegs[0].cbSeg > pVar->cbData)
1125 rc = rtEfiVarStore_VarEnsureDataSz(pVar, off + pSgBuf->paSegs[0].cbSeg);
1126 if (RT_SUCCESS(rc))
1127 rc = rtEfiVarStoreFile_WriteMem(pThis, pVar->pvData, pVar->cbData, off, pSgBuf, pcbWritten);
1128 }
1129 }
1130
1131 return rc;
1132}
1133
1134
1135/**
1136 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
1137 */
1138static DECLCALLBACK(int) rtEfiVarStoreFile_Flush(void *pvThis)
1139{
1140 RT_NOREF(pvThis);
1141 return VINF_SUCCESS;
1142}
1143
1144
1145/**
1146 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
1147 */
1148static DECLCALLBACK(int) rtEfiVarStoreFile_Tell(void *pvThis, PRTFOFF poffActual)
1149{
1150 PRTEFIVARFILE pThis = (PRTEFIVARFILE)pvThis;
1151 *poffActual = pThis->offFile;
1152 return VINF_SUCCESS;
1153}
1154
1155
1156/**
1157 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
1158 */
1159static DECLCALLBACK(int) rtEfiVarStoreFile_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
1160{
1161 RT_NOREF(pvThis, fMode, fMask);
1162 return VERR_WRITE_PROTECT;
1163}
1164
1165
1166/**
1167 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
1168 */
1169static DECLCALLBACK(int) rtEfiVarStoreFile_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
1170 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
1171{
1172 RT_NOREF(pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
1173 return VERR_WRITE_PROTECT;
1174}
1175
1176
1177/**
1178 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
1179 */
1180static DECLCALLBACK(int) rtEfiVarStoreFile_SetOwner(void *pvThis, RTUID uid, RTGID gid)
1181{
1182 RT_NOREF(pvThis, uid, gid);
1183 return VERR_WRITE_PROTECT;
1184}
1185
1186
1187/**
1188 * @interface_method_impl{RTVFSFILEOPS,pfnSeek}
1189 */
1190static DECLCALLBACK(int) rtEfiVarStoreFile_Seek(void *pvThis, RTFOFF offSeek, unsigned uMethod, PRTFOFF poffActual)
1191{
1192 PRTEFIVARFILE pThis = (PRTEFIVARFILE)pvThis;
1193 RTFOFF offNew;
1194 switch (uMethod)
1195 {
1196 case RTFILE_SEEK_BEGIN:
1197 offNew = offSeek;
1198 break;
1199 case RTFILE_SEEK_END:
1200 offNew = pThis->pVar->cbData + offSeek;
1201 break;
1202 case RTFILE_SEEK_CURRENT:
1203 offNew = (RTFOFF)pThis->offFile + offSeek;
1204 break;
1205 default:
1206 return VERR_INVALID_PARAMETER;
1207 }
1208 if (offNew >= 0)
1209 {
1210 pThis->offFile = offNew;
1211 *poffActual = offNew;
1212 return VINF_SUCCESS;
1213 }
1214 return VERR_NEGATIVE_SEEK;
1215}
1216
1217
1218/**
1219 * @interface_method_impl{RTVFSFILEOPS,pfnQuerySize}
1220 */
1221static DECLCALLBACK(int) rtEfiVarStoreFile_QuerySize(void *pvThis, uint64_t *pcbFile)
1222{
1223 PRTEFIVARFILE pThis = (PRTEFIVARFILE)pvThis;
1224 if (pThis->pEntry->cbObject)
1225 *pcbFile = pThis->pEntry->cbObject;
1226 else
1227 *pcbFile = (uint64_t)pThis->pVar->cbData;
1228 return VINF_SUCCESS;
1229}
1230
1231
1232/**
1233 * @interface_method_impl{RTVFSFILEOPS,pfnSetSize}
1234 */
1235static DECLCALLBACK(int) rtEfiVarStoreFile_SetSize(void *pvThis, uint64_t cbFile, uint32_t fFlags)
1236{
1237 PRTEFIVARFILE pThis = (PRTEFIVARFILE)pvThis;
1238 PRTEFIVAR pVar = pThis->pVar;
1239 PRTEFIVARSTORE pVarStore = pThis->pVarStore;
1240
1241 RT_NOREF(fFlags);
1242
1243 if (pVarStore->fMntFlags & RTVFSMNT_F_READ_ONLY)
1244 return VERR_WRITE_PROTECT;
1245
1246 int rc = rtEfiVarStore_VarReadData(pVar);
1247 if (RT_SUCCESS(rc))
1248 rc = rtEfiVarStore_VarEnsureDataSz(pVar, cbFile);
1249
1250 return rc;
1251}
1252
1253
1254/**
1255 * @interface_method_impl{RTVFSFILEOPS,pfnQueryMaxSize}
1256 */
1257static DECLCALLBACK(int) rtEfiVarStoreFile_QueryMaxSize(void *pvThis, uint64_t *pcbMax)
1258{
1259 RT_NOREF(pvThis);
1260 *pcbMax = UINT32_MAX;
1261 return VINF_SUCCESS;
1262}
1263
1264
1265/**
1266 * EFI variable store file operations.
1267 */
1268static const RTVFSFILEOPS g_rtEfiVarStoreFileOps =
1269{
1270 { /* Stream */
1271 { /* Obj */
1272 RTVFSOBJOPS_VERSION,
1273 RTVFSOBJTYPE_FILE,
1274 "EfiVarStore File",
1275 rtEfiVarStoreFile_Close,
1276 rtEfiVarStoreFile_QueryInfo,
1277 NULL,
1278 RTVFSOBJOPS_VERSION
1279 },
1280 RTVFSIOSTREAMOPS_VERSION,
1281 RTVFSIOSTREAMOPS_FEAT_NO_SG,
1282 rtEfiVarStoreFile_Read,
1283 rtEfiVarStoreFile_Write,
1284 rtEfiVarStoreFile_Flush,
1285 NULL /*PollOne*/,
1286 rtEfiVarStoreFile_Tell,
1287 NULL /*pfnSkip*/,
1288 NULL /*pfnZeroFill*/,
1289 RTVFSIOSTREAMOPS_VERSION,
1290 },
1291 RTVFSFILEOPS_VERSION,
1292 0,
1293 { /* ObjSet */
1294 RTVFSOBJSETOPS_VERSION,
1295 RT_UOFFSETOF(RTVFSFILEOPS, ObjSet) - RT_UOFFSETOF(RTVFSFILEOPS, Stream.Obj),
1296 rtEfiVarStoreFile_SetMode,
1297 rtEfiVarStoreFile_SetTimes,
1298 rtEfiVarStoreFile_SetOwner,
1299 RTVFSOBJSETOPS_VERSION
1300 },
1301 rtEfiVarStoreFile_Seek,
1302 rtEfiVarStoreFile_QuerySize,
1303 rtEfiVarStoreFile_SetSize,
1304 rtEfiVarStoreFile_QueryMaxSize,
1305 RTVFSFILEOPS_VERSION
1306};
1307
1308
1309/**
1310 * Creates a new VFS file from the given regular file inode.
1311 *
1312 * @returns IPRT status code.
1313 * @param pThis The ext volume instance.
1314 * @param fOpen Open flags passed.
1315 * @param pVar The variable this file accesses.
1316 * @param pEntry File type entry.
1317 * @param phVfsFile Where to store the VFS file handle on success.
1318 * @param pErrInfo Where to record additional error information on error, optional.
1319 */
1320static int rtEfiVarStore_NewFile(PRTEFIVARSTORE pThis, uint64_t fOpen, PRTEFIVAR pVar,
1321 PCRTEFIVARSTOREFILERAWENTRY pEntry, PRTVFSOBJ phVfsObj)
1322{
1323 RTVFSFILE hVfsFile;
1324 PRTEFIVARFILE pNewFile;
1325 int rc = RTVfsNewFile(&g_rtEfiVarStoreFileOps, sizeof(*pNewFile), fOpen, pThis->hVfsSelf, NIL_RTVFSLOCK,
1326 &hVfsFile, (void **)&pNewFile);
1327 if (RT_SUCCESS(rc))
1328 {
1329 pNewFile->pEntry = pEntry;
1330 pNewFile->pVarStore = pThis;
1331 pNewFile->pVar = pVar;
1332 pNewFile->offFile = 0;
1333
1334 *phVfsObj = RTVfsObjFromFile(hVfsFile);
1335 RTVfsFileRelease(hVfsFile);
1336 AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
1337 }
1338
1339 return rc;
1340}
1341
1342
1343
1344/*
1345 *
1346 * Directory instance methods
1347 * Directory instance methods
1348 * Directory instance methods
1349 *
1350 */
1351
1352/**
1353 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
1354 */
1355static DECLCALLBACK(int) rtEfiVarStoreDir_Close(void *pvThis)
1356{
1357 PRTEFIVARSTOREDIR pThis = (PRTEFIVARSTOREDIR)pvThis;
1358 LogFlowFunc(("pThis=%p\n", pThis));
1359 pThis->pVarStore = NULL;
1360 return VINF_SUCCESS;
1361}
1362
1363
1364/**
1365 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
1366 */
1367static DECLCALLBACK(int) rtEfiVarStoreDir_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1368{
1369 PRTEFIVARSTOREDIR pThis = (PRTEFIVARSTOREDIR)pvThis;
1370 LogFlowFunc(("\n"));
1371 return rtEfiVarStore_QueryInfo(1, true /*fIsDir*/, &pThis->Time, pObjInfo, enmAddAttr);
1372}
1373
1374
1375/**
1376 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
1377 */
1378static DECLCALLBACK(int) rtEfiVarStoreDir_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
1379{
1380 LogFlowFunc(("\n"));
1381 RT_NOREF(pvThis, fMode, fMask);
1382 return VERR_WRITE_PROTECT;
1383}
1384
1385
1386/**
1387 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
1388 */
1389static DECLCALLBACK(int) rtEfiVarStoreDir_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
1390 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
1391{
1392 LogFlowFunc(("\n"));
1393 RT_NOREF(pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
1394 return VERR_WRITE_PROTECT;
1395}
1396
1397
1398/**
1399 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
1400 */
1401static DECLCALLBACK(int) rtEfiVarStoreDir_SetOwner(void *pvThis, RTUID uid, RTGID gid)
1402{
1403 LogFlowFunc(("\n"));
1404 RT_NOREF(pvThis, uid, gid);
1405 return VERR_WRITE_PROTECT;
1406}
1407
1408
1409/**
1410 * @interface_method_impl{RTVFSDIROPS,pfnOpen}
1411 */
1412static DECLCALLBACK(int) rtEfiVarStoreDir_Open(void *pvThis, const char *pszEntry, uint64_t fOpen,
1413 uint32_t fFlags, PRTVFSOBJ phVfsObj)
1414{
1415 LogFlowFunc(("pszEntry='%s' fOpen=%#RX64 fFlags=%#x\n", pszEntry, fOpen, fFlags));
1416 PRTEFIVARSTOREDIR pThis = (PRTEFIVARSTOREDIR)pvThis;
1417 PRTEFIVARSTORE pVarStore = pThis->pVarStore;
1418 int rc = VINF_SUCCESS;
1419
1420 /*
1421 * Special cases '.' and '.'
1422 */
1423 if (pszEntry[0] == '.')
1424 {
1425 RTEFIVARSTOREDIRTYPE enmDirTypeNew = RTEFIVARSTOREDIRTYPE_INVALID;
1426 if (pszEntry[1] == '\0')
1427 enmDirTypeNew = pThis->pEntry->enmType;
1428 else if (pszEntry[1] == '.' && pszEntry[2] == '\0')
1429 enmDirTypeNew = pThis->pEntry->enmParentType;
1430
1431 if (enmDirTypeNew != RTEFIVARSTOREDIRTYPE_INVALID)
1432 {
1433 if (fFlags & RTVFSOBJ_F_OPEN_DIRECTORY)
1434 {
1435 if ( (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN
1436 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE)
1437 rc = rtEfiVarStore_NewDirByType(pVarStore, enmDirTypeNew, NULL /*pGuid*/, 0 /*idVar*/, phVfsObj);
1438 else
1439 rc = VERR_ACCESS_DENIED;
1440 }
1441 else
1442 rc = VERR_IS_A_DIRECTORY;
1443 return rc;
1444 }
1445 }
1446
1447 /*
1448 * We can create or replace in certain directories.
1449 */
1450 if ( (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN
1451 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
1452 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE
1453 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
1454 { /* likely */ }
1455 else
1456 return VERR_WRITE_PROTECT;
1457
1458 switch (pThis->pEntry->enmType)
1459 {
1460 case RTEFIVARSTOREDIRTYPE_ROOT:
1461 {
1462 if (!strcmp(pszEntry, "by-name"))
1463 return rtEfiVarStore_NewDirByType(pVarStore, RTEFIVARSTOREDIRTYPE_BY_NAME,
1464 NULL /*pGuid*/, 0 /*idVar*/, phVfsObj);
1465 else if (!strcmp(pszEntry, "by-uuid"))
1466 return rtEfiVarStore_NewDirByType(pVarStore, RTEFIVARSTOREDIRTYPE_BY_GUID,
1467 NULL /*pGuid*/, 0 /*idVar*/, phVfsObj);
1468 else if (!strcmp(pszEntry, "raw"))
1469 return rtEfiVarStore_NewDirByType(pVarStore, RTEFIVARSTOREDIRTYPE_RAW,
1470 NULL /*pGuid*/, 0 /*idVar*/, phVfsObj);
1471 else
1472 rc = VERR_FILE_NOT_FOUND;
1473 break;
1474 }
1475 case RTEFIVARSTOREDIRTYPE_GUID: /** @todo This looks through all variables, not only the ones with the GUID. */
1476 case RTEFIVARSTOREDIRTYPE_BY_NAME:
1477 case RTEFIVARSTOREDIRTYPE_RAW:
1478 {
1479 /* Look for the name. */
1480 uint32_t idVar = 0;
1481 PRTEFIVAR pVar = rtEfiVarStore_VarGet(pVarStore, pszEntry, &idVar);
1482 if ( !pVar
1483 && ( (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
1484 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE
1485 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE))
1486 {
1487 if (pThis->pEntry->enmType == RTEFIVARSTOREDIRTYPE_GUID)
1488 pVar = rtEfiVarStore_VarAdd(pVarStore, pszEntry, &pThis->pGuid->Uuid, &idVar);
1489 else
1490 {
1491 RTUUID UuidNull;
1492 RTUuidClear(&UuidNull);
1493 pVar = rtEfiVarStore_VarAdd(pVarStore, pszEntry, &UuidNull, &idVar);
1494 }
1495
1496 if (!pVar)
1497 {
1498 rc = VERR_NO_MEMORY;
1499 break;
1500 }
1501 }
1502
1503 if (pVar)
1504 {
1505 if (pThis->pEntry->enmType == RTEFIVARSTOREDIRTYPE_RAW)
1506 return rtEfiVarStore_NewDirByType(pVarStore, RTEFIVARSTOREDIRTYPE_RAW_ENTRY,
1507 NULL /*pGuid*/, idVar, phVfsObj);
1508 else
1509 return rtEfiVarStore_NewFile(pVarStore, fOpen, pVar,
1510 &g_aRawFiles[RTEFIVARSTORE_FILE_ENTRY_DATA], phVfsObj);
1511 }
1512
1513 rc = VERR_FILE_NOT_FOUND;
1514 break;
1515 }
1516 case RTEFIVARSTOREDIRTYPE_BY_GUID:
1517 {
1518 /* Look for the name. */
1519 for (uint32_t i = 0; i < pVarStore->cGuids; i++)
1520 {
1521 PRTEFIGUID pGuid = &pVarStore->paGuids[i];
1522 char szUuid[RTUUID_STR_LENGTH];
1523 rc = RTUuidToStr(&pGuid->Uuid, szUuid, sizeof(szUuid));
1524 AssertRC(rc);
1525
1526 if (!strcmp(pszEntry, szUuid))
1527 return rtEfiVarStore_NewDirByType(pVarStore, RTEFIVARSTOREDIRTYPE_GUID,
1528 pGuid, 0 /*idVar*/, phVfsObj);
1529 }
1530
1531 rc = VERR_FILE_NOT_FOUND;
1532 break;
1533 }
1534 case RTEFIVARSTOREDIRTYPE_RAW_ENTRY:
1535 {
1536 /* Look for the name. */
1537 for (uint32_t i = 0; i < RT_ELEMENTS(g_aRawFiles); i++)
1538 if (!strcmp(pszEntry, g_aRawFiles[i].pszName))
1539 return rtEfiVarStore_NewFile(pVarStore, fOpen, &pVarStore->paVars[pThis->idVar],
1540 &g_aRawFiles[i], phVfsObj);
1541
1542 rc = VERR_FILE_NOT_FOUND;
1543 break;
1544 }
1545 case RTEFIVARSTOREDIRTYPE_INVALID:
1546 default:
1547 AssertFailedReturn(VERR_INTERNAL_ERROR_3);
1548 }
1549
1550 LogFlow(("rtEfiVarStoreDir_Open(%s): returns %Rrc\n", pszEntry, rc));
1551 return rc;
1552}
1553
1554
1555/**
1556 * @interface_method_impl{RTVFSDIROPS,pfnCreateDir}
1557 */
1558static DECLCALLBACK(int) rtEfiVarStoreDir_CreateDir(void *pvThis, const char *pszSubDir, RTFMODE fMode, PRTVFSDIR phVfsDir)
1559{
1560 PRTEFIVARSTOREDIR pThis = (PRTEFIVARSTOREDIR)pvThis;
1561 PRTEFIVARSTORE pVarStore = pThis->pVarStore;
1562 LogFlowFunc(("\n"));
1563
1564 RT_NOREF(fMode, phVfsDir);
1565
1566 if (pVarStore->fMntFlags & RTVFSMNT_F_READ_ONLY)
1567 return VERR_WRITE_PROTECT;
1568
1569 /* We support creating directories only for GUIDs and RAW variable entries. */
1570 int rc = VINF_SUCCESS;
1571 if (pThis->pEntry->enmType == RTEFIVARSTOREDIRTYPE_BY_GUID)
1572 {
1573 RTUUID Uuid;
1574 rc = RTUuidFromStr(&Uuid, pszSubDir);
1575 if (RT_FAILURE(rc))
1576 return VERR_NOT_SUPPORTED;
1577
1578 PRTEFIGUID pGuid = rtEfiVarStore_GetGuid(pVarStore, &Uuid);
1579 if (pGuid)
1580 return VERR_ALREADY_EXISTS;
1581
1582 pGuid = rtEfiVarStore_AddGuid(pVarStore, &Uuid);
1583 if (!pGuid)
1584 return VERR_NO_MEMORY;
1585 }
1586 else if (pThis->pEntry->enmType == RTEFIVARSTOREDIRTYPE_RAW)
1587 {
1588 PRTEFIVAR pVar = rtEfiVarStore_VarGet(pVarStore, pszSubDir, NULL /*pidVar*/);
1589 if (!pVar)
1590 {
1591 if (sizeof(EFI_AUTH_VAR_HEADER) < pVarStore->cbVarStore - pVarStore->cbVarData)
1592 {
1593 uint32_t idVar = 0;
1594 RTUUID UuidNull;
1595 RTUuidClear(&UuidNull);
1596
1597 pVar = rtEfiVarStore_VarAdd(pVarStore, pszSubDir, &UuidNull, &idVar);
1598 if (pVar)
1599 pVarStore->cbVarData += sizeof(EFI_AUTH_VAR_HEADER);
1600 else
1601 rc = VERR_NO_MEMORY;
1602 }
1603 else
1604 rc = VERR_DISK_FULL;
1605 }
1606 else
1607 rc = VERR_ALREADY_EXISTS;
1608 }
1609 else
1610 rc = VERR_NOT_SUPPORTED;
1611
1612 return rc;
1613}
1614
1615
1616/**
1617 * @interface_method_impl{RTVFSDIROPS,pfnOpenSymlink}
1618 */
1619static DECLCALLBACK(int) rtEfiVarStoreDir_OpenSymlink(void *pvThis, const char *pszSymlink, PRTVFSSYMLINK phVfsSymlink)
1620{
1621 RT_NOREF(pvThis, pszSymlink, phVfsSymlink);
1622 LogFlowFunc(("\n"));
1623 return VERR_NOT_SUPPORTED;
1624}
1625
1626
1627/**
1628 * @interface_method_impl{RTVFSDIROPS,pfnCreateSymlink}
1629 */
1630static DECLCALLBACK(int) rtEfiVarStoreDir_CreateSymlink(void *pvThis, const char *pszSymlink, const char *pszTarget,
1631 RTSYMLINKTYPE enmType, PRTVFSSYMLINK phVfsSymlink)
1632{
1633 RT_NOREF(pvThis, pszSymlink, pszTarget, enmType, phVfsSymlink);
1634 LogFlowFunc(("\n"));
1635 return VERR_WRITE_PROTECT;
1636}
1637
1638
1639/**
1640 * @interface_method_impl{RTVFSDIROPS,pfnUnlinkEntry}
1641 */
1642static DECLCALLBACK(int) rtEfiVarStoreDir_UnlinkEntry(void *pvThis, const char *pszEntry, RTFMODE fType)
1643{
1644 PRTEFIVARSTOREDIR pThis = (PRTEFIVARSTOREDIR)pvThis;
1645 PRTEFIVARSTORE pVarStore = pThis->pVarStore;
1646 LogFlowFunc(("\n"));
1647
1648 RT_NOREF(fType);
1649
1650 if (pVarStore->fMntFlags & RTVFSMNT_F_READ_ONLY)
1651 return VERR_WRITE_PROTECT;
1652
1653 if ( pThis->pEntry->enmType == RTEFIVARSTOREDIRTYPE_RAW
1654 || pThis->pEntry->enmType == RTEFIVARSTOREDIRTYPE_BY_NAME
1655 || pThis->pEntry->enmType == RTEFIVARSTOREDIRTYPE_GUID)
1656 return rtEfiVarStore_VarDelByName(pVarStore, pszEntry);
1657 else if (pThis->pEntry->enmType == RTEFIVARSTOREDIRTYPE_BY_GUID)
1658 {
1659 /* Look for the name. */
1660 for (uint32_t i = 0; i < pVarStore->cGuids; i++)
1661 {
1662 PRTEFIGUID pGuid = &pVarStore->paGuids[i];
1663 char szUuid[RTUUID_STR_LENGTH];
1664 int rc = RTUuidToStr(&pGuid->Uuid, szUuid, sizeof(szUuid));
1665 AssertRC(rc); RT_NOREF(rc);
1666
1667 if (!strcmp(pszEntry, szUuid))
1668 {
1669 for (uint32_t iVar = 0; iVar < pGuid->cVars; iVar++)
1670 rtEfiVarStore_VarDelById(pVarStore, pGuid->paidxVars[iVar]);
1671
1672 if (pGuid->paidxVars)
1673 RTMemFree(pGuid->paidxVars);
1674 pGuid->paidxVars = NULL;
1675 pGuid->cVars = 0;
1676 pGuid->cVarsMax = 0;
1677 RTUuidClear(&pGuid->Uuid);
1678 return VINF_SUCCESS;
1679 }
1680 }
1681
1682 return VERR_FILE_NOT_FOUND;
1683 }
1684
1685 return VERR_NOT_SUPPORTED;
1686}
1687
1688
1689/**
1690 * @interface_method_impl{RTVFSDIROPS,pfnRenameEntry}
1691 */
1692static DECLCALLBACK(int) rtEfiVarStoreDir_RenameEntry(void *pvThis, const char *pszEntry, RTFMODE fType, const char *pszNewName)
1693{
1694 RT_NOREF(pvThis, pszEntry, fType, pszNewName);
1695 LogFlowFunc(("\n"));
1696 return VERR_WRITE_PROTECT;
1697}
1698
1699
1700/**
1701 * @interface_method_impl{RTVFSDIROPS,pfnRewindDir}
1702 */
1703static DECLCALLBACK(int) rtEfiVarStoreDir_RewindDir(void *pvThis)
1704{
1705 PRTEFIVARSTOREDIR pThis = (PRTEFIVARSTOREDIR)pvThis;
1706 LogFlowFunc(("\n"));
1707
1708 pThis->idxNext = 0;
1709 return VINF_SUCCESS;
1710}
1711
1712
1713/**
1714 * @interface_method_impl{RTVFSDIROPS,pfnReadDir}
1715 */
1716static DECLCALLBACK(int) rtEfiVarStoreDir_ReadDir(void *pvThis, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry,
1717 RTFSOBJATTRADD enmAddAttr)
1718{
1719 PRTEFIVARSTOREDIR pThis = (PRTEFIVARSTOREDIR)pvThis;
1720 PRTEFIVARSTORE pVarStore = pThis->pVarStore;
1721 LogFlowFunc(("\n"));
1722
1723 if (pThis->fNoMoreFiles)
1724 return VERR_NO_MORE_FILES;
1725
1726 int rc = VINF_SUCCESS;
1727 char aszUuid[RTUUID_STR_LENGTH];
1728 const char *pszName = NULL;
1729 size_t cbName = 0;
1730 uint64_t cbObject = 0;
1731 bool fIsDir = false;
1732 bool fNoMoreFiles = false;
1733 RTTIMESPEC Time;
1734 PCRTTIMESPEC pTimeSpec = &Time;
1735 RTTimeNow(&Time);
1736
1737 switch (pThis->pEntry->enmType)
1738 {
1739 case RTEFIVARSTOREDIRTYPE_ROOT:
1740 {
1741 if (pThis->idxNext == 0)
1742 {
1743 pszName = "by-name";
1744 cbName = sizeof("by-name");
1745 cbObject = 1;
1746 fIsDir = true;
1747 }
1748 else if (pThis->idxNext == 1)
1749 {
1750 pszName = "by-uuid";
1751 cbName = sizeof("by-uuid");
1752 cbObject = 1;
1753 fIsDir = true;
1754 }
1755 else if (pThis->idxNext == 2)
1756 {
1757 pszName = "raw";
1758 cbName = sizeof("raw");
1759 cbObject = 1;
1760 fIsDir = true;
1761 fNoMoreFiles = true;
1762 }
1763 break;
1764 }
1765 case RTEFIVARSTOREDIRTYPE_BY_NAME:
1766 case RTEFIVARSTOREDIRTYPE_RAW:
1767 {
1768 PRTEFIVAR pVar = &pVarStore->paVars[pThis->idxNext];
1769 if (pThis->idxNext + 1 == pVarStore->cVars)
1770 fNoMoreFiles = true;
1771 pszName = pVar->pszName;
1772 cbName = strlen(pszName) + 1;
1773 cbObject = pVar->cbData;
1774 pTimeSpec = &pVar->Time;
1775 if (pThis->pEntry->enmType == RTEFIVARSTOREDIRTYPE_RAW)
1776 fIsDir = true;
1777 break;
1778 }
1779 case RTEFIVARSTOREDIRTYPE_BY_GUID:
1780 {
1781 PRTEFIGUID pGuid = &pVarStore->paGuids[pThis->idxNext];
1782 if (pThis->idxNext + 1 == pVarStore->cGuids)
1783 fNoMoreFiles = true;
1784 pszName = &aszUuid[0];
1785 cbName = sizeof(aszUuid);
1786 cbObject = 1;
1787 rc = RTUuidToStr(&pGuid->Uuid, &aszUuid[0], cbName);
1788 AssertRC(rc);
1789 break;
1790 }
1791 case RTEFIVARSTOREDIRTYPE_GUID:
1792 {
1793 PRTEFIGUID pGuid = pThis->pGuid;
1794 uint32_t idVar = pGuid->paidxVars[pThis->idxNext];
1795 PRTEFIVAR pVar = &pVarStore->paVars[idVar];
1796 if (pThis->idxNext + 1 == pGuid->cVars)
1797 fNoMoreFiles = true;
1798 pszName = pVar->pszName;
1799 cbName = strlen(pszName) + 1;
1800 cbObject = pVar->cbData;
1801 pTimeSpec = &pVar->Time;
1802 break;
1803 }
1804 case RTEFIVARSTOREDIRTYPE_RAW_ENTRY:
1805 {
1806 PCRTEFIVARSTOREFILERAWENTRY pEntry = &g_aRawFiles[pThis->idxNext];
1807 PRTEFIVAR pVar = &pVarStore->paVars[pThis->idVar];
1808
1809 if (pThis->idxNext + 1 == RT_ELEMENTS(g_aRawFiles))
1810 fNoMoreFiles = true;
1811 pszName = pEntry->pszName;
1812 cbName = strlen(pszName) + 1;
1813 cbObject = pEntry->cbObject;
1814 if (!cbObject)
1815 cbObject = pVar->cbData;
1816 pTimeSpec = &pVar->Time;
1817 break;
1818 }
1819 case RTEFIVARSTOREDIRTYPE_INVALID:
1820 default:
1821 AssertFailedReturn(VERR_INTERNAL_ERROR_3);
1822 }
1823
1824 if (cbName <= 255)
1825 {
1826 size_t const cbDirEntry = *pcbDirEntry;
1827
1828 *pcbDirEntry = RT_UOFFSETOF_DYN(RTDIRENTRYEX, szName[cbName + 2]);
1829 if (*pcbDirEntry <= cbDirEntry)
1830 {
1831 memcpy(&pDirEntry->szName[0], pszName, cbName);
1832 pDirEntry->szName[cbName] = '\0';
1833 pDirEntry->cbName = (uint16_t)cbName;
1834 rc = rtEfiVarStore_QueryInfo(cbObject, fIsDir, &Time, &pDirEntry->Info, enmAddAttr);
1835 if (RT_SUCCESS(rc))
1836 {
1837 pThis->fNoMoreFiles = fNoMoreFiles;
1838 pThis->idxNext++;
1839 return VINF_SUCCESS;
1840 }
1841 }
1842 else
1843 rc = VERR_BUFFER_OVERFLOW;
1844 }
1845 else
1846 rc = VERR_FILENAME_TOO_LONG;
1847 return rc;
1848}
1849
1850
1851/**
1852 * EFI variable store directory operations.
1853 */
1854static const RTVFSDIROPS g_rtEfiVarStoreDirOps =
1855{
1856 { /* Obj */
1857 RTVFSOBJOPS_VERSION,
1858 RTVFSOBJTYPE_DIR,
1859 "EfiVarStore Dir",
1860 rtEfiVarStoreDir_Close,
1861 rtEfiVarStoreDir_QueryInfo,
1862 NULL,
1863 RTVFSOBJOPS_VERSION
1864 },
1865 RTVFSDIROPS_VERSION,
1866 0,
1867 { /* ObjSet */
1868 RTVFSOBJSETOPS_VERSION,
1869 RT_UOFFSETOF(RTVFSDIROPS, ObjSet) - RT_UOFFSETOF(RTVFSDIROPS, Obj),
1870 rtEfiVarStoreDir_SetMode,
1871 rtEfiVarStoreDir_SetTimes,
1872 rtEfiVarStoreDir_SetOwner,
1873 RTVFSOBJSETOPS_VERSION
1874 },
1875 rtEfiVarStoreDir_Open,
1876 NULL /* pfnFollowAbsoluteSymlink */,
1877 NULL /* pfnOpenFile */,
1878 NULL /* pfnOpenDir */,
1879 rtEfiVarStoreDir_CreateDir,
1880 rtEfiVarStoreDir_OpenSymlink,
1881 rtEfiVarStoreDir_CreateSymlink,
1882 NULL /* pfnQueryEntryInfo */,
1883 rtEfiVarStoreDir_UnlinkEntry,
1884 rtEfiVarStoreDir_RenameEntry,
1885 rtEfiVarStoreDir_RewindDir,
1886 rtEfiVarStoreDir_ReadDir,
1887 RTVFSDIROPS_VERSION,
1888};
1889
1890
1891static int rtEfiVarStore_NewDirByType(PRTEFIVARSTORE pThis, RTEFIVARSTOREDIRTYPE enmDirType,
1892 PRTEFIGUID pGuid, uint32_t idVar, PRTVFSOBJ phVfsObj)
1893{
1894 RTVFSDIR hVfsDir;
1895 PRTEFIVARSTOREDIR pDir;
1896 int rc = RTVfsNewDir(&g_rtEfiVarStoreDirOps, sizeof(*pDir), 0 /*fFlags*/, pThis->hVfsSelf, NIL_RTVFSLOCK,
1897 &hVfsDir, (void **)&pDir);
1898 if (RT_SUCCESS(rc))
1899 {
1900 PCRTEFIVARSTOREDIRENTRY pEntry = NULL;
1901
1902 for (uint32_t i = 0; i < RT_ELEMENTS(g_aDirs); i++)
1903 if (g_aDirs[i].enmType == enmDirType)
1904 {
1905 pEntry = &g_aDirs[i];
1906 break;
1907 }
1908
1909 AssertPtr(pEntry);
1910 pDir->idxNext = 0;
1911 pDir->pEntry = pEntry;
1912 pDir->pVarStore = pThis;
1913 pDir->pGuid = pGuid;
1914 pDir->idVar = idVar;
1915 RTTimeNow(&pDir->Time);
1916
1917 *phVfsObj = RTVfsObjFromDir(hVfsDir);
1918 RTVfsDirRelease(hVfsDir);
1919 AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
1920 }
1921
1922 return rc;
1923}
1924
1925
1926/*
1927 *
1928 * Volume level code.
1929 * Volume level code.
1930 * Volume level code.
1931 *
1932 */
1933
1934/**
1935 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnClose}
1936 */
1937static DECLCALLBACK(int) rtEfiVarStore_Close(void *pvThis)
1938{
1939 PRTEFIVARSTORE pThis = (PRTEFIVARSTORE)pvThis;
1940
1941 /* Write the variable store if in read/write mode. */
1942 if (!(pThis->fMntFlags & RTVFSMNT_F_READ_ONLY))
1943 {
1944 int rc = rtEfiVarStore_Flush(pThis);
1945 if (RT_FAILURE(rc))
1946 return rc;
1947 }
1948
1949 /*
1950 * Backing file and handles.
1951 */
1952 RTVfsFileRelease(pThis->hVfsBacking);
1953 pThis->hVfsBacking = NIL_RTVFSFILE;
1954 pThis->hVfsSelf = NIL_RTVFS;
1955 if (pThis->paVars)
1956 {
1957 for (uint32_t i = 0; i < pThis->cVars; i++)
1958 {
1959 RTStrFree(pThis->paVars[i].pszName);
1960 if (pThis->paVars[i].pvData)
1961 RTMemFree(pThis->paVars[i].pvData);
1962 }
1963
1964 RTMemFree(pThis->paVars);
1965 pThis->paVars = NULL;
1966 pThis->cVars = 0;
1967 pThis->cVarsMax = 0;
1968 }
1969
1970 if (pThis->paGuids)
1971 {
1972 for (uint32_t i = 0; i < pThis->cGuids; i++)
1973 {
1974 PRTEFIGUID pGuid = &pThis->paGuids[i];
1975
1976 if (pGuid->paidxVars)
1977 {
1978 RTMemFree(pGuid->paidxVars);
1979 pGuid->paidxVars = NULL;
1980 }
1981 }
1982
1983 RTMemFree(pThis->paGuids);
1984 pThis->paGuids = NULL;
1985 }
1986
1987 return VINF_SUCCESS;
1988}
1989
1990
1991/**
1992 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnQueryInfo}
1993 */
1994static DECLCALLBACK(int) rtEfiVarStore_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1995{
1996 RT_NOREF(pvThis, pObjInfo, enmAddAttr);
1997 return VERR_WRONG_TYPE;
1998}
1999
2000
2001/**
2002 * @interface_method_impl{RTVFSOBJOPS::Obj,pfnOpenRoot}
2003 */
2004static DECLCALLBACK(int) rtEfiVarStore_OpenRoot(void *pvThis, PRTVFSDIR phVfsDir)
2005{
2006 PRTEFIVARSTORE pThis = (PRTEFIVARSTORE)pvThis;
2007 RTVFSOBJ hVfsObj;
2008 int rc = rtEfiVarStore_NewDirByType(pThis, RTEFIVARSTOREDIRTYPE_ROOT,
2009 NULL /*pGuid*/, 0 /*idVar*/, &hVfsObj);
2010 if (RT_SUCCESS(rc))
2011 {
2012 *phVfsDir = RTVfsObjToDir(hVfsObj);
2013 RTVfsObjRelease(hVfsObj);
2014 }
2015
2016 LogFlowFunc(("returns %Rrc\n", rc));
2017 return rc;
2018}
2019
2020
2021DECL_HIDDEN_CONST(const RTVFSOPS) g_rtEfiVarStoreOps =
2022{
2023 /* .Obj = */
2024 {
2025 /* .uVersion = */ RTVFSOBJOPS_VERSION,
2026 /* .enmType = */ RTVFSOBJTYPE_VFS,
2027 /* .pszName = */ "EfiVarStore",
2028 /* .pfnClose = */ rtEfiVarStore_Close,
2029 /* .pfnQueryInfo = */ rtEfiVarStore_QueryInfo,
2030 /* .pfnQueryInfoEx = */ NULL,
2031 /* .uEndMarker = */ RTVFSOBJOPS_VERSION
2032 },
2033 /* .uVersion = */ RTVFSOPS_VERSION,
2034 /* .fFeatures = */ 0,
2035 /* .pfnOpenRoot = */ rtEfiVarStore_OpenRoot,
2036 /* .pfnQueryRangeState = */ NULL,
2037 /* .uEndMarker = */ RTVFSOPS_VERSION
2038};
2039
2040
2041/**
2042 * Validates the given firmware header.
2043 *
2044 * @returns true if the given header is considered valid, flse otherwise.
2045 * @param pThis The EFI variable store instance.
2046 * @param pFvHdr The firmware volume header to validate.
2047 * @param poffData The offset into the backing where the data area begins.
2048 * @param pErrInfo Where to return additional error info.
2049 */
2050static int rtEfiVarStoreFvHdr_Validate(PRTEFIVARSTORE pThis, PCEFI_FIRMWARE_VOLUME_HEADER pFvHdr, uint64_t *poffData,
2051 PRTERRINFO pErrInfo)
2052{
2053#ifdef LOG_ENABLED
2054 rtEfiVarStoreFvHdr_Log(pFvHdr);
2055#endif
2056
2057 EFI_GUID GuidNvData = EFI_VARSTORE_FILESYSTEM_GUID;
2058 if (memcmp(&pFvHdr->GuidFilesystem, &GuidNvData, sizeof(GuidNvData)))
2059 return RTERRINFO_LOG_SET(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "Filesystem GUID doesn't indicate a variable store");
2060 if (RT_LE2H_U64(pFvHdr->cbFv) > pThis->cbBacking)
2061 return RTERRINFO_LOG_SET(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "Firmware volume length exceeds size of backing storage (truncated file?)");
2062 /* Signature was already verfied by caller. */
2063 /** @todo Check attributes. */
2064 if (pFvHdr->bRsvd != 0)
2065 return RTERRINFO_LOG_SET(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "Reserved field of header is not 0");
2066 if (pFvHdr->bRevision != EFI_FIRMWARE_VOLUME_HEADER_REVISION)
2067 return RTERRINFO_LOG_SET(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "Unexpected revision of the firmware volume header");
2068 if (RT_LE2H_U16(pFvHdr->offExtHdr) != 0)
2069 return RTERRINFO_LOG_SET(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "Firmware volume header contains unsupported extended headers");
2070
2071 /* Start calculating the checksum of the main header. */
2072 uint16_t u16Chksum = 0;
2073 const uint16_t *pu16 = (const uint16_t *)pFvHdr;
2074 while (pu16 < (const uint16_t *)pFvHdr + (sizeof(*pFvHdr) / sizeof(uint16_t)))
2075 u16Chksum += RT_LE2H_U16(*pu16++);
2076
2077 /* Read in the block map and verify it as well. */
2078 uint64_t cbFvVol = 0;
2079 uint64_t cbFvHdr = sizeof(*pFvHdr);
2080 uint64_t offBlockMap = sizeof(*pFvHdr);
2081 for (;;)
2082 {
2083 EFI_FW_BLOCK_MAP BlockMap;
2084 int rc = RTVfsFileReadAt(pThis->hVfsBacking, offBlockMap, &BlockMap, sizeof(BlockMap), NULL);
2085 if (RT_FAILURE(rc))
2086 return RTERRINFO_LOG_SET_F(pErrInfo, rc, "Reading block map entry from %#RX64 failed", offBlockMap);
2087
2088 cbFvHdr += sizeof(BlockMap);
2089 offBlockMap += sizeof(BlockMap);
2090
2091 /* A zero entry denotes the end. */
2092 if ( !RT_LE2H_U32(BlockMap.cBlocks)
2093 && !RT_LE2H_U32(BlockMap.cbBlock))
2094 break;
2095
2096 cbFvVol += RT_LE2H_U32(BlockMap.cBlocks) * RT_LE2H_U32(BlockMap.cbBlock);
2097
2098 pu16 = (const uint16_t *)&BlockMap;
2099 while (pu16 < (const uint16_t *)&BlockMap + (sizeof(BlockMap) / sizeof(uint16_t)))
2100 u16Chksum += RT_LE2H_U16(*pu16++);
2101 }
2102
2103 *poffData = offBlockMap;
2104
2105 if (u16Chksum)
2106 return RTERRINFO_LOG_SET(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "Firmware volume header has incorrect checksum");
2107 if (RT_LE2H_U16(pFvHdr->cbFvHdr) != cbFvHdr)
2108 return RTERRINFO_LOG_SET(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "Unexpected firmware volume header size");
2109
2110 return VINF_SUCCESS;
2111}
2112
2113
2114/**
2115 * Validates the given variable store header.
2116 *
2117 * @returns true if the given header is considered valid, false otherwise.
2118 * @param pThis The EFI variable store instance.
2119 * @param pHdr The variable store header to validate.
2120 * @param pfAuth Where to store whether the variable store uses authenticated variables or not.
2121 * @param pErrInfo Where to return additional error info.
2122 */
2123static int rtEfiVarStoreHdr_Validate(PRTEFIVARSTORE pThis, PCEFI_VARSTORE_HEADER pHdr, bool *pfAuth, PRTERRINFO pErrInfo)
2124{
2125#ifdef LOG_ENABLED
2126 rtEfiVarStoreHdr_Log(pHdr);
2127#endif
2128
2129 EFI_GUID GuidVarStoreAuth = EFI_VARSTORE_HEADER_GUID_AUTHENTICATED_VARIABLE;
2130 EFI_GUID GuidVarStore = EFI_VARSTORE_HEADER_GUID_VARIABLE;
2131 if (!memcmp(&pHdr->GuidVarStore, &GuidVarStoreAuth, sizeof(GuidVarStoreAuth)))
2132 *pfAuth = true;
2133 else if (!memcmp(&pHdr->GuidVarStore, &GuidVarStore, sizeof(GuidVarStore)))
2134 *pfAuth = false;
2135 else
2136 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT,
2137 "Variable store GUID doesn't indicate a variable store (%RTuuid)", pHdr->GuidVarStore);
2138 if (RT_LE2H_U32(pHdr->cbVarStore) >= pThis->cbBacking)
2139 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT,
2140 "Variable store length exceeds size of backing storage (truncated file?): %#RX32, max %#RX64",
2141 RT_LE2H_U32(pHdr->cbVarStore), pThis->cbBacking);
2142 if (pHdr->bFmt != EFI_VARSTORE_HEADER_FMT_FORMATTED)
2143 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "Variable store is not formatted (%#x)", pHdr->bFmt);
2144 if (pHdr->bState != EFI_VARSTORE_HEADER_STATE_HEALTHY)
2145 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "Variable store is not healthy (%#x)", pHdr->bState);
2146
2147 return VINF_SUCCESS;
2148}
2149
2150
2151/**
2152 * Validates the given authenticate variable header.
2153 *
2154 * @returns true if the given header is considered valid, false otherwise.
2155 * @param pThis The EFI variable store instance.
2156 * @param pVarHdr The variable header to validate.
2157 * @param offVar Offset of the authenticated variable header.
2158 * @param pErrInfo Where to return additional error info.
2159 */
2160static int rtEfiVarStoreAuthVar_Validate(PRTEFIVARSTORE pThis, PCEFI_AUTH_VAR_HEADER pVarHdr, uint64_t offVar, PRTERRINFO pErrInfo)
2161{
2162#ifdef LOG_ENABLED
2163 rtEfiVarStoreAuthVarHdr_Log(pVarHdr, offVar);
2164#endif
2165
2166 uint32_t cbName = RT_LE2H_U32(pVarHdr->cbName);
2167 uint32_t cbData = RT_LE2H_U32(pVarHdr->cbData);
2168 uint64_t cbVarMax = pThis->cbBacking - offVar - sizeof(*pVarHdr);
2169 if ( cbVarMax <= cbName
2170 || cbVarMax - cbName <= cbData)
2171 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "Variable exceeds remaining space in store (cbName=%u cbData=%u cbVarMax=%llu)",
2172 cbName, cbData, cbVarMax);
2173
2174 return VINF_SUCCESS;
2175}
2176
2177
2178/**
2179 * Loads the authenticated variable at the given offset.
2180 *
2181 * @returns IPRT status code.
2182 * @retval VERR_EOF if the end of the store was reached.
2183 * @param pThis The EFI variable store instance.
2184 * @param offVar Offset of the variable to load.
2185 * @param poffVarEnd Where to store the offset pointing to the end of the variable.
2186 * @param fIgnoreDelVars Flag whether to ignore deleted variables.
2187 * @param pErrInfo Where to return additional error info.
2188 */
2189static int rtEfiVarStoreLoadAuthVar(PRTEFIVARSTORE pThis, uint64_t offVar, uint64_t *poffVarEnd,
2190 bool fIgnoreDelVars, PRTERRINFO pErrInfo)
2191{
2192 EFI_AUTH_VAR_HEADER VarHdr;
2193 int rc = RTVfsFileReadAt(pThis->hVfsBacking, offVar, &VarHdr, sizeof(VarHdr), NULL);
2194 if (RT_FAILURE(rc))
2195 return rc;
2196
2197 rc = rtEfiVarStoreAuthVar_Validate(pThis, &VarHdr, offVar, pErrInfo);
2198 if (RT_FAILURE(rc))
2199 return rc;
2200
2201 if (poffVarEnd)
2202 *poffVarEnd = offVar + sizeof(VarHdr) + RT_LE2H_U32(VarHdr.cbData) + RT_LE2H_U32(VarHdr.cbName);
2203
2204 /* Only add complete variables or deleted variables when requested. */
2205 if ( ( fIgnoreDelVars
2206 && VarHdr.bState != EFI_AUTH_VAR_HEADER_STATE_ADDED)
2207 || VarHdr.bState == EFI_AUTH_VAR_HEADER_STATE_HDR_VALID_ONLY)
2208 return VINF_SUCCESS;
2209
2210 pThis->cbVarData += sizeof(VarHdr) + RT_LE2H_U32(VarHdr.cbData) + RT_LE2H_U32(VarHdr.cbName);
2211
2212 RTUTF16 awchName[128]; RT_ZERO(awchName);
2213 if (RT_LE2H_U32(VarHdr.cbName) > sizeof(awchName) - sizeof(RTUTF16))
2214 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNSUPPORTED_FORMAT, "Variable name is too long (%llu vs. %llu)\n",
2215 RT_LE2H_U32(VarHdr.cbName), sizeof(awchName));
2216
2217 rc = RTVfsFileReadAt(pThis->hVfsBacking, offVar + sizeof(VarHdr), &awchName[0], RT_LE2H_U32(VarHdr.cbName), NULL);
2218 if (RT_FAILURE(rc))
2219 return rc;
2220
2221 Log2(("Variable name '%ls'\n", &awchName[0]));
2222 rc = rtEfiVarStore_VarMaybeGrowEntries(pThis);
2223 if (RT_FAILURE(rc))
2224 return rc;
2225
2226 PRTEFIVAR pVar = &pThis->paVars[pThis->cVars++];
2227 pVar->pVarStore = pThis;
2228 if (RT_LE2H_U32(VarHdr.cbData))
2229 pVar->offVarData = offVar + sizeof(VarHdr) + RT_LE2H_U32(VarHdr.cbName);
2230 else
2231 pVar->offVarData = 0;
2232 pVar->fAttr = RT_LE2H_U32(VarHdr.fAttr);
2233 pVar->cMonotonic = RT_LE2H_U64(VarHdr.cMonotonic);
2234 pVar->idPubKey = RT_LE2H_U32(VarHdr.idPubKey);
2235 pVar->cbData = RT_LE2H_U32(VarHdr.cbData);
2236 pVar->pvData = NULL;
2237 pVar->fDeleted = false;
2238 memcpy(&pVar->EfiTimestamp, &VarHdr.Timestamp, sizeof(VarHdr.Timestamp));
2239
2240 if (VarHdr.Timestamp.u8Month)
2241 RTEfiTimeToTimeSpec(&pVar->Time, &VarHdr.Timestamp);
2242 else
2243 RTTimeNow(&pVar->Time);
2244
2245 RTEfiGuidToUuid(&pVar->Uuid, &VarHdr.GuidVendor);
2246
2247 rc = RTUtf16ToUtf8(&awchName[0], &pVar->pszName);
2248 if (RT_FAILURE(rc))
2249 pThis->cVars--;
2250
2251 rc = rtEfiVarStore_AddVarByGuid(pThis, &pVar->Uuid, pThis->cVars - 1);
2252
2253 return rc;
2254}
2255
2256
2257/**
2258 * Looks for the next variable starting at the given offset.
2259 *
2260 * @returns IPRT status code.
2261 * @retval VERR_EOF if the end of the store was reached.
2262 * @param pThis The EFI variable store instance.
2263 * @param offStart Where in the image to start looking.
2264 * @param poffVar Where to store the start of the next variable if found.
2265 */
2266static int rtEfiVarStoreFindVar(PRTEFIVARSTORE pThis, uint64_t offStart, uint64_t *poffVar)
2267{
2268 /* Try to find the ID indicating a variable start by loading data in chunks. */
2269 uint64_t offEnd = pThis->offStoreData + pThis->cbVarStore;
2270 while (offStart < offEnd)
2271 {
2272 uint16_t au16Tmp[_1K / sizeof(uint16_t)];
2273 size_t cbThisRead = RT_MIN(sizeof(au16Tmp), offEnd - offStart);
2274 int rc = RTVfsFileReadAt(pThis->hVfsBacking, offStart, &au16Tmp[0], sizeof(au16Tmp), NULL);
2275 if (RT_FAILURE(rc))
2276 return rc;
2277
2278 for (uint32_t i = 0; i < RT_ELEMENTS(au16Tmp); i++)
2279 if (RT_LE2H_U16(au16Tmp[i]) == EFI_AUTH_VAR_HEADER_START)
2280 {
2281 *poffVar = offStart + i * sizeof(uint16_t);
2282 return VINF_SUCCESS;
2283 }
2284
2285 offStart += cbThisRead;
2286 }
2287
2288 return VERR_EOF;
2289}
2290
2291
2292/**
2293 * Loads and parses the superblock of the filesystem.
2294 *
2295 * @returns IPRT status code.
2296 * @param pThis The EFI variable store instance.
2297 * @param pErrInfo Where to return additional error info.
2298 */
2299static int rtEfiVarStoreLoad(PRTEFIVARSTORE pThis, PRTERRINFO pErrInfo)
2300{
2301 EFI_FIRMWARE_VOLUME_HEADER FvHdr;
2302 int rc = RTVfsFileReadAt(pThis->hVfsBacking, 0, &FvHdr, sizeof(FvHdr), NULL);
2303 if (RT_FAILURE(rc))
2304 return RTERRINFO_LOG_SET(pErrInfo, rc, "Error reading firmware volume header");
2305
2306 /* Validate the signature. */
2307 if (RT_LE2H_U32(FvHdr.u32Signature) != EFI_FIRMWARE_VOLUME_HEADER_SIGNATURE)
2308 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_VFS_UNKNOWN_FORMAT, "Not a EFI variable store - Signature mismatch: %RX32", RT_LE2H_U16(FvHdr.u32Signature));
2309
2310 uint64_t offData = 0;
2311 rc = rtEfiVarStoreFvHdr_Validate(pThis, &FvHdr, &offData, pErrInfo);
2312 if (RT_FAILURE(rc))
2313 return rc;
2314
2315 EFI_VARSTORE_HEADER StoreHdr;
2316 rc = RTVfsFileReadAt(pThis->hVfsBacking, offData, &StoreHdr, sizeof(StoreHdr), NULL);
2317 if (RT_FAILURE(rc))
2318 return RTERRINFO_LOG_SET(pErrInfo, rc, "Error reading variable store header");
2319
2320 rc = rtEfiVarStoreHdr_Validate(pThis, &StoreHdr, &pThis->fAuth, pErrInfo);
2321 if (RT_FAILURE(rc))
2322 return rc;
2323
2324 pThis->offStoreData = offData + sizeof(StoreHdr);
2325 pThis->cbVarStore = RT_LE2H_U32(StoreHdr.cbVarStore) - sizeof(StoreHdr);
2326
2327 /* Go over variables and set up the pointers. */
2328 offData = pThis->offStoreData;
2329 for (;;)
2330 {
2331 uint64_t offVar = 0;
2332
2333 rc = rtEfiVarStoreFindVar(pThis, offData, &offVar);
2334 if (RT_FAILURE(rc))
2335 break;
2336
2337 rc = rtEfiVarStoreLoadAuthVar(pThis, offVar, &offData, true /* fIgnoreDelVars*/, pErrInfo);
2338 if (RT_FAILURE(rc))
2339 break;
2340
2341 /* Align to 16bit boundary. */
2342 offData = RT_ALIGN_64(offData, 2);
2343 }
2344
2345 if (rc == VERR_EOF) /* Reached end of variable store. */
2346 rc = VINF_SUCCESS;
2347
2348 return rc;
2349}
2350
2351
2352/**
2353 * Fills the given range with 0xff to match what a real NAND flash device would return for
2354 * unwritten storage.
2355 *
2356 * @returns IPRT status code.
2357 * @param hVfsFile The VFS file handle to write to.
2358 * @param offStart The start offset to fill.
2359 * @param offEnd Offset to fill up to (exclusive).
2360 */
2361static int rtEfiVarStoreFillWithFF(RTVFSFILE hVfsFile, uint64_t offStart, uint64_t offEnd)
2362{
2363 int rc = VINF_SUCCESS;
2364 uint8_t abFF[512];
2365 memset(&abFF[0], 0xff, sizeof(abFF));
2366
2367 while ( offStart < offEnd
2368 && RT_SUCCESS(rc))
2369 {
2370 size_t cbThisWrite = RT_MIN(sizeof(abFF), offEnd - offStart);
2371 rc = RTVfsFileWriteAt(hVfsFile, offStart, &abFF[0], cbThisWrite, NULL);
2372 offStart += cbThisWrite;
2373 }
2374
2375 return rc;
2376}
2377
2378
2379RTDECL(int) RTEfiVarStoreOpenAsVfs(RTVFSFILE hVfsFileIn, uint32_t fMntFlags, uint32_t fVarStoreFlags, PRTVFS phVfs, PRTERRINFO pErrInfo)
2380{
2381 AssertPtrReturn(phVfs, VERR_INVALID_POINTER);
2382 AssertReturn(!(fMntFlags & ~RTVFSMNT_F_VALID_MASK), VERR_INVALID_FLAGS);
2383 AssertReturn(!fVarStoreFlags, VERR_INVALID_FLAGS);
2384
2385 uint32_t cRefs = RTVfsFileRetain(hVfsFileIn);
2386 AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
2387
2388 /*
2389 * Create a VFS instance and initialize the data so rtFsExtVol_Close works.
2390 */
2391 RTVFS hVfs;
2392 PRTEFIVARSTORE pThis;
2393 int rc = RTVfsNew(&g_rtEfiVarStoreOps, sizeof(*pThis), NIL_RTVFS, RTVFSLOCK_CREATE_RW, &hVfs, (void **)&pThis);
2394 if (RT_SUCCESS(rc))
2395 {
2396 pThis->hVfsBacking = hVfsFileIn;
2397 pThis->hVfsSelf = hVfs;
2398 pThis->fMntFlags = fMntFlags;
2399 pThis->fVarStoreFlags = fVarStoreFlags;
2400
2401 rc = RTVfsFileQuerySize(pThis->hVfsBacking, &pThis->cbBacking);
2402 if (RT_SUCCESS(rc))
2403 {
2404 rc = rtEfiVarStoreLoad(pThis, pErrInfo);
2405 if (RT_SUCCESS(rc))
2406 {
2407 *phVfs = hVfs;
2408 return VINF_SUCCESS;
2409 }
2410 }
2411
2412 RTVfsRelease(hVfs);
2413 *phVfs = NIL_RTVFS;
2414 }
2415 else
2416 RTVfsFileRelease(hVfsFileIn);
2417
2418 return rc;
2419}
2420
2421
2422RTDECL(int) RTEfiVarStoreCreate(RTVFSFILE hVfsFile, uint64_t offStore, uint64_t cbStore, uint32_t fFlags, uint32_t cbBlock,
2423 PRTERRINFO pErrInfo)
2424{
2425 RT_NOREF(pErrInfo);
2426
2427 /*
2428 * Validate input.
2429 */
2430 if (!cbBlock)
2431 cbBlock = 4096;
2432 else
2433 AssertMsgReturn(cbBlock <= 8192 && RT_IS_POWER_OF_TWO(cbBlock),
2434 ("cbBlock=%#x\n", cbBlock), VERR_INVALID_PARAMETER);
2435 AssertReturn(!(fFlags & ~RTEFIVARSTORE_CREATE_F_VALID_MASK), VERR_INVALID_FLAGS);
2436
2437 if (!cbStore)
2438 {
2439 uint64_t cbFile;
2440 int rc = RTVfsFileQuerySize(hVfsFile, &cbFile);
2441 AssertRCReturn(rc, rc);
2442 AssertMsgReturn(cbFile > offStore, ("cbFile=%#RX64 offStore=%#RX64\n", cbFile, offStore), VERR_INVALID_PARAMETER);
2443 cbStore = cbFile - offStore;
2444 }
2445
2446 uint32_t cbFtw = 0;
2447 uint32_t offFtw = 0;
2448 uint32_t cbVarStore = cbStore;
2449 uint32_t cbNvEventLog = 0;
2450 uint32_t offNvEventLog = 0;
2451 if (!(fFlags & RTEFIVARSTORE_CREATE_F_NO_FTW_WORKING_SPACE))
2452 {
2453 /* Split the available space in half for the fault tolerant working area. */
2454 /** @todo Don't fully understand how these values come together right now but
2455 * we want to create NVRAM files matching the default OVMF_VARS.fd for now, see
2456 * https://github.com/tianocore/edk2/commit/b24fca05751f8222acf264853709012e0ab7bf49
2457 * for the layout.
2458 * Probably have toadd more arguments to control the different parameters.
2459 */
2460 cbNvEventLog = _4K;
2461 cbVarStore = cbStore / 2 - cbNvEventLog - _4K;
2462 cbFtw = cbVarStore + _4K;
2463 offNvEventLog = cbVarStore;
2464 offFtw = offNvEventLog + cbNvEventLog;
2465 }
2466
2467 uint32_t const cBlocks = (uint32_t)(cbStore / cbBlock);
2468
2469 EFI_GUID GuidVarStore = EFI_VARSTORE_FILESYSTEM_GUID;
2470 EFI_GUID GuidVarAuth = EFI_VARSTORE_HEADER_GUID_AUTHENTICATED_VARIABLE;
2471 EFI_FIRMWARE_VOLUME_HEADER FvHdr; RT_ZERO(FvHdr);
2472 EFI_FW_BLOCK_MAP aBlockMap[2]; RT_ZERO(aBlockMap);
2473 EFI_VARSTORE_HEADER VarStoreHdr; RT_ZERO(VarStoreHdr);
2474
2475 /* Firmware volume header. */
2476 memcpy(&FvHdr.GuidFilesystem, &GuidVarStore, sizeof(GuidVarStore));
2477 FvHdr.cbFv = RT_H2LE_U64(cbStore);
2478 FvHdr.u32Signature = RT_H2LE_U32(EFI_FIRMWARE_VOLUME_HEADER_SIGNATURE);
2479 FvHdr.fAttr = RT_H2LE_U32(0x4feff); /** @todo */
2480 FvHdr.cbFvHdr = RT_H2LE_U16(sizeof(FvHdr) + sizeof(aBlockMap));
2481 FvHdr.bRevision = EFI_FIRMWARE_VOLUME_HEADER_REVISION;
2482
2483 /* Start calculating the checksum of the main header. */
2484 uint16_t u16Chksum = 0;
2485 const uint16_t *pu16 = (const uint16_t *)&FvHdr;
2486 while (pu16 < (const uint16_t *)&FvHdr + (sizeof(FvHdr) / sizeof(uint16_t)))
2487 u16Chksum += RT_LE2H_U16(*pu16++);
2488
2489 /* Block map, the second entry remains 0 as it serves the delimiter. */
2490 aBlockMap[0].cbBlock = RT_H2LE_U32(cbBlock);
2491 aBlockMap[0].cBlocks = RT_H2LE_U32(cBlocks);
2492
2493 pu16 = (const uint16_t *)&aBlockMap[0];
2494 while (pu16 < (const uint16_t *)&aBlockMap[0] + (sizeof(aBlockMap) / (sizeof(uint16_t))))
2495 u16Chksum += RT_LE2H_U16(*pu16++);
2496
2497 FvHdr.u16Chksum = RT_H2LE_U16(UINT16_MAX - u16Chksum + 1);
2498
2499 /* Variable store header. */
2500 memcpy(&VarStoreHdr.GuidVarStore, &GuidVarAuth, sizeof(GuidVarAuth));
2501 VarStoreHdr.cbVarStore = RT_H2LE_U32(cbVarStore - sizeof(FvHdr) - sizeof(aBlockMap));
2502 VarStoreHdr.bFmt = EFI_VARSTORE_HEADER_FMT_FORMATTED;
2503 VarStoreHdr.bState = EFI_VARSTORE_HEADER_STATE_HEALTHY;
2504
2505 /* Write everything. */
2506 int rc = RTVfsFileWriteAt(hVfsFile, offStore, &FvHdr, sizeof(FvHdr), NULL);
2507 if (RT_SUCCESS(rc))
2508 rc = RTVfsFileWriteAt(hVfsFile, offStore + sizeof(FvHdr), &aBlockMap[0], sizeof(aBlockMap), NULL);
2509 if (RT_SUCCESS(rc))
2510 rc = RTVfsFileWriteAt(hVfsFile, offStore + sizeof(FvHdr) + sizeof(aBlockMap), &VarStoreHdr, sizeof(VarStoreHdr), NULL);
2511 if (RT_SUCCESS(rc))
2512 {
2513 /* Fill the remainder with 0xff as it would be the case for a real NAND flash device. */
2514 uint64_t offStart = offStore + sizeof(FvHdr) + sizeof(aBlockMap) + sizeof(VarStoreHdr);
2515 uint64_t offEnd = offStore + cbVarStore;
2516
2517 rc = rtEfiVarStoreFillWithFF(hVfsFile, offStart, offEnd);
2518 }
2519
2520 if ( RT_SUCCESS(rc)
2521 && !(fFlags & RTEFIVARSTORE_CREATE_F_NO_FTW_WORKING_SPACE))
2522 {
2523 EFI_GUID GuidFtwArea = EFI_WORKING_BLOCK_SIGNATURE_GUID;
2524 EFI_FTW_BLOCK_HEADER FtwHdr; RT_ZERO(FtwHdr);
2525
2526 memcpy(&FtwHdr.GuidSignature, &GuidFtwArea, sizeof(GuidFtwArea));
2527 FtwHdr.fWorkingBlockValid = RT_H2LE_U32(0xfffffffe); /** @todo */
2528 FtwHdr.cbWriteQueue = RT_H2LE_U64(0xfe0ULL); /* This comes from the default OVMF variable volume. */
2529 FtwHdr.u32Chksum = RTCrc32(&FtwHdr, sizeof(FtwHdr));
2530
2531 /* The area starts with the event log which defaults to 0xff. */
2532 rc = rtEfiVarStoreFillWithFF(hVfsFile, offNvEventLog, offNvEventLog + cbNvEventLog);
2533 if (RT_SUCCESS(rc))
2534 {
2535 /* Write the FTW header. */
2536 rc = RTVfsFileWriteAt(hVfsFile, offFtw, &FtwHdr, sizeof(FtwHdr), NULL);
2537 if (RT_SUCCESS(rc))
2538 rc = rtEfiVarStoreFillWithFF(hVfsFile, offFtw + sizeof(FtwHdr), offFtw + cbFtw);
2539 }
2540 }
2541
2542 return rc;
2543}
2544
2545
2546/**
2547 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate}
2548 */
2549static DECLCALLBACK(int) rtVfsChainEfiVarStore_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
2550 PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
2551{
2552 RT_NOREF(pProviderReg);
2553
2554 /*
2555 * Basic checks.
2556 */
2557 if (pElement->enmTypeIn != RTVFSOBJTYPE_FILE)
2558 return pElement->enmTypeIn == RTVFSOBJTYPE_INVALID ? VERR_VFS_CHAIN_CANNOT_BE_FIRST_ELEMENT : VERR_VFS_CHAIN_TAKES_FILE;
2559 if ( pElement->enmType != RTVFSOBJTYPE_VFS
2560 && pElement->enmType != RTVFSOBJTYPE_DIR)
2561 return VERR_VFS_CHAIN_ONLY_DIR_OR_VFS;
2562 if (pElement->cArgs > 1)
2563 return VERR_VFS_CHAIN_AT_MOST_ONE_ARG;
2564
2565 /*
2566 * Parse the flag if present, save in pElement->uProvider.
2567 */
2568 bool fReadOnly = (pSpec->fOpenFile & RTFILE_O_ACCESS_MASK) == RTFILE_O_READ;
2569 if (pElement->cArgs > 0)
2570 {
2571 const char *psz = pElement->paArgs[0].psz;
2572 if (*psz)
2573 {
2574 if (!strcmp(psz, "ro"))
2575 fReadOnly = true;
2576 else if (!strcmp(psz, "rw"))
2577 fReadOnly = false;
2578 else
2579 {
2580 *poffError = pElement->paArgs[0].offSpec;
2581 return RTErrInfoSet(pErrInfo, VERR_VFS_CHAIN_INVALID_ARGUMENT, "Expected 'ro' or 'rw' as argument");
2582 }
2583 }
2584 }
2585
2586 pElement->uProvider = fReadOnly ? RTVFSMNT_F_READ_ONLY : 0;
2587 return VINF_SUCCESS;
2588}
2589
2590
2591/**
2592 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnInstantiate}
2593 */
2594static DECLCALLBACK(int) rtVfsChainEfiVarStore_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
2595 PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
2596 PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
2597{
2598 RT_NOREF(pProviderReg, pSpec, poffError);
2599
2600 int rc;
2601 RTVFSFILE hVfsFileIn = RTVfsObjToFile(hPrevVfsObj);
2602 if (hVfsFileIn != NIL_RTVFSFILE)
2603 {
2604 RTVFS hVfs;
2605 rc = RTEfiVarStoreOpenAsVfs(hVfsFileIn, (uint32_t)pElement->uProvider, (uint32_t)(pElement->uProvider >> 32), &hVfs, pErrInfo);
2606 RTVfsFileRelease(hVfsFileIn);
2607 if (RT_SUCCESS(rc))
2608 {
2609 *phVfsObj = RTVfsObjFromVfs(hVfs);
2610 RTVfsRelease(hVfs);
2611 if (*phVfsObj != NIL_RTVFSOBJ)
2612 return VINF_SUCCESS;
2613 rc = VERR_VFS_CHAIN_CAST_FAILED;
2614 }
2615 }
2616 else
2617 rc = VERR_VFS_CHAIN_CAST_FAILED;
2618 return rc;
2619}
2620
2621
2622/**
2623 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnCanReuseElement}
2624 */
2625static DECLCALLBACK(bool) rtVfsChainEfiVarStore_CanReuseElement(PCRTVFSCHAINELEMENTREG pProviderReg,
2626 PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement,
2627 PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)
2628{
2629 RT_NOREF(pProviderReg, pSpec, pReuseSpec);
2630 if ( pElement->paArgs[0].uProvider == pReuseElement->paArgs[0].uProvider
2631 || !pReuseElement->paArgs[0].uProvider)
2632 return true;
2633 return false;
2634}
2635
2636
2637/** VFS chain element 'efivarstore'. */
2638static RTVFSCHAINELEMENTREG g_rtVfsChainEfiVarStoreReg =
2639{
2640 /* uVersion = */ RTVFSCHAINELEMENTREG_VERSION,
2641 /* fReserved = */ 0,
2642 /* pszName = */ "efivarstore",
2643 /* ListEntry = */ { NULL, NULL },
2644 /* pszHelp = */ "Open a EFI variable store, requires a file object on the left side.\n"
2645 "First argument is an optional 'ro' (read-only) or 'rw' (read-write) flag.\n",
2646 /* pfnValidate = */ rtVfsChainEfiVarStore_Validate,
2647 /* pfnInstantiate = */ rtVfsChainEfiVarStore_Instantiate,
2648 /* pfnCanReuseElement = */ rtVfsChainEfiVarStore_CanReuseElement,
2649 /* uEndMarker = */ RTVFSCHAINELEMENTREG_VERSION
2650};
2651
2652RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(&g_rtVfsChainEfiVarStoreReg, rtVfsChainEfiVarStoreReg);
2653
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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