/** @file

Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution.  The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php

THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.


**/

#include "Edb.h"


/**

  Display memory unit.

  @param  Address         - Memory Address
  @param  Width           - Memory Width

  @return Length of the memory unit

**/
UINTN
EdbDisplayMemoryUnit (
  IN UINTN           Address,
  IN EDB_DATA_WIDTH  Width
  )
{
  UINT8  Data8;
  UINT16 Data16;
  UINT32 Data32;
  UINT64 Data64;

  //
  // Print according to width
  //
  switch (Width) {
  case EdbWidthUint8:
    CopyMem (&Data8, (VOID *)Address, sizeof(UINT8));
    EDBPrint (L"%02x ", Data8);
    return sizeof(UINT8);
  case EdbWidthUint16:
    CopyMem (&Data16, (VOID *)Address, sizeof(UINT16));
    EDBPrint (L"%04x ", Data16);
    return sizeof(UINT16);
  case EdbWidthUint32:
    CopyMem (&Data32, (VOID *)Address, sizeof(UINT32));
    EDBPrint (L"%08x ", Data32);
    return sizeof(UINT32);
  case EdbWidthUint64:
    CopyMem (&Data64, (VOID *)Address, sizeof(UINT64));
    EDBPrint (L"%016lx ", Data64);
    return sizeof(UINT64);
  default:
    ASSERT (FALSE);
    break;
  }

  //
  // something wrong
  //
  return 0;
}

/**

  Display memory.

  @param  Address         - Memory Address
  @param  Count           - Memory Count
  @param  Width           - Memory Width

**/
VOID
EdbDisplayMemory (
  IN UINTN          Address,
  IN UINTN          Count,
  IN EDB_DATA_WIDTH Width
  )
{
  UINTN  LineNumber;
  UINTN  ByteNumber;
  UINTN  LineIndex;
  UINTN  ByteIndex;
  UINTN  NumberInLine;

  if (Count == 0) {
    return ;
  }

  //
  // Get line number and byte number
  //
  switch (Width) {
  case EdbWidthUint8:
    NumberInLine = 16;
    break;
  case EdbWidthUint16:
    NumberInLine = 8;
    break;
  case EdbWidthUint32:
    NumberInLine = 4;
    break;
  case EdbWidthUint64:
    NumberInLine = 2;
    break;
  default:
    return;
  }

  LineNumber = Count / NumberInLine;
  ByteNumber = Count % NumberInLine;
  if (ByteNumber == 0) {
    LineNumber -= 1;
    ByteNumber  = NumberInLine;
  }

  //
  // Print each line
  //
  for (LineIndex = 0; LineIndex < LineNumber; LineIndex++) {

    //
    // Break check
    //
    if (((LineIndex % EFI_DEBUGGER_LINE_NUMBER_IN_PAGE) == 0) &&
        (LineIndex != 0)) {
      if (SetPageBreak ()) {
        break;
      }
    }

    EDBPrint (EDB_PRINT_ADDRESS_FORMAT, (UINTN)Address);
    for (ByteIndex = 0; ByteIndex < NumberInLine; ByteIndex++) {
      Address += EdbDisplayMemoryUnit (Address, Width);
    }
    EDBPrint (L"\n");
  }

  //
  // Break check
  //
  if (((LineIndex % EFI_DEBUGGER_LINE_NUMBER_IN_PAGE) == 0) &&
      (LineIndex != 0)) {
    if (SetPageBreak ()) {
      return;
    }
  }

  //
  // Print last line
  //
  EDBPrint (EDB_PRINT_ADDRESS_FORMAT, (UINTN)Address);
  for (ByteIndex = 0; ByteIndex < ByteNumber; ByteIndex++) {
    Address += EdbDisplayMemoryUnit (Address, Width);
  }

  return ;
}

/**

  Entry memory.

  @param  Address         - Memory Address
  @param  Value           - Memory Value
  @param  Width           - Memory Width

**/
VOID
EdbEnterMemory (
  IN UINTN          Address,
  IN VOID           *Value,
  IN EDB_DATA_WIDTH Width
  )
{
  switch (Width) {
  case EdbWidthUint8:
    CopyMem ((VOID *)Address, Value, sizeof(UINT8));
    break;
  case EdbWidthUint16:
    CopyMem ((VOID *)Address, Value, sizeof(UINT16));
    break;
  case EdbWidthUint32:
    CopyMem ((VOID *)Address, Value, sizeof(UINT32));
    break;
  case EdbWidthUint64:
    CopyMem ((VOID *)Address, Value, sizeof(UINT64));
    break;
  default:
    break;
  }

  return ;
}

/**

  Get memory address and count.

  @param  CommandArg      - The argument for this command
  @param  Address         - Memory Address
  @param  Count           - Memory Count

  @retval EFI_SUCCESS           - memory address and count are got
  @retval EFI_INVALID_PARAMETER - something wrong

**/
EFI_STATUS
EdbGetMemoryAddressCount (
  IN CHAR16    *CommandArg,
  IN UINTN     *Address,
  IN UINTN     *Count
  )
{
  CHAR16       *CommandStr;
  UINTN        MemAddress;
  EFI_STATUS   Status;

  //
  // Get Address
  //
  CommandStr = CommandArg;
  if (CommandStr == NULL) {
    EDBPrint (L"Memory: Address error!\n");
    return EFI_INVALID_PARAMETER;
  }
  Status = Symboltoi (CommandStr, &MemAddress);
  if (EFI_ERROR (Status)) {
    if (Status == EFI_NOT_FOUND) {
      MemAddress = Xtoi(CommandStr);
    } else {
      //
      // Something wrong, let Symboltoi print error info.
      //
      EDBPrint (L"Command Argument error!\n");
      return EFI_INVALID_PARAMETER;
    }
  }
  *Address = MemAddress;

  //
  // Get Count
  //
  CommandStr = StrGetNextTokenLine (L" ");
  if (CommandStr == NULL) {
    *Count = 1;
  } else {
    *Count = Xtoi(CommandStr);
  }

  //
  // Done
  //
  return EFI_SUCCESS;
}

/**

  Get memory address and value.

  @param  CommandArg      - The argument for this command
  @param  Address         - Memory Address
  @param  Value           - Memory Value

  @retval EFI_SUCCESS           - memory address and value are got
  @retval EFI_INVALID_PARAMETER - something wrong

**/
EFI_STATUS
EdbGetMemoryAddressValue (
  IN CHAR16    *CommandArg,
  IN UINTN     *Address,
  IN UINT64    *Value
  )
{
  CHAR16       *CommandStr;
  UINTN        MemAddress;
  EFI_STATUS   Status;

  //
  // Get Address
  //
  CommandStr = CommandArg;
  if (CommandStr == NULL) {
    EDBPrint (L"Memory: Address error!\n");
    return EFI_INVALID_PARAMETER;
  }
  Status = Symboltoi (CommandStr, &MemAddress);
  if (EFI_ERROR (Status)) {
    if (Status == EFI_NOT_FOUND) {
      MemAddress = Xtoi(CommandStr);
    } else {
      //
      // Something wrong, let Symboltoi print error info.
      //
      EDBPrint (L"Command Argument error!\n");
      return EFI_INVALID_PARAMETER;
    }
  }
  *Address = MemAddress;

  //
  // Get Value
  //
  CommandStr = StrGetNextTokenLine (L" ");
  if (CommandStr == NULL) {
    EDBPrint (L"Memory: Value error!\n");
    return EFI_INVALID_PARAMETER;
  }
  *Value = LXtoi(CommandStr);

  //
  // Done
  //
  return EFI_SUCCESS;
}

/**

  Display memory.

  @param  CommandArg      - The argument for this command
  @param  Width           - Memory Width

  @retval EFI_DEBUG_RETURN   - formal return value

**/
EFI_DEBUG_STATUS
DebuggerMemoryDisplay (
  IN     CHAR16                    *CommandArg,
  IN     EDB_DATA_WIDTH            Width
  )
{
  EFI_STATUS Status;
  UINTN      Address;
  UINTN      Count;

  //
  // Get memory address and count
  //
  Status = EdbGetMemoryAddressCount (CommandArg, &Address, &Count);
  if (EFI_ERROR(Status)) {
    return EFI_DEBUG_CONTINUE;
  }

  //
  // Display memory
  //
  EdbDisplayMemory (Address, Count, Width);

  //
  // Done
  //
  return EFI_DEBUG_CONTINUE;
}

/**

  Enter memory.

  @param  CommandArg      - The argument for this command
  @param  Width           - Memory Width

  @retval EFI_DEBUG_RETURN   - formal return value

**/
EFI_DEBUG_STATUS
DebuggerMemoryEnter (
  IN     CHAR16                    *CommandArg,
  IN     EDB_DATA_WIDTH            Width
  )
{
  EFI_STATUS Status;
  UINTN      Address;
  UINT64     Value;

  //
  // Get memory address and value
  //
  Status = EdbGetMemoryAddressValue (CommandArg, &Address, &Value);
  if (EFI_ERROR(Status)) {
    return EFI_DEBUG_CONTINUE;
  }

  //
  // Enter memory
  //
  EdbEnterMemory (Address, &Value, Width);

  //
  // Done
  //
  return EFI_DEBUG_CONTINUE;
}

/**

  DebuggerCommand - DB.

  @param  CommandArg      - The argument for this command
  @param  DebuggerPrivate - EBC Debugger private data structure
  @param  ExceptionType   - Interrupt type.
  @param  SystemContext   - EBC system context.

  @retval EFI_DEBUG_RETURN   - formal return value

**/
EFI_DEBUG_STATUS
DebuggerMemoryDB (
  IN     CHAR16                    *CommandArg,
  IN     EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
  IN     EFI_EXCEPTION_TYPE        ExceptionType,
  IN OUT EFI_SYSTEM_CONTEXT        SystemContext
  )
{
  return DebuggerMemoryDisplay (CommandArg, EdbWidthUint8);
}

/**

  DebuggerCommand - DW.

  @param  CommandArg      - The argument for this command
  @param  DebuggerPrivate - EBC Debugger private data structure
  @param  ExceptionType   - Interrupt type.
  @param  SystemContext   - EBC system context.

  @retval EFI_DEBUG_RETURN   - formal return value

**/
EFI_DEBUG_STATUS
DebuggerMemoryDW (
  IN     CHAR16                    *CommandArg,
  IN     EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
  IN     EFI_EXCEPTION_TYPE        ExceptionType,
  IN OUT EFI_SYSTEM_CONTEXT        SystemContext
  )
{
  return DebuggerMemoryDisplay (CommandArg, EdbWidthUint16);
}

/**

  DebuggerCommand - DD.

  @param  CommandArg      - The argument for this command
  @param  DebuggerPrivate - EBC Debugger private data structure
  @param  ExceptionType   - Interrupt type.
  @param  SystemContext   - EBC system context.

  @retval EFI_DEBUG_RETURN   - formal return value

**/
EFI_DEBUG_STATUS
DebuggerMemoryDD (
  IN     CHAR16                    *CommandArg,
  IN     EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
  IN     EFI_EXCEPTION_TYPE        ExceptionType,
  IN OUT EFI_SYSTEM_CONTEXT        SystemContext
  )
{
  return DebuggerMemoryDisplay (CommandArg, EdbWidthUint32);
}

/**

  DebuggerCommand - DQ.

  @param  CommandArg      - The argument for this command
  @param  DebuggerPrivate - EBC Debugger private data structure
  @param  ExceptionType   - Exception type.
  @param  SystemContext   - EBC system context.

  @retval EFI_DEBUG_RETURN   - formal return value

**/
EFI_DEBUG_STATUS
DebuggerMemoryDQ (
  IN     CHAR16                    *CommandArg,
  IN     EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
  IN     EFI_EXCEPTION_TYPE        ExceptionType,
  IN OUT EFI_SYSTEM_CONTEXT        SystemContext
  )
{
  return DebuggerMemoryDisplay (CommandArg, EdbWidthUint64);
}

/**

  DebuggerCommand - EB.

  @param  CommandArg      - The argument for this command
  @param  DebuggerPrivate - EBC Debugger private data structure
  @param  ExceptionType   - Exception type.
  @param  SystemContext   - EBC system context.

  @retval EFI_DEBUG_RETURN   - formal return value

**/
EFI_DEBUG_STATUS
DebuggerMemoryEB (
  IN     CHAR16                    *CommandArg,
  IN     EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
  IN     EFI_EXCEPTION_TYPE        ExceptionType,
  IN OUT EFI_SYSTEM_CONTEXT        SystemContext
  )
{
  return DebuggerMemoryEnter (CommandArg, EdbWidthUint8);
}

/**

  DebuggerCommand - EW.

  @param  CommandArg      - The argument for this command
  @param  DebuggerPrivate - EBC Debugger private data structure
  @param  ExceptionType   - Interrupt type.
  @param  SystemContext   - EBC system context.

  @retval EFI_DEBUG_RETURN   - formal return value

**/
EFI_DEBUG_STATUS
DebuggerMemoryEW (
  IN     CHAR16                    *CommandArg,
  IN     EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
  IN     EFI_EXCEPTION_TYPE        ExceptionType,
  IN OUT EFI_SYSTEM_CONTEXT        SystemContext
  )
{
  return DebuggerMemoryEnter (CommandArg, EdbWidthUint16);
}

/**

  DebuggerCommand - ED.

  @param  CommandArg      - The argument for this command
  @param  DebuggerPrivate - EBC Debugger private data structure
  @param  ExceptionType   - Exception type.
  @param  SystemContext   - EBC system context.

  @retval EFI_DEBUG_RETURN   - formal return value

**/
EFI_DEBUG_STATUS
DebuggerMemoryED (
  IN     CHAR16                    *CommandArg,
  IN     EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
  IN     EFI_EXCEPTION_TYPE        ExceptionType,
  IN OUT EFI_SYSTEM_CONTEXT        SystemContext
  )
{
  return DebuggerMemoryEnter (CommandArg, EdbWidthUint32);
}

/**

  DebuggerCommand - EQ.

  @param  CommandArg      - The argument for this command
  @param  DebuggerPrivate - EBC Debugger private data structure
  @param  ExceptionType   - Exception type.
  @param  SystemContext   - EBC system context.

  @retval EFI_DEBUG_RETURN   - formal return value

**/
EFI_DEBUG_STATUS
DebuggerMemoryEQ (
  IN     CHAR16                    *CommandArg,
  IN     EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
  IN     EFI_EXCEPTION_TYPE        ExceptionType,
  IN OUT EFI_SYSTEM_CONTEXT        SystemContext
  )
{
  return DebuggerMemoryEnter (CommandArg, EdbWidthUint64);
}
