]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPkg/Filesystem/SemihostFs/Arm/SemihostFs.c
ArmPkg/SemihostFs: Make the driver more compliant with the UEFI specification
[mirror_edk2.git] / ArmPkg / Filesystem / SemihostFs / Arm / SemihostFs.c
index b04e866a995f405f131961b86bb8e6e8a9fcd803..5f1159d81a74060d10faae0a430d4aae06b2a4ed 100644 (file)
@@ -2,7 +2,7 @@
   Support a Semi Host file system over a debuggers JTAG\r
 \r
   Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
   Support a Semi Host file system over a debuggers JTAG\r
 \r
   Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
-  Portions copyright (c) 2011-2013, ARM Ltd. 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
 \r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
@@ -18,6 +18,7 @@
 \r
 #include <Guid/FileInfo.h>\r
 #include <Guid/FileSystemInfo.h>\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 <Library/BaseLib.h>\r
 #include <Library/BaseMemoryLib.h> \r
@@ -32,6 +33,9 @@
 \r
 #include "SemihostFs.h"\r
 \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
 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gSemihostFs = {\r
   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,\r
@@ -69,13 +73,15 @@ SEMIHOST_DEVICE_PATH gDevicePath = {
 };\r
 \r
 typedef struct {\r
 };\r
 \r
 typedef struct {\r
-  LIST_ENTRY  Link;\r
-  UINT64      Signature;\r
-  EFI_FILE    File;\r
-  CHAR8       *FileName;\r
-  UINT32      Position;\r
-  UINTN       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
 } SEMIHOST_FCB;\r
 \r
 #define SEMIHOST_FCB_SIGNATURE      SIGNATURE_32( 'S', 'H', 'F', 'C' )\r
@@ -134,6 +140,7 @@ VolumeOpen (
   }\r
   \r
   RootFcb->IsRoot = TRUE;\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
   InsertTailList (&gFileList, &RootFcb->Link);\r
 \r
@@ -157,11 +164,17 @@ FileOpen (
   CHAR8         *AsciiFileName;\r
   UINT32        SemihostMode;\r
   BOOLEAN       IsRoot;\r
   CHAR8         *AsciiFileName;\r
   UINT32        SemihostMode;\r
   BOOLEAN       IsRoot;\r
+  UINTN         Length;\r
 \r
   if ((FileName == NULL) || (NewHandle == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \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
+  }\r
+\r
   // Semihost interface requires ASCII filenames\r
   AsciiFileName = AllocatePool ((StrLen (FileName) + 1) * sizeof (CHAR8));\r
   if (AsciiFileName == NULL) {\r
   // Semihost interface requires ASCII filenames\r
   AsciiFileName = AllocatePool ((StrLen (FileName) + 1) * sizeof (CHAR8));\r
   if (AsciiFileName == NULL) {\r
@@ -213,6 +226,18 @@ FileOpen (
   FileFcb->SemihostHandle = SemihostHandle;\r
   FileFcb->Position       = 0;\r
   FileFcb->IsRoot         = IsRoot;\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
   InsertTailList (&gFileList, &FileFcb->Link);\r
 \r
@@ -271,8 +296,11 @@ FileDelete (
 \r
     // Call the semihost interface to delete the file.\r
     Status = SemihostFileRemove (FileName);\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
   } else {\r
-    Status = EFI_UNSUPPORTED;\r
+    Status = EFI_WARN_DELETE_FAILURE;\r
   }\r
 \r
   return Status;\r
   }\r
 \r
   return Status;\r
@@ -316,6 +344,11 @@ FileWrite (
 \r
   Fcb = SEMIHOST_FCB_FROM_THIS(File);\r
 \r
 \r
   Fcb = SEMIHOST_FCB_FROM_THIS(File);\r
 \r
+  // We cannot write a read-only file\r
+  if (Fcb->OpenMode & EFI_FILE_READ_ONLY) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
   Status = SemihostFileWrite (Fcb->SemihostHandle, &WriteSize, Buffer);\r
 \r
   if (!EFI_ERROR(Status)) {\r
   Status = SemihostFileWrite (Fcb->SemihostHandle, &WriteSize, Buffer);\r
 \r
   if (!EFI_ERROR(Status)) {\r
@@ -388,8 +421,6 @@ GetFileInfo (
   UINTN           NameSize = 0;\r
   UINTN           ResultSize;\r
   UINTN           Index;\r
   UINTN           NameSize = 0;\r
   UINTN           ResultSize;\r
   UINTN           Index;\r
-  UINTN           Length;\r
-  EFI_STATUS      Status;\r
 \r
   if (Fcb->IsRoot == TRUE) {\r
     ResultSize = SIZE_OF_EFI_FILE_INFO + sizeof(CHAR16);\r
 \r
   if (Fcb->IsRoot == TRUE) {\r
     ResultSize = SIZE_OF_EFI_FILE_INFO + sizeof(CHAR16);\r
@@ -405,30 +436,20 @@ GetFileInfo (
 \r
   Info = Buffer;\r
 \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
 \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
     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
     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
   *BufferSize = ResultSize;    \r
 \r
   return EFI_SUCCESS;\r
@@ -444,10 +465,9 @@ GetFilesystemInfo (
 {\r
   EFI_FILE_SYSTEM_INFO    *Info = NULL;\r
   EFI_STATUS              Status;\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
     \r
-  if(*BufferSize >= ResultSize) {\r
+  if (*BufferSize >= ResultSize) {\r
     ZeroMem (Buffer, ResultSize);\r
     Status = EFI_SUCCESS;\r
         \r
     ZeroMem (Buffer, ResultSize);\r
     Status = EFI_SUCCESS;\r
         \r
@@ -459,7 +479,7 @@ GetFilesystemInfo (
     Info->FreeSpace  = 0;\r
     Info->BlockSize  = 0;\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
   } else {\r
     Status = EFI_BUFFER_TOO_SMALL;\r
   }\r
@@ -476,17 +496,31 @@ FileGetInfo (
   OUT    VOID     *Buffer\r
   )\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
   \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
+\r
   return Status;\r
 }\r
 \r
   return Status;\r
 }\r
 \r
@@ -498,7 +532,27 @@ FileSetInfo (
   IN VOID     *Buffer\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
 }\r
 \r
 EFI_STATUS\r
@@ -506,7 +560,19 @@ FileFlush (
   IN EFI_FILE *File\r
   )\r
 {\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
+      return EFI_ACCESS_DENIED;\r
+    } else {\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
 }\r
 \r
 EFI_STATUS\r
 }\r
 \r
 EFI_STATUS\r
@@ -515,17 +581,27 @@ SemihostFsEntryPoint (
   IN EFI_SYSTEM_TABLE     *SystemTable\r
   )\r
 {\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
 \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
     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
  \r
   return Status;\r
 }\r
-\r