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
This commit is contained in:
Ronald Cron 2014-10-27 10:40:33 +00:00 committed by oliviermartin
parent 0f0a6fe907
commit fdd12bd569
2 changed files with 131 additions and 54 deletions

View File

@ -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 { typedef struct {
VENDOR_DEVICE_PATH Guid; VENDOR_DEVICE_PATH Guid;
@ -149,100 +149,151 @@ VolumeOpen (
return EFI_SUCCESS; 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 EFI_STATUS
FileOpen ( FileOpen (
IN EFI_FILE *File, IN EFI_FILE *This,
OUT EFI_FILE **NewHandle, OUT EFI_FILE **NewHandle,
IN CHAR16 *FileName, IN CHAR16 *FileName,
IN UINT64 OpenMode, IN UINT64 OpenMode,
IN UINT64 Attributes IN UINT64 Attributes
) )
{ {
SEMIHOST_FCB *FileFcb = NULL; SEMIHOST_FCB *FileFcb;
EFI_STATUS Status = EFI_SUCCESS; RETURN_STATUS Return;
EFI_STATUS Status;
UINTN SemihostHandle; UINTN SemihostHandle;
CHAR8 *AsciiFileName; CHAR8 *AsciiFileName;
UINT32 SemihostMode; UINT32 SemihostMode;
BOOLEAN IsRoot;
UINTN Length; UINTN Length;
if ((FileName == NULL) || (NewHandle == NULL)) { if ((FileName == NULL) || (NewHandle == NULL)) {
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
} }
// Semihosting does not support directories if ( (OpenMode != EFI_FILE_MODE_READ) &&
if (Attributes & EFI_FILE_DIRECTORY) { (OpenMode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE)) &&
return EFI_UNSUPPORTED; (OpenMode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE)) ) {
return EFI_INVALID_PARAMETER;
} }
// Semihost interface requires ASCII filenames if ((OpenMode & EFI_FILE_MODE_CREATE) &&
AsciiFileName = AllocatePool ((StrLen (FileName) + 1) * sizeof (CHAR8)); (Attributes & EFI_FILE_DIRECTORY) ) {
return EFI_WRITE_PROTECTED;
}
AsciiFileName = AllocatePool (StrLen (FileName) + 1);
if (AsciiFileName == NULL) { if (AsciiFileName == NULL) {
return EFI_OUT_OF_RESOURCES; return EFI_OUT_OF_RESOURCES;
} }
UnicodeStrToAsciiStr (FileName, AsciiFileName); UnicodeStrToAsciiStr (FileName, AsciiFileName);
// Opening '/', '\', '.', or the NULL pathname is trying to open the root directory
if ((AsciiStrCmp (AsciiFileName, "\\") == 0) || if ((AsciiStrCmp (AsciiFileName, "\\") == 0) ||
(AsciiStrCmp (AsciiFileName, "/") == 0) || (AsciiStrCmp (AsciiFileName, "/") == 0) ||
(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.
FreePool (AsciiFileName); FreePool (AsciiFileName);
AsciiFileName = NULL; return (VolumeOpen (&gSemihostFs, NewHandle));
} else { }
// Translate EFI_FILE_MODE into Semihosting mode
if (OpenMode & EFI_FILE_MODE_WRITE) { //
SemihostMode = SEMIHOST_FILE_MODE_WRITE | SEMIHOST_FILE_MODE_BINARY; // No control is done here concerning the file path. It is passed
} else if (OpenMode & EFI_FILE_MODE_READ) { // 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; SemihostMode = SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY;
} else { } 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) { if (OpenMode & EFI_FILE_MODE_CREATE) {
SemihostMode |= SEMIHOST_FILE_MODE_UPDATE; //
// 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 {
// Call the semihosting interface to open the file. Status = EFI_NOT_FOUND;
Status = SemihostFileOpen (AsciiFileName, SemihostMode, &SemihostHandle); goto Error;
if (EFI_ERROR(Status)) {
return Status;
} }
IsRoot = FALSE;
} }
// Allocate a control block and fill it // Allocate a control block and fill it
FileFcb = AllocateFCB (); FileFcb = AllocateFCB ();
if (FileFcb == NULL) { if (FileFcb == NULL) {
return EFI_OUT_OF_RESOURCES; Status = EFI_OUT_OF_RESOURCES;
goto Error;
} }
FileFcb->FileName = AsciiFileName; FileFcb->FileName = AsciiFileName;
FileFcb->SemihostHandle = SemihostHandle; FileFcb->SemihostHandle = SemihostHandle;
FileFcb->Position = 0; FileFcb->Position = 0;
FileFcb->IsRoot = IsRoot; FileFcb->IsRoot = 0;
FileFcb->OpenMode = OpenMode; FileFcb->OpenMode = OpenMode;
if (!IsRoot) { Return = SemihostFileLength (SemihostHandle, &Length);
Status = SemihostFileLength (SemihostHandle, &Length); if (RETURN_ERROR (Return)) {
if (EFI_ERROR(Status)) { Status = EFI_DEVICE_ERROR;
return Status; FreeFCB (FileFcb);
goto Error;
} }
FileFcb->Info.FileSize = Length; FileFcb->Info.FileSize = Length;
FileFcb->Info.PhysicalSize = Length; FileFcb->Info.PhysicalSize = Length;
FileFcb->Info.Attribute = Attributes; FileFcb->Info.Attribute = (OpenMode & EFI_FILE_MODE_CREATE) ? Attributes : 0;
}
InsertTailList (&gFileList, &FileFcb->Link); InsertTailList (&gFileList, &FileFcb->Link);
*NewHandle = &FileFcb->File; *NewHandle = &FileFcb->File;
return EFI_SUCCESS;
Error:
FreePool (AsciiFileName);
return Status; return Status;
} }

View File

@ -22,9 +22,35 @@ VolumeOpen (
OUT EFI_FILE **Root 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 EFI_STATUS
FileOpen ( FileOpen (
IN EFI_FILE *File, IN EFI_FILE *This,
OUT EFI_FILE **NewHandle, OUT EFI_FILE **NewHandle,
IN CHAR16 *FileName, IN CHAR16 *FileName,
IN UINT64 OpenMode, IN UINT64 OpenMode,