mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-10-31 03:03:46 +01:00 
			
		
		
		
	Trailing spaces create issue/warning when generating/applying patches. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ronald Cron <ronald.cron@arm.com> Reviewed-By: Olivier Martin <olivier.martin@arm.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15833 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			676 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			676 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /** @file
 | ||
|   Processor specific parts of the GDB stub
 | ||
| 
 | ||
|   Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
 | ||
| 
 | ||
|   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/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;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /**
 | ||
|  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);
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /**
 | ||
|  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 ();
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| /**
 | ||
|  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';
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  FIQ state is only changed by FIQ exception. We don't want to take FIQ
 | ||
|  ticks in the GDB stub. The stub disables FIQ on entry, but this is the
 | ||
|  third instruction that executes in the execption handler. Thus we have
 | ||
|  a crack we need to test for.
 | ||
| 
 | ||
|  @param PC     PC of execption
 | ||
| 
 | ||
|  @return  TRUE  We are in the GDB stub exception preamble
 | ||
|  @return  FALSE We are not in GDB stub code
 | ||
|  **/
 | ||
| BOOLEAN
 | ||
| InFiqCrack (
 | ||
|   IN UINT32 PC
 | ||
|   )
 | ||
| {
 | ||
|   UINT32 VectorBase = PcdGet32 (PcdCpuVectorBaseAddress);
 | ||
|   UINT32 Length     = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart;
 | ||
| 
 | ||
|   if ((PC >= VectorBase) && (PC <= (VectorBase + Length))) {
 | ||
|     return TRUE;
 | ||
|   }
 | ||
| 
 | ||
|   return FALSE;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| /**
 | ||
|  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
 | ||
|   )
 | ||
| {
 | ||
|   CHAR8     Char;
 | ||
|   BOOLEAN   Return = TRUE;
 | ||
| 
 | ||
|   if (ExceptionType != EXCEPT_ARM_FIQ) {
 | ||
|     // Skip it as it is not related to ctrl-c
 | ||
|     return FALSE;
 | ||
|   }
 | ||
| 
 | ||
|   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;
 | ||
|   }
 | ||
| 
 | ||
|   while (TRUE) {
 | ||
|     if (!GdbIsCharAvailable ()) {
 | ||
|       //
 | ||
|       // No characters are pending so exit the loop
 | ||
|       //
 | ||
|       Return = TRUE;
 | ||
|       break;
 | ||
|     }
 | ||
| 
 | ||
|     Char = GdbGetChar ();
 | ||
|     if (Char == 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.
 | ||
| 
 | ||
|   @retval TRUE  Debug timer interrupt were enabled on entry to this call.
 | ||
|   @retval FALSE Debug timer interrupt were disabled on entry to this call.
 | ||
| 
 | ||
| **/
 | ||
| BOOLEAN
 | ||
| EFIAPI
 | ||
| SaveAndSetDebugTimerInterrupt (
 | ||
|   IN BOOLEAN                EnableStatus
 | ||
|   )
 | ||
| {
 | ||
|   BOOLEAN              FiqEnabled;
 | ||
| 
 | ||
|   FiqEnabled = ArmGetFiqState ();
 | ||
| 
 | ||
|   if (EnableStatus) {
 | ||
|     DebugAgentTimerSetPeriod (PcdGet32 (PcdGdbTimerPeriodMilliseconds));
 | ||
|     ArmEnableFiq ();
 | ||
|   } else {
 | ||
|     DebugAgentTimerSetPeriod (0);
 | ||
|     ArmDisableFiq ();
 | ||
|   }
 | ||
| 
 | ||
|   return FiqEnabled;
 | ||
| }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| VOID
 | ||
| GdbFPutString (
 | ||
|   IN CHAR8  *String
 | ||
|   );
 | ||
| 
 | ||
| /**
 | ||
|   Initialize debug agent.
 | ||
| 
 | ||
|   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().
 | ||
| 
 | ||
|   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.
 | ||
| 
 | ||
| **/
 | ||
| VOID
 | ||
| EFIAPI
 | ||
| InitializeDebugAgent (
 | ||
|   IN UINT32                InitFlag,
 | ||
|   IN VOID                  *Context, OPTIONAL
 | ||
|   IN DEBUG_AGENT_CONTINUE  Function  OPTIONAL
 | ||
|   )
 | ||
| {
 | ||
|   UINTN                Offset;
 | ||
|   UINTN                Length;
 | ||
|   BOOLEAN              IrqEnabled;
 | ||
|   UINT32               *VectorBase;
 | ||
| 
 | ||
| 
 | ||
|   //
 | ||
|   // 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
 | ||
|   //
 | ||
|   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);
 | ||
| 
 | ||
|   // setup a timer so gdb can break in via ctrl-c
 | ||
|   DebugAgentTimerIntialize ();
 | ||
| 
 | ||
|   if (IrqEnabled) {
 | ||
|     ArmEnableInterrupts ();
 | ||
|   }
 | ||
| 
 | ||
|   if (Function != NULL) {
 | ||
|     Function (Context);
 | ||
|   }
 | ||
| 
 | ||
|   return;
 | ||
| }
 | ||
| 
 |