};\r
\r
//\r
-// Device path for SemiHosting. It contains our autogened Caller ID GUID.\r
+// Device path for semi-hosting. It contains our autogened Caller ID GUID.\r
//\r
typedef struct {\r
VENDOR_DEVICE_PATH Guid;\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Open a file on the host system by means of the semihosting interface.\r
+\r
+ @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is\r
+ the file handle to source location.\r
+ @param[out] NewHandle A pointer to the location to return the opened\r
+ handle for the new file.\r
+ @param[in] FileName The Null-terminated string of the name of the file\r
+ to be opened.\r
+ @param[in] OpenMode The mode to open the file : Read or Read/Write or\r
+ Read/Write/Create\r
+ @param[in] Attributes Only valid for EFI_FILE_MODE_CREATE, in which case these\r
+ are the attribute bits for the newly created file. The\r
+ mnemonics of the attribute bits are : EFI_FILE_READ_ONLY,\r
+ EFI_FILE_HIDDEN, EFI_FILE_SYSTEM, EFI_FILE_RESERVED,\r
+ EFI_FILE_DIRECTORY and EFI_FILE_ARCHIVE.\r
+\r
+ @retval EFI_SUCCESS The file was open.\r
+ @retval EFI_NOT_FOUND The specified file could not be found.\r
+ @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.\r
+ @retval EFI_WRITE_PROTECTED Attempt to create a directory. This is not possible\r
+ with the semi-hosting interface.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.\r
+ @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.\r
+\r
+**/\r
EFI_STATUS\r
FileOpen (\r
- IN EFI_FILE *File,\r
- OUT EFI_FILE **NewHandle,\r
- IN CHAR16 *FileName,\r
- IN UINT64 OpenMode,\r
- IN UINT64 Attributes\r
+ IN EFI_FILE *This,\r
+ OUT EFI_FILE **NewHandle,\r
+ IN CHAR16 *FileName,\r
+ IN UINT64 OpenMode,\r
+ IN UINT64 Attributes\r
)\r
{\r
- SEMIHOST_FCB *FileFcb = NULL;\r
- EFI_STATUS Status = EFI_SUCCESS;\r
- UINTN SemihostHandle;\r
- CHAR8 *AsciiFileName;\r
- UINT32 SemihostMode;\r
- BOOLEAN IsRoot;\r
- UINTN Length;\r
+ SEMIHOST_FCB *FileFcb;\r
+ RETURN_STATUS Return;\r
+ EFI_STATUS Status;\r
+ UINTN SemihostHandle;\r
+ CHAR8 *AsciiFileName;\r
+ UINT32 SemihostMode;\r
+ UINTN Length;\r
\r
if ((FileName == NULL) || (NewHandle == NULL)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- // Semihosting does not support directories\r
- if (Attributes & EFI_FILE_DIRECTORY) {\r
- return EFI_UNSUPPORTED;\r
+ if ( (OpenMode != EFI_FILE_MODE_READ) &&\r
+ (OpenMode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE)) &&\r
+ (OpenMode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE)) ) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((OpenMode & EFI_FILE_MODE_CREATE) &&\r
+ (Attributes & EFI_FILE_DIRECTORY) ) {\r
+ return EFI_WRITE_PROTECTED;\r
}\r
\r
- // Semihost interface requires ASCII filenames\r
- AsciiFileName = AllocatePool ((StrLen (FileName) + 1) * sizeof (CHAR8));\r
+ AsciiFileName = AllocatePool (StrLen (FileName) + 1);\r
if (AsciiFileName == NULL) {\r
return EFI_OUT_OF_RESOURCES;\r
}\r
UnicodeStrToAsciiStr (FileName, AsciiFileName);\r
\r
+ // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory\r
if ((AsciiStrCmp (AsciiFileName, "\\") == 0) ||\r
(AsciiStrCmp (AsciiFileName, "/") == 0) ||\r
(AsciiStrCmp (AsciiFileName, "") == 0) ||\r
- (AsciiStrCmp (AsciiFileName, ".") == 0)) {\r
- // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory\r
- IsRoot = TRUE;\r
-\r
- // Root directory node doesn't have a name.\r
+ (AsciiStrCmp (AsciiFileName, ".") == 0) ) {\r
FreePool (AsciiFileName);\r
- AsciiFileName = NULL;\r
+ return (VolumeOpen (&gSemihostFs, NewHandle));\r
+ }\r
+\r
+ //\r
+ // No control is done here concerning the file path. It is passed\r
+ // as it is to the host operating system through the semi-hosting\r
+ // interface. We first try to open the file in the read or update\r
+ // mode even if the file creation has been asked for. That way, if\r
+ // the file already exists, it is not truncated to zero length. In\r
+ // write mode (bit SEMIHOST_FILE_MODE_WRITE up), if the file already\r
+ // exists, it is reset to an empty file.\r
+ //\r
+ if (OpenMode == EFI_FILE_MODE_READ) {\r
+ SemihostMode = SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY;\r
} else {\r
- // Translate EFI_FILE_MODE into Semihosting mode\r
- if (OpenMode & EFI_FILE_MODE_WRITE) {\r
- SemihostMode = SEMIHOST_FILE_MODE_WRITE | SEMIHOST_FILE_MODE_BINARY;\r
- } else if (OpenMode & EFI_FILE_MODE_READ) {\r
- SemihostMode = SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY;\r
- } else {\r
- return EFI_UNSUPPORTED;\r
- }\r
+ SemihostMode = SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY | SEMIHOST_FILE_MODE_UPDATE;\r
+ }\r
+ Return = SemihostFileOpen (AsciiFileName, SemihostMode, &SemihostHandle);\r
\r
- // Add the creation flag if necessary\r
+ if (RETURN_ERROR (Return)) {\r
if (OpenMode & EFI_FILE_MODE_CREATE) {\r
- SemihostMode |= SEMIHOST_FILE_MODE_UPDATE;\r
- }\r
-\r
- // Call the semihosting interface to open the file.\r
- Status = SemihostFileOpen (AsciiFileName, SemihostMode, &SemihostHandle);\r
- if (EFI_ERROR(Status)) {\r
- return Status;\r
+ //\r
+ // In the create if does not exist case, if the opening in update\r
+ // mode failed, create it and open it in update mode. The update\r
+ // mode allows for both read and write from and to the file.\r
+ //\r
+ Return = SemihostFileOpen (\r
+ AsciiFileName,\r
+ SEMIHOST_FILE_MODE_WRITE | SEMIHOST_FILE_MODE_BINARY | SEMIHOST_FILE_MODE_UPDATE,\r
+ &SemihostHandle\r
+ );\r
+ if (RETURN_ERROR (Return)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Error;\r
+ }\r
+ } else {\r
+ Status = EFI_NOT_FOUND;\r
+ goto Error;\r
}\r
-\r
- IsRoot = FALSE;\r
}\r
\r
// Allocate a control block and fill it\r
FileFcb = AllocateFCB ();\r
if (FileFcb == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error;\r
}\r
\r
FileFcb->FileName = AsciiFileName;\r
FileFcb->SemihostHandle = SemihostHandle;\r
FileFcb->Position = 0;\r
- FileFcb->IsRoot = IsRoot;\r
+ FileFcb->IsRoot = 0;\r
FileFcb->OpenMode = OpenMode;\r
\r
- if (!IsRoot) {\r
- Status = SemihostFileLength (SemihostHandle, &Length);\r
- if (EFI_ERROR(Status)) {\r
- return Status;\r
- }\r
-\r
- FileFcb->Info.FileSize = Length;\r
- FileFcb->Info.PhysicalSize = Length;\r
- FileFcb->Info.Attribute = Attributes;\r
+ Return = SemihostFileLength (SemihostHandle, &Length);\r
+ if (RETURN_ERROR (Return)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ FreeFCB (FileFcb);\r
+ goto Error;\r
}\r
\r
+ FileFcb->Info.FileSize = Length;\r
+ FileFcb->Info.PhysicalSize = Length;\r
+ FileFcb->Info.Attribute = (OpenMode & EFI_FILE_MODE_CREATE) ? Attributes : 0;\r
+\r
InsertTailList (&gFileList, &FileFcb->Link);\r
\r
*NewHandle = &FileFcb->File;\r
\r
+ return EFI_SUCCESS;\r
+\r
+Error:\r
+\r
+ FreePool (AsciiFileName);\r
+\r
return Status;\r
}\r
\r