summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsApi.h145
-rw-r--r--ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsDir.c429
-rw-r--r--ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsEntryPoint.c89
-rw-r--r--ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsInternal.h8
-rw-r--r--ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsOpenClose.c379
-rw-r--r--ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsReadWrite.c122
6 files changed, 818 insertions, 354 deletions
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsApi.h b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsApi.h
index affc510931..d690520a0f 100644
--- a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsApi.h
+++ b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsApi.h
@@ -79,12 +79,37 @@ BootMonFsFlushDirectory (
IN EFI_FILE_PROTOCOL *This
);
+/**
+ Flush all modified data associated with a file to a device.
+
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
+ file handle to flush.
+
+ @retval EFI_SUCCESS The data was flushed.
+ @retval EFI_ACCESS_DENIED The file was opened read-only.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_FULL The volume is full.
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to flush the data.
+ @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
+
+**/
EFIAPI
EFI_STATUS
BootMonFsFlushFile (
IN EFI_FILE_PROTOCOL *This
);
+/**
+ Close a specified file handle.
+
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
+ handle to close.
+
+ @retval EFI_SUCCESS The file was closed.
+ @retval EFI_INVALID_PARAMETER The parameter "This" is NULL or is not an open
+ file handle.
+
+**/
EFIAPI
EFI_STATUS
BootMonFsCloseFile (
@@ -94,7 +119,12 @@ BootMonFsCloseFile (
/**
Open a file on the boot monitor file system.
- @param[in] This The EFI_FILE_PROTOCOL parent handle.
+ The boot monitor file system does not allow for sub-directories. There is only
+ one directory, the root one. On any attempt to create a directory, the function
+ returns in error with the EFI_WRITE_PROTECTED error code.
+
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
+ the file handle to source location.
@param[out] NewHandle A pointer to the location to return the opened
handle for the new file.
@param[in] FileName The Null-terminated string of the name of the file
@@ -108,7 +138,7 @@ BootMonFsCloseFile (
directory in which to create a file could not be found.
@retval EFI_DEVICE_ERROR The device reported an error.
@retval EFI_WRITE_PROTECTED Attempt to create a directory. This is not possible
- with the BootMon file system.
+ with the Boot Monitor file system.
@retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.
@retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
@@ -139,6 +169,7 @@ BootMonFsOpenFile (
reported an error while performing the read
operation.
@retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
+
**/
EFIAPI
EFI_STATUS
@@ -162,6 +193,26 @@ BootMonFsGetPosition (
OUT UINT64 *Position
);
+/**
+ Write data to an open file.
+
+ The data is not written to the flash yet. It will be written when the file
+ will be either read, closed or flushed.
+
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
+ is the file handle to write data to.
+ @param[in out] BufferSize On input, the size of the Buffer. On output, the
+ size of the data actually written. In both cases,
+ the size is measured in bytes.
+ @param[in] Buffer The buffer of data to write.
+
+ @retval EFI_SUCCESS The data was written.
+ @retval EFI_ACCESS_DENIED The file was opened read only.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate the buffer to store the
+ data to write.
+ @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
+
+**/
EFIAPI
EFI_STATUS
BootMonFsWriteFile (
@@ -176,12 +227,35 @@ BootMonFsDeleteFail (
IN EFI_FILE_PROTOCOL *This
);
+/**
+ Close and delete a file from the boot monitor file system.
+
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
+ handle to delete.
+
+ @retval EFI_SUCCESS The file was closed and deleted.
+ @retval EFI_INVALID_PARAMETER The parameter "This" is NULL or is not an open
+ file handle.
+ @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not deleted.
+
+**/
EFIAPI
EFI_STATUS
BootMonFsDelete (
IN EFI_FILE_PROTOCOL *This
);
+/**
+ Set a file's current position.
+
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
+ the file handle to set the requested position on.
+ @param[in] Position The byte position from the start of the file to set.
+
+ @retval EFI_SUCCESS The position was set.
+ @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
+
+**/
EFIAPI
EFI_STATUS
BootMonFsSetPosition (
@@ -189,6 +263,17 @@ BootMonFsSetPosition (
IN UINT64 Position
);
+/**
+ Return a file's current position.
+
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
+ the file handle to get the current position on.
+ @param[out] Position The address to return the file's current position value.
+
+ @retval EFI_SUCCESS The position was returned.
+ @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
+
+**/
EFIAPI
EFI_STATUS
BootMonFsGetPosition(
@@ -207,6 +292,37 @@ BootMonFsGetPositionUnsupported (
OUT UINT64 *Position
);
+/**
+ Set information about a file or a volume.
+
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
+ is the file handle the information is for.
+ @param[in] InformationType The type identifier for the information being set :
+ EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or
+ EFI_FILE_SYSTEM_VOLUME_LABEL_ID
+ @param[in] BufferSize The size, in bytes, of Buffer.
+ @param[in] Buffer A pointer to the data buffer to write. The type of the
+ data inside the buffer is indicated by InformationType.
+
+ @retval EFI_SUCCESS The information was set.
+ @retval EFI_UNSUPPORTED The InformationType is not known.
+ @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
+ @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
+ to a file that is already present.
+ @retval EFI_ACCESS_DENIED An attempt is being made to change the
+ EFI_FILE_DIRECTORY Attribute.
+ @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and
+ the file was opened in read-only mode and an
+ attempt is being made to modify a field other
+ than Attribute.
+ @retval EFI_WRITE_PROTECTED An attempt is being made to modify a read-only
+ attribute.
+ @retval EFI_BAD_BUFFER_SIZE The size of the buffer is lower than that indicated by
+ the data inside the buffer.
+ @retval EFI_OUT_OF_RESOURCES A allocation needed to process the request failed.
+ @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
+
+**/
EFIAPI
EFI_STATUS
BootMonFsSetInfo (
@@ -230,6 +346,31 @@ BootMonFsOpenDirectory (
//
// Internal API
//
+
+/**
+ Search for a file given its name coded in Ascii.
+
+ When searching through the files of the volume, if a file is currently not
+ open, its name was written on the media and is kept in RAM in the
+ "HwDescription.Footer.Filename[]" field of the file's description.
+
+ If a file is currently open, its name might not have been written on the
+ media yet, and as the "HwDescription" is a mirror in RAM of what is on the
+ media the "HwDescription.Footer.Filename[]" might be outdated. In that case,
+ the up to date name of the file is stored in the "Info" field of the file's
+ description.
+
+ @param[in] Instance Pointer to the description of the volume in which
+ the file has to be search for.
+ @param[in] AsciiFileName Name of the file.
+
+ @param[out] File Pointer to the description of the file if the
+ file was found.
+
+ @retval EFI_SUCCESS The file was found.
+ @retval EFI_NOT_FOUND The file was not found.
+
+**/
EFI_STATUS
BootMonGetFileFromAsciiFileName (
IN BOOTMON_FS_INSTANCE *Instance,
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsDir.c b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsDir.c
index 835cdae18a..450a707f18 100644
--- a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsDir.c
+++ b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsDir.c
@@ -28,6 +28,8 @@ OpenBootMonFsOpenVolume (
return EFI_DEVICE_ERROR;
}
+ Instance->RootFile->Info->Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;
+
*Root = &Instance->RootFile->File;
return EFI_SUCCESS;
@@ -114,6 +116,8 @@ BootMonFsOpenDirectory (
return EFI_UNSUPPORTED;
}
+
+STATIC
EFI_STATUS
GetFileSystemVolumeLabelInfo (
IN BOOTMON_FS_INSTANCE *Instance,
@@ -178,6 +182,7 @@ ComputeFreeSpace (
return MediaSize - (FileSizeSum + (Media->BlockSize + NumFiles));
}
+STATIC
EFI_STATUS
GetFilesystemInfo (
IN BOOTMON_FS_INSTANCE *Instance,
@@ -199,26 +204,19 @@ GetFilesystemInfo (
return Status;
}
+STATIC
EFI_STATUS
GetFileInfo (
- IN BOOTMON_FS_INSTANCE *Instance,
- IN BOOTMON_FS_FILE *File,
- IN OUT UINTN *BufferSize,
- OUT VOID *Buffer
+ 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;
+ EFI_FILE_INFO *Info;
+ UINTN ResultSize;
- 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));
- }
+ ResultSize = SIZE_OF_EFI_FILE_INFO + StrSize (File->Info->FileName);
if (*BufferSize < ResultSize) {
*BufferSize = ResultSize;
@@ -227,24 +225,10 @@ GetFileInfo (
Info = Buffer;
- // Zero out the structure
- ZeroMem (Info, ResultSize);
-
- // Fill in the structure
+ CopyMem (Info, File->Info, ResultSize);
+ // Size of the information
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;
@@ -297,171 +281,253 @@ GetBootMonFsFileInfo (
return Status;
}
+/**
+ Set the name of a file.
+
+ This is a helper function for SetFileInfo().
+
+ @param[in] Instance A pointer to the description of the volume
+ the file belongs to.
+ @param[in] File A pointer to the description of the file.
+ @param[in] FileName A pointer to the new name of the file.
+
+ @retval EFI_SUCCESS The name was set.
+ @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
+ to a file that is already present.
+
+**/
STATIC
EFI_STATUS
SetFileName (
- IN BOOTMON_FS_FILE *File,
- IN CHAR16 *FileNameUnicode
+ IN BOOTMON_FS_INSTANCE *Instance,
+ IN BOOTMON_FS_FILE *File,
+ IN CONST CHAR16 *FileName
)
{
- CHAR8 *FileNameAscii;
- UINT16 SavedChar;
- UINTN FileNameSize;
- BOOTMON_FS_FILE *SameFile;
- EFI_STATUS Status;
+ CHAR16 TruncFileName[MAX_NAME_LENGTH];
+ CHAR8 AsciiFileName[MAX_NAME_LENGTH];
+ BOOTMON_FS_FILE *SameFile;
- // EFI Shell inserts '\' in front of the filename that must be stripped
- if (FileNameUnicode[0] == L'\\') {
- FileNameUnicode++;
+ // If the file path start with a \ strip it. The EFI Shell may
+ // insert a \ in front of the file name.
+ if (FileName[0] == L'\\') {
+ FileName++;
}
- //
- // 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) {
+
+ StrnCpy (TruncFileName, FileName, MAX_NAME_LENGTH - 1);
+ TruncFileName[MAX_NAME_LENGTH - 1] = 0;
+ UnicodeStrToAsciiStr (TruncFileName, AsciiFileName);
+
+ if (BootMonGetFileFromAsciiFileName (
+ File->Instance,
+ AsciiFileName,
+ &SameFile
+ ) != EFI_NOT_FOUND) {
// A file with that name already exists.
- Status = EFI_ACCESS_DENIED;
+ return EFI_ACCESS_DENIED;
} else {
// OK, change the filename.
- AsciiStrCpy (FileNameAscii, File->HwDescription.Footer.Filename);
- Status = EFI_SUCCESS;
+ AsciiStrToUnicodeStr (AsciiFileName, File->Info->FileName);
+ return 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.)
+/**
+ Set the size of a file.
+
+ This is a helper function for SetFileInfo().
+
+ @param[in] Instance A pointer to the description of the volume
+ the file belongs to.
+ @param[in] File A pointer to the description of the file.
+ @param[in] NewSize The requested new size for the file.
+
+ @retval EFI_SUCCESS The size was set.
+ @retval EFI_OUT_OF_RESOURCES An allocation needed to process the request failed.
+
+**/
STATIC
EFI_STATUS
SetFileSize (
- IN BOOTMON_FS_INSTANCE *Instance,
- IN BOOTMON_FS_FILE *BootMonFsFile,
- IN UINTN NewSize
+ 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);
+ EFI_STATUS Status;
+ UINT32 OldSize;
+ LIST_ENTRY *RegionToFlushLink;
+ LIST_ENTRY *NextRegionToFlushLink;
+ BOOTMON_FS_FILE_REGION *Region;
+ EFI_FILE_PROTOCOL *File;
+ CHAR8 *Buffer;
+ UINTN BufferSize;
+ UINT64 StoredPosition;
- File = &BootMonFsFile->File;
+ OldSize = BootMonFsFile->Info->FileSize;
- if (!(BootMonFsFile->OpenMode & EFI_FILE_MODE_WRITE)) {
- return EFI_ACCESS_DENIED;
- }
+ //
+ // In case of file truncation, force the regions waiting for writing to
+ // not overflow the new size of the file.
+ //
+ if (NewSize < OldSize) {
+ for (RegionToFlushLink = GetFirstNode (&BootMonFsFile->RegionToFlushLink);
+ !IsNull (&BootMonFsFile->RegionToFlushLink, RegionToFlushLink);
+ )
+ {
+ NextRegionToFlushLink = GetNextNode (&BootMonFsFile->RegionToFlushLink, RegionToFlushLink);
+ Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;
+ if (Region->Offset > NewSize) {
+ RemoveEntryList (RegionToFlushLink);
+ FreePool (Region->Buffer);
+ FreePool (Region);
+ } else {
+ Region->Size = MIN (Region->Size, NewSize - Region->Offset);
+ }
+ RegionToFlushLink = NextRegionToFlushLink;
+ }
- if (NewSize <= OldSize) {
- OldSize = NewSize;
- } else {
+ } else if (NewSize > OldSize) {
// 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.
+ File = &BootMonFsFile->File;
// Save position
Status = File->GetPosition (File, &StoredPosition);
if (EFI_ERROR (Status)) {
return Status;
}
-
- Status = File->SetPosition (File, NewSize - 1);
+ // Set position at the end of the file
+ Status = File->SetPosition (File, OldSize);
if (EFI_ERROR (Status)) {
return Status;
}
- Status = File->Write (File, &BufferSize, &Buffer);
- if (EFI_ERROR (Status)) {
- return Status;
+
+ BufferSize = NewSize - OldSize;
+ Buffer = AllocateZeroPool (BufferSize);
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
}
- // Restore saved position
- Status = File->SetPosition (File, NewSize - 1);
+ Status = File->Write (File, &BufferSize, Buffer);
+ FreePool (Buffer);
if (EFI_ERROR (Status)) {
return Status;
}
- Status = File->Flush (File);
+ // Restore saved position
+ Status = File->SetPosition (File, StoredPosition);
if (EFI_ERROR (Status)) {
return Status;
}
}
+
+ BootMonFsFile->Info->FileSize = NewSize;
+
return EFI_SUCCESS;
}
+/**
+ Set information about a file.
+
+ @param[in] Instance A pointer to the description of the volume
+ the file belongs to.
+ @param[in] File A pointer to the description of the file.
+ @param[in] Info A pointer to the file information to write.
+
+ @retval EFI_SUCCESS The information was set.
+ @retval EFI_ACCESS_DENIED An attempt is being made to change the
+ EFI_FILE_DIRECTORY Attribute.
+ @retval EFI_ACCESS_DENIED The file was opened in read-only mode and an
+ attempt is being made to modify a field other
+ than Attribute.
+ @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
+ to a file that is already present.
+ @retval EFI_WRITE_PROTECTED An attempt is being made to modify a read-only
+ attribute.
+ @retval EFI_OUT_OF_RESOURCES An allocation needed to process the request
+ failed.
+
+**/
+STATIC
EFI_STATUS
SetFileInfo (
- IN BOOTMON_FS_INSTANCE *Instance,
- IN BOOTMON_FS_FILE *File,
- IN UINTN BufferSize,
- IN EFI_FILE_INFO *Info
+ IN BOOTMON_FS_INSTANCE *Instance,
+ IN BOOTMON_FS_FILE *File,
+ IN EFI_FILE_INFO *Info
)
{
- EFI_STATUS Status;
+ EFI_STATUS Status;
+ BOOLEAN FileSizeIsDifferent;
+ BOOLEAN FileNameIsDifferent;
+ BOOLEAN TimeIsDifferent;
- Status = EFI_SUCCESS;
+ //
+ // A directory can not be changed to a file and a file can
+ // not be changed to a directory.
+ //
+ if ((Info->Attribute & EFI_FILE_DIRECTORY) !=
+ (File->Info->Attribute & EFI_FILE_DIRECTORY) ) {
+ return EFI_ACCESS_DENIED;
+ }
- // 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.
+ FileSizeIsDifferent = (Info->FileSize != File->Info->FileSize);
+ FileNameIsDifferent = (StrnCmp (
+ Info->FileName,
+ File->Info->FileName,
+ MAX_NAME_LENGTH - 1
+ ) != 0);
+ //
+ // Check if the CreateTime, LastAccess or ModificationTime
+ // have been changed. The file system does not support file
+ // timestamps thus the three times in "File->Info" are
+ // always equal to zero. The following comparison actually
+ // checks if all three times are still equal to 0 or not.
+ //
+ TimeIsDifferent = CompareMem (
+ &Info->CreateTime,
+ &File->Info->CreateTime,
+ 3 * sizeof (EFI_TIME)
+ ) != 0;
- if (File != Instance->RootFile) {
- if (!(File->OpenMode & EFI_FILE_MODE_WRITE)) {
+ //
+ // For a file opened in read-only mode, only the Attribute field can be
+ // modified. The root directory open mode is forced to read-only at opening
+ // thus the following test protects the root directory to be somehow modified.
+ //
+ if (File->OpenMode == EFI_FILE_MODE_READ) {
+ if (FileSizeIsDifferent || FileNameIsDifferent || TimeIsDifferent) {
return EFI_ACCESS_DENIED;
}
+ }
+
+ if (TimeIsDifferent) {
+ return EFI_WRITE_PROTECTED;
+ }
- Status = SetFileName (File, Info->FileName);
+ if (FileSizeIsDifferent) {
+ Status = SetFileSize (Instance, File, Info->FileSize);
if (EFI_ERROR (Status)) {
return Status;
}
+ }
- // Update file size
- Status = SetFileSize (Instance, File, Info->FileSize);
+ //
+ // Note down in RAM the Attribute field but we can not
+ // ask to store it in flash for the time being.
+ //
+ File->Info->Attribute = Info->Attribute;
+
+ if (FileNameIsDifferent) {
+ Status = SetFileName (Instance, File, Info->FileName);
if (EFI_ERROR (Status)) {
return Status;
}
}
- return Status;
+
+ return EFI_SUCCESS;
}
EFIAPI
@@ -477,11 +543,17 @@ BootMonFsGetInfo (
BOOTMON_FS_FILE *File;
BOOTMON_FS_INSTANCE *Instance;
- File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
- if (File == NULL) {
- return EFI_DEVICE_ERROR;
+ if ((This == NULL) ||
+ (InformationType == NULL) ||
+ (BufferSize == NULL) ||
+ ((Buffer == NULL) && (*BufferSize > 0)) ) {
+ return EFI_INVALID_PARAMETER;
}
+ File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
+ if (File->Info == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
Instance = File->Instance;
// If the instance has not been initialized yet then do it ...
@@ -509,6 +581,37 @@ BootMonFsGetInfo (
return Status;
}
+/**
+ Set information about a file or a volume.
+
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
+ is the file handle the information is for.
+ @param[in] InformationType The type identifier for the information being set :
+ EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or
+ EFI_FILE_SYSTEM_VOLUME_LABEL_ID
+ @param[in] BufferSize The size, in bytes, of Buffer.
+ @param[in] Buffer A pointer to the data buffer to write. The type of the
+ data inside the buffer is indicated by InformationType.
+
+ @retval EFI_SUCCESS The information was set.
+ @retval EFI_UNSUPPORTED The InformationType is not known.
+ @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
+ @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file
+ to a file that is already present.
+ @retval EFI_ACCESS_DENIED An attempt is being made to change the
+ EFI_FILE_DIRECTORY Attribute.
+ @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and
+ the file was opened in read-only mode and an
+ attempt is being made to modify a field other
+ than Attribute.
+ @retval EFI_WRITE_PROTECTED An attempt is being made to modify a read-only
+ attribute.
+ @retval EFI_BAD_BUFFER_SIZE The size of the buffer is lower than that indicated by
+ the data inside the buffer.
+ @retval EFI_OUT_OF_RESOURCES A allocation needed to process the request failed.
+ @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
+
+**/
EFIAPI
EFI_STATUS
BootMonFsSetInfo (
@@ -518,28 +621,56 @@ BootMonFsSetInfo (
IN VOID *Buffer
)
{
- EFI_STATUS Status;
- BOOTMON_FS_FILE *File;
- BOOTMON_FS_INSTANCE *Instance;
+ BOOTMON_FS_FILE *File;
+ EFI_FILE_INFO *Info;
+ EFI_FILE_SYSTEM_INFO *SystemInfo;
+
+ if ((This == NULL) ||
+ (InformationType == NULL) ||
+ (Buffer == NULL) ) {
+ return EFI_INVALID_PARAMETER;
+ }
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
- if (File == NULL) {
- return EFI_DEVICE_ERROR;
+ if (File->Info == NULL) {
+ return EFI_INVALID_PARAMETER;
}
- Instance = File->Instance;
+ if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
+ Info = Buffer;
+ if (Info->Size < (SIZE_OF_EFI_FILE_INFO + StrSize (Info->FileName))) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (BufferSize < Info->Size) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+ return (SetFileInfo (File->Instance, File, Info));
+ }
- 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;
+ //
+ // 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.
+ //
+
+ if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
+ SystemInfo = Buffer;
+ if (SystemInfo->Size <
+ (SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (SystemInfo->VolumeLabel))) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (BufferSize < SystemInfo->Size) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+ return EFI_WRITE_PROTECTED;
}
- return Status;
+ if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ return EFI_UNSUPPORTED;
}
EFIAPI
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsEntryPoint.c b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsEntryPoint.c
index 5eb7afca7c..3d71760fef 100644
--- a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsEntryPoint.c
+++ b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsEntryPoint.c
@@ -54,6 +54,30 @@ EFI_FILE_PROTOCOL mBootMonFsFileTemplate = {
BootMonFsFlushFile
};
+/**
+ Search for a file given its name coded in Ascii.
+
+ When searching through the files of the volume, if a file is currently not
+ open, its name was written on the media and is kept in RAM in the
+ "HwDescription.Footer.Filename[]" field of the file's description.
+
+ If a file is currently open, its name might not have been written on the
+ media yet, and as the "HwDescription" is a mirror in RAM of what is on the
+ media the "HwDescription.Footer.Filename[]" might be outdated. In that case,
+ the up to date name of the file is stored in the "Info" field of the file's
+ description.
+
+ @param[in] Instance Pointer to the description of the volume in which
+ the file has to be search for.
+ @param[in] AsciiFileName Name of the file.
+
+ @param[out] File Pointer to the description of the file if the
+ file was found.
+
+ @retval EFI_SUCCESS The file was found.
+ @retval EFI_NOT_FOUND The file was not found.
+
+**/
EFI_STATUS
BootMonGetFileFromAsciiFileName (
IN BOOTMON_FS_INSTANCE *Instance,
@@ -61,22 +85,26 @@ BootMonGetFileFromAsciiFileName (
OUT BOOTMON_FS_FILE **File
)
{
- LIST_ENTRY *Entry;
- BOOTMON_FS_FILE *FileEntry;
-
- // Remove the leading '\\'
- if (*AsciiFileName == '\\') {
- AsciiFileName++;
- }
+ LIST_ENTRY *Entry;
+ BOOTMON_FS_FILE *FileEntry;
+ CHAR8 OpenFileAsciiFileName[MAX_NAME_LENGTH];
+ CHAR8 *AsciiFileNameToCompare;
// Go through all the files in the list and return the file handle
for (Entry = GetFirstNode (&Instance->RootFile->Link);
- !IsNull (&Instance->RootFile->Link, Entry);
- Entry = GetNextNode (&Instance->RootFile->Link, Entry)
- )
+ !IsNull (&Instance->RootFile->Link, Entry);
+ Entry = GetNextNode (&Instance->RootFile->Link, Entry)
+ )
{
FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (Entry);
- if (AsciiStrCmp (FileEntry->HwDescription.Footer.Filename, AsciiFileName) == 0) {
+ if (FileEntry->Info != NULL) {
+ UnicodeStrToAsciiStr (FileEntry->Info->FileName, OpenFileAsciiFileName);
+ AsciiFileNameToCompare = OpenFileAsciiFileName;
+ } else {
+ AsciiFileNameToCompare = FileEntry->HwDescription.Footer.Filename;
+ }
+
+ if (AsciiStrCmp (AsciiFileNameToCompare, AsciiFileName) == 0) {
*File = FileEntry;
return EFI_SUCCESS;
}
@@ -291,6 +319,7 @@ BootMonFsDriverStart (
BOOTMON_FS_INSTANCE *Instance;
EFI_STATUS Status;
UINTN VolumeNameSize;
+ EFI_FILE_INFO *Info;
Instance = AllocateZeroPool (sizeof (BOOTMON_FS_INSTANCE));
if (Instance == NULL) {
@@ -307,8 +336,7 @@ BootMonFsDriverStart (
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
- FreePool (Instance);
- return Status;
+ goto Error;
}
Status = gBS->OpenProtocol (
@@ -320,8 +348,7 @@ BootMonFsDriverStart (
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
- FreePool (Instance);
- return Status;
+ goto Error;
}
//
@@ -350,10 +377,16 @@ BootMonFsDriverStart (
// Initialize the root file
Status = BootMonFsCreateFile (Instance, &Instance->RootFile);
if (EFI_ERROR (Status)) {
- FreePool (Instance);
- return Status;
+ goto Error;
}
+ Info = AllocateZeroPool (sizeof (EFI_FILE_INFO));
+ if (Info == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+ Instance->RootFile->Info = Info;
+
// Initialize the DevicePath of the Instance
Status = gBS->OpenProtocol (
ControllerHandle,
@@ -364,8 +397,7 @@ BootMonFsDriverStart (
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
- FreePool (Instance);
- return Status;
+ goto Error;
}
//
@@ -376,9 +408,24 @@ BootMonFsDriverStart (
&gEfiSimpleFileSystemProtocolGuid, &Instance->Fs,
NULL
);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
InsertTailList (&mInstances, &Instance->Link);
+ return EFI_SUCCESS;
+
+Error:
+
+ if (Instance->RootFile != NULL) {
+ if (Instance->RootFile->Info != NULL) {
+ FreePool (Instance->RootFile->Info);
+ }
+ FreePool (Instance->RootFile);
+ }
+ FreePool (Instance);
+
return Status;
}
@@ -434,6 +481,10 @@ BootMonFsDriverStop (
&gEfiSimpleFileSystemProtocolGuid, &Instance->Fs,
NULL);
+ FreePool (Instance->RootFile->Info);
+ FreePool (Instance->RootFile);
+ FreePool (Instance);
+
return Status;
}
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsInternal.h b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsInternal.h
index 57343618ab..c0c6599cb7 100644
--- a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsInternal.h
+++ b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsInternal.h
@@ -54,8 +54,14 @@ typedef struct {
EFI_FILE_PROTOCOL File;
+ //
+ // The following fields are relevant only if the file is open.
+ //
+
+ EFI_FILE_INFO *Info;
UINT64 Position;
- // If the file needs to be flushed then this list contain the memory buffer that creates this file
+ // If the file needs to be flushed then this list contain the memory
+ // buffer that creates this file
LIST_ENTRY RegionToFlushLink;
UINT64 OpenMode;
} BOOTMON_FS_FILE;
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsOpenClose.c b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsOpenClose.c
index 45ac89026f..dc83b3882b 100644
--- a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsOpenClose.c
+++ b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsOpenClose.c
@@ -39,6 +39,10 @@ InvalidateImageDescription (
Buffer = AllocateZeroPool (sizeof (HW_IMAGE_DESCRIPTION));
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
Status = DiskIo->WriteDisk (DiskIo,
MediaId,
File->HwDescAddress,
@@ -51,83 +55,75 @@ InvalidateImageDescription (
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.
+/**
+ Write the description of a file to storage media.
+
+ This function uses DiskIo to write to the media, so call BlockIo->FlushBlocks()
+ after calling it to ensure the data are written on the media.
+
+ @param[in] File Description of the file whose description on the
+ storage media has to be updated.
+ @param[in] FileName Name of the file. Its length is assumed to be
+ lower than MAX_NAME_LENGTH.
+ @param[in] DataSize Number of data bytes of the file.
+ @param[in] FileStart File's starting position on media. FileStart must
+ be aligned to the media's block size.
+
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing
+ the write operation.
+
+**/
STATIC
EFI_STATUS
-FlushAppendRegion (
- IN BOOTMON_FS_FILE *File,
- IN BOOTMON_FS_FILE_REGION *Region,
- IN UINT64 NewFileSize,
- IN UINT64 FileStart
+WriteFileDescription (
+ IN BOOTMON_FS_FILE *File,
+ IN CHAR8 *FileName,
+ IN UINT32 DataSize,
+ IN UINT64 FileStart
)
{
- EFI_STATUS Status;
- EFI_DISK_IO_PROTOCOL *DiskIo;
- UINTN BlockSize;
- HW_IMAGE_DESCRIPTION *Description;
-
- DiskIo = File->Instance->DiskIo;
+ EFI_STATUS Status;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ UINTN BlockSize;
+ UINT32 FileSize;
+ 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->HwDescAddress != 0) {
- Status = InvalidateImageDescription (File);
- ASSERT_EFI_ERROR (Status);
- }
-
//
- // Update File Description
+ // Construct the file description
//
+
+ FileSize = DataSize + sizeof (HW_IMAGE_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->BlockEnd = Description->BlockStart + (FileSize / BlockSize);
+ AsciiStrCpy (Description->Footer.Filename, FileName);
+
#ifdef MDE_CPU_ARM
+ Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET;
Description->Footer.Version = HW_IMAGE_FOOTER_VERSION;
- Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET;
#else
+ Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET2;
Description->Footer.Version = HW_IMAGE_FOOTER_VERSION2;
- Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET2;
#endif
+ Description->Footer.FooterSignature1 = HW_IMAGE_FOOTER_SIGNATURE_1;
+ Description->Footer.FooterSignature2 = HW_IMAGE_FOOTER_SIGNATURE_2;
Description->RegionCount = 1;
Description->Region[0].Checksum = 0;
Description->Region[0].Offset = Description->BlockStart * BlockSize;
- Description->Region[0].Size = NewFileSize - sizeof (HW_IMAGE_DESCRIPTION);
+ Description->Region[0].Size = DataSize;
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);
- }
-
- File->HwDescAddress = (FileStart + NewFileSize) - sizeof (HW_IMAGE_DESCRIPTION);
+ File->HwDescAddress = ((Description->BlockEnd + 1) * BlockSize) - sizeof (HW_IMAGE_DESCRIPTION);
// Update the file description on the media
Status = DiskIo->WriteDisk (
@@ -142,14 +138,6 @@ FlushAppendRegion (
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:
@@ -167,6 +155,7 @@ STATIC
EFI_STATUS
BootMonFsFindSpaceForNewFile (
IN BOOTMON_FS_FILE *File,
+ IN UINT64 FileSize,
OUT UINT64 *FileStart
)
{
@@ -174,26 +163,16 @@ BootMonFsFindSpaceForNewFile (
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);
@@ -253,6 +232,20 @@ FreeFileRegions (
}
}
+/**
+ Flush all modified data associated with a file to a device.
+
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the
+ file handle to flush.
+
+ @retval EFI_SUCCESS The data was flushed.
+ @retval EFI_ACCESS_DENIED The file was opened read-only.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_FULL The volume is full.
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to flush the data.
+ @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
+
+**/
EFIAPI
EFI_STATUS
BootMonFsFlushFile (
@@ -261,52 +254,62 @@ BootMonFsFlushFile (
{
EFI_STATUS Status;
BOOTMON_FS_INSTANCE *Instance;
+ EFI_FILE_INFO *Info;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_BLOCK_IO_MEDIA *Media;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ UINTN BlockSize;
+ CHAR8 AsciiFileName[MAX_NAME_LENGTH];
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 NewDataSize;
UINT64 NewFileSize;
UINT64 EndOfAppendSpace;
BOOLEAN HasSpace;
- EFI_DISK_IO_PROTOCOL *DiskIo;
- EFI_BLOCK_IO_PROTOCOL *BlockIo;
- Status = EFI_SUCCESS;
- FileStart = 0;
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
- if (File == NULL) {
+ if (File->Info == NULL) {
return EFI_INVALID_PARAMETER;
}
- // Check if the file needs to be flushed
- if (!BootMonFsFileNeedFlush (File)) {
- return Status;
+ if (File->OpenMode == EFI_FILE_MODE_READ) {
+ return EFI_ACCESS_DENIED;
}
- Instance = File->Instance;
- BlockIo = Instance->BlockIo;
- DiskIo = Instance->DiskIo;
- BlockSize = BlockIo->Media->BlockSize;
+ Instance = File->Instance;
+ Info = File->Info;
+ BlockIo = Instance->BlockIo;
+ Media = BlockIo->Media;
+ DiskIo = Instance->DiskIo;
+ BlockSize = Media->BlockSize;
+
+ UnicodeStrToAsciiStr (Info->FileName, AsciiFileName);
// 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
+ Status = BootMonFsFindSpaceForNewFile (
+ File,
+ Info->FileSize + sizeof (HW_IMAGE_DESCRIPTION),
+ &FileStart
+ );
if (EFI_ERROR (Status)) {
return Status;
}
} else {
FileStart = File->HwDescription.BlockStart * BlockSize;
}
-
// FileEnd is the current NOR address of the end of the file's data
FileEnd = FileStart + File->HwDescription.Region[0].Size;
@@ -316,17 +319,20 @@ BootMonFsFlushFile (
)
{
Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;
+ if (Region->Size == 0) {
+ continue;
+ }
// 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;
+ 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,
+ Media->MediaId,
RegionStart,
Region->Size,
Region->Buffer
@@ -345,7 +351,8 @@ BootMonFsFlushFile (
// Check if there is space to append the new region
HasSpace = FALSE;
- NewFileSize = (RegionEnd - FileStart) + sizeof (HW_IMAGE_DESCRIPTION);
+ NewDataSize = RegionEnd - FileStart;
+ NewFileSize = NewDataSize + sizeof (HW_IMAGE_DESCRIPTION);
CurrentPhysicalSize = BootMonFsGetPhysicalSize (File);
if (NewFileSize <= CurrentPhysicalSize) {
HasSpace = TRUE;
@@ -360,7 +367,7 @@ BootMonFsFlushFile (
EndOfAppendSpace = NextFile->HwDescription.BlockStart * BlockSize;
} else {
// We are flushing the last file.
- EndOfAppendSpace = (BlockIo->Media->LastBlock + 1) * BlockSize;
+ EndOfAppendSpace = (Media->LastBlock + 1) * BlockSize;
}
if (EndOfAppendSpace - FileStart >= NewFileSize) {
HasSpace = TRUE;
@@ -368,10 +375,31 @@ BootMonFsFlushFile (
}
if (HasSpace == TRUE) {
- Status = FlushAppendRegion (File, Region, NewFileSize, FileStart);
+ // Invalidate the current image description of the file if any.
+ if (File->HwDescAddress != 0) {
+ Status = InvalidateImageDescription (File);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ // Write the new file data
+ Status = DiskIo->WriteDisk (
+ DiskIo,
+ Media->MediaId,
+ RegionStart,
+ Region->Size,
+ Region->Buffer
+ );
if (EFI_ERROR (Status)) {
return Status;
}
+
+ Status = WriteFileDescription (File, AsciiFileName, NewDataSize, 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
@@ -385,20 +413,32 @@ BootMonFsFlushFile (
}
FreeFileRegions (File);
+ Info->PhysicalSize = BootMonFsGetPhysicalSize (File);
+
+ if ((AsciiStrCmp (AsciiFileName, File->HwDescription.Footer.Filename) != 0) ||
+ (Info->FileSize != File->HwDescription.Region[0].Size) ) {
+ Status = WriteFileDescription (File, AsciiFileName, Info->FileSize, FileStart);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
// 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;
+ return EFI_SUCCESS;
}
/**
- Closes a file on the Nor Flash FS volume.
+ Close a specified file handle.
- @param This The EFI_FILE_PROTOCOL to close.
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
+ handle to close.
- @return Always returns EFI_SUCCESS.
+ @retval EFI_SUCCESS The file was closed.
+ @retval EFI_INVALID_PARAMETER The parameter "This" is NULL or is not an open
+ file handle.
**/
EFIAPI
@@ -407,42 +447,25 @@ BootMonFsCloseFile (
IN EFI_FILE_PROTOCOL *This
)
{
- // Flush the file if needed
- This->Flush (This);
- return EFI_SUCCESS;
-}
+ BOOTMON_FS_FILE *File;
-// 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;
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
}
- // Remove the leading '\\'
- if (*AsciiFileName == '\\') {
- AsciiFileName++;
+ File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
+ if (File->Info == NULL) {
+ return EFI_INVALID_PARAMETER;
}
- // 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);
+ // In the case of a file and not the root directory
+ if (This != &File->Instance->RootFile->File) {
+ This->Flush (This);
+ FreePool (File->Info);
+ File->Info = NULL;
+ }
- *NewHandle = File;
- return Status;
+ return EFI_SUCCESS;
}
/**
@@ -490,11 +513,17 @@ BootMonFsOpenFile (
CHAR16 *Path;
CHAR16 *Separator;
CHAR8 *AsciiFileName;
+ EFI_FILE_INFO *Info;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
+ Directory = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
+ if (Directory->Info == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
if ((FileName == NULL) || (NewHandle == NULL)) {
return EFI_INVALID_PARAMETER;
}
@@ -508,11 +537,6 @@ BootMonFsOpenFile (
return EFI_INVALID_PARAMETER;
}
- Directory = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
- if (Directory == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
Instance = Directory->Instance;
//
@@ -535,6 +559,7 @@ BootMonFsOpenFile (
}
Path = (CHAR16*)Buf;
AsciiFileName = NULL;
+ Info = NULL;
//
// Handle single periods, double periods and convert forward slashes '/'
@@ -625,6 +650,18 @@ BootMonFsOpenFile (
}
//
+ // Allocate a buffer to store the characteristics of the file while the
+ // file is open. We allocate the maximum size to not have to reallocate
+ // if the file name is changed.
+ //
+ Info = AllocateZeroPool (
+ SIZE_OF_EFI_FILE_INFO + (sizeof (CHAR16) * MAX_NAME_LENGTH));
+ if (Info == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ //
// Open or create a file in the root directory.
//
@@ -634,20 +671,32 @@ BootMonFsOpenFile (
goto Error;
}
- Status = CreateNewFile (Instance, AsciiFileName, &File);
- if (!EFI_ERROR (Status)) {
- File->OpenMode = OpenMode;
- *NewHandle = &File->File;
- File->Position = 0;
+ Status = BootMonFsCreateFile (Instance, &File);
+ if (EFI_ERROR (Status)) {
+ goto Error;
}
+ InsertHeadList (&Instance->RootFile->Link, &File->Link);
+ Info->Attribute = Attributes;
} else {
//
- // The file already exists.
+ // File already open, not supported yet.
//
- File->OpenMode = OpenMode;
- *NewHandle = &File->File;
- File->Position = 0;
+ if (File->Info != NULL) {
+ Status = EFI_UNSUPPORTED;
+ goto Error;
+ }
}
+
+ Info->FileSize = BootMonFsGetImageLength (File);
+ Info->PhysicalSize = BootMonFsGetPhysicalSize (File);
+ AsciiStrToUnicodeStr (AsciiFileName, Info->FileName);
+
+ File->Info = Info;
+ Info = NULL;
+ File->Position = 0;
+ File->OpenMode = OpenMode;
+
+ *NewHandle = &File->File;
}
Error:
@@ -656,6 +705,9 @@ Error:
if (AsciiFileName != NULL) {
FreePool (AsciiFileName);
}
+ if (Info != NULL) {
+ FreePool (Info);
+ }
return Status;
}
@@ -671,6 +723,19 @@ BootMonFsDeleteFail (
// You can't delete the root directory
return EFI_WARN_DELETE_FAILURE;
}
+
+/**
+ Close and delete a file from the boot monitor file system.
+
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file
+ handle to delete.
+
+ @retval EFI_SUCCESS The file was closed and deleted.
+ @retval EFI_INVALID_PARAMETER The parameter "This" is NULL or is not an open
+ file handle.
+ @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not deleted.
+
+**/
EFIAPI
EFI_STATUS
BootMonFsDelete (
@@ -681,23 +746,26 @@ BootMonFsDelete (
BOOTMON_FS_FILE *File;
LIST_ENTRY *RegionToFlushLink;
BOOTMON_FS_FILE_REGION *Region;
- EFI_BLOCK_IO_PROTOCOL *BlockIo;
- UINT8 *EmptyBuffer;
- File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
- if (File == NULL) {
- return EFI_DEVICE_ERROR;
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
}
- Status = EFI_SUCCESS;
+ File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
+ if (File->Info == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
- if (BootMonFsFileNeedFlush (File)) {
+ if (!IsListEmpty (&File->RegionToFlushLink)) {
// Free the entries from the Buffer List
RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink);
do {
Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink;
- // Get Next entry
+ //
+ // Get next element of the list before deleting the region description
+ // that contain the LIST_ENTRY structure.
+ //
RegionToFlushLink = RemoveEntryList (RegionToFlushLink);
// Free the buffers
@@ -708,25 +776,18 @@ BootMonFsDelete (
// If (RegionCount is greater than 0) then the file already exists
if (File->HwDescription.RegionCount > 0) {
- 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 = InvalidateImageDescription (File);
ASSERT_EFI_ERROR (Status);
-
- FreePool (EmptyBuffer);
+ if (EFI_ERROR (Status)) {
+ return EFI_WARN_DELETE_FAILURE;
+ }
}
// Remove the entry from the list
RemoveEntryList (&File->Link);
+ FreePool (File->Info);
FreePool (File);
- return Status;
-}
+ return EFI_SUCCESS;
+}
diff --git a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsReadWrite.c b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsReadWrite.c
index 358332d658..f8124e95ac 100644
--- a/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsReadWrite.c
+++ b/ArmPlatformPkg/FileSystem/BootMonFs/BootMonFsReadWrite.c
@@ -36,6 +36,7 @@
reported an error while performing the read
operation.
@retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
+
**/
EFIAPI
EFI_STATUS
@@ -53,25 +54,30 @@ BootMonFsReadFile (
EFI_STATUS Status;
UINTN RemainingFileSize;
- // Ensure the file has been written in Flash before reading it.
- // This keeps the code simple and avoids having to manage a non-flushed file.
- BootMonFsFlushFile (This);
-
+ if ((This == NULL) ||
+ (BufferSize == NULL) ||
+ (Buffer == NULL) ) {
+ return EFI_INVALID_PARAMETER;
+ }
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
- if (File == NULL) {
+ if (File->Info == NULL) {
return EFI_INVALID_PARAMETER;
}
- Instance = File->Instance;
- DiskIo = Instance->DiskIo;
- Media = Instance->Media;
+ // Ensure the file has been written in Flash before reading it.
+ // This keeps the code simple and avoids having to manage a non-flushed file.
+ BootMonFsFlushFile (This);
+
+ Instance = File->Instance;
+ DiskIo = Instance->DiskIo;
+ Media = Instance->Media;
FileStart = (Media->LowestAlignedLba + File->HwDescription.BlockStart) * Media->BlockSize;
- if (File->Position >= File->HwDescription.Region[0].Size) {
+ if (File->Position >= File->Info->FileSize) {
// The entire file has been read or the position has been
// set past the end of the file.
*BufferSize = 0;
- if (File->Position > File->HwDescription.Region[0].Size) {
+ if (File->Position > File->Info->FileSize) {
return EFI_DEVICE_ERROR;
} else {
return EFI_SUCCESS;
@@ -79,7 +85,7 @@ BootMonFsReadFile (
}
// This driver assumes that the entire file is in region 0.
- RemainingFileSize = File->HwDescription.Region[0].Size - File->Position;
+ RemainingFileSize = File->Info->FileSize - File->Position;
// If read would go past end of file, truncate the read
if (*BufferSize > RemainingFileSize) {
@@ -102,7 +108,26 @@ BootMonFsReadFile (
return Status;
}
-// Inserts an entry into the write chain
+/**
+ Write data to an open file.
+
+ The data is not written to the flash yet. It will be written when the file
+ will be either read, closed or flushed.
+
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that
+ is the file handle to write data to.
+ @param[in out] BufferSize On input, the size of the Buffer. On output, the
+ size of the data actually written. In both cases,
+ the size is measured in bytes.
+ @param[in] Buffer The buffer of data to write.
+
+ @retval EFI_SUCCESS The data was written.
+ @retval EFI_ACCESS_DENIED The file was opened read only.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate the buffer to store the
+ data to write.
+ @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
+
+**/
EFIAPI
EFI_STATUS
BootMonFsWriteFile (
@@ -114,38 +139,57 @@ BootMonFsWriteFile (
BOOTMON_FS_FILE *File;
BOOTMON_FS_FILE_REGION *Region;
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
- if (File == NULL) {
+ if (File->Info == NULL) {
return EFI_INVALID_PARAMETER;
}
- if (!(File->OpenMode & EFI_FILE_MODE_WRITE)) {
+ if (File->OpenMode == EFI_FILE_MODE_READ) {
return EFI_ACCESS_DENIED;
}
// Allocate and initialize the memory region
Region = (BOOTMON_FS_FILE_REGION*)AllocateZeroPool (sizeof (BOOTMON_FS_FILE_REGION));
if (Region == NULL) {
+ *BufferSize = 0;
return EFI_OUT_OF_RESOURCES;
}
- Region->Buffer = AllocateCopyPool (*BufferSize, Buffer);
+ Region->Buffer = AllocateCopyPool (*BufferSize, Buffer);
if (Region->Buffer == NULL) {
+ *BufferSize = 0;
FreePool (Region);
return EFI_OUT_OF_RESOURCES;
}
- Region->Size = *BufferSize;
-
+ Region->Size = *BufferSize;
Region->Offset = File->Position;
InsertTailList (&File->RegionToFlushLink, &Region->Link);
File->Position += *BufferSize;
+ if (File->Position > File->Info->FileSize) {
+ File->Info->FileSize = File->Position;
+ }
+
return EFI_SUCCESS;
}
+/**
+ Set a file's current position.
+
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
+ the file handle to set the requested position on.
+ @param[in] Position The byte position from the start of the file to set.
+
+ @retval EFI_SUCCESS The position was set.
+ @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
+
+**/
EFIAPI
EFI_STATUS
BootMonFsSetPosition (
@@ -153,33 +197,63 @@ BootMonFsSetPosition (
IN UINT64 Position
)
{
- BOOTMON_FS_FILE *File;
+ BOOTMON_FS_FILE *File;
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
+ if (File->Info == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
// UEFI Spec section 12.5:
// "Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to
- // be set to the end of the file."
+ // be set to the end of the file."
+ //
if (Position == 0xFFFFFFFFFFFFFFFF) {
- File->Position = BootMonFsGetImageLength (File);
- } else {
- // NB: Seeking past the end of the file is valid.
- File->Position = Position;
+ Position = File->Info->FileSize;
}
+ File->Position = Position;
+
return EFI_SUCCESS;
}
+/**
+ Return a file's current position.
+
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is
+ the file handle to get the current position on.
+ @param[out] Position The address to return the file's current position value.
+
+ @retval EFI_SUCCESS The position was returned.
+ @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.
+
+**/
EFIAPI
EFI_STATUS
BootMonFsGetPosition (
IN EFI_FILE_PROTOCOL *This,
OUT UINT64 *Position
- ) {
+ )
+{
BOOTMON_FS_FILE *File;
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
File = BOOTMON_FS_FILE_FROM_FILE_THIS (This);
+ if (File->Info == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Position == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
*Position = File->Position;
+
return EFI_SUCCESS;
}