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