]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/NvVarsFileLib/FsAccess.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / OvmfPkg / Library / NvVarsFileLib / FsAccess.c
1 /** @file
2 File System Access for NvVarsFileLib
3
4 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "NvVarsFileLib.h"
10
11 #include <Library/BaseMemoryLib.h>
12 #include <Library/DebugLib.h>
13 #include <Library/MemoryAllocationLib.h>
14
15 /**
16 Open the NvVars file for reading or writing
17
18 @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
19 @param[in] ReadingFile - TRUE: open the file for reading. FALSE: writing
20 @param[out] NvVarsFile - If EFI_SUCCESS is returned, then this is updated
21 with the opened NvVars file.
22
23 @return EFI_SUCCESS if the file was opened
24
25 **/
26 EFI_STATUS
27 GetNvVarsFile (
28 IN EFI_HANDLE FsHandle,
29 IN BOOLEAN ReadingFile,
30 OUT EFI_FILE_HANDLE *NvVarsFile
31 )
32 {
33 EFI_STATUS Status;
34 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
35 EFI_FILE_HANDLE Root;
36
37 //
38 // Get the FileSystem protocol on that handle
39 //
40 Status = gBS->HandleProtocol (
41 FsHandle,
42 &gEfiSimpleFileSystemProtocolGuid,
43 (VOID **)&Fs
44 );
45 if (EFI_ERROR (Status)) {
46 return Status;
47 }
48
49 //
50 // Get the volume (the root directory)
51 //
52 Status = Fs->OpenVolume (Fs, &Root);
53 if (EFI_ERROR (Status)) {
54 return Status;
55 }
56
57 //
58 // Attempt to open the NvVars file in the root directory
59 //
60 Status = Root->Open (
61 Root,
62 NvVarsFile,
63 L"NvVars",
64 ReadingFile ?
65 EFI_FILE_MODE_READ :
66 (
67 EFI_FILE_MODE_CREATE |
68 EFI_FILE_MODE_READ |
69 EFI_FILE_MODE_WRITE
70 ),
71 0
72 );
73
74 return Status;
75 }
76
77 /**
78 Open the NvVars file for reading or writing
79
80 @param[in] File - The file to inspect
81 @param[out] Exists - Returns whether the file exists
82 @param[out] Size - Returns the size of the file
83 (0 if the file does not exist)
84
85 **/
86 VOID
87 NvVarsFileReadCheckup (
88 IN EFI_FILE_HANDLE File,
89 OUT BOOLEAN *Exists,
90 OUT UINTN *Size
91 )
92 {
93 EFI_FILE_INFO *FileInfo;
94
95 *Exists = FALSE;
96 *Size = 0;
97
98 FileInfo = FileHandleGetInfo (File);
99 if (FileInfo == NULL) {
100 return;
101 }
102
103 if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) != 0) {
104 FreePool (FileInfo);
105 return;
106 }
107
108 *Exists = TRUE;
109 *Size = (UINTN)FileInfo->FileSize;
110
111 FreePool (FileInfo);
112 }
113
114 /**
115 Open the NvVars file for reading or writing
116
117 @param[in] File - The file to inspect
118 @param[out] Exists - Returns whether the file exists
119 @param[out] Size - Returns the size of the file
120 (0 if the file does not exist)
121
122 **/
123 EFI_STATUS
124 FileHandleEmpty (
125 IN EFI_FILE_HANDLE File
126 )
127 {
128 EFI_STATUS Status;
129 EFI_FILE_INFO *FileInfo;
130
131 //
132 // Retrieve the FileInfo structure
133 //
134 FileInfo = FileHandleGetInfo (File);
135 if (FileInfo == NULL) {
136 return EFI_INVALID_PARAMETER;
137 }
138
139 //
140 // If the path is a directory, then return an error
141 //
142 if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) != 0) {
143 FreePool (FileInfo);
144 return EFI_INVALID_PARAMETER;
145 }
146
147 //
148 // If the file size is already 0, then it is empty, so
149 // we can return success.
150 //
151 if (FileInfo->FileSize == 0) {
152 FreePool (FileInfo);
153 return EFI_SUCCESS;
154 }
155
156 //
157 // Set the file size to 0.
158 //
159 FileInfo->FileSize = 0;
160 Status = FileHandleSetInfo (File, FileInfo);
161
162 FreePool (FileInfo);
163
164 return Status;
165 }
166
167 /**
168 Reads a file to a newly allocated buffer
169
170 @param[in] File - The file to read
171 @param[in] ReadSize - The size of data to read from the file
172
173 @return Pointer to buffer allocated to hold the file
174 contents. NULL if an error occurred.
175
176 **/
177 VOID *
178 FileHandleReadToNewBuffer (
179 IN EFI_FILE_HANDLE FileHandle,
180 IN UINTN ReadSize
181 )
182 {
183 EFI_STATUS Status;
184 UINTN ActualReadSize;
185 VOID *FileContents;
186
187 ActualReadSize = ReadSize;
188 FileContents = AllocatePool (ReadSize);
189 if (FileContents != NULL) {
190 Status = FileHandleRead (
191 FileHandle,
192 &ReadSize,
193 FileContents
194 );
195 if (EFI_ERROR (Status) || (ActualReadSize != ReadSize)) {
196 FreePool (FileContents);
197 return NULL;
198 }
199 }
200
201 return FileContents;
202 }
203
204 /**
205 Reads the contents of the NvVars file on the file system
206
207 @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
208
209 @return EFI_STATUS based on the success or failure of the file read
210
211 **/
212 EFI_STATUS
213 ReadNvVarsFile (
214 IN EFI_HANDLE FsHandle
215 )
216 {
217 EFI_STATUS Status;
218 EFI_FILE_HANDLE File;
219 UINTN FileSize;
220 BOOLEAN FileExists;
221 VOID *FileContents;
222 EFI_HANDLE SerializedVariables;
223
224 Status = GetNvVarsFile (FsHandle, TRUE, &File);
225 if (EFI_ERROR (Status)) {
226 DEBUG ((DEBUG_INFO, "FsAccess.c: Could not open NV Variables file on this file system\n"));
227 return Status;
228 }
229
230 NvVarsFileReadCheckup (File, &FileExists, &FileSize);
231 if (FileSize == 0) {
232 FileHandleClose (File);
233 return EFI_UNSUPPORTED;
234 }
235
236 FileContents = FileHandleReadToNewBuffer (File, FileSize);
237 if (FileContents == NULL) {
238 FileHandleClose (File);
239 return EFI_UNSUPPORTED;
240 }
241
242 DEBUG ((
243 DEBUG_INFO,
244 "FsAccess.c: Read %Lu bytes from NV Variables file\n",
245 (UINT64)FileSize
246 ));
247
248 Status = SerializeVariablesNewInstanceFromBuffer (
249 &SerializedVariables,
250 FileContents,
251 FileSize
252 );
253 if (!RETURN_ERROR (Status)) {
254 Status = SerializeVariablesSetSerializedVariables (SerializedVariables);
255 }
256
257 FreePool (FileContents);
258 FileHandleClose (File);
259
260 return Status;
261 }
262
263 /**
264 Writes a variable to indicate that the NV variables
265 have been loaded from the file system.
266
267 **/
268 STATIC
269 VOID
270 SetNvVarsVariable (
271 VOID
272 )
273 {
274 BOOLEAN VarData;
275 UINTN Size;
276
277 //
278 // Write a variable to indicate we've already loaded the
279 // variable data. If it is found, we skip the loading on
280 // subsequent attempts.
281 //
282 Size = sizeof (VarData);
283 VarData = TRUE;
284 gRT->SetVariable (
285 L"NvVars",
286 &gEfiSimpleFileSystemProtocolGuid,
287 EFI_VARIABLE_NON_VOLATILE |
288 EFI_VARIABLE_BOOTSERVICE_ACCESS |
289 EFI_VARIABLE_RUNTIME_ACCESS,
290 Size,
291 (VOID *)&VarData
292 );
293 }
294
295 /**
296 Loads the non-volatile variables from the NvVars file on the
297 given file system.
298
299 @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
300
301 @return EFI_STATUS based on the success or failure of load operation
302
303 **/
304 EFI_STATUS
305 LoadNvVarsFromFs (
306 EFI_HANDLE FsHandle
307 )
308 {
309 EFI_STATUS Status;
310 BOOLEAN VarData;
311 UINTN Size;
312
313 DEBUG ((DEBUG_INFO, "FsAccess.c: LoadNvVarsFromFs\n"));
314
315 //
316 // We write a variable to indicate we've already loaded the
317 // variable data. If it is found, we skip the loading.
318 //
319 // This is relevant if the non-volatile variable have been
320 // able to survive a reboot operation. In that case, we don't
321 // want to re-load the file as it would overwrite newer changes
322 // made to the variables.
323 //
324 Size = sizeof (VarData);
325 VarData = TRUE;
326 Status = gRT->GetVariable (
327 L"NvVars",
328 &gEfiSimpleFileSystemProtocolGuid,
329 NULL,
330 &Size,
331 (VOID *)&VarData
332 );
333 if (Status == EFI_SUCCESS) {
334 DEBUG ((DEBUG_INFO, "NV Variables were already loaded\n"));
335 return EFI_ALREADY_STARTED;
336 }
337
338 //
339 // Attempt to restore the variables from the NvVars file.
340 //
341 Status = ReadNvVarsFile (FsHandle);
342 if (EFI_ERROR (Status)) {
343 DEBUG ((DEBUG_INFO, "Error while restoring NV variable data\n"));
344 return Status;
345 }
346
347 //
348 // Write a variable to indicate we've already loaded the
349 // variable data. If it is found, we skip the loading on
350 // subsequent attempts.
351 //
352 SetNvVarsVariable ();
353
354 DEBUG ((
355 DEBUG_INFO,
356 "FsAccess.c: Read NV Variables file (size=%Lu)\n",
357 (UINT64)Size
358 ));
359
360 return Status;
361 }
362
363 STATIC
364 RETURN_STATUS
365 EFIAPI
366 IterateVariablesCallbackAddAllNvVariables (
367 IN VOID *Context,
368 IN CHAR16 *VariableName,
369 IN EFI_GUID *VendorGuid,
370 IN UINT32 Attributes,
371 IN UINTN DataSize,
372 IN VOID *Data
373 )
374 {
375 EFI_HANDLE Instance;
376
377 Instance = (EFI_HANDLE)Context;
378
379 //
380 // Only save non-volatile variables
381 //
382 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
383 return RETURN_SUCCESS;
384 }
385
386 return SerializeVariablesAddVariable (
387 Instance,
388 VariableName,
389 VendorGuid,
390 Attributes,
391 DataSize,
392 Data
393 );
394 }
395
396 /**
397 Saves the non-volatile variables into the NvVars file on the
398 given file system.
399
400 @param[in] FsHandle - Handle for a gEfiSimpleFileSystemProtocolGuid instance
401
402 @return EFI_STATUS based on the success or failure of load operation
403
404 **/
405 EFI_STATUS
406 SaveNvVarsToFs (
407 EFI_HANDLE FsHandle
408 )
409 {
410 EFI_STATUS Status;
411 EFI_FILE_HANDLE File;
412 UINTN WriteSize;
413 UINTN VariableDataSize;
414 VOID *VariableData;
415 EFI_HANDLE SerializedVariables;
416
417 SerializedVariables = NULL;
418
419 Status = SerializeVariablesNewInstance (&SerializedVariables);
420 if (EFI_ERROR (Status)) {
421 return Status;
422 }
423
424 Status = SerializeVariablesIterateSystemVariables (
425 IterateVariablesCallbackAddAllNvVariables,
426 (VOID *)SerializedVariables
427 );
428 if (EFI_ERROR (Status)) {
429 return Status;
430 }
431
432 VariableData = NULL;
433 VariableDataSize = 0;
434 Status = SerializeVariablesToBuffer (
435 SerializedVariables,
436 NULL,
437 &VariableDataSize
438 );
439 if (Status == RETURN_BUFFER_TOO_SMALL) {
440 VariableData = AllocatePool (VariableDataSize);
441 if (VariableData == NULL) {
442 Status = EFI_OUT_OF_RESOURCES;
443 } else {
444 Status = SerializeVariablesToBuffer (
445 SerializedVariables,
446 VariableData,
447 &VariableDataSize
448 );
449 }
450 }
451
452 SerializeVariablesFreeInstance (SerializedVariables);
453
454 if (EFI_ERROR (Status)) {
455 return Status;
456 }
457
458 //
459 // Open the NvVars file for writing.
460 //
461 Status = GetNvVarsFile (FsHandle, FALSE, &File);
462 if (EFI_ERROR (Status)) {
463 DEBUG ((DEBUG_INFO, "FsAccess.c: Unable to open file to saved NV Variables\n"));
464 return Status;
465 }
466
467 //
468 // Empty the starting file contents.
469 //
470 Status = FileHandleEmpty (File);
471 if (EFI_ERROR (Status)) {
472 FileHandleClose (File);
473 return Status;
474 }
475
476 WriteSize = VariableDataSize;
477 Status = FileHandleWrite (File, &WriteSize, VariableData);
478 if (EFI_ERROR (Status)) {
479 return Status;
480 }
481
482 FileHandleClose (File);
483
484 if (!EFI_ERROR (Status)) {
485 //
486 // Write a variable to indicate we've already loaded the
487 // variable data. If it is found, we skip the loading on
488 // subsequent attempts.
489 //
490 SetNvVarsVariable ();
491
492 DEBUG ((DEBUG_INFO, "Saved NV Variables to NvVars file\n"));
493 }
494
495 return Status;
496 }