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