/** @file
  Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
  Copyright (c) 2013 - 2021, Arm Limited. All rights reserved.
  SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include 
#include 
#include 
#include "SemihostPrivate.h"
BOOLEAN
SemihostConnectionSupported (
  VOID
  )
{
  return SEMIHOST_SUPPORTED;
}
RETURN_STATUS
SemihostFileOpen (
  IN  CHAR8   *FileName,
  IN  UINT32  Mode,
  OUT UINTN   *FileHandle
  )
{
  SEMIHOST_FILE_OPEN_BLOCK  OpenBlock;
  INT32                     Result;
  if (FileHandle == NULL) {
    return RETURN_INVALID_PARAMETER;
  }
  // Remove any leading separator (e.g.: '\'). EFI Shell adds one.
  if (*FileName == '\\') {
    FileName++;
  }
  OpenBlock.FileName   = FileName;
  OpenBlock.Mode       = Mode;
  OpenBlock.NameLength = AsciiStrLen (FileName);
  Result = SEMIHOST_SYS_OPEN (&OpenBlock);
  if (Result == -1) {
    return RETURN_NOT_FOUND;
  } else {
    *FileHandle = Result;
    return RETURN_SUCCESS;
  }
}
RETURN_STATUS
SemihostFileSeek (
  IN UINTN  FileHandle,
  IN UINTN  Offset
  )
{
  SEMIHOST_FILE_SEEK_BLOCK  SeekBlock;
  INT32                     Result;
  SeekBlock.Handle   = FileHandle;
  SeekBlock.Location = Offset;
  Result = SEMIHOST_SYS_SEEK (&SeekBlock);
  // Semihosting does not behave as documented. It returns the offset on
  // success.
  if (Result < 0) {
    return RETURN_ABORTED;
  } else {
    return RETURN_SUCCESS;
  }
}
RETURN_STATUS
SemihostFileRead (
  IN     UINTN  FileHandle,
  IN OUT UINTN  *Length,
  OUT    VOID   *Buffer
  )
{
  SEMIHOST_FILE_READ_WRITE_BLOCK  ReadBlock;
  UINT32                          Result;
  if ((Length == NULL) || (Buffer == NULL)) {
    return RETURN_INVALID_PARAMETER;
  }
  ReadBlock.Handle = FileHandle;
  ReadBlock.Buffer = Buffer;
  ReadBlock.Length = *Length;
  Result = SEMIHOST_SYS_READ (&ReadBlock);
  if ((*Length != 0) && (Result == *Length)) {
    return RETURN_ABORTED;
  } else {
    *Length -= Result;
    return RETURN_SUCCESS;
  }
}
RETURN_STATUS
SemihostFileWrite (
  IN     UINTN  FileHandle,
  IN OUT UINTN  *Length,
  IN     VOID   *Buffer
  )
{
  SEMIHOST_FILE_READ_WRITE_BLOCK  WriteBlock;
  if ((Length == NULL) || (Buffer == NULL)) {
    return RETURN_INVALID_PARAMETER;
  }
  WriteBlock.Handle = FileHandle;
  WriteBlock.Buffer = Buffer;
  WriteBlock.Length = *Length;
  *Length = SEMIHOST_SYS_WRITE (&WriteBlock);
  if (*Length != 0) {
    return RETURN_ABORTED;
  } else {
    return RETURN_SUCCESS;
  }
}
RETURN_STATUS
SemihostFileClose (
  IN UINTN  FileHandle
  )
{
  if (SEMIHOST_SYS_CLOSE (&FileHandle) == -1) {
    return RETURN_INVALID_PARAMETER;
  } else {
    return RETURN_SUCCESS;
  }
}
RETURN_STATUS
SemihostFileLength (
  IN  UINTN  FileHandle,
  OUT UINTN  *Length
  )
{
  INT32  Result;
  if (Length == NULL) {
    return RETURN_INVALID_PARAMETER;
  }
  Result = SEMIHOST_SYS_FLEN (&FileHandle);
  if (Result == -1) {
    return RETURN_ABORTED;
  } else {
    *Length = Result;
    return RETURN_SUCCESS;
  }
}
/**
  Get a temporary name for a file from the host running the debug agent.
  @param[out]  Buffer      Pointer to the buffer where the temporary name has to
                           be stored
  @param[in]   Identifier  File name identifier (integer in the range 0 to 255)
  @param[in]   Length      Length of the buffer to store the temporary name
  @retval  RETURN_SUCCESS            Temporary name returned
  @retval  RETURN_INVALID_PARAMETER  Invalid buffer address
  @retval  RETURN_ABORTED            Temporary name not returned
**/
RETURN_STATUS
SemihostFileTmpName (
  OUT  VOID   *Buffer,
  IN   UINT8  Identifier,
  IN   UINTN  Length
  )
{
  SEMIHOST_FILE_TMPNAME_BLOCK  TmpNameBlock;
  INT32                        Result;
  if (Buffer == NULL) {
    return RETURN_INVALID_PARAMETER;
  }
  TmpNameBlock.Buffer     = Buffer;
  TmpNameBlock.Identifier = Identifier;
  TmpNameBlock.Length     = Length;
  Result = SEMIHOST_SYS_TMPNAME (&TmpNameBlock);
  if (Result != 0) {
    return RETURN_ABORTED;
  } else {
    return RETURN_SUCCESS;
  }
}
RETURN_STATUS
SemihostFileRemove (
  IN CHAR8  *FileName
  )
{
  SEMIHOST_FILE_REMOVE_BLOCK  RemoveBlock;
  UINT32                      Result;
  // Remove any leading separator (e.g.: '\'). EFI Shell adds one.
  if (*FileName == '\\') {
    FileName++;
  }
  RemoveBlock.FileName   = FileName;
  RemoveBlock.NameLength = AsciiStrLen (FileName);
  Result = SEMIHOST_SYS_REMOVE (&RemoveBlock);
  if (Result == 0) {
    return RETURN_SUCCESS;
  } else {
    return RETURN_ABORTED;
  }
}
/**
  Rename a specified file.
  @param[in]  FileName     Name of the file to rename.
  @param[in]  NewFileName  The new name of the file.
  @retval  RETURN_SUCCESS            File Renamed
  @retval  RETURN_INVALID_PARAMETER  Either the current or the new name is not specified
  @retval  RETURN_ABORTED            Rename failed
**/
RETURN_STATUS
SemihostFileRename (
  IN  CHAR8  *FileName,
  IN  CHAR8  *NewFileName
  )
{
  SEMIHOST_FILE_RENAME_BLOCK  RenameBlock;
  INT32                       Result;
  if ((FileName == NULL) || (NewFileName == NULL)) {
    return RETURN_INVALID_PARAMETER;
  }
  RenameBlock.FileName          = FileName;
  RenameBlock.FileNameLength    = AsciiStrLen (FileName);
  RenameBlock.NewFileName       = NewFileName;
  RenameBlock.NewFileNameLength = AsciiStrLen (NewFileName);
  Result = SEMIHOST_SYS_RENAME (&RenameBlock);
  if (Result != 0) {
    return RETURN_ABORTED;
  } else {
    return RETURN_SUCCESS;
  }
}
CHAR8
SemihostReadCharacter (
  VOID
  )
{
  return SEMIHOST_SYS_READC ();
}
VOID
SemihostWriteCharacter (
  IN CHAR8  Character
  )
{
  SEMIHOST_SYS_WRITEC (&Character);
}
VOID
SemihostWriteString (
  IN CHAR8  *String
  )
{
  SEMIHOST_SYS_WRITE0 (String);
}
UINT32
SemihostSystem (
  IN CHAR8  *CommandLine
  )
{
  SEMIHOST_SYSTEM_BLOCK  SystemBlock;
  SystemBlock.CommandLine   = CommandLine;
  SystemBlock.CommandLength = AsciiStrLen (CommandLine);
  return SEMIHOST_SYS_SYSTEM (&SystemBlock);
}