| /** @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); | |
| } |