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