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