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;
 | ||
| }
 | ||
| 
 |