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