mirror of https://github.com/acidanthera/audk.git
270 lines
7.5 KiB
C
270 lines
7.5 KiB
C
/** @file
|
|
PE/Coff Extra Action library instances.
|
|
|
|
Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php.
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
**/
|
|
|
|
#include <Base.h>
|
|
#include <Library/PeCoffExtraActionLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/IoLib.h>
|
|
#include <Library/PcdLib.h>
|
|
|
|
#include <ImageDebugSupport.h>
|
|
|
|
#define DEBUG_LOAD_IMAGE_METHOD_IO_HW_BREAKPOINT 1
|
|
#define DEBUG_LOAD_IMAGE_METHOD_SOFT_INT3 2
|
|
|
|
/**
|
|
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));
|
|
}
|
|
|
|
/**
|
|
Performs additional actions after a PE/COFF image has been loaded and relocated.
|
|
|
|
If ImageContext is NULL, then ASSERT().
|
|
|
|
@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
|
|
)
|
|
{
|
|
BOOLEAN InterruptState;
|
|
UINTN Dr0;
|
|
UINTN Dr1;
|
|
UINTN Dr2;
|
|
UINTN Dr3;
|
|
UINTN Dr7;
|
|
UINTN Cr4;
|
|
UINTN NewDr7;
|
|
UINT8 LoadImageMethod;
|
|
UINT8 DebugAgentStatus;
|
|
|
|
ASSERT (ImageContext != NULL);
|
|
|
|
if (ImageContext->PdbPointer != NULL) {
|
|
DEBUG((EFI_D_ERROR, " PDB = %a\n", ImageContext->PdbPointer));
|
|
}
|
|
|
|
//
|
|
// Disable interrupts and save the current interrupt state
|
|
//
|
|
InterruptState = SaveAndDisableInterrupts ();
|
|
|
|
//
|
|
// Save Debug Register State
|
|
//
|
|
Dr0 = AsmReadDr0 ();
|
|
Dr1 = AsmReadDr1 ();
|
|
Dr2 = AsmReadDr2 ();
|
|
Dr3 = AsmReadDr3 ();
|
|
Dr7 = AsmReadDr7 ();
|
|
Cr4 = AsmReadCr4 ();
|
|
|
|
//
|
|
// DR0 = IMAGE_LOAD_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 (0);
|
|
AsmWriteDr0 (IMAGE_LOAD_SIGNATURE);
|
|
AsmWriteDr1 ((UINTN)ImageContext->PdbPointer);
|
|
AsmWriteDr2 ((UINTN)ImageContext);
|
|
AsmWriteDr3 (IO_PORT_BREAKPOINT_ADDRESS);
|
|
|
|
LoadImageMethod = PcdGet8 (PcdDebugLoadImageMethod);
|
|
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 ();
|
|
if (!IsDrxEnabled (0, NewDr7)) {
|
|
AsmWriteDr0 (Dr0);
|
|
}
|
|
if (!IsDrxEnabled (1, NewDr7)) {
|
|
AsmWriteDr1 (Dr1);
|
|
}
|
|
if (!IsDrxEnabled (2, NewDr7)) {
|
|
AsmWriteDr2 (Dr2);
|
|
}
|
|
if (!IsDrxEnabled (3, NewDr7)) {
|
|
AsmWriteDr3 (Dr3);
|
|
}
|
|
if (AsmReadCr4 () == (Cr4 | BIT3)) {
|
|
AsmWriteCr4 (Cr4);
|
|
}
|
|
if (NewDr7 == 0x20000480) {
|
|
AsmWriteDr7 (Dr7);
|
|
}
|
|
//
|
|
// Restore the interrupt state
|
|
//
|
|
SetInterruptState (InterruptState);
|
|
}
|
|
|
|
/**
|
|
Performs additional actions just before a PE/COFF image is unloaded. Any resources
|
|
that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed.
|
|
|
|
If ImageContext is NULL, then ASSERT().
|
|
|
|
@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
|
|
)
|
|
{
|
|
BOOLEAN InterruptState;
|
|
UINTN Dr0;
|
|
UINTN Dr1;
|
|
UINTN Dr2;
|
|
UINTN Dr3;
|
|
UINTN Dr7;
|
|
UINTN Cr4;
|
|
UINTN NewDr7;
|
|
UINT8 LoadImageMethod;
|
|
UINT8 DebugAgentStatus;
|
|
|
|
ASSERT (ImageContext != NULL);
|
|
|
|
if (ImageContext->PdbPointer != NULL) {
|
|
DEBUG((EFI_D_ERROR, " PDB = %a\n", ImageContext->PdbPointer));
|
|
}
|
|
|
|
//
|
|
// Disable interrupts and save the current interrupt state
|
|
//
|
|
InterruptState = SaveAndDisableInterrupts ();
|
|
|
|
//
|
|
// Save Debug Register State
|
|
//
|
|
Dr0 = AsmReadDr0 ();
|
|
Dr1 = AsmReadDr1 ();
|
|
Dr2 = AsmReadDr2 ();
|
|
Dr3 = AsmReadDr3 ();
|
|
Dr7 = AsmReadDr7 ();
|
|
Cr4 = AsmReadCr4 ();
|
|
|
|
//
|
|
// DR0 = IMAGE_UNLOAD_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 (0);
|
|
AsmWriteDr0 (IMAGE_UNLOAD_SIGNATURE);
|
|
AsmWriteDr1 ((UINTN)ImageContext->PdbPointer);
|
|
AsmWriteDr2 ((UINTN)ImageContext);
|
|
AsmWriteDr3 (IO_PORT_BREAKPOINT_ADDRESS);
|
|
|
|
LoadImageMethod = PcdGet8 (PcdDebugLoadImageMethod);
|
|
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 ();
|
|
if (!IsDrxEnabled (0, NewDr7)) {
|
|
AsmWriteDr0 (Dr0);
|
|
}
|
|
if (!IsDrxEnabled (1, NewDr7)) {
|
|
AsmWriteDr1 (Dr1);
|
|
}
|
|
if (!IsDrxEnabled (2, NewDr7)) {
|
|
AsmWriteDr2 (Dr2);
|
|
}
|
|
if (!IsDrxEnabled (3, NewDr7)) {
|
|
AsmWriteDr3 (Dr3);
|
|
}
|
|
if (AsmReadCr4 () == (Cr4 | BIT3)) {
|
|
AsmWriteCr4 (Cr4);
|
|
}
|
|
if (NewDr7 == 0x20000480) {
|
|
AsmWriteDr7 (Dr7);
|
|
}
|
|
|
|
//
|
|
// Restore the interrupt state
|
|
//
|
|
SetInterruptState (InterruptState);
|
|
}
|