mirror of https://github.com/acidanthera/audk.git
638 lines
17 KiB
C
638 lines
17 KiB
C
/** @file
|
|
*
|
|
* Copyright (c) 2012-2014, ARM Limited. All rights reserved.
|
|
*
|
|
* This program and the accompanying materials
|
|
* are licensed and made available under the terms and conditions of the BSD License
|
|
* which accompanies this distribution. The full text of the license may be found at
|
|
* http://opensource.org/licenses/bsd-license.php
|
|
*
|
|
* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
*
|
|
**/
|
|
|
|
#include "BootMonFsInternal.h"
|
|
|
|
EFIAPI
|
|
EFI_STATUS
|
|
OpenBootMonFsOpenVolume (
|
|
IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
|
|
OUT EFI_FILE_PROTOCOL **Root
|
|
)
|
|
{
|
|
BOOTMON_FS_INSTANCE *Instance;
|
|
|
|
Instance = BOOTMON_FS_FROM_FS_THIS (This);
|
|
if (Instance == NULL) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
*Root = &Instance->RootFile->File;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
UINT32
|
|
BootMonFsGetImageLength (
|
|
IN BOOTMON_FS_FILE *File
|
|
)
|
|
{
|
|
UINT32 Index;
|
|
UINT32 FileSize;
|
|
LIST_ENTRY *RegionToFlushLink;
|
|
BOOTMON_FS_FILE_REGION *Region;
|
|
|
|
FileSize = 0;
|
|
|
|
// Look at all Flash areas to determine file size
|
|
for (Index = 0; Index < HW_IMAGE_DESCRIPTION_REGION_MAX; Index++) {
|
|
FileSize += File->HwDescription.Region[Index].Size;
|
|
}
|
|
|
|
// Add the regions that have not been flushed yet
|
|
for (RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);
|
|
!IsNull (&File->RegionToFlushLink, RegionToFlushLink);
|
|
RegionToFlushLink = GetNextNode (&File->RegionToFlushLink, RegionToFlushLink)
|
|
)
|
|
{
|
|
Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;
|
|
if (Region->Offset + Region->Size > FileSize) {
|
|
FileSize += Region->Offset + Region->Size;
|
|
}
|
|
}
|
|
|
|
return FileSize;
|
|
}
|
|
|
|
UINTN
|
|
BootMonFsGetPhysicalSize (
|
|
IN BOOTMON_FS_FILE* File
|
|
)
|
|
{
|
|
// Return 0 for files that haven't yet been flushed to media
|
|
if (File->HwDescription.RegionCount == 0) {
|
|
return 0;
|
|
}
|
|
|
|
return ((File->HwDescription.BlockEnd - File->HwDescription.BlockStart) + 1 )
|
|
* File->Instance->Media->BlockSize;
|
|
}
|
|
|
|
EFIAPI
|
|
EFI_STATUS
|
|
BootMonFsSetDirPosition (
|
|
IN EFI_FILE_PROTOCOL *This,
|
|
IN UINT64 Position
|
|
)
|
|
{
|
|
BOOTMON_FS_FILE *File;
|
|
|
|
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
|
|
if (File == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
// UEFI Spec section 12.5:
|
|
// "The seek request for nonzero is not valid on open directories."
|
|
if (Position != 0) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
File->Position = Position;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
BootMonFsOpenDirectory (
|
|
OUT EFI_FILE_PROTOCOL **NewHandle,
|
|
IN CHAR16 *FileName,
|
|
IN BOOTMON_FS_INSTANCE *Volume
|
|
)
|
|
{
|
|
ASSERT(0);
|
|
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
EFI_STATUS
|
|
GetFileSystemVolumeLabelInfo (
|
|
IN BOOTMON_FS_INSTANCE *Instance,
|
|
IN OUT UINTN *BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
{
|
|
UINTN Size;
|
|
EFI_FILE_SYSTEM_VOLUME_LABEL *Label;
|
|
EFI_STATUS Status;
|
|
|
|
Label = Buffer;
|
|
|
|
// Value returned by StrSize includes null terminator.
|
|
Size = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL
|
|
+ StrSize (Instance->FsInfo.VolumeLabel);
|
|
|
|
if (*BufferSize >= Size) {
|
|
CopyMem (&Label->VolumeLabel, &Instance->FsInfo.VolumeLabel, Size);
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
Status = EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
*BufferSize = Size;
|
|
return Status;
|
|
}
|
|
|
|
// Helper function that calculates a rough "free space" by:
|
|
// - Taking the media size
|
|
// - Subtracting the sum of all file sizes
|
|
// - Subtracting the block size times the number of files
|
|
// (To account for the blocks containing the HW_IMAGE_INFO
|
|
STATIC
|
|
UINT64
|
|
ComputeFreeSpace (
|
|
IN BOOTMON_FS_INSTANCE *Instance
|
|
)
|
|
{
|
|
LIST_ENTRY *FileLink;
|
|
UINT64 FileSizeSum;
|
|
UINT64 MediaSize;
|
|
UINTN NumFiles;
|
|
EFI_BLOCK_IO_MEDIA *Media;
|
|
BOOTMON_FS_FILE *File;
|
|
|
|
Media = Instance->BlockIo->Media;
|
|
MediaSize = Media->BlockSize * (Media->LastBlock + 1);
|
|
|
|
NumFiles = 0;
|
|
FileSizeSum = 0;
|
|
for (FileLink = GetFirstNode (&Instance->RootFile->Link);
|
|
!IsNull (&Instance->RootFile->Link, FileLink);
|
|
FileLink = GetNextNode (&Instance->RootFile->Link, FileLink)
|
|
)
|
|
{
|
|
File = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink);
|
|
FileSizeSum += BootMonFsGetImageLength (File);
|
|
|
|
NumFiles++;
|
|
}
|
|
|
|
return MediaSize - (FileSizeSum + (Media->BlockSize + NumFiles));
|
|
}
|
|
|
|
EFI_STATUS
|
|
GetFilesystemInfo (
|
|
IN BOOTMON_FS_INSTANCE *Instance,
|
|
IN OUT UINTN *BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
if (*BufferSize >= Instance->FsInfo.Size) {
|
|
Instance->FsInfo.FreeSpace = ComputeFreeSpace (Instance);
|
|
CopyMem (Buffer, &Instance->FsInfo, Instance->FsInfo.Size);
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
Status = EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
*BufferSize = Instance->FsInfo.Size;
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
GetFileInfo (
|
|
IN BOOTMON_FS_INSTANCE *Instance,
|
|
IN BOOTMON_FS_FILE *File,
|
|
IN OUT UINTN *BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
{
|
|
EFI_FILE_INFO *Info;
|
|
UINTN ResultSize;
|
|
UINTN NameSize;
|
|
UINTN Index;
|
|
|
|
if (File == Instance->RootFile) {
|
|
NameSize = 0;
|
|
ResultSize = SIZE_OF_EFI_FILE_INFO + sizeof (CHAR16);
|
|
} else {
|
|
NameSize = AsciiStrLen (File->HwDescription.Footer.Filename) + 1;
|
|
ResultSize = SIZE_OF_EFI_FILE_INFO + (NameSize * sizeof (CHAR16));
|
|
}
|
|
|
|
if (*BufferSize < ResultSize) {
|
|
*BufferSize = ResultSize;
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
Info = Buffer;
|
|
|
|
// Zero out the structure
|
|
ZeroMem (Info, ResultSize);
|
|
|
|
// Fill in the structure
|
|
Info->Size = ResultSize;
|
|
|
|
if (File == Instance->RootFile) {
|
|
Info->Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;
|
|
Info->FileName[0] = L'\0';
|
|
} else {
|
|
Info->FileSize = BootMonFsGetImageLength (File);
|
|
Info->PhysicalSize = BootMonFsGetPhysicalSize (File);
|
|
|
|
for (Index = 0; Index < NameSize; Index++) {
|
|
Info->FileName[Index] = File->HwDescription.Footer.Filename[Index];
|
|
}
|
|
}
|
|
|
|
*BufferSize = ResultSize;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
GetBootMonFsFileInfo (
|
|
IN BOOTMON_FS_INSTANCE *Instance,
|
|
IN BOOTMON_FS_FILE *File,
|
|
IN OUT UINTN *BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
BOOTMON_FS_FILE_INFO *Info;
|
|
UINTN ResultSize;
|
|
UINTN Index;
|
|
|
|
if (File == Instance->RootFile) {
|
|
Status = EFI_UNSUPPORTED;
|
|
} else {
|
|
ResultSize = SIZE_OF_BOOTMON_FS_FILE_INFO;
|
|
|
|
if (*BufferSize < ResultSize) {
|
|
*BufferSize = ResultSize;
|
|
Status = EFI_BUFFER_TOO_SMALL;
|
|
} else {
|
|
Info = Buffer;
|
|
|
|
// Zero out the structure
|
|
ZeroMem (Info, ResultSize);
|
|
|
|
// Fill in the structure
|
|
Info->Size = ResultSize;
|
|
|
|
Info->EntryPoint = File->HwDescription.EntryPoint;
|
|
Info->RegionCount = File->HwDescription.RegionCount;
|
|
for (Index = 0; Index < File->HwDescription.RegionCount; Index++) {
|
|
Info->Region[Index].LoadAddress = File->HwDescription.Region[Index].LoadAddress;
|
|
Info->Region[Index].Size = File->HwDescription.Region[Index].Size;
|
|
Info->Region[Index].Offset = File->HwDescription.Region[Index].Offset;
|
|
Info->Region[Index].Checksum = File->HwDescription.Region[Index].Checksum;
|
|
}
|
|
*BufferSize = ResultSize;
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
SetFileName (
|
|
IN BOOTMON_FS_FILE *File,
|
|
IN CHAR16 *FileNameUnicode
|
|
)
|
|
{
|
|
CHAR8 *FileNameAscii;
|
|
UINT16 SavedChar;
|
|
UINTN FileNameSize;
|
|
BOOTMON_FS_FILE *SameFile;
|
|
EFI_STATUS Status;
|
|
|
|
// EFI Shell inserts '\' in front of the filename that must be stripped
|
|
if (FileNameUnicode[0] == L'\\') {
|
|
FileNameUnicode++;
|
|
}
|
|
//
|
|
// Convert Unicode into Ascii
|
|
//
|
|
SavedChar = L'\0';
|
|
FileNameSize = StrLen (FileNameUnicode) + 1;
|
|
FileNameAscii = AllocatePool (FileNameSize * sizeof (CHAR8));
|
|
if (FileNameAscii == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
// If Unicode string is too long then truncate it.
|
|
if (FileNameSize > MAX_NAME_LENGTH) {
|
|
SavedChar = FileNameUnicode[MAX_NAME_LENGTH - 1];
|
|
FileNameUnicode[MAX_NAME_LENGTH - 1] = L'\0';
|
|
}
|
|
UnicodeStrToAsciiStr (FileNameUnicode, FileNameAscii);
|
|
// If the unicode string was truncated then restore its original content.
|
|
if (SavedChar != L'\0') {
|
|
FileNameUnicode[MAX_NAME_LENGTH - 1] = SavedChar;
|
|
}
|
|
|
|
// If we're changing the file name
|
|
if (AsciiStrCmp (FileNameAscii, File->HwDescription.Footer.Filename) == 0) {
|
|
// No change to filename.
|
|
Status = EFI_SUCCESS;
|
|
} else if (!(File->OpenMode & EFI_FILE_MODE_WRITE)) {
|
|
// You can only change the filename if you open the file for write.
|
|
Status = EFI_ACCESS_DENIED;
|
|
} else if (BootMonGetFileFromAsciiFileName (
|
|
File->Instance,
|
|
File->HwDescription.Footer.Filename,
|
|
&SameFile) != EFI_NOT_FOUND) {
|
|
// A file with that name already exists.
|
|
Status = EFI_ACCESS_DENIED;
|
|
} else {
|
|
// OK, change the filename.
|
|
AsciiStrCpy (FileNameAscii, File->HwDescription.Footer.Filename);
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
|
|
FreePool (FileNameAscii);
|
|
return Status;
|
|
}
|
|
|
|
// Set the file's size (NB "size", not "physical size"). If the change amounts
|
|
// to an increase, simply do a write followed by a flush.
|
|
// (This is a helper function for SetFileInfo.)
|
|
STATIC
|
|
EFI_STATUS
|
|
SetFileSize (
|
|
IN BOOTMON_FS_INSTANCE *Instance,
|
|
IN BOOTMON_FS_FILE *BootMonFsFile,
|
|
IN UINTN NewSize
|
|
)
|
|
{
|
|
UINT64 StoredPosition;
|
|
EFI_STATUS Status;
|
|
EFI_FILE_PROTOCOL *File;
|
|
CHAR8 Buffer;
|
|
UINTN BufferSize;
|
|
UINT32 OldSize;
|
|
|
|
OldSize = BootMonFsFile->HwDescription.Region[0].Size;
|
|
|
|
if (OldSize == NewSize) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
Buffer = 0;
|
|
BufferSize = sizeof (Buffer);
|
|
|
|
File = &BootMonFsFile->File;
|
|
|
|
if (!(BootMonFsFile->OpenMode & EFI_FILE_MODE_WRITE)) {
|
|
return EFI_ACCESS_DENIED;
|
|
}
|
|
|
|
if (NewSize <= OldSize) {
|
|
OldSize = NewSize;
|
|
} else {
|
|
// Increasing a file's size is potentially complicated as it may require
|
|
// moving the image description on media. The simplest way to do it is to
|
|
// seek past the end of the file (which is valid in UEFI) and perform a
|
|
// Write.
|
|
|
|
// Save position
|
|
Status = File->GetPosition (File, &StoredPosition);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = File->SetPosition (File, NewSize - 1);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
Status = File->Write (File, &BufferSize, &Buffer);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
// Restore saved position
|
|
Status = File->SetPosition (File, NewSize - 1);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = File->Flush (File);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
SetFileInfo (
|
|
IN BOOTMON_FS_INSTANCE *Instance,
|
|
IN BOOTMON_FS_FILE *File,
|
|
IN UINTN BufferSize,
|
|
IN EFI_FILE_INFO *Info
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
// Note that a call to this function on a file opened read-only is only
|
|
// invalid if it actually changes fields, so we don't immediately fail if the
|
|
// OpenMode is wrong.
|
|
// Also note that the only fields supported are filename and size, others are
|
|
// ignored.
|
|
|
|
if (File != Instance->RootFile) {
|
|
if (!(File->OpenMode & EFI_FILE_MODE_WRITE)) {
|
|
return EFI_ACCESS_DENIED;
|
|
}
|
|
|
|
Status = SetFileName (File, Info->FileName);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
// Update file size
|
|
Status = SetFileSize (Instance, File, Info->FileSize);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
EFIAPI
|
|
EFI_STATUS
|
|
BootMonFsGetInfo (
|
|
IN EFI_FILE_PROTOCOL *This,
|
|
IN EFI_GUID *InformationType,
|
|
IN OUT UINTN *BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
BOOTMON_FS_FILE *File;
|
|
BOOTMON_FS_INSTANCE *Instance;
|
|
|
|
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
|
|
if (File == NULL) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
Instance = File->Instance;
|
|
|
|
// If the instance has not been initialized yet then do it ...
|
|
if (!Instance->Initialized) {
|
|
Status = BootMonFsInitialize (Instance);
|
|
} else {
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)
|
|
!= 0) {
|
|
Status = GetFileSystemVolumeLabelInfo (Instance, BufferSize, Buffer);
|
|
} else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid) != 0) {
|
|
Status = GetFilesystemInfo (Instance, BufferSize, Buffer);
|
|
} else if (CompareGuid (InformationType, &gEfiFileInfoGuid) != 0) {
|
|
Status = GetFileInfo (Instance, File, BufferSize, Buffer);
|
|
} else if (CompareGuid (InformationType, &gArmBootMonFsFileInfoGuid) != 0) {
|
|
Status = GetBootMonFsFileInfo (Instance, File, BufferSize, Buffer);
|
|
} else {
|
|
Status = EFI_UNSUPPORTED;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFIAPI
|
|
EFI_STATUS
|
|
BootMonFsSetInfo (
|
|
IN EFI_FILE_PROTOCOL *This,
|
|
IN EFI_GUID *InformationType,
|
|
IN UINTN BufferSize,
|
|
IN VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
BOOTMON_FS_FILE *File;
|
|
BOOTMON_FS_INSTANCE *Instance;
|
|
|
|
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
|
|
if (File == NULL) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
Instance = File->Instance;
|
|
|
|
if (CompareGuid (InformationType, &gEfiFileInfoGuid) != 0) {
|
|
Status = SetFileInfo (Instance, File, BufferSize, (EFI_FILE_INFO *) Buffer);
|
|
} else {
|
|
// The only writable field in the other two information types
|
|
// (i.e. EFI_FILE_SYSTEM_INFO and EFI_FILE_SYSTEM_VOLUME_LABEL) is the
|
|
// filesystem volume label. This can be retrieved with GetInfo, but it is
|
|
// hard-coded into this driver, not stored on media.
|
|
Status = EFI_UNSUPPORTED;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFIAPI
|
|
EFI_STATUS
|
|
BootMonFsReadDirectory (
|
|
IN EFI_FILE_PROTOCOL *This,
|
|
IN OUT UINTN *BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
{
|
|
BOOTMON_FS_INSTANCE *Instance;
|
|
BOOTMON_FS_FILE *RootFile;
|
|
BOOTMON_FS_FILE *File;
|
|
EFI_FILE_INFO *Info;
|
|
UINTN NameSize;
|
|
UINTN ResultSize;
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
|
|
RootFile = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
|
|
if (RootFile == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Instance = RootFile->Instance;
|
|
Status = BootMonGetFileFromPosition (Instance, RootFile->Position, &File);
|
|
if (EFI_ERROR (Status)) {
|
|
// No more file
|
|
*BufferSize = 0;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
NameSize = AsciiStrLen (File->HwDescription.Footer.Filename) + 1;
|
|
ResultSize = SIZE_OF_EFI_FILE_INFO + (NameSize * sizeof (CHAR16));
|
|
if (*BufferSize < ResultSize) {
|
|
*BufferSize = ResultSize;
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
// Zero out the structure
|
|
Info = Buffer;
|
|
ZeroMem (Info, ResultSize);
|
|
|
|
// Fill in the structure
|
|
Info->Size = ResultSize;
|
|
Info->FileSize = BootMonFsGetImageLength (File);
|
|
Info->PhysicalSize = BootMonFsGetPhysicalSize (File);
|
|
for (Index = 0; Index < NameSize; Index++) {
|
|
Info->FileName[Index] = File->HwDescription.Footer.Filename[Index];
|
|
}
|
|
|
|
*BufferSize = ResultSize;
|
|
RootFile->Position++;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFIAPI
|
|
EFI_STATUS
|
|
BootMonFsFlushDirectory (
|
|
IN EFI_FILE_PROTOCOL *This
|
|
)
|
|
{
|
|
BOOTMON_FS_FILE *RootFile;
|
|
LIST_ENTRY *ListFiles;
|
|
LIST_ENTRY *Link;
|
|
BOOTMON_FS_FILE *File;
|
|
|
|
RootFile = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
|
|
if (RootFile == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ListFiles = &RootFile->Link;
|
|
|
|
if (IsListEmpty (ListFiles)) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Flush all the files that need to be flushed
|
|
//
|
|
|
|
// Go through all the list of files to flush them
|
|
for (Link = GetFirstNode (ListFiles);
|
|
!IsNull (ListFiles, Link);
|
|
Link = GetNextNode (ListFiles, Link)
|
|
)
|
|
{
|
|
File = BOOTMON_FS_FILE_FROM_LINK_THIS (Link);
|
|
File->File.Flush (&File->File);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|