Add the beginning of a GDB based Debug Agent. IA-32 and X64 don't have low level...
authorandrewfish <andrewfish@6f19259b-4bc3-4df7-8a09-765794883524>
Sat, 3 Apr 2010 00:41:42 +0000 (00:41 +0000)
committerandrewfish <andrewfish@6f19259b-4bc3-4df7-8a09-765794883524>
Sat, 3 Apr 2010 00:41:42 +0000 (00:41 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10334 6f19259b-4bc3-4df7-8a09-765794883524

14 files changed:
EmbeddedPkg/EmbeddedPkg.dec
EmbeddedPkg/GdbStub/Arm/Processor.c
EmbeddedPkg/Include/Library/DebugAgentTimerLib.h [new file with mode: 0755]
EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLib.c [new file with mode: 0755]
EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLibNull.inf [new file with mode: 0755]
EmbeddedPkg/Library/GdbDebugAgent/Arm/ExceptionSupport.ARMv6.S [new file with mode: 0755]
EmbeddedPkg/Library/GdbDebugAgent/Arm/ExceptionSupport.ARMv6.asm [new file with mode: 0755]
EmbeddedPkg/Library/GdbDebugAgent/Arm/Processor.c [new file with mode: 0755]
EmbeddedPkg/Library/GdbDebugAgent/GdbDebugAgent.c [new file with mode: 0755]
EmbeddedPkg/Library/GdbDebugAgent/GdbDebugAgent.h [new file with mode: 0755]
EmbeddedPkg/Library/GdbDebugAgent/GdbDebugAgent.inf [new file with mode: 0755]
EmbeddedPkg/Library/GdbDebugAgent/Ia32/Processor.c [new file with mode: 0755]
EmbeddedPkg/Library/GdbDebugAgent/X64/Processor.c [new file with mode: 0755]
EmbeddedPkg/Library/GdbDebugAgent/gdbnotes.txt [new file with mode: 0755]

index f795128..d61d1a9 100644 (file)
   RealTimeClockLib|Include/Library/RealTimeClockLib.h\r
   EfiResetSystemLib|Include/Library/EfiResetSystemLib.h\r
   EblCmdLib|Include/Library/EblCmdLib.h\r
   RealTimeClockLib|Include/Library/RealTimeClockLib.h\r
   EfiResetSystemLib|Include/Library/EfiResetSystemLib.h\r
   EblCmdLib|Include/Library/EblCmdLib.h\r
-  EblAddExternalCommandLib|Library/EblAddExternalCommandLib.h\r
-  EblNetworkLib|Library/EblNetworkLib.h\r
+  EblAddExternalCommandLib|Include/Library/EblAddExternalCommandLib.h\r
+  EblNetworkLib|Include/Library/EblNetworkLib.h\r
   GdbSerialLib|Include/Library/GdbSerialLib.h\r
   GdbSerialLib|Include/Library/GdbSerialLib.h\r
+  DebugAgentTimerLib|Include/Library/DebugAgentTimerLib.h\r
 \r
 \r
 [Guids.common]\r
 \r
 \r
 [Guids.common]\r
index e620d34..77ea933 100644 (file)
@@ -88,8 +88,6 @@ UINTN gRegisterOffsets[] = {
   0x00000F72,\r
   0x00000F73,\r
   0x00000FFF,                               // fps\r
   0x00000F72,\r
   0x00000F73,\r
   0x00000FFF,                               // fps\r
-  0x00000FFF,                               \r
-  0x00000FFF,                               \r
   OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, CPSR)\r
 };\r
 \r
   OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, CPSR)\r
 };\r
 \r
diff --git a/EmbeddedPkg/Include/Library/DebugAgentTimerLib.h b/EmbeddedPkg/Include/Library/DebugAgentTimerLib.h
new file mode 100755 (executable)
index 0000000..fed071a
--- /dev/null
@@ -0,0 +1,62 @@
+/** @file\r
+  Platform specific Debug Agent abstraction for timer used by the agent. \r
+\r
+  The timer is used by the debugger to break into a running program.\r
+\r
+  Copyright (c) 2008-2010, 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
+\r
+#ifndef __GDB_TIMER_LIB__\r
+#define __GDB_TIMER_LIB__\r
+\r
+\r
+\r
+/**\r
+  Setup all the hardware needed for the debug agents timer.\r
+\r
+  This function is used to set up debug enviroment. It may enable interrupts.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+DebugAgentTimerIntialize (\r
+  VOID\r
+  );\r
+  \r
+\r
+/**\r
+  Set the period for the debug agent timer. Zero means disable the timer.\r
+\r
+  @param[in] TimerPeriodMilliseconds    Frequency of the debug agent timer.\r
+\r
+**/  \r
+VOID\r
+EFIAPI\r
+DebugAgentTimerSetPeriod (\r
+  IN  UINT32  TimerPeriodMilliseconds\r
+  );\r
+  \r
+\r
+/**\r
+  Perform End Of Interrupt for the debug agent timer. This is called in the \r
+  interrupt handler after the interrupt has been processed. \r
+\r
+**/  \r
+VOID\r
+EFIAPI\r
+DebugAgentTimerEndOfInterrupt (\r
+  VOID\r
+  );\r
+  \r
+#endif\r
+  \r
+  
\ No newline at end of file
diff --git a/EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLib.c b/EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLib.c
new file mode 100755 (executable)
index 0000000..1aa2d29
--- /dev/null
@@ -0,0 +1,64 @@
+/** @file\r
+  Null Debug Agent timer.\r
+\r
+  The debug agent uses the timer so the debugger can break into running programs.\r
+  If you link against this library you will not be able to break into a running\r
+  program with the debugger.\r
+\r
+  Copyright (c) 2008-2010, 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
+\r
+\r
+/**\r
+  Setup all the hardware needed for the debug agents timer.\r
+\r
+  This function is used to set up debug enviroment. It may enable interrupts.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+DebugAgentTimerIntialize (\r
+  VOID\r
+  )\r
+{\r
+}\r
+  \r
+  \r
+/**\r
+  Set the period for the debug agent timer. Zero means disable the timer.\r
+\r
+  @param[in] TimerPeriodMilliseconds    Frequency of the debug agent timer.\r
+\r
+**/  \r
+VOID\r
+EFIAPI\r
+DebugAgentTimerSetPeriod (\r
+  IN  UINT32  TimerPeriodMilliseconds\r
+  )\r
+{\r
+}\r
+  \r
+\r
+/**\r
+  Perform End Of Interrupt for the debug agent timer. This is called in the \r
+  interrupt handler after the interrupt has been processed. \r
+\r
+**/  \r
+VOID\r
+EFIAPI\r
+DebugAgentTimerEndOfInterrupt (\r
+  VOID\r
+  )\r
+{\r
+}\r
+  \r
+  
\ No newline at end of file
diff --git a/EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLibNull.inf b/EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLibNull.inf
new file mode 100755 (executable)
index 0000000..4df40a3
--- /dev/null
@@ -0,0 +1,37 @@
+#/** @file\r
+# Component description file for Base PCI Cf8 Library.\r
+#\r
+# PCI CF8 Library that uses I/O ports 0xCF8 and 0xCFC to perform PCI Configuration cycles.\r
+#  Layers on top of an I/O Library instance.\r
+# Copyright (c) 2007, Intel Corporation.\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
+#  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
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = DebugAgentTimerLibNull\r
+  FILE_GUID                      = 02f04694-2c0a-4f1e-b0ce-64be25890b03\r
+  MODULE_TYPE                    = BASE\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = DebugAgentTimerLib|SEC BASE DXE_CORE\r
+\r
+\r
+[Sources.common]\r
+  DebugAgentTimerLib.c\r
+\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  EmbeddedPkg/EmbeddedPkg.dec\r
+\r
+[LibraryClasses]\r
+  IoLib\r
+\r
diff --git a/EmbeddedPkg/Library/GdbDebugAgent/Arm/ExceptionSupport.ARMv6.S b/EmbeddedPkg/Library/GdbDebugAgent/Arm/ExceptionSupport.ARMv6.S
new file mode 100755 (executable)
index 0000000..bb4d17c
--- /dev/null
@@ -0,0 +1,258 @@
+#------------------------------------------------------------------------------ 
+#
+# Use ARMv6 instruction to operate on a single stack
+#
+# Copyright (c) 2008-2010 Apple Inc. All rights reserved.
+#
+# All rights reserved. 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.
+#
+#------------------------------------------------------------------------------
+
+/*
+
+This is the stack constructed by the exception handler (low address to high address)
+                # R0 - IFAR is EFI_SYSTEM_CONTEXT for ARM
+  Reg   Offset
+  ===   ======              
+  R0    0x00    # stmfd     SP!,{R0-R12}
+  R1    0x04
+  R2    0x08
+  R3    0x0c
+  R4    0x10
+  R5    0x14
+  R6    0x18
+  R7    0x1c
+  R8    0x20
+  R9    0x24
+  R10   0x28
+  R11   0x2c
+  R12   0x30
+  SP    0x34    # reserved via adding 0x20 (32) to the SP
+  LR    0x38
+  PC    0x3c
+  CPSR  0x40
+  DFSR  0x44
+  DFAR  0x48
+  IFSR  0x4c
+  IFAR  0x50
+  
+  LR    0x54    # SVC Link register (we need to restore it)
+  
+  LR    0x58    # pushed by srsfd    
+  CPSR  0x5c    
+
+ */
+
+.globl ASM_PFX(ExceptionHandlersStart)
+.globl ASM_PFX(ExceptionHandlersEnd)
+.globl ASM_PFX(CommonExceptionEntry)
+.globl ASM_PFX(AsmCommonExceptionEntry)
+.globl ASM_PFX(GdbExceptionHandler)
+
+.text
+.align 3
+
+
+//
+// This code gets copied to the ARM vector table
+// ExceptionHandlersStart - ExceptionHandlersEnd gets copied
+//
+ASM_PFX(ExceptionHandlersStart):
+
+ASM_PFX(Reset):
+  b ASM_PFX(Reset)
+
+ASM_PFX(UndefinedInstruction):
+  b ASM_PFX(UndefinedInstructionEntry)
+
+ASM_PFX(SoftwareInterrupt):
+  b ASM_PFX(SoftwareInterruptEntry)
+
+ASM_PFX(PrefetchAbort):
+  b ASM_PFX(PrefetchAbortEntry)
+
+ASM_PFX(DataAbort):
+  b ASM_PFX(DataAbortEntry)
+
+ASM_PFX(ReservedException):
+  b ASM_PFX(ReservedExceptionEntry)
+
+ASM_PFX(Irq):
+  b ASM_PFX(Irq)
+
+ASM_PFX(Fiq):
+  b ASM_PFX(FiqEntry)
+
+
+ASM_PFX(UndefinedInstructionEntry):
+  sub       LR, LR, #4                @ Only -2 for Thumb, adjust in CommonExceptionEntry
+  srsdb     #0x13!                    @ Store return state on SVC stack
+  cps       #0x13                     @ Switch to SVC for common stack
+  stmfd     SP!,{LR}                  @ Store the link register for the current mode
+  sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR
+  stmfd     SP!,{R0-R12}              @ Store the register state
+
+  mov       R0,#1                     @ ExceptionType
+  ldr       R1,ASM_PFX(CommonExceptionEntry)
+  bx        R1
+
+ASM_PFX(SoftwareInterruptEntry):
+  sub       LR, LR, #4                @ Only -2 for Thumb, adjust in CommonExceptionEntry
+  srsdb     #0x13!                    @ Store return state on SVC stack
+                                      @ We are already in SVC mode
+  stmfd     SP!,{LR}                  @ Store the link register for the current mode
+  sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR
+  stmfd     SP!,{R0-R12}              @ Store the register state
+
+  mov       R0,#2                     @ ExceptionType
+  ldr       R1,ASM_PFX(CommonExceptionEntry)
+  bx        R1
+
+ASM_PFX(PrefetchAbortEntry):
+  sub       LR,LR,#4
+  srsdb     #0x13!                    @ Store return state on SVC stack
+  cps       #0x13                     @ Switch to SVC for common stack
+  stmfd     SP!,{LR}                  @ Store the link register for the current mode
+  sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR
+  stmfd     SP!,{R0-R12}              @ Store the register state
+
+  mov       R0,#3                     @ ExceptionType
+  ldr       R1,ASM_PFX(CommonExceptionEntry)
+  bx        R1
+
+ASM_PFX(DataAbortEntry):
+  sub       LR,LR,#8
+  srsdb     #0x13!                    @ Store return state on SVC stack
+  cps       #0x13                     @ Switch to SVC for common stack
+  stmfd     SP!,{LR}                  @ Store the link register for the current mode
+  sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR
+  stmfd     SP!,{R0-R12}              @ Store the register state
+
+  mov       R0,#4
+  ldr       R1,ASM_PFX(CommonExceptionEntry)
+  bx        R1
+
+ASM_PFX(ReservedExceptionEntry):
+  srsdb     #0x13!                    @ Store return state on SVC stack
+  cps       #0x13                     @ Switch to SVC for common stack
+  stmfd     SP!,{LR}                  @ Store the link register for the current mode
+  sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR
+  stmfd     SP!,{R0-R12}              @ Store the register state
+
+  mov       R0,#5
+  ldr       R1,ASM_PFX(CommonExceptionEntry)
+  bx        R1
+
+ASM_PFX(FiqEntry):
+  sub       LR,LR,#4
+  srsdb     #0x13!                    @ Store return state on SVC stack
+  cps       #0x13                     @ Switch to SVC for common stack
+  stmfd     SP!,{LR}                  @ Store the link register for the current mode
+  sub       SP,SP,#0x20               @ Save space for SP, LR, PC, IFAR - CPSR
+  stmfd     SP!,{R0-R12}              @ Store the register state
+                                      @ Since we have already switch to SVC R8_fiq - R12_fiq
+                                      @ never get used or saved
+  mov       R0,#7                     @ ExceptionType
+  ldr       R1,ASM_PFX(CommonExceptionEntry)
+  bx        R1
+
+//
+// This gets patched by the C code that patches in the vector table
+//
+ASM_PFX(CommonExceptionEntry):
+  .byte       0x12
+  .byte       0x34
+  .byte       0x56
+  .byte       0x78
+
+ASM_PFX(ExceptionHandlersEnd):
+
+//
+// This code runs from CpuDxe driver loaded address. It is patched into 
+// CommonExceptionEntry.
+//
+ASM_PFX(AsmCommonExceptionEntry):
+  mrc       p15, 0, R1, c6, c0, 2   @ Read IFAR
+  str       R1, [SP, #0x50]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.IFAR 
+  
+  mrc       p15, 0, R1, c5, c0, 1   @ Read IFSR
+  str       R1, [SP, #0x4c]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.IFSR
+  
+  mrc       p15, 0, R1, c6, c0, 0   @ Read DFAR
+  str       R1, [SP, #0x48]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFAR
+  
+  mrc       p15, 0, R1, c5, c0, 0   @ Read DFSR
+  str       R1, [SP, #0x44]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR
+  
+  ldr       R1, [SP, #0x5c]         @ srsdb saved pre-exception CPSR on the stack 
+  str       R1, [SP, #0x40]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.CPSR
+
+  add       R2, SP, #0x38           @ Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR
+  and       R3, R1, #0x1f           @ Check CPSR to see if User or System Mode
+  cmp       R3, #0x1f               @ if ((CPSR == 0x10) || (CPSR == 0x1df))
+  cmpne     R3, #0x10               @   
+  stmeqed   R2, {lr}^               @   save unbanked lr
+                                    @ else 
+  stmneed   R2, {lr}                @   save SVC lr
+
+
+  ldr       R5, [SP, #0x58]         @ PC is the LR pushed by srsfd 
+                                    @ Check to see if we have to adjust for Thumb entry
+  sub       r4, r0, #1              @ if (ExceptionType == 1 || ExceptionType ==2)) {
+  cmp       r4, #1                  @   // UND & SVC have differnt LR adjust for Thumb 
+  bhi       NoAdjustNeeded
+  
+  tst       r1, #0x20               @   if ((CPSR & T)) == T) {  // Thumb Mode on entry 
+  addne     R5, R5, #2              @     PC += 2@
+  str       R5,[SP,#0x58]           @ Update LR value pused by srsfd 
+  
+NoAdjustNeeded:
+
+  str       R5, [SP, #0x3c]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.PC
+  
+  sub       R1, SP, #0x60           @ We pused 0x60 bytes on the stack 
+  str       R1, [SP, #0x34]         @ Store it in EFI_SYSTEM_CONTEXT_ARM.SP
+  
+                                    @ R0 is ExceptionType 
+  mov       R1,SP                   @ R1 is SystemContext 
+
+/* 
+VOID
+EFIAPI
+GdbExceptionHandler (
+  IN     EFI_EXCEPTION_TYPE           ExceptionType,   R0
+  IN OUT EFI_SYSTEM_CONTEXT           SystemContext    R1
+  )
+
+*/  
+  blx       ASM_PFX(GdbExceptionHandler)  @ Call exception handler
+  
+  ldr       R1,[SP,#0x3c]           @ EFI_SYSTEM_CONTEXT_ARM.PC
+  str       R1,[SP,#0x58]           @ Store it back to srsfd stack slot so it can be restored 
+
+  ldr       R1,[SP,#0x40]           @ EFI_SYSTEM_CONTEXT_ARM.CPSR
+  str       R1,[SP,#0x5c]           @ Store it back to srsfd stack slot so it can be restored 
+  
+  add       R3, SP, #0x54           @ Make R3 point to SVC LR saved on entry
+  add       R2, SP, #0x38           @ Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR
+  and       R1, R1, #0x1f           @ Check to see if User or System Mode
+  cmp       R1, #0x1f               @ if ((CPSR == 0x10) || (CPSR == 0x1f))
+  cmpne     R1, #0x10               @   
+  ldmeqed   R2, {lr}^               @   restore unbanked lr
+                                    @ else
+  ldmneed   R3, {lr}                @   restore SVC lr, via ldmfd SP!, {LR}
+  
+  ldmfd     SP!,{R0-R12}            @ Restore general purpose registers
+                                    @ Exception handler can not change SP
+                                    
+  add       SP,SP,#0x20             @ Clear out the remaining stack space
+  ldmfd     SP!,{LR}                @ restore the link register for this context
+  rfefd     SP!                     @ return from exception via srsfd stack slot
+  
diff --git a/EmbeddedPkg/Library/GdbDebugAgent/Arm/ExceptionSupport.ARMv6.asm b/EmbeddedPkg/Library/GdbDebugAgent/Arm/ExceptionSupport.ARMv6.asm
new file mode 100755 (executable)
index 0000000..3dccf5b
--- /dev/null
@@ -0,0 +1,259 @@
+//------------------------------------------------------------------------------ 
+//
+// Use ARMv6 instruction to operate on a single stack
+//
+// Copyright (c) 2008-2010 Apple Inc. All rights reserved.
+//
+// All rights reserved. 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.
+//
+//------------------------------------------------------------------------------
+
+
+
+/*
+
+This is the stack constructed by the exception handler (low address to high address)
+                # R0 - IFAR is EFI_SYSTEM_CONTEXT for ARM
+  Reg   Offset
+  ===   ======              
+  R0    0x00    # stmfd     SP!,{R0-R12}
+  R1    0x04
+  R2    0x08
+  R3    0x0c
+  R4    0x10
+  R5    0x14
+  R6    0x18
+  R7    0x1c
+  R8    0x20
+  R9    0x24
+  R10   0x28
+  R11   0x2c
+  R12   0x30
+  SP    0x34    # reserved via adding 0x20 (32) to the SP
+  LR    0x38
+  PC    0x3c
+  CPSR  0x40
+  DFSR  0x44
+  DFAR  0x48
+  IFSR  0x4c
+  IFAR  0x50
+  
+  LR    0x54    # SVC Link register (we need to restore it)
+  
+  LR    0x58    # pushed by srsfd    
+  CPSR  0x5c    
+
+ */
+  EXPORT  ExceptionHandlersStart
+  EXPORT  ExceptionHandlersEnd
+  EXPORT  CommonExceptionEntry
+  EXPORT  AsmCommonExceptionEntry
+  IMPORT  GdbExceptionHandler
+
+  PRESERVE8
+  AREA  DxeExceptionHandlers, CODE, READONLY
+  
+//
+// This code gets copied to the ARM vector table
+// ExceptionHandlersStart - ExceptionHandlersEnd gets copied
+//
+ExceptionHandlersStart
+
+Reset
+  b   Reset
+
+UndefinedInstruction
+  b   UndefinedInstructionEntry
+
+SoftwareInterrupt
+  b   SoftwareInterruptEntry
+
+PrefetchAbort
+  b   PrefetchAbortEntry
+
+DataAbort
+  b   DataAbortEntry
+
+ReservedException
+  b   ReservedExceptionEntry
+
+Irq
+  b   Irq
+
+Fiq
+  b   FiqEntry
+
+
+UndefinedInstructionEntry
+  sub       LR, LR, #4                ; Only -2 for Thumb, adjust in CommonExceptionEntry
+  srsfd     #0x13!                    ; Store return state on SVC stack
+  cps       #0x13                     ; Switch to SVC for common stack
+  stmfd     SP!,{LR}                  ; Store the link register for the current mode
+  sub       SP,SP,#0x20               ; Save space for SP, LR, PC, IFAR - CPSR
+  stmfd     SP!,{R0-R12}              ; Store the register state
+
+  mov       R0,#1                     ; ExceptionType
+  ldr       R1,CommonExceptionEntry; 
+  bx        R1
+
+SoftwareInterruptEntry
+  sub       LR, LR, #4                ; Only -2 for Thumb, adjust in CommonExceptionEntry
+  srsfd     #0x13!                    ; Store return state on SVC stack
+                                      ; We are already in SVC mode
+  stmfd     SP!,{LR}                  ; Store the link register for the current mode
+  sub       SP,SP,#0x20               ; Save space for SP, LR, PC, IFAR - CPSR
+  stmfd     SP!,{R0-R12}              ; Store the register state
+
+  mov       R0,#2                     ; ExceptionType
+  ldr       R1,CommonExceptionEntry
+  bx        R1
+
+PrefetchAbortEntry
+  sub       LR,LR,#4
+  srsfd     #0x13!                    ; Store return state on SVC stack
+  cps       #0x13                     ; Switch to SVC for common stack
+  stmfd     SP!,{LR}                  ; Store the link register for the current mode
+  sub       SP,SP,#0x20               ; Save space for SP, LR, PC, IFAR - CPSR
+  stmfd     SP!,{R0-R12}              ; Store the register state
+
+  mov       R0,#3                     ; ExceptionType
+  ldr       R1,CommonExceptionEntry
+  bx        R1
+
+DataAbortEntry
+  sub       LR,LR,#8
+  srsfd     #0x13!                    ; Store return state on SVC stack
+  cps       #0x13                     ; Switch to SVC for common stack
+  stmfd     SP!,{LR}                  ; Store the link register for the current mode
+  sub       SP,SP,#0x20               ; Save space for SP, LR, PC, IFAR - CPSR
+  stmfd     SP!,{R0-R12}              ; Store the register state
+
+  mov       R0,#4                     ; ExceptionType
+  ldr       R1,CommonExceptionEntry
+  bx        R1
+
+ReservedExceptionEntry
+  srsfd     #0x13!                    ; Store return state on SVC stack
+  cps       #0x13                     ; Switch to SVC for common stack
+  stmfd     SP!,{LR}                  ; Store the link register for the current mode
+  sub       SP,SP,#0x20               ; Save space for SP, LR, PC, IFAR - CPSR
+  stmfd     SP!,{R0-R12}              ; Store the register state
+
+  mov       R0,#5                     ; ExceptionType
+  ldr       R1,CommonExceptionEntry
+  bx        R1
+
+FiqEntry
+  sub       LR,LR,#4
+  srsfd     #0x13!                    ; Store return state on SVC stack
+  cps       #0x13                     ; Switch to SVC for common stack
+  stmfd     SP!,{LR}                  ; Store the link register for the current mode
+  sub       SP,SP,#0x20               ; Save space for SP, LR, PC, IFAR - CPSR
+  stmfd     SP!,{R0-R12}              ; Store the register state
+                                      ; Since we have already switch to SVC R8_fiq - R12_fiq
+                                      ; never get used or saved
+  mov       R0,#7                     ; ExceptionType
+  ldr       R1,CommonExceptionEntry
+  bx        R1
+
+//
+// This gets patched by the C code that patches in the vector table
+//
+CommonExceptionEntry
+  dcd       0x12345678
+
+ExceptionHandlersEnd
+
+//
+// This code runs from CpuDxe driver loaded address. It is patched into 
+// CommonExceptionEntry.
+//
+AsmCommonExceptionEntry
+  mrc       p15, 0, R1, c6, c0, 2   ; Read IFAR
+  str       R1, [SP, #0x50]         ; Store it in EFI_SYSTEM_CONTEXT_ARM.IFAR 
+  
+  mrc       p15, 0, R1, c5, c0, 1   ; Read IFSR
+  str       R1, [SP, #0x4c]         ; Store it in EFI_SYSTEM_CONTEXT_ARM.IFSR
+  
+  mrc       p15, 0, R1, c6, c0, 0   ; Read DFAR
+  str       R1, [SP, #0x48]         ; Store it in EFI_SYSTEM_CONTEXT_ARM.DFAR
+  
+  mrc       p15, 0, R1, c5, c0, 0   ; Read DFSR
+  str       R1, [SP, #0x44]         ; Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR
+  
+  ldr       R1, [SP, #0x5c]         ; srsfd saved pre-exception CPSR on the stack 
+  str       R1, [SP, #0x40]         ; Store it in EFI_SYSTEM_CONTEXT_ARM.CPSR
+
+  add       R2, SP, #0x38           ; Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR
+  and       R3, R1, #0x1f           ; Check CPSR to see if User or System Mode
+  cmp       R3, #0x1f               ; if ((CPSR == 0x10) || (CPSR == 0x1df))
+  cmpne     R3, #0x10               ;   
+  stmeqed   R2, {lr}^               ;   save unbanked lr
+                                    ; else 
+  stmneed   R2, {lr}                ;   save SVC lr
+
+
+  ldr       R5, [SP, #0x58]         ; PC is the LR pushed by srsfd 
+                                    ; Check to see if we have to adjust for Thumb entry
+  sub       r4, r0, #1              ; if (ExceptionType == 1 || ExceptionType ==2)) {
+  cmp       r4, #1                  ;   // UND & SVC have differnt LR adjust for Thumb 
+  bhi       NoAdjustNeeded
+  
+  tst       r1, #0x20               ;   if ((CPSR & T)) == T) {  // Thumb Mode on entry 
+  addne     R5, R5, #2              ;     PC += 2;
+  str       R5,[SP,#0x58]           ; Update LR value pused by srsfd 
+  
+NoAdjustNeeded
+
+  str       R5, [SP, #0x3c]         ; Store it in EFI_SYSTEM_CONTEXT_ARM.PC
+  
+  sub       R1, SP, #0x60           ; We pused 0x60 bytes on the stack 
+  str       R1, [SP, #0x34]         ; Store it in EFI_SYSTEM_CONTEXT_ARM.SP
+  
+                                    ; R0 is ExceptionType 
+  mov       R1,SP                   ; R1 is SystemContext 
+
+/* 
+VOID
+EFIAPI
+GdbExceptionHandler (
+  IN     EFI_EXCEPTION_TYPE           ExceptionType,   R0
+  IN OUT EFI_SYSTEM_CONTEXT           SystemContext    R1
+  )
+
+*/
+  blx       GdbExceptionHandler     ; Call exception handler
+  
+  ldr       R1,[SP,#0x3c]           ; EFI_SYSTEM_CONTEXT_ARM.PC
+  str       R1,[SP,#0x58]           ; Store it back to srsfd stack slot so it can be restored 
+
+  ldr       R1,[SP,#0x40]           ; EFI_SYSTEM_CONTEXT_ARM.CPSR
+  str       R1,[SP,#0x5c]           ; Store it back to srsfd stack slot so it can be restored 
+  
+  add       R3, SP, #0x54           ; Make R3 point to SVC LR saved on entry
+  add       R2, SP, #0x38           ; Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR
+  and       R1, R1, #0x1f           ; Check to see if User or System Mode
+  cmp       R1, #0x1f               ; if ((CPSR == 0x10) || (CPSR == 0x1f))
+  cmpne     R1, #0x10               ;   
+  ldmeqed   R2, {lr}^               ;   restore unbanked lr
+                                    ; else
+  ldmneed   R3, {lr}                ;   restore SVC lr, via ldmfd SP!, {LR}
+  
+  ldmfd     SP!,{R0-R12}            ; Restore general purpose registers
+                                    ; Exception handler can not change SP
+                                    
+  add       SP,SP,#0x20             ; Clear out the remaining stack space
+  ldmfd     SP!,{LR}                ; restore the link register for this context
+  rfefd     SP!                     ; return from exception via srsfd stack slot
+  
+  END
+
+
diff --git a/EmbeddedPkg/Library/GdbDebugAgent/Arm/Processor.c b/EmbeddedPkg/Library/GdbDebugAgent/Arm/Processor.c
new file mode 100755 (executable)
index 0000000..e09e18d
--- /dev/null
@@ -0,0 +1,630 @@
+/** @file\r
+  Processor specific parts of the GDB stub\r
+\r
+  Copyright (c) 2008-2010, 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
+\r
+\r
+#include <GdbDebugAgent.h>\r
+#include <Library/CacheMaintenanceLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/ArmLib.h>\r
+\r
+//\r
+// Externs from the exception handler assembly file\r
+//\r
+VOID\r
+ExceptionHandlersStart (\r
+  VOID\r
+  );\r
+\r
+VOID\r
+ExceptionHandlersEnd (\r
+  VOID\r
+  );\r
+\r
+VOID\r
+CommonExceptionEntry (\r
+  VOID\r
+  );\r
+\r
+VOID\r
+AsmCommonExceptionEntry (\r
+  VOID\r
+  );\r
+\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_SIGTRAP },    // GDB_SIGEMT\r
+  { EXCEPT_ARM_RESERVED,              GDB_SIGTRAP },    // GDB_SIGILL\r
+  { EXCEPT_ARM_FIQ,                   GDB_SIGINT }      // Used for ctrl-c\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
+  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
+/**\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
+\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 >= (sizeof (gRegisterOffsets)/sizeof (UINTN))) {\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
+  // a UINT32 takes 8 ascii characters\r
+  CHAR8   OutBuffer[(sizeof (gRegisterOffsets) * 2) + 1];\r
+  CHAR8   *OutBufPtr;\r
+  \r
+  // It is not safe to allocate pool here....\r
+  OutBufPtr = OutBuffer;\r
+  for (Index = 0; Index < (sizeof (gRegisterOffsets)/sizeof (UINTN)); Index++) {\r
+    OutBufPtr = BasicReadRegister (SystemContext, Index, OutBufPtr);\r
+  }\r
+  \r
+  *OutBufPtr = '\0';\r
+  SendPacket(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 >= (sizeof (gRegisterOffsets)/sizeof (UINTN))) {\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 = (sizeof (gRegisterOffsets)/sizeof (UINTN));\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
+\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
+\r
+VOID\r
+EFIAPI\r
+InsertBreakPoint (\r
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,\r
+  IN  CHAR8              *PacketData\r
+  )\r
+{\r
+  SendNotSupported ();\r
+}\r
+\r
+VOID\r
+EFIAPI\r
+RemoveBreakPoint (\r
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,\r
+  IN  CHAR8               *PacketData\r
+  )\r
+{\r
+  SendNotSupported ();\r
+}\r
+\r
+\r
+/**
+ Send the T signal with the given exception type (in gdb order) and possibly 
+ with n:r pairs related to the watchpoints
+ @param  SystemContext        Register content at time of the exception
+ @param  GdbExceptionType     GDB exception type
+ **/
+VOID
+ProcessorSendTSignal (
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,
+  IN  UINT8               GdbExceptionType,
+  IN  OUT CHAR8           *TSignalPtr,
+  IN  UINTN               SizeOfBuffer
+  )
+{
+  *TSignalPtr = '\0';
+}
+\r
+/**\r
+ Check to see if this exception is related to ctrl-c handling.\r
+\r
+ In this scheme we dedicate FIQ to the ctrl-c handler so it is \r
+ independent of the rest of the system. \r
\r
+ SaveAndSetDebugTimerInterrupt () can be used to \r
+\r
+ @param ExceptionType     Exception that is being processed\r
+ @param SystemContext     Register content at time of the exception  \r
+\r
+ @return  TRUE  This was a ctrl-c check that did not find a ctrl-c\r
+ @return  FALSE This was not a ctrl-c check or some one hit ctrl-c\r
+ **/\r
+BOOLEAN\r
+ProcessorControlC ( \r
+  IN  EFI_EXCEPTION_TYPE        ExceptionType, \r
+  IN OUT EFI_SYSTEM_CONTEXT     SystemContext \r
+  )\r
+{\r
+  BOOLEAN   Return = TRUE;\r
+\r
+  if (ExceptionType != EXCEPT_ARM_FIQ) {\r
+    // Skip it as it is not related to ctrl-c\r
+    return FALSE;\r
+  }\r
+\r
+  while (TRUE) {
+    if (!GdbIsCharAvailable ()) {
+      //
+      // No characters are pending so exit the loop
+      //
+      Return = TRUE;
+      break;
+    }
+    
+    if (GdbGetChar () == 0x03) {
+      //
+      // We have a ctrl-c so exit and process exception for ctrl-c
+      //
+      Return = FALSE;
+      break;
+    }
+  }
+\r
+  DebugAgentTimerEndOfInterrupt ();\r
+\r
+  //  Force an exit from the exception handler as we are done\r
+  return Return;\r
+}\r
+\r
+\r
+/**\r
+  Enable/Disable the interrupt of debug timer and return the interrupt state\r
+  prior to the operation.\r
+\r
+  If EnableStatus is TRUE, enable the interrupt of debug timer.\r
+  If EnableStatus is FALSE, disable the interrupt of debug timer.\r
+\r
+  @param[in] EnableStatus    Enable/Disable.\r
+\r
+  @return FALSE always.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+SaveAndSetDebugTimerInterrupt (\r
+  IN BOOLEAN                EnableStatus\r
+  )\r
+{\r
+  BOOLEAN              FiqEnabled;\r
+\r
+  FiqEnabled = ArmGetFiqState ();\r
+\r
+  if (EnableStatus) {\r
+    DebugAgentTimerSetPeriod (100);\r
+    ArmEnableFiq ();\r
+  } else {\r
+    DebugAgentTimerSetPeriod (0);\r
+    ArmDisableFiq ();\r
+  }\r
+\r
+  return FiqEnabled;\r
+}\r
+\r
+VOID\r
+GdbFPutString (\r
+  IN CHAR8  *String\r
+  );\r
+\r
+/**\r
+  Initialize debug agent.\r
+\r
+  This function is used to set up debug enviroment. It may enable interrupts.\r
+\r
+  @param[in] InitFlag   Init flag is used to decide initialize process.\r
+  @param[in] Context    Context needed according to InitFlag, it was optional.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+InitializeDebugAgent (\r
+  IN UINT32                InitFlag,\r
+  IN VOID                  *Context  OPTIONAL\r
+  )\r
+{  
+  UINTN                Offset;\r
+  UINTN                Length;\r
+  BOOLEAN              IrqEnabled;\r
+  BOOLEAN              FiqEnabled;\r
+  UINT32               *VectorBase;\r
+\r
+    
+  //\r
+  // Disable interrupts\r
+  //\r
+  IrqEnabled = ArmGetInterruptState ();\r
+  ArmDisableInterrupts ();\r
+\r
+  //\r
+  // EFI does not use the FIQ, but a debugger might so we must disable \r
+  // as we take over the exception vectors. \r
+  //\r
+  FiqEnabled = ArmGetFiqState ();\r
+  ArmDisableFiq ();\r
+\r
+  //\r
+  // Copy an implementation of the ARM exception vectors to PcdCpuVectorBaseAddress.\r
+  //\r
+  Length = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart;\r
+\r
+  //\r
+  // Reserve space for the exception handlers\r
+  //\r
+  VectorBase = (UINT32 *)(UINTN)PcdGet32 (PcdCpuVectorBaseAddress);\r
+\r
+\r
+  // Copy our assembly code into the page that contains the exception vectors. \r
+  CopyMem ((VOID *)VectorBase, (VOID *)ExceptionHandlersStart, Length);\r
+\r
+  //\r
+  // Patch in the common Assembly exception handler\r
+  //\r
+  Offset = (UINTN)CommonExceptionEntry - (UINTN)ExceptionHandlersStart;\r
+  *(UINTN *) (((UINT8 *)VectorBase) + Offset) = (UINTN)AsmCommonExceptionEntry;\r
+\r
+  // Flush Caches since we updated executable stuff\r
+  InvalidateInstructionCacheRange ((VOID *)PcdGet32(PcdCpuVectorBaseAddress), Length);\r
+\r
+  DebugAgentTimerIntialize ();\r
+\r
+  if (FiqEnabled) {\r
+    ArmEnableFiq ();\r
+  }\r
+\r
+  if (IrqEnabled) {\r
+    ArmEnableInterrupts ();\r
+  }\r
+\r
+  return;\r
+}\r
+\r
diff --git a/EmbeddedPkg/Library/GdbDebugAgent/GdbDebugAgent.c b/EmbeddedPkg/Library/GdbDebugAgent/GdbDebugAgent.c
new file mode 100755 (executable)
index 0000000..d7f6dd9
--- /dev/null
@@ -0,0 +1,816 @@
+/** @file\r
+  Debug Agent library implementition with empty functions.\r
+\r
+  Copyright (c) 2010, Intel Corporation\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 "GdbDebugAgent.h"\r
+\r
+\r
+UINTN     gMaxProcessorIndex = 0;\r
+\r
+//\r
+// Buffers for basic gdb communication\r
+//\r
+CHAR8 gInBuffer[MAX_BUF_SIZE];\r
+CHAR8 gOutBuffer[MAX_BUF_SIZE];\r
+\r
+\r
+//\r
+// Globals for returning XML from qXfer:libraries:read packet\r
+//\r
+UINTN                             gPacketqXferLibraryOffset = 0;\r
+UINTN                             gEfiDebugImageTableEntry = 0;\r
+CHAR8                             gXferLibraryBuffer[2000];\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mHexToStr[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};\r
+\r
+\r
+// add-symbol-file c:/work/edk2/Build/BeagleBoard/DEBUG_ARMGCC/ARM/BeagleBoardPkg/Sec/Sec/DEBUG/BeagleBoardSec.dll 0x80008360 \r
+CHAR8  *qXferHack = "<library name=\"c:/work/edk2/Build/BeagleBoard/DEBUG_ARMGCC/ARM/BeagleBoardPkg/Sec/Sec/DEBUG/BeagleBoardSec.dll\"><segment address=\"0x80008360\"/></library>";\r
+\r
+UINTN\r
+gXferObjectReadResponse (\r
+  IN  CHAR8         Type,\r
+  IN  CHAR8         *Str\r
+  )\r
+{\r
+  CHAR8   *OutBufPtr;             // pointer to the output buffer\r
+  CHAR8   Char;\r
+  UINTN   Count;\r
+\r
+  // responce starts with 'm' or 'l' if it is the end\r
+  OutBufPtr = gOutBuffer;\r
+  *OutBufPtr++ = Type;\r
+  Count = 1;\r
+\r
+  // Binary data encoding \r
+  OutBufPtr = gOutBuffer;\r
+  while (*Str != '\0') {\r
+    Char = *Str++;\r
+    if ((Char == 0x7d) || (Char == 0x23) || (Char == 0x24) || (Char == 0x2a)) {\r
+      // escape character\r
+      *OutBufPtr++ = 0x7d;\r
+\r
+      Char ^= 0x20;\r
+    }\r
+    *OutBufPtr++ = Char;\r
+    Count++;\r
+  }\r
+\r
+  *OutBufPtr = '\0' ;  // the end of the buffer\r
+  SendPacket (gOutBuffer);\r
+  \r
+  return Count;\r
+}\r
+\r
+/** \r
+  Process "qXfer:object:read:annex:offset,length" request.\r
+  \r
+  Returns an XML document that contains loaded libraries. In our case it is \r
+  infomration in the EFI Debug Inmage Table converted into an XML document.\r
+  \r
+  GDB will call with an arbitrary length (it can't know the real length and \r
+  will reply with chunks of XML that are easy for us to deal with. Gdb will \r
+  keep calling until we say we are done. XML doc looks like:\r
+  \r
+  <library-list>\r
+    <library name="/a/a/c/d.dSYM"><segment address="0x10000000"/></library>\r
+    <library name="/a/m/e/e.pdb"><segment address="0x20000000"/></library>\r
+    <library name="/a/l/f/f.dll"><segment address="0x30000000"/></library>\r
+  </library-list>\r
+  \r
+  Since we can not allocate memory in interupt context this module has \r
+  assumptions about how it will get called:\r
+  1) Length will generally be max remote packet size (big enough)\r
+  2) First Offset of an XML document read needs to be 0\r
+  3) This code will return back small chunks of the XML document on every read.\r
+     Each subseqent call will ask for the next availble part of the document.\r
+     \r
+  Note: The only variable size element in the XML is:\r
+  "  <library name=\"%s\"><segment address=\"%p\"/></library>\n" and it is \r
+  based on the file path and name of the symbol file. If the symbol file name\r
+  is bigger than the max gdb remote packet size we could update this code\r
+  to respond back in chunks.\r
+\r
+ @param Offset  offset into special data area\r
+ @param Length  number of bytes to read starting at Offset  \r
+  \r
+ **/\r
+VOID\r
+QxferLibrary (\r
+  IN  UINTN   Offset,\r
+  IN  UINTN   Length\r
+  )\r
+{\r
+  gPacketqXferLibraryOffset += gXferObjectReadResponse ('m', "<library-list>\n");\r
+  gPacketqXferLibraryOffset += gXferObjectReadResponse ('m', qXferHack);\r
+  gXferObjectReadResponse ('l', "</library-list>\n");\r
+  gPacketqXferLibraryOffset = 0;\r
+}\r
+\r
+/**\r
+ Transfer length bytes of input buffer, starting at Address, to memory.\r
+\r
+ @param     length                  the number of the bytes to be transferred/written\r
+ @param     *address                the start address of the transferring/writing the memory\r
+ @param     *new_data               the new data to be written to memory\r
+ **/\r
+\r
+VOID\r
+TransferFromInBufToMem (\r
+  IN    UINTN                       Length,\r
+  IN    unsigned char               *Address,\r
+  IN    CHAR8                       *NewData\r
+  )\r
+{\r
+  CHAR8 c1;\r
+  CHAR8 c2;\r
+   \r
+  while (Length-- > 0) {\r
+    c1 = (CHAR8)HexCharToInt (*NewData++);\r
+    c2 = (CHAR8)HexCharToInt (*NewData++);\r
+\r
+    if ((c1 < 0) || (c2 < 0)) {\r
+      SendError (GDB_EBADMEMDATA); \r
+      return;\r
+    }\r
+    *Address++ = (UINT8)((c1 << 4) + c2);\r
+  }\r
+\r
+  SendSuccess();\r
+}\r
+\r
+\r
+/**\r
+ Transfer Length bytes of memory starting at Address to an output buffer, OutBuffer. This function will finally send the buffer\r
+ as a packet.\r
+\r
+ @param     Length                  the number of the bytes to be transferred/read\r
+ @param     *address                pointer to the start address of the transferring/reading the memory\r
+ **/\r
+\r
+VOID\r
+TransferFromMemToOutBufAndSend (\r
+  IN    UINTN                       Length,\r
+  IN    unsigned char               *Address\r
+  )\r
+{\r
+  // there are Length bytes and every byte is represented as 2 hex chars\r
+  CHAR8   OutBuffer[MAX_BUF_SIZE];\r
+  CHAR8   *OutBufPtr;             // pointer to the output buffer\r
+  CHAR8   Char;\r
+\r
+  OutBufPtr = OutBuffer;\r
+  while (Length > 0) {\r
+    \r
+    Char = mHexToStr[*Address >> 4];\r
+    if ((Char >= 'A') && (Char <= 'F')) {\r
+      Char = Char - 'A' + 'a';\r
+    }\r
+    *OutBufPtr++ = Char;\r
+\r
+    Char = mHexToStr[*Address & 0x0f];\r
+    if ((Char >= 'A') && (Char <= 'F')) {\r
+      Char = Char - 'A' + 'a';\r
+    }\r
+    *OutBufPtr++ = Char;\r
+\r
+    Address++;\r
+    Length--;\r
+  }\r
+\r
+  *OutBufPtr = '\0' ;  // the end of the buffer\r
+  SendPacket (OutBuffer);\r
+}\r
+\r
+\r
+\r
+/**\r
+  Send a GDB Remote Serial Protocol Packet\r
+  \r
+  $PacketData#checksum PacketData is passed in and this function adds the packet prefix '$', \r
+  the packet teminating character '#' and the two digit checksum.\r
+  \r
+  If an ack '+' is not sent resend the packet, but timeout eventually so we don't end up \r
+  in an infinit loop. This is so if you unplug the debugger code just keeps running\r
+\r
+  @param PacketData   Payload data for the packet  \r
+\r
+  \r
+  @retval             Number of bytes of packet data sent.\r
+\r
+**/\r
+UINTN\r
+SendPacket (\r
+  IN  CHAR8 *PacketData\r
+  )\r
+{\r
+  UINT8 CheckSum;\r
+  UINTN Timeout;\r
+  CHAR8 *Ptr;\r
+  CHAR8 TestChar;\r
+  UINTN Count;\r
+  \r
+  Timeout = PcdGet32 (PcdGdbMaxPacketRetryCount);\r
+\r
+  Count = 0;\r
+  do {\r
+\r
+    Ptr = PacketData;\r
+\r
+    if (Timeout-- == 0) {\r
+      // Only try a finite number of times so we don't get stuck in the loop\r
+      return Count;\r
+    }\r
+  \r
+    // Packet prefix\r
+    GdbPutChar ('$');\r
+  \r
+    for (CheckSum = 0, Count =0 ; *Ptr != '\0'; Ptr++, Count++) {\r
+      GdbPutChar (*Ptr);\r
+      CheckSum = CheckSum + *Ptr;\r
+    }\r
+  \r
+    // Packet terminating character and checksum \r
+    GdbPutChar ('#');\r
+    GdbPutChar (mHexToStr[CheckSum >> 4]);\r
+    GdbPutChar (mHexToStr[CheckSum & 0x0F]);\r
+    \r
+    TestChar =  GdbGetChar ();\r
+  } while (TestChar != '+');\r
+  \r
+  return Count;\r
+}\r
+\r
+/**\r
+  Receive a GDB Remote Serial Protocol Packet\r
+  \r
+  $PacketData#checksum PacketData is passed in and this function adds the packet prefix '$', \r
+  the packet teminating character '#' and the two digit checksum.\r
\r
+  If host re-starts sending a packet without ending the previous packet, only the last valid packet is proccessed.\r
+  (In other words, if received packet is '$12345$12345$123456#checksum', only '$123456#checksum' will be processed.)\r
\r
+  If an ack '+' is not sent resend the packet\r
+\r
+  @param PacketData   Payload data for the packet  \r
+\r
+  @retval             Number of bytes of packet data received.\r
+\r
+**/\r
+UINTN\r
+ReceivePacket (\r
+  OUT  CHAR8 *PacketData,\r
+  IN   UINTN PacketDataSize\r
+ )\r
+{\r
+  UINT8 CheckSum;\r
+  UINTN Index;\r
+  CHAR8 Char;\r
+  CHAR8 SumString[3];\r
+  CHAR8 TestChar;\r
+  \r
+  ZeroMem (PacketData, PacketDataSize);\r
+  \r
+  for (;;) {\r
+      // wait for the start of a packet\r
+    TestChar = GdbGetChar ();\r
+    while (TestChar != '$') {\r
+      TestChar = GdbGetChar ();\r
+    };\r
+    \r
+  retry:\r
+    for (Index = 0, CheckSum = 0; Index < (PacketDataSize - 1); Index++) {\r
+      Char = GdbGetChar ();\r
+      if (Char == '$') {\r
+        goto retry;\r
+      }\r
+      if (Char == '#') {\r
+        break;\r
+      }\r
+\r
+      PacketData[Index] = Char;\r
+      CheckSum = CheckSum + Char;\r
+    }\r
+    PacketData[Index] = '\0';\r
+\r
+    if (Index == PacketDataSize) {\r
+      continue;\r
+    }\r
+\r
+    SumString[0] = GdbGetChar ();  \r
+    SumString[1] = GdbGetChar ();\r
+    SumString[2] = '\0';\r
+    \r
+    if (AsciiStrHexToUintn (SumString) == CheckSum) {\r
+      // Ack: Success\r
+      GdbPutChar ('+');\r
+  \r
+      // Null terminate the callers string\r
+      PacketData[Index] = '\0';\r
+      return Index;\r
+    } else {\r
+      // Ack: Failure\r
+      GdbPutChar ('-');\r
+    }\r
+  }\r
+  \r
+  //return 0;\r
+}\r
+\r
+\r
+/**\r
+ Empties the given buffer \r
+ @param   Buf          pointer to the first element in buffer to be emptied\r
+ **/\r
+VOID\r
+EmptyBuffer ( \r
+  IN  CHAR8           *Buf\r
+  )\r
+{ \r
+  *Buf = '\0';\r
+}\r
+\r
+\r
+/**\r
+ Converts an 8-bit Hex Char into a INTN.\r
\r
+ @param   Char the hex character to be converted into UINTN\r
+ @retval  a INTN, from 0 to 15, that corressponds to Char\r
+ -1 if Char is not a hex character\r
+ **/\r
+INTN\r
+HexCharToInt (\r
+  IN  CHAR8           Char\r
+  )\r
+{\r
+  if ((Char >= 'A') && (Char <= 'F')) {\r
+    return Char - 'A' + 10;\r
+  } else if ((Char >= 'a') && (Char <= 'f')) {\r
+    return Char - 'a' + 10;\r
+  } else if ((Char >= '0') && (Char <= '9')) {\r
+    return Char - '0';\r
+  } else { // if not a hex value, return a negative value\r
+    return -1; \r
+  }\r
+}\r
+\r
+  // 'E' + the biggest error number is 255, so its 2 hex digits + buffer end\r
+CHAR8 *gError = "E__";\r
+\r
+/** 'E NN'\r
+ Send an error with the given error number after converting to hex.\r
+ The error number is put into the buffer in hex. '255' is the biggest errno we can send.\r
+ ex: 162 will be sent as A2.\r
\r
+ @param   errno           the error number that will be sent\r
+ **/\r
+VOID\r
+EFIAPI\r
+SendError (\r
+  IN  UINT8              ErrorNum\r
+  )\r
+{\r
+  //\r
+  // Replace _, or old data, with current errno\r
+  //\r
+  gError[1] = mHexToStr [ErrorNum >> 4];\r
+  gError[2] = mHexToStr [ErrorNum & 0x0f];\r
+    \r
+  SendPacket (gError); // send buffer\r
+}\r
+\r
+\r
+\r
+/**\r
+ Send 'OK' when the function is done executing successfully.\r
+ **/\r
+VOID\r
+EFIAPI\r
+SendSuccess (\r
+  VOID\r
+  ) \r
+{\r
+  SendPacket ("OK"); // send buffer\r
+}\r
+\r
+\r
+/**\r
+ Send empty packet to specify that particular command/functionality is not supported.\r
+ **/\r
+VOID        \r
+EFIAPI      \r
+SendNotSupported (\r
+  VOID          \r
+  )             \r
+{       \r
+  SendPacket ("");\r
+}\r
+\r
+\r
+\r
+\r
+\r
+/**\r
+ Translates the EFI mapping to GDB mapping\r
\r
+ @param   EFIExceptionType    EFI Exception that is being processed\r
+ @retval  UINTN that corresponds to EFIExceptionType's GDB exception type number\r
+ **/\r
+UINT8\r
+ConvertEFItoGDBtype ( \r
+  IN  EFI_EXCEPTION_TYPE      EFIExceptionType\r
+  )\r
+{ \r
+  UINTN i;\r
+  \r
+  for (i=0; i < MaxEfiException() ; i++) {\r
+    if (gExceptionType[i].Exception == EFIExceptionType) {\r
+      return gExceptionType[i].SignalNo;\r
+    }\r
+  }\r
+  return GDB_SIGTRAP; // this is a GDB trap\r
+}\r
+\r
+\r
+/** "m addr,length"\r
+ Find the Length of the area to read and the start addres. Finally, pass them to \r
+ another function, TransferFromMemToOutBufAndSend, that will read from that memory space and \r
+ send it as a packet.\r
+ **/\r
+\r
+VOID\r
+EFIAPI\r
+ReadFromMemory (\r
+  CHAR8 *PacketData\r
+  )\r
+{\r
+  UINTN Address;\r
+  UINTN Length;\r
+  CHAR8 AddressBuffer[MAX_ADDR_SIZE]; // the buffer that will hold the address in hex chars\r
+  CHAR8 *AddrBufPtr; // pointer to the address buffer\r
+  CHAR8 *InBufPtr; /// pointer to the input buffer\r
+  \r
+  AddrBufPtr = AddressBuffer;\r
+  InBufPtr = &PacketData[1];\r
+  while (*InBufPtr != ',') {\r
+    *AddrBufPtr++ = *InBufPtr++;\r
+  }\r
+  *AddrBufPtr = '\0';\r
+  \r
+  InBufPtr++; // this skips ',' in the buffer\r
+  \r
+  /* Error checking */\r
+  if (AsciiStrLen(AddressBuffer) >= MAX_ADDR_SIZE) {\r
+    SendError (GDB_EBADMEMADDRBUFSIZE); \r
+    return;\r
+  }\r
+  \r
+  // 2 = 'm' + ','\r
+  if (AsciiStrLen(PacketData) - AsciiStrLen(AddressBuffer) - 2 >= MAX_LENGTH_SIZE) {\r
+    SendError (GDB_EBADMEMLENGTH); \r
+    return;\r
+  }\r
+  \r
+  Address = AsciiStrHexToUintn (AddressBuffer);\r
+  Length = AsciiStrHexToUintn (InBufPtr);\r
+  \r
+  TransferFromMemToOutBufAndSend (Length, (unsigned char *)Address);\r
+}\r
+\r
+\r
+/** "M addr,length :XX..."\r
+ Find the Length of the area in bytes to write and the start addres. Finally, pass them to \r
+ another function, TransferFromInBufToMem, that will write to that memory space the info in\r
+ the input buffer.\r
+ **/\r
+VOID\r
+EFIAPI\r
+WriteToMemory (\r
+  IN CHAR8 *PacketData\r
+  )\r
+{\r
+  UINTN Address;\r
+  UINTN Length;\r
+  UINTN MessageLength;\r
+  CHAR8 AddressBuffer[MAX_ADDR_SIZE]; // the buffer that will hold the Address in hex chars\r
+  CHAR8 LengthBuffer[MAX_LENGTH_SIZE]; // the buffer that will hold the Length in hex chars\r
+  CHAR8 *AddrBufPtr; // pointer to the Address buffer\r
+  CHAR8 *LengthBufPtr; // pointer to the Length buffer\r
+  CHAR8 *InBufPtr; /// pointer to the input buffer\r
+  \r
+  AddrBufPtr = AddressBuffer;\r
+  LengthBufPtr = LengthBuffer;\r
+  InBufPtr = &PacketData[1];\r
+  \r
+  while (*InBufPtr != ',') {\r
+    *AddrBufPtr++ = *InBufPtr++;\r
+  }\r
+  *AddrBufPtr = '\0';\r
+  \r
+  InBufPtr++; // this skips ',' in the buffer\r
+  \r
+  while (*InBufPtr != ':') {\r
+    *LengthBufPtr++ = *InBufPtr++;\r
+  }\r
+  *LengthBufPtr = '\0';\r
+  \r
+  InBufPtr++; // this skips ':' in the buffer\r
+  \r
+  Address = AsciiStrHexToUintn (AddressBuffer);\r
+  Length = AsciiStrHexToUintn (LengthBuffer);\r
+  \r
+  /* Error checking */\r
+  \r
+  //Check if Address is not too long.\r
+  if (AsciiStrLen(AddressBuffer) >= MAX_ADDR_SIZE) {\r
+    SendError (GDB_EBADMEMADDRBUFSIZE); \r
+    return;\r
+  }\r
+  \r
+  //Check if message length is not too long\r
+  if (AsciiStrLen(LengthBuffer) >= MAX_LENGTH_SIZE) {\r
+    SendError (GDB_EBADMEMLENGBUFSIZE); \r
+    return;\r
+  }\r
+  \r
+  // Check if Message is not too long/short.\r
+  // 3 = 'M' + ',' + ':'\r
+  MessageLength = (AsciiStrLen(PacketData) - AsciiStrLen(AddressBuffer) - AsciiStrLen(LengthBuffer) - 3);\r
+  if (MessageLength != (2*Length)) {\r
+    //Message too long/short. New data is not the right size.\r
+    SendError (GDB_EBADMEMDATASIZE);   \r
+    return;\r
+  }\r
+  TransferFromInBufToMem (Length, (unsigned char *)Address, InBufPtr);\r
+}\r
+\r
+/**\r
+  Parses breakpoint packet data and captures Breakpoint type, Address and length.\r
+  In case of an error, function returns particular error code. Returning 0 meaning\r
+  no error.\r
+\r
+  @param  PacketData  Pointer to the payload data for the packet.\r
+  @param  Type        Breakpoint type\r
+  @param  Address     Breakpoint address\r
+  @param  Length      Breakpoint length in Bytes (1 byte, 2 byte, 4 byte)\r
+\r
+  @retval 1           Success\r
+  @retval {other}     Particular error code\r
+\r
+**/\r
+UINTN\r
+ParseBreakpointPacket (\r
+  IN  CHAR8 *PacketData,\r
+  OUT UINTN *Type,\r
+  OUT UINTN *Address,\r
+  OUT UINTN *Length\r
+  )\r
+{\r
+  CHAR8 AddressBuffer[MAX_ADDR_SIZE];\r
+  CHAR8 *AddressBufferPtr;\r
+  CHAR8 *PacketDataPtr;\r
+\r
+  PacketDataPtr = &PacketData[1];\r
+  AddressBufferPtr = AddressBuffer;\r
+\r
+  *Type = AsciiStrHexToUintn (PacketDataPtr);\r
+\r
+  //Breakpoint/watchpoint type should be between 0 to 4\r
+  if (*Type > 4) {\r
+    return 22; //EINVAL: Invalid argument.\r
+  }\r
+\r
+  //Skip ',' in the buffer.\r
+  while (*PacketDataPtr++ != ',');\r
+\r
+  //Parse Address information\r
+  while (*PacketDataPtr != ',') {\r
+    *AddressBufferPtr++ = *PacketDataPtr++;\r
+  }\r
+  *AddressBufferPtr = '\0';\r
+\r
+  //Check if Address is not too long.\r
+  if (AsciiStrLen(AddressBuffer) >= MAX_ADDR_SIZE) {\r
+    return 40; //EMSGSIZE: Message size too long.\r
+  }\r
+\r
+  *Address = AsciiStrHexToUintn (AddressBuffer);\r
+\r
+  PacketDataPtr++; //This skips , in the buffer\r
+\r
+  //Parse Length information\r
+  *Length = AsciiStrHexToUintn (PacketDataPtr);\r
+\r
+  //Length should be 1, 2 or 4 bytes\r
+  if (*Length > 4) {\r
+    return 22; //EINVAL: Invalid argument\r
+  }\r
+\r
+  return 0; //0 = No error\r
+}\r
+\r
+\r
+\r
+/**\r
+ Send the T signal with the given exception type (in gdb order) and possibly with n:r pairs related to the watchpoints\r
\r
+ @param  SystemContext        Register content at time of the exception\r
+ @param  GdbExceptionType     GDB exception type\r
+ **/\r
+VOID\r
+GdbSendTSignal (\r
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,\r
+  IN  UINT8               GdbExceptionType\r
+  )\r
+{\r
+  CHAR8 TSignalBuffer[128];\r
+  CHAR8 *TSignalPtr;\r
+\r
+  TSignalPtr = &TSignalBuffer[0];\r
+\r
+  //Construct TSignal packet\r
+  *TSignalPtr++ = 'T';\r
+\r
+  //\r
+  // replace _, or previous value, with Exception type\r
+  //\r
+  *TSignalPtr++ = mHexToStr [GdbExceptionType >> 4]; \r
+  *TSignalPtr++ = mHexToStr [GdbExceptionType & 0x0f];\r
+  \r
+  ProcessorSendTSignal (SystemContext, GdbExceptionType, TSignalPtr, sizeof (TSignalBuffer) - 2);\r
+\r
+  SendPacket (TSignalBuffer); \r
+}\r
+\r
+VOID\r
+GdbFWrite (\r
+  IN  UINTN Fd,\r
+  IN  CHAR8 *Data,\r
+  IN  UINTN DataSize\r
+  )\r
+{\r
+  CHAR8 Buffer[128];\r
+\r
+  AsciiSPrint (Buffer, sizeof (Buffer), "Fwrite,%x,%x,%x", Fd, Data, DataSize);\r
+  SendPacket (Buffer);\r
+\r
+  for( ; ; ) {\r
+    ReceivePacket (gInBuffer, MAX_BUF_SIZE);\r
+    \r
+    switch (gInBuffer[0]) {\r
+    case 'm':\r
+      ReadFromMemory (gInBuffer);\r
+      break;\r
+\r
+    case 'M':\r
+      WriteToMemory (gInBuffer);\r
+      break;\r
+\r
+    case 'F':\r
+      return;\r
+      break;\r
+    }\r
+  }\r
+}\r
+\r
+\r
+VOID\r
+GdbFPutString (\r
+  IN CHAR8  *String\r
+  )\r
+{\r
+  UINTN Len = AsciiStrSize (String);\r
+\r
+  GdbFWrite (2, String, Len);\r
+}\r
+\r
+\r
+/**\r
+ Exception Hanldler for GDB. It will be called for all exceptions\r
+ registered via the gExceptionType[] array.\r
\r
+ @param ExceptionType     Exception that is being processed\r
+ @param SystemContext     Register content at time of the exception  \r
+ **/\r
+VOID\r
+EFIAPI\r
+GdbExceptionHandler ( \r
+  IN  EFI_EXCEPTION_TYPE        ExceptionType, \r
+  IN OUT EFI_SYSTEM_CONTEXT     SystemContext \r
+  )\r
+{\r
+  UINT8   GdbExceptionType;\r
+  CHAR8   *Ptr;\r
+  \r
+  if (ProcessorControlC (ExceptionType, SystemContext)) {\r
+    // We tried to process a control C handler and there is nothing to do\r
+    return;\r
+  }\r
+\r
+  GdbExceptionType = ConvertEFItoGDBtype (ExceptionType);\r
+  GdbSendTSignal (SystemContext, GdbExceptionType);\r
+  \r
+  for( ; ; ) {\r
+    ReceivePacket (gInBuffer, MAX_BUF_SIZE);\r
+    \r
+    switch (gInBuffer[0]) {\r
+      case '?':\r
+        GdbSendTSignal (SystemContext, GdbExceptionType);\r
+        break;\r
+          \r
+      case 'c':\r
+        ContinueAtAddress (SystemContext, gInBuffer);          \r
+        return;\r
+\r
+      case 'D':\r
+        // gdb wants to disconnect so return "OK" packet since. \r
+        SendSuccess ();\r
+        return;\r
+\r
+      case 'g':\r
+        ReadGeneralRegisters (SystemContext);\r
+        break;\r
+          \r
+      case 'G':\r
+        WriteGeneralRegisters (SystemContext, gInBuffer);\r
+        break;\r
+          \r
+      case 'H':\r
+        //Return "OK" packet since we don't have more than one thread. \r
+        SendSuccess ();\r
+        break;\r
+          \r
+      case 'm':\r
+        ReadFromMemory (gInBuffer);\r
+        break;\r
+\r
+      case 'M':\r
+        WriteToMemory (gInBuffer);\r
+        break;\r
+\r
+      case 'P':\r
+        WriteNthRegister (SystemContext, gInBuffer);\r
+        break;\r
+\r
+      //\r
+      // Still debugging this code. Not used in Darwin\r
+      //\r
+      case 'q': \r
+        // General Query Packets\r
+        if (AsciiStrnCmp (gInBuffer, "qSupported", 10) == 0) {\r
+          // return what we currently support, we don't parse what gdb suports\r
+          AsciiSPrint (gOutBuffer, MAX_BUF_SIZE, "qXfer:libraries:read+;PacketSize=%d", MAX_BUF_SIZE);\r
+          SendPacket (gOutBuffer);\r
+        } else if (AsciiStrnCmp (gInBuffer, "qXfer:libraries:read::", 22) == 0) {\r
+          // \91qXfer:libraries:read::offset,length\r
+          // gInBuffer[22] is offset string, ++Ptr is length string\92\r
+          for (Ptr = &gInBuffer[22]; *Ptr != ','; Ptr++);\r
+        \r
+          // Not sure if multi-radix support is required. Currently only support decimal\r
+          QxferLibrary (AsciiStrHexToUintn (&gInBuffer[22]), AsciiStrHexToUintn (++Ptr));\r
+        } else if (AsciiStrnCmp (gInBuffer, "qOffsets", 8) == 0) {\r
+          AsciiSPrint (gOutBuffer, MAX_BUF_SIZE, "Text=1000;Data=f000;Bss=f000");\r
+          SendPacket (gOutBuffer);\r
+        } else if (AsciiStrnCmp (gInBuffer, "qAttached", 9) == 0) {\r
+          // remote server attached to an existing process\r
+          SendPacket ("1");\r
+        } else {\r
+          //Send empty packet\r
+          SendNotSupported ();\r
+        }\r
+        break;\r
+\r
+      case 's':\r
+        SingleStep (SystemContext, gInBuffer);          \r
+        return;\r
+         \r
+      case 'z':\r
+        RemoveBreakPoint (SystemContext, gInBuffer);\r
+        break;\r
+  \r
+      case 'Z':\r
+        InsertBreakPoint (SystemContext, gInBuffer);\r
+        break;\r
+                  \r
+      default:  \r
+        //Send empty packet\r
+        SendNotSupported ();\r
+        break;\r
+    }\r
+  }\r
+}\r
+\r
+\r
+\r
+\r
+\r
diff --git a/EmbeddedPkg/Library/GdbDebugAgent/GdbDebugAgent.h b/EmbeddedPkg/Library/GdbDebugAgent/GdbDebugAgent.h
new file mode 100755 (executable)
index 0000000..6cc2f62
--- /dev/null
@@ -0,0 +1,727 @@
+/** @file
+  Private include file for GDB stub
+
+  Copyright (c) 2008-2009 Apple Inc. All rights reserved.<BR>
+
+  All rights reserved. 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.
+
+**/
+
+#ifndef __GCC_DEBUG_AGENT_INTERNAL__
+#define __GCC_DEBUG_AGENT_INTERNAL__
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/GdbSerialLib.h>
+#include <Library/PrintLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/DebugAgentTimerLib.h>
+
+#include <IndustryStandard/PeImage.h>
+#include <Protocol/DebugSupport.h>
+
+extern CONST CHAR8 mHexToStr[];
+
+// maximum size of input and output buffers
+// This value came from the show remote command of the gdb we tested against 
+#define MAX_BUF_SIZE 2000
+
+// maximum size of address buffer
+#define MAX_ADDR_SIZE 32
+
+// maximum size of register number buffer
+#define MAX_REG_NUM_BUF_SIZE 32
+
+// maximum size of length buffer
+#define MAX_LENGTH_SIZE 32
+
+// maximum size of T signal members
+#define MAX_T_SIGNAL_SIZE 64
+
+// the mask used to clear all the cache
+#define TF_BIT 0x00000100
+
+
+//
+// GDB Signal definitions - generic names for interrupts
+//
+#define GDB_SIGINT      2  // Interrupt process via ctrl-c
+#define GDB_SIGILL      4  // Illegal instruction       
+#define GDB_SIGTRAP     5  // Trace Trap (Breakpoint and SingleStep)
+#define GDB_SIGEMT      7  // Emulator Trap
+#define GDB_SIGFPE      8  // Floating point exception
+#define GDB_SIGSEGV     11 // Setgment violation, page fault 
+
+
+//
+// GDB File I/O Error values, zero means no error
+// Includes all general GDB Unix like error values
+//
+#define GDB_EBADMEMADDRBUFSIZE   11  // the buffer that stores memory Address to be read from/written to is not the right size
+#define GDB_EBADMEMLENGBUFSIZE   12  // the buffer that stores Length is not the right size 
+#define GDB_EBADMEMLENGTH        13  // Length, the given number of bytes to read or write, is not the right size
+#define GDB_EBADMEMDATA          14  // one of the bytes or nibbles of the memory is leess than 0 
+#define GDB_EBADMEMDATASIZE      15  // the memory data, 'XX..', is too short or too long
+#define GDB_EBADBUFSIZE          21  // the buffer created is not the correct size
+#define GDB_EINVALIDARG          31  // argument is invalid
+#define GDB_ENOSPACE             41  //
+#define GDB_EINVALIDBRKPOINTTYPE 51  // the breakpoint type is not recognized
+#define GDB_EINVALIDREGNUM       61  // given register number is not valid: either <0 or >=Number of Registers
+#define GDB_EUNKNOWN             255 // unknown
+
+
+//
+// These devices are open by GDB so we can just read and write to them
+//
+#define GDB_STDIN   0x00
+#define GDB_STDOUT  0x01
+#define GDB_STDERR  0x02
+
+//
+//Define Register size for different architectures
+//
+#if defined (MDE_CPU_IA32) 
+#define REG_SIZE  32
+#elif defined (MDE_CPU_X64)
+#define REG_SIZE  64
+#elif defined (MDE_CPU_ARM)
+#define REG_SIZE  32
+#endif
+
+
+typedef struct {
+  EFI_EXCEPTION_TYPE  Exception;
+  UINT8               SignalNo;
+} EFI_EXCEPTION_TYPE_ENTRY;
+
+
+#if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64)
+
+//
+// Byte packed structure for DR6
+// 32-bits on IA-32
+// 64-bits on X64.  The upper 32-bits on X64 are reserved
+//
+typedef union {
+  struct {
+    UINT32  B0:1;           // Breakpoint condition detected
+    UINT32  B1:1;           // Breakpoint condition detected
+    UINT32  B2:1;           // Breakpoint condition detected
+    UINT32  B3:1;           // Breakpoint condition detected
+    UINT32  Reserved_1:9;   // Reserved 
+    UINT32  BD:1;           // Debug register access detected
+    UINT32  BS:1;           // Single step
+    UINT32  BT:1;           // Task switch
+    UINT32  Reserved_2:16;  // Reserved
+  } Bits;
+  UINTN     UintN;
+} IA32_DR6;
+
+//
+// Byte packed structure for DR7
+// 32-bits on IA-32
+// 64-bits on X64.  The upper 32-bits on X64 are reserved
+//
+typedef union {
+  struct {
+    UINT32  L0:1;           // Local breakpoint enable
+    UINT32  G0:1;           // Global breakpoint enable
+    UINT32  L1:1;           // Local breakpoint enable
+    UINT32  G1:1;           // Global breakpoint enable
+    UINT32  L2:1;           // Local breakpoint enable
+    UINT32  G2:1;           // Global breakpoint enable
+    UINT32  L3:1;           // Local breakpoint enable
+    UINT32  G3:1;           // Global breakpoint enable
+    UINT32  LE:1;           // Local exact breakpoint enable
+    UINT32  GE:1;           // Global exact breakpoint enable
+    UINT32  Reserved_1:3;   // Reserved
+    UINT32  GD:1;           // Global detect enable
+    UINT32  Reserved_2:2;   // Reserved
+    UINT32  RW0:2;          // Read/Write field
+    UINT32  LEN0:2;         // Length field
+    UINT32  RW1:2;          // Read/Write field
+    UINT32  LEN1:2;         // Length field
+    UINT32  RW2:2;          // Read/Write field
+    UINT32  LEN2:2;         // Length field
+    UINT32  RW3:2;          // Read/Write field
+    UINT32  LEN3:2;         // Length field
+  } Bits;
+  UINTN     UintN;
+} IA32_DR7;
+
+#endif /* if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64) */
+
+typedef enum {
+  InstructionExecution,   //Hardware breakpoint
+  DataWrite,              //watch
+  DataRead,               //rwatch
+  DataReadWrite,          //awatch
+  SoftwareBreakpoint,     //Software breakpoint
+  NotSupported
+} BREAK_TYPE;
+
+//
+// Array of exception types that need to be hooked by the debugger
+//
+extern EFI_EXCEPTION_TYPE_ENTRY gExceptionType[];
+
+//
+// If the periodic callback is called while we are processing an F packet we need
+// to let the callback know to not read from the serail stream as it could steal
+// characters from the F reponse packet
+//
+extern BOOLEAN gProcessingFPacket;
+
+
+/**
+ Return the number of entries in the gExceptionType[]
+ @retval    UINTN, the number of entries in the gExceptionType[] array.    
+ **/
+UINTN
+MaxEfiException (
+  VOID
+  );
+
+
+/**
+ Check to see if the ISA is supported. 
+ ISA = Instruction Set Architecture
+ @retval    TRUE if Isa is supported,
+ FALSE otherwise.
+ **/
+BOOLEAN
+CheckIsa (
+  IN    EFI_INSTRUCTION_SET_ARCHITECTURE    Isa
+  );
+
+
+/**
+ Send the T signal with the given exception type (in gdb order) and possibly with n:r pairs related to the watchpoints
+ @param  SystemContext        Register content at time of the exception
+ @param  GdbExceptionType     GDB exception type
+ **/
+
+VOID
+GdbSendTSignal (
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,
+  IN  UINT8                  GdbExceptionType
+  );
+
+
+/**
+ Translates the EFI mapping to GDB mapping
+ @param     EFIExceptionType        EFI Exception that is being processed
+ @retval    UINTN that corresponds to EFIExceptionType's GDB exception type number
+ **/
+UINT8
+ConvertEFItoGDBtype ( 
+  IN  EFI_EXCEPTION_TYPE EFIExceptionType
+  );
+
+
+/**
+ Empties the given buffer 
+ @param *Buf pointer to the first element in buffer to be emptied
+ **/
+VOID
+EmptyBuffer ( 
+  IN CHAR8  *Buf
+  );
+
+
+/**
+ Converts an 8-bit Hex Char into a INTN.
+ @param     Char  - the hex character to be converted into UINTN
+ @retval    a INTN, from 0 to 15, that corressponds to Char
+ -1 if Char is not a hex character
+ **/
+INTN
+HexCharToInt (
+  IN  CHAR8 Char
+  );
+
+
+/** 'E NN'
+ Send an error with the given error number after converting to hex.
+ The error number is put into the buffer in hex. '255' is the biggest errno we can send.
+ ex: 162 will be sent as A2.
+ @param   errno    the error number that will be sent
+ **/
+VOID
+EFIAPI
+SendError (
+  IN  UINT8     ErrorNum
+  );
+
+
+/**
+ Send 'OK' when the function is done executing successfully.
+ **/
+VOID
+SendSuccess (
+  VOID
+  );
+
+
+/**
+ Send empty packet to specify that particular command/functionality is not supported.
+ **/
+VOID
+SendNotSupported (
+  VOID
+  );
+
+/** ‘p n’ 
+ 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            This is the input buffer received from gdb server
+ **/
+VOID
+ReadNthRegister (
+  IN    EFI_SYSTEM_CONTEXT  SystemContext,
+  IN    CHAR8               *InBuffer
+  );
+
+
+/** ‘g’ 
+ Reads the general registers into an output buffer  and sends it as a packet 
+ @param     SystemContext           Register content at time of the exception
+ **/
+VOID
+ReadGeneralRegisters (  
+  IN    EFI_SYSTEM_CONTEXT  SystemContext
+  );
+
+
+/** ‘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            This is the input buffer received from gdb server
+ **/
+VOID
+WriteNthRegister (
+  IN    EFI_SYSTEM_CONTEXT  SystemContext,
+  IN    CHAR8               *InBuffer
+  );
+
+
+/** ‘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
+WriteGeneralRegisters (
+  IN    EFI_SYSTEM_CONTEXT  SystemContext,
+  IN    CHAR8               *InBuffer
+  );
+
+
+/** ‘m addr,length ’
+ Find the Length of the area to read and the start addres. Finally, pass them to 
+ another function, TransferFromMemToOutBufAndSend, that will read from that memory space and 
+ send it as a packet.
+ @param  *PacketData  Pointer to Payload data for the packet
+ **/
+VOID
+ReadFromMemory (
+  IN  CHAR8  *PacketData
+  );
+
+
+/** ‘M addr,length :XX...’
+ Find the Length of the area in bytes to write and the start addres. Finally, pass them to 
+ another function, TransferFromInBufToMem, that will write to that memory space the info in
+ the input buffer.
+ @param   PacketData     Pointer to Payload data for the packet
+ **/
+VOID
+WriteToMemory (
+  IN CHAR8 *PacketData
+  );
+
+
+/** ‘c [addr ]’ 
+ Continue. addr is Address to resume. If addr is omitted, resume at current 
+ Address.
+ @param SystemContext Register content at time of the exception  
+ @param *PacketData   Pointer to PacketData
+ **/
+
+VOID
+ContinueAtAddress (
+  IN  EFI_SYSTEM_CONTEXT   SystemContext,
+  IN  CHAR8                *PacketData
+  );
+
+
+/** ‘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
+ @param PacketData      Pointer to Payload data for the packet
+ **/
+VOID
+SingleStep (
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,
+  IN  CHAR8               *PacketData
+  );
+
+/** 
+ Insert Single Step in the SystemContext
+ @param SystemContext   Register content at time of the exception
+ **/
+VOID
+AddSingleStep (
+  IN  EFI_SYSTEM_CONTEXT  SystemContext
+  );
+  
+/** 
+ Remove Single Step in the SystemContext
+ @param SystemContext   Register content at time of the exception
+ **/
+VOID
+RemoveSingleStep (
+  IN  EFI_SYSTEM_CONTEXT  SystemContext
+  );
+  
+  
+/**
+  ‘Z1, [addr], [length]’
+  ‘Z2, [addr], [length]’
+  ‘Z3, [addr], [length]’
+  ‘Z4, [addr], [length]’
+
+  Insert hardware breakpoint/watchpoint at address addr of size length
+
+  @param SystemContext  Register content at time of the exception
+  @param *PacketData    Pointer to the Payload data for the packet
+
+**/
+VOID
+EFIAPI
+InsertBreakPoint(
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,
+  IN  CHAR8               *PacketData
+  );
+
+
+/**
+  ‘z1, [addr], [length]’
+  ‘z2, [addr], [length]’
+  ‘z3, [addr], [length]’
+  ‘z4, [addr], [length]’
+
+  Remove hardware breakpoint/watchpoint at address addr of size length
+
+  @param SystemContext  Register content at time of the exception
+  @param *PacketData    Pointer to the Payload data for the packet
+
+**/
+VOID
+EFIAPI
+RemoveBreakPoint(
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,
+  IN  CHAR8               *PacketData
+  );
+
+
+/**
+ Exception Hanldler for GDB. It will be called for all exceptions
+ registered via the gExceptionType[] array.
+ @param ExceptionType   Exception that is being processed
+ @param SystemContext   Register content at time of the exception  
+ **/
+VOID
+EFIAPI
+GdbExceptionHandler ( 
+  IN     EFI_EXCEPTION_TYPE  ExceptionType, 
+  IN OUT EFI_SYSTEM_CONTEXT  SystemContext 
+  );
+
+
+/**
+ Periodic callback for GDB. This function is used to catch a ctrl-c or other 
+ break in type command from GDB.
+ @param SystemContext           Register content at time of the call
+ **/
+VOID
+EFIAPI
+GdbPeriodicCallBack ( 
+  IN OUT EFI_SYSTEM_CONTEXT  SystemContext 
+  );
+
+
+/**
+  Make two serail consoles: 1) StdIn and StdOut via GDB. 2) StdErr via GDB.
+  
+  These console show up on the remote system running GDB
+
+**/
+
+VOID
+GdbInitializeSerialConsole (
+  VOID
+  );
+
+
+/**
+  Send a GDB Remote Serial Protocol Packet
+  
+  $PacketData#checksum PacketData is passed in and this function adds the packet prefix '$', 
+  the packet teminating character '#' and the two digit checksum.
+  
+  If an ack '+' is not sent resend the packet, but timeout eventually so we don't end up 
+  in an infinit loop. This is so if you unplug the debugger code just keeps running
+
+  @param PacketData   Payload data for the packet  
+  
+  @retval             Number of bytes of packet data sent.
+
+**/
+UINTN
+SendPacket (
+  IN  CHAR8 *PacketData
+  );
+  
+
+/**
+ Receive a GDB Remote Serial Protocol Packet
+ $PacketData#checksum PacketData is passed in and this function adds the packet prefix '$', 
+ the packet teminating character '#' and the two digit checksum.
+ If host re-starts sending a packet without ending the previous packet, only the last valid packet is proccessed.
+ (In other words, if received packet is '$12345$12345$123456#checksum', only '$123456#checksum' will be processed.)
+ If an ack '+' is not sent resend the packet
+ @param PacketData   Payload data for the packet  
+ @retval             Number of bytes of packet data received.
+
+ **/
+UINTN
+ReceivePacket (
+ OUT  CHAR8 *PacketData,
+ IN   UINTN PacketDataSize
+ );
+  
+
+/**
+  Read data from a FileDescriptor. On success number of bytes read is returned. Zero indicates 
+  the end of a file. On error -1 is returned. If count is zero, GdbRead returns zero.
+
+  @param  FileDescriptor   Device to talk to.
+  @param  Buffer           Buffer to hold Count bytes that were read
+  @param  Count            Number of bytes to transfer. 
+
+  @retval -1               Error
+  @retval {other}          Number of bytes read.
+
+**/
+INTN
+GdbRead (
+  IN  INTN    FileDescriptor,
+  OUT VOID    *Buffer,
+  IN  UINTN   Count
+  );
+  
+
+/**
+  Write data to a FileDescriptor. On success number of bytes written is returned. Zero indicates 
+  nothing was written. On error -1 is returned. 
+
+  @param  FileDescriptor   Device to talk to.
+  @param  Buffer           Buffer to hold Count bytes that are to be written
+  @param  Count            Number of bytes to transfer. 
+
+  @retval -1               Error
+  @retval {other}          Number of bytes written.
+
+**/
+INTN
+GdbWrite (
+  IN  INTN          FileDescriptor,
+  OUT CONST VOID    *Buffer,
+  IN  UINTN         Count
+  );
+
+UINTN *  
+FindPointerToRegister (
+  IN  EFI_SYSTEM_CONTEXT    SystemContext,
+  IN  UINTN                 RegNumber  
+  );
+
+CHAR8 * 
+BasicReadRegister (
+  IN  EFI_SYSTEM_CONTEXT      SystemContext,
+  IN  UINTN                   RegNumber,
+  IN  CHAR8                   *OutBufPtr
+  );
+
+VOID
+TransferFromInBufToMem (
+  IN  UINTN   Length,
+  IN  UINT8   *Address,
+  IN  CHAR8   *NewData
+  );
+
+VOID
+TransferFromMemToOutBufAndSend (
+  IN  UINTN  Length,
+  IN  UINT8  *Address
+  );
+
+CHAR8 *
+BasicWriteRegister (
+  IN  EFI_SYSTEM_CONTEXT    SystemContext,
+  IN  UINTN                 RegNumber,
+  IN  CHAR8                 *InBufPtr
+  );
+
+VOID  
+PrintReg (
+  EFI_SYSTEM_CONTEXT SystemContext
+  );
+
+UINTN
+ParseBreakpointPacket (
+  IN  CHAR8 *PacketData,
+  OUT UINTN *Type,
+  OUT UINTN *Address,
+  OUT UINTN *Length
+  );
+
+UINTN
+GetBreakpointDataAddress (
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,
+  IN  UINTN               BreakpointNumber 
+  );
+
+UINTN
+GetBreakpointDetected (
+  IN  EFI_SYSTEM_CONTEXT  SystemContext
+  );
+
+BREAK_TYPE
+GetBreakpointType (
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,
+  IN  UINTN               BreakpointNumber  
+  );
+
+UINTN
+ConvertLengthData (
+  IN  UINTN  Length
+  );
+
+EFI_STATUS
+FindNextFreeDebugRegister (
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,
+  OUT UINTN               *Register
+  );
+
+EFI_STATUS
+EnableDebugRegister (
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,
+  IN  UINTN               Register,
+  IN  UINTN               Address,
+  IN  UINTN               Length,
+  IN  UINTN               Type
+  );
+
+EFI_STATUS
+FindMatchingDebugRegister (
+ IN  EFI_SYSTEM_CONTEXT  SystemContext,
+ IN  UINTN               Address,
+ IN  UINTN               Length,
+ IN  UINTN               Type,
+ OUT UINTN               *Register
+ );
+
+EFI_STATUS
+DisableDebugRegister (
+ IN  EFI_SYSTEM_CONTEXT  SystemContext,
+ IN  UINTN               Register
+ );
+
+VOID
+InitializeProcessor (
+  VOID
+  );
+
+/**
+ Send the T signal with the given exception type (in gdb order) and possibly with n:r pairs related to the watchpoints
+ @param  SystemContext        Register content at time of the exception
+ @param  GdbExceptionType     GDB exception type
+ **/
+VOID
+ProcessorSendTSignal (
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,
+  IN  UINT8               GdbExceptionType,
+  IN  OUT CHAR8           *TSignalPtr,
+  IN  UINTN               SizeOfBuffer
+  );
+
+/**\r
+ Check to see if this exception is related to ctrl-c handling.\r
\r
+ @param ExceptionType     Exception that is being processed\r
+ @param SystemContext     Register content at time of the exception  \r
+\r
+ @return  TRUE  This was a ctrl-c check that did not find a ctrl-c\r
+ @return  FALSE This was not a ctrl-c check or some one hit ctrl-c\r
+ **/\r
+BOOLEAN\r
+ProcessorControlC ( \r
+  IN  EFI_EXCEPTION_TYPE        ExceptionType, \r
+  IN OUT EFI_SYSTEM_CONTEXT     SystemContext \r
+  );
+
+
+/**\r
+  Initialize debug agent.\r
+\r
+  This function is used to set up debug enviroment. It may enable interrupts.\r
+\r
+  @param[in] InitFlag   Init flag is used to decide initialize process.\r
+  @param[in] Context    Context needed according to InitFlag, it was optional.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+DebugAgentHookExceptions (\r
+  IN UINT32                InitFlag,\r
+  IN VOID                  *Context  OPTIONAL\r
+  );\r
+
+
+#endif
diff --git a/EmbeddedPkg/Library/GdbDebugAgent/GdbDebugAgent.inf b/EmbeddedPkg/Library/GdbDebugAgent/GdbDebugAgent.inf
new file mode 100755 (executable)
index 0000000..9ccb90b
--- /dev/null
@@ -0,0 +1,69 @@
+#/** @file\r
+# Null instance of Debug Agent Library with empty functions.\r
+#\r
+#  Copyright (c) 2010, Intel Corporation.\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
+#  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
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = GdbDebugAgent\r
+  FILE_GUID                      = b9f10c17-6ca0-40b5-9b44-6253cfc7d24b\r
+  MODULE_TYPE                    = BASE\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = DebugAgentLib\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources.common]\r
+  GdbDebugAgent.c\r
+\r
+[Sources.arm]\r
+  Arm/Processor.c\r
+  Arm/ExceptionSupport.ARMv6.S\r
+  Arm/ExceptionSupport.ARMv6.asm\r
+\r
+[Sources.X64]\r
+  Ia32/Processor.c\r
+\r
+[Sources.Ia32]\r
+  X64/Processor.c\r
+\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  EmbeddedPkg/EmbeddedPkg.dec\r
+\r
+[Packages.arm]\r
+  ArmPkg/ArmPkg.dec\r
+\r
+[LibraryClasses]\r
+  BaseLib  \r
+  DebugLib  \r
+  BaseMemoryLib  \r
+  PcdLib  \r
+  GdbSerialLib\r
+  CacheMaintenanceLib\r
+  DebugAgentTimerLib\r
+\r
+[FeaturePcd.common]\r
+  gEmbeddedTokenSpaceGuid.PcdGdbSerial\r
+\r
+[FixedPcd.common]\r
+  gEmbeddedTokenSpaceGuid.PcdGdbMaxPacketRetryCount\r
+\r
+[FixedPcd.arm]\r
+  gArmTokenSpaceGuid.PcdCpuVectorBaseAddress\r
diff --git a/EmbeddedPkg/Library/GdbDebugAgent/Ia32/Processor.c b/EmbeddedPkg/Library/GdbDebugAgent/Ia32/Processor.c
new file mode 100755 (executable)
index 0000000..d81e70f
--- /dev/null
@@ -0,0 +1,933 @@
+/** @file
+  Processor specific parts of the GDB stub
+
+  Copyright (c) 2008-2009, Apple Inc. All rights reserved.
+  
+  All rights reserved. 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 <GdbDebugAgent.h>\r
+
+//
+// Array of exception types that need to be hooked by the debugger
+// {EFI mapping, GDB mapping}
+//
+EFI_EXCEPTION_TYPE_ENTRY gExceptionType[] = {
+  { EXCEPT_IA32_DIVIDE_ERROR,     GDB_SIGFPE  }, 
+  { EXCEPT_IA32_DEBUG,            GDB_SIGTRAP },
+  { EXCEPT_IA32_NMI,              GDB_SIGEMT  },
+  { EXCEPT_IA32_BREAKPOINT,       GDB_SIGTRAP },
+  { EXCEPT_IA32_OVERFLOW,         GDB_SIGSEGV },
+  { EXCEPT_IA32_BOUND,            GDB_SIGSEGV },
+  { EXCEPT_IA32_INVALID_OPCODE,   GDB_SIGILL  },
+  { EXCEPT_IA32_DOUBLE_FAULT,     GDB_SIGEMT  },
+  { EXCEPT_IA32_STACK_FAULT,      GDB_SIGSEGV },
+  { EXCEPT_IA32_GP_FAULT,         GDB_SIGSEGV },
+  { EXCEPT_IA32_PAGE_FAULT,       GDB_SIGSEGV },
+  { EXCEPT_IA32_FP_ERROR,         GDB_SIGEMT  },
+  { EXCEPT_IA32_ALIGNMENT_CHECK,  GDB_SIGEMT  },
+  { EXCEPT_IA32_MACHINE_CHECK,    GDB_SIGEMT  }
+};
+
+
+// The offsets of registers SystemContext.
+// The fields in the array are in the gdb ordering.
+//
+//16 regs
+UINTN gRegisterOffsets[] = {
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Eax),
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Ecx),
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Edx),
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Ebx),
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Esp),
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Ebp),
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Esi),
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Edi),
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Eip),
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Eflags),
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Cs),
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Ss),
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Ds),
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Es),
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Fs),
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Gs)
+};
+
+
+//Debug only..
+VOID 
+PrintReg (
+  IN EFI_SYSTEM_CONTEXT SystemContext
+  )
+{
+  Print ((CHAR16 *)L"EAX: %x ", SystemContext.SystemContextIa32->Eax);
+  Print ((CHAR16 *)L"ECX: %x ", SystemContext.SystemContextIa32->Ecx);
+  Print ((CHAR16 *)L"EDX: %x ", SystemContext.SystemContextIa32->Edx);
+  Print ((CHAR16 *)L"EBX: %x ", SystemContext.SystemContextIa32->Ebx);
+  Print ((CHAR16 *)L"ESP: %x ", SystemContext.SystemContextIa32->Esp);
+  Print ((CHAR16 *)L"EBP: %x ", SystemContext.SystemContextIa32->Ebp);
+  Print ((CHAR16 *)L"ESI: %x ", SystemContext.SystemContextIa32->Esi);
+  Print ((CHAR16 *)L"EDI: %x ", SystemContext.SystemContextIa32->Edi);
+  Print ((CHAR16 *)L"EIP: %x\n", SystemContext.SystemContextIa32->Eip);
+  Print ((CHAR16 *)L"EFlags: %x\n", SystemContext.SystemContextIa32->Eflags);
+}
+
+//Debug only..
+VOID 
+PrintDRreg (
+  IN EFI_SYSTEM_CONTEXT SystemContext
+  )
+{
+  Print ((CHAR16 *)L"DR0: %x ", SystemContext.SystemContextIa32->Dr0);
+  Print ((CHAR16 *)L"DR1: %x ", SystemContext.SystemContextIa32->Dr1);
+  Print ((CHAR16 *)L"DR2: %x ", SystemContext.SystemContextIa32->Dr2);
+  Print ((CHAR16 *)L"DR3: %x ", SystemContext.SystemContextIa32->Dr3);
+  Print ((CHAR16 *)L"DR6: %x ", SystemContext.SystemContextIa32->Dr6);
+  Print ((CHAR16 *)L"DR7: %x\n", SystemContext.SystemContextIa32->Dr7);
+}
+
+
+/**
+ 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);
+}
+
+
+/**
+  Check to see if the ISA is supported. 
+  ISA = Instruction Set Architecture
+  @retval TRUE if Isa is supported,
+      FALSE otherwise.
+**/
+BOOLEAN
+CheckIsa (
+  IN  EFI_INSTRUCTION_SET_ARCHITECTURE  Isa
+  )
+{
+  return (BOOLEAN)(Isa == IsaIa32);
+}
+
+
+/**
+ 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 IA32 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;
+  TempPtr = ((UINT8 *)SystemContext.SystemContextIa32) + gRegisterOffsets[RegNumber];
+  return (UINTN *)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;
+  
+  RegSize = 0;
+  while (RegSize < REG_SIZE) {
+    *OutBufPtr++ = mHexToStr[((*FindPointerToRegister(SystemContext, RegNumber) >> (RegSize+4)) & 0xf)];
+    *OutBufPtr++ = mHexToStr[((*FindPointerToRegister(SystemContext, RegNumber) >> RegSize) & 0xf)];
+    RegSize = RegSize + 8;
+  }
+  return OutBufPtr;
+}
+
+
+/** ‘p n’ 
+ 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
+EFIAPI
+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 < 0) || (RegNumber >= sizeof (gRegisterOffsets)/sizeof (UINTN))) {
+    SendError (GDB_EINVALIDREGNUM);
+    return;
+  }
+
+  OutBufPtr = OutBuffer;
+  OutBufPtr = BasicReadRegister(SystemContext, RegNumber, OutBufPtr);
+
+  *OutBufPtr = '\0';  // the end of the buffer
+  SendPacket(OutBuffer);
+}
+
+
+/** ‘g’ 
+ 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   i;
+  CHAR8 OutBuffer[129]; // 16 regs, 8 hex chars each, and the end '\0' (escape seq)
+  CHAR8 *OutBufPtr;   // pointer to the output buffer
+
+  OutBufPtr = OutBuffer;
+  for(i = 0 ; i < sizeof (gRegisterOffsets)/sizeof (UINTN) ; i++) {  // there are only 16 registers to read   
+    OutBufPtr = BasicReadRegister(SystemContext, i, OutBufPtr);
+  }
+
+  *OutBufPtr = '\0';  // the end of the buffer
+  SendPacket(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
+  
+  NewValue = 0;
+  RegSize = 0;
+  while (RegSize < REG_SIZE) {
+    TempValue = HexCharToInt(*InBufPtr++);
+    
+   if (TempValue < 0) {
+      SendError (GDB_EBADMEMDATA); 
+      return NULL;
+    }
+
+    NewValue += (TempValue << (RegSize+4));
+    TempValue = HexCharToInt(*InBufPtr++);
+    
+    if (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
+EFIAPI
+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 < 0) || (RegNumber >= sizeof (gRegisterOffsets)/sizeof (UINTN))) {
+       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
+
+  // check to see if the buffer is the right size which is 
+  // 1 (for 'G') + 16 (for 16 registers) * 8 ( for 8 hex chars each) = 129 
+  if (AsciiStrLen(InBuffer) != 129) { // 16 regs, 8 hex chars each, and the end '\0' (escape seq)
+       //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 < sizeof (gRegisterOffsets)/sizeof (UINTN); i++) {  // there are only 16 registers to write
+    InBufPtr = BasicWriteRegister(SystemContext, i, InBufPtr);
+  }
+
+  SendSuccess();
+}
+
+/** ‘c [addr ]’ 
+ 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.SystemContextIa32->Eip = 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();\r
+}
+
+
+/**
+  Returns breakpoint data address from DR0-DR3 based on the input breakpoint number
+
+  @param  SystemContext      Register content at time of the exception
+  @param  BreakpointNumber   Breakpoint number
+
+  @retval Address            Data address from DR0-DR3 based on the breakpoint number.
+
+**/
+UINTN
+GetBreakpointDataAddress (
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,
+  IN  UINTN               BreakpointNumber
+  )
+{
+  UINTN Address;
+
+  if (BreakpointNumber == 1) {
+    Address = SystemContext.SystemContextIa32->Dr0;
+  } else if (BreakpointNumber == 2) {
+    Address = SystemContext.SystemContextIa32->Dr1;
+  } else if (BreakpointNumber == 3) {
+    Address = SystemContext.SystemContextIa32->Dr2;
+  } else if (BreakpointNumber == 4) {
+    Address = SystemContext.SystemContextIa32->Dr3;
+  } else {
+    Address = 0;
+  }
+
+  return Address;
+}
+
+
+/**
+  Returns currently detected breakpoint value based on the register DR6 B0-B3 field.
+  If no breakpoint is detected then it returns 0.
+
+  @param  SystemContext  Register content at time of the exception
+
+  @retval {1-4}          Currently detected breakpoint value   
+  @retval 0              No breakpoint detected.
+**/
+UINTN
+GetBreakpointDetected (
+  IN  EFI_SYSTEM_CONTEXT  SystemContext
+  )
+{
+  IA32_DR6 Dr6;
+  UINTN BreakpointNumber;
+
+  Dr6.UintN = SystemContext.SystemContextIa32->Dr6;
+
+  if (Dr6.Bits.B0 == 1) {
+    BreakpointNumber = 1;
+  } else if (Dr6.Bits.B1 == 1) {
+    BreakpointNumber = 2;
+  } else if (Dr6.Bits.B2 == 1) {
+    BreakpointNumber = 3;
+  } else if (Dr6.Bits.B3 == 1) {
+    BreakpointNumber = 4;
+  } else {
+    BreakpointNumber = 0;  //No breakpoint detected 
+  }
+
+  return BreakpointNumber;
+}
+
+
+/**
+  Returns Breakpoint type (InstructionExecution, DataWrite, DataRead or DataReadWrite)
+  based on the Breakpoint number
+  
+  @param  SystemContext        Register content at time of the exception
+  @param  BreakpointNumber     Breakpoint number
+  
+  @retval BREAK_TYPE           Breakpoint type value read from register DR7 RWn field
+                               For unknown value, it returns NotSupported.
+  
+**/
+BREAK_TYPE
+GetBreakpointType (
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,
+  IN  UINTN               BreakpointNumber
+  )
+{
+  IA32_DR7 Dr7;
+  BREAK_TYPE Type = NotSupported;  //Default is NotSupported type
+
+  Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
+
+  if (BreakpointNumber == 1) {
+    Type = (BREAK_TYPE) Dr7.Bits.RW0;  
+  } else if (BreakpointNumber == 2) {
+    Type = (BREAK_TYPE) Dr7.Bits.RW1;  
+  } else if (BreakpointNumber == 3) {
+    Type = (BREAK_TYPE) Dr7.Bits.RW2;  
+  } else if (BreakpointNumber == 4) {
+    Type = (BREAK_TYPE) Dr7.Bits.RW3;  
+  }
+
+  return Type;
+}
+
+
+/** 
+  Parses Length and returns the length which DR7 LENn field accepts.
+  For example: If we receive 1-Byte length then we should return 0. 
+               Zero gets written to DR7 LENn field.
+
+  @param  Length  Breakpoint length in Bytes (1 byte, 2 byte, 4 byte)
+
+  @retval Length  Appropriate converted values which DR7 LENn field accepts.
+
+**/
+UINTN
+ConvertLengthData (
+  IN     UINTN   Length
+  )
+{
+  if (Length == 1) {         //1-Byte length 
+    return 0;
+  } else if (Length == 2) {  //2-Byte length
+    return 1;
+  } else if (Length == 4) {  //4-Byte length
+    return 3;
+  } else {                   //Undefined or 8-byte length
+    return 2;
+  }
+}
+
+
+/**
+  Finds the next free debug register. If all the registers are occupied then 
+  EFI_OUT_OF_RESOURCES is returned.  
+
+  @param  SystemContext   Register content at time of the exception
+  @param  Register        Register value (0 - 3 for the first free debug register)
+
+  @retval EFI_STATUS      Appropriate status value.
+
+**/
+EFI_STATUS
+FindNextFreeDebugRegister (
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,
+  OUT UINTN               *Register
+  )
+{
+  IA32_DR7 Dr7;
+
+  Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
+
+  if (Dr7.Bits.G0 == 0) {
+    *Register = 0;
+  } else if (Dr7.Bits.G1 == 0) {
+    *Register = 1;
+  } else if (Dr7.Bits.G2 == 0) {
+    *Register = 2;
+  } else if (Dr7.Bits.G3 == 0) {
+    *Register = 3;
+  } else {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Enables the debug register. Writes Address value to appropriate DR0-3 register.
+  Sets LENn, Gn, RWn bits in DR7 register.
+  @param  SystemContext   Register content at time of the exception
+  @param  Register        Register value (0 - 3) 
+  @param  Address         Breakpoint address value
+  @param  Type            Breakpoint type (Instruction, Data write, Data read 
+                          or write etc.)
+
+  @retval EFI_STATUS      Appropriate status value.
+
+**/
+EFI_STATUS
+EnableDebugRegister (
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,
+  IN  UINTN               Register,
+  IN  UINTN               Address,
+  IN  UINTN               Length,
+  IN  UINTN               Type
+  )
+{
+  IA32_DR7  Dr7;
+
+  //Convert length data
+  Length = ConvertLengthData (Length);
+
+  //For Instruction execution, length should be 0 
+  //(Ref. Intel reference manual 18.2.4)
+  if ((Type == 0) && (Length != 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+  //Hardware doesn't support ReadWatch (z3 packet) type. GDB can handle
+  //software breakpoint. We should send empty packet in both these cases.
+  if ((Type == (BREAK_TYPE)DataRead) || 
+      (Type == (BREAK_TYPE)SoftwareBreakpoint)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //Read DR7 so appropriate Gn, RWn and LENn bits can be modified.
+  Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
+
+  if (Register == 0) {
+    SystemContext.SystemContextIa32->Dr0 = Address;
+    Dr7.Bits.G0 = 1;
+    Dr7.Bits.RW0 = Type;
+    Dr7.Bits.LEN0 = Length;
+  } else if (Register == 1) {
+    SystemContext.SystemContextIa32->Dr1 = Address;
+    Dr7.Bits.G1 = 1;
+    Dr7.Bits.RW1 = Type;
+    Dr7.Bits.LEN1 = Length;
+  } else if (Register == 2) {
+    SystemContext.SystemContextIa32->Dr2 = Address;
+    Dr7.Bits.G2 = 1;
+    Dr7.Bits.RW2 = Type;
+    Dr7.Bits.LEN2 = Length;
+  } else if (Register == 3) {
+    SystemContext.SystemContextIa32->Dr3 = Address;
+    Dr7.Bits.G3 = 1;
+    Dr7.Bits.RW3 = Type;
+    Dr7.Bits.LEN3 = Length;
+  } else {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //Update Dr7 with appropriate Gn, RWn and LENn bits 
+  SystemContext.SystemContextIa32->Dr7 = Dr7.UintN;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Returns register number 0 - 3 for the maching debug register.
+  This function compares incoming Address, Type, Length and
+  if there is a match then it returns the appropriate register number.
+  In case of mismatch, function returns EFI_NOT_FOUND message.
+
+  @param  SystemContext  Register content at time of the exception
+  @param  Address        Breakpoint address value
+  @param  Length         Breakpoint length value
+  @param  Type           Breakpoint type (Instruction, Data write, 
+                         Data read or write etc.)
+  @param  Register       Register value to be returned
+
+  @retval EFI_STATUS     Appropriate status value.
+
+**/
+EFI_STATUS
+FindMatchingDebugRegister (
+ IN  EFI_SYSTEM_CONTEXT  SystemContext,
+ IN  UINTN               Address,
+ IN  UINTN               Length,
+ IN  UINTN               Type,
+ OUT UINTN               *Register
+ )
+{
+  IA32_DR7 Dr7;
+
+  //Hardware doesn't support ReadWatch (z3 packet) type. GDB can handle
+  //software breakpoint. We should send empty packet in both these cases.
+  if ((Type == (BREAK_TYPE)DataRead) || 
+      (Type == (BREAK_TYPE)SoftwareBreakpoint)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //Convert length data
+  Length = ConvertLengthData(Length);
+
+  Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
+
+  if ((Dr7.Bits.G0 == 1) && 
+      (Dr7.Bits.LEN0 == Length) &&
+      (Dr7.Bits.RW0 == Type) && 
+      (Address == SystemContext.SystemContextIa32->Dr0)) {
+    *Register = 0;
+  } else if ((Dr7.Bits.G1 == 1) && 
+             (Dr7.Bits.LEN1 == Length) &&
+             (Dr7.Bits.RW1 == Type) && 
+             (Address == SystemContext.SystemContextIa32->Dr1)) {
+    *Register = 1;
+  } else if ((Dr7.Bits.G2 == 1) && 
+             (Dr7.Bits.LEN2 == Length) &&
+             (Dr7.Bits.RW2 == Type) && 
+             (Address == SystemContext.SystemContextIa32->Dr2)) {
+    *Register = 2;
+  } else if ((Dr7.Bits.G3 == 1) && 
+             (Dr7.Bits.LEN3 == Length) &&
+             (Dr7.Bits.RW3 == Type) && 
+             (Address == SystemContext.SystemContextIa32->Dr3)) {
+    *Register = 3;
+  } else {
+    Print ((CHAR16 *)L"No match found..\n");
+    return EFI_NOT_FOUND;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Disables the particular debug register.
+
+  @param  SystemContext   Register content at time of the exception
+  @param  Register        Register to be disabled
+
+  @retval EFI_STATUS      Appropriate status value.
+
+**/
+EFI_STATUS
+DisableDebugRegister (
+ IN  EFI_SYSTEM_CONTEXT  SystemContext,
+ IN  UINTN               Register  
+ )
+{
+  IA32_DR7  Dr7;
+  UINTN Address = 0;
+  //Read DR7 register so appropriate Gn, RWn and LENn bits can be turned off.
+  Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
+
+  if (Register == 0) {
+    SystemContext.SystemContextIa32->Dr0 = Address;
+    Dr7.Bits.G0 = 0;
+    Dr7.Bits.RW0 = 0;
+    Dr7.Bits.LEN0 = 0;
+  } else if (Register == 1) {
+    SystemContext.SystemContextIa32->Dr1 = Address;
+    Dr7.Bits.G1 = 0;
+    Dr7.Bits.RW1 = 0;
+    Dr7.Bits.LEN1 = 0;
+  } else if (Register == 2) {
+    SystemContext.SystemContextIa32->Dr2 = Address;
+    Dr7.Bits.G2 = 0;
+    Dr7.Bits.RW2 = 0;
+    Dr7.Bits.LEN2 = 0;
+  } else if (Register == 3) {
+    SystemContext.SystemContextIa32->Dr3 = Address;
+    Dr7.Bits.G3 = 0;
+    Dr7.Bits.RW3 = 0;
+    Dr7.Bits.LEN3 = 0;
+  } else {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //Update DR7 register so appropriate Gn, RWn and LENn bits can be turned off.
+  SystemContext.SystemContextIa32->Dr7 = Dr7.UintN;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  ‘Z1, [addr], [length]’
+  ‘Z2, [addr], [length]’
+  ‘Z3, [addr], [length]’
+  ‘Z4, [addr], [length]’
+
+  Insert hardware breakpoint/watchpoint at address addr of size length
+
+  @param SystemContext  Register content at time of the exception
+  @param *PacketData    Pointer to the Payload data for the packet
+
+**/
+VOID
+EFIAPI
+InsertBreakPoint (
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,
+  IN  CHAR8              *PacketData
+  )
+{
+  UINTN Type;
+  UINTN Address;
+  UINTN Length;
+  UINTN Register;
+  EFI_STATUS Status;
+  BREAK_TYPE BreakType = NotSupported;
+  UINTN ErrorCode;
+
+  ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);
+  if (ErrorCode > 0) {
+    SendError ((UINT8)ErrorCode);
+    return;
+  }
+
+  switch (Type) {
+
+    case    0:   //Software breakpoint
+      BreakType = SoftwareBreakpoint;
+      break;
+
+    case    1:   //Hardware breakpoint
+      BreakType = InstructionExecution;
+      break;
+
+    case    2:   //Write watchpoint
+      BreakType = DataWrite;
+      break;
+
+    case    3:   //Read watchpoint
+      BreakType = DataRead;
+      break;
+
+    case    4:   //Access watchpoint
+      BreakType = DataReadWrite;
+      break;
+
+    default  :
+      Print ((CHAR16 *)L"Insert breakpoint default: %x\n", Type);
+      SendError (GDB_EINVALIDBRKPOINTTYPE);
+      return;
+  }
+
+  // Find next free debug register
+  Status = FindNextFreeDebugRegister (SystemContext, &Register);
+  if (EFI_ERROR(Status)) {
+    Print ((CHAR16 *)L"No space left on device\n");
+    SendError (GDB_ENOSPACE);
+    return;
+  }
+
+  // Write Address, length data at particular DR register
+  Status = EnableDebugRegister (SystemContext, Register, Address, Length, (UINTN)BreakType);
+  if (EFI_ERROR(Status)) {
+    if (Status == EFI_UNSUPPORTED) {
+      SendNotSupported();
+      return;
+    }
+
+    SendError (GDB_EINVALIDARG);
+    return;
+  }
+
+  SendSuccess ();
+}
+
+
+/**
+  ‘z1, [addr], [length]’
+  ‘z2, [addr], [length]’
+  ‘z3, [addr], [length]’
+  ‘z4, [addr], [length]’
+
+  Remove hardware breakpoint/watchpoint at address addr of size length
+
+  @param *PacketData    Pointer to the Payload data for the packet
+
+**/
+VOID
+EFIAPI
+RemoveBreakPoint (
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,
+  IN  CHAR8               *PacketData
+  )
+{
+  UINTN      Type;
+  UINTN      Address;
+  UINTN      Length;
+  UINTN      Register;
+  BREAK_TYPE BreakType = NotSupported;
+  EFI_STATUS Status;
+  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
+      BreakType = SoftwareBreakpoint;
+      break;
+      
+    case    1:   //Hardware breakpoint
+      BreakType = InstructionExecution;
+      break;
+      
+    case    2:   //Write watchpoint
+      BreakType = DataWrite;
+      break;
+
+    case    3:   //Read watchpoint
+      BreakType = DataRead;
+      break;
+
+    case    4:   //Access watchpoint
+      BreakType = DataReadWrite;
+      break;
+
+    default  :
+      SendError (GDB_EINVALIDBRKPOINTTYPE);
+      return;
+  }
+
+  //Find matching debug register
+  Status = FindMatchingDebugRegister (SystemContext, Address, Length, (UINTN)BreakType, &Register);
+  if (EFI_ERROR(Status)) {
+    if (Status == EFI_UNSUPPORTED) {
+      SendNotSupported();
+      return;
+    }
+
+    SendError (GDB_ENOSPACE);
+    return;
+  }
+
+  //Remove breakpoint
+  Status = DisableDebugRegister(SystemContext, Register);
+  if (EFI_ERROR(Status)) {
+    SendError (GDB_EINVALIDARG);
+    return;
+  }
+
+  SendSuccess ();
+}
+
+
+/**\r
+  Initialize debug agent.\r
+\r
+  This function is used to set up debug enviroment. It may enable interrupts.\r
+\r
+  @param[in] InitFlag   Init flag is used to decide initialize process.\r
+  @param[in] Context    Context needed according to InitFlag, it was optional.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+InitializeDebugAgent (\r
+  IN UINT32                InitFlag,\r
+  IN VOID                  *Context  OPTIONAL\r
+  )\r
+{\r
+  // BugBug: Add the code to build an GDT/IDT\r
+}\r
+\r
diff --git a/EmbeddedPkg/Library/GdbDebugAgent/X64/Processor.c b/EmbeddedPkg/Library/GdbDebugAgent/X64/Processor.c
new file mode 100755 (executable)
index 0000000..0758bc4
--- /dev/null
@@ -0,0 +1,963 @@
+/** @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
+\r
+#include <GdbStubInternal.h>\r
+\r
+//\r
+// Array of exception types that need to be hooked by the debugger\r
+//\r
+EFI_EXCEPTION_TYPE_ENTRY gExceptionType[] = {\r
+  { EXCEPT_X64_DIVIDE_ERROR,    GDB_SIGFPE  },  \r
+  { EXCEPT_X64_DEBUG,           GDB_SIGTRAP },\r
+  { EXCEPT_X64_NMI,             GDB_SIGEMT  },\r
+  { EXCEPT_X64_BREAKPOINT,      GDB_SIGTRAP },\r
+  { EXCEPT_X64_OVERFLOW,        GDB_SIGSEGV },\r
+  { EXCEPT_X64_BOUND,           GDB_SIGSEGV },\r
+  { EXCEPT_X64_INVALID_OPCODE,  GDB_SIGILL  },\r
+  { EXCEPT_X64_DOUBLE_FAULT,    GDB_SIGEMT  },\r
+  { EXCEPT_X64_STACK_FAULT,     GDB_SIGSEGV },\r
+  { EXCEPT_X64_GP_FAULT,        GDB_SIGSEGV },\r
+  { EXCEPT_X64_PAGE_FAULT,      GDB_SIGSEGV },\r
+  { EXCEPT_X64_FP_ERROR,        GDB_SIGEMT  },\r
+  { EXCEPT_X64_ALIGNMENT_CHECK, GDB_SIGEMT  },\r
+  { EXCEPT_X64_MACHINE_CHECK,   GDB_SIGEMT  }\r
+};\r
+\r
+\r
+// The offsets of registers SystemContextX64.\r
+// The fields in the array are in the gdb ordering.  \r
+// HAVE TO DOUBLE-CHECK THE ORDER of the 24 regs\r
+//\r
+UINTN gRegisterOffsets[] = {\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rax),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rcx),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rdx),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rbx),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rsp),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rbp),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rsi),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rdi),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rip),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rflags),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Cs),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Ss),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Ds),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Es),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Fs),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Gs),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R8),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R9),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R10),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R11),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R12),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R13),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R14),\r
+  OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R15)\r
+};\r
+\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
+BOOLEAN\r
+CheckIsa (\r
+  IN  EFI_INSTRUCTION_SET_ARCHITECTURE  Isa\r
+  )\r
+{\r
+  return (BOOLEAN)(Isa == IsaX64);\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 X64 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
+  TempPtr = ((UINT8 *)SystemContext.SystemContextX64) + gRegisterOffsets[RegNumber];\r
+  return (UINTN *)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
+  \r
+  RegSize = 0;\r
+  while (RegSize < 64) {\r
+    *OutBufPtr++ = mHexToStr[((*FindPointerToRegister(SystemContext, RegNumber) >> (RegSize+4)) & 0xf)];\r
+    *OutBufPtr++ = mHexToStr[((*FindPointerToRegister(SystemContext, RegNumber) >> RegSize) & 0xf)];\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[17];  // 1 reg=16 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 < 0) || (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
+\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   i;\r
+  CHAR8 OutBuffer[385]; // 24 regs, 16 hex chars each, and the end '\0' (escape seq)\r
+  CHAR8 *OutBufPtr;   // pointer to the output buffer\r
+  \r
+  OutBufPtr = OutBuffer;\r
+  for(i = 0 ; i < MaxRegisterCount() ; i++) {  // there are only 24 registers to read   \r
+    OutBufPtr = BasicReadRegister(SystemContext, i, OutBufPtr);\r
+  }\r
+  \r
+  *OutBufPtr = '\0';  // the end of the buffer\r
+  SendPacket (OutBuffer);\r
+}\r
+\r
+\r
+/**\r
+ Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr\r
+\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
+  UINT64 NewValue; // the new value of the RegNumber-th Register\r
+  \r
+  NewValue = 0;\r
+  RegSize = 0;\r
+  while (RegSize < 64) {\r
+    TempValue = HexCharToInt(*InBufPtr++);\r
+    \r
+    if (TempValue < 0) {\r
+      SendError (GDB_EBADMEMDATA); \r
+      return NULL;\r
+    }\r
+    \r
+    NewValue += (TempValue << (RegSize+4));\r
+    TempValue = HexCharToInt(*InBufPtr++);\r
+    \r
+    if (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
+\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
+EFIAPI\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 < 0) || (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
+\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
+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
+  \r
+  // check to see if the buffer is the right size which is \r
+  // 1 (for 'G') + 16 (for 16 registers) * 8 ( for 8 hex chars each) = 385 \r
+  if (AsciiStrLen(InBuffer) != 385) { // 24 regs, 16 hex chars each, and the end '\0' (escape seq)\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 < MaxRegisterCount(); i++) {  // there are only 16 registers to write\r
+    InBufPtr = BasicWriteRegister(SystemContext, i, InBufPtr);\r
+  }\r
+  \r
+  SendSuccess();\r
+}\r
+\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
+  SystemContext.SystemContextX64->Rflags |= TF_BIT; //Setting the TF bit.\r
+}\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
+  SystemContext.SystemContextX64->Rflags &= ~TF_BIT;  // clearing the TF bit.\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.SystemContextX64->Rip = 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
+  if (PacketData[1] != '\0') {\r
+    SystemContext.SystemContextX64->Rip = AsciiStrHexToUintn (&PacketData[1]);\r
+  }\r
+  \r
+  AddSingleStep (SystemContext);\r
+}\r
+\r
+\r
+/**\r
+  Returns breakpoint data address from DR0-DR3 based on the input breakpoint \r
+  number\r
+\r
+  @param  SystemContext      Register content at time of the exception\r
+  @param  BreakpointNumber   Breakpoint number\r
+\r
+  @retval Address            Data address from DR0-DR3 based on the \r
+                             breakpoint number.\r
+\r
+**/\r
+UINTN\r
+GetBreakpointDataAddress (\r
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,\r
+  IN  UINTN               BreakpointNumber\r
+  )\r
+{\r
+  UINTN Address;\r
+\r
+  if (BreakpointNumber == 1) {\r
+    Address = SystemContext.SystemContextIa32->Dr0;\r
+  } else if (BreakpointNumber == 2) {\r
+    Address = SystemContext.SystemContextIa32->Dr1;\r
+  } else if (BreakpointNumber == 3) {\r
+    Address = SystemContext.SystemContextIa32->Dr2;\r
+  } else if (BreakpointNumber == 4) {\r
+    Address = SystemContext.SystemContextIa32->Dr3;\r
+  } else {\r
+    Address = 0;\r
+  }\r
+\r
+  return Address;\r
+}\r
+\r
+/**\r
+  Returns currently detected breakpoint value based on the register \r
+  DR6 B0-B3 field.\r
+  If no breakpoint is detected then it returns 0.\r
+\r
+  @param  SystemContext  Register content at time of the exception\r
+\r
+  @retval {1-4}          Currently detected breakpoint value\r
+  @retval 0              No breakpoint detected.\r
+\r
+**/\r
+UINTN\r
+GetBreakpointDetected (\r
+  IN  EFI_SYSTEM_CONTEXT  SystemContext\r
+  )\r
+{\r
+  IA32_DR6 Dr6;\r
+  UINTN BreakpointNumber;\r
+\r
+  Dr6.UintN = SystemContext.SystemContextIa32->Dr6;\r
+\r
+  if (Dr6.Bits.B0 == 1) {\r
+    BreakpointNumber = 1;\r
+  } else if (Dr6.Bits.B1 == 1) {\r
+    BreakpointNumber = 2;\r
+  } else if (Dr6.Bits.B2 == 1) {\r
+    BreakpointNumber = 3;\r
+  } else if (Dr6.Bits.B3 == 1) {\r
+    BreakpointNumber = 4;\r
+  } else {\r
+    BreakpointNumber = 0;  //No breakpoint detected\r
+  }\r
+\r
+  return BreakpointNumber;\r
+}\r
+\r
+/**\r
+  Returns Breakpoint type (InstructionExecution, DataWrite, DataRead \r
+  or DataReadWrite) based on the Breakpoint number\r
+\r
+  @param  SystemContext      Register content at time of the exception\r
+  @param  BreakpointNumber   Breakpoint number\r
+\r
+  @retval BREAK_TYPE         Breakpoint type value read from register DR7 RWn \r
+                             field. For unknown value, it returns NotSupported.\r
+\r
+**/\r
+BREAK_TYPE\r
+GetBreakpointType (\r
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,\r
+  IN  UINTN               BreakpointNumber\r
+  )\r
+{\r
+  IA32_DR7 Dr7;\r
+  BREAK_TYPE Type = NotSupported;  //Default is NotSupported type\r
+\r
+  Dr7.UintN = SystemContext.SystemContextIa32->Dr7;\r
+\r
+  if (BreakpointNumber == 1) {\r
+    Type = (BREAK_TYPE) Dr7.Bits.RW0;\r
+  } else if (BreakpointNumber == 2) {\r
+    Type = (BREAK_TYPE) Dr7.Bits.RW1;\r
+  } else if (BreakpointNumber == 3) {\r
+    Type = (BREAK_TYPE) Dr7.Bits.RW2;\r
+  } else if (BreakpointNumber == 4) {\r
+    Type = (BREAK_TYPE) Dr7.Bits.RW3;\r
+  }\r
+\r
+  return Type;\r
+}\r
+\r
+\r
+/** \r
+  Parses Length and returns the length which DR7 LENn field accepts.\r
+  For example: If we receive 1-Byte length then we should return 0. \r
+               Zero gets written to DR7 LENn field.\r
+\r
+  @param  Length  Breakpoint length in Bytes (1 byte, 2 byte, 4 byte)\r
+\r
+  @retval Length  Appropriate converted values which DR7 LENn field accepts.\r
+\r
+**/\r
+UINTN\r
+ConvertLengthData (\r
+  IN     UINTN   Length\r
+  )\r
+{\r
+  if (Length == 1) {         //1-Byte length \r
+    return 0;\r
+  } else if (Length == 2) {  //2-Byte length\r
+    return 1;\r
+  } else if (Length == 4) {  //4-Byte length\r
+    return 3;\r
+  } else {                   //Undefined or 8-byte length\r
+    return 2;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Finds the next free debug register. If all the registers are occupied then\r
+  EFI_OUT_OF_RESOURCES is returned.\r
+\r
+  @param  SystemContext  Register content at time of the exception\r
+  @param  Register       Register value (0 - 3 for the first free debug register)\r
+\r
+  @retval EFI_STATUS     Appropriate status value.\r
+\r
+**/\r
+EFI_STATUS\r
+FindNextFreeDebugRegister (\r
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,\r
+  OUT UINTN               *Register\r
+  )\r
+{\r
+  IA32_DR7 Dr7;\r
+\r
+  Dr7.UintN = SystemContext.SystemContextIa32->Dr7;\r
+\r
+  if (Dr7.Bits.G0 == 0) {\r
+    *Register = 0;\r
+  } else if (Dr7.Bits.G1 == 0) {\r
+    *Register = 1;\r
+  } else if (Dr7.Bits.G2 == 0) {\r
+    *Register = 2;\r
+  } else if (Dr7.Bits.G3 == 0) {\r
+    *Register = 3;\r
+  } else {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Enables the debug register. Writes Address value to appropriate DR0-3 register.\r
+  Sets LENn, Gn, RWn bits in DR7 register.\r
+\r
+  @param  SystemContext   Register content at time of the exception\r
+  @param  Register        Register value (0 - 3)\r
+  @param  Address         Breakpoint address value\r
+  @param  Type            Breakpoint type (Instruction, Data write, \r
+                          Data read or write etc.)\r
+\r
+  @retval EFI_STATUS      Appropriate status value.\r
+\r
+**/\r
+EFI_STATUS\r
+EnableDebugRegister (\r
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,\r
+  IN  UINTN               Register,\r
+  IN  UINTN               Address,\r
+  IN  UINTN               Length,\r
+  IN  UINTN               Type\r
+  )\r
+{\r
+  IA32_DR7  Dr7;\r
+\r
+  //Convert length data\r
+  Length = ConvertLengthData (Length);\r
+\r
+  //For Instruction execution, length should be 0 \r
+  //(Ref. Intel reference manual 18.2.4)\r
+  if ((Type == 0) && (Length != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //Hardware doesn't support ReadWatch (z3 packet) type. GDB can handle\r
+  //software breakpoint. We should send empty packet in both these cases.\r
+  if ((Type == (BREAK_TYPE)DataRead) || \r
+      (Type == (BREAK_TYPE)SoftwareBreakpoint))  {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //Read DR7 so appropriate Gn, RWn and LENn bits can be modified.\r
+  Dr7.UintN = SystemContext.SystemContextIa32->Dr7;\r
+\r
+  if (Register == 0) {\r
+    SystemContext.SystemContextIa32->Dr0 = Address;\r
+    Dr7.Bits.G0 = 1;\r
+    Dr7.Bits.RW0 = Type;\r
+    Dr7.Bits.LEN0 = Length;\r
+  } else if (Register == 1) {\r
+    SystemContext.SystemContextIa32->Dr1 = Address;\r
+    Dr7.Bits.G1 = 1;\r
+    Dr7.Bits.RW1 = Type;\r
+    Dr7.Bits.LEN1 = Length;\r
+  } else if (Register == 2) {\r
+    SystemContext.SystemContextIa32->Dr2 = Address;\r
+    Dr7.Bits.G2 = 1;\r
+    Dr7.Bits.RW2 = Type;\r
+    Dr7.Bits.LEN2 = Length;\r
+  } else if (Register == 3) {\r
+    SystemContext.SystemContextIa32->Dr3 = Address;\r
+    Dr7.Bits.G3 = 1;\r
+    Dr7.Bits.RW3 = Type;\r
+    Dr7.Bits.LEN3 = Length;\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //Update Dr7 with appropriate Gn, RWn and LENn bits\r
+  SystemContext.SystemContextIa32->Dr7 = Dr7.UintN;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**  \r
+  Returns register number 0 - 3 for the maching debug register. \r
+  This function compares incoming Address, Type, Length and \r
+  if there is a match then it returns the appropriate register number.\r
+  In case of mismatch, function returns EFI_NOT_FOUND message.\r
+\r
+  @param  SystemContext  Register content at time of the exception\r
+  @param  Address        Breakpoint address value  \r
+  @param  Length         Breakpoint length value\r
+  @param  Type           Breakpoint type (Instruction, Data write, Data read\r
+                         or write etc.)\r
+  @param  Register       Register value to be returned\r
+\r
+  @retval EFI_STATUS     Appropriate status value.\r
+\r
+**/\r
+EFI_STATUS\r
+FindMatchingDebugRegister (\r
+ IN  EFI_SYSTEM_CONTEXT  SystemContext,\r
+ IN  UINTN               Address,\r
+ IN  UINTN               Length,\r
+ IN  UINTN               Type,\r
+ OUT UINTN               *Register\r
+ )\r
+{\r
+  IA32_DR7 Dr7;\r
+\r
+  //Hardware doesn't support ReadWatch (z3 packet) type. GDB can handle\r
+  //software breakpoint. We should send empty packet in both these cases.\r
+  if ((Type == (BREAK_TYPE)DataRead) || \r
+      (Type == (BREAK_TYPE)SoftwareBreakpoint)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //Convert length data\r
+  Length = ConvertLengthData(Length);\r
+\r
+  Dr7.UintN = SystemContext.SystemContextIa32->Dr7;\r
+\r
+  if ((Dr7.Bits.G0 == 1) && \r
+      (Dr7.Bits.LEN0 == Length) &&\r
+      (Dr7.Bits.RW0 == Type) && \r
+      (Address == SystemContext.SystemContextIa32->Dr0)) {\r
+    *Register = 0;\r
+  } else if ((Dr7.Bits.G1 == 1) && \r
+             (Dr7.Bits.LEN1 == Length) &&\r
+             (Dr7.Bits.RW1 == Type) && \r
+             (Address == SystemContext.SystemContextIa32->Dr1)) {\r
+    *Register = 1;\r
+  } else if ((Dr7.Bits.G2 == 1) && \r
+             (Dr7.Bits.LEN2 == Length) &&\r
+             (Dr7.Bits.RW2 == Type) && \r
+             (Address == SystemContext.SystemContextIa32->Dr2)) {\r
+    *Register = 2;\r
+  } else if ((Dr7.Bits.G3 == 1) && \r
+             (Dr7.Bits.LEN3 == Length) &&\r
+             (Dr7.Bits.RW3 == Type) && \r
+             (Address == SystemContext.SystemContextIa32->Dr3)) {\r
+    *Register = 3;\r
+  } else {\r
+    Print ((CHAR16 *)L"No match found..\n");\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Disables the particular debug register.\r
+\r
+  @param  SystemContext   Register content at time of the exception\r
+  @param  Register        Register to be disabled\r
+\r
+  @retval EFI_STATUS      Appropriate status value.\r
+\r
+**/\r
+EFI_STATUS\r
+DisableDebugRegister (\r
+ IN  EFI_SYSTEM_CONTEXT  SystemContext,\r
+ IN  UINTN               Register\r
+ )\r
+{\r
+  IA32_DR7  Dr7;\r
+  UINTN Address = 0;\r
+\r
+  //Read DR7 register so appropriate Gn, RWn and LENn bits can be turned off.\r
+  Dr7.UintN = SystemContext.SystemContextIa32->Dr7;\r
+\r
+  if (Register == 0) {\r
+    SystemContext.SystemContextIa32->Dr0 = Address;\r
+    Dr7.Bits.G0 = 0;\r
+    Dr7.Bits.RW0 = 0;\r
+    Dr7.Bits.LEN0 = 0;\r
+  } else if (Register == 1) {\r
+    SystemContext.SystemContextIa32->Dr1 = Address;\r
+    Dr7.Bits.G1 = 0;\r
+    Dr7.Bits.RW1 = 0;\r
+    Dr7.Bits.LEN1 = 0;\r
+  } else if (Register == 2) {\r
+    SystemContext.SystemContextIa32->Dr2 = Address;\r
+    Dr7.Bits.G2 = 0;\r
+    Dr7.Bits.RW2 = 0;\r
+    Dr7.Bits.LEN2 = 0;\r
+  } else if (Register == 3) {\r
+    SystemContext.SystemContextIa32->Dr3 = Address;\r
+    Dr7.Bits.G3 = 0;\r
+    Dr7.Bits.RW3 = 0;\r
+    Dr7.Bits.LEN3 = 0;\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //Update DR7 register so appropriate Gn, RWn and LENn bits can be turned off.\r
+  SystemContext.SystemContextIa32->Dr7 = Dr7.UintN;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  ‘Z1, [addr], [length]’\r
+  ‘Z2, [addr], [length]’\r
+  ‘Z3, [addr], [length]’\r
+  ‘Z4, [addr], [length]’\r
+\r
+  Insert hardware breakpoint/watchpoint at address addr of size length\r
+\r
+  @param SystemContext  Register content at time of the exception\r
+  @param *PacketData    Pointer to the Payload data for the packet\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 Register;\r
+  EFI_STATUS Status;\r
+  BREAK_TYPE BreakType = NotSupported;\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
+\r
+    case    0:   //Software breakpoint\r
+      BreakType = SoftwareBreakpoint;\r
+      break;\r
+\r
+    case    1:   //Hardware breakpoint\r
+      BreakType = InstructionExecution;\r
+      break;\r
+\r
+    case    2:   //Write watchpoint\r
+      BreakType = DataWrite;\r
+      break;\r
+\r
+    case    3:   //Read watchpoint\r
+      BreakType = DataRead;\r
+      break;\r
+\r
+    case    4:   //Access watchpoint\r
+      BreakType = DataReadWrite;\r
+      break;\r
+\r
+    default  :\r
+      Print ((CHAR16 *)L"Insert breakpoint default: %x\n", Type);\r
+      SendError (GDB_EINVALIDBRKPOINTTYPE);\r
+      return;\r
+  }\r
+\r
+  // Find next free debug register\r
+  Status = FindNextFreeDebugRegister (SystemContext, &Register);\r
+  if (EFI_ERROR(Status)) {\r
+    Print ((CHAR16 *)L"No space left on device\n");\r
+    SendError (GDB_ENOSPACE);\r
+    return;\r
+  }\r
+\r
+  // Write Address, length data at particular DR register\r
+  Status = EnableDebugRegister (SystemContext, Register, Address, Length, (UINTN)BreakType);\r
+  if (EFI_ERROR(Status)) {\r
+\r
+    if (Status == EFI_UNSUPPORTED) {\r
+      Print ((CHAR16 *)L"Not supported\n");\r
+      SendNotSupported();\r
+      return;\r
+    }\r
+\r
+    Print ((CHAR16 *)L"Invalid argument\n");\r
+    SendError (GDB_EINVALIDARG);\r
+    return;\r
+  }\r
+\r
+  SendSuccess ();\r
+}\r
+\r
+\r
+/**\r
+  ‘z1, [addr], [length]’\r
+  ‘z2, [addr], [length]’\r
+  ‘z3, [addr], [length]’\r
+  ‘z4, [addr], [length]’\r
+\r
+  Remove hardware breakpoint/watchpoint at address addr of size length\r
+\r
+  @param *PacketData    Pointer to the Payload data for the packet\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      Register;\r
+  BREAK_TYPE BreakType = NotSupported;\r
+  EFI_STATUS Status;\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
+  \r
+    case    0:   //Software breakpoint\r
+      BreakType = SoftwareBreakpoint;\r
+      break;\r
+      \r
+    case    1:   //Hardware breakpoint\r
+      BreakType = InstructionExecution;\r
+      break;\r
+      \r
+    case    2:   //Write watchpoint\r
+      BreakType = DataWrite;\r
+      break;\r
+\r
+    case    3:   //Read watchpoint\r
+      BreakType = DataRead;\r
+      break;\r
+\r
+    case    4:   //Access watchpoint\r
+      BreakType = DataReadWrite;\r
+      break;\r
+\r
+    default  :\r
+      SendError (GDB_EINVALIDBRKPOINTTYPE);\r
+      return;\r
+  }\r
+\r
+  //Find matching debug register\r
+  Status = FindMatchingDebugRegister (SystemContext, Address, Length, (UINTN)BreakType, &Register);\r
+  if (EFI_ERROR(Status)) {\r
+\r
+    if (Status == EFI_UNSUPPORTED) {\r
+      Print ((CHAR16 *)L"Not supported.\n");\r
+      SendNotSupported();\r
+      return;\r
+    }\r
+\r
+    Print ((CHAR16 *)L"No matching register found.\n");\r
+    SendError (GDB_ENOSPACE);\r
+    return;\r
+  }\r
+\r
+  //Remove breakpoint\r
+  Status = DisableDebugRegister(SystemContext, Register);\r
+  if (EFI_ERROR(Status)) {\r
+    Print ((CHAR16 *)L"Invalid argument.\n");\r
+    SendError (GDB_EINVALIDARG);\r
+    return;\r
+  }\r
+\r
+  SendSuccess ();\r
+}\r
+\r
+\r
+VOID\r
+InitializeProcessor (\r
+  VOID\r
+  )\r
+{\r
+}\r
+\r
+BOOLEAN\r
+ValidateAddress (\r
+  IN  VOID  *Address\r
+  )\r
+{\r
+  return TRUE;\r
+}\r
+\r
+BOOLEAN\r
+ValidateException (\r
+  IN  EFI_EXCEPTION_TYPE    ExceptionType, \r
+  IN OUT EFI_SYSTEM_CONTEXT SystemContext \r
+  )\r
+{\r
+  return TRUE;\r
+}\r
+\r
diff --git a/EmbeddedPkg/Library/GdbDebugAgent/gdbnotes.txt b/EmbeddedPkg/Library/GdbDebugAgent/gdbnotes.txt
new file mode 100755 (executable)
index 0000000..b5e303d
--- /dev/null
@@ -0,0 +1,15 @@
+arm-none-eabi-gcc -march=armv7-a -mthumb  t.c -Wl,-nostdlib --emit-relocs\r
+\r
+target remote com7\r
+set debug remote 1 \r
+set remotetimeout 30\r
+set remotelogfile log.txt\r
+add-symbol-file c:/work/edk2/Build/BeagleBoard/DEBUG_ARMGCC/ARM/BeagleBoardPkg/Sec/Sec/DEBUG/BeagleBoardSec.dll 0x80008360 \r
+\r
+\r
+qSupported\r
+Hg0\r
+\r
+Hc-1\r
+qC\r
+qAttached
\ No newline at end of file