2010-04-03 02:41:42 +02:00
|
|
|
|
/** @file
|
|
|
|
|
Processor specific parts of the GDB stub
|
|
|
|
|
|
2010-04-29 14:40:51 +02:00
|
|
|
|
Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
2010-04-29 14:40:51 +02:00
|
|
|
|
This program and the accompanying materials
|
2010-04-03 02:41:42 +02:00
|
|
|
|
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/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 },
|
2014-08-19 15:29:52 +02:00
|
|
|
|
{ EXCEPT_ARM_UNDEFINED_INSTRUCTION, GDB_SIGTRAP },
|
|
|
|
|
{ EXCEPT_ARM_PREFETCH_ABORT, GDB_SIGTRAP },
|
2010-04-03 02:41:42 +02:00
|
|
|
|
{ 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[]
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
|
|
|
|
@retval UINTN, the number of entries in the gExceptionType[] array.
|
2010-04-03 02:41:42 +02:00
|
|
|
|
**/
|
|
|
|
|
UINTN
|
|
|
|
|
MaxEfiException (
|
|
|
|
|
VOID
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
return sizeof (gExceptionType)/sizeof (EFI_EXCEPTION_TYPE_ENTRY);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2014-08-19 15:29:52 +02:00
|
|
|
|
Check to see if the ISA is supported.
|
2010-04-03 02:41:42 +02:00
|
|
|
|
ISA = Instruction Set Architecture
|
|
|
|
|
|
2014-08-19 15:29:52 +02:00
|
|
|
|
@retval TRUE if Isa is supported
|
2010-04-03 02:41:42 +02:00
|
|
|
|
|
|
|
|
|
**/
|
|
|
|
|
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
|
2014-08-19 15:29:52 +02:00
|
|
|
|
@param SystemContext Register content at time of the exception
|
2010-04-03 02:41:42 +02:00
|
|
|
|
@param RegNumber The register to which we want to find a pointer
|
|
|
|
|
@retval the pointer to the RegNumber-th pointer
|
2014-08-19 15:29:52 +02:00
|
|
|
|
**/
|
2010-04-03 02:41:42 +02:00
|
|
|
|
UINTN *
|
|
|
|
|
FindPointerToRegister(
|
|
|
|
|
IN EFI_SYSTEM_CONTEXT SystemContext,
|
2014-08-19 15:29:52 +02:00
|
|
|
|
IN UINTN RegNumber
|
2010-04-03 02:41:42 +02:00
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
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;
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
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;
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
Char = mHexToStr[(UINT8)((*FindPointerToRegister(SystemContext, RegNumber) >> RegSize) & 0xf)];
|
|
|
|
|
if ((Char >= 'A') && (Char <= 'F')) {
|
|
|
|
|
Char = Char - 'A' + 'a';
|
|
|
|
|
}
|
|
|
|
|
*OutBufPtr++ = Char;
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
RegSize = RegSize + 8;
|
|
|
|
|
}
|
|
|
|
|
return OutBufPtr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-09-23 00:53:54 +02:00
|
|
|
|
/**
|
2014-08-19 15:29:52 +02:00
|
|
|
|
Reads the n-th register's value into an output buffer and sends it as a packet
|
2010-04-03 02:41:42 +02:00
|
|
|
|
@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
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
RegNumber = AsciiStrHexToUintn (&InBuffer[1]);
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
if (RegNumber >= (sizeof (gRegisterOffsets)/sizeof (UINTN))) {
|
2014-08-19 15:29:52 +02:00
|
|
|
|
SendError (GDB_EINVALIDREGNUM);
|
2010-04-03 02:41:42 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
OutBufPtr = OutBuffer;
|
|
|
|
|
OutBufPtr = BasicReadRegister (SystemContext, RegNumber, OutBufPtr);
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
*OutBufPtr = '\0'; // the end of the buffer
|
|
|
|
|
SendPacket(OutBuffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-09-23 00:53:54 +02:00
|
|
|
|
/**
|
2014-08-19 15:29:52 +02:00
|
|
|
|
Reads the general registers into an output buffer and sends it as a packet
|
2010-04-03 02:41:42 +02:00
|
|
|
|
@param SystemContext Register content at time of the exception
|
|
|
|
|
**/
|
|
|
|
|
VOID
|
|
|
|
|
EFIAPI
|
2014-08-19 15:29:52 +02:00
|
|
|
|
ReadGeneralRegisters (
|
2010-04-03 02:41:42 +02:00
|
|
|
|
IN EFI_SYSTEM_CONTEXT SystemContext
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
UINTN Index;
|
|
|
|
|
// a UINT32 takes 8 ascii characters
|
|
|
|
|
CHAR8 OutBuffer[(sizeof (gRegisterOffsets) * 2) + 1];
|
|
|
|
|
CHAR8 *OutBufPtr;
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
// It is not safe to allocate pool here....
|
|
|
|
|
OutBufPtr = OutBuffer;
|
|
|
|
|
for (Index = 0; Index < (sizeof (gRegisterOffsets)/sizeof (UINTN)); Index++) {
|
|
|
|
|
OutBufPtr = BasicReadRegister (SystemContext, Index, OutBufPtr);
|
|
|
|
|
}
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
*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
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
if (gRegisterOffsets[RegNumber] > 0xF00) {
|
|
|
|
|
return InBufPtr + 8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NewValue = 0;
|
|
|
|
|
RegSize = 0;
|
|
|
|
|
while (RegSize < 32) {
|
|
|
|
|
TempValue = HexCharToInt(*InBufPtr++);
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
if ((INTN)TempValue < 0) {
|
2014-08-19 15:29:52 +02:00
|
|
|
|
SendError (GDB_EBADMEMDATA);
|
2010-04-03 02:41:42 +02:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
NewValue += (TempValue << (RegSize+4));
|
|
|
|
|
TempValue = HexCharToInt(*InBufPtr++);
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
if ((INTN)TempValue < 0) {
|
2014-08-19 15:29:52 +02:00
|
|
|
|
SendError (GDB_EBADMEMDATA);
|
2010-04-03 02:41:42 +02:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
|
|
|
|
NewValue += (TempValue << RegSize);
|
2010-04-03 02:41:42 +02:00
|
|
|
|
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
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
// find the register number to write
|
|
|
|
|
InBufPtr = &InBuffer[1];
|
|
|
|
|
RegNumBufPtr = RegNumBuffer;
|
|
|
|
|
while (*InBufPtr != '=') {
|
|
|
|
|
*RegNumBufPtr++ = *InBufPtr++;
|
2014-08-19 15:29:52 +02:00
|
|
|
|
}
|
2010-04-03 02:41:42 +02:00
|
|
|
|
*RegNumBufPtr = '\0';
|
2014-08-19 15:29:52 +02:00
|
|
|
|
RegNumber = AsciiStrHexToUintn (RegNumBuffer);
|
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
// check if this is a valid Register Number
|
|
|
|
|
if (RegNumber >= (sizeof (gRegisterOffsets)/sizeof (UINTN))) {
|
2014-08-19 15:29:52 +02:00
|
|
|
|
SendError (GDB_EINVALIDREGNUM);
|
2010-04-03 02:41:42 +02:00
|
|
|
|
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
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
if (AsciiStrLen(InBuffer) < MinLength) {
|
2014-08-19 15:29:52 +02:00
|
|
|
|
//Bad message. Message is not the right length
|
|
|
|
|
SendError (GDB_EBADBUFSIZE);
|
2010-04-03 02:41:42 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
InBufPtr = &InBuffer[1];
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
// 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);
|
|
|
|
|
}
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
SendSuccess ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-09-23 00:53:54 +02:00
|
|
|
|
/**
|
2014-08-19 15:29:52 +02:00
|
|
|
|
Continue. addr is Address to resume. If addr is omitted, resume at current
|
2010-04-03 02:41:42 +02:00
|
|
|
|
Address.
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
|
|
|
|
@param SystemContext Register content at time of the exception
|
2010-04-03 02:41:42 +02:00
|
|
|
|
**/
|
|
|
|
|
VOID
|
|
|
|
|
EFIAPI
|
|
|
|
|
ContinueAtAddress (
|
|
|
|
|
IN EFI_SYSTEM_CONTEXT SystemContext,
|
|
|
|
|
IN CHAR8 *PacketData
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
if (PacketData[1] != '\0') {
|
|
|
|
|
SystemContext.SystemContextArm->PC = AsciiStrHexToUintn(&PacketData[1]);
|
2014-08-19 15:29:52 +02:00
|
|
|
|
}
|
2010-04-03 02:41:42 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** ‘s [addr ]’
|
2014-08-19 15:29:52 +02:00
|
|
|
|
Single step. addr is the Address at which to resume. If addr is omitted, resume
|
2010-04-03 02:41:42 +02:00
|
|
|
|
at same Address.
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
|
|
|
|
@param SystemContext Register content at time of the exception
|
2010-04-03 02:41:42 +02:00
|
|
|
|
**/
|
|
|
|
|
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 ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-01-25 12:28:06 +01:00
|
|
|
|
/**
|
2014-08-19 15:29:52 +02:00
|
|
|
|
Send the T signal with the given exception type (in gdb order) and possibly
|
2013-01-25 12:28:06 +01:00
|
|
|
|
with n:r pairs related to the watchpoints
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
2013-01-25 12:28:06 +01:00
|
|
|
|
@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';
|
|
|
|
|
}
|
2010-04-03 02:41:42 +02:00
|
|
|
|
|
2010-04-22 00:08:28 +02:00
|
|
|
|
/**
|
|
|
|
|
FIQ state is only changed by FIQ exception. We don't want to take FIQ
|
2014-08-19 15:29:52 +02:00
|
|
|
|
ticks in the GDB stub. The stub disables FIQ on entry, but this is the
|
2010-04-22 00:08:28 +02:00
|
|
|
|
third instruction that executes in the execption handler. Thus we have
|
|
|
|
|
a crack we need to test for.
|
|
|
|
|
|
|
|
|
|
@param PC PC of execption
|
|
|
|
|
|
2014-08-19 15:29:52 +02:00
|
|
|
|
@return TRUE We are in the GDB stub exception preamble
|
2010-04-22 00:08:28 +02:00
|
|
|
|
@return FALSE We are not in GDB stub code
|
2013-01-25 12:28:06 +01:00
|
|
|
|
**/
|
|
|
|
|
BOOLEAN
|
|
|
|
|
InFiqCrack (
|
|
|
|
|
IN UINT32 PC
|
|
|
|
|
)
|
|
|
|
|
{
|
2016-03-24 21:30:06 +01:00
|
|
|
|
UINT64 VectorBase = PcdGet64 (PcdCpuVectorBaseAddress);
|
2013-01-25 12:28:06 +01:00
|
|
|
|
UINT32 Length = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart;
|
|
|
|
|
|
|
|
|
|
if ((PC >= VectorBase) && (PC <= (VectorBase + Length))) {
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2010-04-22 00:08:28 +02:00
|
|
|
|
|
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
/**
|
|
|
|
|
Check to see if this exception is related to ctrl-c handling.
|
|
|
|
|
|
2014-08-19 15:29:52 +02:00
|
|
|
|
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
|
2010-04-03 02:41:42 +02:00
|
|
|
|
|
|
|
|
|
@param ExceptionType Exception that is being processed
|
2014-08-19 15:29:52 +02:00
|
|
|
|
@param SystemContext Register content at time of the exception
|
2010-04-03 02:41:42 +02:00
|
|
|
|
|
|
|
|
|
@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
|
2014-08-19 15:29:52 +02:00
|
|
|
|
ProcessorControlC (
|
|
|
|
|
IN EFI_EXCEPTION_TYPE ExceptionType,
|
|
|
|
|
IN OUT EFI_SYSTEM_CONTEXT SystemContext
|
2010-04-03 02:41:42 +02:00
|
|
|
|
)
|
|
|
|
|
{
|
2010-04-22 00:08:28 +02:00
|
|
|
|
CHAR8 Char;
|
2010-04-03 02:41:42 +02:00
|
|
|
|
BOOLEAN Return = TRUE;
|
|
|
|
|
|
|
|
|
|
if (ExceptionType != EXCEPT_ARM_FIQ) {
|
|
|
|
|
// Skip it as it is not related to ctrl-c
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-22 00:08:28 +02:00
|
|
|
|
if (InFiqCrack (SystemContext.SystemContextArm->PC)) {
|
|
|
|
|
// We are in our own interrupt preable, so skip this tick.
|
|
|
|
|
// We never want to let gdb see the debug stub running if we can help it
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-25 12:28:06 +01:00
|
|
|
|
while (TRUE) {
|
|
|
|
|
if (!GdbIsCharAvailable ()) {
|
|
|
|
|
//
|
|
|
|
|
// No characters are pending so exit the loop
|
|
|
|
|
//
|
|
|
|
|
Return = TRUE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2014-08-19 15:29:52 +02:00
|
|
|
|
|
2013-01-25 12:28:06 +01:00
|
|
|
|
Char = GdbGetChar ();
|
|
|
|
|
if (Char == 0x03) {
|
|
|
|
|
//
|
|
|
|
|
// We have a ctrl-c so exit and process exception for ctrl-c
|
|
|
|
|
//
|
|
|
|
|
Return = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-03 02:41:42 +02:00
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
2010-04-22 00:08:28 +02:00
|
|
|
|
@retval TRUE Debug timer interrupt were enabled on entry to this call.
|
|
|
|
|
@retval FALSE Debug timer interrupt were disabled on entry to this call.
|
2010-04-03 02:41:42 +02:00
|
|
|
|
|
|
|
|
|
**/
|
|
|
|
|
BOOLEAN
|
|
|
|
|
EFIAPI
|
|
|
|
|
SaveAndSetDebugTimerInterrupt (
|
|
|
|
|
IN BOOLEAN EnableStatus
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
BOOLEAN FiqEnabled;
|
|
|
|
|
|
|
|
|
|
FiqEnabled = ArmGetFiqState ();
|
|
|
|
|
|
|
|
|
|
if (EnableStatus) {
|
2010-04-22 00:08:28 +02:00
|
|
|
|
DebugAgentTimerSetPeriod (PcdGet32 (PcdGdbTimerPeriodMilliseconds));
|
2010-04-03 02:41:42 +02:00
|
|
|
|
ArmEnableFiq ();
|
|
|
|
|
} else {
|
|
|
|
|
DebugAgentTimerSetPeriod (0);
|
|
|
|
|
ArmDisableFiq ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FiqEnabled;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-22 00:08:28 +02:00
|
|
|
|
|
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
VOID
|
|
|
|
|
GdbFPutString (
|
|
|
|
|
IN CHAR8 *String
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
Initialize debug agent.
|
|
|
|
|
|
2010-07-23 17:25:32 +02:00
|
|
|
|
This function is used to set up debug environment to support source level debugging.
|
|
|
|
|
If certain Debug Agent Library instance has to save some private data in the stack,
|
|
|
|
|
this function must work on the mode that doesn't return to the caller, then
|
|
|
|
|
the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one
|
|
|
|
|
function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is
|
|
|
|
|
responsible to invoke the passing-in function at the end of InitializeDebugAgent().
|
2010-04-03 02:41:42 +02:00
|
|
|
|
|
2010-07-23 17:25:32 +02:00
|
|
|
|
If the parameter Function is not NULL, Debug Agent Libary instance will invoke it by
|
|
|
|
|
passing in the Context to be its parameter.
|
|
|
|
|
|
|
|
|
|
If Function() is NULL, Debug Agent Library instance will return after setup debug
|
|
|
|
|
environment.
|
|
|
|
|
|
|
|
|
|
@param[in] InitFlag Init flag is used to decide the initialize process.
|
|
|
|
|
@param[in] Context Context needed according to InitFlag; it was optional.
|
|
|
|
|
@param[in] Function Continue function called by debug agent library; it was
|
|
|
|
|
optional.
|
2010-04-03 02:41:42 +02:00
|
|
|
|
|
|
|
|
|
**/
|
|
|
|
|
VOID
|
|
|
|
|
EFIAPI
|
|
|
|
|
InitializeDebugAgent (
|
|
|
|
|
IN UINT32 InitFlag,
|
2010-07-23 17:25:32 +02:00
|
|
|
|
IN VOID *Context, OPTIONAL
|
|
|
|
|
IN DEBUG_AGENT_CONTINUE Function OPTIONAL
|
2010-04-03 02:41:42 +02:00
|
|
|
|
)
|
2014-08-19 15:29:52 +02:00
|
|
|
|
{
|
2010-04-03 02:41:42 +02:00
|
|
|
|
UINTN Offset;
|
|
|
|
|
UINTN Length;
|
|
|
|
|
BOOLEAN IrqEnabled;
|
2016-03-24 21:30:06 +01:00
|
|
|
|
UINT64 *VectorBase;
|
2010-04-03 02:41:42 +02:00
|
|
|
|
|
2013-01-25 12:28:06 +01:00
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
//
|
|
|
|
|
// Disable interrupts
|
|
|
|
|
//
|
|
|
|
|
IrqEnabled = ArmGetInterruptState ();
|
|
|
|
|
ArmDisableInterrupts ();
|
|
|
|
|
ArmDisableFiq ();
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Copy an implementation of the ARM exception vectors to PcdCpuVectorBaseAddress.
|
|
|
|
|
//
|
|
|
|
|
Length = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Reserve space for the exception handlers
|
|
|
|
|
//
|
2016-03-24 21:30:06 +01:00
|
|
|
|
VectorBase = (UINT64 *)(UINTN)PcdGet64 (PcdCpuVectorBaseAddress);
|
2010-04-03 02:41:42 +02:00
|
|
|
|
|
|
|
|
|
|
2014-08-19 15:29:52 +02:00
|
|
|
|
// Copy our assembly code into the page that contains the exception vectors.
|
2010-04-03 02:41:42 +02:00
|
|
|
|
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
|
2016-03-24 21:30:06 +01:00
|
|
|
|
InvalidateInstructionCacheRange ((VOID *)PcdGet64(PcdCpuVectorBaseAddress), Length);
|
2010-04-03 02:41:42 +02:00
|
|
|
|
|
2010-04-22 00:08:28 +02:00
|
|
|
|
// setup a timer so gdb can break in via ctrl-c
|
2010-04-03 02:41:42 +02:00
|
|
|
|
DebugAgentTimerIntialize ();
|
|
|
|
|
|
|
|
|
|
if (IrqEnabled) {
|
|
|
|
|
ArmEnableInterrupts ();
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-23 17:25:32 +02:00
|
|
|
|
if (Function != NULL) {
|
|
|
|
|
Function (Context);
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-03 02:41:42 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|