]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EmbeddedPkg/GdbStub/Arm/Processor.c
Adding support for BeagleBoard.
[mirror_edk2.git] / EmbeddedPkg / GdbStub / Arm / Processor.c
diff --git a/EmbeddedPkg/GdbStub/Arm/Processor.c b/EmbeddedPkg/GdbStub/Arm/Processor.c
new file mode 100644 (file)
index 0000000..e620d34
--- /dev/null
@@ -0,0 +1,717 @@
+/** @file\r
+  Processor specific parts of the GDB stub\r
+\r
+  Copyright (c) 2008-2009, Apple Inc. All rights reserved.\r
+  \r
+  All rights reserved. This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+/** @file\r
+  \r
+  Copyright (c) 2008, Apple, Inc                                                         \r
+  All rights reserved. This program and the accompanying materials                          \r
+  are licensed and made available under the terms and conditions of the BSD License         \r
+  which accompanies this distribution.  The full text of the license may be found at        \r
+  http://opensource.org/licenses/bsd-license.php                                            \r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+**/\r
+\r
+#include <GdbStubInternal.h>\r
+#include <Library/CacheMaintenanceLib.h>\r
+#include <Library/PrintLib.h>\r
+\r
+//\r
+// Array of exception types that need to be hooked by the debugger\r
+// (efi, gdb) //efi number\r
+//\r
+EFI_EXCEPTION_TYPE_ENTRY gExceptionType[] = {\r
+  { EXCEPT_ARM_SOFTWARE_INTERRUPT,  GDB_SIGTRAP }\r
+//  { EXCEPT_ARM_UNDEFINED_INSTRUCTION, GDB_SIGTRAP },  \r
+//  { EXCEPT_ARM_PREFETCH_ABORT,        GDB_SIGTRAP }, \r
+//  { EXCEPT_ARM_DATA_ABORT,            GDB_SIGEMT  },  \r
+//  { EXCEPT_ARM_RESERVED,              GDB_SIGILL  }  \r
+};\r
+\r
+// Shut up some annoying RVCT warnings\r
+#ifdef __CC_ARM\r
+#pragma diag_suppress 1296\r
+#endif\r
+\r
+UINTN gRegisterOffsets[] = {\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R0),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R1),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R2),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R3),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R4),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R5),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R6),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R7),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R8),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R9),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R10),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R11),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R12),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, SP),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, LR),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, PC),\r
+  0x00000F01,                               // f0\r
+  0x00000F02,\r
+  0x00000F03,\r
+  0x00000F11,                               // f1\r
+  0x00000F12,\r
+  0x00000F13,\r
+  0x00000F21,                               // f2\r
+  0x00000F22,\r
+  0x00000F23,\r
+  0x00000F31,                               // f3\r
+  0x00000F32,\r
+  0x00000F33,\r
+  0x00000F41,                               // f4\r
+  0x00000F42,\r
+  0x00000F43,\r
+  0x00000F51,                               // f5\r
+  0x00000F52,\r
+  0x00000F53,\r
+  0x00000F61,                               // f6\r
+  0x00000F62,\r
+  0x00000F63,\r
+  0x00000F71,                               // f7\r
+  0x00000F72,\r
+  0x00000F73,\r
+  0x00000FFF,                               // fps\r
+  0x00000FFF,                               \r
+  0x00000FFF,                               \r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, CPSR)\r
+};\r
+\r
+// restore warnings for RVCT\r
+#ifdef __CC_ARM\r
+#pragma diag_default 1296\r
+#endif\r
+\r
+/**\r
+ Return the number of entries in the gExceptionType[]\r
\r
+ @retval  UINTN, the number of entries in the gExceptionType[] array.    \r
+ **/\r
+UINTN\r
+MaxEfiException (\r
+  VOID\r
+  )\r
+{\r
+  return sizeof (gExceptionType)/sizeof (EFI_EXCEPTION_TYPE_ENTRY);\r
+}\r
+\r
+\r
+/**\r
+ Return the number of entries in the gRegisters[]\r
\r
+ @retval  UINTN, the number of entries (registers) in the gRegisters[] array.    \r
+ **/\r
+UINTN\r
+MaxRegisterCount (\r
+  VOID\r
+  )\r
+{\r
+  return sizeof (gRegisterOffsets)/sizeof (UINTN);\r
+}\r
+\r
+\r
+/**\r
+ Check to see if the ISA is supported. \r
+ ISA = Instruction Set Architecture\r
+\r
+ @retval TRUE if Isa is supported    \r
+\r
+**/\r
+BOOLEAN\r
+CheckIsa (\r
+  IN  EFI_INSTRUCTION_SET_ARCHITECTURE  Isa\r
+  )\r
+{\r
+  if (Isa == IsaArm) {\r
+    return TRUE;\r
+  } else {\r
+    return FALSE;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+ This takes in the register number and the System Context, and returns a pointer to the RegNumber-th register in gdb ordering\r
+ It is, by default, set to find the register pointer of the ARM member\r
+ @param   SystemContext     Register content at time of the exception \r
+ @param   RegNumber       The register to which we want to find a pointer\r
+ @retval  the pointer to the RegNumber-th pointer\r
+ **/ \r
+UINTN *\r
+FindPointerToRegister(\r
+  IN  EFI_SYSTEM_CONTEXT      SystemContext,\r
+  IN  UINTN           RegNumber  \r
+  )\r
+{\r
+  UINT8 *TempPtr;\r
+  ASSERT(gRegisterOffsets[RegNumber] < 0xF00);\r
+  TempPtr = ((UINT8 *)SystemContext.SystemContextArm) + gRegisterOffsets[RegNumber];\r
+  return (UINT32 *)TempPtr;\r
+}\r
+\r
+\r
+/**\r
+ Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr\r
+ @param SystemContext     Register content at time of the exception\r
+ @param   RegNumber       the number of the register that we want to read\r
+ @param   OutBufPtr       pointer to the output buffer's end. the new data will be added from this point on.\r
+ @retval  the pointer to the next character of the output buffer that is available to be written on.\r
+ **/\r
+CHAR8 *\r
+BasicReadRegister (\r
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,\r
+  IN  UINTN               RegNumber,\r
+  IN  CHAR8               *OutBufPtr\r
+  )\r
+{\r
+  UINTN RegSize;\r
+  CHAR8 Char;\r
+  \r
+  if (gRegisterOffsets[RegNumber] > 0xF00) {\r
+    AsciiSPrint(OutBufPtr, 9, "00000000");\r
+    OutBufPtr += 8;\r
+    return OutBufPtr;\r
+  }\r
+\r
+  RegSize = 0;\r
+  while (RegSize < 32) {\r
+    Char = mHexToStr[(UINT8)((*FindPointerToRegister(SystemContext, RegNumber) >> (RegSize+4)) & 0xf)];\r
+    if ((Char >= 'A') && (Char <= 'F')) {\r
+      Char = Char - 'A' + 'a';\r
+    }\r
+    *OutBufPtr++ = Char;\r
+    \r
+    Char = mHexToStr[(UINT8)((*FindPointerToRegister(SystemContext, RegNumber) >> RegSize) & 0xf)];\r
+    if ((Char >= 'A') && (Char <= 'F')) {\r
+      Char = Char - 'A' + 'a';\r
+    }\r
+    *OutBufPtr++ = Char;\r
+    \r
+    RegSize = RegSize + 8;\r
+  }\r
+  return OutBufPtr;\r
+}\r
+\r
+\r
+/** ‘p n’ \r
+ Reads the n-th register's value into an output buffer and sends it as a packet \r
+ @param   SystemContext   Register content at time of the exception\r
+ @param   InBuffer      Pointer to the input buffer received from gdb server\r
+ **/\r
+VOID\r
+ReadNthRegister (\r
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,\r
+  IN  CHAR8               *InBuffer\r
+  )\r
+{\r
+  UINTN RegNumber;\r
+  CHAR8 OutBuffer[9]; // 1 reg=8 hex chars, and the end '\0' (escape seq)\r
+  CHAR8 *OutBufPtr;   // pointer to the output buffer\r
+  \r
+  RegNumber = AsciiStrHexToUintn (&InBuffer[1]);\r
+  \r
+  if (RegNumber >= MaxRegisterCount()) {\r
+    SendError (GDB_EINVALIDREGNUM); \r
+    return;\r
+  }\r
+  \r
+  OutBufPtr = OutBuffer;\r
+  OutBufPtr = BasicReadRegister (SystemContext, RegNumber, OutBufPtr);\r
+  \r
+  *OutBufPtr = '\0';  // the end of the buffer\r
+  SendPacket(OutBuffer);\r
+}\r
+\r
+\r
+/** ‘g’ \r
+ Reads the general registers into an output buffer  and sends it as a packet \r
+ @param   SystemContext     Register content at time of the exception\r
+ **/\r
+VOID\r
+EFIAPI\r
+ReadGeneralRegisters (  \r
+  IN  EFI_SYSTEM_CONTEXT      SystemContext\r
+  )\r
+{\r
+  UINTN   Index;\r
+  CHAR8   *OutBuffer;\r
+  CHAR8   *OutBufPtr;\r
+  UINTN   RegisterCount = MaxRegisterCount();\r
+  \r
+  // It is not safe to allocate pool here....\r
+  OutBuffer = AllocatePool((RegisterCount * 8) + 1); // 8 bytes per register in string format plus a null to terminate\r
+  OutBufPtr = OutBuffer;\r
+  for (Index = 0; Index < RegisterCount; Index++) {\r
+    OutBufPtr = BasicReadRegister (SystemContext, Index, OutBufPtr);\r
+  }\r
+  \r
+  *OutBufPtr = '\0';\r
+  SendPacket(OutBuffer);\r
+  FreePool(OutBuffer);\r
+}\r
+\r
+\r
+/**\r
+ Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr\r
+ @param   SystemContext       Register content at time of the exception\r
+ @param   RegNumber         the number of the register that we want to write\r
+ @param   InBufPtr          pointer to the output buffer. the new data will be extracted from the input buffer from this point on.\r
+ @retval  the pointer to the next character of the input buffer that can be used\r
+ **/\r
+CHAR8\r
+*BasicWriteRegister (\r
+  IN  EFI_SYSTEM_CONTEXT      SystemContext,\r
+  IN  UINTN           RegNumber,\r
+  IN  CHAR8           *InBufPtr\r
+  )\r
+{\r
+  UINTN RegSize;\r
+  UINTN TempValue; // the value transferred from a hex char\r
+  UINT32 NewValue; // the new value of the RegNumber-th Register\r
+  \r
+  if (gRegisterOffsets[RegNumber] > 0xF00) {\r
+    return InBufPtr + 8;\r
+  }\r
+\r
+  NewValue = 0;\r
+  RegSize = 0;\r
+  while (RegSize < 32) {\r
+    TempValue = HexCharToInt(*InBufPtr++);\r
+    \r
+    if ((INTN)TempValue < 0) {\r
+      SendError (GDB_EBADMEMDATA); \r
+      return NULL;\r
+    }\r
+    \r
+    NewValue += (TempValue << (RegSize+4));\r
+    TempValue = HexCharToInt(*InBufPtr++);\r
+    \r
+    if ((INTN)TempValue < 0) {\r
+      SendError (GDB_EBADMEMDATA); \r
+      return NULL;\r
+    }\r
+    \r
+    NewValue += (TempValue << RegSize); \r
+    RegSize = RegSize + 8;\r
+  }\r
+  *(FindPointerToRegister(SystemContext, RegNumber)) = NewValue;\r
+  return InBufPtr;\r
+}\r
+\r
+\r
+/** ‘P n...=r...’\r
+ Writes the new value of n-th register received into the input buffer to the n-th register\r
+ @param   SystemContext   Register content at time of the exception\r
+ @param   InBuffer      Ponter to the input buffer received from gdb server\r
+ **/\r
+VOID\r
+WriteNthRegister (\r
+  IN  EFI_SYSTEM_CONTEXT      SystemContext,\r
+  IN  CHAR8           *InBuffer\r
+  )\r
+{\r
+  UINTN RegNumber;\r
+  CHAR8 RegNumBuffer[MAX_REG_NUM_BUF_SIZE];  // put the 'n..' part of the message into this array\r
+  CHAR8 *RegNumBufPtr;\r
+  CHAR8 *InBufPtr; // pointer to the input buffer\r
+  \r
+  // find the register number to write\r
+  InBufPtr = &InBuffer[1];\r
+  RegNumBufPtr = RegNumBuffer;\r
+  while (*InBufPtr != '=') {\r
+    *RegNumBufPtr++ = *InBufPtr++;\r
+  } \r
+  *RegNumBufPtr = '\0';\r
+  RegNumber = AsciiStrHexToUintn (RegNumBuffer); \r
+  \r
+  // check if this is a valid Register Number\r
+  if (RegNumber >= MaxRegisterCount()) {\r
+    SendError (GDB_EINVALIDREGNUM); \r
+    return;\r
+  }\r
+  InBufPtr++;  // skips the '=' character\r
+  BasicWriteRegister (SystemContext, RegNumber, InBufPtr);\r
+  SendSuccess();\r
+}\r
+\r
+\r
+/** ‘G XX...’\r
+ Writes the new values received into the input buffer to the general registers\r
+ @param   SystemContext       Register content at time of the exception\r
+ @param   InBuffer          Pointer to the input buffer received from gdb server\r
+ **/\r
+\r
+VOID\r
+EFIAPI\r
+WriteGeneralRegisters (\r
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,\r
+  IN  CHAR8               *InBuffer\r
+  )\r
+{\r
+  UINTN  i;\r
+  CHAR8  *InBufPtr; /// pointer to the input buffer\r
+  UINTN  MinLength;\r
+  UINTN  RegisterCount = MaxRegisterCount();\r
+\r
+  MinLength = (RegisterCount * 8) + 1;  // 'G' plus the registers in ASCII format\r
+  \r
+  if (AsciiStrLen(InBuffer) < MinLength) {\r
+    //Bad message. Message is not the right length \r
+    SendError (GDB_EBADBUFSIZE); \r
+    return;\r
+  }\r
+  \r
+  InBufPtr = &InBuffer[1];\r
+  \r
+  // Read the new values for the registers from the input buffer to an array, NewValueArray.\r
+  // The values in the array are in the gdb ordering\r
+  for(i = 0; i < RegisterCount; i++) {\r
+    InBufPtr = BasicWriteRegister (SystemContext, i, InBufPtr);\r
+  }\r
+  \r
+  SendSuccess ();\r
+}\r
+\r
+// What about Thumb?\r
+// Use SWI 0xdbdbdb as the debug instruction\r
+#define GDB_ARM_BKPT    0xefdbdbdb\r
+\r
+BOOLEAN mSingleStepActive = FALSE;\r
+UINT32  mSingleStepPC;\r
+UINT32  mSingleStepData;\r
+UINTN   mSingleStepDataSize;\r
+\r
+typedef struct {\r
+  LIST_ENTRY  Link;\r
+  UINT64      Signature;\r
+  UINT32      Address;\r
+  UINT32      Instruction;\r
+} ARM_SOFTWARE_BREAKPOINT;\r
+\r
+#define ARM_SOFTWARE_BREAKPOINT_SIGNATURE     SIGNATURE_64('A', 'R', 'M', 'B', 'R', 'K', 'P', 'T')\r
+#define ARM_SOFTWARE_BREAKPOINT_FROM_LINK(a)  CR(a, ARM_SOFTWARE_BREAKPOINT, Link, ARM_SOFTWARE_BREAKPOINT_SIGNATURE)\r
+\r
+LIST_ENTRY  BreakpointList;\r
+\r
+/** \r
+ Insert Single Step in the SystemContext\r
\r
+ @param        SystemContext   Register content at time of the exception\r
+ **/\r
+VOID\r
+AddSingleStep (\r
+  IN EFI_SYSTEM_CONTEXT SystemContext\r
+  )\r
+{\r
+  if (mSingleStepActive) {\r
+    // Currently don't support nesting\r
+    return;\r
+  }\r
+  mSingleStepActive = TRUE;\r
+  \r
+  mSingleStepPC = SystemContext.SystemContextArm->PC;\r
+\r
+  mSingleStepDataSize = sizeof (UINT32);\r
+  mSingleStepData = (*(UINT32 *)mSingleStepPC); \r
+  *(UINT32 *)mSingleStepPC = GDB_ARM_BKPT;\r
+  if (*(UINT32 *)mSingleStepPC != GDB_ARM_BKPT) {\r
+    // For some reason our breakpoint did not take\r
+    mSingleStepActive = FALSE;\r
+  }\r
+\r
+  InvalidateInstructionCacheRange((VOID *)mSingleStepPC, mSingleStepDataSize);\r
+  //DEBUG((EFI_D_ERROR, "AddSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, mSingleStepData, *(UINT32 *)mSingleStepPC));\r
+}\r
+\r
+  \r
+/** \r
+ Remove Single Step in the SystemContext\r
\r
+ @param        SystemContext   Register content at time of the exception\r
+ **/\r
+VOID\r
+RemoveSingleStep (\r
+  IN  EFI_SYSTEM_CONTEXT  SystemContext\r
+  )\r
+{\r
+  if (!mSingleStepActive) {\r
+    return;\r
+  }\r
+  \r
+  if (mSingleStepDataSize == sizeof (UINT16)) {\r
+    *(UINT16 *)mSingleStepPC = (UINT16)mSingleStepData;\r
+  } else {\r
+    //DEBUG((EFI_D_ERROR, "RemoveSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, *(UINT32 *)mSingleStepPC, mSingleStepData));\r
+    *(UINT32 *)mSingleStepPC = mSingleStepData;\r
+  }\r
+  InvalidateInstructionCacheRange((VOID *)mSingleStepPC, mSingleStepDataSize);\r
+  mSingleStepActive = FALSE;\r
+}\r
+\r
+\r
+\r
+/** ‘c [addr ]’ \r
+ Continue. addr is Address to resume. If addr is omitted, resume at current \r
+ Address.\r
\r
+ @param   SystemContext     Register content at time of the exception  \r
+ **/\r
+VOID\r
+EFIAPI\r
+ContinueAtAddress (\r
+  IN  EFI_SYSTEM_CONTEXT      SystemContext,\r
+  IN    CHAR8                 *PacketData\r
+  )\r
+{\r
+  if (PacketData[1] != '\0') {\r
+    SystemContext.SystemContextArm->PC = AsciiStrHexToUintn(&PacketData[1]);\r
+  } \r
+}\r
+\r
+\r
+/** ‘s [addr ]’\r
+ Single step. addr is the Address at which to resume. If addr is omitted, resume \r
+ at same Address.\r
\r
+ @param   SystemContext     Register content at time of the exception  \r
+ **/\r
+VOID\r
+EFIAPI\r
+SingleStep (\r
+  IN  EFI_SYSTEM_CONTEXT      SystemContext,\r
+  IN    CHAR8                       *PacketData\r
+  )\r
+{\r
+  SendNotSupported();\r
+}\r
+\r
+UINTN\r
+GetBreakpointDataAddress (\r
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,\r
+  IN  UINTN               BreakpointNumber\r
+  )\r
+{\r
+  return 0;\r
+}\r
+\r
+UINTN\r
+GetBreakpointDetected (\r
+  IN  EFI_SYSTEM_CONTEXT  SystemContext\r
+  )\r
+{\r
+  return 0;\r
+}\r
+\r
+BREAK_TYPE\r
+GetBreakpointType (\r
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,\r
+  IN  UINTN               BreakpointNumber\r
+  )\r
+{\r
+  return NotSupported;\r
+}\r
+\r
+ARM_SOFTWARE_BREAKPOINT *\r
+SearchBreakpointList (\r
+  IN  UINT32  Address\r
+  )\r
+{\r
+  LIST_ENTRY              *Current;\r
+  ARM_SOFTWARE_BREAKPOINT *Breakpoint;\r
+\r
+  Current = GetFirstNode(&BreakpointList);\r
+  while (!IsNull(&BreakpointList, Current)) {\r
+    Breakpoint = ARM_SOFTWARE_BREAKPOINT_FROM_LINK(Current);\r
+\r
+    if (Address == Breakpoint->Address) {\r
+      return Breakpoint;\r
+    }\r
+\r
+    Current = GetNextNode(&BreakpointList, Current);\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+VOID\r
+SetBreakpoint (\r
+  IN UINT32 Address\r
+  )\r
+{\r
+  ARM_SOFTWARE_BREAKPOINT *Breakpoint;\r
+\r
+  Breakpoint = SearchBreakpointList(Address);\r
+\r
+  if (Breakpoint != NULL) {\r
+    return;\r
+  }\r
+\r
+  // create and fill breakpoint structure\r
+  Breakpoint = AllocatePool(sizeof(ARM_SOFTWARE_BREAKPOINT));\r
+\r
+  Breakpoint->Signature   = ARM_SOFTWARE_BREAKPOINT_SIGNATURE;\r
+  Breakpoint->Address     = Address;\r
+  Breakpoint->Instruction = *(UINT32 *)Address;\r
+  \r
+  // Add it to the list\r
+  InsertTailList(&BreakpointList, &Breakpoint->Link);\r
+\r
+  // Insert the software breakpoint\r
+  *(UINT32 *)Address = GDB_ARM_BKPT;\r
+  InvalidateInstructionCacheRange((VOID *)Address, 4);\r
+\r
+  //DEBUG((EFI_D_ERROR, "SetBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, Breakpoint->Instruction, *(UINT32 *)Address));\r
+}\r
+\r
+VOID\r
+ClearBreakpoint (\r
+  IN UINT32 Address\r
+  )\r
+{\r
+  ARM_SOFTWARE_BREAKPOINT *Breakpoint;\r
+\r
+  Breakpoint = SearchBreakpointList(Address);\r
+\r
+  if (Breakpoint == NULL) {\r
+    return;\r
+  }\r
+\r
+  // Add it to the list\r
+  RemoveEntryList(&Breakpoint->Link);\r
+\r
+  // Restore the original instruction\r
+  *(UINT32 *)Address = Breakpoint->Instruction;\r
+  InvalidateInstructionCacheRange((VOID *)Address, 4);\r
+\r
+  //DEBUG((EFI_D_ERROR, "ClearBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, GDB_ARM_BKPT, *(UINT32 *)Address));\r
+\r
+  FreePool(Breakpoint);\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+InsertBreakPoint (\r
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,\r
+  IN  CHAR8              *PacketData\r
+  )\r
+{\r
+  UINTN Type;\r
+  UINTN Address;\r
+  UINTN Length;\r
+  UINTN ErrorCode;\r
+\r
+  ErrorCode = ParseBreakpointPacket(PacketData, &Type, &Address, &Length);\r
+  if (ErrorCode > 0) {\r
+    SendError ((UINT8)ErrorCode);\r
+    return;\r
+  }\r
+\r
+  switch (Type) {\r
+    case 0:   //Software breakpoint\r
+      break;\r
+\r
+    default  :\r
+      DEBUG((EFI_D_ERROR, "Insert breakpoint default: %x\n", Type));\r
+      SendError (GDB_EINVALIDBRKPOINTTYPE);\r
+      return;\r
+  }\r
+\r
+  SetBreakpoint(Address);\r
+\r
+  SendSuccess ();\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+RemoveBreakPoint (\r
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,\r
+  IN  CHAR8               *PacketData\r
+  )\r
+{\r
+  UINTN      Type;\r
+  UINTN      Address;\r
+  UINTN      Length;\r
+  UINTN      ErrorCode;\r
+\r
+  //Parse breakpoint packet data\r
+  ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);\r
+  if (ErrorCode > 0) {\r
+    SendError ((UINT8)ErrorCode);\r
+    return;\r
+  }\r
+\r
+  switch (Type) {\r
+    case 0:   //Software breakpoint\r
+      break;\r
+    \r
+    default:\r
+      SendError (GDB_EINVALIDBRKPOINTTYPE);\r
+      return;\r
+  }\r
+\r
+  ClearBreakpoint(Address);\r
+\r
+  SendSuccess ();\r
+}\r
+\r
+VOID\r
+InitializeProcessor (\r
+  VOID\r
+  )\r
+{\r
+  // Initialize breakpoint list\r
+  InitializeListHead(&BreakpointList);\r
+}\r
+\r
+BOOLEAN\r
+ValidateAddress (\r
+  IN  VOID  *Address\r
+  )\r
+{\r
+  if ((UINT32)Address < 0x80000000) {\r
+    return FALSE;\r
+  } else {\r
+    return TRUE;\r
+  }\r
+}\r
+\r
+BOOLEAN\r
+ValidateException (\r
+  IN  EFI_EXCEPTION_TYPE    ExceptionType, \r
+  IN OUT EFI_SYSTEM_CONTEXT SystemContext \r
+  )\r
+{\r
+  UINT32  ExceptionAddress;\r
+  UINT32  Instruction;\r
+  \r
+  // Is it a debugger SWI?\r
+  ExceptionAddress = SystemContext.SystemContextArm->PC -= 4;\r
+  Instruction      = *(UINT32 *)ExceptionAddress;\r
+  if (Instruction != GDB_ARM_BKPT) {\r
+    return FALSE;\r
+  }\r
+\r
+  // Special for SWI-based exception handling.  SWI sets up the context\r
+  // to return to the instruction following the SWI instruction - NOT what we want\r
+  // for a debugger!\r
+  SystemContext.SystemContextArm->PC = ExceptionAddress;\r
+\r
+  return TRUE;\r
+}\r
+\r