mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-31 17:09:09 +00:00 
			
		
		
		
	 18b144ea42
			
		
	
	
		18b144ea42
		
	
	
	
	
		
			
			git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10867 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			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);
 | |
| }
 |