Home | History | Annotate | Download | only in X64
      1 /** @file
      2   Processor specific parts of the GDB stub
      3 
      4   Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
      5 
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include <GdbStubInternal.h>
     17 
     18 //
     19 // Array of exception types that need to be hooked by the debugger
     20 //
     21 EFI_EXCEPTION_TYPE_ENTRY gExceptionType[] = {
     22   { EXCEPT_X64_DIVIDE_ERROR,    GDB_SIGFPE  },
     23   { EXCEPT_X64_DEBUG,           GDB_SIGTRAP },
     24   { EXCEPT_X64_NMI,             GDB_SIGEMT  },
     25   { EXCEPT_X64_BREAKPOINT,      GDB_SIGTRAP },
     26   { EXCEPT_X64_OVERFLOW,        GDB_SIGSEGV },
     27   { EXCEPT_X64_BOUND,           GDB_SIGSEGV },
     28   { EXCEPT_X64_INVALID_OPCODE,  GDB_SIGILL  },
     29   { EXCEPT_X64_DOUBLE_FAULT,    GDB_SIGEMT  },
     30   { EXCEPT_X64_STACK_FAULT,     GDB_SIGSEGV },
     31   { EXCEPT_X64_GP_FAULT,        GDB_SIGSEGV },
     32   { EXCEPT_X64_PAGE_FAULT,      GDB_SIGSEGV },
     33   { EXCEPT_X64_FP_ERROR,        GDB_SIGEMT  },
     34   { EXCEPT_X64_ALIGNMENT_CHECK, GDB_SIGEMT  },
     35   { EXCEPT_X64_MACHINE_CHECK,   GDB_SIGEMT  }
     36 };
     37 
     38 
     39 // The offsets of registers SystemContextX64.
     40 // The fields in the array are in the gdb ordering.
     41 // HAVE TO DOUBLE-CHECK THE ORDER of the 24 regs
     42 //
     43 UINTN gRegisterOffsets[] = {
     44   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rax),
     45   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rcx),
     46   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rdx),
     47   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rbx),
     48   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rsp),
     49   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rbp),
     50   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rsi),
     51   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rdi),
     52   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rip),
     53   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rflags),
     54   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Cs),
     55   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Ss),
     56   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Ds),
     57   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Es),
     58   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Fs),
     59   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Gs),
     60   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R8),
     61   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R9),
     62   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R10),
     63   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R11),
     64   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R12),
     65   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R13),
     66   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R14),
     67   OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R15)
     68 };
     69 
     70 
     71 /**
     72  Return the number of entries in the gExceptionType[]
     73 
     74  @retval  UINTN, the number of entries in the gExceptionType[] array.
     75  **/
     76 UINTN
     77 MaxEfiException (
     78   VOID
     79   )
     80 {
     81   return sizeof (gExceptionType)/sizeof (EFI_EXCEPTION_TYPE_ENTRY);
     82 }
     83 
     84 
     85 /**
     86  Return the number of entries in the gRegisters[]
     87 
     88  @retval  UINTN, the number of entries (registers) in the gRegisters[] array.
     89  **/
     90 UINTN
     91 MaxRegisterCount (
     92   VOID
     93   )
     94 {
     95   return sizeof (gRegisterOffsets)/sizeof (UINTN);
     96 }
     97 
     98 
     99 /**
    100   Check to see if the ISA is supported.
    101   ISA = Instruction Set Architecture
    102 
    103   @retval TRUE if Isa is supported
    104 **/
    105 BOOLEAN
    106 CheckIsa (
    107   IN  EFI_INSTRUCTION_SET_ARCHITECTURE  Isa
    108   )
    109 {
    110   return (BOOLEAN)(Isa == IsaX64);
    111 }
    112 
    113 
    114 /**
    115  This takes in the register number and the System Context, and returns a pointer to the RegNumber-th register in gdb ordering
    116  It is, by default, set to find the register pointer of the X64 member
    117  @param   SystemContext     Register content at time of the exception
    118  @param   RegNumber       The register to which we want to find a pointer
    119  @retval  the pointer to the RegNumber-th pointer
    120  **/
    121 UINTN *
    122 FindPointerToRegister(
    123   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    124   IN  UINTN               RegNumber
    125   )
    126 {
    127   UINT8 *TempPtr;
    128   TempPtr = ((UINT8 *)SystemContext.SystemContextX64) + gRegisterOffsets[RegNumber];
    129   return (UINTN *)TempPtr;
    130 }
    131 
    132 
    133 /**
    134  Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
    135  @param   SystemContext     Register content at time of the exception
    136  @param   RegNumber       the number of the register that we want to read
    137  @param   OutBufPtr       pointer to the output buffer's end. the new data will be added from this point on.
    138  @retval  the pointer to the next character of the output buffer that is available to be written on.
    139  **/
    140 CHAR8 *
    141 BasicReadRegister (
    142   IN  EFI_SYSTEM_CONTEXT      SystemContext,
    143   IN  UINTN           RegNumber,
    144   IN  CHAR8           *OutBufPtr
    145   )
    146 {
    147   UINTN RegSize;
    148 
    149   RegSize = 0;
    150   while (RegSize < 64) {
    151     *OutBufPtr++ = mHexToStr[((*FindPointerToRegister(SystemContext, RegNumber) >> (RegSize+4)) & 0xf)];
    152     *OutBufPtr++ = mHexToStr[((*FindPointerToRegister(SystemContext, RegNumber) >> RegSize) & 0xf)];
    153     RegSize = RegSize + 8;
    154   }
    155   return OutBufPtr;
    156 }
    157 
    158 
    159 /** p n
    160  Reads the n-th register's value into an output buffer and sends it as a packet
    161  @param   SystemContext   Register content at time of the exception
    162  @param   InBuffer      Pointer to the input buffer received from gdb server
    163  **/
    164 VOID
    165 ReadNthRegister (
    166   IN  EFI_SYSTEM_CONTEXT   SystemContext,
    167   IN  CHAR8                *InBuffer
    168   )
    169 {
    170   UINTN RegNumber;
    171   CHAR8 OutBuffer[17];  // 1 reg=16 hex chars, and the end '\0' (escape seq)
    172   CHAR8 *OutBufPtr;   // pointer to the output buffer
    173 
    174   RegNumber = AsciiStrHexToUintn (&InBuffer[1]);
    175 
    176   if ((RegNumber < 0) || (RegNumber >= MaxRegisterCount())) {
    177     SendError (GDB_EINVALIDREGNUM);
    178     return;
    179   }
    180 
    181   OutBufPtr = OutBuffer;
    182   OutBufPtr = BasicReadRegister(SystemContext, RegNumber, OutBufPtr);
    183 
    184   *OutBufPtr = '\0';  // the end of the buffer
    185   SendPacket (OutBuffer);
    186 }
    187 
    188 
    189 /** g
    190  Reads the general registers into an output buffer  and sends it as a packet
    191 
    192  @param   SystemContext     Register content at time of the exception
    193  **/
    194 VOID
    195 EFIAPI
    196 ReadGeneralRegisters (
    197   IN  EFI_SYSTEM_CONTEXT      SystemContext
    198   )
    199 {
    200   UINTN   i;
    201   CHAR8 OutBuffer[385]; // 24 regs, 16 hex chars each, and the end '\0' (escape seq)
    202   CHAR8 *OutBufPtr;   // pointer to the output buffer
    203 
    204   OutBufPtr = OutBuffer;
    205   for(i = 0 ; i < MaxRegisterCount() ; i++) {  // there are only 24 registers to read
    206     OutBufPtr = BasicReadRegister(SystemContext, i, OutBufPtr);
    207   }
    208 
    209   *OutBufPtr = '\0';  // the end of the buffer
    210   SendPacket (OutBuffer);
    211 }
    212 
    213 
    214 /**
    215  Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
    216 
    217  @param   SystemContext       Register content at time of the exception
    218  @param   RegNumber         the number of the register that we want to write
    219  @param   InBufPtr          pointer to the output buffer. the new data will be extracted from the input buffer from this point on.
    220  @retval  the pointer to the next character of the input buffer that can be used
    221  **/
    222 CHAR8 *
    223 BasicWriteRegister (
    224   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    225   IN  UINTN               RegNumber,
    226   IN  CHAR8               *InBufPtr
    227   )
    228 {
    229   UINTN RegSize;
    230   UINTN TempValue; // the value transferred from a hex char
    231   UINT64 NewValue; // the new value of the RegNumber-th Register
    232 
    233   NewValue = 0;
    234   RegSize = 0;
    235   while (RegSize < 64) {
    236     TempValue = HexCharToInt(*InBufPtr++);
    237 
    238     if (TempValue < 0) {
    239       SendError (GDB_EBADMEMDATA);
    240       return NULL;
    241     }
    242 
    243     NewValue += (TempValue << (RegSize+4));
    244     TempValue = HexCharToInt(*InBufPtr++);
    245 
    246     if (TempValue < 0) {
    247       SendError (GDB_EBADMEMDATA);
    248       return NULL;
    249   }
    250 
    251     NewValue += (TempValue << RegSize);
    252     RegSize = RegSize + 8;
    253   }
    254   *(FindPointerToRegister(SystemContext, RegNumber)) = NewValue;
    255   return InBufPtr;
    256 }
    257 
    258 
    259 /** P n...=r...
    260  Writes the new value of n-th register received into the input buffer to the n-th register
    261 
    262  @param   SystemContext   Register content at time of the exception
    263  @param   InBuffer      Ponter to the input buffer received from gdb server
    264  **/
    265 VOID
    266 EFIAPI
    267 WriteNthRegister (
    268   IN  EFI_SYSTEM_CONTEXT      SystemContext,
    269   IN  CHAR8           *InBuffer
    270   )
    271 {
    272   UINTN RegNumber;
    273   CHAR8 RegNumBuffer[MAX_REG_NUM_BUF_SIZE];  // put the 'n..' part of the message into this array
    274   CHAR8 *RegNumBufPtr;
    275   CHAR8 *InBufPtr; // pointer to the input buffer
    276 
    277   // find the register number to write
    278   InBufPtr = &InBuffer[1];
    279   RegNumBufPtr = RegNumBuffer;
    280   while (*InBufPtr != '=') {
    281     *RegNumBufPtr++ = *InBufPtr++;
    282   }
    283   *RegNumBufPtr = '\0';
    284   RegNumber = AsciiStrHexToUintn (RegNumBuffer);
    285 
    286   // check if this is a valid Register Number
    287   if ((RegNumber < 0) || (RegNumber >= MaxRegisterCount())) {
    288     SendError (GDB_EINVALIDREGNUM);
    289     return;
    290   }
    291   InBufPtr++;  // skips the '=' character
    292   BasicWriteRegister (SystemContext, RegNumber, InBufPtr);
    293   SendSuccess();
    294 }
    295 
    296 
    297 /** G XX...
    298  Writes the new values received into the input buffer to the general registers
    299 
    300  @param   SystemContext       Register content at time of the exception
    301  @param   InBuffer          Pointer to the input buffer received from gdb server
    302  **/
    303 VOID
    304 EFIAPI
    305 WriteGeneralRegisters (
    306   IN  EFI_SYSTEM_CONTEXT    SystemContext,
    307   IN  CHAR8                 *InBuffer
    308   )
    309 {
    310   UINTN  i;
    311   CHAR8 *InBufPtr; /// pointer to the input buffer
    312 
    313   // check to see if the buffer is the right size which is
    314   // 1 (for 'G') + 16 (for 16 registers) * 8 ( for 8 hex chars each) = 385
    315   if (AsciiStrLen(InBuffer) != 385) { // 24 regs, 16 hex chars each, and the end '\0' (escape seq)
    316     //Bad message. Message is not the right length
    317     SendError (GDB_EBADBUFSIZE);
    318     return;
    319   }
    320 
    321   InBufPtr = &InBuffer[1];
    322 
    323   // Read the new values for the registers from the input buffer to an array, NewValueArray.
    324   // The values in the array are in the gdb ordering
    325   for(i=0; i < MaxRegisterCount(); i++) {  // there are only 16 registers to write
    326     InBufPtr = BasicWriteRegister(SystemContext, i, InBufPtr);
    327   }
    328 
    329   SendSuccess();
    330 }
    331 
    332 
    333  /**
    334  Insert Single Step in the SystemContext
    335 
    336  @param SystemContext Register content at time of the exception
    337  **/
    338 VOID
    339 AddSingleStep (
    340   IN  EFI_SYSTEM_CONTEXT  SystemContext
    341   )
    342 {
    343   SystemContext.SystemContextX64->Rflags |= TF_BIT; //Setting the TF bit.
    344 }
    345 
    346 
    347 
    348 /**
    349  Remove Single Step in the SystemContext
    350 
    351  @param SystemContext Register content at time of the exception
    352  **/
    353 VOID
    354 RemoveSingleStep (
    355   IN  EFI_SYSTEM_CONTEXT  SystemContext
    356   )
    357 {
    358   SystemContext.SystemContextX64->Rflags &= ~TF_BIT;  // clearing the TF bit.
    359 }
    360 
    361 
    362 
    363 /** c [addr ]
    364  Continue. addr is Address to resume. If addr is omitted, resume at current
    365  Address.
    366 
    367  @param   SystemContext     Register content at time of the exception
    368  **/
    369 VOID
    370 EFIAPI
    371 ContinueAtAddress (
    372   IN  EFI_SYSTEM_CONTEXT      SystemContext,
    373   IN    CHAR8                 *PacketData
    374   )
    375 {
    376   if (PacketData[1] != '\0') {
    377     SystemContext.SystemContextX64->Rip = AsciiStrHexToUintn(&PacketData[1]);
    378   }
    379 }
    380 
    381 
    382 /** s [addr ]
    383  Single step. addr is the Address at which to resume. If addr is omitted, resume
    384  at same Address.
    385 
    386  @param   SystemContext     Register content at time of the exception
    387  **/
    388 VOID
    389 EFIAPI
    390 SingleStep (
    391   IN  EFI_SYSTEM_CONTEXT      SystemContext,
    392   IN    CHAR8                 *PacketData
    393   )
    394 {
    395   if (PacketData[1] != '\0') {
    396     SystemContext.SystemContextX64->Rip = AsciiStrHexToUintn (&PacketData[1]);
    397   }
    398 
    399   AddSingleStep (SystemContext);
    400 }
    401 
    402 
    403 /**
    404   Returns breakpoint data address from DR0-DR3 based on the input breakpoint
    405   number
    406 
    407   @param  SystemContext      Register content at time of the exception
    408   @param  BreakpointNumber   Breakpoint number
    409 
    410   @retval Address            Data address from DR0-DR3 based on the
    411                              breakpoint number.
    412 
    413 **/
    414 UINTN
    415 GetBreakpointDataAddress (
    416   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    417   IN  UINTN               BreakpointNumber
    418   )
    419 {
    420   UINTN Address;
    421 
    422   if (BreakpointNumber == 1) {
    423     Address = SystemContext.SystemContextIa32->Dr0;
    424   } else if (BreakpointNumber == 2) {
    425     Address = SystemContext.SystemContextIa32->Dr1;
    426   } else if (BreakpointNumber == 3) {
    427     Address = SystemContext.SystemContextIa32->Dr2;
    428   } else if (BreakpointNumber == 4) {
    429     Address = SystemContext.SystemContextIa32->Dr3;
    430   } else {
    431     Address = 0;
    432   }
    433 
    434   return Address;
    435 }
    436 
    437 /**
    438   Returns currently detected breakpoint value based on the register
    439   DR6 B0-B3 field.
    440   If no breakpoint is detected then it returns 0.
    441 
    442   @param  SystemContext  Register content at time of the exception
    443 
    444   @retval {1-4}          Currently detected breakpoint value
    445   @retval 0              No breakpoint detected.
    446 
    447 **/
    448 UINTN
    449 GetBreakpointDetected (
    450   IN  EFI_SYSTEM_CONTEXT  SystemContext
    451   )
    452 {
    453   IA32_DR6 Dr6;
    454   UINTN BreakpointNumber;
    455 
    456   Dr6.UintN = SystemContext.SystemContextIa32->Dr6;
    457 
    458   if (Dr6.Bits.B0 == 1) {
    459     BreakpointNumber = 1;
    460   } else if (Dr6.Bits.B1 == 1) {
    461     BreakpointNumber = 2;
    462   } else if (Dr6.Bits.B2 == 1) {
    463     BreakpointNumber = 3;
    464   } else if (Dr6.Bits.B3 == 1) {
    465     BreakpointNumber = 4;
    466   } else {
    467     BreakpointNumber = 0;  //No breakpoint detected
    468   }
    469 
    470   return BreakpointNumber;
    471 }
    472 
    473 /**
    474   Returns Breakpoint type (InstructionExecution, DataWrite, DataRead
    475   or DataReadWrite) based on the Breakpoint number
    476 
    477   @param  SystemContext      Register content at time of the exception
    478   @param  BreakpointNumber   Breakpoint number
    479 
    480   @retval BREAK_TYPE         Breakpoint type value read from register DR7 RWn
    481                              field. For unknown value, it returns NotSupported.
    482 
    483 **/
    484 BREAK_TYPE
    485 GetBreakpointType (
    486   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    487   IN  UINTN               BreakpointNumber
    488   )
    489 {
    490   IA32_DR7 Dr7;
    491   BREAK_TYPE Type = NotSupported;  //Default is NotSupported type
    492 
    493   Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
    494 
    495   if (BreakpointNumber == 1) {
    496     Type = (BREAK_TYPE) Dr7.Bits.RW0;
    497   } else if (BreakpointNumber == 2) {
    498     Type = (BREAK_TYPE) Dr7.Bits.RW1;
    499   } else if (BreakpointNumber == 3) {
    500     Type = (BREAK_TYPE) Dr7.Bits.RW2;
    501   } else if (BreakpointNumber == 4) {
    502     Type = (BREAK_TYPE) Dr7.Bits.RW3;
    503   }
    504 
    505   return Type;
    506 }
    507 
    508 
    509 /**
    510   Parses Length and returns the length which DR7 LENn field accepts.
    511   For example: If we receive 1-Byte length then we should return 0.
    512                Zero gets written to DR7 LENn field.
    513 
    514   @param  Length  Breakpoint length in Bytes (1 byte, 2 byte, 4 byte)
    515 
    516   @retval Length  Appropriate converted values which DR7 LENn field accepts.
    517 
    518 **/
    519 UINTN
    520 ConvertLengthData (
    521   IN     UINTN   Length
    522   )
    523 {
    524   if (Length == 1) {         //1-Byte length
    525     return 0;
    526   } else if (Length == 2) {  //2-Byte length
    527     return 1;
    528   } else if (Length == 4) {  //4-Byte length
    529     return 3;
    530   } else {                   //Undefined or 8-byte length
    531     return 2;
    532   }
    533 }
    534 
    535 
    536 /**
    537   Finds the next free debug register. If all the registers are occupied then
    538   EFI_OUT_OF_RESOURCES is returned.
    539 
    540   @param  SystemContext  Register content at time of the exception
    541   @param  Register       Register value (0 - 3 for the first free debug register)
    542 
    543   @retval EFI_STATUS     Appropriate status value.
    544 
    545 **/
    546 EFI_STATUS
    547 FindNextFreeDebugRegister (
    548   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    549   OUT UINTN               *Register
    550   )
    551 {
    552   IA32_DR7 Dr7;
    553 
    554   Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
    555 
    556   if (Dr7.Bits.G0 == 0) {
    557     *Register = 0;
    558   } else if (Dr7.Bits.G1 == 0) {
    559     *Register = 1;
    560   } else if (Dr7.Bits.G2 == 0) {
    561     *Register = 2;
    562   } else if (Dr7.Bits.G3 == 0) {
    563     *Register = 3;
    564   } else {
    565     return EFI_OUT_OF_RESOURCES;
    566   }
    567 
    568   return EFI_SUCCESS;
    569 }
    570 
    571 
    572 /**
    573   Enables the debug register. Writes Address value to appropriate DR0-3 register.
    574   Sets LENn, Gn, RWn bits in DR7 register.
    575 
    576   @param  SystemContext   Register content at time of the exception
    577   @param  Register        Register value (0 - 3)
    578   @param  Address         Breakpoint address value
    579   @param  Type            Breakpoint type (Instruction, Data write,
    580                           Data read or write etc.)
    581 
    582   @retval EFI_STATUS      Appropriate status value.
    583 
    584 **/
    585 EFI_STATUS
    586 EnableDebugRegister (
    587   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    588   IN  UINTN               Register,
    589   IN  UINTN               Address,
    590   IN  UINTN               Length,
    591   IN  UINTN               Type
    592   )
    593 {
    594   IA32_DR7  Dr7;
    595 
    596   //Convert length data
    597   Length = ConvertLengthData (Length);
    598 
    599   //For Instruction execution, length should be 0
    600   //(Ref. Intel reference manual 18.2.4)
    601   if ((Type == 0) && (Length != 0)) {
    602     return EFI_INVALID_PARAMETER;
    603   }
    604 
    605   //Hardware doesn't support ReadWatch (z3 packet) type. GDB can handle
    606   //software breakpoint. We should send empty packet in both these cases.
    607   if ((Type == (BREAK_TYPE)DataRead) ||
    608       (Type == (BREAK_TYPE)SoftwareBreakpoint))  {
    609     return EFI_UNSUPPORTED;
    610   }
    611 
    612   //Read DR7 so appropriate Gn, RWn and LENn bits can be modified.
    613   Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
    614 
    615   if (Register == 0) {
    616     SystemContext.SystemContextIa32->Dr0 = Address;
    617     Dr7.Bits.G0 = 1;
    618     Dr7.Bits.RW0 = Type;
    619     Dr7.Bits.LEN0 = Length;
    620   } else if (Register == 1) {
    621     SystemContext.SystemContextIa32->Dr1 = Address;
    622     Dr7.Bits.G1 = 1;
    623     Dr7.Bits.RW1 = Type;
    624     Dr7.Bits.LEN1 = Length;
    625   } else if (Register == 2) {
    626     SystemContext.SystemContextIa32->Dr2 = Address;
    627     Dr7.Bits.G2 = 1;
    628     Dr7.Bits.RW2 = Type;
    629     Dr7.Bits.LEN2 = Length;
    630   } else if (Register == 3) {
    631     SystemContext.SystemContextIa32->Dr3 = Address;
    632     Dr7.Bits.G3 = 1;
    633     Dr7.Bits.RW3 = Type;
    634     Dr7.Bits.LEN3 = Length;
    635   } else {
    636     return EFI_INVALID_PARAMETER;
    637   }
    638 
    639   //Update Dr7 with appropriate Gn, RWn and LENn bits
    640   SystemContext.SystemContextIa32->Dr7 = Dr7.UintN;
    641 
    642   return EFI_SUCCESS;
    643 }
    644 
    645 
    646 /**
    647   Returns register number 0 - 3 for the maching debug register.
    648   This function compares incoming Address, Type, Length and
    649   if there is a match then it returns the appropriate register number.
    650   In case of mismatch, function returns EFI_NOT_FOUND message.
    651 
    652   @param  SystemContext  Register content at time of the exception
    653   @param  Address        Breakpoint address value
    654   @param  Length         Breakpoint length value
    655   @param  Type           Breakpoint type (Instruction, Data write, Data read
    656                          or write etc.)
    657   @param  Register       Register value to be returned
    658 
    659   @retval EFI_STATUS     Appropriate status value.
    660 
    661 **/
    662 EFI_STATUS
    663 FindMatchingDebugRegister (
    664  IN  EFI_SYSTEM_CONTEXT  SystemContext,
    665  IN  UINTN               Address,
    666  IN  UINTN               Length,
    667  IN  UINTN               Type,
    668  OUT UINTN               *Register
    669  )
    670 {
    671   IA32_DR7 Dr7;
    672 
    673   //Hardware doesn't support ReadWatch (z3 packet) type. GDB can handle
    674   //software breakpoint. We should send empty packet in both these cases.
    675   if ((Type == (BREAK_TYPE)DataRead) ||
    676       (Type == (BREAK_TYPE)SoftwareBreakpoint)) {
    677     return EFI_UNSUPPORTED;
    678   }
    679 
    680   //Convert length data
    681   Length = ConvertLengthData(Length);
    682 
    683   Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
    684 
    685   if ((Dr7.Bits.G0 == 1) &&
    686       (Dr7.Bits.LEN0 == Length) &&
    687       (Dr7.Bits.RW0 == Type) &&
    688       (Address == SystemContext.SystemContextIa32->Dr0)) {
    689     *Register = 0;
    690   } else if ((Dr7.Bits.G1 == 1) &&
    691              (Dr7.Bits.LEN1 == Length) &&
    692              (Dr7.Bits.RW1 == Type) &&
    693              (Address == SystemContext.SystemContextIa32->Dr1)) {
    694     *Register = 1;
    695   } else if ((Dr7.Bits.G2 == 1) &&
    696              (Dr7.Bits.LEN2 == Length) &&
    697              (Dr7.Bits.RW2 == Type) &&
    698              (Address == SystemContext.SystemContextIa32->Dr2)) {
    699     *Register = 2;
    700   } else if ((Dr7.Bits.G3 == 1) &&
    701              (Dr7.Bits.LEN3 == Length) &&
    702              (Dr7.Bits.RW3 == Type) &&
    703              (Address == SystemContext.SystemContextIa32->Dr3)) {
    704     *Register = 3;
    705   } else {
    706     Print ((CHAR16 *)L"No match found..\n");
    707     return EFI_NOT_FOUND;
    708   }
    709 
    710   return EFI_SUCCESS;
    711 }
    712 
    713 
    714 /**
    715   Disables the particular debug register.
    716 
    717   @param  SystemContext   Register content at time of the exception
    718   @param  Register        Register to be disabled
    719 
    720   @retval EFI_STATUS      Appropriate status value.
    721 
    722 **/
    723 EFI_STATUS
    724 DisableDebugRegister (
    725  IN  EFI_SYSTEM_CONTEXT  SystemContext,
    726  IN  UINTN               Register
    727  )
    728 {
    729   IA32_DR7  Dr7;
    730   UINTN Address = 0;
    731 
    732   //Read DR7 register so appropriate Gn, RWn and LENn bits can be turned off.
    733   Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
    734 
    735   if (Register == 0) {
    736     SystemContext.SystemContextIa32->Dr0 = Address;
    737     Dr7.Bits.G0 = 0;
    738     Dr7.Bits.RW0 = 0;
    739     Dr7.Bits.LEN0 = 0;
    740   } else if (Register == 1) {
    741     SystemContext.SystemContextIa32->Dr1 = Address;
    742     Dr7.Bits.G1 = 0;
    743     Dr7.Bits.RW1 = 0;
    744     Dr7.Bits.LEN1 = 0;
    745   } else if (Register == 2) {
    746     SystemContext.SystemContextIa32->Dr2 = Address;
    747     Dr7.Bits.G2 = 0;
    748     Dr7.Bits.RW2 = 0;
    749     Dr7.Bits.LEN2 = 0;
    750   } else if (Register == 3) {
    751     SystemContext.SystemContextIa32->Dr3 = Address;
    752     Dr7.Bits.G3 = 0;
    753     Dr7.Bits.RW3 = 0;
    754     Dr7.Bits.LEN3 = 0;
    755   } else {
    756     return EFI_INVALID_PARAMETER;
    757   }
    758 
    759   //Update DR7 register so appropriate Gn, RWn and LENn bits can be turned off.
    760   SystemContext.SystemContextIa32->Dr7 = Dr7.UintN;
    761 
    762   return EFI_SUCCESS;
    763 }
    764 
    765 /**
    766   Z1, [addr], [length]
    767   Z2, [addr], [length]
    768   Z3, [addr], [length]
    769   Z4, [addr], [length]
    770 
    771   Insert hardware breakpoint/watchpoint at address addr of size length
    772 
    773   @param SystemContext  Register content at time of the exception
    774   @param *PacketData    Pointer to the Payload data for the packet
    775 
    776 **/
    777 VOID
    778 EFIAPI
    779 InsertBreakPoint (
    780   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    781   IN  CHAR8              *PacketData
    782   )
    783 {
    784   UINTN Type;
    785   UINTN Address;
    786   UINTN Length;
    787   UINTN Register;
    788   EFI_STATUS Status;
    789   BREAK_TYPE BreakType = NotSupported;
    790   UINTN ErrorCode;
    791 
    792   ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);
    793   if (ErrorCode > 0) {
    794     SendError ((UINT8)ErrorCode);
    795     return;
    796   }
    797 
    798   switch (Type) {
    799 
    800     case    0:   //Software breakpoint
    801       BreakType = SoftwareBreakpoint;
    802       break;
    803 
    804     case    1:   //Hardware breakpoint
    805       BreakType = InstructionExecution;
    806       break;
    807 
    808     case    2:   //Write watchpoint
    809       BreakType = DataWrite;
    810       break;
    811 
    812     case    3:   //Read watchpoint
    813       BreakType = DataRead;
    814       break;
    815 
    816     case    4:   //Access watchpoint
    817       BreakType = DataReadWrite;
    818       break;
    819 
    820     default  :
    821       Print ((CHAR16 *)L"Insert breakpoint default: %x\n", Type);
    822       SendError (GDB_EINVALIDBRKPOINTTYPE);
    823       return;
    824   }
    825 
    826   // Find next free debug register
    827   Status = FindNextFreeDebugRegister (SystemContext, &Register);
    828   if (EFI_ERROR(Status)) {
    829     Print ((CHAR16 *)L"No space left on device\n");
    830     SendError (GDB_ENOSPACE);
    831     return;
    832   }
    833 
    834   // Write Address, length data at particular DR register
    835   Status = EnableDebugRegister (SystemContext, Register, Address, Length, (UINTN)BreakType);
    836   if (EFI_ERROR(Status)) {
    837 
    838     if (Status == EFI_UNSUPPORTED) {
    839       Print ((CHAR16 *)L"Not supported\n");
    840       SendNotSupported();
    841       return;
    842     }
    843 
    844     Print ((CHAR16 *)L"Invalid argument\n");
    845     SendError (GDB_EINVALIDARG);
    846     return;
    847   }
    848 
    849   SendSuccess ();
    850 }
    851 
    852 
    853 /**
    854   z1, [addr], [length]
    855   z2, [addr], [length]
    856   z3, [addr], [length]
    857   z4, [addr], [length]
    858 
    859   Remove hardware breakpoint/watchpoint at address addr of size length
    860 
    861   @param *PacketData    Pointer to the Payload data for the packet
    862 
    863 **/
    864 VOID
    865 EFIAPI
    866 RemoveBreakPoint (
    867   IN  EFI_SYSTEM_CONTEXT  SystemContext,
    868   IN  CHAR8               *PacketData
    869   )
    870 {
    871   UINTN      Type;
    872   UINTN      Address;
    873   UINTN      Length;
    874   UINTN      Register;
    875   BREAK_TYPE BreakType = NotSupported;
    876   EFI_STATUS Status;
    877   UINTN      ErrorCode;
    878 
    879   //Parse breakpoint packet data
    880   ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);
    881   if (ErrorCode > 0) {
    882     SendError ((UINT8)ErrorCode);
    883     return;
    884   }
    885 
    886   switch (Type) {
    887 
    888     case    0:   //Software breakpoint
    889       BreakType = SoftwareBreakpoint;
    890       break;
    891 
    892     case    1:   //Hardware breakpoint
    893       BreakType = InstructionExecution;
    894       break;
    895 
    896     case    2:   //Write watchpoint
    897       BreakType = DataWrite;
    898       break;
    899 
    900     case    3:   //Read watchpoint
    901       BreakType = DataRead;
    902       break;
    903 
    904     case    4:   //Access watchpoint
    905       BreakType = DataReadWrite;
    906       break;
    907 
    908     default  :
    909       SendError (GDB_EINVALIDBRKPOINTTYPE);
    910       return;
    911   }
    912 
    913   //Find matching debug register
    914   Status = FindMatchingDebugRegister (SystemContext, Address, Length, (UINTN)BreakType, &Register);
    915   if (EFI_ERROR(Status)) {
    916 
    917     if (Status == EFI_UNSUPPORTED) {
    918       Print ((CHAR16 *)L"Not supported.\n");
    919       SendNotSupported();
    920       return;
    921     }
    922 
    923     Print ((CHAR16 *)L"No matching register found.\n");
    924     SendError (GDB_ENOSPACE);
    925     return;
    926   }
    927 
    928   //Remove breakpoint
    929   Status = DisableDebugRegister(SystemContext, Register);
    930   if (EFI_ERROR(Status)) {
    931     Print ((CHAR16 *)L"Invalid argument.\n");
    932     SendError (GDB_EINVALIDARG);
    933     return;
    934   }
    935 
    936   SendSuccess ();
    937 }
    938 
    939 
    940 VOID
    941 InitializeProcessor (
    942   VOID
    943   )
    944 {
    945 }
    946 
    947 BOOLEAN
    948 ValidateAddress (
    949   IN  VOID  *Address
    950   )
    951 {
    952   return TRUE;
    953 }
    954 
    955 BOOLEAN
    956 ValidateException (
    957   IN  EFI_EXCEPTION_TYPE    ExceptionType,
    958   IN OUT EFI_SYSTEM_CONTEXT SystemContext
    959   )
    960 {
    961   return TRUE;
    962 }
    963 
    964