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