mirror of https://github.com/acidanthera/audk.git
629 lines
19 KiB
C
629 lines
19 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"
|
||
|
|
||
|
// Clear a file's image description on storage media:
|
||
|
// UEFI allows you to seek past the end of a file, a subsequent write will grow
|
||
|
// the file. It does not specify how space between the former end of the file
|
||
|
// and the beginning of the write should be filled. It's therefore possible that
|
||
|
// BootMonFs metadata, that comes after the end of a file, could be left there
|
||
|
// and wrongly detected by BootMonFsImageInBlock.
|
||
|
STATIC
|
||
|
EFI_STATUS
|
||
|
InvalidateImageDescription (
|
||
|
IN BOOTMON_FS_FILE *File
|
||
|
)
|
||
|
{
|
||
|
EFI_DISK_IO_PROTOCOL *DiskIo;
|
||
|
EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
||
|
UINT32 MediaId;
|
||
|
UINT32 BlockSize;
|
||
|
VOID *Buffer;
|
||
|
EFI_STATUS Status;
|
||
|
UINT64 DescriptionAddress;
|
||
|
|
||
|
DiskIo = File->Instance->DiskIo;
|
||
|
BlockIo = File->Instance->BlockIo;
|
||
|
MediaId = BlockIo->Media->MediaId;
|
||
|
BlockSize = BlockIo->Media->BlockSize;
|
||
|
|
||
|
DescriptionAddress = (File->HwDescription.BlockEnd * BlockSize)
|
||
|
- sizeof (HW_IMAGE_DESCRIPTION);
|
||
|
|
||
|
Buffer = AllocateZeroPool (sizeof (HW_IMAGE_DESCRIPTION));
|
||
|
|
||
|
Status = DiskIo->WriteDisk (DiskIo,
|
||
|
MediaId,
|
||
|
DescriptionAddress,
|
||
|
sizeof (HW_IMAGE_DESCRIPTION),
|
||
|
Buffer
|
||
|
);
|
||
|
|
||
|
FreePool(Buffer);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
// Flush file data that will extend the file's length. Update and, if necessary,
|
||
|
// move the image description.
|
||
|
// We need to pass the file's starting position on media (FileStart), because
|
||
|
// if the file hasn't been flushed before its Description->BlockStart won't
|
||
|
// have been initialised.
|
||
|
// FileStart must be aligned to the media's block size.
|
||
|
// Note that this function uses DiskIo to flush, so call BlockIo->FlushBlocks()
|
||
|
// after calling it.
|
||
|
STATIC
|
||
|
EFI_STATUS
|
||
|
FlushAppendRegion (
|
||
|
IN BOOTMON_FS_FILE *File,
|
||
|
IN BOOTMON_FS_FILE_REGION *Region,
|
||
|
IN UINT64 NewFileSize,
|
||
|
IN UINT64 FileStart
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
EFI_DISK_IO_PROTOCOL *DiskIo;
|
||
|
UINTN BlockSize;
|
||
|
HW_IMAGE_DESCRIPTION *Description;
|
||
|
|
||
|
DiskIo = File->Instance->DiskIo;
|
||
|
|
||
|
BlockSize = File->Instance->BlockIo->Media->BlockSize;
|
||
|
|
||
|
ASSERT (FileStart % BlockSize == 0);
|
||
|
|
||
|
// Only invalidate the Image Description of files that have already been
|
||
|
// written in Flash
|
||
|
if (File->HwDescription.RegionCount > 0) {
|
||
|
Status = InvalidateImageDescription (File);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Update File Description
|
||
|
//
|
||
|
Description = &File->HwDescription;
|
||
|
Description->Attributes = 1;
|
||
|
Description->BlockStart = FileStart / BlockSize;
|
||
|
Description->BlockEnd = Description->BlockStart + (NewFileSize / BlockSize);
|
||
|
Description->Footer.FooterSignature1 = HW_IMAGE_FOOTER_SIGNATURE_1;
|
||
|
Description->Footer.FooterSignature2 = HW_IMAGE_FOOTER_SIGNATURE_2;
|
||
|
Description->Footer.Version = HW_IMAGE_FOOTER_VERSION;
|
||
|
Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET;
|
||
|
Description->RegionCount = 1;
|
||
|
Description->Region[0].Checksum = 0;
|
||
|
Description->Region[0].Offset = Description->BlockStart * BlockSize;
|
||
|
Description->Region[0].Size = NewFileSize - sizeof (HW_IMAGE_DESCRIPTION);
|
||
|
|
||
|
Status = BootMonFsComputeFooterChecksum (Description);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
// Write the new file data
|
||
|
Status = DiskIo->WriteDisk (
|
||
|
DiskIo,
|
||
|
File->Instance->Media->MediaId,
|
||
|
FileStart + Region->Offset,
|
||
|
Region->Size,
|
||
|
Region->Buffer
|
||
|
);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
|
||
|
// Round the file size up to the nearest block size
|
||
|
if ((NewFileSize % BlockSize) > 0) {
|
||
|
NewFileSize += BlockSize - (NewFileSize % BlockSize);
|
||
|
}
|
||
|
// Update the file description on the media
|
||
|
Status = DiskIo->WriteDisk (
|
||
|
DiskIo,
|
||
|
File->Instance->Media->MediaId,
|
||
|
(FileStart + NewFileSize) - sizeof (HW_IMAGE_DESCRIPTION),
|
||
|
sizeof (HW_IMAGE_DESCRIPTION),
|
||
|
Description
|
||
|
);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
BootMonFsFileNeedFlush (
|
||
|
IN BOOTMON_FS_FILE *File
|
||
|
)
|
||
|
{
|
||
|
return !IsListEmpty (&File->RegionToFlushLink);
|
||
|
}
|
||
|
|
||
|
// Find a space on media for a file that has not yet been flushed to disk.
|
||
|
// Just returns the first space that's big enough.
|
||
|
// This function could easily be adapted to:
|
||
|
// - Find space for moving an existing file that has outgrown its space
|
||
|
// (We do not currently move files, just return EFI_VOLUME_FULL)
|
||
|
// - Find space for a fragment of a file that has outgrown its space
|
||
|
// (We do not currently fragment files - it's not clear whether fragmentation
|
||
|
// is actually part of BootMonFs as there is no spec)
|
||
|
// - Be more clever about finding space (choosing the largest or smallest
|
||
|
// suitable space)
|
||
|
// Parameters:
|
||
|
// File - the new (not yet flushed) file for which we need to find space.
|
||
|
// FileStart - the position on media of the file (in bytes).
|
||
|
STATIC
|
||
|
EFI_STATUS
|
||
|
BootMonFsFindSpaceForNewFile (
|
||
|
IN BOOTMON_FS_FILE *File,
|
||
|
OUT UINT64 *FileStart
|
||
|
)
|
||
|
{
|
||
|
LIST_ENTRY *FileLink;
|
||
|
BOOTMON_FS_FILE *RootFile;
|
||
|
BOOTMON_FS_FILE *FileEntry;
|
||
|
UINTN BlockSize;
|
||
|
UINT64 FileSize;
|
||
|
EFI_BLOCK_IO_MEDIA *Media;
|
||
|
|
||
|
Media = File->Instance->BlockIo->Media;
|
||
|
BlockSize = Media->BlockSize;
|
||
|
RootFile = File->Instance->RootFile;
|
||
|
|
||
|
if (IsListEmpty (&RootFile->Link)) {
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
// This function must only be called for file which has not been flushed into
|
||
|
// Flash yet
|
||
|
ASSERT (File->HwDescription.RegionCount == 0);
|
||
|
|
||
|
// Find out how big the file will be
|
||
|
FileSize = BootMonFsGetImageLength (File);
|
||
|
// Add the file header to the file
|
||
|
FileSize += sizeof (HW_IMAGE_DESCRIPTION);
|
||
|
|
||
|
*FileStart = 0;
|
||
|
// Go through all the files in the list
|
||
|
for (FileLink = GetFirstNode (&RootFile->Link);
|
||
|
!IsNull (&RootFile->Link, FileLink);
|
||
|
FileLink = GetNextNode (&RootFile->Link, FileLink)
|
||
|
)
|
||
|
{
|
||
|
FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink);
|
||
|
// If the free space preceding the file is big enough to contain the new
|
||
|
// file then use it!
|
||
|
if (((FileEntry->HwDescription.BlockStart * BlockSize) - *FileStart)
|
||
|
>= FileSize) {
|
||
|
// The file list must be in disk-order
|
||
|
RemoveEntryList (&File->Link);
|
||
|
File->Link.BackLink = FileLink->BackLink;
|
||
|
File->Link.ForwardLink = FileLink;
|
||
|
FileLink->BackLink->ForwardLink = &File->Link;
|
||
|
FileLink->BackLink = &File->Link;
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
} else {
|
||
|
*FileStart = (FileEntry->HwDescription.BlockEnd + 1) * BlockSize;
|
||
|
}
|
||
|
}
|
||
|
// See if there's space after the last file
|
||
|
if ((((Media->LastBlock + 1) * BlockSize) - *FileStart) >= FileSize) {
|
||
|
return EFI_SUCCESS;
|
||
|
} else {
|
||
|
return EFI_VOLUME_FULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Free the resources in the file's Region list.
|
||
|
STATIC
|
||
|
VOID
|
||
|
FreeFileRegions (
|
||
|
IN BOOTMON_FS_FILE *File
|
||
|
)
|
||
|
{
|
||
|
LIST_ENTRY *RegionToFlushLink;
|
||
|
BOOTMON_FS_FILE_REGION *Region;
|
||
|
|
||
|
RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);
|
||
|
while (!IsNull (&File->RegionToFlushLink, RegionToFlushLink)) {
|
||
|
// Repeatedly remove the first node from the list and free its resources.
|
||
|
Region = (BOOTMON_FS_FILE_REGION *) RegionToFlushLink;
|
||
|
RemoveEntryList (RegionToFlushLink);
|
||
|
FreePool (Region->Buffer);
|
||
|
FreePool (Region);
|
||
|
|
||
|
RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
EFIAPI
|
||
|
EFI_STATUS
|
||
|
BootMonFsFlushFile (
|
||
|
IN EFI_FILE_PROTOCOL *This
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
BOOTMON_FS_INSTANCE *Instance;
|
||
|
LIST_ENTRY *RegionToFlushLink;
|
||
|
BOOTMON_FS_FILE *File;
|
||
|
BOOTMON_FS_FILE *NextFile;
|
||
|
BOOTMON_FS_FILE_REGION *Region;
|
||
|
LIST_ENTRY *FileLink;
|
||
|
UINTN CurrentPhysicalSize;
|
||
|
UINTN BlockSize;
|
||
|
UINT64 FileStart;
|
||
|
UINT64 FileEnd;
|
||
|
UINT64 RegionStart;
|
||
|
UINT64 RegionEnd;
|
||
|
UINT64 NewFileSize;
|
||
|
UINT64 EndOfAppendSpace;
|
||
|
BOOLEAN HasSpace;
|
||
|
EFI_DISK_IO_PROTOCOL *DiskIo;
|
||
|
EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
||
|
|
||
|
Status = EFI_SUCCESS;
|
||
|
FileStart = 0;
|
||
|
|
||
|
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
|
||
|
if (File == NULL) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
// Check if the file needs to be flushed
|
||
|
if (!BootMonFsFileNeedFlush (File)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
Instance = File->Instance;
|
||
|
BlockIo = Instance->BlockIo;
|
||
|
DiskIo = Instance->DiskIo;
|
||
|
BlockSize = BlockIo->Media->BlockSize;
|
||
|
|
||
|
// If the file doesn't exist then find a space for it
|
||
|
if (File->HwDescription.RegionCount == 0) {
|
||
|
Status = BootMonFsFindSpaceForNewFile (File, &FileStart);
|
||
|
// FileStart has changed so we need to recompute RegionEnd
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
} else {
|
||
|
FileStart = File->HwDescription.BlockStart * BlockSize;
|
||
|
}
|
||
|
|
||
|
// FileEnd is the NOR address of the end of the file's data
|
||
|
FileEnd = FileStart + BootMonFsGetImageLength (File);
|
||
|
|
||
|
for (RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);
|
||
|
!IsNull (&File->RegionToFlushLink, RegionToFlushLink);
|
||
|
RegionToFlushLink = GetNextNode (&File->RegionToFlushLink, RegionToFlushLink)
|
||
|
)
|
||
|
{
|
||
|
Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;
|
||
|
|
||
|
// RegionStart and RegionEnd are the the intended NOR address of the
|
||
|
// start and end of the region
|
||
|
RegionStart = FileStart + Region->Offset;
|
||
|
RegionEnd = RegionStart + Region->Size;
|
||
|
|
||
|
if (RegionEnd < FileEnd) {
|
||
|
// Handle regions representing edits to existing portions of the file
|
||
|
// Write the region data straight into the file
|
||
|
Status = DiskIo->WriteDisk (DiskIo,
|
||
|
BlockIo->Media->MediaId,
|
||
|
RegionStart,
|
||
|
Region->Size,
|
||
|
Region->Buffer
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
} else {
|
||
|
// Handle regions representing appends to the file
|
||
|
//
|
||
|
// Note: Since seeking past the end of the file with SetPosition() is
|
||
|
// valid, it's possible there will be a gap between the current end of
|
||
|
// the file and the beginning of the new region. Since the UEFI spec
|
||
|
// says nothing about this case (except "a subsequent write would grow
|
||
|
// the file"), we just leave garbage in the gap.
|
||
|
|
||
|
// Check if there is space to append the new region
|
||
|
HasSpace = FALSE;
|
||
|
NewFileSize = (RegionEnd - FileStart) + sizeof (HW_IMAGE_DESCRIPTION);
|
||
|
CurrentPhysicalSize = BootMonFsGetPhysicalSize (File);
|
||
|
if (NewFileSize <= CurrentPhysicalSize) {
|
||
|
HasSpace = TRUE;
|
||
|
} else {
|
||
|
// Get the File Description for the next file
|
||
|
FileLink = GetNextNode (&Instance->RootFile->Link, &File->Link);
|
||
|
if (!IsNull (&Instance->RootFile->Link, FileLink)) {
|
||
|
NextFile = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink);
|
||
|
|
||
|
// If there is space between the beginning of the current file and the
|
||
|
// beginning of the next file then use it
|
||
|
EndOfAppendSpace = NextFile->HwDescription.BlockStart * BlockSize;
|
||
|
} else {
|
||
|
// We are flushing the last file.
|
||
|
EndOfAppendSpace = (BlockIo->Media->LastBlock + 1) * BlockSize;
|
||
|
}
|
||
|
if (EndOfAppendSpace - FileStart >= NewFileSize) {
|
||
|
HasSpace = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (HasSpace == TRUE) {
|
||
|
Status = FlushAppendRegion (File, Region, NewFileSize, FileStart);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
} else {
|
||
|
// There isn't a space for the file.
|
||
|
// Options here are to move the file or fragment it. However as files
|
||
|
// may represent boot images at fixed positions, these options will
|
||
|
// break booting if the bootloader doesn't use BootMonFs to find the
|
||
|
// image.
|
||
|
|
||
|
return EFI_VOLUME_FULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FreeFileRegions (File);
|
||
|
|
||
|
// Flush DiskIo Buffers (see UEFI Spec 12.7 - DiskIo buffers are flushed by
|
||
|
// calling FlushBlocks on the same device's BlockIo).
|
||
|
BlockIo->FlushBlocks (BlockIo);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Closes a file on the Nor Flash FS volume.
|
||
|
|
||
|
@param This The EFI_FILE_PROTOCOL to close.
|
||
|
|
||
|
@return Always returns EFI_SUCCESS.
|
||
|
|
||
|
**/
|
||
|
EFIAPI
|
||
|
EFI_STATUS
|
||
|
BootMonFsCloseFile (
|
||
|
IN EFI_FILE_PROTOCOL *This
|
||
|
)
|
||
|
{
|
||
|
// Flush the file if needed
|
||
|
This->Flush (This);
|
||
|
return EFI_SUCCESS;
|
||
|
}
|
||
|
|
||
|
// Create a new instance of BOOTMON_FS_FILE.
|
||
|
// Uses BootMonFsCreateFile to
|
||
|
STATIC
|
||
|
EFI_STATUS
|
||
|
CreateNewFile (
|
||
|
IN BOOTMON_FS_INSTANCE *Instance,
|
||
|
IN CHAR8* AsciiFileName,
|
||
|
OUT BOOTMON_FS_FILE **NewHandle
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
BOOTMON_FS_FILE *File;
|
||
|
|
||
|
Status = BootMonFsCreateFile (Instance, &File);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
// Remove the leading '\\'
|
||
|
if (*AsciiFileName == '\\') {
|
||
|
AsciiFileName++;
|
||
|
}
|
||
|
|
||
|
// Set the file name
|
||
|
CopyMem (File->HwDescription.Footer.Filename, AsciiFileName, MAX_NAME_LENGTH);
|
||
|
|
||
|
// Add the file to list of files of the File System
|
||
|
InsertHeadList (&Instance->RootFile->Link, &File->Link);
|
||
|
|
||
|
*NewHandle = File;
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Opens a file on the Nor Flash FS volume
|
||
|
|
||
|
Calls BootMonFsGetFileFromAsciiFilename to search the list of tracked files.
|
||
|
|
||
|
@param This The EFI_FILE_PROTOCOL parent handle.
|
||
|
@param NewHandle Double-pointer to the newly created protocol.
|
||
|
@param FileName The name of the image/metadata on flash
|
||
|
@param OpenMode Read,write,append etc
|
||
|
@param Attributes ?
|
||
|
|
||
|
@return EFI_STATUS
|
||
|
OUT_OF_RESOURCES
|
||
|
Run out of space to keep track of the allocated structures
|
||
|
DEVICE_ERROR
|
||
|
Unable to locate the volume associated with the parent file handle
|
||
|
NOT_FOUND
|
||
|
Filename wasn't found on flash
|
||
|
SUCCESS
|
||
|
|
||
|
**/
|
||
|
EFIAPI
|
||
|
EFI_STATUS
|
||
|
BootMonFsOpenFile (
|
||
|
IN EFI_FILE_PROTOCOL *This,
|
||
|
OUT EFI_FILE_PROTOCOL **NewHandle,
|
||
|
IN CHAR16 *FileName,
|
||
|
IN UINT64 OpenMode,
|
||
|
IN UINT64 Attributes
|
||
|
)
|
||
|
{
|
||
|
BOOTMON_FS_FILE *Directory;
|
||
|
BOOTMON_FS_FILE *File;
|
||
|
BOOTMON_FS_INSTANCE *Instance;
|
||
|
CHAR8* AsciiFileName;
|
||
|
EFI_STATUS Status;
|
||
|
|
||
|
if ((FileName == NULL) || (NewHandle == NULL)) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
// The only valid modes are read, read/write, and read/write/create
|
||
|
if (!(OpenMode & EFI_FILE_MODE_READ) || ((OpenMode & EFI_FILE_MODE_CREATE) && !(OpenMode & EFI_FILE_MODE_WRITE))) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
Directory = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
|
||
|
if (Directory == NULL) {
|
||
|
return EFI_DEVICE_ERROR;
|
||
|
}
|
||
|
|
||
|
Instance = Directory->Instance;
|
||
|
|
||
|
// If the instance has not been initialized it yet then do it ...
|
||
|
if (!Instance->Initialized) {
|
||
|
Status = BootMonFsInitialize (Instance);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// BootMonFs interface requires ASCII filenames
|
||
|
AsciiFileName = AllocatePool ((StrLen (FileName) + 1) * sizeof (CHAR8));
|
||
|
if (AsciiFileName == NULL) {
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
UnicodeStrToAsciiStr (FileName, AsciiFileName);
|
||
|
|
||
|
if ((AsciiStrCmp (AsciiFileName, "\\") == 0) ||
|
||
|
(AsciiStrCmp (AsciiFileName, "/") == 0) ||
|
||
|
(AsciiStrCmp (AsciiFileName, "") == 0) ||
|
||
|
(AsciiStrCmp (AsciiFileName, ".") == 0))
|
||
|
{
|
||
|
//
|
||
|
// Opening '/', '\', '.', or the NULL pathname is trying to open the root directory
|
||
|
//
|
||
|
|
||
|
*NewHandle = &Instance->RootFile->File;
|
||
|
Instance->RootFile->Position = 0;
|
||
|
Status = EFI_SUCCESS;
|
||
|
} else {
|
||
|
//
|
||
|
// Open or Create a regular file
|
||
|
//
|
||
|
|
||
|
// Check if the file already exists
|
||
|
Status = BootMonGetFileFromAsciiFileName (Instance, AsciiFileName, &File);
|
||
|
if (Status == EFI_NOT_FOUND) {
|
||
|
// The file doesn't exist.
|
||
|
if (OpenMode & EFI_FILE_MODE_CREATE) {
|
||
|
// If the file does not exist but is required then create it.
|
||
|
if (Attributes & EFI_FILE_DIRECTORY) {
|
||
|
// BootMonFS doesn't support subdirectories
|
||
|
Status = EFI_UNSUPPORTED;
|
||
|
} else {
|
||
|
// Create a new file
|
||
|
Status = CreateNewFile (Instance, AsciiFileName, &File);
|
||
|
if (!EFI_ERROR (Status)) {
|
||
|
File->OpenMode = OpenMode;
|
||
|
*NewHandle = &File->File;
|
||
|
File->Position = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else if (Status == EFI_SUCCESS) {
|
||
|
// The file exists
|
||
|
File->OpenMode = OpenMode;
|
||
|
*NewHandle = &File->File;
|
||
|
File->Position = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FreePool (AsciiFileName);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
// Delete() for the root directory's EFI_FILE_PROTOCOL instance
|
||
|
EFIAPI
|
||
|
EFI_STATUS
|
||
|
BootMonFsDeleteFail (
|
||
|
IN EFI_FILE_PROTOCOL *This
|
||
|
)
|
||
|
{
|
||
|
This->Close(This);
|
||
|
// You can't delete the root directory
|
||
|
return EFI_WARN_DELETE_FAILURE;
|
||
|
}
|
||
|
EFIAPI
|
||
|
EFI_STATUS
|
||
|
BootMonFsDelete (
|
||
|
IN EFI_FILE_PROTOCOL *This
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
BOOTMON_FS_FILE *File;
|
||
|
LIST_ENTRY *RegionToFlushLink;
|
||
|
BOOTMON_FS_FILE_REGION *Region;
|
||
|
HW_IMAGE_DESCRIPTION *Description;
|
||
|
EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
||
|
UINT8 *EmptyBuffer;
|
||
|
|
||
|
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
|
||
|
if (File == NULL) {
|
||
|
return EFI_DEVICE_ERROR;
|
||
|
}
|
||
|
|
||
|
Status = EFI_SUCCESS;
|
||
|
|
||
|
if (BootMonFsFileNeedFlush (File)) {
|
||
|
// Free the entries from the Buffer List
|
||
|
RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);
|
||
|
do {
|
||
|
Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;
|
||
|
|
||
|
// Get Next entry
|
||
|
RegionToFlushLink = RemoveEntryList (RegionToFlushLink);
|
||
|
|
||
|
// Free the buffers
|
||
|
FreePool (Region->Buffer);
|
||
|
FreePool (Region);
|
||
|
} while (!IsListEmpty (&File->RegionToFlushLink));
|
||
|
}
|
||
|
|
||
|
// If (RegionCount is greater than 0) then the file already exists
|
||
|
if (File->HwDescription.RegionCount > 0) {
|
||
|
Description = &File->HwDescription;
|
||
|
BlockIo = File->Instance->BlockIo;
|
||
|
|
||
|
// Create an empty buffer
|
||
|
EmptyBuffer = AllocateZeroPool (BlockIo->Media->BlockSize);
|
||
|
if (EmptyBuffer == NULL) {
|
||
|
FreePool (File);
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
|
||
|
// Invalidate the last Block
|
||
|
Status = BlockIo->WriteBlocks (BlockIo, BlockIo->Media->MediaId, Description->BlockEnd, BlockIo->Media->BlockSize, EmptyBuffer);
|
||
|
ASSERT_EFI_ERROR (Status);
|
||
|
|
||
|
FreePool (EmptyBuffer);
|
||
|
}
|
||
|
|
||
|
// Remove the entry from the list
|
||
|
RemoveEntryList (&File->Link);
|
||
|
FreePool (File);
|
||
|
return Status;
|
||
|
}
|
||
|
|