/** @file Processor specific parts of the GDB stub Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include // // Array of exception types that need to be hooked by the debugger // EFI_EXCEPTION_TYPE_ENTRY gExceptionType[] = { { EXCEPT_X64_DIVIDE_ERROR, GDB_SIGFPE }, { EXCEPT_X64_DEBUG, GDB_SIGTRAP }, { EXCEPT_X64_NMI, GDB_SIGEMT }, { EXCEPT_X64_BREAKPOINT, GDB_SIGTRAP }, { EXCEPT_X64_OVERFLOW, GDB_SIGSEGV }, { EXCEPT_X64_BOUND, GDB_SIGSEGV }, { EXCEPT_X64_INVALID_OPCODE, GDB_SIGILL }, { EXCEPT_X64_DOUBLE_FAULT, GDB_SIGEMT }, { EXCEPT_X64_STACK_FAULT, GDB_SIGSEGV }, { EXCEPT_X64_GP_FAULT, GDB_SIGSEGV }, { EXCEPT_X64_PAGE_FAULT, GDB_SIGSEGV }, { EXCEPT_X64_FP_ERROR, GDB_SIGEMT }, { EXCEPT_X64_ALIGNMENT_CHECK, GDB_SIGEMT }, { EXCEPT_X64_MACHINE_CHECK, GDB_SIGEMT } }; // The offsets of registers SystemContextX64. // The fields in the array are in the gdb ordering. // HAVE TO DOUBLE-CHECK THE ORDER of the 24 regs // UINTN gRegisterOffsets[] = { OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rax), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rcx), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rdx), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rbx), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rsp), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rbp), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rsi), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rdi), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rip), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Rflags), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Cs), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Ss), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Ds), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Es), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Fs), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, Gs), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R8), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R9), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R10), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R11), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R12), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R13), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R14), OFFSET_OF (EFI_SYSTEM_CONTEXT_X64, R15) }; /** Return the number of entries in the gExceptionType[] @retval UINTN, the number of entries in the gExceptionType[] array. **/ UINTN MaxEfiException ( VOID ) { return sizeof (gExceptionType)/sizeof (EFI_EXCEPTION_TYPE_ENTRY); } /** Return the number of entries in the gRegisters[] @retval UINTN, the number of entries (registers) in the gRegisters[] array. **/ UINTN MaxRegisterCount ( VOID ) { return sizeof (gRegisterOffsets)/sizeof (UINTN); } /** Check to see if the ISA is supported. ISA = Instruction Set Architecture @retval TRUE if Isa is supported **/ BOOLEAN CheckIsa ( IN EFI_INSTRUCTION_SET_ARCHITECTURE Isa ) { return (BOOLEAN)(Isa == IsaX64); } /** This takes in the register number and the System Context, and returns a pointer to the RegNumber-th register in gdb ordering It is, by default, set to find the register pointer of the X64 member @param SystemContext Register content at time of the exception @param RegNumber The register to which we want to find a pointer @retval the pointer to the RegNumber-th pointer **/ UINTN * FindPointerToRegister ( IN EFI_SYSTEM_CONTEXT SystemContext, IN UINTN RegNumber ) { UINT8 *TempPtr; TempPtr = ((UINT8 *)SystemContext.SystemContextX64) + gRegisterOffsets[RegNumber]; return (UINTN *)TempPtr; } /** Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr @param SystemContext Register content at time of the exception @param RegNumber the number of the register that we want to read @param OutBufPtr pointer to the output buffer's end. the new data will be added from this point on. @retval the pointer to the next character of the output buffer that is available to be written on. **/ CHAR8 * BasicReadRegister ( IN EFI_SYSTEM_CONTEXT SystemContext, IN UINTN RegNumber, IN CHAR8 *OutBufPtr ) { UINTN RegSize; RegSize = 0; while (RegSize < 64) { *OutBufPtr++ = mHexToStr[((*FindPointerToRegister (SystemContext, RegNumber) >> (RegSize+4)) & 0xf)]; *OutBufPtr++ = mHexToStr[((*FindPointerToRegister (SystemContext, RegNumber) >> RegSize) & 0xf)]; RegSize = RegSize + 8; } return OutBufPtr; } /** ‘p n’ Reads the n-th register's value into an output buffer and sends it as a packet @param SystemContext Register content at time of the exception @param InBuffer Pointer to the input buffer received from gdb server **/ VOID ReadNthRegister ( IN EFI_SYSTEM_CONTEXT SystemContext, IN CHAR8 *InBuffer ) { UINTN RegNumber; CHAR8 OutBuffer[17]; // 1 reg=16 hex chars, and the end '\0' (escape seq) CHAR8 *OutBufPtr; // pointer to the output buffer RegNumber = AsciiStrHexToUintn (&InBuffer[1]); if ((RegNumber < 0) || (RegNumber >= MaxRegisterCount ())) { SendError (GDB_EINVALIDREGNUM); return; } OutBufPtr = OutBuffer; OutBufPtr = BasicReadRegister (SystemContext, RegNumber, OutBufPtr); *OutBufPtr = '\0'; // the end of the buffer SendPacket (OutBuffer); } /** ‘g’ Reads the general registers into an output buffer and sends it as a packet @param SystemContext Register content at time of the exception **/ VOID EFIAPI ReadGeneralRegisters ( IN EFI_SYSTEM_CONTEXT SystemContext ) { UINTN i; CHAR8 OutBuffer[385]; // 24 regs, 16 hex chars each, and the end '\0' (escape seq) CHAR8 *OutBufPtr; // pointer to the output buffer OutBufPtr = OutBuffer; for (i = 0; i < MaxRegisterCount (); i++) { // there are only 24 registers to read OutBufPtr = BasicReadRegister (SystemContext, i, OutBufPtr); } *OutBufPtr = '\0'; // the end of the buffer SendPacket (OutBuffer); } /** Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr @param SystemContext Register content at time of the exception @param RegNumber the number of the register that we want to write @param InBufPtr pointer to the output buffer. the new data will be extracted from the input buffer from this point on. @retval the pointer to the next character of the input buffer that can be used **/ CHAR8 * BasicWriteRegister ( IN EFI_SYSTEM_CONTEXT SystemContext, IN UINTN RegNumber, IN CHAR8 *InBufPtr ) { UINTN RegSize; UINTN TempValue; // the value transferred from a hex char UINT64 NewValue; // the new value of the RegNumber-th Register NewValue = 0; RegSize = 0; while (RegSize < 64) { TempValue = HexCharToInt (*InBufPtr++); if (TempValue < 0) { SendError (GDB_EBADMEMDATA); return NULL; } NewValue += (TempValue << (RegSize+4)); TempValue = HexCharToInt (*InBufPtr++); if (TempValue < 0) { SendError (GDB_EBADMEMDATA); return NULL; } NewValue += (TempValue << RegSize); RegSize = RegSize + 8; } *(FindPointerToRegister (SystemContext, RegNumber)) = NewValue; return InBufPtr; } /** ‘P n...=r...’ Writes the new value of n-th register received into the input buffer to the n-th register @param SystemContext Register content at time of the exception @param InBuffer Pointer to the input buffer received from gdb server **/ VOID EFIAPI WriteNthRegister ( IN EFI_SYSTEM_CONTEXT SystemContext, IN CHAR8 *InBuffer ) { UINTN RegNumber; CHAR8 RegNumBuffer[MAX_REG_NUM_BUF_SIZE]; // put the 'n..' part of the message into this array CHAR8 *RegNumBufPtr; CHAR8 *InBufPtr; // pointer to the input buffer // find the register number to write InBufPtr = &InBuffer[1]; RegNumBufPtr = RegNumBuffer; while (*InBufPtr != '=') { *RegNumBufPtr++ = *InBufPtr++; } *RegNumBufPtr = '\0'; RegNumber = AsciiStrHexToUintn (RegNumBuffer); // check if this is a valid Register Number if ((RegNumber < 0) || (RegNumber >= MaxRegisterCount ())) { SendError (GDB_EINVALIDREGNUM); return; } InBufPtr++; // skips the '=' character BasicWriteRegister (SystemContext, RegNumber, InBufPtr); SendSuccess (); } /** ‘G XX...’ Writes the new values received into the input buffer to the general registers @param SystemContext Register content at time of the exception @param InBuffer Pointer to the input buffer received from gdb server **/ VOID EFIAPI WriteGeneralRegisters ( IN EFI_SYSTEM_CONTEXT SystemContext, IN CHAR8 *InBuffer ) { UINTN i; CHAR8 *InBufPtr; /// pointer to the input buffer // check to see if the buffer is the right size which is // 1 (for 'G') + 16 (for 16 registers) * 8 ( for 8 hex chars each) = 385 if (AsciiStrLen (InBuffer) != 385) { // 24 regs, 16 hex chars each, and the end '\0' (escape seq) // Bad message. Message is not the right length SendError (GDB_EBADBUFSIZE); return; } InBufPtr = &InBuffer[1]; // Read the new values for the registers from the input buffer to an array, NewValueArray. // The values in the array are in the gdb ordering for (i = 0; i < MaxRegisterCount (); i++) { // there are only 16 registers to write InBufPtr = BasicWriteRegister (SystemContext, i, InBufPtr); } SendSuccess (); } /** Insert Single Step in the SystemContext @param SystemContext Register content at time of the exception **/ VOID AddSingleStep ( IN EFI_SYSTEM_CONTEXT SystemContext ) { SystemContext.SystemContextX64->Rflags |= TF_BIT; // Setting the TF bit. } /** Remove Single Step in the SystemContext @param SystemContext Register content at time of the exception **/ VOID RemoveSingleStep ( IN EFI_SYSTEM_CONTEXT SystemContext ) { SystemContext.SystemContextX64->Rflags &= ~TF_BIT; // clearing the TF bit. } /** ‘c [addr ]’ Continue. addr is Address to resume. If addr is omitted, resume at current Address. @param SystemContext Register content at time of the exception **/ VOID EFIAPI ContinueAtAddress ( IN EFI_SYSTEM_CONTEXT SystemContext, IN CHAR8 *PacketData ) { if (PacketData[1] != '\0') { SystemContext.SystemContextX64->Rip = AsciiStrHexToUintn (&PacketData[1]); } } /** ‘s [addr ]’ Single step. addr is the Address at which to resume. If addr is omitted, resume at same Address. @param SystemContext Register content at time of the exception **/ VOID EFIAPI SingleStep ( IN EFI_SYSTEM_CONTEXT SystemContext, IN CHAR8 *PacketData ) { if (PacketData[1] != '\0') { SystemContext.SystemContextX64->Rip = AsciiStrHexToUintn (&PacketData[1]); } AddSingleStep (SystemContext); } /** Returns breakpoint data address from DR0-DR3 based on the input breakpoint number @param SystemContext Register content at time of the exception @param BreakpointNumber Breakpoint number @retval Address Data address from DR0-DR3 based on the breakpoint number. **/ UINTN GetBreakpointDataAddress ( IN EFI_SYSTEM_CONTEXT SystemContext, IN UINTN BreakpointNumber ) { UINTN Address; if (BreakpointNumber == 1) { Address = SystemContext.SystemContextIa32->Dr0; } else if (BreakpointNumber == 2) { Address = SystemContext.SystemContextIa32->Dr1; } else if (BreakpointNumber == 3) { Address = SystemContext.SystemContextIa32->Dr2; } else if (BreakpointNumber == 4) { Address = SystemContext.SystemContextIa32->Dr3; } else { Address = 0; } return Address; } /** Returns currently detected breakpoint value based on the register DR6 B0-B3 field. If no breakpoint is detected then it returns 0. @param SystemContext Register content at time of the exception @retval {1-4} Currently detected breakpoint value @retval 0 No breakpoint detected. **/ UINTN GetBreakpointDetected ( IN EFI_SYSTEM_CONTEXT SystemContext ) { IA32_DR6 Dr6; UINTN BreakpointNumber; Dr6.UintN = SystemContext.SystemContextIa32->Dr6; if (Dr6.Bits.B0 == 1) { BreakpointNumber = 1; } else if (Dr6.Bits.B1 == 1) { BreakpointNumber = 2; } else if (Dr6.Bits.B2 == 1) { BreakpointNumber = 3; } else if (Dr6.Bits.B3 == 1) { BreakpointNumber = 4; } else { BreakpointNumber = 0; // No breakpoint detected } return BreakpointNumber; } /** Returns Breakpoint type (InstructionExecution, DataWrite, DataRead or DataReadWrite) based on the Breakpoint number @param SystemContext Register content at time of the exception @param BreakpointNumber Breakpoint number @retval BREAK_TYPE Breakpoint type value read from register DR7 RWn field. For unknown value, it returns NotSupported. **/ BREAK_TYPE GetBreakpointType ( IN EFI_SYSTEM_CONTEXT SystemContext, IN UINTN BreakpointNumber ) { IA32_DR7 Dr7; BREAK_TYPE Type = NotSupported; // Default is NotSupported type Dr7.UintN = SystemContext.SystemContextIa32->Dr7; if (BreakpointNumber == 1) { Type = (BREAK_TYPE)Dr7.Bits.RW0; } else if (BreakpointNumber == 2) { Type = (BREAK_TYPE)Dr7.Bits.RW1; } else if (BreakpointNumber == 3) { Type = (BREAK_TYPE)Dr7.Bits.RW2; } else if (BreakpointNumber == 4) { Type = (BREAK_TYPE)Dr7.Bits.RW3; } return Type; } /** Parses Length and returns the length which DR7 LENn field accepts. For example: If we receive 1-Byte length then we should return 0. Zero gets written to DR7 LENn field. @param Length Breakpoint length in Bytes (1 byte, 2 byte, 4 byte) @retval Length Appropriate converted values which DR7 LENn field accepts. **/ UINTN ConvertLengthData ( IN UINTN Length ) { if (Length == 1) { // 1-Byte length return 0; } else if (Length == 2) { // 2-Byte length return 1; } else if (Length == 4) { // 4-Byte length return 3; } else { // Undefined or 8-byte length return 2; } } /** Finds the next free debug register. If all the registers are occupied then EFI_OUT_OF_RESOURCES is returned. @param SystemContext Register content at time of the exception @param Register Register value (0 - 3 for the first free debug register) @retval EFI_STATUS Appropriate status value. **/ EFI_STATUS FindNextFreeDebugRegister ( IN EFI_SYSTEM_CONTEXT SystemContext, OUT UINTN *Register ) { IA32_DR7 Dr7; Dr7.UintN = SystemContext.SystemContextIa32->Dr7; if (Dr7.Bits.G0 == 0) { *Register = 0; } else if (Dr7.Bits.G1 == 0) { *Register = 1; } else if (Dr7.Bits.G2 == 0) { *Register = 2; } else if (Dr7.Bits.G3 == 0) { *Register = 3; } else { return EFI_OUT_OF_RESOURCES; } return EFI_SUCCESS; } /** Enables the debug register. Writes Address value to appropriate DR0-3 register. Sets LENn, Gn, RWn bits in DR7 register. @param SystemContext Register content at time of the exception @param Register Register value (0 - 3) @param Address Breakpoint address value @param Type Breakpoint type (Instruction, Data write, Data read or write etc.) @retval EFI_STATUS Appropriate status value. **/ EFI_STATUS EnableDebugRegister ( IN EFI_SYSTEM_CONTEXT SystemContext, IN UINTN Register, IN UINTN Address, IN UINTN Length, IN UINTN Type ) { IA32_DR7 Dr7; // Convert length data Length = ConvertLengthData (Length); // For Instruction execution, length should be 0 // (Ref. Intel reference manual 18.2.4) if ((Type == 0) && (Length != 0)) { return EFI_INVALID_PARAMETER; } // Hardware doesn't support ReadWatch (z3 packet) type. GDB can handle // software breakpoint. We should send empty packet in both these cases. if ((Type == (BREAK_TYPE)DataRead) || (Type == (BREAK_TYPE)SoftwareBreakpoint)) { return EFI_UNSUPPORTED; } // Read DR7 so appropriate Gn, RWn and LENn bits can be modified. Dr7.UintN = SystemContext.SystemContextIa32->Dr7; if (Register == 0) { SystemContext.SystemContextIa32->Dr0 = Address; Dr7.Bits.G0 = 1; Dr7.Bits.RW0 = Type; Dr7.Bits.LEN0 = Length; } else if (Register == 1) { SystemContext.SystemContextIa32->Dr1 = Address; Dr7.Bits.G1 = 1; Dr7.Bits.RW1 = Type; Dr7.Bits.LEN1 = Length; } else if (Register == 2) { SystemContext.SystemContextIa32->Dr2 = Address; Dr7.Bits.G2 = 1; Dr7.Bits.RW2 = Type; Dr7.Bits.LEN2 = Length; } else if (Register == 3) { SystemContext.SystemContextIa32->Dr3 = Address; Dr7.Bits.G3 = 1; Dr7.Bits.RW3 = Type; Dr7.Bits.LEN3 = Length; } else { return EFI_INVALID_PARAMETER; } // Update Dr7 with appropriate Gn, RWn and LENn bits SystemContext.SystemContextIa32->Dr7 = Dr7.UintN; return EFI_SUCCESS; } /** Returns register number 0 - 3 for the matching debug register. This function compares incoming Address, Type, Length and if there is a match then it returns the appropriate register number. In case of mismatch, function returns EFI_NOT_FOUND message. @param SystemContext Register content at time of the exception @param Address Breakpoint address value @param Length Breakpoint length value @param Type Breakpoint type (Instruction, Data write, Data read or write etc.) @param Register Register value to be returned @retval EFI_STATUS Appropriate status value. **/ EFI_STATUS FindMatchingDebugRegister ( IN EFI_SYSTEM_CONTEXT SystemContext, IN UINTN Address, IN UINTN Length, IN UINTN Type, OUT UINTN *Register ) { IA32_DR7 Dr7; // Hardware doesn't support ReadWatch (z3 packet) type. GDB can handle // software breakpoint. We should send empty packet in both these cases. if ((Type == (BREAK_TYPE)DataRead) || (Type == (BREAK_TYPE)SoftwareBreakpoint)) { return EFI_UNSUPPORTED; } // Convert length data Length = ConvertLengthData (Length); Dr7.UintN = SystemContext.SystemContextIa32->Dr7; if ((Dr7.Bits.G0 == 1) && (Dr7.Bits.LEN0 == Length) && (Dr7.Bits.RW0 == Type) && (Address == SystemContext.SystemContextIa32->Dr0)) { *Register = 0; } else if ((Dr7.Bits.G1 == 1) && (Dr7.Bits.LEN1 == Length) && (Dr7.Bits.RW1 == Type) && (Address == SystemContext.SystemContextIa32->Dr1)) { *Register = 1; } else if ((Dr7.Bits.G2 == 1) && (Dr7.Bits.LEN2 == Length) && (Dr7.Bits.RW2 == Type) && (Address == SystemContext.SystemContextIa32->Dr2)) { *Register = 2; } else if ((Dr7.Bits.G3 == 1) && (Dr7.Bits.LEN3 == Length) && (Dr7.Bits.RW3 == Type) && (Address == SystemContext.SystemContextIa32->Dr3)) { *Register = 3; } else { Print ((CHAR16 *)L"No match found..\n"); return EFI_NOT_FOUND; } return EFI_SUCCESS; } /** Disables the particular debug register. @param SystemContext Register content at time of the exception @param Register Register to be disabled @retval EFI_STATUS Appropriate status value. **/ EFI_STATUS DisableDebugRegister ( IN EFI_SYSTEM_CONTEXT SystemContext, IN UINTN Register ) { IA32_DR7 Dr7; UINTN Address = 0; // Read DR7 register so appropriate Gn, RWn and LENn bits can be turned off. Dr7.UintN = SystemContext.SystemContextIa32->Dr7; if (Register == 0) { SystemContext.SystemContextIa32->Dr0 = Address; Dr7.Bits.G0 = 0; Dr7.Bits.RW0 = 0; Dr7.Bits.LEN0 = 0; } else if (Register == 1) { SystemContext.SystemContextIa32->Dr1 = Address; Dr7.Bits.G1 = 0; Dr7.Bits.RW1 = 0; Dr7.Bits.LEN1 = 0; } else if (Register == 2) { SystemContext.SystemContextIa32->Dr2 = Address; Dr7.Bits.G2 = 0; Dr7.Bits.RW2 = 0; Dr7.Bits.LEN2 = 0; } else if (Register == 3) { SystemContext.SystemContextIa32->Dr3 = Address; Dr7.Bits.G3 = 0; Dr7.Bits.RW3 = 0; Dr7.Bits.LEN3 = 0; } else { return EFI_INVALID_PARAMETER; } // Update DR7 register so appropriate Gn, RWn and LENn bits can be turned off. SystemContext.SystemContextIa32->Dr7 = Dr7.UintN; return EFI_SUCCESS; } /** ‘Z1, [addr], [length]’ ‘Z2, [addr], [length]’ ‘Z3, [addr], [length]’ ‘Z4, [addr], [length]’ Insert hardware breakpoint/watchpoint at address addr of size length @param SystemContext Register content at time of the exception @param *PacketData Pointer to the Payload data for the packet **/ VOID EFIAPI InsertBreakPoint ( IN EFI_SYSTEM_CONTEXT SystemContext, IN CHAR8 *PacketData ) { UINTN Type; UINTN Address; UINTN Length; UINTN Register; EFI_STATUS Status; BREAK_TYPE BreakType = NotSupported; UINTN ErrorCode; ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length); if (ErrorCode > 0) { SendError ((UINT8)ErrorCode); return; } switch (Type) { case 0: // Software breakpoint BreakType = SoftwareBreakpoint; break; case 1: // Hardware breakpoint BreakType = InstructionExecution; break; case 2: // Write watchpoint BreakType = DataWrite; break; case 3: // Read watchpoint BreakType = DataRead; break; case 4: // Access watchpoint BreakType = DataReadWrite; break; default: Print ((CHAR16 *)L"Insert breakpoint default: %x\n", Type); SendError (GDB_EINVALIDBRKPOINTTYPE); return; } // Find next free debug register Status = FindNextFreeDebugRegister (SystemContext, &Register); if (EFI_ERROR (Status)) { Print ((CHAR16 *)L"No space left on device\n"); SendError (GDB_ENOSPACE); return; } // Write Address, length data at particular DR register Status = EnableDebugRegister (SystemContext, Register, Address, Length, (UINTN)BreakType); if (EFI_ERROR (Status)) { if (Status == EFI_UNSUPPORTED) { Print ((CHAR16 *)L"Not supported\n"); SendNotSupported (); return; } Print ((CHAR16 *)L"Invalid argument\n"); SendError (GDB_EINVALIDARG); return; } SendSuccess (); } /** ‘z1, [addr], [length]’ ‘z2, [addr], [length]’ ‘z3, [addr], [length]’ ‘z4, [addr], [length]’ Remove hardware breakpoint/watchpoint at address addr of size length @param *PacketData Pointer to the Payload data for the packet **/ VOID EFIAPI RemoveBreakPoint ( IN EFI_SYSTEM_CONTEXT SystemContext, IN CHAR8 *PacketData ) { UINTN Type; UINTN Address; UINTN Length; UINTN Register; BREAK_TYPE BreakType = NotSupported; EFI_STATUS Status; UINTN ErrorCode; // Parse breakpoint packet data ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length); if (ErrorCode > 0) { SendError ((UINT8)ErrorCode); return; } switch (Type) { case 0: // Software breakpoint BreakType = SoftwareBreakpoint; break; case 1: // Hardware breakpoint BreakType = InstructionExecution; break; case 2: // Write watchpoint BreakType = DataWrite; break; case 3: // Read watchpoint BreakType = DataRead; break; case 4: // Access watchpoint BreakType = DataReadWrite; break; default: SendError (GDB_EINVALIDBRKPOINTTYPE); return; } // Find matching debug register Status = FindMatchingDebugRegister (SystemContext, Address, Length, (UINTN)BreakType, &Register); if (EFI_ERROR (Status)) { if (Status == EFI_UNSUPPORTED) { Print ((CHAR16 *)L"Not supported.\n"); SendNotSupported (); return; } Print ((CHAR16 *)L"No matching register found.\n"); SendError (GDB_ENOSPACE); return; } // Remove breakpoint Status = DisableDebugRegister (SystemContext, Register); if (EFI_ERROR (Status)) { Print ((CHAR16 *)L"Invalid argument.\n"); SendError (GDB_EINVALIDARG); return; } SendSuccess (); } VOID InitializeProcessor ( VOID ) { } BOOLEAN ValidateAddress ( IN VOID *Address ) { return TRUE; } BOOLEAN ValidateException ( IN EFI_EXCEPTION_TYPE ExceptionType, IN OUT EFI_SYSTEM_CONTEXT SystemContext ) { return TRUE; }