Adding support for BeagleBoard.
ArmPkg - Supoprt for ARM specific things that can change as the architecture changes. Plus semihosting JTAG drivers. EmbeddedPkg - Generic support for an embeddded platform. Including a light weight command line shell. BeagleBoardPkg - Platform specifics for BeagleBoard. SD Card works, but USB has issues. Looks like a bug in the open source USB stack (Our internal stack works fine). git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9518 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
717
EmbeddedPkg/GdbStub/Arm/Processor.c
Normal file
717
EmbeddedPkg/GdbStub/Arm/Processor.c
Normal file
@@ -0,0 +1,717 @@
|
||||
/** @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.
|
||||
|
||||
**/
|
||||
/** @file
|
||||
|
||||
Copyright (c) 2008, Apple, Inc
|
||||
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 <GdbStubInternal.h>
|
||||
#include <Library/CacheMaintenanceLib.h>
|
||||
#include <Library/PrintLib.h>
|
||||
|
||||
//
|
||||
// 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_SIGEMT },
|
||||
// { EXCEPT_ARM_RESERVED, GDB_SIGILL }
|
||||
};
|
||||
|
||||
// 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
|
||||
0x00000FFF,
|
||||
0x00000FFF,
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Return the number of entries in the gRegisters[]
|
||||
|
||||
@retval UINTN, the number of entries (registers) in the gRegisters[] array.
|
||||
**/
|
||||
UINTN
|
||||
MaxRegisterCount (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
return sizeof (gRegisterOffsets)/sizeof (UINTN);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
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 >= MaxRegisterCount()) {
|
||||
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;
|
||||
CHAR8 *OutBuffer;
|
||||
CHAR8 *OutBufPtr;
|
||||
UINTN RegisterCount = MaxRegisterCount();
|
||||
|
||||
// It is not safe to allocate pool here....
|
||||
OutBuffer = AllocatePool((RegisterCount * 8) + 1); // 8 bytes per register in string format plus a null to terminate
|
||||
OutBufPtr = OutBuffer;
|
||||
for (Index = 0; Index < RegisterCount; Index++) {
|
||||
OutBufPtr = BasicReadRegister (SystemContext, Index, OutBufPtr);
|
||||
}
|
||||
|
||||
*OutBufPtr = '\0';
|
||||
SendPacket(OutBuffer);
|
||||
FreePool(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 >= MaxRegisterCount()) {
|
||||
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 = MaxRegisterCount();
|
||||
|
||||
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 ();
|
||||
}
|
||||
|
||||
// What about Thumb?
|
||||
// Use SWI 0xdbdbdb as the debug instruction
|
||||
#define GDB_ARM_BKPT 0xefdbdbdb
|
||||
|
||||
BOOLEAN mSingleStepActive = FALSE;
|
||||
UINT32 mSingleStepPC;
|
||||
UINT32 mSingleStepData;
|
||||
UINTN mSingleStepDataSize;
|
||||
|
||||
typedef struct {
|
||||
LIST_ENTRY Link;
|
||||
UINT64 Signature;
|
||||
UINT32 Address;
|
||||
UINT32 Instruction;
|
||||
} ARM_SOFTWARE_BREAKPOINT;
|
||||
|
||||
#define ARM_SOFTWARE_BREAKPOINT_SIGNATURE SIGNATURE_64('A', 'R', 'M', 'B', 'R', 'K', 'P', 'T')
|
||||
#define ARM_SOFTWARE_BREAKPOINT_FROM_LINK(a) CR(a, ARM_SOFTWARE_BREAKPOINT, Link, ARM_SOFTWARE_BREAKPOINT_SIGNATURE)
|
||||
|
||||
LIST_ENTRY BreakpointList;
|
||||
|
||||
/**
|
||||
Insert Single Step in the SystemContext
|
||||
|
||||
@param SystemContext Register content at time of the exception
|
||||
**/
|
||||
VOID
|
||||
AddSingleStep (
|
||||
IN EFI_SYSTEM_CONTEXT SystemContext
|
||||
)
|
||||
{
|
||||
if (mSingleStepActive) {
|
||||
// Currently don't support nesting
|
||||
return;
|
||||
}
|
||||
mSingleStepActive = TRUE;
|
||||
|
||||
mSingleStepPC = SystemContext.SystemContextArm->PC;
|
||||
|
||||
mSingleStepDataSize = sizeof (UINT32);
|
||||
mSingleStepData = (*(UINT32 *)mSingleStepPC);
|
||||
*(UINT32 *)mSingleStepPC = GDB_ARM_BKPT;
|
||||
if (*(UINT32 *)mSingleStepPC != GDB_ARM_BKPT) {
|
||||
// For some reason our breakpoint did not take
|
||||
mSingleStepActive = FALSE;
|
||||
}
|
||||
|
||||
InvalidateInstructionCacheRange((VOID *)mSingleStepPC, mSingleStepDataSize);
|
||||
//DEBUG((EFI_D_ERROR, "AddSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, mSingleStepData, *(UINT32 *)mSingleStepPC));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Remove Single Step in the SystemContext
|
||||
|
||||
@param SystemContext Register content at time of the exception
|
||||
**/
|
||||
VOID
|
||||
RemoveSingleStep (
|
||||
IN EFI_SYSTEM_CONTEXT SystemContext
|
||||
)
|
||||
{
|
||||
if (!mSingleStepActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mSingleStepDataSize == sizeof (UINT16)) {
|
||||
*(UINT16 *)mSingleStepPC = (UINT16)mSingleStepData;
|
||||
} else {
|
||||
//DEBUG((EFI_D_ERROR, "RemoveSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, *(UINT32 *)mSingleStepPC, mSingleStepData));
|
||||
*(UINT32 *)mSingleStepPC = mSingleStepData;
|
||||
}
|
||||
InvalidateInstructionCacheRange((VOID *)mSingleStepPC, mSingleStepDataSize);
|
||||
mSingleStepActive = FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** ‘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();
|
||||
}
|
||||
|
||||
UINTN
|
||||
GetBreakpointDataAddress (
|
||||
IN EFI_SYSTEM_CONTEXT SystemContext,
|
||||
IN UINTN BreakpointNumber
|
||||
)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
UINTN
|
||||
GetBreakpointDetected (
|
||||
IN EFI_SYSTEM_CONTEXT SystemContext
|
||||
)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
BREAK_TYPE
|
||||
GetBreakpointType (
|
||||
IN EFI_SYSTEM_CONTEXT SystemContext,
|
||||
IN UINTN BreakpointNumber
|
||||
)
|
||||
{
|
||||
return NotSupported;
|
||||
}
|
||||
|
||||
ARM_SOFTWARE_BREAKPOINT *
|
||||
SearchBreakpointList (
|
||||
IN UINT32 Address
|
||||
)
|
||||
{
|
||||
LIST_ENTRY *Current;
|
||||
ARM_SOFTWARE_BREAKPOINT *Breakpoint;
|
||||
|
||||
Current = GetFirstNode(&BreakpointList);
|
||||
while (!IsNull(&BreakpointList, Current)) {
|
||||
Breakpoint = ARM_SOFTWARE_BREAKPOINT_FROM_LINK(Current);
|
||||
|
||||
if (Address == Breakpoint->Address) {
|
||||
return Breakpoint;
|
||||
}
|
||||
|
||||
Current = GetNextNode(&BreakpointList, Current);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VOID
|
||||
SetBreakpoint (
|
||||
IN UINT32 Address
|
||||
)
|
||||
{
|
||||
ARM_SOFTWARE_BREAKPOINT *Breakpoint;
|
||||
|
||||
Breakpoint = SearchBreakpointList(Address);
|
||||
|
||||
if (Breakpoint != NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// create and fill breakpoint structure
|
||||
Breakpoint = AllocatePool(sizeof(ARM_SOFTWARE_BREAKPOINT));
|
||||
|
||||
Breakpoint->Signature = ARM_SOFTWARE_BREAKPOINT_SIGNATURE;
|
||||
Breakpoint->Address = Address;
|
||||
Breakpoint->Instruction = *(UINT32 *)Address;
|
||||
|
||||
// Add it to the list
|
||||
InsertTailList(&BreakpointList, &Breakpoint->Link);
|
||||
|
||||
// Insert the software breakpoint
|
||||
*(UINT32 *)Address = GDB_ARM_BKPT;
|
||||
InvalidateInstructionCacheRange((VOID *)Address, 4);
|
||||
|
||||
//DEBUG((EFI_D_ERROR, "SetBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, Breakpoint->Instruction, *(UINT32 *)Address));
|
||||
}
|
||||
|
||||
VOID
|
||||
ClearBreakpoint (
|
||||
IN UINT32 Address
|
||||
)
|
||||
{
|
||||
ARM_SOFTWARE_BREAKPOINT *Breakpoint;
|
||||
|
||||
Breakpoint = SearchBreakpointList(Address);
|
||||
|
||||
if (Breakpoint == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add it to the list
|
||||
RemoveEntryList(&Breakpoint->Link);
|
||||
|
||||
// Restore the original instruction
|
||||
*(UINT32 *)Address = Breakpoint->Instruction;
|
||||
InvalidateInstructionCacheRange((VOID *)Address, 4);
|
||||
|
||||
//DEBUG((EFI_D_ERROR, "ClearBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, GDB_ARM_BKPT, *(UINT32 *)Address));
|
||||
|
||||
FreePool(Breakpoint);
|
||||
}
|
||||
|
||||
VOID
|
||||
EFIAPI
|
||||
InsertBreakPoint (
|
||||
IN EFI_SYSTEM_CONTEXT SystemContext,
|
||||
IN CHAR8 *PacketData
|
||||
)
|
||||
{
|
||||
UINTN Type;
|
||||
UINTN Address;
|
||||
UINTN Length;
|
||||
UINTN ErrorCode;
|
||||
|
||||
ErrorCode = ParseBreakpointPacket(PacketData, &Type, &Address, &Length);
|
||||
if (ErrorCode > 0) {
|
||||
SendError ((UINT8)ErrorCode);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (Type) {
|
||||
case 0: //Software breakpoint
|
||||
break;
|
||||
|
||||
default :
|
||||
DEBUG((EFI_D_ERROR, "Insert breakpoint default: %x\n", Type));
|
||||
SendError (GDB_EINVALIDBRKPOINTTYPE);
|
||||
return;
|
||||
}
|
||||
|
||||
SetBreakpoint(Address);
|
||||
|
||||
SendSuccess ();
|
||||
}
|
||||
|
||||
VOID
|
||||
EFIAPI
|
||||
RemoveBreakPoint (
|
||||
IN EFI_SYSTEM_CONTEXT SystemContext,
|
||||
IN CHAR8 *PacketData
|
||||
)
|
||||
{
|
||||
UINTN Type;
|
||||
UINTN Address;
|
||||
UINTN Length;
|
||||
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
|
||||
break;
|
||||
|
||||
default:
|
||||
SendError (GDB_EINVALIDBRKPOINTTYPE);
|
||||
return;
|
||||
}
|
||||
|
||||
ClearBreakpoint(Address);
|
||||
|
||||
SendSuccess ();
|
||||
}
|
||||
|
||||
VOID
|
||||
InitializeProcessor (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
// Initialize breakpoint list
|
||||
InitializeListHead(&BreakpointList);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
ValidateAddress (
|
||||
IN VOID *Address
|
||||
)
|
||||
{
|
||||
if ((UINT32)Address < 0x80000000) {
|
||||
return FALSE;
|
||||
} else {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
ValidateException (
|
||||
IN EFI_EXCEPTION_TYPE ExceptionType,
|
||||
IN OUT EFI_SYSTEM_CONTEXT SystemContext
|
||||
)
|
||||
{
|
||||
UINT32 ExceptionAddress;
|
||||
UINT32 Instruction;
|
||||
|
||||
// Is it a debugger SWI?
|
||||
ExceptionAddress = SystemContext.SystemContextArm->PC -= 4;
|
||||
Instruction = *(UINT32 *)ExceptionAddress;
|
||||
if (Instruction != GDB_ARM_BKPT) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Special for SWI-based exception handling. SWI sets up the context
|
||||
// to return to the instruction following the SWI instruction - NOT what we want
|
||||
// for a debugger!
|
||||
SystemContext.SystemContextArm->PC = ExceptionAddress;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
Reference in New Issue
Block a user