Fix various typos in ArmPkg. Signed-off-by: Coeur <coeur@gmx.fr> Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
		
			
				
	
	
		
			1204 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1204 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Support a Semi Host file system over a debuggers JTAG
 | 
						|
 | 
						|
  Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
 | 
						|
  Portions copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
 | 
						|
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include <Uefi.h>
 | 
						|
 | 
						|
#include <Guid/FileInfo.h>
 | 
						|
#include <Guid/FileSystemInfo.h>
 | 
						|
#include <Guid/FileSystemVolumeLabelInfo.h>
 | 
						|
 | 
						|
#include <Library/BaseLib.h>
 | 
						|
#include <Library/BaseMemoryLib.h>
 | 
						|
#include <Library/DebugLib.h>
 | 
						|
#include <Library/MemoryAllocationLib.h>
 | 
						|
#include <Library/SemihostLib.h>
 | 
						|
#include <Library/UefiBootServicesTableLib.h>
 | 
						|
#include <Library/UefiLib.h>
 | 
						|
 | 
						|
#include <Protocol/DevicePath.h>
 | 
						|
#include <Protocol/SimpleFileSystem.h>
 | 
						|
 | 
						|
#include "SemihostFs.h"
 | 
						|
 | 
						|
#define DEFAULT_SEMIHOST_FS_LABEL   L"SemihostFs"
 | 
						|
 | 
						|
STATIC CHAR16 *mSemihostFsLabel;
 | 
						|
 | 
						|
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gSemihostFs = {
 | 
						|
  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
 | 
						|
  VolumeOpen
 | 
						|
};
 | 
						|
 | 
						|
EFI_FILE gSemihostFsFile = {
 | 
						|
  EFI_FILE_PROTOCOL_REVISION,
 | 
						|
  FileOpen,
 | 
						|
  FileClose,
 | 
						|
  FileDelete,
 | 
						|
  FileRead,
 | 
						|
  FileWrite,
 | 
						|
  FileGetPosition,
 | 
						|
  FileSetPosition,
 | 
						|
  FileGetInfo,
 | 
						|
  FileSetInfo,
 | 
						|
  FileFlush
 | 
						|
};
 | 
						|
 | 
						|
//
 | 
						|
// Device path for semi-hosting. It contains our autogened Caller ID GUID.
 | 
						|
//
 | 
						|
typedef struct {
 | 
						|
  VENDOR_DEVICE_PATH        Guid;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  End;
 | 
						|
} SEMIHOST_DEVICE_PATH;
 | 
						|
 | 
						|
SEMIHOST_DEVICE_PATH gDevicePath = {
 | 
						|
  {
 | 
						|
    { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0 } },
 | 
						|
    EFI_CALLER_ID_GUID
 | 
						|
  },
 | 
						|
  { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } }
 | 
						|
};
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  LIST_ENTRY    Link;
 | 
						|
  UINT64        Signature;
 | 
						|
  EFI_FILE      File;
 | 
						|
  CHAR8         *FileName;
 | 
						|
  UINT64        OpenMode;
 | 
						|
  UINT32        Position;
 | 
						|
  UINTN         SemihostHandle;
 | 
						|
  BOOLEAN       IsRoot;
 | 
						|
  EFI_FILE_INFO Info;
 | 
						|
} SEMIHOST_FCB;
 | 
						|
 | 
						|
#define SEMIHOST_FCB_SIGNATURE      SIGNATURE_32( 'S', 'H', 'F', 'C' )
 | 
						|
#define SEMIHOST_FCB_FROM_THIS(a)   CR(a, SEMIHOST_FCB, File, SEMIHOST_FCB_SIGNATURE)
 | 
						|
#define SEMIHOST_FCB_FROM_LINK(a)   CR(a, SEMIHOST_FCB, Link, SEMIHOST_FCB_SIGNATURE);
 | 
						|
 | 
						|
EFI_HANDLE  gInstallHandle = NULL;
 | 
						|
LIST_ENTRY  gFileList = INITIALIZE_LIST_HEAD_VARIABLE (gFileList);
 | 
						|
 | 
						|
SEMIHOST_FCB *
 | 
						|
AllocateFCB (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  SEMIHOST_FCB *Fcb = AllocateZeroPool (sizeof (SEMIHOST_FCB));
 | 
						|
 | 
						|
  if (Fcb != NULL) {
 | 
						|
    CopyMem (&Fcb->File, &gSemihostFsFile, sizeof (gSemihostFsFile));
 | 
						|
    Fcb->Signature = SEMIHOST_FCB_SIGNATURE;
 | 
						|
  }
 | 
						|
 | 
						|
  return Fcb;
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
FreeFCB (
 | 
						|
  IN SEMIHOST_FCB *Fcb
 | 
						|
  )
 | 
						|
{
 | 
						|
  // Remove Fcb from gFileList.
 | 
						|
  RemoveEntryList (&Fcb->Link);
 | 
						|
 | 
						|
  // To help debugging...
 | 
						|
  Fcb->Signature = 0;
 | 
						|
 | 
						|
  FreePool (Fcb);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
VolumeOpen (
 | 
						|
  IN  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
 | 
						|
  OUT EFI_FILE                        **Root
 | 
						|
  )
 | 
						|
{
 | 
						|
  SEMIHOST_FCB *RootFcb = NULL;
 | 
						|
 | 
						|
  if (Root == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  RootFcb = AllocateFCB ();
 | 
						|
  if (RootFcb == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  RootFcb->IsRoot = TRUE;
 | 
						|
  RootFcb->Info.Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;
 | 
						|
 | 
						|
  InsertTailList (&gFileList, &RootFcb->Link);
 | 
						|
 | 
						|
  *Root = &RootFcb->File;
 | 
						|
 | 
						|
  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  *This,
 | 
						|
  OUT EFI_FILE  **NewHandle,
 | 
						|
  IN  CHAR16    *FileName,
 | 
						|
  IN  UINT64    OpenMode,
 | 
						|
  IN  UINT64    Attributes
 | 
						|
  )
 | 
						|
{
 | 
						|
  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;
 | 
						|
  }
 | 
						|
 | 
						|
  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;
 | 
						|
  }
 | 
						|
 | 
						|
  Length = StrLen (FileName) + 1;
 | 
						|
  AsciiFileName = AllocatePool (Length);
 | 
						|
  if (AsciiFileName == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
  UnicodeStrToAsciiStrS (FileName, AsciiFileName, Length);
 | 
						|
 | 
						|
  // 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)    ) {
 | 
						|
    FreePool (AsciiFileName);
 | 
						|
    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 {
 | 
						|
    SemihostMode = SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY | SEMIHOST_FILE_MODE_UPDATE;
 | 
						|
  }
 | 
						|
  Return = SemihostFileOpen (AsciiFileName, SemihostMode, &SemihostHandle);
 | 
						|
 | 
						|
  if (RETURN_ERROR (Return)) {
 | 
						|
    if (OpenMode & EFI_FILE_MODE_CREATE) {
 | 
						|
      //
 | 
						|
      // 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;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // Allocate a control block and fill it
 | 
						|
  FileFcb = AllocateFCB ();
 | 
						|
  if (FileFcb == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto Error;
 | 
						|
  }
 | 
						|
 | 
						|
  FileFcb->FileName       = AsciiFileName;
 | 
						|
  FileFcb->SemihostHandle = SemihostHandle;
 | 
						|
  FileFcb->Position       = 0;
 | 
						|
  FileFcb->IsRoot         = 0;
 | 
						|
  FileFcb->OpenMode       = OpenMode;
 | 
						|
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Worker function that truncate a file specified by its name to a given size.
 | 
						|
 | 
						|
  @param[in]  FileName  The Null-terminated string of the name of the file to be opened.
 | 
						|
  @param[in]  Size      The target size for the file.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS       The file was truncated.
 | 
						|
  @retval  EFI_DEVICE_ERROR  The last issued semi-hosting operation failed.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
TruncateFile (
 | 
						|
  IN CHAR8  *FileName,
 | 
						|
  IN UINTN   Size
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS     Status;
 | 
						|
  RETURN_STATUS  Return;
 | 
						|
  UINTN          FileHandle;
 | 
						|
  UINT8          *Buffer;
 | 
						|
  UINTN          Remaining;
 | 
						|
  UINTN          Read;
 | 
						|
  UINTN          ToRead;
 | 
						|
 | 
						|
  Status     = EFI_DEVICE_ERROR;
 | 
						|
  FileHandle = 0;
 | 
						|
  Buffer     = NULL;
 | 
						|
 | 
						|
  Return = SemihostFileOpen (
 | 
						|
             FileName,
 | 
						|
             SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY,
 | 
						|
             &FileHandle
 | 
						|
             );
 | 
						|
  if (RETURN_ERROR (Return)) {
 | 
						|
    goto Error;
 | 
						|
  }
 | 
						|
 | 
						|
  Buffer = AllocatePool (Size);
 | 
						|
  if (Buffer == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto Error;
 | 
						|
  }
 | 
						|
 | 
						|
  Read = 0;
 | 
						|
  Remaining = Size;
 | 
						|
  while (Remaining > 0) {
 | 
						|
    ToRead = Remaining;
 | 
						|
    Return = SemihostFileRead (FileHandle, &ToRead, Buffer + Read);
 | 
						|
    if (RETURN_ERROR (Return)) {
 | 
						|
      goto Error;
 | 
						|
    }
 | 
						|
    Remaining -= ToRead;
 | 
						|
    Read      += ToRead;
 | 
						|
  }
 | 
						|
 | 
						|
  Return = SemihostFileClose (FileHandle);
 | 
						|
  FileHandle = 0;
 | 
						|
  if (RETURN_ERROR (Return)) {
 | 
						|
    goto Error;
 | 
						|
  }
 | 
						|
 | 
						|
  Return = SemihostFileOpen (
 | 
						|
             FileName,
 | 
						|
             SEMIHOST_FILE_MODE_WRITE | SEMIHOST_FILE_MODE_BINARY,
 | 
						|
             &FileHandle
 | 
						|
             );
 | 
						|
  if (RETURN_ERROR (Return)) {
 | 
						|
    goto Error;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Size > 0) {
 | 
						|
    Return = SemihostFileWrite (FileHandle, &Size, Buffer);
 | 
						|
    if (RETURN_ERROR (Return)) {
 | 
						|
      goto Error;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
Error:
 | 
						|
 | 
						|
  if (FileHandle != 0) {
 | 
						|
    SemihostFileClose (FileHandle);
 | 
						|
  }
 | 
						|
  if (Buffer != NULL) {
 | 
						|
    FreePool (Buffer);
 | 
						|
  }
 | 
						|
 | 
						|
  return (Status);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Close a specified file handle.
 | 
						|
 | 
						|
  @param[in]  This  A pointer to the EFI_FILE_PROTOCOL instance that is the file
 | 
						|
                    handle to close.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS            The file was closed.
 | 
						|
  @retval  EFI_INVALID_PARAMETER  The parameter "This" is NULL.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FileClose (
 | 
						|
  IN EFI_FILE  *This
 | 
						|
  )
 | 
						|
{
 | 
						|
  SEMIHOST_FCB   *Fcb;
 | 
						|
 | 
						|
  if (This == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Fcb = SEMIHOST_FCB_FROM_THIS(This);
 | 
						|
 | 
						|
  if (!Fcb->IsRoot) {
 | 
						|
    SemihostFileClose (Fcb->SemihostHandle);
 | 
						|
    //
 | 
						|
    // The file size might have been reduced from its actual
 | 
						|
    // size on the host file system with FileSetInfo(). In
 | 
						|
    // that case, the file has to be truncated.
 | 
						|
    //
 | 
						|
    if (Fcb->Info.FileSize < Fcb->Info.PhysicalSize) {
 | 
						|
      TruncateFile (Fcb->FileName, Fcb->Info.FileSize);
 | 
						|
    }
 | 
						|
    FreePool (Fcb->FileName);
 | 
						|
  }
 | 
						|
 | 
						|
  FreeFCB (Fcb);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Close and delete a file.
 | 
						|
 | 
						|
  @param[in]  This  A pointer to the EFI_FILE_PROTOCOL instance that is the file
 | 
						|
                    handle to delete.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS              The file was closed and deleted.
 | 
						|
  @retval  EFI_WARN_DELETE_FAILURE  The handle was closed, but the file was not deleted.
 | 
						|
  @retval  EFI_INVALID_PARAMETER    The parameter "This" is NULL.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FileDelete (
 | 
						|
  IN EFI_FILE *This
 | 
						|
  )
 | 
						|
{
 | 
						|
  SEMIHOST_FCB   *Fcb;
 | 
						|
  RETURN_STATUS  Return;
 | 
						|
  CHAR8          *FileName;
 | 
						|
  UINTN          NameSize;
 | 
						|
 | 
						|
  if (This == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Fcb = SEMIHOST_FCB_FROM_THIS (This);
 | 
						|
 | 
						|
  if (!Fcb->IsRoot) {
 | 
						|
    // Get the filename from the Fcb
 | 
						|
    NameSize = AsciiStrLen (Fcb->FileName);
 | 
						|
    FileName = AllocatePool (NameSize + 1);
 | 
						|
 | 
						|
    AsciiStrCpyS (FileName, NameSize + 1, Fcb->FileName);
 | 
						|
 | 
						|
    // Close the file if it's open.  Disregard return status,
 | 
						|
    // since it might give an error if the file isn't open.
 | 
						|
    This->Close (This);
 | 
						|
 | 
						|
    // Call the semihost interface to delete the file.
 | 
						|
    Return = SemihostFileRemove (FileName);
 | 
						|
    if (RETURN_ERROR (Return)) {
 | 
						|
      return EFI_WARN_DELETE_FAILURE;
 | 
						|
    }
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  } else {
 | 
						|
    return EFI_WARN_DELETE_FAILURE;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Read data from an open file.
 | 
						|
 | 
						|
  @param[in]      This        A pointer to the EFI_FILE_PROTOCOL instance that
 | 
						|
                              is the file handle to read data from.
 | 
						|
  @param[in out]  BufferSize  On input, the size of the Buffer. On output, the
 | 
						|
                              amount of data returned in Buffer. In both cases,
 | 
						|
                              the size is measured in bytes.
 | 
						|
  @param[out]     Buffer      The buffer into which the data is read.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS            The data was read.
 | 
						|
  @retval  EFI_DEVICE_ERROR       On entry, the current file position is
 | 
						|
                                  beyond the end of the file, or the semi-hosting
 | 
						|
                                  interface reported an error while performing the
 | 
						|
                                  read operation.
 | 
						|
  @retval  EFI_INVALID_PARAMETER  At least one of the three input pointers is NULL.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FileRead (
 | 
						|
  IN     EFI_FILE  *This,
 | 
						|
  IN OUT UINTN     *BufferSize,
 | 
						|
  OUT    VOID      *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  SEMIHOST_FCB   *Fcb;
 | 
						|
  EFI_STATUS     Status;
 | 
						|
  RETURN_STATUS  Return;
 | 
						|
 | 
						|
  if ((This == NULL) || (BufferSize == NULL) || (Buffer == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Fcb = SEMIHOST_FCB_FROM_THIS (This);
 | 
						|
 | 
						|
  if (Fcb->IsRoot) {
 | 
						|
    // The semi-hosting interface does not allow to list files on the host machine.
 | 
						|
    Status = EFI_UNSUPPORTED;
 | 
						|
  } else {
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
    if (Fcb->Position >= Fcb->Info.FileSize) {
 | 
						|
      *BufferSize = 0;
 | 
						|
      if (Fcb->Position > Fcb->Info.FileSize) {
 | 
						|
        Status = EFI_DEVICE_ERROR;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      Return = SemihostFileRead (Fcb->SemihostHandle, BufferSize, Buffer);
 | 
						|
      if (RETURN_ERROR (Return)) {
 | 
						|
        Status = EFI_DEVICE_ERROR;
 | 
						|
      } else {
 | 
						|
        Fcb->Position += *BufferSize;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Worker function that extends the size of an open file.
 | 
						|
 | 
						|
  The extension is filled with zeros.
 | 
						|
 | 
						|
  @param[in]  Fcb   Internal description of the opened file
 | 
						|
  @param[in]  Size  The number of bytes, the file has to be extended.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS       The file was extended.
 | 
						|
  @retval  EFI_DEVICE_ERROR  The last issued semi-hosting operation failed.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
ExtendFile (
 | 
						|
  IN  SEMIHOST_FCB  *Fcb,
 | 
						|
  IN  UINTN         Size
 | 
						|
  )
 | 
						|
{
 | 
						|
  RETURN_STATUS  Return;
 | 
						|
  UINTN          Remaining;
 | 
						|
  CHAR8          WriteBuffer[128];
 | 
						|
  UINTN          WriteNb;
 | 
						|
  UINTN          WriteSize;
 | 
						|
 | 
						|
  Return = SemihostFileSeek (Fcb->SemihostHandle, Fcb->Info.FileSize);
 | 
						|
  if (RETURN_ERROR (Return)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Remaining = Size;
 | 
						|
  SetMem (WriteBuffer, 0, sizeof(WriteBuffer));
 | 
						|
  while (Remaining > 0) {
 | 
						|
    WriteNb = MIN (Remaining, sizeof(WriteBuffer));
 | 
						|
    WriteSize = WriteNb;
 | 
						|
    Return = SemihostFileWrite (Fcb->SemihostHandle, &WriteSize, WriteBuffer);
 | 
						|
    if (RETURN_ERROR (Return)) {
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
    Remaining -= WriteNb;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Write data to an open file.
 | 
						|
 | 
						|
  @param[in]      This        A pointer to the EFI_FILE_PROTOCOL instance that
 | 
						|
                              is the file handle to write data to.
 | 
						|
  @param[in out]  BufferSize  On input, the size of the Buffer. On output, the
 | 
						|
                              size of the data actually written. In both cases,
 | 
						|
                              the size is measured in bytes.
 | 
						|
  @param[in]      Buffer      The buffer of data to write.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS            The data was written.
 | 
						|
  @retval  EFI_ACCESS_DENIED      Attempt to write into a read only file or
 | 
						|
                                  in a file opened in read only mode.
 | 
						|
  @retval  EFI_DEVICE_ERROR       The last issued semi-hosting operation failed.
 | 
						|
  @retval  EFI_INVALID_PARAMETER  At least one of the three input pointers is NULL.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FileWrite (
 | 
						|
  IN     EFI_FILE *This,
 | 
						|
  IN OUT UINTN    *BufferSize,
 | 
						|
  IN     VOID     *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  SEMIHOST_FCB   *Fcb;
 | 
						|
  EFI_STATUS     Status;
 | 
						|
  UINTN          WriteSize;
 | 
						|
  RETURN_STATUS  Return;
 | 
						|
  UINTN          Length;
 | 
						|
 | 
						|
  if ((This == NULL) || (BufferSize == NULL) || (Buffer == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Fcb = SEMIHOST_FCB_FROM_THIS (This);
 | 
						|
 | 
						|
  // We cannot write a read-only file
 | 
						|
  if ((Fcb->Info.Attribute & EFI_FILE_READ_ONLY)
 | 
						|
      || !(Fcb->OpenMode & EFI_FILE_MODE_WRITE)) {
 | 
						|
    return EFI_ACCESS_DENIED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If the position has been set past the end of the file, first grow the
 | 
						|
  // file from its current size "Fcb->Info.FileSize" to "Fcb->Position"
 | 
						|
  // size, filling the gap with zeros.
 | 
						|
  //
 | 
						|
  if (Fcb->Position > Fcb->Info.FileSize) {
 | 
						|
    Status = ExtendFile (Fcb, Fcb->Position - Fcb->Info.FileSize);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
    Fcb->Info.FileSize = Fcb->Position;
 | 
						|
  }
 | 
						|
 | 
						|
  WriteSize = *BufferSize;
 | 
						|
  Return = SemihostFileWrite (Fcb->SemihostHandle, &WriteSize, Buffer);
 | 
						|
  if (RETURN_ERROR (Return)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Fcb->Position += *BufferSize;
 | 
						|
  if (Fcb->Position > Fcb->Info.FileSize) {
 | 
						|
    Fcb->Info.FileSize = Fcb->Position;
 | 
						|
  }
 | 
						|
 | 
						|
  Return = SemihostFileLength (Fcb->SemihostHandle, &Length);
 | 
						|
  if (RETURN_ERROR (Return)) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
  Fcb->Info.PhysicalSize = Length;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return a file's current position.
 | 
						|
 | 
						|
  @param[in]   This      A pointer to the EFI_FILE_PROTOCOL instance that is
 | 
						|
                         the file handle to get the current position on.
 | 
						|
  @param[out]  Position  The address to return the file's current position value.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS            The position was returned.
 | 
						|
  @retval  EFI_INVALID_PARAMETER  The parameter "This" or "Position" is NULL.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FileGetPosition (
 | 
						|
  IN  EFI_FILE    *This,
 | 
						|
  OUT UINT64      *Position
 | 
						|
  )
 | 
						|
{
 | 
						|
  SEMIHOST_FCB *Fcb;
 | 
						|
 | 
						|
  if ((This == NULL) || (Position == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Fcb = SEMIHOST_FCB_FROM_THIS(This);
 | 
						|
 | 
						|
  *Position = Fcb->Position;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Set a file's current position.
 | 
						|
 | 
						|
  @param[in]  This      A pointer to the EFI_FILE_PROTOCOL instance that is
 | 
						|
                        the file handle to set the requested position on.
 | 
						|
  @param[in]  Position  The byte position from the start of the file to set.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS       The position was set.
 | 
						|
  @retval  EFI_DEVICE_ERROR  The semi-hosting positioning operation failed.
 | 
						|
  @retval  EFI_UNSUPPORTED   The seek request for nonzero is not valid on open
 | 
						|
                             directories.
 | 
						|
  @retval  EFI_INVALID_PARAMETER  The parameter "This" is NULL.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FileSetPosition (
 | 
						|
  IN EFI_FILE *This,
 | 
						|
  IN UINT64   Position
 | 
						|
  )
 | 
						|
{
 | 
						|
  SEMIHOST_FCB   *Fcb;
 | 
						|
  RETURN_STATUS  Return;
 | 
						|
 | 
						|
  if (This == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Fcb = SEMIHOST_FCB_FROM_THIS (This);
 | 
						|
 | 
						|
  if (Fcb->IsRoot) {
 | 
						|
    if (Position != 0) {
 | 
						|
      return EFI_UNSUPPORTED;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    //
 | 
						|
    // UEFI Spec section 12.5:
 | 
						|
    // "Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to
 | 
						|
    // be set to the end of the file."
 | 
						|
    //
 | 
						|
    if (Position == 0xFFFFFFFFFFFFFFFF) {
 | 
						|
      Position = Fcb->Info.FileSize;
 | 
						|
    }
 | 
						|
    Return = SemihostFileSeek (Fcb->SemihostHandle, MIN (Position, Fcb->Info.FileSize));
 | 
						|
    if (RETURN_ERROR (Return)) {
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Fcb->Position = Position;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return information about a file.
 | 
						|
 | 
						|
  @param[in]      Fcb         A pointer to the description of an open file.
 | 
						|
  @param[in out]  BufferSize  The size, in bytes, of Buffer.
 | 
						|
  @param[out]     Buffer      A pointer to the data buffer to return. Not NULL if
 | 
						|
                              "*BufferSize" is greater than 0.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS            The information was returned.
 | 
						|
  @retval  EFI_BUFFER_TOO_SMALL   The BufferSize is too small to return the information.
 | 
						|
                                  BufferSize has been updated with the size needed to
 | 
						|
                                  complete the request.
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
GetFileInfo (
 | 
						|
  IN     SEMIHOST_FCB  *Fcb,
 | 
						|
  IN OUT UINTN         *BufferSize,
 | 
						|
  OUT    VOID          *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_FILE_INFO   *Info = NULL;
 | 
						|
  UINTN           NameSize = 0;
 | 
						|
  UINTN           ResultSize;
 | 
						|
  UINTN           Index;
 | 
						|
 | 
						|
  if (Fcb->IsRoot == TRUE) {
 | 
						|
    ResultSize = SIZE_OF_EFI_FILE_INFO + sizeof(CHAR16);
 | 
						|
  } else {
 | 
						|
    NameSize   = AsciiStrLen (Fcb->FileName) + 1;
 | 
						|
    ResultSize = SIZE_OF_EFI_FILE_INFO + NameSize * sizeof (CHAR16);
 | 
						|
  }
 | 
						|
 | 
						|
  if (*BufferSize < ResultSize) {
 | 
						|
    *BufferSize = ResultSize;
 | 
						|
    return EFI_BUFFER_TOO_SMALL;
 | 
						|
  }
 | 
						|
 | 
						|
  Info = Buffer;
 | 
						|
 | 
						|
  // Copy the current file info
 | 
						|
  CopyMem (Info, &Fcb->Info, SIZE_OF_EFI_FILE_INFO);
 | 
						|
 | 
						|
  // Fill in the structure
 | 
						|
  Info->Size = ResultSize;
 | 
						|
 | 
						|
  if (Fcb->IsRoot == TRUE) {
 | 
						|
    Info->FileName[0]  = L'\0';
 | 
						|
  } else {
 | 
						|
    for (Index = 0; Index < NameSize; Index++) {
 | 
						|
      Info->FileName[Index] = Fcb->FileName[Index];
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  *BufferSize = ResultSize;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return information about a file system.
 | 
						|
 | 
						|
  @param[in]      Fcb         A pointer to the description of an open file
 | 
						|
                              which belongs to the file system, the information
 | 
						|
                              is requested for.
 | 
						|
  @param[in out]  BufferSize  The size, in bytes, of Buffer.
 | 
						|
  @param[out]     Buffer      A pointer to the data buffer to return. Not NULL if
 | 
						|
                              "*BufferSize" is greater than 0.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS            The information was returned.
 | 
						|
  @retval  EFI_BUFFER_TOO_SMALL   The BufferSize is too small to return the information.
 | 
						|
                                  BufferSize has been updated with the size needed to
 | 
						|
                                  complete the request.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
GetFilesystemInfo (
 | 
						|
  IN     SEMIHOST_FCB *Fcb,
 | 
						|
  IN OUT UINTN        *BufferSize,
 | 
						|
  OUT    VOID         *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_FILE_SYSTEM_INFO  *Info;
 | 
						|
  EFI_STATUS            Status;
 | 
						|
  UINTN                 ResultSize;
 | 
						|
  UINTN                 StringSize;
 | 
						|
 | 
						|
  StringSize = StrSize (mSemihostFsLabel);
 | 
						|
  ResultSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StringSize;
 | 
						|
 | 
						|
  if (*BufferSize >= ResultSize) {
 | 
						|
    ZeroMem (Buffer, ResultSize);
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
 | 
						|
    Info = Buffer;
 | 
						|
 | 
						|
    Info->Size       = ResultSize;
 | 
						|
    Info->ReadOnly   = FALSE;
 | 
						|
    Info->VolumeSize = 0;
 | 
						|
    Info->FreeSpace  = 0;
 | 
						|
    Info->BlockSize  = 0;
 | 
						|
 | 
						|
    CopyMem (Info->VolumeLabel, mSemihostFsLabel, StringSize);
 | 
						|
  } else {
 | 
						|
    Status = EFI_BUFFER_TOO_SMALL;
 | 
						|
  }
 | 
						|
 | 
						|
  *BufferSize = ResultSize;
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Return information about a file or a file system.
 | 
						|
 | 
						|
  @param[in]      This             A pointer to the EFI_FILE_PROTOCOL instance that
 | 
						|
                                   is the file handle the requested information is for.
 | 
						|
  @param[in]      InformationType  The type identifier for the information being requested :
 | 
						|
                                   EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or
 | 
						|
                                   EFI_FILE_SYSTEM_VOLUME_LABEL_ID
 | 
						|
  @param[in out]  BufferSize       The size, in bytes, of Buffer.
 | 
						|
  @param[out]     Buffer           A pointer to the data buffer to return. The type of the
 | 
						|
                                   data inside the buffer is indicated by InformationType.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS           The information was returned.
 | 
						|
  @retval  EFI_UNSUPPORTED       The InformationType is not known.
 | 
						|
  @retval  EFI_BUFFER_TOO_SMALL  The BufferSize is too small to return the information.
 | 
						|
                                 BufferSize has been updated with the size needed to
 | 
						|
                                 complete the request.
 | 
						|
  @retval  EFI_INVALID_PARAMETER  The parameter "This" or "InformationType" or "BufferSize"
 | 
						|
                                  is NULL or "Buffer" is NULL and "*Buffersize" is greater
 | 
						|
                                  than 0.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FileGetInfo (
 | 
						|
  IN     EFI_FILE  *This,
 | 
						|
  IN     EFI_GUID  *InformationType,
 | 
						|
  IN OUT UINTN     *BufferSize,
 | 
						|
  OUT    VOID      *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  SEMIHOST_FCB *Fcb;
 | 
						|
  EFI_STATUS   Status;
 | 
						|
  UINTN        ResultSize;
 | 
						|
 | 
						|
  if ((This == NULL)                         ||
 | 
						|
      (InformationType == NULL)              ||
 | 
						|
      (BufferSize == NULL)                   ||
 | 
						|
      ((Buffer == NULL) && (*BufferSize > 0))  ) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Fcb = SEMIHOST_FCB_FROM_THIS(This);
 | 
						|
 | 
						|
  if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
 | 
						|
    Status = GetFilesystemInfo (Fcb, BufferSize, Buffer);
 | 
						|
  } else if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
 | 
						|
    Status = GetFileInfo (Fcb, BufferSize, Buffer);
 | 
						|
  } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
 | 
						|
    ResultSize = StrSize (mSemihostFsLabel);
 | 
						|
 | 
						|
    if (*BufferSize >= ResultSize) {
 | 
						|
      CopyMem (Buffer, mSemihostFsLabel, ResultSize);
 | 
						|
      Status = EFI_SUCCESS;
 | 
						|
    } else {
 | 
						|
      Status = EFI_BUFFER_TOO_SMALL;
 | 
						|
    }
 | 
						|
 | 
						|
    *BufferSize = ResultSize;
 | 
						|
  } else {
 | 
						|
    Status = EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Set information about a file.
 | 
						|
 | 
						|
  @param[in]  Fcb   A pointer to the description of the open file.
 | 
						|
  @param[in]  Info  A pointer to the file information to write.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS           The information was set.
 | 
						|
  @retval  EFI_ACCESS_DENIED     An attempt is made to change the name of a file
 | 
						|
                                 to a file that is already present.
 | 
						|
  @retval  EFI_ACCESS_DENIED     An attempt is being made to change the
 | 
						|
                                 EFI_FILE_DIRECTORY Attribute.
 | 
						|
  @retval  EFI_ACCESS_DENIED     The file is a read-only file or has been
 | 
						|
                                 opened in read-only mode and an attempt is
 | 
						|
                                 being made to modify a field other than
 | 
						|
                                 Attribute.
 | 
						|
  @retval  EFI_WRITE_PROTECTED   An attempt is being made to modify a
 | 
						|
                                 read-only attribute.
 | 
						|
  @retval  EFI_DEVICE_ERROR      The last issued semi-hosting operation failed.
 | 
						|
  @retval  EFI_OUT_OF_RESOURCES  A allocation needed to process the request failed.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
SetFileInfo (
 | 
						|
  IN  SEMIHOST_FCB   *Fcb,
 | 
						|
  IN  EFI_FILE_INFO  *Info
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS     Status;
 | 
						|
  RETURN_STATUS  Return;
 | 
						|
  BOOLEAN        FileSizeIsDifferent;
 | 
						|
  BOOLEAN        FileNameIsDifferent;
 | 
						|
  BOOLEAN        ReadOnlyIsDifferent;
 | 
						|
  CHAR8          *AsciiFileName;
 | 
						|
  UINTN          FileSize;
 | 
						|
  UINTN          Length;
 | 
						|
  UINTN          SemihostHandle;
 | 
						|
 | 
						|
  //
 | 
						|
  // A directory can not be changed to a file and a file can
 | 
						|
  // not be changed to a directory.
 | 
						|
  //
 | 
						|
  if (((Info->Attribute & EFI_FILE_DIRECTORY) != 0) != Fcb->IsRoot) {
 | 
						|
    return EFI_ACCESS_DENIED;
 | 
						|
  }
 | 
						|
 | 
						|
  Length = StrLen (Info->FileName) + 1;
 | 
						|
  AsciiFileName = AllocatePool (Length);
 | 
						|
  if (AsciiFileName == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
  UnicodeStrToAsciiStrS (Info->FileName, AsciiFileName, Length);
 | 
						|
 | 
						|
  FileSizeIsDifferent = (Info->FileSize != Fcb->Info.FileSize);
 | 
						|
  FileNameIsDifferent = (AsciiStrCmp (AsciiFileName, Fcb->FileName) != 0);
 | 
						|
  ReadOnlyIsDifferent = CompareMem (
 | 
						|
                          &Info->CreateTime,
 | 
						|
                          &Fcb->Info.CreateTime,
 | 
						|
                          3 * sizeof (EFI_TIME)
 | 
						|
                          ) != 0;
 | 
						|
 | 
						|
  //
 | 
						|
  // For a read-only file or a file opened in read-only mode, only
 | 
						|
  // the Attribute field can be modified. As the root directory is
 | 
						|
  // read-only (i.e. VolumeOpen()), this protects the root directory
 | 
						|
  // description.
 | 
						|
  //
 | 
						|
  if ((Fcb->OpenMode == EFI_FILE_MODE_READ)     ||
 | 
						|
      (Fcb->Info.Attribute & EFI_FILE_READ_ONLY)  ) {
 | 
						|
    if (FileSizeIsDifferent || FileNameIsDifferent || ReadOnlyIsDifferent) {
 | 
						|
      Status = EFI_ACCESS_DENIED;
 | 
						|
      goto Error;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (ReadOnlyIsDifferent) {
 | 
						|
    Status = EFI_WRITE_PROTECTED;
 | 
						|
    goto Error;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = EFI_DEVICE_ERROR;
 | 
						|
 | 
						|
  if (FileSizeIsDifferent) {
 | 
						|
    FileSize = Info->FileSize;
 | 
						|
    if (Fcb->Info.FileSize < FileSize) {
 | 
						|
      Status = ExtendFile (Fcb, FileSize - Fcb->Info.FileSize);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // The read/write position from the host file system point of view
 | 
						|
      // is at the end of the file. If the position from this module
 | 
						|
      // point of view is smaller than the new file size, then
 | 
						|
      // ask the host file system to move to that position.
 | 
						|
      //
 | 
						|
      if (Fcb->Position < FileSize) {
 | 
						|
        FileSetPosition (&Fcb->File, Fcb->Position);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    Fcb->Info.FileSize = FileSize;
 | 
						|
 | 
						|
    Return = SemihostFileLength (Fcb->SemihostHandle, &Length);
 | 
						|
    if (RETURN_ERROR (Return)) {
 | 
						|
      goto Error;
 | 
						|
    }
 | 
						|
    Fcb->Info.PhysicalSize = Length;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Note down in RAM the Attribute field but we can not ask
 | 
						|
  // for its modification to the host file system as the
 | 
						|
  // semi-host interface does not provide this feature.
 | 
						|
  //
 | 
						|
  Fcb->Info.Attribute = Info->Attribute;
 | 
						|
 | 
						|
  if (FileNameIsDifferent) {
 | 
						|
    Return = SemihostFileOpen (
 | 
						|
               AsciiFileName,
 | 
						|
               SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY,
 | 
						|
               &SemihostHandle
 | 
						|
               );
 | 
						|
    if (!RETURN_ERROR (Return)) {
 | 
						|
      SemihostFileClose (SemihostHandle);
 | 
						|
      Status = EFI_ACCESS_DENIED;
 | 
						|
      goto Error;
 | 
						|
    }
 | 
						|
 | 
						|
    Return = SemihostFileRename (Fcb->FileName, AsciiFileName);
 | 
						|
    if (RETURN_ERROR (Return)) {
 | 
						|
      goto Error;
 | 
						|
    }
 | 
						|
    FreePool (Fcb->FileName);
 | 
						|
    Fcb->FileName = AsciiFileName;
 | 
						|
    AsciiFileName = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
Error:
 | 
						|
  if (AsciiFileName != NULL) {
 | 
						|
    FreePool (AsciiFileName);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Set information about a file or a file system.
 | 
						|
 | 
						|
  @param[in]  This             A pointer to the EFI_FILE_PROTOCOL instance that
 | 
						|
                               is the file handle the information is for.
 | 
						|
  @param[in]  InformationType  The type identifier for the information being set :
 | 
						|
                               EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or
 | 
						|
                               EFI_FILE_SYSTEM_VOLUME_LABEL_ID
 | 
						|
  @param[in]  BufferSize       The size, in bytes, of Buffer.
 | 
						|
  @param[in]  Buffer           A pointer to the data buffer to write. The type of the
 | 
						|
                               data inside the buffer is indicated by InformationType.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS            The information was set.
 | 
						|
  @retval  EFI_UNSUPPORTED        The InformationType is not known.
 | 
						|
  @retval  EFI_DEVICE_ERROR       The last issued semi-hosting operation failed.
 | 
						|
  @retval  EFI_ACCESS_DENIED      An attempt is being made to change the
 | 
						|
                                  EFI_FILE_DIRECTORY Attribute.
 | 
						|
  @retval  EFI_ACCESS_DENIED      InformationType is EFI_FILE_INFO_ID and
 | 
						|
                                  the file is a read-only file or has been
 | 
						|
                                  opened in read-only mode and an attempt is
 | 
						|
                                  being made to modify a field other than
 | 
						|
                                  Attribute.
 | 
						|
  @retval  EFI_ACCESS_DENIED      An attempt is made to change the name of a file
 | 
						|
                                  to a file that is already present.
 | 
						|
  @retval  EFI_WRITE_PROTECTED    An attempt is being made to modify a
 | 
						|
                                  read-only attribute.
 | 
						|
  @retval  EFI_BAD_BUFFER_SIZE    The size of the buffer is lower than that indicated by
 | 
						|
                                  the data inside the buffer.
 | 
						|
  @retval  EFI_OUT_OF_RESOURCES   An allocation needed to process the request failed.
 | 
						|
  @retval  EFI_INVALID_PARAMETER  At least one of the parameters is invalid.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FileSetInfo (
 | 
						|
  IN EFI_FILE  *This,
 | 
						|
  IN EFI_GUID  *InformationType,
 | 
						|
  IN UINTN     BufferSize,
 | 
						|
  IN VOID      *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  SEMIHOST_FCB          *Fcb;
 | 
						|
  EFI_FILE_INFO         *Info;
 | 
						|
  EFI_FILE_SYSTEM_INFO  *SystemInfo;
 | 
						|
  CHAR16                *VolumeLabel;
 | 
						|
 | 
						|
  if ((This == NULL) || (InformationType == NULL) || (Buffer == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Fcb = SEMIHOST_FCB_FROM_THIS (This);
 | 
						|
 | 
						|
  if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
 | 
						|
    Info = Buffer;
 | 
						|
    if (Info->Size < (SIZE_OF_EFI_FILE_INFO + StrSize (Info->FileName))) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
    if (BufferSize < Info->Size) {
 | 
						|
      return EFI_BAD_BUFFER_SIZE;
 | 
						|
    }
 | 
						|
    return SetFileInfo (Fcb, Info);
 | 
						|
  } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
 | 
						|
    SystemInfo = Buffer;
 | 
						|
    if (SystemInfo->Size <
 | 
						|
        (SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (SystemInfo->VolumeLabel))) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
    if (BufferSize < SystemInfo->Size) {
 | 
						|
      return EFI_BAD_BUFFER_SIZE;
 | 
						|
    }
 | 
						|
    Buffer = SystemInfo->VolumeLabel;
 | 
						|
 | 
						|
    if (StrSize (Buffer) > 0) {
 | 
						|
      VolumeLabel = AllocateCopyPool (StrSize (Buffer), Buffer);
 | 
						|
      if (VolumeLabel != NULL) {
 | 
						|
        FreePool (mSemihostFsLabel);
 | 
						|
        mSemihostFsLabel = VolumeLabel;
 | 
						|
        return EFI_SUCCESS;
 | 
						|
      } else {
 | 
						|
        return EFI_OUT_OF_RESOURCES;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
  } else if (!CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  } else {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
FileFlush (
 | 
						|
  IN EFI_FILE *File
 | 
						|
  )
 | 
						|
{
 | 
						|
  SEMIHOST_FCB *Fcb;
 | 
						|
 | 
						|
  Fcb = SEMIHOST_FCB_FROM_THIS(File);
 | 
						|
 | 
						|
  if (Fcb->IsRoot) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  } else {
 | 
						|
    if ((Fcb->Info.Attribute & EFI_FILE_READ_ONLY)
 | 
						|
        || !(Fcb->OpenMode & EFI_FILE_MODE_WRITE)) {
 | 
						|
      return EFI_ACCESS_DENIED;
 | 
						|
    } else {
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
SemihostFsEntryPoint (
 | 
						|
  IN EFI_HANDLE           ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE     *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS    Status;
 | 
						|
 | 
						|
  Status = EFI_NOT_FOUND;
 | 
						|
 | 
						|
  if (SemihostConnectionSupported ()) {
 | 
						|
    mSemihostFsLabel = AllocateCopyPool (StrSize (DEFAULT_SEMIHOST_FS_LABEL), DEFAULT_SEMIHOST_FS_LABEL);
 | 
						|
    if (mSemihostFsLabel == NULL) {
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = gBS->InstallMultipleProtocolInterfaces (
 | 
						|
                    &gInstallHandle,
 | 
						|
                    &gEfiSimpleFileSystemProtocolGuid, &gSemihostFs,
 | 
						|
                    &gEfiDevicePathProtocolGuid,       &gDevicePath,
 | 
						|
                    NULL
 | 
						|
                    );
 | 
						|
 | 
						|
    if (EFI_ERROR(Status)) {
 | 
						|
      FreePool (mSemihostFsLabel);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 |