Home | History | Annotate | Download | only in Ia32
      1 /** @file
      2 Page table manipulation functions for IA-32 processors
      3 
      4 Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "PiSmmCpuDxeSmm.h"
     16 
     17 SPIN_LOCK                           mPFLock;
     18 
     19 /**
     20   Create PageTable for SMM use.
     21 
     22   @return     PageTable Address
     23 
     24 **/
     25 UINT32
     26 SmmInitPageTable (
     27   VOID
     28   )
     29 {
     30   UINTN                             PageFaultHandlerHookAddress;
     31   IA32_IDT_GATE_DESCRIPTOR          *IdtEntry;
     32 
     33   //
     34   // Initialize spin lock
     35   //
     36   InitializeSpinLock (&mPFLock);
     37 
     38   if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
     39     //
     40     // Set own Page Fault entry instead of the default one, because SMM Profile
     41     // feature depends on IRET instruction to do Single Step
     42     //
     43     PageFaultHandlerHookAddress = (UINTN)PageFaultIdtHandlerSmmProfile;
     44     IdtEntry  = (IA32_IDT_GATE_DESCRIPTOR *) gcSmiIdtr.Base;
     45     IdtEntry += EXCEPT_IA32_PAGE_FAULT;
     46     IdtEntry->Bits.OffsetLow      = (UINT16)PageFaultHandlerHookAddress;
     47     IdtEntry->Bits.Reserved_0     = 0;
     48     IdtEntry->Bits.GateType       = IA32_IDT_GATE_TYPE_INTERRUPT_32;
     49     IdtEntry->Bits.OffsetHigh     = (UINT16)(PageFaultHandlerHookAddress >> 16);
     50   } else {
     51     //
     52     // Register SMM Page Fault Handler
     53     //
     54     SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_PAGE_FAULT, SmiPFHandler);
     55   }
     56 
     57   //
     58   // Additional SMM IDT initialization for SMM stack guard
     59   //
     60   if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
     61     InitializeIDTSmmStackGuard ();
     62   }
     63   return Gen4GPageTable (0, TRUE);
     64 }
     65 
     66 /**
     67   Page Fault handler for SMM use.
     68 
     69 **/
     70 VOID
     71 SmiDefaultPFHandler (
     72   VOID
     73   )
     74 {
     75   CpuDeadLoop ();
     76 }
     77 
     78 /**
     79   ThePage Fault handler wrapper for SMM use.
     80 
     81   @param  InterruptType    Defines the type of interrupt or exception that
     82                            occurred on the processor.This parameter is processor architecture specific.
     83   @param  SystemContext    A pointer to the processor context when
     84                            the interrupt occurred on the processor.
     85 **/
     86 VOID
     87 EFIAPI
     88 SmiPFHandler (
     89     IN EFI_EXCEPTION_TYPE   InterruptType,
     90     IN EFI_SYSTEM_CONTEXT   SystemContext
     91   )
     92 {
     93   UINTN             PFAddress;
     94 
     95   ASSERT (InterruptType == EXCEPT_IA32_PAGE_FAULT);
     96 
     97   AcquireSpinLock (&mPFLock);
     98 
     99   PFAddress = AsmReadCr2 ();
    100 
    101   if ((FeaturePcdGet (PcdCpuSmmStackGuard)) &&
    102       (PFAddress >= mCpuHotPlugData.SmrrBase) &&
    103       (PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))) {
    104     DEBUG ((EFI_D_ERROR, "SMM stack overflow!\n"));
    105     CpuDeadLoop ();
    106   }
    107 
    108   //
    109   // If a page fault occurs in SMM range
    110   //
    111   if ((PFAddress < mCpuHotPlugData.SmrrBase) ||
    112       (PFAddress >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) {
    113     if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {
    114       DEBUG ((EFI_D_ERROR, "Code executed on IP(0x%x) out of SMM range after SMM is locked!\n", PFAddress));
    115       DEBUG_CODE (
    116         DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp);
    117       );
    118       CpuDeadLoop ();
    119     }
    120   }
    121 
    122   if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
    123     SmmProfilePFHandler (
    124       SystemContext.SystemContextIa32->Eip,
    125       SystemContext.SystemContextIa32->ExceptionData
    126       );
    127   } else {
    128     SmiDefaultPFHandler ();
    129   }
    130 
    131   ReleaseSpinLock (&mPFLock);
    132 }
    133