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