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
MaxEfiException(VOID)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
MaxRegisterCount(VOID)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
CheckIsa(IN EFI_INSTRUCTION_SET_ARCHITECTURE Isa)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 *
FindPointerToRegister(IN EFI_SYSTEM_CONTEXT SystemContext,IN UINTN RegNumber)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 *
BasicReadRegister(IN EFI_SYSTEM_CONTEXT SystemContext,IN UINTN RegNumber,IN CHAR8 * OutBufPtr)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
ReadNthRegister(IN EFI_SYSTEM_CONTEXT SystemContext,IN CHAR8 * InBuffer)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
ReadGeneralRegisters(IN EFI_SYSTEM_CONTEXT SystemContext)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
BasicWriteRegister(IN EFI_SYSTEM_CONTEXT SystemContext,IN UINTN RegNumber,IN CHAR8 * InBufPtr)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
WriteNthRegister(IN EFI_SYSTEM_CONTEXT SystemContext,IN CHAR8 * InBuffer)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
WriteGeneralRegisters(IN EFI_SYSTEM_CONTEXT SystemContext,IN CHAR8 * InBuffer)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
AddSingleStep(IN EFI_SYSTEM_CONTEXT SystemContext)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
RemoveSingleStep(IN EFI_SYSTEM_CONTEXT SystemContext)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
ContinueAtAddress(IN EFI_SYSTEM_CONTEXT SystemContext,IN CHAR8 * PacketData)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
SingleStep(IN EFI_SYSTEM_CONTEXT SystemContext,IN CHAR8 * PacketData)482 SingleStep (
483   IN  EFI_SYSTEM_CONTEXT      SystemContext,
484   IN    CHAR8                       *PacketData
485   )
486 {
487   SendNotSupported ();
488 }
489 
490 UINTN
GetBreakpointDataAddress(IN EFI_SYSTEM_CONTEXT SystemContext,IN UINTN BreakpointNumber)491 GetBreakpointDataAddress (
492   IN  EFI_SYSTEM_CONTEXT  SystemContext,
493   IN  UINTN               BreakpointNumber
494   )
495 {
496   return 0;
497 }
498 
499 UINTN
GetBreakpointDetected(IN EFI_SYSTEM_CONTEXT SystemContext)500 GetBreakpointDetected (
501   IN  EFI_SYSTEM_CONTEXT  SystemContext
502   )
503 {
504   return 0;
505 }
506 
507 BREAK_TYPE
GetBreakpointType(IN EFI_SYSTEM_CONTEXT SystemContext,IN UINTN BreakpointNumber)508 GetBreakpointType (
509   IN  EFI_SYSTEM_CONTEXT  SystemContext,
510   IN  UINTN               BreakpointNumber
511   )
512 {
513   return NotSupported;
514 }
515 
516 ARM_SOFTWARE_BREAKPOINT *
SearchBreakpointList(IN UINT32 Address)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
SetBreakpoint(IN UINT32 Address)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
ClearBreakpoint(IN UINT32 Address)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
InsertBreakPoint(IN EFI_SYSTEM_CONTEXT SystemContext,IN CHAR8 * PacketData)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
RemoveBreakPoint(IN EFI_SYSTEM_CONTEXT SystemContext,IN CHAR8 * PacketData)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
InitializeProcessor(VOID)660 InitializeProcessor (
661   VOID
662   )
663 {
664   // Initialize breakpoint list
665   InitializeListHead (&BreakpointList);
666 }
667 
668 BOOLEAN
ValidateAddress(IN VOID * Address)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
ValidateException(IN EFI_EXCEPTION_TYPE ExceptionType,IN OUT EFI_SYSTEM_CONTEXT SystemContext)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