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