/** @file\r
Support a Semi Host file system over a debuggers JTAG\r
\r
- Copyright (c) 2008-2009, Apple Inc. All rights reserved.\r
- \r
- All rights reserved. This program and the accompanying materials\r
+ Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
+ Portions copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
which accompanies this distribution. The full text of the license may be found at\r
http://opensource.org/licenses/bsd-license.php\r
\r
#include <Guid/FileInfo.h>\r
#include <Guid/FileSystemInfo.h>\r
+#include <Guid/FileSystemVolumeLabelInfo.h>\r
\r
#include <Library/BaseLib.h>\r
#include <Library/BaseMemoryLib.h> \r
\r
#include "SemihostFs.h"\r
\r
+#define DEFAULT_SEMIHOST_FS_LABEL L"SemihostFs"\r
+\r
+STATIC CHAR16 *mSemihostFsLabel;\r
\r
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gSemihostFs = {\r
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,\r
};\r
\r
typedef struct {\r
- LIST_ENTRY Link;\r
- UINT64 Signature;\r
- EFI_FILE File;\r
- CHAR8 *FileName;\r
- UINT32 Position;\r
- UINT32 SemihostHandle;\r
- BOOLEAN IsRoot;\r
+ LIST_ENTRY Link;\r
+ UINT64 Signature;\r
+ EFI_FILE File;\r
+ CHAR8 *FileName;\r
+ UINT64 OpenMode;\r
+ UINT32 Position;\r
+ UINTN SemihostHandle;\r
+ BOOLEAN IsRoot;\r
+ EFI_FILE_INFO Info;\r
} SEMIHOST_FCB;\r
\r
#define SEMIHOST_FCB_SIGNATURE SIGNATURE_32( 'S', 'H', 'F', 'C' )\r
}\r
\r
RootFcb->IsRoot = TRUE;\r
+ RootFcb->Info.Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;\r
\r
InsertTailList (&gFileList, &RootFcb->Link);\r
\r
{\r
SEMIHOST_FCB *FileFcb = NULL;\r
EFI_STATUS Status = EFI_SUCCESS;\r
- UINT32 SemihostHandle;\r
+ UINTN SemihostHandle;\r
CHAR8 *AsciiFileName;\r
- CHAR8 *AsciiPtr;\r
- UINTN Length;\r
UINT32 SemihostMode;\r
BOOLEAN IsRoot;\r
+ UINTN Length;\r
\r
if ((FileName == NULL) || (NewHandle == NULL)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- // Semihost interface requires ASCII filesnames\r
- Length = StrSize (FileName);\r
+ // Semihosting does not support directories\r
+ if (Attributes & EFI_FILE_DIRECTORY) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
\r
- AsciiFileName = AllocatePool (Length);\r
+ // Semihost interface requires ASCII filenames\r
+ AsciiFileName = AllocatePool ((StrLen (FileName) + 1) * sizeof (CHAR8));\r
if (AsciiFileName == NULL) {\r
return EFI_OUT_OF_RESOURCES;\r
}\r
+ UnicodeStrToAsciiStr (FileName, AsciiFileName);\r
\r
- AsciiPtr = AsciiFileName;\r
-\r
- while (Length--) {\r
- *AsciiPtr++ = *FileName++ & 0xFF;\r
- }\r
-\r
- if ((AsciiStrCmp (AsciiFileName, "\\") == 0) || (AsciiStrCmp (AsciiFileName, "/") == 0) || (AsciiStrCmp (AsciiFileName, "") == 0)) {\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
FileFcb->SemihostHandle = SemihostHandle;\r
FileFcb->Position = 0;\r
FileFcb->IsRoot = IsRoot;\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
+ }\r
\r
InsertTailList (&gFileList, &FileFcb->Link);\r
\r
\r
Fcb = SEMIHOST_FCB_FROM_THIS(File);\r
\r
- // Get the filename from the Fcb\r
- NameSize = AsciiStrLen (Fcb->FileName);\r
- FileName = AllocatePool (NameSize + 1);\r
+ if (!Fcb->IsRoot) {\r
+ // Get the filename from the Fcb\r
+ NameSize = AsciiStrLen (Fcb->FileName);\r
+ FileName = AllocatePool (NameSize + 1);\r
\r
- AsciiStrCpy (FileName, Fcb->FileName);\r
+ AsciiStrCpy (FileName, Fcb->FileName);\r
\r
- // Close the file if it's open. Disregard return status,\r
- // since it might give an error if the file isn't open.\r
- File->Close (File);\r
- \r
- // Call the semihost interface to delete the file.\r
- Status = SemihostFileRemove (FileName);\r
+ // Close the file if it's open. Disregard return status,\r
+ // since it might give an error if the file isn't open.\r
+ File->Close (File);\r
+\r
+ // Call the semihost interface to delete the file.\r
+ Status = SemihostFileRemove (FileName);\r
+ if (EFI_ERROR(Status)) {\r
+ Status = EFI_WARN_DELETE_FAILURE;\r
+ }\r
+ } else {\r
+ Status = EFI_WARN_DELETE_FAILURE;\r
+ }\r
\r
return Status;\r
}\r
Fcb = SEMIHOST_FCB_FROM_THIS(File);\r
\r
if (Fcb->IsRoot == TRUE) {\r
+ // By design, the Semihosting feature does not allow to list files on the host machine.\r
Status = EFI_UNSUPPORTED;\r
} else {\r
Status = SemihostFileRead (Fcb->SemihostHandle, BufferSize, Buffer);\r
\r
Fcb = SEMIHOST_FCB_FROM_THIS(File);\r
\r
+ // We cannot write a read-only file\r
+ if ((Fcb->Info.Attribute & EFI_FILE_READ_ONLY)\r
+ || !(Fcb->OpenMode & EFI_FILE_MODE_WRITE)) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
Status = SemihostFileWrite (Fcb->SemihostHandle, &WriteSize, Buffer);\r
\r
if (!EFI_ERROR(Status)) {\r
)\r
{\r
SEMIHOST_FCB *Fcb = NULL;\r
- UINT32 Length;\r
+ UINTN Length;\r
EFI_STATUS Status;\r
\r
Fcb = SEMIHOST_FCB_FROM_THIS(File);\r
\r
- Status = SemihostFileLength (Fcb->SemihostHandle, &Length);\r
- if (!EFI_ERROR(Status) && (Length < Position)) {\r
- Position = Length;\r
- }\r
+ if (!Fcb->IsRoot) {\r
+ Status = SemihostFileLength (Fcb->SemihostHandle, &Length);\r
+ if (!EFI_ERROR(Status) && (Length < Position)) {\r
+ Position = Length;\r
+ }\r
\r
- Status = SemihostFileSeek (Fcb->SemihostHandle, (UINT32)Position);\r
- if (!EFI_ERROR(Status)) {\r
+ Status = SemihostFileSeek (Fcb->SemihostHandle, (UINT32)Position);\r
+ if (!EFI_ERROR(Status)) {\r
+ Fcb->Position = Position;\r
+ }\r
+ } else {\r
Fcb->Position = Position;\r
+ Status = EFI_SUCCESS;\r
}\r
\r
return Status;\r
UINTN NameSize = 0;\r
UINTN ResultSize;\r
UINTN Index;\r
- UINT32 Length;\r
- EFI_STATUS Status;\r
\r
if (Fcb->IsRoot == TRUE) {\r
ResultSize = SIZE_OF_EFI_FILE_INFO + sizeof(CHAR16);\r
\r
Info = Buffer;\r
\r
- // Zero out the structure\r
- ZeroMem (Info, SIZE_OF_EFI_FILE_INFO);\r
+ // Copy the current file info\r
+ CopyMem (Info, &Fcb->Info, SIZE_OF_EFI_FILE_INFO);\r
\r
// Fill in the structure\r
Info->Size = ResultSize;\r
\r
if (Fcb->IsRoot == TRUE) {\r
- Info->Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;\r
Info->FileName[0] = L'\0';\r
} else {\r
- Status = SemihostFileLength (Fcb->SemihostHandle, &Length);\r
- if (EFI_ERROR(Status)) {\r
- return Status;\r
- }\r
-\r
- Info->FileSize = Length;\r
- Info->PhysicalSize = Length;\r
-\r
for (Index = 0; Index < NameSize; Index++) {\r
Info->FileName[Index] = Fcb->FileName[Index]; \r
}\r
}\r
\r
-\r
*BufferSize = ResultSize; \r
\r
return EFI_SUCCESS;\r
{\r
EFI_FILE_SYSTEM_INFO *Info = NULL;\r
EFI_STATUS Status;\r
- STATIC CHAR16 Label[] = L"SemihostFs";\r
- UINTN ResultSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize(Label);\r
+ UINTN ResultSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (mSemihostFsLabel);\r
\r
- if(*BufferSize >= ResultSize) {\r
+ if (*BufferSize >= ResultSize) {\r
ZeroMem (Buffer, ResultSize);\r
Status = EFI_SUCCESS;\r
\r
Info->FreeSpace = 0;\r
Info->BlockSize = 0;\r
\r
- StrCpy (Info->VolumeLabel, Label);\r
+ StrCpy (Info->VolumeLabel, mSemihostFsLabel);\r
} else {\r
Status = EFI_BUFFER_TOO_SMALL;\r
}\r
OUT VOID *Buffer\r
)\r
{\r
- SEMIHOST_FCB *Fcb = NULL;\r
- EFI_STATUS Status = EFI_UNSUPPORTED;\r
+ SEMIHOST_FCB *Fcb;\r
+ EFI_STATUS Status;\r
+ UINTN ResultSize;\r
\r
Fcb = SEMIHOST_FCB_FROM_THIS(File);\r
\r
- if (CompareGuid(InformationType, &gEfiFileSystemInfoGuid) != 0) {\r
- Status = GetFilesystemInfo(Fcb, BufferSize, Buffer); \r
- } else if (CompareGuid(InformationType, &gEfiFileInfoGuid) != 0) {\r
- Status = GetFileInfo(Fcb, BufferSize, Buffer); \r
+ if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid) != 0) {\r
+ Status = GetFilesystemInfo (Fcb, BufferSize, Buffer);\r
+ } else if (CompareGuid (InformationType, &gEfiFileInfoGuid) != 0) {\r
+ Status = GetFileInfo (Fcb, BufferSize, Buffer);\r
+ } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid) != 0) {\r
+ ResultSize = StrSize (mSemihostFsLabel);\r
+\r
+ if (*BufferSize >= ResultSize) {\r
+ StrCpy (Buffer, mSemihostFsLabel);\r
+ Status = EFI_SUCCESS;\r
+ } else {\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ *BufferSize = ResultSize;\r
+ } else {\r
+ Status = EFI_UNSUPPORTED;\r
}\r
- \r
+\r
return Status;\r
}\r
\r
IN VOID *Buffer\r
)\r
{\r
- return EFI_UNSUPPORTED;\r
+ EFI_STATUS Status;\r
+\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = EFI_UNSUPPORTED;\r
+\r
+ if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid) != 0) {\r
+ //Status = SetFilesystemInfo (Fcb, BufferSize, Buffer);\r
+ } else if (CompareGuid (InformationType, &gEfiFileInfoGuid) != 0) {\r
+ //Status = SetFileInfo (Fcb, BufferSize, Buffer);\r
+ } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid) != 0) {\r
+ if (StrSize (Buffer) > 0) {\r
+ FreePool (mSemihostFsLabel);\r
+ mSemihostFsLabel = AllocateCopyPool (StrSize (Buffer), Buffer);\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ return Status;\r
}\r
\r
EFI_STATUS\r
IN EFI_FILE *File\r
)\r
{\r
- return EFI_SUCCESS;\r
+ SEMIHOST_FCB *Fcb;\r
+\r
+ Fcb = SEMIHOST_FCB_FROM_THIS(File);\r
+\r
+ if (Fcb->IsRoot) {\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ if ((Fcb->Info.Attribute & EFI_FILE_READ_ONLY)\r
+ || !(Fcb->OpenMode & EFI_FILE_MODE_WRITE)) {\r
+ return EFI_ACCESS_DENIED;\r
+ } else {\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
}\r
\r
EFI_STATUS\r
IN EFI_SYSTEM_TABLE *SystemTable\r
)\r
{\r
- EFI_STATUS Status = EFI_NOT_FOUND;\r
+ EFI_STATUS Status;\r
+\r
+ Status = EFI_NOT_FOUND;\r
\r
if (SemihostConnectionSupported ()) {\r
+ mSemihostFsLabel = AllocateCopyPool (StrSize (DEFAULT_SEMIHOST_FS_LABEL), DEFAULT_SEMIHOST_FS_LABEL);\r
+ if (mSemihostFsLabel == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
Status = gBS->InstallMultipleProtocolInterfaces (\r
&gInstallHandle, \r
&gEfiSimpleFileSystemProtocolGuid, &gSemihostFs, \r
&gEfiDevicePathProtocolGuid, &gDevicePath,\r
NULL\r
);\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ FreePool (mSemihostFsLabel);\r
+ }\r
}\r
\r
return Status;\r
}\r
-\r