Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng <star.zeng@intel.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@14896 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			199 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			199 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Set a IDT entry for debug purpose
 | |
| 
 | |
|   Set a IDT entry for interrupt vector 3 for debug purpose for x64 platform
 | |
| 
 | |
| Copyright (c) 2006 - 2013, 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 "ScriptExecute.h"
 | |
| 
 | |
| #define IA32_PG_P                   BIT0
 | |
| #define IA32_PG_RW                  BIT1
 | |
| #define IA32_PG_PS                  BIT7
 | |
| 
 | |
| UINT64                             mPhyMask;
 | |
| VOID                               *mOriginalHandler;
 | |
| UINTN                              mS3NvsPageTableAddress;
 | |
| 
 | |
| /**
 | |
|   Page fault handler.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| PageFaultHandlerHook (
 | |
|   VOID
 | |
|   );
 | |
| 
 | |
| /**
 | |
|   Hook IDT with our page fault handler so that the on-demand paging works on page fault.
 | |
| 
 | |
|   @param  IdtEntry  a pointer to IDT entry
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| HookPageFaultHandler (
 | |
|   IN IA32_IDT_GATE_DESCRIPTOR                   *IdtEntry
 | |
|   )
 | |
| {
 | |
|   UINT32         RegEax;
 | |
|   UINT8          PhysicalAddressBits;
 | |
|   UINTN          PageFaultHandlerHookAddress;
 | |
| 
 | |
|   AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
 | |
|   if (RegEax >= 0x80000008) {
 | |
|     AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
 | |
|     PhysicalAddressBits = (UINT8) RegEax;
 | |
|   } else {
 | |
|     PhysicalAddressBits = 36;
 | |
|   }
 | |
|   mPhyMask = LShiftU64 (1, PhysicalAddressBits) - 1;
 | |
|   mPhyMask &= (1ull << 48) - SIZE_4KB;
 | |
| 
 | |
|   //
 | |
|   // Set Page Fault entry to catch >4G access
 | |
|   //
 | |
|   PageFaultHandlerHookAddress = (UINTN)PageFaultHandlerHook;
 | |
|   mOriginalHandler = (VOID *)(UINTN)(LShiftU64 (IdtEntry->Bits.OffsetUpper, 32) + IdtEntry->Bits.OffsetLow + (IdtEntry->Bits.OffsetHigh << 16));
 | |
|   IdtEntry->Bits.OffsetLow      = (UINT16)PageFaultHandlerHookAddress;
 | |
|   IdtEntry->Bits.Selector       = (UINT16)AsmReadCs ();
 | |
|   IdtEntry->Bits.Reserved_0     = 0;
 | |
|   IdtEntry->Bits.GateType       = IA32_IDT_GATE_TYPE_INTERRUPT_32;
 | |
|   IdtEntry->Bits.OffsetHigh     = (UINT16)(PageFaultHandlerHookAddress >> 16);
 | |
|   IdtEntry->Bits.OffsetUpper    = (UINT32)(PageFaultHandlerHookAddress >> 32);
 | |
|   IdtEntry->Bits.Reserved_1     = 0;
 | |
| 
 | |
|   if (mPage1GSupport) {
 | |
|     mS3NvsPageTableAddress = (UINTN)(AsmReadCr3 () & mPhyMask) + EFI_PAGES_TO_SIZE(2);
 | |
|   }else {
 | |
|     mS3NvsPageTableAddress = (UINTN)(AsmReadCr3 () & mPhyMask) + EFI_PAGES_TO_SIZE(6);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Set a IDT entry for interrupt vector 3 for debug purpose.
 | |
| 
 | |
|   @param  AcpiS3Context  a pointer to a structure of ACPI_S3_CONTEXT
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SetIdtEntry (
 | |
|   IN ACPI_S3_CONTEXT     *AcpiS3Context
 | |
|   )
 | |
| {
 | |
|   IA32_IDT_GATE_DESCRIPTOR                      *IdtEntry;
 | |
|   IA32_DESCRIPTOR                               *IdtDescriptor;
 | |
|   UINTN                                         S3DebugBuffer;
 | |
|   EFI_STATUS                                    Status;
 | |
| 
 | |
|   //
 | |
|   // Restore IDT for debug
 | |
|   //
 | |
|   IdtDescriptor = (IA32_DESCRIPTOR *) (UINTN) (AcpiS3Context->IdtrProfile);
 | |
|   AsmWriteIdtr (IdtDescriptor);
 | |
| 
 | |
|   //
 | |
|   // Setup the default CPU exception handlers
 | |
|   //
 | |
|   Status = InitializeCpuExceptionHandlers (NULL);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   DEBUG_CODE (
 | |
|     //
 | |
|     // Update IDT entry INT3 if the instruction is valid in it
 | |
|     //
 | |
|     S3DebugBuffer = (UINTN) (AcpiS3Context->S3DebugBufferAddress);
 | |
|     if (*(UINTN *)S3DebugBuffer != (UINTN) -1) {
 | |
|       IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)(IdtDescriptor->Base + (3 * sizeof (IA32_IDT_GATE_DESCRIPTOR)));
 | |
|       IdtEntry->Bits.OffsetLow      = (UINT16)S3DebugBuffer;
 | |
|       IdtEntry->Bits.Selector       = (UINT16)AsmReadCs ();
 | |
|       IdtEntry->Bits.Reserved_0     = 0;
 | |
|       IdtEntry->Bits.GateType       = IA32_IDT_GATE_TYPE_INTERRUPT_32;
 | |
|       IdtEntry->Bits.OffsetHigh     = (UINT16)(S3DebugBuffer >> 16);
 | |
|       IdtEntry->Bits.OffsetUpper    = (UINT32)(S3DebugBuffer >> 32);
 | |
|       IdtEntry->Bits.Reserved_1     = 0;
 | |
|     }
 | |
|   );
 | |
| 
 | |
|   IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *)(IdtDescriptor->Base + (14 * sizeof (IA32_IDT_GATE_DESCRIPTOR)));
 | |
|   HookPageFaultHandler (IdtEntry);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get new page address.
 | |
| 
 | |
|   @param  PageNum  new page number needed
 | |
| 
 | |
|   @return new page address
 | |
| **/
 | |
| UINTN
 | |
| GetNewPage (
 | |
|   IN UINTN  PageNum
 | |
|   )
 | |
| {
 | |
|   UINTN  NewPage;
 | |
|   NewPage = mS3NvsPageTableAddress;
 | |
|   ZeroMem ((VOID *)NewPage, EFI_PAGES_TO_SIZE(PageNum));
 | |
|   mS3NvsPageTableAddress += EFI_PAGES_TO_SIZE(PageNum);
 | |
|   return NewPage;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   The page fault handler that on-demand read >4G memory/MMIO.
 | |
|   
 | |
|   @retval TRUE     The page fault is correctly handled.
 | |
|   @retval FALSE    The page fault is not handled and is passed through to original handler.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| EFIAPI
 | |
| PageFaultHandler (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINT64         *PageTable;
 | |
|   UINT64         PFAddress;
 | |
|   UINTN          PTIndex;
 | |
| 
 | |
|   PFAddress = AsmReadCr2 ();
 | |
|   DEBUG ((EFI_D_ERROR, "BootScript - PageFaultHandler: Cr2 - %lx\n", PFAddress));
 | |
| 
 | |
|   if (PFAddress >= mPhyMask + SIZE_4KB) {
 | |
|     return FALSE;
 | |
|   }
 | |
|   PFAddress &= mPhyMask;
 | |
| 
 | |
|   PageTable = (UINT64*)(UINTN)(AsmReadCr3 () & mPhyMask);
 | |
| 
 | |
|   PTIndex = BitFieldRead64 (PFAddress, 39, 47);
 | |
|   // PML4E
 | |
|   if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
 | |
|     PageTable[PTIndex] = GetNewPage (1) | IA32_PG_P | IA32_PG_RW;
 | |
|   }
 | |
|   PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & mPhyMask);
 | |
|   PTIndex = BitFieldRead64 (PFAddress, 30, 38);
 | |
|   // PDPTE
 | |
|   if (mPage1GSupport) {
 | |
|     PageTable[PTIndex] = PFAddress | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;
 | |
|   } else {
 | |
|     if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
 | |
|       PageTable[PTIndex] = GetNewPage (1) | IA32_PG_P | IA32_PG_RW;
 | |
|     }
 | |
|     PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & mPhyMask);
 | |
|     PTIndex = BitFieldRead64 (PFAddress, 21, 29);
 | |
|     // PD
 | |
|     PageTable[PTIndex] = PFAddress | IA32_PG_P | IA32_PG_RW | IA32_PG_PS;
 | |
|   }
 | |
| 
 | |
|   return TRUE;
 | |
| }
 |