REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the EmbeddedPkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Andrew Fish <afish@apple.com>
		
			
				
	
	
		
			946 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			946 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | ||
|   Processor specific parts of the GDB stub
 | ||
| 
 | ||
|   Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
 | ||
| 
 | ||
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | ||
| 
 | ||
| **/
 | ||
| 
 | ||
| #include <GdbStubInternal.h>
 | ||
| 
 | ||
| //
 | ||
| // Array of exception types that need to be hooked by the debugger
 | ||
| //
 | ||
| EFI_EXCEPTION_TYPE_ENTRY  gExceptionType[] = {
 | ||
|   { EXCEPT_X64_DIVIDE_ERROR,    GDB_SIGFPE  },
 | ||
|   { EXCEPT_X64_DEBUG,           GDB_SIGTRAP },
 | ||
|   { EXCEPT_X64_NMI,             GDB_SIGEMT  },
 | ||
|   { EXCEPT_X64_BREAKPOINT,      GDB_SIGTRAP },
 | ||
|   { EXCEPT_X64_OVERFLOW,        GDB_SIGSEGV },
 | ||
|   { EXCEPT_X64_BOUND,           GDB_SIGSEGV },
 | ||
|   { EXCEPT_X64_INVALID_OPCODE,  GDB_SIGILL  },
 | ||
|   { EXCEPT_X64_DOUBLE_FAULT,    GDB_SIGEMT  },
 | ||
|   { EXCEPT_X64_STACK_FAULT,     GDB_SIGSEGV },
 | ||
|   { EXCEPT_X64_GP_FAULT,        GDB_SIGSEGV },
 | ||
|   { EXCEPT_X64_PAGE_FAULT,      GDB_SIGSEGV },
 | ||
|   { EXCEPT_X64_FP_ERROR,        GDB_SIGEMT  },
 | ||
|   { EXCEPT_X64_ALIGNMENT_CHECK, GDB_SIGEMT  },
 | ||
|   { EXCEPT_X64_MACHINE_CHECK,   GDB_SIGEMT  }
 | ||
| };
 | ||
| 
 | ||
| // The offsets of registers SystemContextX64.
 | ||
| // The fields in the array are in the gdb ordering.
 | ||
| // HAVE TO DOUBLE-CHECK THE ORDER of the 24 regs
 | ||
| //
 | ||
| UINTN  gRegisterOffsets[] = {
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rax),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rcx),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rdx),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rbx),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rsp),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rbp),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rsi),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rdi),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rip),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rflags),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Cs),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Ss),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Ds),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Es),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Fs),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Gs),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R8),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R9),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R10),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R11),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R12),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R13),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R14),
 | ||
|   OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R15)
 | ||
| };
 | ||
| 
 | ||
| /**
 | ||
|  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
 | ||
|   )
 | ||
| {
 | ||
|   return (BOOLEAN)(Isa == IsaX64);
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  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 X64 member
 | ||
|  @param   SystemContext     Register content at time of the exception
 | ||
|  @param   RegNumber       The register to which we want to find a pointer
 | ||
|  @retval  the pointer to the RegNumber-th pointer
 | ||
|  **/
 | ||
| UINTN *
 | ||
| FindPointerToRegister (
 | ||
|   IN  EFI_SYSTEM_CONTEXT  SystemContext,
 | ||
|   IN  UINTN               RegNumber
 | ||
|   )
 | ||
| {
 | ||
|   UINT8  *TempPtr;
 | ||
| 
 | ||
|   TempPtr = ((UINT8 *)SystemContext.SystemContextX64) + gRegisterOffsets[RegNumber];
 | ||
|   return (UINTN *)TempPtr;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
 | ||
|  @param   SystemContext     Register content at time of the exception
 | ||
|  @param   RegNumber       the number of the register that we want to read
 | ||
|  @param   OutBufPtr       pointer to the output buffer's end. the new data will be added from this point on.
 | ||
|  @retval  the pointer to the next character of the output buffer that is available to be written on.
 | ||
|  **/
 | ||
| CHAR8 *
 | ||
| BasicReadRegister (
 | ||
|   IN  EFI_SYSTEM_CONTEXT  SystemContext,
 | ||
|   IN  UINTN               RegNumber,
 | ||
|   IN  CHAR8               *OutBufPtr
 | ||
|   )
 | ||
| {
 | ||
|   UINTN  RegSize;
 | ||
| 
 | ||
|   RegSize = 0;
 | ||
|   while (RegSize < 64) {
 | ||
|     *OutBufPtr++ = mHexToStr[((*FindPointerToRegister (SystemContext, RegNumber) >> (RegSize+4)) & 0xf)];
 | ||
|     *OutBufPtr++ = mHexToStr[((*FindPointerToRegister (SystemContext, RegNumber) >> RegSize) & 0xf)];
 | ||
|     RegSize      = RegSize + 8;
 | ||
|   }
 | ||
| 
 | ||
|   return OutBufPtr;
 | ||
| }
 | ||
| 
 | ||
| /** ‘p n’
 | ||
|  Reads the n-th register's value into an output buffer and sends it as a packet
 | ||
|  @param   SystemContext   Register content at time of the exception
 | ||
|  @param   InBuffer      Pointer to the input buffer received from gdb server
 | ||
|  **/
 | ||
| VOID
 | ||
| ReadNthRegister (
 | ||
|   IN  EFI_SYSTEM_CONTEXT  SystemContext,
 | ||
|   IN  CHAR8               *InBuffer
 | ||
|   )
 | ||
| {
 | ||
|   UINTN  RegNumber;
 | ||
|   CHAR8  OutBuffer[17]; // 1 reg=16 hex chars, and the end '\0' (escape seq)
 | ||
|   CHAR8  *OutBufPtr;    // pointer to the output buffer
 | ||
| 
 | ||
|   RegNumber = AsciiStrHexToUintn (&InBuffer[1]);
 | ||
| 
 | ||
|   if ((RegNumber < 0) || (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  i;
 | ||
|   CHAR8  OutBuffer[385]; // 24 regs, 16 hex chars each, and the end '\0' (escape seq)
 | ||
|   CHAR8  *OutBufPtr;     // pointer to the output buffer
 | ||
| 
 | ||
|   OutBufPtr = OutBuffer;
 | ||
|   for (i = 0; i < MaxRegisterCount (); i++) {
 | ||
|     // there are only 24 registers to read
 | ||
|     OutBufPtr = BasicReadRegister (SystemContext, i, OutBufPtr);
 | ||
|   }
 | ||
| 
 | ||
|   *OutBufPtr = '\0';  // the end of the buffer
 | ||
|   SendPacket (OutBuffer);
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
 | ||
| 
 | ||
|  @param   SystemContext       Register content at time of the exception
 | ||
|  @param   RegNumber         the number of the register that we want to write
 | ||
|  @param   InBufPtr          pointer to the output buffer. the new data will be extracted from the input buffer from this point on.
 | ||
|  @retval  the pointer to the next character of the input buffer that can be used
 | ||
|  **/
 | ||
| CHAR8 *
 | ||
| BasicWriteRegister (
 | ||
|   IN  EFI_SYSTEM_CONTEXT  SystemContext,
 | ||
|   IN  UINTN               RegNumber,
 | ||
|   IN  CHAR8               *InBufPtr
 | ||
|   )
 | ||
| {
 | ||
|   UINTN   RegSize;
 | ||
|   UINTN   TempValue; // the value transferred from a hex char
 | ||
|   UINT64  NewValue;  // the new value of the RegNumber-th Register
 | ||
| 
 | ||
|   NewValue = 0;
 | ||
|   RegSize  = 0;
 | ||
|   while (RegSize < 64) {
 | ||
|     TempValue = HexCharToInt (*InBufPtr++);
 | ||
| 
 | ||
|     if (TempValue < 0) {
 | ||
|       SendError (GDB_EBADMEMDATA);
 | ||
|       return NULL;
 | ||
|     }
 | ||
| 
 | ||
|     NewValue += (TempValue << (RegSize+4));
 | ||
|     TempValue = HexCharToInt (*InBufPtr++);
 | ||
| 
 | ||
|     if (TempValue < 0) {
 | ||
|       SendError (GDB_EBADMEMDATA);
 | ||
|       return NULL;
 | ||
|     }
 | ||
| 
 | ||
|     NewValue += (TempValue << RegSize);
 | ||
|     RegSize   = RegSize + 8;
 | ||
|   }
 | ||
| 
 | ||
|   *(FindPointerToRegister (SystemContext, RegNumber)) = NewValue;
 | ||
|   return InBufPtr;
 | ||
| }
 | ||
| 
 | ||
| /** ‘P n...=r...’
 | ||
|  Writes the new value of n-th register received into the input buffer to the n-th register
 | ||
| 
 | ||
|  @param   SystemContext   Register content at time of the exception
 | ||
|  @param   InBuffer      Pointer to the input buffer received from gdb server
 | ||
|  **/
 | ||
| VOID
 | ||
| EFIAPI
 | ||
| WriteNthRegister (
 | ||
|   IN  EFI_SYSTEM_CONTEXT  SystemContext,
 | ||
|   IN  CHAR8               *InBuffer
 | ||
|   )
 | ||
| {
 | ||
|   UINTN  RegNumber;
 | ||
|   CHAR8  RegNumBuffer[MAX_REG_NUM_BUF_SIZE]; // put the 'n..' part of the message into this array
 | ||
|   CHAR8  *RegNumBufPtr;
 | ||
|   CHAR8  *InBufPtr; // pointer to the input buffer
 | ||
| 
 | ||
|   // find the register number to write
 | ||
|   InBufPtr     = &InBuffer[1];
 | ||
|   RegNumBufPtr = RegNumBuffer;
 | ||
|   while (*InBufPtr != '=') {
 | ||
|     *RegNumBufPtr++ = *InBufPtr++;
 | ||
|   }
 | ||
| 
 | ||
|   *RegNumBufPtr = '\0';
 | ||
|   RegNumber     = AsciiStrHexToUintn (RegNumBuffer);
 | ||
| 
 | ||
|   // check if this is a valid Register Number
 | ||
|   if ((RegNumber < 0) || (RegNumber >= 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
 | ||
| 
 | ||
|   // check to see if the buffer is the right size which is
 | ||
|   // 1 (for 'G') + 16 (for 16 registers) * 8 ( for 8 hex chars each) = 385
 | ||
|   if (AsciiStrLen (InBuffer) != 385) {
 | ||
|     // 24 regs, 16 hex chars each, and the end '\0' (escape seq)
 | ||
|     // Bad message. Message is not the right length
 | ||
|     SendError (GDB_EBADBUFSIZE);
 | ||
|     return;
 | ||
|   }
 | ||
| 
 | ||
|   InBufPtr = &InBuffer[1];
 | ||
| 
 | ||
|   // Read the new values for the registers from the input buffer to an array, NewValueArray.
 | ||
|   // The values in the array are in the gdb ordering
 | ||
|   for (i = 0; i < MaxRegisterCount (); i++) {
 | ||
|     // there are only 16 registers to write
 | ||
|     InBufPtr = BasicWriteRegister (SystemContext, i, InBufPtr);
 | ||
|   }
 | ||
| 
 | ||
|   SendSuccess ();
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
| Insert Single Step in the SystemContext
 | ||
| 
 | ||
| @param SystemContext Register content at time of the exception
 | ||
| **/
 | ||
| VOID
 | ||
| AddSingleStep (
 | ||
|   IN  EFI_SYSTEM_CONTEXT  SystemContext
 | ||
|   )
 | ||
| {
 | ||
|   SystemContext.SystemContextX64->Rflags |= TF_BIT; // Setting the TF bit.
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|  Remove Single Step in the SystemContext
 | ||
| 
 | ||
|  @param SystemContext Register content at time of the exception
 | ||
|  **/
 | ||
| VOID
 | ||
| RemoveSingleStep (
 | ||
|   IN  EFI_SYSTEM_CONTEXT  SystemContext
 | ||
|   )
 | ||
| {
 | ||
|   SystemContext.SystemContextX64->Rflags &= ~TF_BIT;  // clearing the TF bit.
 | ||
| }
 | ||
| 
 | ||
| /** ‘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.SystemContextX64->Rip = 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
 | ||
|   )
 | ||
| {
 | ||
|   if (PacketData[1] != '\0') {
 | ||
|     SystemContext.SystemContextX64->Rip = AsciiStrHexToUintn (&PacketData[1]);
 | ||
|   }
 | ||
| 
 | ||
|   AddSingleStep (SystemContext);
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|   Returns breakpoint data address from DR0-DR3 based on the input breakpoint
 | ||
|   number
 | ||
| 
 | ||
|   @param  SystemContext      Register content at time of the exception
 | ||
|   @param  BreakpointNumber   Breakpoint number
 | ||
| 
 | ||
|   @retval Address            Data address from DR0-DR3 based on the
 | ||
|                              breakpoint number.
 | ||
| 
 | ||
| **/
 | ||
| UINTN
 | ||
| GetBreakpointDataAddress (
 | ||
|   IN  EFI_SYSTEM_CONTEXT  SystemContext,
 | ||
|   IN  UINTN               BreakpointNumber
 | ||
|   )
 | ||
| {
 | ||
|   UINTN  Address;
 | ||
| 
 | ||
|   if (BreakpointNumber == 1) {
 | ||
|     Address = SystemContext.SystemContextIa32->Dr0;
 | ||
|   } else if (BreakpointNumber == 2) {
 | ||
|     Address = SystemContext.SystemContextIa32->Dr1;
 | ||
|   } else if (BreakpointNumber == 3) {
 | ||
|     Address = SystemContext.SystemContextIa32->Dr2;
 | ||
|   } else if (BreakpointNumber == 4) {
 | ||
|     Address = SystemContext.SystemContextIa32->Dr3;
 | ||
|   } else {
 | ||
|     Address = 0;
 | ||
|   }
 | ||
| 
 | ||
|   return Address;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|   Returns currently detected breakpoint value based on the register
 | ||
|   DR6 B0-B3 field.
 | ||
|   If no breakpoint is detected then it returns 0.
 | ||
| 
 | ||
|   @param  SystemContext  Register content at time of the exception
 | ||
| 
 | ||
|   @retval {1-4}          Currently detected breakpoint value
 | ||
|   @retval 0              No breakpoint detected.
 | ||
| 
 | ||
| **/
 | ||
| UINTN
 | ||
| GetBreakpointDetected (
 | ||
|   IN  EFI_SYSTEM_CONTEXT  SystemContext
 | ||
|   )
 | ||
| {
 | ||
|   IA32_DR6  Dr6;
 | ||
|   UINTN     BreakpointNumber;
 | ||
| 
 | ||
|   Dr6.UintN = SystemContext.SystemContextIa32->Dr6;
 | ||
| 
 | ||
|   if (Dr6.Bits.B0 == 1) {
 | ||
|     BreakpointNumber = 1;
 | ||
|   } else if (Dr6.Bits.B1 == 1) {
 | ||
|     BreakpointNumber = 2;
 | ||
|   } else if (Dr6.Bits.B2 == 1) {
 | ||
|     BreakpointNumber = 3;
 | ||
|   } else if (Dr6.Bits.B3 == 1) {
 | ||
|     BreakpointNumber = 4;
 | ||
|   } else {
 | ||
|     BreakpointNumber = 0;  // No breakpoint detected
 | ||
|   }
 | ||
| 
 | ||
|   return BreakpointNumber;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|   Returns Breakpoint type (InstructionExecution, DataWrite, DataRead
 | ||
|   or DataReadWrite) based on the Breakpoint number
 | ||
| 
 | ||
|   @param  SystemContext      Register content at time of the exception
 | ||
|   @param  BreakpointNumber   Breakpoint number
 | ||
| 
 | ||
|   @retval BREAK_TYPE         Breakpoint type value read from register DR7 RWn
 | ||
|                              field. For unknown value, it returns NotSupported.
 | ||
| 
 | ||
| **/
 | ||
| BREAK_TYPE
 | ||
| GetBreakpointType (
 | ||
|   IN  EFI_SYSTEM_CONTEXT  SystemContext,
 | ||
|   IN  UINTN               BreakpointNumber
 | ||
|   )
 | ||
| {
 | ||
|   IA32_DR7    Dr7;
 | ||
|   BREAK_TYPE  Type = NotSupported; // Default is NotSupported type
 | ||
| 
 | ||
|   Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
 | ||
| 
 | ||
|   if (BreakpointNumber == 1) {
 | ||
|     Type = (BREAK_TYPE)Dr7.Bits.RW0;
 | ||
|   } else if (BreakpointNumber == 2) {
 | ||
|     Type = (BREAK_TYPE)Dr7.Bits.RW1;
 | ||
|   } else if (BreakpointNumber == 3) {
 | ||
|     Type = (BREAK_TYPE)Dr7.Bits.RW2;
 | ||
|   } else if (BreakpointNumber == 4) {
 | ||
|     Type = (BREAK_TYPE)Dr7.Bits.RW3;
 | ||
|   }
 | ||
| 
 | ||
|   return Type;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|   Parses Length and returns the length which DR7 LENn field accepts.
 | ||
|   For example: If we receive 1-Byte length then we should return 0.
 | ||
|                Zero gets written to DR7 LENn field.
 | ||
| 
 | ||
|   @param  Length  Breakpoint length in Bytes (1 byte, 2 byte, 4 byte)
 | ||
| 
 | ||
|   @retval Length  Appropriate converted values which DR7 LENn field accepts.
 | ||
| 
 | ||
| **/
 | ||
| UINTN
 | ||
| ConvertLengthData (
 | ||
|   IN     UINTN  Length
 | ||
|   )
 | ||
| {
 | ||
|   if (Length == 1) {
 | ||
|     // 1-Byte length
 | ||
|     return 0;
 | ||
|   } else if (Length == 2) {
 | ||
|     // 2-Byte length
 | ||
|     return 1;
 | ||
|   } else if (Length == 4) {
 | ||
|     // 4-Byte length
 | ||
|     return 3;
 | ||
|   } else {
 | ||
|     // Undefined or 8-byte length
 | ||
|     return 2;
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|   Finds the next free debug register. If all the registers are occupied then
 | ||
|   EFI_OUT_OF_RESOURCES is returned.
 | ||
| 
 | ||
|   @param  SystemContext  Register content at time of the exception
 | ||
|   @param  Register       Register value (0 - 3 for the first free debug register)
 | ||
| 
 | ||
|   @retval EFI_STATUS     Appropriate status value.
 | ||
| 
 | ||
| **/
 | ||
| EFI_STATUS
 | ||
| FindNextFreeDebugRegister (
 | ||
|   IN  EFI_SYSTEM_CONTEXT  SystemContext,
 | ||
|   OUT UINTN               *Register
 | ||
|   )
 | ||
| {
 | ||
|   IA32_DR7  Dr7;
 | ||
| 
 | ||
|   Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
 | ||
| 
 | ||
|   if (Dr7.Bits.G0 == 0) {
 | ||
|     *Register = 0;
 | ||
|   } else if (Dr7.Bits.G1 == 0) {
 | ||
|     *Register = 1;
 | ||
|   } else if (Dr7.Bits.G2 == 0) {
 | ||
|     *Register = 2;
 | ||
|   } else if (Dr7.Bits.G3 == 0) {
 | ||
|     *Register = 3;
 | ||
|   } else {
 | ||
|     return EFI_OUT_OF_RESOURCES;
 | ||
|   }
 | ||
| 
 | ||
|   return EFI_SUCCESS;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|   Enables the debug register. Writes Address value to appropriate DR0-3 register.
 | ||
|   Sets LENn, Gn, RWn bits in DR7 register.
 | ||
| 
 | ||
|   @param  SystemContext   Register content at time of the exception
 | ||
|   @param  Register        Register value (0 - 3)
 | ||
|   @param  Address         Breakpoint address value
 | ||
|   @param  Type            Breakpoint type (Instruction, Data write,
 | ||
|                           Data read or write etc.)
 | ||
| 
 | ||
|   @retval EFI_STATUS      Appropriate status value.
 | ||
| 
 | ||
| **/
 | ||
| EFI_STATUS
 | ||
| EnableDebugRegister (
 | ||
|   IN  EFI_SYSTEM_CONTEXT  SystemContext,
 | ||
|   IN  UINTN               Register,
 | ||
|   IN  UINTN               Address,
 | ||
|   IN  UINTN               Length,
 | ||
|   IN  UINTN               Type
 | ||
|   )
 | ||
| {
 | ||
|   IA32_DR7  Dr7;
 | ||
| 
 | ||
|   // Convert length data
 | ||
|   Length = ConvertLengthData (Length);
 | ||
| 
 | ||
|   // For Instruction execution, length should be 0
 | ||
|   // (Ref. Intel reference manual 18.2.4)
 | ||
|   if ((Type == 0) && (Length != 0)) {
 | ||
|     return EFI_INVALID_PARAMETER;
 | ||
|   }
 | ||
| 
 | ||
|   // Hardware doesn't support ReadWatch (z3 packet) type. GDB can handle
 | ||
|   // software breakpoint. We should send empty packet in both these cases.
 | ||
|   if ((Type == (BREAK_TYPE)DataRead) ||
 | ||
|       (Type == (BREAK_TYPE)SoftwareBreakpoint))
 | ||
|   {
 | ||
|     return EFI_UNSUPPORTED;
 | ||
|   }
 | ||
| 
 | ||
|   // Read DR7 so appropriate Gn, RWn and LENn bits can be modified.
 | ||
|   Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
 | ||
| 
 | ||
|   if (Register == 0) {
 | ||
|     SystemContext.SystemContextIa32->Dr0 = Address;
 | ||
|     Dr7.Bits.G0                          = 1;
 | ||
|     Dr7.Bits.RW0                         = Type;
 | ||
|     Dr7.Bits.LEN0                        = Length;
 | ||
|   } else if (Register == 1) {
 | ||
|     SystemContext.SystemContextIa32->Dr1 = Address;
 | ||
|     Dr7.Bits.G1                          = 1;
 | ||
|     Dr7.Bits.RW1                         = Type;
 | ||
|     Dr7.Bits.LEN1                        = Length;
 | ||
|   } else if (Register == 2) {
 | ||
|     SystemContext.SystemContextIa32->Dr2 = Address;
 | ||
|     Dr7.Bits.G2                          = 1;
 | ||
|     Dr7.Bits.RW2                         = Type;
 | ||
|     Dr7.Bits.LEN2                        = Length;
 | ||
|   } else if (Register == 3) {
 | ||
|     SystemContext.SystemContextIa32->Dr3 = Address;
 | ||
|     Dr7.Bits.G3                          = 1;
 | ||
|     Dr7.Bits.RW3                         = Type;
 | ||
|     Dr7.Bits.LEN3                        = Length;
 | ||
|   } else {
 | ||
|     return EFI_INVALID_PARAMETER;
 | ||
|   }
 | ||
| 
 | ||
|   // Update Dr7 with appropriate Gn, RWn and LENn bits
 | ||
|   SystemContext.SystemContextIa32->Dr7 = Dr7.UintN;
 | ||
| 
 | ||
|   return EFI_SUCCESS;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|   Returns register number 0 - 3 for the matching debug register.
 | ||
|   This function compares incoming Address, Type, Length and
 | ||
|   if there is a match then it returns the appropriate register number.
 | ||
|   In case of mismatch, function returns EFI_NOT_FOUND message.
 | ||
| 
 | ||
|   @param  SystemContext  Register content at time of the exception
 | ||
|   @param  Address        Breakpoint address value
 | ||
|   @param  Length         Breakpoint length value
 | ||
|   @param  Type           Breakpoint type (Instruction, Data write, Data read
 | ||
|                          or write etc.)
 | ||
|   @param  Register       Register value to be returned
 | ||
| 
 | ||
|   @retval EFI_STATUS     Appropriate status value.
 | ||
| 
 | ||
| **/
 | ||
| EFI_STATUS
 | ||
| FindMatchingDebugRegister (
 | ||
|   IN  EFI_SYSTEM_CONTEXT  SystemContext,
 | ||
|   IN  UINTN               Address,
 | ||
|   IN  UINTN               Length,
 | ||
|   IN  UINTN               Type,
 | ||
|   OUT UINTN               *Register
 | ||
|   )
 | ||
| {
 | ||
|   IA32_DR7  Dr7;
 | ||
| 
 | ||
|   // Hardware doesn't support ReadWatch (z3 packet) type. GDB can handle
 | ||
|   // software breakpoint. We should send empty packet in both these cases.
 | ||
|   if ((Type == (BREAK_TYPE)DataRead) ||
 | ||
|       (Type == (BREAK_TYPE)SoftwareBreakpoint))
 | ||
|   {
 | ||
|     return EFI_UNSUPPORTED;
 | ||
|   }
 | ||
| 
 | ||
|   // Convert length data
 | ||
|   Length = ConvertLengthData (Length);
 | ||
| 
 | ||
|   Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
 | ||
| 
 | ||
|   if ((Dr7.Bits.G0 == 1) &&
 | ||
|       (Dr7.Bits.LEN0 == Length) &&
 | ||
|       (Dr7.Bits.RW0 == Type) &&
 | ||
|       (Address == SystemContext.SystemContextIa32->Dr0))
 | ||
|   {
 | ||
|     *Register = 0;
 | ||
|   } else if ((Dr7.Bits.G1 == 1) &&
 | ||
|              (Dr7.Bits.LEN1 == Length) &&
 | ||
|              (Dr7.Bits.RW1 == Type) &&
 | ||
|              (Address == SystemContext.SystemContextIa32->Dr1))
 | ||
|   {
 | ||
|     *Register = 1;
 | ||
|   } else if ((Dr7.Bits.G2 == 1) &&
 | ||
|              (Dr7.Bits.LEN2 == Length) &&
 | ||
|              (Dr7.Bits.RW2 == Type) &&
 | ||
|              (Address == SystemContext.SystemContextIa32->Dr2))
 | ||
|   {
 | ||
|     *Register = 2;
 | ||
|   } else if ((Dr7.Bits.G3 == 1) &&
 | ||
|              (Dr7.Bits.LEN3 == Length) &&
 | ||
|              (Dr7.Bits.RW3 == Type) &&
 | ||
|              (Address == SystemContext.SystemContextIa32->Dr3))
 | ||
|   {
 | ||
|     *Register = 3;
 | ||
|   } else {
 | ||
|     Print ((CHAR16 *)L"No match found..\n");
 | ||
|     return EFI_NOT_FOUND;
 | ||
|   }
 | ||
| 
 | ||
|   return EFI_SUCCESS;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|   Disables the particular debug register.
 | ||
| 
 | ||
|   @param  SystemContext   Register content at time of the exception
 | ||
|   @param  Register        Register to be disabled
 | ||
| 
 | ||
|   @retval EFI_STATUS      Appropriate status value.
 | ||
| 
 | ||
| **/
 | ||
| EFI_STATUS
 | ||
| DisableDebugRegister (
 | ||
|   IN  EFI_SYSTEM_CONTEXT  SystemContext,
 | ||
|   IN  UINTN               Register
 | ||
|   )
 | ||
| {
 | ||
|   IA32_DR7  Dr7;
 | ||
|   UINTN     Address = 0;
 | ||
| 
 | ||
|   // Read DR7 register so appropriate Gn, RWn and LENn bits can be turned off.
 | ||
|   Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
 | ||
| 
 | ||
|   if (Register == 0) {
 | ||
|     SystemContext.SystemContextIa32->Dr0 = Address;
 | ||
|     Dr7.Bits.G0                          = 0;
 | ||
|     Dr7.Bits.RW0                         = 0;
 | ||
|     Dr7.Bits.LEN0                        = 0;
 | ||
|   } else if (Register == 1) {
 | ||
|     SystemContext.SystemContextIa32->Dr1 = Address;
 | ||
|     Dr7.Bits.G1                          = 0;
 | ||
|     Dr7.Bits.RW1                         = 0;
 | ||
|     Dr7.Bits.LEN1                        = 0;
 | ||
|   } else if (Register == 2) {
 | ||
|     SystemContext.SystemContextIa32->Dr2 = Address;
 | ||
|     Dr7.Bits.G2                          = 0;
 | ||
|     Dr7.Bits.RW2                         = 0;
 | ||
|     Dr7.Bits.LEN2                        = 0;
 | ||
|   } else if (Register == 3) {
 | ||
|     SystemContext.SystemContextIa32->Dr3 = Address;
 | ||
|     Dr7.Bits.G3                          = 0;
 | ||
|     Dr7.Bits.RW3                         = 0;
 | ||
|     Dr7.Bits.LEN3                        = 0;
 | ||
|   } else {
 | ||
|     return EFI_INVALID_PARAMETER;
 | ||
|   }
 | ||
| 
 | ||
|   // Update DR7 register so appropriate Gn, RWn and LENn bits can be turned off.
 | ||
|   SystemContext.SystemContextIa32->Dr7 = Dr7.UintN;
 | ||
| 
 | ||
|   return EFI_SUCCESS;
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|   ‘Z1, [addr], [length]’
 | ||
|   ‘Z2, [addr], [length]’
 | ||
|   ‘Z3, [addr], [length]’
 | ||
|   ‘Z4, [addr], [length]’
 | ||
| 
 | ||
|   Insert hardware breakpoint/watchpoint at address addr of size length
 | ||
| 
 | ||
|   @param SystemContext  Register content at time of the exception
 | ||
|   @param *PacketData    Pointer to the Payload data for the packet
 | ||
| 
 | ||
| **/
 | ||
| VOID
 | ||
| EFIAPI
 | ||
| InsertBreakPoint (
 | ||
|   IN  EFI_SYSTEM_CONTEXT  SystemContext,
 | ||
|   IN  CHAR8               *PacketData
 | ||
|   )
 | ||
| {
 | ||
|   UINTN       Type;
 | ||
|   UINTN       Address;
 | ||
|   UINTN       Length;
 | ||
|   UINTN       Register;
 | ||
|   EFI_STATUS  Status;
 | ||
|   BREAK_TYPE  BreakType = NotSupported;
 | ||
|   UINTN       ErrorCode;
 | ||
| 
 | ||
|   ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);
 | ||
|   if (ErrorCode > 0) {
 | ||
|     SendError ((UINT8)ErrorCode);
 | ||
|     return;
 | ||
|   }
 | ||
| 
 | ||
|   switch (Type) {
 | ||
|     case 0:      // Software breakpoint
 | ||
|       BreakType = SoftwareBreakpoint;
 | ||
|       break;
 | ||
| 
 | ||
|     case 1:      // Hardware breakpoint
 | ||
|       BreakType = InstructionExecution;
 | ||
|       break;
 | ||
| 
 | ||
|     case 2:      // Write watchpoint
 | ||
|       BreakType = DataWrite;
 | ||
|       break;
 | ||
| 
 | ||
|     case 3:      // Read watchpoint
 | ||
|       BreakType = DataRead;
 | ||
|       break;
 | ||
| 
 | ||
|     case 4:      // Access watchpoint
 | ||
|       BreakType = DataReadWrite;
 | ||
|       break;
 | ||
| 
 | ||
|     default:
 | ||
|       Print ((CHAR16 *)L"Insert breakpoint default: %x\n", Type);
 | ||
|       SendError (GDB_EINVALIDBRKPOINTTYPE);
 | ||
|       return;
 | ||
|   }
 | ||
| 
 | ||
|   // Find next free debug register
 | ||
|   Status = FindNextFreeDebugRegister (SystemContext, &Register);
 | ||
|   if (EFI_ERROR (Status)) {
 | ||
|     Print ((CHAR16 *)L"No space left on device\n");
 | ||
|     SendError (GDB_ENOSPACE);
 | ||
|     return;
 | ||
|   }
 | ||
| 
 | ||
|   // Write Address, length data at particular DR register
 | ||
|   Status = EnableDebugRegister (SystemContext, Register, Address, Length, (UINTN)BreakType);
 | ||
|   if (EFI_ERROR (Status)) {
 | ||
|     if (Status == EFI_UNSUPPORTED) {
 | ||
|       Print ((CHAR16 *)L"Not supported\n");
 | ||
|       SendNotSupported ();
 | ||
|       return;
 | ||
|     }
 | ||
| 
 | ||
|     Print ((CHAR16 *)L"Invalid argument\n");
 | ||
|     SendError (GDB_EINVALIDARG);
 | ||
|     return;
 | ||
|   }
 | ||
| 
 | ||
|   SendSuccess ();
 | ||
| }
 | ||
| 
 | ||
| /**
 | ||
|   ‘z1, [addr], [length]’
 | ||
|   ‘z2, [addr], [length]’
 | ||
|   ‘z3, [addr], [length]’
 | ||
|   ‘z4, [addr], [length]’
 | ||
| 
 | ||
|   Remove hardware breakpoint/watchpoint at address addr of size length
 | ||
| 
 | ||
|   @param *PacketData    Pointer to the Payload data for the packet
 | ||
| 
 | ||
| **/
 | ||
| VOID
 | ||
| EFIAPI
 | ||
| RemoveBreakPoint (
 | ||
|   IN  EFI_SYSTEM_CONTEXT  SystemContext,
 | ||
|   IN  CHAR8               *PacketData
 | ||
|   )
 | ||
| {
 | ||
|   UINTN       Type;
 | ||
|   UINTN       Address;
 | ||
|   UINTN       Length;
 | ||
|   UINTN       Register;
 | ||
|   BREAK_TYPE  BreakType = NotSupported;
 | ||
|   EFI_STATUS  Status;
 | ||
|   UINTN       ErrorCode;
 | ||
| 
 | ||
|   // Parse breakpoint packet data
 | ||
|   ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);
 | ||
|   if (ErrorCode > 0) {
 | ||
|     SendError ((UINT8)ErrorCode);
 | ||
|     return;
 | ||
|   }
 | ||
| 
 | ||
|   switch (Type) {
 | ||
|     case 0:      // Software breakpoint
 | ||
|       BreakType = SoftwareBreakpoint;
 | ||
|       break;
 | ||
| 
 | ||
|     case 1:      // Hardware breakpoint
 | ||
|       BreakType = InstructionExecution;
 | ||
|       break;
 | ||
| 
 | ||
|     case 2:      // Write watchpoint
 | ||
|       BreakType = DataWrite;
 | ||
|       break;
 | ||
| 
 | ||
|     case 3:      // Read watchpoint
 | ||
|       BreakType = DataRead;
 | ||
|       break;
 | ||
| 
 | ||
|     case 4:      // Access watchpoint
 | ||
|       BreakType = DataReadWrite;
 | ||
|       break;
 | ||
| 
 | ||
|     default:
 | ||
|       SendError (GDB_EINVALIDBRKPOINTTYPE);
 | ||
|       return;
 | ||
|   }
 | ||
| 
 | ||
|   // Find matching debug register
 | ||
|   Status = FindMatchingDebugRegister (SystemContext, Address, Length, (UINTN)BreakType, &Register);
 | ||
|   if (EFI_ERROR (Status)) {
 | ||
|     if (Status == EFI_UNSUPPORTED) {
 | ||
|       Print ((CHAR16 *)L"Not supported.\n");
 | ||
|       SendNotSupported ();
 | ||
|       return;
 | ||
|     }
 | ||
| 
 | ||
|     Print ((CHAR16 *)L"No matching register found.\n");
 | ||
|     SendError (GDB_ENOSPACE);
 | ||
|     return;
 | ||
|   }
 | ||
| 
 | ||
|   // Remove breakpoint
 | ||
|   Status = DisableDebugRegister (SystemContext, Register);
 | ||
|   if (EFI_ERROR (Status)) {
 | ||
|     Print ((CHAR16 *)L"Invalid argument.\n");
 | ||
|     SendError (GDB_EINVALIDARG);
 | ||
|     return;
 | ||
|   }
 | ||
| 
 | ||
|   SendSuccess ();
 | ||
| }
 | ||
| 
 | ||
| VOID
 | ||
| InitializeProcessor (
 | ||
|   VOID
 | ||
|   )
 | ||
| {
 | ||
| }
 | ||
| 
 | ||
| BOOLEAN
 | ||
| ValidateAddress (
 | ||
|   IN  VOID  *Address
 | ||
|   )
 | ||
| {
 | ||
|   return TRUE;
 | ||
| }
 | ||
| 
 | ||
| BOOLEAN
 | ||
| ValidateException (
 | ||
|   IN  EFI_EXCEPTION_TYPE     ExceptionType,
 | ||
|   IN OUT EFI_SYSTEM_CONTEXT  SystemContext
 | ||
|   )
 | ||
| {
 | ||
|   return TRUE;
 | ||
| }
 |