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