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