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