summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRonald Cron <ronald.cron@arm.com>2014-10-27 10:40:33 +0000
committeroliviermartin <oliviermartin@Edk2>2014-10-27 10:40:33 +0000
commitfdd12bd56985bfc6090b972ddc07418eb4f7212a (patch)
tree7240f7d6057e4167a50928b04607e3254b3ae934
parent0f0a6fe907e6233f95546599ee3fe48d91259dce (diff)
downloadedk2-fdd12bd56985bfc6090b972ddc07418eb4f7212a.tar.gz
edk2-fdd12bd56985bfc6090b972ddc07418eb4f7212a.tar.bz2
edk2-fdd12bd56985bfc6090b972ddc07418eb4f7212a.zip
ArmPkg/SemihostFs: Fix open file issues revealed by SCT
Fix return codes in case of errors. Fix translation from EFI open mode to semi-hosting open mode to avoid the truncate to zero length of an already existing file opened in read/write or read/write/create mode. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ronald Cron <ronald.cron@arm.com> Reviewed-By: Olivier Martin <olivier.martin@arm.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16241 6f19259b-4bc3-4df7-8a09-765794883524
-rw-r--r--ArmPkg/Filesystem/SemihostFs/Arm/SemihostFs.c157
-rw-r--r--ArmPkg/Filesystem/SemihostFs/Arm/SemihostFs.h28
2 files changed, 131 insertions, 54 deletions
diff --git a/ArmPkg/Filesystem/SemihostFs/Arm/SemihostFs.c b/ArmPkg/Filesystem/SemihostFs/Arm/SemihostFs.c
index b865143c74..34e2f62402 100644
--- a/ArmPkg/Filesystem/SemihostFs/Arm/SemihostFs.c
+++ b/ArmPkg/Filesystem/SemihostFs/Arm/SemihostFs.c
@@ -57,7 +57,7 @@ EFI_FILE gSemihostFsFile = {
};
//
-// Device path for SemiHosting. It contains our autogened Caller ID GUID.
+// Device path for semi-hosting. It contains our autogened Caller ID GUID.
//
typedef struct {
VENDOR_DEVICE_PATH Guid;
@@ -149,100 +149,151 @@ VolumeOpen (
return EFI_SUCCESS;
}
+/**
+ Open a file on the host system by means of the semihosting interface.
+
+ @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
+ to be opened.
+ @param[in] OpenMode The mode to open the file : Read or Read/Write or
+ Read/Write/Create
+ @param[in] Attributes Only valid for EFI_FILE_MODE_CREATE, in which case these
+ are the attribute bits for the newly created file. The
+ mnemonics of the attribute bits are : EFI_FILE_READ_ONLY,
+ EFI_FILE_HIDDEN, EFI_FILE_SYSTEM, EFI_FILE_RESERVED,
+ EFI_FILE_DIRECTORY and EFI_FILE_ARCHIVE.
+
+ @retval EFI_SUCCESS The file was open.
+ @retval EFI_NOT_FOUND The specified file could not be found.
+ @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
+ @retval EFI_WRITE_PROTECTED Attempt to create a directory. This is not possible
+ with the semi-hosting interface.
+ @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.
+
+**/
EFI_STATUS
FileOpen (
- IN EFI_FILE *File,
- OUT EFI_FILE **NewHandle,
- IN CHAR16 *FileName,
- IN UINT64 OpenMode,
- IN UINT64 Attributes
+ IN EFI_FILE *This,
+ OUT EFI_FILE **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
)
{
- SEMIHOST_FCB *FileFcb = NULL;
- EFI_STATUS Status = EFI_SUCCESS;
- UINTN SemihostHandle;
- CHAR8 *AsciiFileName;
- UINT32 SemihostMode;
- BOOLEAN IsRoot;
- UINTN Length;
+ SEMIHOST_FCB *FileFcb;
+ RETURN_STATUS Return;
+ EFI_STATUS Status;
+ UINTN SemihostHandle;
+ CHAR8 *AsciiFileName;
+ UINT32 SemihostMode;
+ UINTN Length;
if ((FileName == NULL) || (NewHandle == NULL)) {
return EFI_INVALID_PARAMETER;
}
- // Semihosting does not support directories
- if (Attributes & EFI_FILE_DIRECTORY) {
- return EFI_UNSUPPORTED;
+ if ( (OpenMode != EFI_FILE_MODE_READ) &&
+ (OpenMode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE)) &&
+ (OpenMode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE)) ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((OpenMode & EFI_FILE_MODE_CREATE) &&
+ (Attributes & EFI_FILE_DIRECTORY) ) {
+ return EFI_WRITE_PROTECTED;
}
- // Semihost interface requires ASCII filenames
- AsciiFileName = AllocatePool ((StrLen (FileName) + 1) * sizeof (CHAR8));
+ AsciiFileName = AllocatePool (StrLen (FileName) + 1);
if (AsciiFileName == NULL) {
return EFI_OUT_OF_RESOURCES;
}
UnicodeStrToAsciiStr (FileName, AsciiFileName);
+ // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory
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
- IsRoot = TRUE;
-
- // Root directory node doesn't have a name.
+ (AsciiStrCmp (AsciiFileName, ".") == 0) ) {
FreePool (AsciiFileName);
- AsciiFileName = NULL;
+ return (VolumeOpen (&gSemihostFs, NewHandle));
+ }
+
+ //
+ // No control is done here concerning the file path. It is passed
+ // as it is to the host operating system through the semi-hosting
+ // interface. We first try to open the file in the read or update
+ // mode even if the file creation has been asked for. That way, if
+ // the file already exists, it is not truncated to zero length. In
+ // write mode (bit SEMIHOST_FILE_MODE_WRITE up), if the file already
+ // exists, it is reset to an empty file.
+ //
+ if (OpenMode == EFI_FILE_MODE_READ) {
+ SemihostMode = SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY;
} else {
- // Translate EFI_FILE_MODE into Semihosting mode
- if (OpenMode & EFI_FILE_MODE_WRITE) {
- SemihostMode = SEMIHOST_FILE_MODE_WRITE | SEMIHOST_FILE_MODE_BINARY;
- } else if (OpenMode & EFI_FILE_MODE_READ) {
- SemihostMode = SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY;
- } else {
- return EFI_UNSUPPORTED;
- }
+ SemihostMode = SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY | SEMIHOST_FILE_MODE_UPDATE;
+ }
+ Return = SemihostFileOpen (AsciiFileName, SemihostMode, &SemihostHandle);
- // Add the creation flag if necessary
+ if (RETURN_ERROR (Return)) {
if (OpenMode & EFI_FILE_MODE_CREATE) {
- SemihostMode |= SEMIHOST_FILE_MODE_UPDATE;
- }
-
- // Call the semihosting interface to open the file.
- Status = SemihostFileOpen (AsciiFileName, SemihostMode, &SemihostHandle);
- if (EFI_ERROR(Status)) {
- return Status;
+ //
+ // In the create if does not exist case, if the opening in update
+ // mode failed, create it and open it in update mode. The update
+ // mode allows for both read and write from and to the file.
+ //
+ Return = SemihostFileOpen (
+ AsciiFileName,
+ SEMIHOST_FILE_MODE_WRITE | SEMIHOST_FILE_MODE_BINARY | SEMIHOST_FILE_MODE_UPDATE,
+ &SemihostHandle
+ );
+ if (RETURN_ERROR (Return)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Error;
+ }
+ } else {
+ Status = EFI_NOT_FOUND;
+ goto Error;
}
-
- IsRoot = FALSE;
}
// Allocate a control block and fill it
FileFcb = AllocateFCB ();
if (FileFcb == NULL) {
- return EFI_OUT_OF_RESOURCES;
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
}
FileFcb->FileName = AsciiFileName;
FileFcb->SemihostHandle = SemihostHandle;
FileFcb->Position = 0;
- FileFcb->IsRoot = IsRoot;
+ FileFcb->IsRoot = 0;
FileFcb->OpenMode = OpenMode;
- if (!IsRoot) {
- Status = SemihostFileLength (SemihostHandle, &Length);
- if (EFI_ERROR(Status)) {
- return Status;
- }
-
- FileFcb->Info.FileSize = Length;
- FileFcb->Info.PhysicalSize = Length;
- FileFcb->Info.Attribute = Attributes;
+ Return = SemihostFileLength (SemihostHandle, &Length);
+ if (RETURN_ERROR (Return)) {
+ Status = EFI_DEVICE_ERROR;
+ FreeFCB (FileFcb);
+ goto Error;
}
+ FileFcb->Info.FileSize = Length;
+ FileFcb->Info.PhysicalSize = Length;
+ FileFcb->Info.Attribute = (OpenMode & EFI_FILE_MODE_CREATE) ? Attributes : 0;
+
InsertTailList (&gFileList, &FileFcb->Link);
*NewHandle = &FileFcb->File;
+ return EFI_SUCCESS;
+
+Error:
+
+ FreePool (AsciiFileName);
+
return Status;
}
diff --git a/ArmPkg/Filesystem/SemihostFs/Arm/SemihostFs.h b/ArmPkg/Filesystem/SemihostFs/Arm/SemihostFs.h
index a9b200b2a0..c02b36ae5f 100644
--- a/ArmPkg/Filesystem/SemihostFs/Arm/SemihostFs.h
+++ b/ArmPkg/Filesystem/SemihostFs/Arm/SemihostFs.h
@@ -22,9 +22,35 @@ VolumeOpen (
OUT EFI_FILE **Root
);
+/**
+ Open a file on the host system by means of the semihosting interface.
+
+ @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
+ to be opened.
+ @param[in] OpenMode The mode to open the file : Read or Read/Write or
+ Read/Write/Create
+ @param[in] Attributes Only valid for EFI_FILE_MODE_CREATE, in which case these
+ are the attribute bits for the newly created file. The
+ mnemonics of the attribute bits are : EFI_FILE_READ_ONLY,
+ EFI_FILE_HIDDEN, EFI_FILE_SYSTEM, EFI_FILE_RESERVED,
+ EFI_FILE_DIRECTORY and EFI_FILE_ARCHIVE.
+
+ @retval EFI_SUCCESS The file was open.
+ @retval EFI_NOT_FOUND The specified file could not be found.
+ @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.
+ @retval EFI_WRITE_PROTECTED Attempt to create a directory. This is not possible
+ with the semi-hosting interface.
+ @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.
+
+**/
EFI_STATUS
FileOpen (
- IN EFI_FILE *File,
+ IN EFI_FILE *This,
OUT EFI_FILE **NewHandle,
IN CHAR16 *FileName,
IN UINT64 OpenMode,