Replace tabs by spaces for indentation to comply to EDK2 coding standards. Done in files with extension ".S", ".c", ".h", ".asm", ".dsc", ".inc", "*.inf", "*.dec" or ".fdf" and located in ArmPkg, ArmPlatformPkg, EmbeddedPkg, BeagleBoardPkg or Omap35xxPkg. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ronald Cron <ronald.cron@arm.com> Reviewed-By: Olivier Martin <olivier.martin@arm.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15901 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			704 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			704 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						||
  Processor specific parts of the GDB stub
 | 
						||
 | 
						||
  Copyright (c) 2008 - 2009, Apple Inc. 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 <GdbStubInternal.h>
 | 
						||
#include <Library/CacheMaintenanceLib.h>
 | 
						||
#include <Library/PrintLib.h>
 | 
						||
 | 
						||
//
 | 
						||
// Array of exception types that need to be hooked by the debugger
 | 
						||
// (efi, gdb) //efi number
 | 
						||
//
 | 
						||
EFI_EXCEPTION_TYPE_ENTRY gExceptionType[] = {
 | 
						||
  { EXCEPT_ARM_SOFTWARE_INTERRUPT,  GDB_SIGTRAP }
 | 
						||
//  { EXCEPT_ARM_UNDEFINED_INSTRUCTION, GDB_SIGTRAP },
 | 
						||
//  { EXCEPT_ARM_PREFETCH_ABORT,        GDB_SIGTRAP },
 | 
						||
//  { EXCEPT_ARM_DATA_ABORT,            GDB_SIGEMT  },
 | 
						||
//  { EXCEPT_ARM_RESERVED,              GDB_SIGILL  }
 | 
						||
};
 | 
						||
 | 
						||
// Shut up some annoying RVCT warnings
 | 
						||
#ifdef __CC_ARM
 | 
						||
#pragma diag_suppress 1296
 | 
						||
#endif
 | 
						||
 | 
						||
UINTN gRegisterOffsets[] = {
 | 
						||
  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R0),
 | 
						||
  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R1),
 | 
						||
  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R2),
 | 
						||
  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R3),
 | 
						||
  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R4),
 | 
						||
  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R5),
 | 
						||
  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R6),
 | 
						||
  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R7),
 | 
						||
  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R8),
 | 
						||
  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R9),
 | 
						||
  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R10),
 | 
						||
  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R11),
 | 
						||
  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R12),
 | 
						||
  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, SP),
 | 
						||
  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, LR),
 | 
						||
  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, PC),
 | 
						||
  0x00000F01,                               // f0
 | 
						||
  0x00000F02,
 | 
						||
  0x00000F03,
 | 
						||
  0x00000F11,                               // f1
 | 
						||
  0x00000F12,
 | 
						||
  0x00000F13,
 | 
						||
  0x00000F21,                               // f2
 | 
						||
  0x00000F22,
 | 
						||
  0x00000F23,
 | 
						||
  0x00000F31,                               // f3
 | 
						||
  0x00000F32,
 | 
						||
  0x00000F33,
 | 
						||
  0x00000F41,                               // f4
 | 
						||
  0x00000F42,
 | 
						||
  0x00000F43,
 | 
						||
  0x00000F51,                               // f5
 | 
						||
  0x00000F52,
 | 
						||
  0x00000F53,
 | 
						||
  0x00000F61,                               // f6
 | 
						||
  0x00000F62,
 | 
						||
  0x00000F63,
 | 
						||
  0x00000F71,                               // f7
 | 
						||
  0x00000F72,
 | 
						||
  0x00000F73,
 | 
						||
  0x00000FFF,                               // fps
 | 
						||
  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, CPSR)
 | 
						||
};
 | 
						||
 | 
						||
// restore warnings for RVCT
 | 
						||
#ifdef __CC_ARM
 | 
						||
#pragma diag_default 1296
 | 
						||
#endif
 | 
						||
 | 
						||
/**
 | 
						||
 Return the number of entries in the gExceptionType[]
 | 
						||
 | 
						||
 @retval  UINTN, the number of entries in the gExceptionType[] array.
 | 
						||
 **/
 | 
						||
UINTN
 | 
						||
MaxEfiException (
 | 
						||
  VOID
 | 
						||
  )
 | 
						||
{
 | 
						||
  return sizeof (gExceptionType) / sizeof (EFI_EXCEPTION_TYPE_ENTRY);
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 Return the number of entries in the gRegisters[]
 | 
						||
 | 
						||
 @retval  UINTN, the number of entries (registers) in the gRegisters[] array.
 | 
						||
 **/
 | 
						||
UINTN
 | 
						||
MaxRegisterCount (
 | 
						||
  VOID
 | 
						||
  )
 | 
						||
{
 | 
						||
  return sizeof (gRegisterOffsets) / sizeof (UINTN);
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 Check to see if the ISA is supported.
 | 
						||
 ISA = Instruction Set Architecture
 | 
						||
 | 
						||
 @retval TRUE if Isa is supported
 | 
						||
 | 
						||
**/
 | 
						||
BOOLEAN
 | 
						||
CheckIsa (
 | 
						||
  IN  EFI_INSTRUCTION_SET_ARCHITECTURE  Isa
 | 
						||
  )
 | 
						||
{
 | 
						||
  if (Isa == IsaArm) {
 | 
						||
    return TRUE;
 | 
						||
  } else {
 | 
						||
    return FALSE;
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 This takes in the register number and the System Context, and returns a pointer to the RegNumber-th register in gdb ordering
 | 
						||
 It is, by default, set to find the register pointer of the ARM member
 | 
						||
 @param   SystemContext     Register content at time of the exception
 | 
						||
 @param   RegNumber       The register to which we want to find a pointer
 | 
						||
 @retval  the pointer to the RegNumber-th pointer
 | 
						||
 **/
 | 
						||
UINTN *
 | 
						||
FindPointerToRegister (
 | 
						||
  IN  EFI_SYSTEM_CONTEXT      SystemContext,
 | 
						||
  IN  UINTN           RegNumber
 | 
						||
  )
 | 
						||
{
 | 
						||
  UINT8 *TempPtr;
 | 
						||
  ASSERT(gRegisterOffsets[RegNumber] < 0xF00);
 | 
						||
  TempPtr = ((UINT8 *)SystemContext.SystemContextArm) + gRegisterOffsets[RegNumber];
 | 
						||
  return (UINT32 *)TempPtr;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
 | 
						||
 @param SystemContext     Register content at time of the exception
 | 
						||
 @param   RegNumber       the number of the register that we want to read
 | 
						||
 @param   OutBufPtr       pointer to the output buffer's end. the new data will be added from this point on.
 | 
						||
 @retval  the pointer to the next character of the output buffer that is available to be written on.
 | 
						||
 **/
 | 
						||
CHAR8 *
 | 
						||
BasicReadRegister (
 | 
						||
  IN  EFI_SYSTEM_CONTEXT  SystemContext,
 | 
						||
  IN  UINTN               RegNumber,
 | 
						||
  IN  CHAR8               *OutBufPtr
 | 
						||
  )
 | 
						||
{
 | 
						||
  UINTN RegSize;
 | 
						||
  CHAR8 Char;
 | 
						||
 | 
						||
  if (gRegisterOffsets[RegNumber] > 0xF00) {
 | 
						||
    AsciiSPrint (OutBufPtr, 9, "00000000");
 | 
						||
    OutBufPtr += 8;
 | 
						||
    return OutBufPtr;
 | 
						||
  }
 | 
						||
 | 
						||
  RegSize = 0;
 | 
						||
  while (RegSize < 32) {
 | 
						||
    Char = mHexToStr[(UINT8)((*FindPointerToRegister (SystemContext, RegNumber) >> (RegSize+4)) & 0xf)];
 | 
						||
    if ((Char >= 'A') && (Char <= 'F')) {
 | 
						||
      Char = Char - 'A' + 'a';
 | 
						||
    }
 | 
						||
    *OutBufPtr++ = Char;
 | 
						||
 | 
						||
    Char = mHexToStr[(UINT8)((*FindPointerToRegister (SystemContext, RegNumber) >> RegSize) & 0xf)];
 | 
						||
    if ((Char >= 'A') && (Char <= 'F')) {
 | 
						||
      Char = Char - 'A' + 'a';
 | 
						||
    }
 | 
						||
    *OutBufPtr++ = Char;
 | 
						||
 | 
						||
    RegSize = RegSize + 8;
 | 
						||
  }
 | 
						||
  return OutBufPtr;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 Reads the n-th register's value into an output buffer and sends it as a packet
 | 
						||
 @param   SystemContext   Register content at time of the exception
 | 
						||
 @param   InBuffer      Pointer to the input buffer received from gdb server
 | 
						||
 **/
 | 
						||
VOID
 | 
						||
ReadNthRegister (
 | 
						||
  IN  EFI_SYSTEM_CONTEXT  SystemContext,
 | 
						||
  IN  CHAR8               *InBuffer
 | 
						||
  )
 | 
						||
{
 | 
						||
  UINTN RegNumber;
 | 
						||
  CHAR8 OutBuffer[9]; // 1 reg=8 hex chars, and the end '\0' (escape seq)
 | 
						||
  CHAR8 *OutBufPtr;   // pointer to the output buffer
 | 
						||
 | 
						||
  RegNumber = AsciiStrHexToUintn (&InBuffer[1]);
 | 
						||
 | 
						||
  if (RegNumber >= MaxRegisterCount ()) {
 | 
						||
    SendError (GDB_EINVALIDREGNUM);
 | 
						||
    return;
 | 
						||
  }
 | 
						||
 | 
						||
  OutBufPtr = OutBuffer;
 | 
						||
  OutBufPtr = BasicReadRegister (SystemContext, RegNumber, OutBufPtr);
 | 
						||
 | 
						||
  *OutBufPtr = '\0';  // the end of the buffer
 | 
						||
  SendPacket (OutBuffer);
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 Reads the general registers into an output buffer  and sends it as a packet
 | 
						||
 @param   SystemContext     Register content at time of the exception
 | 
						||
 **/
 | 
						||
VOID
 | 
						||
EFIAPI
 | 
						||
ReadGeneralRegisters (
 | 
						||
  IN  EFI_SYSTEM_CONTEXT      SystemContext
 | 
						||
  )
 | 
						||
{
 | 
						||
  UINTN   Index;
 | 
						||
  CHAR8   *OutBuffer;
 | 
						||
  CHAR8   *OutBufPtr;
 | 
						||
  UINTN   RegisterCount = MaxRegisterCount ();
 | 
						||
 | 
						||
  // It is not safe to allocate pool here....
 | 
						||
  OutBuffer = AllocatePool ((RegisterCount * 8) + 1); // 8 bytes per register in string format plus a null to terminate
 | 
						||
  OutBufPtr = OutBuffer;
 | 
						||
  for (Index = 0; Index < RegisterCount; Index++) {
 | 
						||
    OutBufPtr = BasicReadRegister (SystemContext, Index, OutBufPtr);
 | 
						||
  }
 | 
						||
 | 
						||
  *OutBufPtr = '\0';
 | 
						||
  SendPacket (OutBuffer);
 | 
						||
  FreePool (OutBuffer);
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
 | 
						||
 @param   SystemContext       Register content at time of the exception
 | 
						||
 @param   RegNumber         the number of the register that we want to write
 | 
						||
 @param   InBufPtr          pointer to the output buffer. the new data will be extracted from the input buffer from this point on.
 | 
						||
 @retval  the pointer to the next character of the input buffer that can be used
 | 
						||
 **/
 | 
						||
CHAR8
 | 
						||
*BasicWriteRegister (
 | 
						||
  IN  EFI_SYSTEM_CONTEXT      SystemContext,
 | 
						||
  IN  UINTN           RegNumber,
 | 
						||
  IN  CHAR8           *InBufPtr
 | 
						||
  )
 | 
						||
{
 | 
						||
  UINTN RegSize;
 | 
						||
  UINTN TempValue; // the value transferred from a hex char
 | 
						||
  UINT32 NewValue; // the new value of the RegNumber-th Register
 | 
						||
 | 
						||
  if (gRegisterOffsets[RegNumber] > 0xF00) {
 | 
						||
    return InBufPtr + 8;
 | 
						||
  }
 | 
						||
 | 
						||
  NewValue = 0;
 | 
						||
  RegSize = 0;
 | 
						||
  while (RegSize < 32) {
 | 
						||
    TempValue = HexCharToInt (*InBufPtr++);
 | 
						||
 | 
						||
    if ((INTN)TempValue < 0) {
 | 
						||
      SendError (GDB_EBADMEMDATA);
 | 
						||
      return NULL;
 | 
						||
    }
 | 
						||
 | 
						||
    NewValue += (TempValue << (RegSize+4));
 | 
						||
    TempValue = HexCharToInt (*InBufPtr++);
 | 
						||
 | 
						||
    if ((INTN)TempValue < 0) {
 | 
						||
      SendError (GDB_EBADMEMDATA);
 | 
						||
      return NULL;
 | 
						||
    }
 | 
						||
 | 
						||
    NewValue += (TempValue << RegSize);
 | 
						||
    RegSize = RegSize + 8;
 | 
						||
  }
 | 
						||
  *(FindPointerToRegister (SystemContext, RegNumber)) = NewValue;
 | 
						||
  return InBufPtr;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/** ‘P n...=r...’
 | 
						||
 Writes the new value of n-th register received into the input buffer to the n-th register
 | 
						||
 @param   SystemContext   Register content at time of the exception
 | 
						||
 @param   InBuffer      Ponter to the input buffer received from gdb server
 | 
						||
 **/
 | 
						||
VOID
 | 
						||
WriteNthRegister (
 | 
						||
  IN  EFI_SYSTEM_CONTEXT      SystemContext,
 | 
						||
  IN  CHAR8           *InBuffer
 | 
						||
  )
 | 
						||
{
 | 
						||
  UINTN RegNumber;
 | 
						||
  CHAR8 RegNumBuffer[MAX_REG_NUM_BUF_SIZE];  // put the 'n..' part of the message into this array
 | 
						||
  CHAR8 *RegNumBufPtr;
 | 
						||
  CHAR8 *InBufPtr; // pointer to the input buffer
 | 
						||
 | 
						||
  // find the register number to write
 | 
						||
  InBufPtr = &InBuffer[1];
 | 
						||
  RegNumBufPtr = RegNumBuffer;
 | 
						||
  while (*InBufPtr != '=') {
 | 
						||
    *RegNumBufPtr++ = *InBufPtr++;
 | 
						||
  }
 | 
						||
  *RegNumBufPtr = '\0';
 | 
						||
  RegNumber = AsciiStrHexToUintn (RegNumBuffer);
 | 
						||
 | 
						||
  // check if this is a valid Register Number
 | 
						||
  if (RegNumber >= MaxRegisterCount ()) {
 | 
						||
    SendError (GDB_EINVALIDREGNUM);
 | 
						||
    return;
 | 
						||
  }
 | 
						||
  InBufPtr++;  // skips the '=' character
 | 
						||
  BasicWriteRegister (SystemContext, RegNumber, InBufPtr);
 | 
						||
  SendSuccess();
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/** ‘G XX...’
 | 
						||
 Writes the new values received into the input buffer to the general registers
 | 
						||
 @param   SystemContext       Register content at time of the exception
 | 
						||
 @param   InBuffer          Pointer to the input buffer received from gdb server
 | 
						||
 **/
 | 
						||
 | 
						||
VOID
 | 
						||
EFIAPI
 | 
						||
WriteGeneralRegisters (
 | 
						||
  IN  EFI_SYSTEM_CONTEXT  SystemContext,
 | 
						||
  IN  CHAR8               *InBuffer
 | 
						||
  )
 | 
						||
{
 | 
						||
  UINTN  i;
 | 
						||
  CHAR8  *InBufPtr; /// pointer to the input buffer
 | 
						||
  UINTN  MinLength;
 | 
						||
  UINTN  RegisterCount = MaxRegisterCount ();
 | 
						||
 | 
						||
  MinLength = (RegisterCount * 8) + 1;  // 'G' plus the registers in ASCII format
 | 
						||
 | 
						||
  if (AsciiStrLen (InBuffer) < MinLength) {
 | 
						||
    //Bad message. Message is not the right length
 | 
						||
    SendError (GDB_EBADBUFSIZE);
 | 
						||
    return;
 | 
						||
  }
 | 
						||
 | 
						||
  InBufPtr = &InBuffer[1];
 | 
						||
 | 
						||
  // Read the new values for the registers from the input buffer to an array, NewValueArray.
 | 
						||
  // The values in the array are in the gdb ordering
 | 
						||
  for (i = 0; i < RegisterCount; i++) {
 | 
						||
    InBufPtr = BasicWriteRegister (SystemContext, i, InBufPtr);
 | 
						||
  }
 | 
						||
 | 
						||
  SendSuccess ();
 | 
						||
}
 | 
						||
 | 
						||
// What about Thumb?
 | 
						||
// Use SWI 0xdbdbdb as the debug instruction
 | 
						||
#define GDB_ARM_BKPT    0xefdbdbdb
 | 
						||
 | 
						||
BOOLEAN mSingleStepActive = FALSE;
 | 
						||
UINT32  mSingleStepPC;
 | 
						||
UINT32  mSingleStepData;
 | 
						||
UINTN   mSingleStepDataSize;
 | 
						||
 | 
						||
typedef struct {
 | 
						||
  LIST_ENTRY  Link;
 | 
						||
  UINT64      Signature;
 | 
						||
  UINT32      Address;
 | 
						||
  UINT32      Instruction;
 | 
						||
} ARM_SOFTWARE_BREAKPOINT;
 | 
						||
 | 
						||
#define ARM_SOFTWARE_BREAKPOINT_SIGNATURE     SIGNATURE_64('A', 'R', 'M', 'B', 'R', 'K', 'P', 'T')
 | 
						||
#define ARM_SOFTWARE_BREAKPOINT_FROM_LINK(a)  CR(a, ARM_SOFTWARE_BREAKPOINT, Link, ARM_SOFTWARE_BREAKPOINT_SIGNATURE)
 | 
						||
 | 
						||
LIST_ENTRY  BreakpointList;
 | 
						||
 | 
						||
/**
 | 
						||
 Insert Single Step in the SystemContext
 | 
						||
 | 
						||
 @param SystemContext  Register content at time of the exception
 | 
						||
 **/
 | 
						||
VOID
 | 
						||
AddSingleStep (
 | 
						||
  IN EFI_SYSTEM_CONTEXT SystemContext
 | 
						||
  )
 | 
						||
{
 | 
						||
  if (mSingleStepActive) {
 | 
						||
    // Currently don't support nesting
 | 
						||
    return;
 | 
						||
  }
 | 
						||
  mSingleStepActive = TRUE;
 | 
						||
 | 
						||
  mSingleStepPC = SystemContext.SystemContextArm->PC;
 | 
						||
 | 
						||
  mSingleStepDataSize = sizeof (UINT32);
 | 
						||
  mSingleStepData = (*(UINT32 *)mSingleStepPC);
 | 
						||
  *(UINT32 *)mSingleStepPC = GDB_ARM_BKPT;
 | 
						||
  if (*(UINT32 *)mSingleStepPC != GDB_ARM_BKPT) {
 | 
						||
    // For some reason our breakpoint did not take
 | 
						||
    mSingleStepActive = FALSE;
 | 
						||
  }
 | 
						||
 | 
						||
  InvalidateInstructionCacheRange ((VOID *)mSingleStepPC, mSingleStepDataSize);
 | 
						||
  //DEBUG((EFI_D_ERROR, "AddSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, mSingleStepData, *(UINT32 *)mSingleStepPC));
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 Remove Single Step in the SystemContext
 | 
						||
 | 
						||
 @param SystemContext  Register content at time of the exception
 | 
						||
 **/
 | 
						||
VOID
 | 
						||
RemoveSingleStep (
 | 
						||
  IN  EFI_SYSTEM_CONTEXT  SystemContext
 | 
						||
  )
 | 
						||
{
 | 
						||
  if (!mSingleStepActive) {
 | 
						||
    return;
 | 
						||
  }
 | 
						||
 | 
						||
  if (mSingleStepDataSize == sizeof (UINT16)) {
 | 
						||
    *(UINT16 *)mSingleStepPC = (UINT16)mSingleStepData;
 | 
						||
  } else {
 | 
						||
    //DEBUG((EFI_D_ERROR, "RemoveSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, *(UINT32 *)mSingleStepPC, mSingleStepData));
 | 
						||
    *(UINT32 *)mSingleStepPC = mSingleStepData;
 | 
						||
  }
 | 
						||
  InvalidateInstructionCacheRange ((VOID *)mSingleStepPC, mSingleStepDataSize);
 | 
						||
  mSingleStepActive = FALSE;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
 | 
						||
/**
 | 
						||
 Continue. addr is Address to resume. If addr is omitted, resume at current
 | 
						||
 Address.
 | 
						||
 | 
						||
 @param   SystemContext     Register content at time of the exception
 | 
						||
 **/
 | 
						||
VOID
 | 
						||
EFIAPI
 | 
						||
ContinueAtAddress (
 | 
						||
  IN  EFI_SYSTEM_CONTEXT      SystemContext,
 | 
						||
  IN    CHAR8                 *PacketData
 | 
						||
  )
 | 
						||
{
 | 
						||
  if (PacketData[1] != '\0') {
 | 
						||
    SystemContext.SystemContextArm->PC = AsciiStrHexToUintn (&PacketData[1]);
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
/** ‘s [addr ]’
 | 
						||
 Single step. addr is the Address at which to resume. If addr is omitted, resume
 | 
						||
 at same Address.
 | 
						||
 | 
						||
 @param   SystemContext     Register content at time of the exception
 | 
						||
 **/
 | 
						||
VOID
 | 
						||
EFIAPI
 | 
						||
SingleStep (
 | 
						||
  IN  EFI_SYSTEM_CONTEXT      SystemContext,
 | 
						||
  IN    CHAR8                       *PacketData
 | 
						||
  )
 | 
						||
{
 | 
						||
  SendNotSupported ();
 | 
						||
}
 | 
						||
 | 
						||
UINTN
 | 
						||
GetBreakpointDataAddress (
 | 
						||
  IN  EFI_SYSTEM_CONTEXT  SystemContext,
 | 
						||
  IN  UINTN               BreakpointNumber
 | 
						||
  )
 | 
						||
{
 | 
						||
  return 0;
 | 
						||
}
 | 
						||
 | 
						||
UINTN
 | 
						||
GetBreakpointDetected (
 | 
						||
  IN  EFI_SYSTEM_CONTEXT  SystemContext
 | 
						||
  )
 | 
						||
{
 | 
						||
  return 0;
 | 
						||
}
 | 
						||
 | 
						||
BREAK_TYPE
 | 
						||
GetBreakpointType (
 | 
						||
  IN  EFI_SYSTEM_CONTEXT  SystemContext,
 | 
						||
  IN  UINTN               BreakpointNumber
 | 
						||
  )
 | 
						||
{
 | 
						||
  return NotSupported;
 | 
						||
}
 | 
						||
 | 
						||
ARM_SOFTWARE_BREAKPOINT *
 | 
						||
SearchBreakpointList (
 | 
						||
  IN  UINT32  Address
 | 
						||
  )
 | 
						||
{
 | 
						||
  LIST_ENTRY              *Current;
 | 
						||
  ARM_SOFTWARE_BREAKPOINT *Breakpoint;
 | 
						||
 | 
						||
  Current = GetFirstNode (&BreakpointList);
 | 
						||
  while (!IsNull (&BreakpointList, Current)) {
 | 
						||
    Breakpoint = ARM_SOFTWARE_BREAKPOINT_FROM_LINK(Current);
 | 
						||
 | 
						||
    if (Address == Breakpoint->Address) {
 | 
						||
      return Breakpoint;
 | 
						||
    }
 | 
						||
 | 
						||
    Current = GetNextNode (&BreakpointList, Current);
 | 
						||
  }
 | 
						||
 | 
						||
  return NULL;
 | 
						||
}
 | 
						||
 | 
						||
VOID
 | 
						||
SetBreakpoint (
 | 
						||
  IN UINT32 Address
 | 
						||
  )
 | 
						||
{
 | 
						||
  ARM_SOFTWARE_BREAKPOINT *Breakpoint;
 | 
						||
 | 
						||
  Breakpoint = SearchBreakpointList (Address);
 | 
						||
 | 
						||
  if (Breakpoint != NULL) {
 | 
						||
    return;
 | 
						||
  }
 | 
						||
 | 
						||
  // create and fill breakpoint structure
 | 
						||
  Breakpoint = AllocatePool (sizeof(ARM_SOFTWARE_BREAKPOINT));
 | 
						||
 | 
						||
  Breakpoint->Signature   = ARM_SOFTWARE_BREAKPOINT_SIGNATURE;
 | 
						||
  Breakpoint->Address     = Address;
 | 
						||
  Breakpoint->Instruction = *(UINT32 *)Address;
 | 
						||
 | 
						||
  // Add it to the list
 | 
						||
  InsertTailList (&BreakpointList, &Breakpoint->Link);
 | 
						||
 | 
						||
  // Insert the software breakpoint
 | 
						||
  *(UINT32 *)Address = GDB_ARM_BKPT;
 | 
						||
  InvalidateInstructionCacheRange ((VOID *)Address, 4);
 | 
						||
 | 
						||
  //DEBUG((EFI_D_ERROR, "SetBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, Breakpoint->Instruction, *(UINT32 *)Address));
 | 
						||
}
 | 
						||
 | 
						||
VOID
 | 
						||
ClearBreakpoint (
 | 
						||
  IN UINT32 Address
 | 
						||
  )
 | 
						||
{
 | 
						||
  ARM_SOFTWARE_BREAKPOINT *Breakpoint;
 | 
						||
 | 
						||
  Breakpoint = SearchBreakpointList (Address);
 | 
						||
 | 
						||
  if (Breakpoint == NULL) {
 | 
						||
    return;
 | 
						||
  }
 | 
						||
 | 
						||
  // Add it to the list
 | 
						||
  RemoveEntryList (&Breakpoint->Link);
 | 
						||
 | 
						||
  // Restore the original instruction
 | 
						||
  *(UINT32 *)Address = Breakpoint->Instruction;
 | 
						||
  InvalidateInstructionCacheRange ((VOID *)Address, 4);
 | 
						||
 | 
						||
  //DEBUG((EFI_D_ERROR, "ClearBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, GDB_ARM_BKPT, *(UINT32 *)Address));
 | 
						||
 | 
						||
  FreePool (Breakpoint);
 | 
						||
}
 | 
						||
 | 
						||
VOID
 | 
						||
EFIAPI
 | 
						||
InsertBreakPoint (
 | 
						||
  IN  EFI_SYSTEM_CONTEXT  SystemContext,
 | 
						||
  IN  CHAR8              *PacketData
 | 
						||
  )
 | 
						||
{
 | 
						||
  UINTN Type;
 | 
						||
  UINTN Address;
 | 
						||
  UINTN Length;
 | 
						||
  UINTN ErrorCode;
 | 
						||
 | 
						||
  ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);
 | 
						||
  if (ErrorCode > 0) {
 | 
						||
    SendError ((UINT8)ErrorCode);
 | 
						||
    return;
 | 
						||
  }
 | 
						||
 | 
						||
  switch (Type) {
 | 
						||
    case 0:   //Software breakpoint
 | 
						||
      break;
 | 
						||
 | 
						||
    default  :
 | 
						||
      DEBUG((EFI_D_ERROR, "Insert breakpoint default: %x\n", Type));
 | 
						||
      SendError (GDB_EINVALIDBRKPOINTTYPE);
 | 
						||
      return;
 | 
						||
  }
 | 
						||
 | 
						||
  SetBreakpoint (Address);
 | 
						||
 | 
						||
  SendSuccess ();
 | 
						||
}
 | 
						||
 | 
						||
VOID
 | 
						||
EFIAPI
 | 
						||
RemoveBreakPoint (
 | 
						||
  IN  EFI_SYSTEM_CONTEXT  SystemContext,
 | 
						||
  IN  CHAR8               *PacketData
 | 
						||
  )
 | 
						||
{
 | 
						||
  UINTN      Type;
 | 
						||
  UINTN      Address;
 | 
						||
  UINTN      Length;
 | 
						||
  UINTN      ErrorCode;
 | 
						||
 | 
						||
  //Parse breakpoint packet data
 | 
						||
  ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);
 | 
						||
  if (ErrorCode > 0) {
 | 
						||
    SendError ((UINT8)ErrorCode);
 | 
						||
    return;
 | 
						||
  }
 | 
						||
 | 
						||
  switch (Type) {
 | 
						||
    case 0:   //Software breakpoint
 | 
						||
      break;
 | 
						||
 | 
						||
    default:
 | 
						||
      SendError (GDB_EINVALIDBRKPOINTTYPE);
 | 
						||
      return;
 | 
						||
  }
 | 
						||
 | 
						||
  ClearBreakpoint (Address);
 | 
						||
 | 
						||
  SendSuccess ();
 | 
						||
}
 | 
						||
 | 
						||
VOID
 | 
						||
InitializeProcessor (
 | 
						||
  VOID
 | 
						||
  )
 | 
						||
{
 | 
						||
  // Initialize breakpoint list
 | 
						||
  InitializeListHead (&BreakpointList);
 | 
						||
}
 | 
						||
 | 
						||
BOOLEAN
 | 
						||
ValidateAddress (
 | 
						||
  IN  VOID  *Address
 | 
						||
  )
 | 
						||
{
 | 
						||
  if ((UINT32)Address < 0x80000000) {
 | 
						||
    return FALSE;
 | 
						||
  } else {
 | 
						||
    return TRUE;
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
BOOLEAN
 | 
						||
ValidateException (
 | 
						||
  IN  EFI_EXCEPTION_TYPE    ExceptionType,
 | 
						||
  IN OUT EFI_SYSTEM_CONTEXT SystemContext
 | 
						||
  )
 | 
						||
{
 | 
						||
  UINT32  ExceptionAddress;
 | 
						||
  UINT32  Instruction;
 | 
						||
 | 
						||
  // Is it a debugger SWI?
 | 
						||
  ExceptionAddress = SystemContext.SystemContextArm->PC -= 4;
 | 
						||
  Instruction      = *(UINT32 *)ExceptionAddress;
 | 
						||
  if (Instruction != GDB_ARM_BKPT) {
 | 
						||
    return FALSE;
 | 
						||
  }
 | 
						||
 | 
						||
  // Special for SWI-based exception handling.  SWI sets up the context
 | 
						||
  // to return to the instruction following the SWI instruction - NOT what we want
 | 
						||
  // for a debugger!
 | 
						||
  SystemContext.SystemContextArm->PC = ExceptionAddress;
 | 
						||
 | 
						||
  return TRUE;
 | 
						||
}
 | 
						||
 |