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 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 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 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 * 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 * 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 941 InitializeProcessor ( 942 VOID 943 ) 944 { 945 } 946 947 BOOLEAN 948 ValidateAddress ( 949 IN VOID *Address 950 ) 951 { 952 return TRUE; 953 } 954 955 BOOLEAN 956 ValidateException ( 957 IN EFI_EXCEPTION_TYPE ExceptionType, 958 IN OUT EFI_SYSTEM_CONTEXT SystemContext 959 ) 960 { 961 return TRUE; 962 } 963 964