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