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
+ DebugAgentTimerLib|Include/Library/DebugAgentTimerLib.h\r
\r
\r
[Guids.common]\r
0x00000F72,\r
0x00000F73,\r
0x00000FFF, // fps\r
- 0x00000FFF, \r
- 0x00000FFF, \r
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, CPSR)\r
};\r
\r
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+#/** @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
--- /dev/null
+#------------------------------------------------------------------------------
+#
+# 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
+
--- /dev/null
+//------------------------------------------------------------------------------
+//
+// 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
+
+
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+#/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+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