/** @file | |
PE/Coff Extra Action library instances. | |
Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include <PeCoffExtraActionLib.h> | |
/** | |
Check if the hardware breakpoint in Drx is enabled by checking the Lx and Gx bit in Dr7. | |
It assumes that DebugAgent will set both Lx and Gx bit when setting up the hardware breakpoint. | |
@param RegisterIndex Index of Dr register. The value range is from 0 to 3. | |
@param Dr7 Value of Dr7 register. | |
@return TRUE The hardware breakpoint specified in the Drx is enabled. | |
@return FALSE The hardware breakpoint specified in the Drx is disabled. | |
**/ | |
BOOLEAN | |
IsDrxEnabled ( | |
IN UINT8 RegisterIndex, | |
IN UINTN Dr7 | |
) | |
{ | |
return (BOOLEAN)(((Dr7 >> (RegisterIndex * 2)) & (BIT0 | BIT1)) == (BIT0 | BIT1)); | |
} | |
/** | |
Common routine to report the PE/COFF image loading/relocating or unloading event. | |
If ImageContext is NULL, then ASSERT(). | |
@param ImageContext Pointer to the image context structure that describes the | |
PE/COFF image. | |
@param Signature IMAGE_LOAD_SIGNATURE or IMAGE_UNLOAD_SIGNATURE. | |
**/ | |
VOID | |
PeCoffLoaderExtraActionCommon ( | |
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, | |
IN UINTN Signature | |
) | |
{ | |
BOOLEAN InterruptState; | |
UINTN Dr0; | |
UINTN Dr1; | |
UINTN Dr2; | |
UINTN Dr3; | |
UINTN Dr7; | |
UINTN Cr4; | |
UINTN NewDr7; | |
UINT8 LoadImageMethod; | |
UINT8 DebugAgentStatus; | |
IA32_DESCRIPTOR IdtDescriptor; | |
IA32_IDT_GATE_DESCRIPTOR OriginalIdtEntry; | |
BOOLEAN IdtEntryHooked; | |
UINT32 RegEdx; | |
ASSERT (ImageContext != NULL); | |
if (ImageContext->PdbPointer != NULL) { | |
DEBUG ((DEBUG_ERROR, " PDB = %a\n", ImageContext->PdbPointer)); | |
} | |
// | |
// Disable interrupts and save the current interrupt state | |
// | |
InterruptState = SaveAndDisableInterrupts (); | |
IdtEntryHooked = FALSE; | |
LoadImageMethod = PcdGet8 (PcdDebugLoadImageMethod); | |
if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_IO_HW_BREAKPOINT) { | |
// | |
// If the CPU does not support Debug Extensions(CPUID:01 EDX:BIT2) | |
// then force use of DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3 | |
// | |
AsmCpuid (1, NULL, NULL, NULL, &RegEdx); | |
if ((RegEdx & BIT2) == 0) { | |
LoadImageMethod = DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3; | |
} | |
} | |
AsmReadIdtr (&IdtDescriptor); | |
if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3) { | |
if (!CheckDebugAgentHandler (&IdtDescriptor, SOFT_INT_VECTOR_NUM)) { | |
// | |
// Do not trigger INT3 if Debug Agent did not setup IDT entries. | |
// | |
return; | |
} | |
} else { | |
if (!CheckDebugAgentHandler (&IdtDescriptor, IO_HW_BREAKPOINT_VECTOR_NUM)) { | |
// | |
// Save and update IDT entry for INT1 | |
// | |
SaveAndUpdateIdtEntry1 (&IdtDescriptor, &OriginalIdtEntry); | |
IdtEntryHooked = TRUE; | |
} | |
} | |
// | |
// Save Debug Register State | |
// | |
Dr0 = AsmReadDr0 (); | |
Dr1 = AsmReadDr1 (); | |
Dr2 = AsmReadDr2 (); | |
Dr3 = AsmReadDr3 (); | |
Dr7 = AsmReadDr7 () | BIT10; // H/w sets bit 10, some simulators don't | |
Cr4 = AsmReadCr4 (); | |
// | |
// DR0 = Signature | |
// DR1 = The address of the Null-terminated ASCII string for the PE/COFF image's PDB file name | |
// DR2 = The pointer to the ImageContext structure | |
// DR3 = IO_PORT_BREAKPOINT_ADDRESS | |
// DR7 = Disables all HW breakpoints except for DR3 I/O port access of length 1 byte | |
// CR4 = Make sure DE(BIT3) is set | |
// | |
AsmWriteDr7 (BIT10); | |
AsmWriteDr0 (Signature); | |
AsmWriteDr1 ((UINTN)ImageContext->PdbPointer); | |
AsmWriteDr2 ((UINTN)ImageContext); | |
AsmWriteDr3 (IO_PORT_BREAKPOINT_ADDRESS); | |
if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_IO_HW_BREAKPOINT) { | |
AsmWriteDr7 (0x20000480); | |
AsmWriteCr4 (Cr4 | BIT3); | |
// | |
// Do an IN from IO_PORT_BREAKPOINT_ADDRESS to generate a HW breakpoint until the port | |
// returns a read value other than DEBUG_AGENT_IMAGE_WAIT | |
// | |
do { | |
DebugAgentStatus = IoRead8 (IO_PORT_BREAKPOINT_ADDRESS); | |
} while (DebugAgentStatus == DEBUG_AGENT_IMAGE_WAIT); | |
} else if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3) { | |
// | |
// Generate a software break point. | |
// | |
CpuBreakpoint (); | |
} | |
// | |
// Restore Debug Register State only when Host didn't change it inside exception handler. | |
// E.g.: User halts the target and sets the HW breakpoint while target is | |
// in the above exception handler | |
// | |
NewDr7 = AsmReadDr7 () | BIT10; // H/w sets bit 10, some simulators don't | |
if (!IsDrxEnabled (0, NewDr7) && ((AsmReadDr0 () == 0) || (AsmReadDr0 () == Signature))) { | |
// | |
// If user changed Dr3 (by setting HW bp in the above exception handler, | |
// we will not set Dr0 to 0 in GO/STEP handler because the break cause is not IMAGE_LOAD/_UNLOAD. | |
// | |
AsmWriteDr0 (Dr0); | |
} | |
if (!IsDrxEnabled (1, NewDr7) && (AsmReadDr1 () == (UINTN)ImageContext->PdbPointer)) { | |
AsmWriteDr1 (Dr1); | |
} | |
if (!IsDrxEnabled (2, NewDr7) && (AsmReadDr2 () == (UINTN)ImageContext)) { | |
AsmWriteDr2 (Dr2); | |
} | |
if (!IsDrxEnabled (3, NewDr7) && (AsmReadDr3 () == IO_PORT_BREAKPOINT_ADDRESS)) { | |
AsmWriteDr3 (Dr3); | |
} | |
if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_IO_HW_BREAKPOINT) { | |
if (AsmReadCr4 () == (Cr4 | BIT3)) { | |
AsmWriteCr4 (Cr4); | |
} | |
if (NewDr7 == 0x20000480) { | |
AsmWriteDr7 (Dr7); | |
} | |
} else if (LoadImageMethod == DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3) { | |
if (NewDr7 == BIT10) { | |
AsmWriteDr7 (Dr7); | |
} | |
} | |
// | |
// Restore original IDT entry for INT1 if it was hooked. | |
// | |
if (IdtEntryHooked) { | |
RestoreIdtEntry1 (&IdtDescriptor, &OriginalIdtEntry); | |
} | |
// | |
// Restore the interrupt state | |
// | |
SetInterruptState (InterruptState); | |
} | |
/** | |
Performs additional actions after a PE/COFF image has been loaded and relocated. | |
@param ImageContext Pointer to the image context structure that describes the | |
PE/COFF image that has already been loaded and relocated. | |
**/ | |
VOID | |
EFIAPI | |
PeCoffLoaderRelocateImageExtraAction ( | |
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext | |
) | |
{ | |
PeCoffLoaderExtraActionCommon (ImageContext, IMAGE_LOAD_SIGNATURE); | |
} | |
/** | |
Performs additional actions just before a PE/COFF image is unloaded. Any resources | |
that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed. | |
@param ImageContext Pointer to the image context structure that describes the | |
PE/COFF image that is being unloaded. | |
**/ | |
VOID | |
EFIAPI | |
PeCoffLoaderUnloadImageExtraAction ( | |
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext | |
) | |
{ | |
PeCoffLoaderExtraActionCommon (ImageContext, IMAGE_UNLOAD_SIGNATURE); | |
} |