Home | History | Annotate | Download | only in Arm
      1 /** @file
      2   Processor specific parts of the GDB stub
      3 
      4   Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
      5 
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include <GdbStubInternal.h>
     17 #include <Library/CacheMaintenanceLib.h>
     18 #include <Library/PrintLib.h>
     19 
     20 //
     21 // Array of exception types that need to be hooked by the debugger
     22 // (efi, gdb) //efi number
     23 //
     24 EFI_EXCEPTION_TYPE_ENTRY gExceptionType[] = {
     25   { EXCEPT_ARM_SOFTWARE_INTERRUPT,  GDB_SIGTRAP }
     26 //  { EXCEPT_ARM_UNDEFINED_INSTRUCTION, GDB_SIGTRAP },
     27 //  { EXCEPT_ARM_PREFETCH_ABORT,        GDB_SIGTRAP },
     28 //  { EXCEPT_ARM_DATA_ABORT,            GDB_SIGEMT  },
     29 //  { EXCEPT_ARM_RESERVED,              GDB_SIGILL  }
     30 };
     31 
     32 // Shut up some annoying RVCT warnings
     33 #ifdef __CC_ARM
     34 #pragma diag_suppress 1296
     35 #endif
     36 
     37 UINTN gRegisterOffsets[] = {
     38   OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R0),
     39   OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R1),
     40   OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R2),
     41   OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R3),
     42   OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R4),
     43   OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R5),
     44   OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R6),
     45   OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R7),
     46   OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R8),
     47   OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R9),
     48   OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R10),
     49   OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R11),
     50   OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R12),
     51   OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, SP),
     52   OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, LR),
     53   OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, PC),
     54   0x00000F01,                               // f0
     55   0x00000F02,
     56   0x00000F03,
     57   0x00000F11,                               // f1
     58   0x00000F12,
     59   0x00000F13,
     60   0x00000F21,                               // f2
     61   0x00000F22,
     62   0x00000F23,
     63   0x00000F31,                               // f3
     64   0x00000F32,
     65   0x00000F33,
     66   0x00000F41,                               // f4
     67   0x00000F42,
     68   0x00000F43,
     69   0x00000F51,                               // f5
     70   0x00000F52,
     71   0x00000F53,
     72   0x00000F61,                               // f6
     73   0x00000F62,
     74   0x00000F63,
     75   0x00000F71,                               // f7
     76   0x00000F72,
     77   0x00000F73,
     78   0x00000FFF,                               // fps
     79   OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, CPSR)
     80 };
     81 
     82 // restore warnings for RVCT
     83 #ifdef __CC_ARM
     84 #pragma diag_default 1296
     85 #endif
     86 
     87 /**
     88  Return the number of entries in the gExceptionType[]
     89 
     90  @retval  UINTN, the number of entries in the gExceptionType[] array.
     91  **/
     92 UINTN
     93 MaxEfiException (
     94   VOID
     95   )
     96 {
     97   return sizeof (gExceptionType) / sizeof (EFI_EXCEPTION_TYPE_ENTRY);
     98 }
     99 
    100 
    101 /**
    102  Return the number of entries in the gRegisters[]
    103 
    104  @retval  UINTN, the number of entries (registers) in the gRegisters[] array.
    105  **/
    106 UINTN
    107 MaxRegisterCount (
    108   VOID
    109   )
    110 {
    111   return sizeof (gRegisterOffsets) / sizeof (UINTN);
    112 }
    113 
    114 
    115 /**
    116  Check to see if the ISA is supported.
    117  ISA = Instruction Set Architecture
    118 
    119  @retval TRUE if Isa is supported
    120 
    121 **/
    122 BOOLEAN
    123 CheckIsa (
    124   IN  EFI_INSTRUCTION_SET_ARCHITECTURE  Isa
    125   )
    126 {
    127   if (Isa == IsaArm) {
    128     return TRUE;
    129   } else {
    130     return FALSE;
    131   }
    132 }
    133 
    134 
    135 /**
    136  This takes in the register number and the System Context, and returns a pointer to the RegNumber-th register in gdb ordering
    137  It is, by default, set to find the register pointer of the ARM member
    138  @param   SystemContext     Register content at time of the exception
    139  @param   RegNumber       The register to which we want to find a pointer
    140  @retval  the pointer to the RegNumber-th pointer
    141  **/
    142 UINTN *
    143 FindPointerToRegister (
    144   IN  EFI_SYSTEM_CONTEXT      SystemContext,
    145   IN  UINTN           RegNumber
    146   )
    147 {
    148   UINT8 *TempPtr;
    149   ASSERT(gRegisterOffsets[RegNumber] < 0xF00);
    150   TempPtr = ((UINT8 *)SystemContext.SystemContextArm) + gRegisterOffsets[RegNumber];
    151   return (UINT32 *)TempPtr;
    152 }
    153 
    154 
    155 /**
    156  Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
    157  @param SystemContext     Register content at time of the exception
    158  @param   RegNumber       the number of the register that we want to read
    159  @param   OutBufPtr       pointer to the output buffer's end. the new data will be added from this point on.
    160  @retval  the pointer to the next character of the output buffer that is available to be written on.
    161  **/
    162 CHAR8 *
    163 BasicReadRegister (
    164   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    165   IN  UINTN               RegNumber,
    166   IN  CHAR8               *OutBufPtr
    167   )
    168 {
    169   UINTN RegSize;
    170   CHAR8 Char;
    171 
    172   if (gRegisterOffsets[RegNumber] > 0xF00) {
    173     AsciiSPrint (OutBufPtr, 9, "00000000");
    174     OutBufPtr += 8;
    175     return OutBufPtr;
    176   }
    177 
    178   RegSize = 0;
    179   while (RegSize < 32) {
    180     Char = mHexToStr[(UINT8)((*FindPointerToRegister (SystemContext, RegNumber) >> (RegSize+4)) & 0xf)];
    181     if ((Char >= 'A') && (Char <= 'F')) {
    182       Char = Char - 'A' + 'a';
    183     }
    184     *OutBufPtr++ = Char;
    185 
    186     Char = mHexToStr[(UINT8)((*FindPointerToRegister (SystemContext, RegNumber) >> RegSize) & 0xf)];
    187     if ((Char >= 'A') && (Char <= 'F')) {
    188       Char = Char - 'A' + 'a';
    189     }
    190     *OutBufPtr++ = Char;
    191 
    192     RegSize = RegSize + 8;
    193   }
    194   return OutBufPtr;
    195 }
    196 
    197 
    198 /**
    199  Reads the n-th register's value into an output buffer and sends it as a packet
    200  @param   SystemContext   Register content at time of the exception
    201  @param   InBuffer      Pointer to the input buffer received from gdb server
    202  **/
    203 VOID
    204 ReadNthRegister (
    205   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    206   IN  CHAR8               *InBuffer
    207   )
    208 {
    209   UINTN RegNumber;
    210   CHAR8 OutBuffer[9]; // 1 reg=8 hex chars, and the end '\0' (escape seq)
    211   CHAR8 *OutBufPtr;   // pointer to the output buffer
    212 
    213   RegNumber = AsciiStrHexToUintn (&InBuffer[1]);
    214 
    215   if (RegNumber >= MaxRegisterCount ()) {
    216     SendError (GDB_EINVALIDREGNUM);
    217     return;
    218   }
    219 
    220   OutBufPtr = OutBuffer;
    221   OutBufPtr = BasicReadRegister (SystemContext, RegNumber, OutBufPtr);
    222 
    223   *OutBufPtr = '\0';  // the end of the buffer
    224   SendPacket (OutBuffer);
    225 }
    226 
    227 
    228 /**
    229  Reads the general registers into an output buffer  and sends it as a packet
    230  @param   SystemContext     Register content at time of the exception
    231  **/
    232 VOID
    233 EFIAPI
    234 ReadGeneralRegisters (
    235   IN  EFI_SYSTEM_CONTEXT      SystemContext
    236   )
    237 {
    238   UINTN   Index;
    239   CHAR8   *OutBuffer;
    240   CHAR8   *OutBufPtr;
    241   UINTN   RegisterCount = MaxRegisterCount ();
    242 
    243   // It is not safe to allocate pool here....
    244   OutBuffer = AllocatePool ((RegisterCount * 8) + 1); // 8 bytes per register in string format plus a null to terminate
    245   OutBufPtr = OutBuffer;
    246   for (Index = 0; Index < RegisterCount; Index++) {
    247     OutBufPtr = BasicReadRegister (SystemContext, Index, OutBufPtr);
    248   }
    249 
    250   *OutBufPtr = '\0';
    251   SendPacket (OutBuffer);
    252   FreePool (OutBuffer);
    253 }
    254 
    255 
    256 /**
    257  Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
    258  @param   SystemContext       Register content at time of the exception
    259  @param   RegNumber         the number of the register that we want to write
    260  @param   InBufPtr          pointer to the output buffer. the new data will be extracted from the input buffer from this point on.
    261  @retval  the pointer to the next character of the input buffer that can be used
    262  **/
    263 CHAR8
    264 *BasicWriteRegister (
    265   IN  EFI_SYSTEM_CONTEXT      SystemContext,
    266   IN  UINTN           RegNumber,
    267   IN  CHAR8           *InBufPtr
    268   )
    269 {
    270   UINTN RegSize;
    271   UINTN TempValue; // the value transferred from a hex char
    272   UINT32 NewValue; // the new value of the RegNumber-th Register
    273 
    274   if (gRegisterOffsets[RegNumber] > 0xF00) {
    275     return InBufPtr + 8;
    276   }
    277 
    278   NewValue = 0;
    279   RegSize = 0;
    280   while (RegSize < 32) {
    281     TempValue = HexCharToInt (*InBufPtr++);
    282 
    283     if ((INTN)TempValue < 0) {
    284       SendError (GDB_EBADMEMDATA);
    285       return NULL;
    286     }
    287 
    288     NewValue += (TempValue << (RegSize+4));
    289     TempValue = HexCharToInt (*InBufPtr++);
    290 
    291     if ((INTN)TempValue < 0) {
    292       SendError (GDB_EBADMEMDATA);
    293       return NULL;
    294     }
    295 
    296     NewValue += (TempValue << RegSize);
    297     RegSize = RegSize + 8;
    298   }
    299   *(FindPointerToRegister (SystemContext, RegNumber)) = NewValue;
    300   return InBufPtr;
    301 }
    302 
    303 
    304 /** P n...=r...
    305  Writes the new value of n-th register received into the input buffer to the n-th register
    306  @param   SystemContext   Register content at time of the exception
    307  @param   InBuffer      Ponter to the input buffer received from gdb server
    308  **/
    309 VOID
    310 WriteNthRegister (
    311   IN  EFI_SYSTEM_CONTEXT      SystemContext,
    312   IN  CHAR8           *InBuffer
    313   )
    314 {
    315   UINTN RegNumber;
    316   CHAR8 RegNumBuffer[MAX_REG_NUM_BUF_SIZE];  // put the 'n..' part of the message into this array
    317   CHAR8 *RegNumBufPtr;
    318   CHAR8 *InBufPtr; // pointer to the input buffer
    319 
    320   // find the register number to write
    321   InBufPtr = &InBuffer[1];
    322   RegNumBufPtr = RegNumBuffer;
    323   while (*InBufPtr != '=') {
    324     *RegNumBufPtr++ = *InBufPtr++;
    325   }
    326   *RegNumBufPtr = '\0';
    327   RegNumber = AsciiStrHexToUintn (RegNumBuffer);
    328 
    329   // check if this is a valid Register Number
    330   if (RegNumber >= MaxRegisterCount ()) {
    331     SendError (GDB_EINVALIDREGNUM);
    332     return;
    333   }
    334   InBufPtr++;  // skips the '=' character
    335   BasicWriteRegister (SystemContext, RegNumber, InBufPtr);
    336   SendSuccess();
    337 }
    338 
    339 
    340 /** G XX...
    341  Writes the new values received into the input buffer to the general registers
    342  @param   SystemContext       Register content at time of the exception
    343  @param   InBuffer          Pointer to the input buffer received from gdb server
    344  **/
    345 
    346 VOID
    347 EFIAPI
    348 WriteGeneralRegisters (
    349   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    350   IN  CHAR8               *InBuffer
    351   )
    352 {
    353   UINTN  i;
    354   CHAR8  *InBufPtr; /// pointer to the input buffer
    355   UINTN  MinLength;
    356   UINTN  RegisterCount = MaxRegisterCount ();
    357 
    358   MinLength = (RegisterCount * 8) + 1;  // 'G' plus the registers in ASCII format
    359 
    360   if (AsciiStrLen (InBuffer) < MinLength) {
    361     //Bad message. Message is not the right length
    362     SendError (GDB_EBADBUFSIZE);
    363     return;
    364   }
    365 
    366   InBufPtr = &InBuffer[1];
    367 
    368   // Read the new values for the registers from the input buffer to an array, NewValueArray.
    369   // The values in the array are in the gdb ordering
    370   for (i = 0; i < RegisterCount; i++) {
    371     InBufPtr = BasicWriteRegister (SystemContext, i, InBufPtr);
    372   }
    373 
    374   SendSuccess ();
    375 }
    376 
    377 // What about Thumb?
    378 // Use SWI 0xdbdbdb as the debug instruction
    379 #define GDB_ARM_BKPT    0xefdbdbdb
    380 
    381 BOOLEAN mSingleStepActive = FALSE;
    382 UINT32  mSingleStepPC;
    383 UINT32  mSingleStepData;
    384 UINTN   mSingleStepDataSize;
    385 
    386 typedef struct {
    387   LIST_ENTRY  Link;
    388   UINT64      Signature;
    389   UINT32      Address;
    390   UINT32      Instruction;
    391 } ARM_SOFTWARE_BREAKPOINT;
    392 
    393 #define ARM_SOFTWARE_BREAKPOINT_SIGNATURE     SIGNATURE_64('A', 'R', 'M', 'B', 'R', 'K', 'P', 'T')
    394 #define ARM_SOFTWARE_BREAKPOINT_FROM_LINK(a)  CR(a, ARM_SOFTWARE_BREAKPOINT, Link, ARM_SOFTWARE_BREAKPOINT_SIGNATURE)
    395 
    396 LIST_ENTRY  BreakpointList;
    397 
    398 /**
    399  Insert Single Step in the SystemContext
    400 
    401  @param SystemContext  Register content at time of the exception
    402  **/
    403 VOID
    404 AddSingleStep (
    405   IN EFI_SYSTEM_CONTEXT SystemContext
    406   )
    407 {
    408   if (mSingleStepActive) {
    409     // Currently don't support nesting
    410     return;
    411   }
    412   mSingleStepActive = TRUE;
    413 
    414   mSingleStepPC = SystemContext.SystemContextArm->PC;
    415 
    416   mSingleStepDataSize = sizeof (UINT32);
    417   mSingleStepData = (*(UINT32 *)mSingleStepPC);
    418   *(UINT32 *)mSingleStepPC = GDB_ARM_BKPT;
    419   if (*(UINT32 *)mSingleStepPC != GDB_ARM_BKPT) {
    420     // For some reason our breakpoint did not take
    421     mSingleStepActive = FALSE;
    422   }
    423 
    424   InvalidateInstructionCacheRange ((VOID *)mSingleStepPC, mSingleStepDataSize);
    425   //DEBUG((EFI_D_ERROR, "AddSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, mSingleStepData, *(UINT32 *)mSingleStepPC));
    426 }
    427 
    428 
    429 /**
    430  Remove Single Step in the SystemContext
    431 
    432  @param SystemContext  Register content at time of the exception
    433  **/
    434 VOID
    435 RemoveSingleStep (
    436   IN  EFI_SYSTEM_CONTEXT  SystemContext
    437   )
    438 {
    439   if (!mSingleStepActive) {
    440     return;
    441   }
    442 
    443   if (mSingleStepDataSize == sizeof (UINT16)) {
    444     *(UINT16 *)mSingleStepPC = (UINT16)mSingleStepData;
    445   } else {
    446     //DEBUG((EFI_D_ERROR, "RemoveSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, *(UINT32 *)mSingleStepPC, mSingleStepData));
    447     *(UINT32 *)mSingleStepPC = mSingleStepData;
    448   }
    449   InvalidateInstructionCacheRange ((VOID *)mSingleStepPC, mSingleStepDataSize);
    450   mSingleStepActive = FALSE;
    451 }
    452 
    453 
    454 
    455 /**
    456  Continue. addr is Address to resume. If addr is omitted, resume at current
    457  Address.
    458 
    459  @param   SystemContext     Register content at time of the exception
    460  **/
    461 VOID
    462 EFIAPI
    463 ContinueAtAddress (
    464   IN  EFI_SYSTEM_CONTEXT      SystemContext,
    465   IN    CHAR8                 *PacketData
    466   )
    467 {
    468   if (PacketData[1] != '\0') {
    469     SystemContext.SystemContextArm->PC = AsciiStrHexToUintn (&PacketData[1]);
    470   }
    471 }
    472 
    473 
    474 /** s [addr ]
    475  Single step. addr is the Address at which to resume. If addr is omitted, resume
    476  at same Address.
    477 
    478  @param   SystemContext     Register content at time of the exception
    479  **/
    480 VOID
    481 EFIAPI
    482 SingleStep (
    483   IN  EFI_SYSTEM_CONTEXT      SystemContext,
    484   IN    CHAR8                       *PacketData
    485   )
    486 {
    487   SendNotSupported ();
    488 }
    489 
    490 UINTN
    491 GetBreakpointDataAddress (
    492   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    493   IN  UINTN               BreakpointNumber
    494   )
    495 {
    496   return 0;
    497 }
    498 
    499 UINTN
    500 GetBreakpointDetected (
    501   IN  EFI_SYSTEM_CONTEXT  SystemContext
    502   )
    503 {
    504   return 0;
    505 }
    506 
    507 BREAK_TYPE
    508 GetBreakpointType (
    509   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    510   IN  UINTN               BreakpointNumber
    511   )
    512 {
    513   return NotSupported;
    514 }
    515 
    516 ARM_SOFTWARE_BREAKPOINT *
    517 SearchBreakpointList (
    518   IN  UINT32  Address
    519   )
    520 {
    521   LIST_ENTRY              *Current;
    522   ARM_SOFTWARE_BREAKPOINT *Breakpoint;
    523 
    524   Current = GetFirstNode (&BreakpointList);
    525   while (!IsNull (&BreakpointList, Current)) {
    526     Breakpoint = ARM_SOFTWARE_BREAKPOINT_FROM_LINK(Current);
    527 
    528     if (Address == Breakpoint->Address) {
    529       return Breakpoint;
    530     }
    531 
    532     Current = GetNextNode (&BreakpointList, Current);
    533   }
    534 
    535   return NULL;
    536 }
    537 
    538 VOID
    539 SetBreakpoint (
    540   IN UINT32 Address
    541   )
    542 {
    543   ARM_SOFTWARE_BREAKPOINT *Breakpoint;
    544 
    545   Breakpoint = SearchBreakpointList (Address);
    546 
    547   if (Breakpoint != NULL) {
    548     return;
    549   }
    550 
    551   // create and fill breakpoint structure
    552   Breakpoint = AllocatePool (sizeof(ARM_SOFTWARE_BREAKPOINT));
    553 
    554   Breakpoint->Signature   = ARM_SOFTWARE_BREAKPOINT_SIGNATURE;
    555   Breakpoint->Address     = Address;
    556   Breakpoint->Instruction = *(UINT32 *)Address;
    557 
    558   // Add it to the list
    559   InsertTailList (&BreakpointList, &Breakpoint->Link);
    560 
    561   // Insert the software breakpoint
    562   *(UINT32 *)Address = GDB_ARM_BKPT;
    563   InvalidateInstructionCacheRange ((VOID *)Address, 4);
    564 
    565   //DEBUG((EFI_D_ERROR, "SetBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, Breakpoint->Instruction, *(UINT32 *)Address));
    566 }
    567 
    568 VOID
    569 ClearBreakpoint (
    570   IN UINT32 Address
    571   )
    572 {
    573   ARM_SOFTWARE_BREAKPOINT *Breakpoint;
    574 
    575   Breakpoint = SearchBreakpointList (Address);
    576 
    577   if (Breakpoint == NULL) {
    578     return;
    579   }
    580 
    581   // Add it to the list
    582   RemoveEntryList (&Breakpoint->Link);
    583 
    584   // Restore the original instruction
    585   *(UINT32 *)Address = Breakpoint->Instruction;
    586   InvalidateInstructionCacheRange ((VOID *)Address, 4);
    587 
    588   //DEBUG((EFI_D_ERROR, "ClearBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, GDB_ARM_BKPT, *(UINT32 *)Address));
    589 
    590   FreePool (Breakpoint);
    591 }
    592 
    593 VOID
    594 EFIAPI
    595 InsertBreakPoint (
    596   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    597   IN  CHAR8              *PacketData
    598   )
    599 {
    600   UINTN Type;
    601   UINTN Address;
    602   UINTN Length;
    603   UINTN ErrorCode;
    604 
    605   ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);
    606   if (ErrorCode > 0) {
    607     SendError ((UINT8)ErrorCode);
    608     return;
    609   }
    610 
    611   switch (Type) {
    612     case 0:   //Software breakpoint
    613       break;
    614 
    615     default  :
    616       DEBUG((EFI_D_ERROR, "Insert breakpoint default: %x\n", Type));
    617       SendError (GDB_EINVALIDBRKPOINTTYPE);
    618       return;
    619   }
    620 
    621   SetBreakpoint (Address);
    622 
    623   SendSuccess ();
    624 }
    625 
    626 VOID
    627 EFIAPI
    628 RemoveBreakPoint (
    629   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    630   IN  CHAR8               *PacketData
    631   )
    632 {
    633   UINTN      Type;
    634   UINTN      Address;
    635   UINTN      Length;
    636   UINTN      ErrorCode;
    637 
    638   //Parse breakpoint packet data
    639   ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);
    640   if (ErrorCode > 0) {
    641     SendError ((UINT8)ErrorCode);
    642     return;
    643   }
    644 
    645   switch (Type) {
    646     case 0:   //Software breakpoint
    647       break;
    648 
    649     default:
    650       SendError (GDB_EINVALIDBRKPOINTTYPE);
    651       return;
    652   }
    653 
    654   ClearBreakpoint (Address);
    655 
    656   SendSuccess ();
    657 }
    658 
    659 VOID
    660 InitializeProcessor (
    661   VOID
    662   )
    663 {
    664   // Initialize breakpoint list
    665   InitializeListHead (&BreakpointList);
    666 }
    667 
    668 BOOLEAN
    669 ValidateAddress (
    670   IN  VOID  *Address
    671   )
    672 {
    673   if ((UINT32)Address < 0x80000000) {
    674     return FALSE;
    675   } else {
    676     return TRUE;
    677   }
    678 }
    679 
    680 BOOLEAN
    681 ValidateException (
    682   IN  EFI_EXCEPTION_TYPE    ExceptionType,
    683   IN OUT EFI_SYSTEM_CONTEXT SystemContext
    684   )
    685 {
    686   UINT32  ExceptionAddress;
    687   UINT32  Instruction;
    688 
    689   // Is it a debugger SWI?
    690   ExceptionAddress = SystemContext.SystemContextArm->PC -= 4;
    691   Instruction      = *(UINT32 *)ExceptionAddress;
    692   if (Instruction != GDB_ARM_BKPT) {
    693     return FALSE;
    694   }
    695 
    696   // Special for SWI-based exception handling.  SWI sets up the context
    697   // to return to the instruction following the SWI instruction - NOT what we want
    698   // for a debugger!
    699   SystemContext.SystemContextArm->PC = ExceptionAddress;
    700 
    701   return TRUE;
    702 }
    703 
    704