]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsOpenClose.c
ArmPlatformPkg/BootMonFs: Don't write file header to media until Flush
[mirror_edk2.git] / ArmPlatformPkg / FileSystem / BootMonFs / BootMonFsOpenClose.c
CommitLineData
94e0955d
OM
1/** @file\r
2*\r
3* Copyright (c) 2012-2014, ARM Limited. All rights reserved.\r
4*\r
5* This program and the accompanying materials\r
6* are licensed and made available under the terms and conditions of the BSD License\r
7* which accompanies this distribution. The full text of the license may be found at\r
8* http://opensource.org/licenses/bsd-license.php\r
9*\r
10* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12*\r
13**/\r
14\r
15#include "BootMonFsInternal.h"\r
16\r
17// Clear a file's image description on storage media:\r
18// UEFI allows you to seek past the end of a file, a subsequent write will grow\r
19// the file. It does not specify how space between the former end of the file\r
20// and the beginning of the write should be filled. It's therefore possible that\r
21// BootMonFs metadata, that comes after the end of a file, could be left there\r
22// and wrongly detected by BootMonFsImageInBlock.\r
23STATIC\r
24EFI_STATUS\r
25InvalidateImageDescription (\r
26 IN BOOTMON_FS_FILE *File\r
27 )\r
28{\r
29 EFI_DISK_IO_PROTOCOL *DiskIo;\r
30 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
31 UINT32 MediaId;\r
32 UINT32 BlockSize;\r
33 VOID *Buffer;\r
34 EFI_STATUS Status;\r
35 UINT64 DescriptionAddress;\r
36\r
37 DiskIo = File->Instance->DiskIo;\r
38 BlockIo = File->Instance->BlockIo;\r
39 MediaId = BlockIo->Media->MediaId;\r
40 BlockSize = BlockIo->Media->BlockSize;\r
41\r
42 DescriptionAddress = (File->HwDescription.BlockEnd * BlockSize)\r
43 - sizeof (HW_IMAGE_DESCRIPTION);\r
44\r
45 Buffer = AllocateZeroPool (sizeof (HW_IMAGE_DESCRIPTION));\r
46\r
47 Status = DiskIo->WriteDisk (DiskIo,\r
48 MediaId,\r
49 DescriptionAddress,\r
50 sizeof (HW_IMAGE_DESCRIPTION),\r
51 Buffer\r
52 );\r
53\r
54 FreePool(Buffer);\r
55\r
56 return Status;\r
57}\r
58\r
59// Flush file data that will extend the file's length. Update and, if necessary,\r
60// move the image description.\r
61// We need to pass the file's starting position on media (FileStart), because\r
62// if the file hasn't been flushed before its Description->BlockStart won't\r
63// have been initialised.\r
64// FileStart must be aligned to the media's block size.\r
65// Note that this function uses DiskIo to flush, so call BlockIo->FlushBlocks()\r
66// after calling it.\r
67STATIC\r
68EFI_STATUS\r
69FlushAppendRegion (\r
70 IN BOOTMON_FS_FILE *File,\r
71 IN BOOTMON_FS_FILE_REGION *Region,\r
72 IN UINT64 NewFileSize,\r
73 IN UINT64 FileStart\r
74 )\r
75{\r
76 EFI_STATUS Status;\r
77 EFI_DISK_IO_PROTOCOL *DiskIo;\r
78 UINTN BlockSize;\r
79 HW_IMAGE_DESCRIPTION *Description;\r
80\r
81 DiskIo = File->Instance->DiskIo;\r
82\r
83 BlockSize = File->Instance->BlockIo->Media->BlockSize;\r
84\r
85 ASSERT (FileStart % BlockSize == 0);\r
86\r
87 // Only invalidate the Image Description of files that have already been\r
88 // written in Flash\r
89 if (File->HwDescription.RegionCount > 0) {\r
90 Status = InvalidateImageDescription (File);\r
91 ASSERT_EFI_ERROR (Status);\r
92 }\r
93\r
94 //\r
95 // Update File Description\r
96 //\r
97 Description = &File->HwDescription;\r
98 Description->Attributes = 1;\r
99 Description->BlockStart = FileStart / BlockSize;\r
100 Description->BlockEnd = Description->BlockStart + (NewFileSize / BlockSize);\r
101 Description->Footer.FooterSignature1 = HW_IMAGE_FOOTER_SIGNATURE_1;\r
102 Description->Footer.FooterSignature2 = HW_IMAGE_FOOTER_SIGNATURE_2;\r
cb77b48a 103#ifdef MDE_CPU_ARM\r
94e0955d
OM
104 Description->Footer.Version = HW_IMAGE_FOOTER_VERSION;\r
105 Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET;\r
cb77b48a
OM
106#else\r
107 Description->Footer.Version = HW_IMAGE_FOOTER_VERSION2;\r
108 Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET2;\r
109#endif\r
94e0955d
OM
110 Description->RegionCount = 1;\r
111 Description->Region[0].Checksum = 0;\r
112 Description->Region[0].Offset = Description->BlockStart * BlockSize;\r
113 Description->Region[0].Size = NewFileSize - sizeof (HW_IMAGE_DESCRIPTION);\r
114\r
115 Status = BootMonFsComputeFooterChecksum (Description);\r
116 if (EFI_ERROR (Status)) {\r
117 return Status;\r
118 }\r
119\r
120 // Write the new file data\r
121 Status = DiskIo->WriteDisk (\r
122 DiskIo,\r
123 File->Instance->Media->MediaId,\r
124 FileStart + Region->Offset,\r
125 Region->Size,\r
126 Region->Buffer\r
127 );\r
128 ASSERT_EFI_ERROR (Status);\r
129\r
130 // Round the file size up to the nearest block size\r
131 if ((NewFileSize % BlockSize) > 0) {\r
132 NewFileSize += BlockSize - (NewFileSize % BlockSize);\r
133 }\r
134 // Update the file description on the media\r
135 Status = DiskIo->WriteDisk (\r
136 DiskIo,\r
137 File->Instance->Media->MediaId,\r
138 (FileStart + NewFileSize) - sizeof (HW_IMAGE_DESCRIPTION),\r
139 sizeof (HW_IMAGE_DESCRIPTION),\r
140 Description\r
141 );\r
142 ASSERT_EFI_ERROR (Status);\r
143\r
144 return Status;\r
145}\r
146\r
147BOOLEAN\r
148BootMonFsFileNeedFlush (\r
149 IN BOOTMON_FS_FILE *File\r
150 )\r
151{\r
152 return !IsListEmpty (&File->RegionToFlushLink);\r
153}\r
154\r
155// Find a space on media for a file that has not yet been flushed to disk.\r
156// Just returns the first space that's big enough.\r
157// This function could easily be adapted to:\r
158// - Find space for moving an existing file that has outgrown its space\r
159// (We do not currently move files, just return EFI_VOLUME_FULL)\r
160// - Find space for a fragment of a file that has outgrown its space\r
161// (We do not currently fragment files - it's not clear whether fragmentation\r
162// is actually part of BootMonFs as there is no spec)\r
163// - Be more clever about finding space (choosing the largest or smallest\r
164// suitable space)\r
165// Parameters:\r
166// File - the new (not yet flushed) file for which we need to find space.\r
167// FileStart - the position on media of the file (in bytes).\r
168STATIC\r
169EFI_STATUS\r
170BootMonFsFindSpaceForNewFile (\r
171 IN BOOTMON_FS_FILE *File,\r
172 OUT UINT64 *FileStart\r
173 )\r
174{\r
175 LIST_ENTRY *FileLink;\r
176 BOOTMON_FS_FILE *RootFile;\r
177 BOOTMON_FS_FILE *FileEntry;\r
178 UINTN BlockSize;\r
179 UINT64 FileSize;\r
180 EFI_BLOCK_IO_MEDIA *Media;\r
181\r
182 Media = File->Instance->BlockIo->Media;\r
183 BlockSize = Media->BlockSize;\r
184 RootFile = File->Instance->RootFile;\r
185\r
186 if (IsListEmpty (&RootFile->Link)) {\r
187 return EFI_SUCCESS;\r
188 }\r
189\r
190 // This function must only be called for file which has not been flushed into\r
191 // Flash yet\r
192 ASSERT (File->HwDescription.RegionCount == 0);\r
193\r
194 // Find out how big the file will be\r
195 FileSize = BootMonFsGetImageLength (File);\r
196 // Add the file header to the file\r
197 FileSize += sizeof (HW_IMAGE_DESCRIPTION);\r
198\r
199 *FileStart = 0;\r
200 // Go through all the files in the list\r
201 for (FileLink = GetFirstNode (&RootFile->Link);\r
202 !IsNull (&RootFile->Link, FileLink);\r
203 FileLink = GetNextNode (&RootFile->Link, FileLink)\r
204 )\r
205 {\r
206 FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink);\r
207 // If the free space preceding the file is big enough to contain the new\r
208 // file then use it!\r
209 if (((FileEntry->HwDescription.BlockStart * BlockSize) - *FileStart)\r
210 >= FileSize) {\r
211 // The file list must be in disk-order\r
212 RemoveEntryList (&File->Link);\r
213 File->Link.BackLink = FileLink->BackLink;\r
214 File->Link.ForwardLink = FileLink;\r
215 FileLink->BackLink->ForwardLink = &File->Link;\r
216 FileLink->BackLink = &File->Link;\r
217\r
218 return EFI_SUCCESS;\r
219 } else {\r
220 *FileStart = (FileEntry->HwDescription.BlockEnd + 1) * BlockSize;\r
221 }\r
222 }\r
223 // See if there's space after the last file\r
224 if ((((Media->LastBlock + 1) * BlockSize) - *FileStart) >= FileSize) {\r
225 return EFI_SUCCESS;\r
226 } else {\r
227 return EFI_VOLUME_FULL;\r
228 }\r
229}\r
230\r
231// Free the resources in the file's Region list.\r
232STATIC\r
233VOID\r
234FreeFileRegions (\r
235 IN BOOTMON_FS_FILE *File\r
236 )\r
237{\r
238 LIST_ENTRY *RegionToFlushLink;\r
239 BOOTMON_FS_FILE_REGION *Region;\r
240\r
241 RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);\r
242 while (!IsNull (&File->RegionToFlushLink, RegionToFlushLink)) {\r
243 // Repeatedly remove the first node from the list and free its resources.\r
244 Region = (BOOTMON_FS_FILE_REGION *) RegionToFlushLink;\r
245 RemoveEntryList (RegionToFlushLink);\r
246 FreePool (Region->Buffer);\r
247 FreePool (Region);\r
248\r
249 RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);\r
250 }\r
251}\r
252\r
253EFIAPI\r
254EFI_STATUS\r
255BootMonFsFlushFile (\r
256 IN EFI_FILE_PROTOCOL *This\r
257 )\r
258{\r
259 EFI_STATUS Status;\r
260 BOOTMON_FS_INSTANCE *Instance;\r
261 LIST_ENTRY *RegionToFlushLink;\r
262 BOOTMON_FS_FILE *File;\r
263 BOOTMON_FS_FILE *NextFile;\r
264 BOOTMON_FS_FILE_REGION *Region;\r
265 LIST_ENTRY *FileLink;\r
266 UINTN CurrentPhysicalSize;\r
267 UINTN BlockSize;\r
268 UINT64 FileStart;\r
269 UINT64 FileEnd;\r
270 UINT64 RegionStart;\r
271 UINT64 RegionEnd;\r
272 UINT64 NewFileSize;\r
273 UINT64 EndOfAppendSpace;\r
274 BOOLEAN HasSpace;\r
275 EFI_DISK_IO_PROTOCOL *DiskIo;\r
276 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
277\r
278 Status = EFI_SUCCESS;\r
279 FileStart = 0;\r
280\r
281 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
282 if (File == NULL) {\r
283 return EFI_INVALID_PARAMETER;\r
284 }\r
285\r
286 // Check if the file needs to be flushed\r
287 if (!BootMonFsFileNeedFlush (File)) {\r
288 return Status;\r
289 }\r
290\r
291 Instance = File->Instance;\r
292 BlockIo = Instance->BlockIo;\r
293 DiskIo = Instance->DiskIo;\r
294 BlockSize = BlockIo->Media->BlockSize;\r
295\r
296 // If the file doesn't exist then find a space for it\r
297 if (File->HwDescription.RegionCount == 0) {\r
298 Status = BootMonFsFindSpaceForNewFile (File, &FileStart);\r
299 // FileStart has changed so we need to recompute RegionEnd\r
300 if (EFI_ERROR (Status)) {\r
301 return Status;\r
302 }\r
303 } else {\r
304 FileStart = File->HwDescription.BlockStart * BlockSize;\r
305 }\r
306\r
307 // FileEnd is the NOR address of the end of the file's data\r
308 FileEnd = FileStart + BootMonFsGetImageLength (File);\r
309\r
310 for (RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);\r
311 !IsNull (&File->RegionToFlushLink, RegionToFlushLink);\r
312 RegionToFlushLink = GetNextNode (&File->RegionToFlushLink, RegionToFlushLink)\r
313 )\r
314 {\r
315 Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;\r
316\r
317 // RegionStart and RegionEnd are the the intended NOR address of the\r
318 // start and end of the region\r
319 RegionStart = FileStart + Region->Offset;\r
320 RegionEnd = RegionStart + Region->Size;\r
321\r
322 if (RegionEnd < FileEnd) {\r
323 // Handle regions representing edits to existing portions of the file\r
324 // Write the region data straight into the file\r
325 Status = DiskIo->WriteDisk (DiskIo,\r
326 BlockIo->Media->MediaId,\r
327 RegionStart,\r
328 Region->Size,\r
329 Region->Buffer\r
330 );\r
331 if (EFI_ERROR (Status)) {\r
332 return Status;\r
333 }\r
334 } else {\r
335 // Handle regions representing appends to the file\r
336 //\r
337 // Note: Since seeking past the end of the file with SetPosition() is\r
338 // valid, it's possible there will be a gap between the current end of\r
339 // the file and the beginning of the new region. Since the UEFI spec\r
340 // says nothing about this case (except "a subsequent write would grow\r
341 // the file"), we just leave garbage in the gap.\r
342\r
343 // Check if there is space to append the new region\r
344 HasSpace = FALSE;\r
345 NewFileSize = (RegionEnd - FileStart) + sizeof (HW_IMAGE_DESCRIPTION);\r
346 CurrentPhysicalSize = BootMonFsGetPhysicalSize (File);\r
347 if (NewFileSize <= CurrentPhysicalSize) {\r
348 HasSpace = TRUE;\r
349 } else {\r
350 // Get the File Description for the next file\r
351 FileLink = GetNextNode (&Instance->RootFile->Link, &File->Link);\r
352 if (!IsNull (&Instance->RootFile->Link, FileLink)) {\r
353 NextFile = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink);\r
354\r
355 // If there is space between the beginning of the current file and the\r
356 // beginning of the next file then use it\r
357 EndOfAppendSpace = NextFile->HwDescription.BlockStart * BlockSize;\r
358 } else {\r
359 // We are flushing the last file.\r
360 EndOfAppendSpace = (BlockIo->Media->LastBlock + 1) * BlockSize;\r
361 }\r
362 if (EndOfAppendSpace - FileStart >= NewFileSize) {\r
363 HasSpace = TRUE;\r
364 }\r
365 }\r
366\r
367 if (HasSpace == TRUE) {\r
368 Status = FlushAppendRegion (File, Region, NewFileSize, FileStart);\r
369 if (EFI_ERROR (Status)) {\r
370 return Status;\r
371 }\r
372 } else {\r
373 // There isn't a space for the file.\r
374 // Options here are to move the file or fragment it. However as files\r
375 // may represent boot images at fixed positions, these options will\r
376 // break booting if the bootloader doesn't use BootMonFs to find the\r
377 // image.\r
378\r
379 return EFI_VOLUME_FULL;\r
380 }\r
381 }\r
382 }\r
383\r
384 FreeFileRegions (File);\r
385\r
386 // Flush DiskIo Buffers (see UEFI Spec 12.7 - DiskIo buffers are flushed by\r
387 // calling FlushBlocks on the same device's BlockIo).\r
388 BlockIo->FlushBlocks (BlockIo);\r
389\r
390 return Status;\r
391}\r
392\r
393/**\r
394 Closes a file on the Nor Flash FS volume.\r
395\r
396 @param This The EFI_FILE_PROTOCOL to close.\r
397\r
398 @return Always returns EFI_SUCCESS.\r
399\r
400**/\r
401EFIAPI\r
402EFI_STATUS\r
403BootMonFsCloseFile (\r
404 IN EFI_FILE_PROTOCOL *This\r
405 )\r
406{\r
407 // Flush the file if needed\r
408 This->Flush (This);\r
409 return EFI_SUCCESS;\r
410}\r
411\r
412// Create a new instance of BOOTMON_FS_FILE.\r
413// Uses BootMonFsCreateFile to\r
414STATIC\r
415EFI_STATUS\r
416CreateNewFile (\r
417 IN BOOTMON_FS_INSTANCE *Instance,\r
418 IN CHAR8* AsciiFileName,\r
419 OUT BOOTMON_FS_FILE **NewHandle\r
420 )\r
421{\r
422 EFI_STATUS Status;\r
423 BOOTMON_FS_FILE *File;\r
424\r
425 Status = BootMonFsCreateFile (Instance, &File);\r
426 if (EFI_ERROR (Status)) {\r
427 return Status;\r
428 }\r
429\r
430 // Remove the leading '\\'\r
431 if (*AsciiFileName == '\\') {\r
432 AsciiFileName++;\r
433 }\r
434\r
435 // Set the file name\r
436 CopyMem (File->HwDescription.Footer.Filename, AsciiFileName, MAX_NAME_LENGTH);\r
437\r
438 // Add the file to list of files of the File System\r
439 InsertHeadList (&Instance->RootFile->Link, &File->Link);\r
440\r
441 *NewHandle = File;\r
442 return Status;\r
443}\r
444\r
445/**\r
446 Opens a file on the Nor Flash FS volume\r
447\r
448 Calls BootMonFsGetFileFromAsciiFilename to search the list of tracked files.\r
449\r
450 @param This The EFI_FILE_PROTOCOL parent handle.\r
451 @param NewHandle Double-pointer to the newly created protocol.\r
452 @param FileName The name of the image/metadata on flash\r
453 @param OpenMode Read,write,append etc\r
454 @param Attributes ?\r
455\r
456 @return EFI_STATUS\r
457 OUT_OF_RESOURCES\r
458 Run out of space to keep track of the allocated structures\r
459 DEVICE_ERROR\r
460 Unable to locate the volume associated with the parent file handle\r
461 NOT_FOUND\r
462 Filename wasn't found on flash\r
463 SUCCESS\r
464\r
465**/\r
466EFIAPI\r
467EFI_STATUS\r
468BootMonFsOpenFile (\r
469 IN EFI_FILE_PROTOCOL *This,\r
470 OUT EFI_FILE_PROTOCOL **NewHandle,\r
471 IN CHAR16 *FileName,\r
472 IN UINT64 OpenMode,\r
473 IN UINT64 Attributes\r
474 )\r
475{\r
476 BOOTMON_FS_FILE *Directory;\r
477 BOOTMON_FS_FILE *File;\r
478 BOOTMON_FS_INSTANCE *Instance;\r
479 CHAR8* AsciiFileName;\r
480 EFI_STATUS Status;\r
481\r
482 if ((FileName == NULL) || (NewHandle == NULL)) {\r
483 return EFI_INVALID_PARAMETER;\r
484 }\r
485\r
486 // The only valid modes are read, read/write, and read/write/create\r
487 if (!(OpenMode & EFI_FILE_MODE_READ) || ((OpenMode & EFI_FILE_MODE_CREATE) && !(OpenMode & EFI_FILE_MODE_WRITE))) {\r
488 return EFI_INVALID_PARAMETER;\r
489 }\r
490\r
491 Directory = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
492 if (Directory == NULL) {\r
493 return EFI_DEVICE_ERROR;\r
494 }\r
495\r
496 Instance = Directory->Instance;\r
497\r
498 // If the instance has not been initialized it yet then do it ...\r
499 if (!Instance->Initialized) {\r
500 Status = BootMonFsInitialize (Instance);\r
501 if (EFI_ERROR (Status)) {\r
502 return Status;\r
503 }\r
504 }\r
505\r
506 // BootMonFs interface requires ASCII filenames\r
507 AsciiFileName = AllocatePool ((StrLen (FileName) + 1) * sizeof (CHAR8));\r
508 if (AsciiFileName == NULL) {\r
509 return EFI_OUT_OF_RESOURCES;\r
510 }\r
511 UnicodeStrToAsciiStr (FileName, AsciiFileName);\r
512\r
513 if ((AsciiStrCmp (AsciiFileName, "\\") == 0) ||\r
514 (AsciiStrCmp (AsciiFileName, "/") == 0) ||\r
515 (AsciiStrCmp (AsciiFileName, "") == 0) ||\r
516 (AsciiStrCmp (AsciiFileName, ".") == 0))\r
517 {\r
518 //\r
519 // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory\r
520 //\r
521\r
522 *NewHandle = &Instance->RootFile->File;\r
523 Instance->RootFile->Position = 0;\r
524 Status = EFI_SUCCESS;\r
525 } else {\r
526 //\r
527 // Open or Create a regular file\r
528 //\r
529\r
530 // Check if the file already exists\r
531 Status = BootMonGetFileFromAsciiFileName (Instance, AsciiFileName, &File);\r
532 if (Status == EFI_NOT_FOUND) {\r
533 // The file doesn't exist.\r
534 if (OpenMode & EFI_FILE_MODE_CREATE) {\r
535 // If the file does not exist but is required then create it.\r
536 if (Attributes & EFI_FILE_DIRECTORY) {\r
537 // BootMonFS doesn't support subdirectories\r
538 Status = EFI_UNSUPPORTED;\r
539 } else {\r
540 // Create a new file\r
541 Status = CreateNewFile (Instance, AsciiFileName, &File);\r
542 if (!EFI_ERROR (Status)) {\r
543 File->OpenMode = OpenMode;\r
544 *NewHandle = &File->File;\r
545 File->Position = 0;\r
546 }\r
547 }\r
548 }\r
549 } else if (Status == EFI_SUCCESS) {\r
550 // The file exists\r
551 File->OpenMode = OpenMode;\r
552 *NewHandle = &File->File;\r
553 File->Position = 0;\r
554 }\r
555 }\r
556\r
557 FreePool (AsciiFileName);\r
558\r
559 return Status;\r
560}\r
561\r
562// Delete() for the root directory's EFI_FILE_PROTOCOL instance\r
563EFIAPI\r
564EFI_STATUS\r
565BootMonFsDeleteFail (\r
566 IN EFI_FILE_PROTOCOL *This\r
567 )\r
568{\r
569 This->Close(This);\r
570 // You can't delete the root directory\r
571 return EFI_WARN_DELETE_FAILURE;\r
572}\r
573EFIAPI\r
574EFI_STATUS\r
575BootMonFsDelete (\r
576 IN EFI_FILE_PROTOCOL *This\r
577 )\r
578{\r
579 EFI_STATUS Status;\r
580 BOOTMON_FS_FILE *File;\r
581 LIST_ENTRY *RegionToFlushLink;\r
582 BOOTMON_FS_FILE_REGION *Region;\r
583 HW_IMAGE_DESCRIPTION *Description;\r
584 EFI_BLOCK_IO_PROTOCOL *BlockIo;\r
585 UINT8 *EmptyBuffer;\r
586\r
587 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);\r
588 if (File == NULL) {\r
589 return EFI_DEVICE_ERROR;\r
590 }\r
591\r
592 Status = EFI_SUCCESS;\r
593\r
594 if (BootMonFsFileNeedFlush (File)) {\r
595 // Free the entries from the Buffer List\r
596 RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);\r
597 do {\r
598 Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;\r
599\r
600 // Get Next entry\r
601 RegionToFlushLink = RemoveEntryList (RegionToFlushLink);\r
602\r
603 // Free the buffers\r
604 FreePool (Region->Buffer);\r
605 FreePool (Region);\r
606 } while (!IsListEmpty (&File->RegionToFlushLink));\r
607 }\r
608\r
609 // If (RegionCount is greater than 0) then the file already exists\r
610 if (File->HwDescription.RegionCount > 0) {\r
611 Description = &File->HwDescription;\r
612 BlockIo = File->Instance->BlockIo;\r
613\r
614 // Create an empty buffer\r
615 EmptyBuffer = AllocateZeroPool (BlockIo->Media->BlockSize);\r
616 if (EmptyBuffer == NULL) {\r
617 FreePool (File);\r
618 return EFI_OUT_OF_RESOURCES;\r
619 }\r
620\r
621 // Invalidate the last Block\r
622 Status = BlockIo->WriteBlocks (BlockIo, BlockIo->Media->MediaId, Description->BlockEnd, BlockIo->Media->BlockSize, EmptyBuffer);\r
623 ASSERT_EFI_ERROR (Status);\r
624\r
625 FreePool (EmptyBuffer);\r
626 }\r
627\r
628 // Remove the entry from the list\r
629 RemoveEntryList (&File->Link);\r
630 FreePool (File);\r
631 return Status;\r
632}\r
633\r