Add the beginning of a GDB based Debug Agent. IA-32 and X64 don't have low level interrupt code yet. I've been testing on ARM.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10334 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
andrewfish
2010-04-03 00:41:42 +00:00
parent 66c0b4461a
commit 969eba7b0d
14 changed files with 4836 additions and 4 deletions

View File

@ -0,0 +1,258 @@
#------------------------------------------------------------------------------
#
# Use ARMv6 instruction to operate on a single stack
#
# Copyright (c) 2008-2010 Apple Inc. All rights reserved.
#
# All rights reserved. This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
#------------------------------------------------------------------------------
/*
This is the stack constructed by the exception handler (low address to high address)
# R0 - IFAR is EFI_SYSTEM_CONTEXT for ARM
Reg Offset
=== ======
R0 0x00 # stmfd SP!,{R0-R12}
R1 0x04
R2 0x08
R3 0x0c
R4 0x10
R5 0x14
R6 0x18
R7 0x1c
R8 0x20
R9 0x24
R10 0x28
R11 0x2c
R12 0x30
SP 0x34 # reserved via adding 0x20 (32) to the SP
LR 0x38
PC 0x3c
CPSR 0x40
DFSR 0x44
DFAR 0x48
IFSR 0x4c
IFAR 0x50
LR 0x54 # SVC Link register (we need to restore it)
LR 0x58 # pushed by srsfd
CPSR 0x5c
*/
.globl ASM_PFX(ExceptionHandlersStart)
.globl ASM_PFX(ExceptionHandlersEnd)
.globl ASM_PFX(CommonExceptionEntry)
.globl ASM_PFX(AsmCommonExceptionEntry)
.globl ASM_PFX(GdbExceptionHandler)
.text
.align 3
//
// This code gets copied to the ARM vector table
// ExceptionHandlersStart - ExceptionHandlersEnd gets copied
//
ASM_PFX(ExceptionHandlersStart):
ASM_PFX(Reset):
b ASM_PFX(Reset)
ASM_PFX(UndefinedInstruction):
b ASM_PFX(UndefinedInstructionEntry)
ASM_PFX(SoftwareInterrupt):
b ASM_PFX(SoftwareInterruptEntry)
ASM_PFX(PrefetchAbort):
b ASM_PFX(PrefetchAbortEntry)
ASM_PFX(DataAbort):
b ASM_PFX(DataAbortEntry)
ASM_PFX(ReservedException):
b ASM_PFX(ReservedExceptionEntry)
ASM_PFX(Irq):
b ASM_PFX(Irq)
ASM_PFX(Fiq):
b ASM_PFX(FiqEntry)
ASM_PFX(UndefinedInstructionEntry):
sub LR, LR, #4 @ Only -2 for Thumb, adjust in CommonExceptionEntry
srsdb #0x13! @ Store return state on SVC stack
cps #0x13 @ Switch to SVC for common stack
stmfd SP!,{LR} @ Store the link register for the current mode
sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} @ Store the register state
mov R0,#1 @ ExceptionType
ldr R1,ASM_PFX(CommonExceptionEntry)
bx R1
ASM_PFX(SoftwareInterruptEntry):
sub LR, LR, #4 @ Only -2 for Thumb, adjust in CommonExceptionEntry
srsdb #0x13! @ Store return state on SVC stack
@ We are already in SVC mode
stmfd SP!,{LR} @ Store the link register for the current mode
sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} @ Store the register state
mov R0,#2 @ ExceptionType
ldr R1,ASM_PFX(CommonExceptionEntry)
bx R1
ASM_PFX(PrefetchAbortEntry):
sub LR,LR,#4
srsdb #0x13! @ Store return state on SVC stack
cps #0x13 @ Switch to SVC for common stack
stmfd SP!,{LR} @ Store the link register for the current mode
sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} @ Store the register state
mov R0,#3 @ ExceptionType
ldr R1,ASM_PFX(CommonExceptionEntry)
bx R1
ASM_PFX(DataAbortEntry):
sub LR,LR,#8
srsdb #0x13! @ Store return state on SVC stack
cps #0x13 @ Switch to SVC for common stack
stmfd SP!,{LR} @ Store the link register for the current mode
sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} @ Store the register state
mov R0,#4
ldr R1,ASM_PFX(CommonExceptionEntry)
bx R1
ASM_PFX(ReservedExceptionEntry):
srsdb #0x13! @ Store return state on SVC stack
cps #0x13 @ Switch to SVC for common stack
stmfd SP!,{LR} @ Store the link register for the current mode
sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} @ Store the register state
mov R0,#5
ldr R1,ASM_PFX(CommonExceptionEntry)
bx R1
ASM_PFX(FiqEntry):
sub LR,LR,#4
srsdb #0x13! @ Store return state on SVC stack
cps #0x13 @ Switch to SVC for common stack
stmfd SP!,{LR} @ Store the link register for the current mode
sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} @ Store the register state
@ Since we have already switch to SVC R8_fiq - R12_fiq
@ never get used or saved
mov R0,#7 @ ExceptionType
ldr R1,ASM_PFX(CommonExceptionEntry)
bx R1
//
// This gets patched by the C code that patches in the vector table
//
ASM_PFX(CommonExceptionEntry):
.byte 0x12
.byte 0x34
.byte 0x56
.byte 0x78
ASM_PFX(ExceptionHandlersEnd):
//
// This code runs from CpuDxe driver loaded address. It is patched into
// CommonExceptionEntry.
//
ASM_PFX(AsmCommonExceptionEntry):
mrc p15, 0, R1, c6, c0, 2 @ Read IFAR
str R1, [SP, #0x50] @ Store it in EFI_SYSTEM_CONTEXT_ARM.IFAR
mrc p15, 0, R1, c5, c0, 1 @ Read IFSR
str R1, [SP, #0x4c] @ Store it in EFI_SYSTEM_CONTEXT_ARM.IFSR
mrc p15, 0, R1, c6, c0, 0 @ Read DFAR
str R1, [SP, #0x48] @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFAR
mrc p15, 0, R1, c5, c0, 0 @ Read DFSR
str R1, [SP, #0x44] @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR
ldr R1, [SP, #0x5c] @ srsdb saved pre-exception CPSR on the stack
str R1, [SP, #0x40] @ Store it in EFI_SYSTEM_CONTEXT_ARM.CPSR
add R2, SP, #0x38 @ Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR
and R3, R1, #0x1f @ Check CPSR to see if User or System Mode
cmp R3, #0x1f @ if ((CPSR == 0x10) || (CPSR == 0x1df))
cmpne R3, #0x10 @
stmeqed R2, {lr}^ @ save unbanked lr
@ else
stmneed R2, {lr} @ save SVC lr
ldr R5, [SP, #0x58] @ PC is the LR pushed by srsfd
@ Check to see if we have to adjust for Thumb entry
sub r4, r0, #1 @ if (ExceptionType == 1 || ExceptionType ==2)) {
cmp r4, #1 @ // UND & SVC have differnt LR adjust for Thumb
bhi NoAdjustNeeded
tst r1, #0x20 @ if ((CPSR & T)) == T) { // Thumb Mode on entry
addne R5, R5, #2 @ PC += 2@
str R5,[SP,#0x58] @ Update LR value pused by srsfd
NoAdjustNeeded:
str R5, [SP, #0x3c] @ Store it in EFI_SYSTEM_CONTEXT_ARM.PC
sub R1, SP, #0x60 @ We pused 0x60 bytes on the stack
str R1, [SP, #0x34] @ Store it in EFI_SYSTEM_CONTEXT_ARM.SP
@ R0 is ExceptionType
mov R1,SP @ R1 is SystemContext
/*
VOID
EFIAPI
GdbExceptionHandler (
IN EFI_EXCEPTION_TYPE ExceptionType, R0
IN OUT EFI_SYSTEM_CONTEXT SystemContext R1
)
*/
blx ASM_PFX(GdbExceptionHandler) @ Call exception handler
ldr R1,[SP,#0x3c] @ EFI_SYSTEM_CONTEXT_ARM.PC
str R1,[SP,#0x58] @ Store it back to srsfd stack slot so it can be restored
ldr R1,[SP,#0x40] @ EFI_SYSTEM_CONTEXT_ARM.CPSR
str R1,[SP,#0x5c] @ Store it back to srsfd stack slot so it can be restored
add R3, SP, #0x54 @ Make R3 point to SVC LR saved on entry
add R2, SP, #0x38 @ Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR
and R1, R1, #0x1f @ Check to see if User or System Mode
cmp R1, #0x1f @ if ((CPSR == 0x10) || (CPSR == 0x1f))
cmpne R1, #0x10 @
ldmeqed R2, {lr}^ @ restore unbanked lr
@ else
ldmneed R3, {lr} @ restore SVC lr, via ldmfd SP!, {LR}
ldmfd SP!,{R0-R12} @ Restore general purpose registers
@ Exception handler can not change SP
add SP,SP,#0x20 @ Clear out the remaining stack space
ldmfd SP!,{LR} @ restore the link register for this context
rfefd SP! @ return from exception via srsfd stack slot

View File

@ -0,0 +1,259 @@
//------------------------------------------------------------------------------
//
// Use ARMv6 instruction to operate on a single stack
//
// Copyright (c) 2008-2010 Apple Inc. All rights reserved.
//
// All rights reserved. This program and the accompanying materials
// are licensed and made available under the terms and conditions of the BSD License
// which accompanies this distribution. The full text of the license may be found at
// http://opensource.org/licenses/bsd-license.php
//
// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
//
//------------------------------------------------------------------------------
/*
This is the stack constructed by the exception handler (low address to high address)
# R0 - IFAR is EFI_SYSTEM_CONTEXT for ARM
Reg Offset
=== ======
R0 0x00 # stmfd SP!,{R0-R12}
R1 0x04
R2 0x08
R3 0x0c
R4 0x10
R5 0x14
R6 0x18
R7 0x1c
R8 0x20
R9 0x24
R10 0x28
R11 0x2c
R12 0x30
SP 0x34 # reserved via adding 0x20 (32) to the SP
LR 0x38
PC 0x3c
CPSR 0x40
DFSR 0x44
DFAR 0x48
IFSR 0x4c
IFAR 0x50
LR 0x54 # SVC Link register (we need to restore it)
LR 0x58 # pushed by srsfd
CPSR 0x5c
*/
EXPORT ExceptionHandlersStart
EXPORT ExceptionHandlersEnd
EXPORT CommonExceptionEntry
EXPORT AsmCommonExceptionEntry
IMPORT GdbExceptionHandler
PRESERVE8
AREA DxeExceptionHandlers, CODE, READONLY
//
// This code gets copied to the ARM vector table
// ExceptionHandlersStart - ExceptionHandlersEnd gets copied
//
ExceptionHandlersStart
Reset
b Reset
UndefinedInstruction
b UndefinedInstructionEntry
SoftwareInterrupt
b SoftwareInterruptEntry
PrefetchAbort
b PrefetchAbortEntry
DataAbort
b DataAbortEntry
ReservedException
b ReservedExceptionEntry
Irq
b Irq
Fiq
b FiqEntry
UndefinedInstructionEntry
sub LR, LR, #4 ; Only -2 for Thumb, adjust in CommonExceptionEntry
srsfd #0x13! ; Store return state on SVC stack
cps #0x13 ; Switch to SVC for common stack
stmfd SP!,{LR} ; Store the link register for the current mode
sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} ; Store the register state
mov R0,#1 ; ExceptionType
ldr R1,CommonExceptionEntry;
bx R1
SoftwareInterruptEntry
sub LR, LR, #4 ; Only -2 for Thumb, adjust in CommonExceptionEntry
srsfd #0x13! ; Store return state on SVC stack
; We are already in SVC mode
stmfd SP!,{LR} ; Store the link register for the current mode
sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} ; Store the register state
mov R0,#2 ; ExceptionType
ldr R1,CommonExceptionEntry
bx R1
PrefetchAbortEntry
sub LR,LR,#4
srsfd #0x13! ; Store return state on SVC stack
cps #0x13 ; Switch to SVC for common stack
stmfd SP!,{LR} ; Store the link register for the current mode
sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} ; Store the register state
mov R0,#3 ; ExceptionType
ldr R1,CommonExceptionEntry
bx R1
DataAbortEntry
sub LR,LR,#8
srsfd #0x13! ; Store return state on SVC stack
cps #0x13 ; Switch to SVC for common stack
stmfd SP!,{LR} ; Store the link register for the current mode
sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} ; Store the register state
mov R0,#4 ; ExceptionType
ldr R1,CommonExceptionEntry
bx R1
ReservedExceptionEntry
srsfd #0x13! ; Store return state on SVC stack
cps #0x13 ; Switch to SVC for common stack
stmfd SP!,{LR} ; Store the link register for the current mode
sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} ; Store the register state
mov R0,#5 ; ExceptionType
ldr R1,CommonExceptionEntry
bx R1
FiqEntry
sub LR,LR,#4
srsfd #0x13! ; Store return state on SVC stack
cps #0x13 ; Switch to SVC for common stack
stmfd SP!,{LR} ; Store the link register for the current mode
sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} ; Store the register state
; Since we have already switch to SVC R8_fiq - R12_fiq
; never get used or saved
mov R0,#7 ; ExceptionType
ldr R1,CommonExceptionEntry
bx R1
//
// This gets patched by the C code that patches in the vector table
//
CommonExceptionEntry
dcd 0x12345678
ExceptionHandlersEnd
//
// This code runs from CpuDxe driver loaded address. It is patched into
// CommonExceptionEntry.
//
AsmCommonExceptionEntry
mrc p15, 0, R1, c6, c0, 2 ; Read IFAR
str R1, [SP, #0x50] ; Store it in EFI_SYSTEM_CONTEXT_ARM.IFAR
mrc p15, 0, R1, c5, c0, 1 ; Read IFSR
str R1, [SP, #0x4c] ; Store it in EFI_SYSTEM_CONTEXT_ARM.IFSR
mrc p15, 0, R1, c6, c0, 0 ; Read DFAR
str R1, [SP, #0x48] ; Store it in EFI_SYSTEM_CONTEXT_ARM.DFAR
mrc p15, 0, R1, c5, c0, 0 ; Read DFSR
str R1, [SP, #0x44] ; Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR
ldr R1, [SP, #0x5c] ; srsfd saved pre-exception CPSR on the stack
str R1, [SP, #0x40] ; Store it in EFI_SYSTEM_CONTEXT_ARM.CPSR
add R2, SP, #0x38 ; Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR
and R3, R1, #0x1f ; Check CPSR to see if User or System Mode
cmp R3, #0x1f ; if ((CPSR == 0x10) || (CPSR == 0x1df))
cmpne R3, #0x10 ;
stmeqed R2, {lr}^ ; save unbanked lr
; else
stmneed R2, {lr} ; save SVC lr
ldr R5, [SP, #0x58] ; PC is the LR pushed by srsfd
; Check to see if we have to adjust for Thumb entry
sub r4, r0, #1 ; if (ExceptionType == 1 || ExceptionType ==2)) {
cmp r4, #1 ; // UND & SVC have differnt LR adjust for Thumb
bhi NoAdjustNeeded
tst r1, #0x20 ; if ((CPSR & T)) == T) { // Thumb Mode on entry
addne R5, R5, #2 ; PC += 2;
str R5,[SP,#0x58] ; Update LR value pused by srsfd
NoAdjustNeeded
str R5, [SP, #0x3c] ; Store it in EFI_SYSTEM_CONTEXT_ARM.PC
sub R1, SP, #0x60 ; We pused 0x60 bytes on the stack
str R1, [SP, #0x34] ; Store it in EFI_SYSTEM_CONTEXT_ARM.SP
; R0 is ExceptionType
mov R1,SP ; R1 is SystemContext
/*
VOID
EFIAPI
GdbExceptionHandler (
IN EFI_EXCEPTION_TYPE ExceptionType, R0
IN OUT EFI_SYSTEM_CONTEXT SystemContext R1
)
*/
blx GdbExceptionHandler ; Call exception handler
ldr R1,[SP,#0x3c] ; EFI_SYSTEM_CONTEXT_ARM.PC
str R1,[SP,#0x58] ; Store it back to srsfd stack slot so it can be restored
ldr R1,[SP,#0x40] ; EFI_SYSTEM_CONTEXT_ARM.CPSR
str R1,[SP,#0x5c] ; Store it back to srsfd stack slot so it can be restored
add R3, SP, #0x54 ; Make R3 point to SVC LR saved on entry
add R2, SP, #0x38 ; Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR
and R1, R1, #0x1f ; Check to see if User or System Mode
cmp R1, #0x1f ; if ((CPSR == 0x10) || (CPSR == 0x1f))
cmpne R1, #0x10 ;
ldmeqed R2, {lr}^ ; restore unbanked lr
; else
ldmneed R3, {lr} ; restore SVC lr, via ldmfd SP!, {LR}
ldmfd SP!,{R0-R12} ; Restore general purpose registers
; Exception handler can not change SP
add SP,SP,#0x20 ; Clear out the remaining stack space
ldmfd SP!,{LR} ; restore the link register for this context
rfefd SP! ; return from exception via srsfd stack slot
END

View File

@ -0,0 +1,630 @@
/** @file
Processor specific parts of the GDB stub
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.
**/
#include <GdbDebugAgent.h>
#include <Library/CacheMaintenanceLib.h>
#include <Library/PrintLib.h>
#include <Library/ArmLib.h>
//
// Externs from the exception handler assembly file
//
VOID
ExceptionHandlersStart (
VOID
);
VOID
ExceptionHandlersEnd (
VOID
);
VOID
CommonExceptionEntry (
VOID
);
VOID
AsmCommonExceptionEntry (
VOID
);
//
// Array of exception types that need to be hooked by the debugger
// (efi, gdb) //efi number
//
EFI_EXCEPTION_TYPE_ENTRY gExceptionType[] = {
{ EXCEPT_ARM_SOFTWARE_INTERRUPT, GDB_SIGTRAP },
{ EXCEPT_ARM_UNDEFINED_INSTRUCTION, GDB_SIGTRAP },
{ EXCEPT_ARM_PREFETCH_ABORT, GDB_SIGTRAP },
{ EXCEPT_ARM_DATA_ABORT, GDB_SIGTRAP }, // GDB_SIGEMT
{ EXCEPT_ARM_RESERVED, GDB_SIGTRAP }, // GDB_SIGILL
{ EXCEPT_ARM_FIQ, GDB_SIGINT } // Used for ctrl-c
};
// Shut up some annoying RVCT warnings
#ifdef __CC_ARM
#pragma diag_suppress 1296
#endif
UINTN gRegisterOffsets[] = {
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R0),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R1),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R2),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R3),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R4),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R5),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R6),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R7),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R8),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R9),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R10),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R11),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R12),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, SP),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, LR),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, PC),
0x00000F01, // f0
0x00000F02,
0x00000F03,
0x00000F11, // f1
0x00000F12,
0x00000F13,
0x00000F21, // f2
0x00000F22,
0x00000F23,
0x00000F31, // f3
0x00000F32,
0x00000F33,
0x00000F41, // f4
0x00000F42,
0x00000F43,
0x00000F51, // f5
0x00000F52,
0x00000F53,
0x00000F61, // f6
0x00000F62,
0x00000F63,
0x00000F71, // f7
0x00000F72,
0x00000F73,
0x00000FFF, // fps
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, CPSR)
};
// restore warnings for RVCT
#ifdef __CC_ARM
#pragma diag_default 1296
#endif
/**
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
**/
BOOLEAN
CheckIsa (
IN EFI_INSTRUCTION_SET_ARCHITECTURE Isa
)
{
if (Isa == IsaArm) {
return TRUE;
} else {
return FALSE;
}
}
/**
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 ARM 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;
ASSERT(gRegisterOffsets[RegNumber] < 0xF00);
TempPtr = ((UINT8 *)SystemContext.SystemContextArm) + gRegisterOffsets[RegNumber];
return (UINT32 *)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;
CHAR8 Char;
if (gRegisterOffsets[RegNumber] > 0xF00) {
AsciiSPrint(OutBufPtr, 9, "00000000");
OutBufPtr += 8;
return OutBufPtr;
}
RegSize = 0;
while (RegSize < 32) {
Char = mHexToStr[(UINT8)((*FindPointerToRegister(SystemContext, RegNumber) >> (RegSize+4)) & 0xf)];
if ((Char >= 'A') && (Char <= 'F')) {
Char = Char - 'A' + 'a';
}
*OutBufPtr++ = Char;
Char = mHexToStr[(UINT8)((*FindPointerToRegister(SystemContext, RegNumber) >> RegSize) & 0xf)];
if ((Char >= 'A') && (Char <= 'F')) {
Char = Char - 'A' + 'a';
}
*OutBufPtr++ = Char;
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
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 >= (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 Index;
// a UINT32 takes 8 ascii characters
CHAR8 OutBuffer[(sizeof (gRegisterOffsets) * 2) + 1];
CHAR8 *OutBufPtr;
// It is not safe to allocate pool here....
OutBufPtr = OutBuffer;
for (Index = 0; Index < (sizeof (gRegisterOffsets)/sizeof (UINTN)); Index++) {
OutBufPtr = BasicReadRegister (SystemContext, Index, OutBufPtr);
}
*OutBufPtr = '\0';
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
if (gRegisterOffsets[RegNumber] > 0xF00) {
return InBufPtr + 8;
}
NewValue = 0;
RegSize = 0;
while (RegSize < 32) {
TempValue = HexCharToInt(*InBufPtr++);
if ((INTN)TempValue < 0) {
SendError (GDB_EBADMEMDATA);
return NULL;
}
NewValue += (TempValue << (RegSize+4));
TempValue = HexCharToInt(*InBufPtr++);
if ((INTN)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
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 >= (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
UINTN MinLength;
UINTN RegisterCount = (sizeof (gRegisterOffsets)/sizeof (UINTN));
MinLength = (RegisterCount * 8) + 1; // 'G' plus the registers in ASCII format
if (AsciiStrLen(InBuffer) < MinLength) {
//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 < RegisterCount; i++) {
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.SystemContextArm->PC = 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();
}
VOID
EFIAPI
InsertBreakPoint (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *PacketData
)
{
SendNotSupported ();
}
VOID
EFIAPI
RemoveBreakPoint (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *PacketData
)
{
SendNotSupported ();
}
/**
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';
}
/**
Check to see if this exception is related to ctrl-c handling.
In this scheme we dedicate FIQ to the ctrl-c handler so it is
independent of the rest of the system.
SaveAndSetDebugTimerInterrupt () can be used to
@param ExceptionType Exception that is being processed
@param SystemContext Register content at time of the exception
@return TRUE This was a ctrl-c check that did not find a ctrl-c
@return FALSE This was not a ctrl-c check or some one hit ctrl-c
**/
BOOLEAN
ProcessorControlC (
IN EFI_EXCEPTION_TYPE ExceptionType,
IN OUT EFI_SYSTEM_CONTEXT SystemContext
)
{
BOOLEAN Return = TRUE;
if (ExceptionType != EXCEPT_ARM_FIQ) {
// Skip it as it is not related to ctrl-c
return FALSE;
}
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;
}
}
DebugAgentTimerEndOfInterrupt ();
// Force an exit from the exception handler as we are done
return Return;
}
/**
Enable/Disable the interrupt of debug timer and return the interrupt state
prior to the operation.
If EnableStatus is TRUE, enable the interrupt of debug timer.
If EnableStatus is FALSE, disable the interrupt of debug timer.
@param[in] EnableStatus Enable/Disable.
@return FALSE always.
**/
BOOLEAN
EFIAPI
SaveAndSetDebugTimerInterrupt (
IN BOOLEAN EnableStatus
)
{
BOOLEAN FiqEnabled;
FiqEnabled = ArmGetFiqState ();
if (EnableStatus) {
DebugAgentTimerSetPeriod (100);
ArmEnableFiq ();
} else {
DebugAgentTimerSetPeriod (0);
ArmDisableFiq ();
}
return FiqEnabled;
}
VOID
GdbFPutString (
IN CHAR8 *String
);
/**
Initialize debug agent.
This function is used to set up debug enviroment. It may enable interrupts.
@param[in] InitFlag Init flag is used to decide initialize process.
@param[in] Context Context needed according to InitFlag, it was optional.
**/
VOID
EFIAPI
InitializeDebugAgent (
IN UINT32 InitFlag,
IN VOID *Context OPTIONAL
)
{
UINTN Offset;
UINTN Length;
BOOLEAN IrqEnabled;
BOOLEAN FiqEnabled;
UINT32 *VectorBase;
//
// Disable interrupts
//
IrqEnabled = ArmGetInterruptState ();
ArmDisableInterrupts ();
//
// EFI does not use the FIQ, but a debugger might so we must disable
// as we take over the exception vectors.
//
FiqEnabled = ArmGetFiqState ();
ArmDisableFiq ();
//
// Copy an implementation of the ARM exception vectors to PcdCpuVectorBaseAddress.
//
Length = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart;
//
// Reserve space for the exception handlers
//
VectorBase = (UINT32 *)(UINTN)PcdGet32 (PcdCpuVectorBaseAddress);
// Copy our assembly code into the page that contains the exception vectors.
CopyMem ((VOID *)VectorBase, (VOID *)ExceptionHandlersStart, Length);
//
// Patch in the common Assembly exception handler
//
Offset = (UINTN)CommonExceptionEntry - (UINTN)ExceptionHandlersStart;
*(UINTN *) (((UINT8 *)VectorBase) + Offset) = (UINTN)AsmCommonExceptionEntry;
// Flush Caches since we updated executable stuff
InvalidateInstructionCacheRange ((VOID *)PcdGet32(PcdCpuVectorBaseAddress), Length);
DebugAgentTimerIntialize ();
if (FiqEnabled) {
ArmEnableFiq ();
}
if (IrqEnabled) {
ArmEnableInterrupts ();
}
return;
}