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