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