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