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//
21EFI_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//
43UINTN 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 **/
76UINTN
77MaxEfiException (
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 **/
90UINTN
91MaxRegisterCount (
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**/
105BOOLEAN
106CheckIsa (
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 **/
121UINTN *
122FindPointerToRegister(
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 **/
140CHAR8 *
141BasicReadRegister (
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 **/
164VOID
165ReadNthRegister (
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 **/
194VOID
195EFIAPI
196ReadGeneralRegisters (
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 **/
222CHAR8 *
223BasicWriteRegister (
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 **/
265VOID
266EFIAPI
267WriteNthRegister (
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 **/
303VOID
304EFIAPI
305WriteGeneralRegisters (
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 **/
338VOID
339AddSingleStep (
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 **/
353VOID
354RemoveSingleStep (
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 **/
369VOID
370EFIAPI
371ContinueAtAddress (
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 **/
388VOID
389EFIAPI
390SingleStep (
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**/
414UINTN
415GetBreakpointDataAddress (
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**/
448UINTN
449GetBreakpointDetected (
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**/
484BREAK_TYPE
485GetBreakpointType (
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**/
519UINTN
520ConvertLengthData (
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**/
546EFI_STATUS
547FindNextFreeDebugRegister (
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**/
585EFI_STATUS
586EnableDebugRegister (
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**/
662EFI_STATUS
663FindMatchingDebugRegister (
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**/
723EFI_STATUS
724DisableDebugRegister (
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**/
777VOID
778EFIAPI
779InsertBreakPoint (
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**/
864VOID
865EFIAPI
866RemoveBreakPoint (
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
940VOID
941InitializeProcessor (
942  VOID
943  )
944{
945}
946
947BOOLEAN
948ValidateAddress (
949  IN  VOID  *Address
950  )
951{
952  return TRUE;
953}
954
955BOOLEAN
956ValidateException (
957  IN  EFI_EXCEPTION_TYPE    ExceptionType,
958  IN OUT EFI_SYSTEM_CONTEXT SystemContext
959  )
960{
961  return TRUE;
962}
963
964