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