Home | History | Annotate | Download | only in SmmBaseHelper
      1 /** @file
      2   SMM Base Helper SMM driver.
      3 
      4   This driver is the counterpart of the SMM Base On SMM Base2 Thunk driver. It
      5   provides helping services in SMM to the SMM Base On SMM Base2 Thunk driver.
      6 
      7   Caution: This module requires additional review when modified.
      8   This driver will have external input - communicate buffer in SMM mode.
      9   This external input must be validated carefully to avoid security issue like
     10   buffer overflow, integer overflow.
     11 
     12   SmmHandlerEntry() will receive untrusted input and do validation.
     13 
     14   Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
     15   This program and the accompanying materials
     16   are licensed and made available under the terms and conditions of the BSD License
     17   which accompanies this distribution.  The full text of the license may be found at
     18   http://opensource.org/licenses/bsd-license.php
     19 
     20   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     21   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     22 
     23 **/
     24 
     25 #include <PiSmm.h>
     26 #include <Library/DebugLib.h>
     27 #include <Library/UefiBootServicesTableLib.h>
     28 #include <Library/SmmServicesTableLib.h>
     29 #include <Library/BaseLib.h>
     30 #include <Library/BaseMemoryLib.h>
     31 #include <Library/PeCoffLib.h>
     32 #include <Library/DevicePathLib.h>
     33 #include <Library/CacheMaintenanceLib.h>
     34 #include <Library/MemoryAllocationLib.h>
     35 #include <Library/SynchronizationLib.h>
     36 #include <Library/CpuLib.h>
     37 #include <Library/SmmMemLib.h>
     38 #include <Guid/SmmBaseThunkCommunication.h>
     39 #include <Protocol/SmmBaseHelperReady.h>
     40 #include <Protocol/SmmCpu.h>
     41 #include <Protocol/LoadedImage.h>
     42 #include <Protocol/SmmCpuSaveState.h>
     43 #include <Protocol/MpService.h>
     44 #include <Protocol/LoadPe32Image.h>
     45 #include <Protocol/SmmReadyToLock.h>
     46 
     47 /**
     48   Register SMM image to SMRAM profile.
     49 
     50   @param[in] FilePath           File path of the image.
     51   @param[in] ImageBuffer        Image base address.
     52   @param[in] NumberOfPage       Number of page.
     53 
     54   @retval TRUE                  Register success.
     55   @retval FALSE                 Register fail.
     56 
     57 **/
     58 BOOLEAN
     59 RegisterSmramProfileImage (
     60   IN EFI_DEVICE_PATH_PROTOCOL   *FilePath,
     61   IN PHYSICAL_ADDRESS           ImageBuffer,
     62   IN UINTN                      NumberOfPage
     63   );
     64 
     65 /**
     66   Unregister SMM image from SMRAM profile.
     67 
     68   @param[in] FilePath           File path of the image.
     69   @param[in] ImageBuffer        Image base address.
     70   @param[in] NumberOfPage       Number of page.
     71 
     72   @retval TRUE                  Unregister success.
     73   @retval FALSE                 Unregister fail.
     74 
     75 **/
     76 BOOLEAN
     77 UnregisterSmramProfileImage (
     78   IN EFI_DEVICE_PATH_PROTOCOL   *FilePath,
     79   IN PHYSICAL_ADDRESS           ImageBuffer,
     80   IN UINTN                      NumberOfPage
     81   );
     82 
     83 ///
     84 /// Structure for tracking paired information of registered Framework SMI handler
     85 /// and correpsonding dispatch handle for SMI handler thunk.
     86 ///
     87 typedef struct {
     88   LIST_ENTRY                    Link;
     89   EFI_HANDLE                    DispatchHandle;
     90   EFI_HANDLE                    SmmImageHandle;
     91   EFI_SMM_CALLBACK_ENTRY_POINT  CallbackAddress;
     92   VOID                          *CommunicationBuffer;
     93   UINTN                         *SourceSize;
     94 } CALLBACK_INFO;
     95 
     96 typedef struct {
     97   ///
     98   /// PI SMM CPU Save State register index
     99   ///
    100   EFI_SMM_SAVE_STATE_REGISTER   Register;
    101   ///
    102   /// Offset in Framework SMST
    103   ///
    104   UINTN                         Offset;
    105 } CPU_SAVE_STATE_CONVERSION;
    106 
    107 #define CPU_SAVE_STATE_GET_OFFSET(Field)  (UINTN)(&(((EFI_SMM_CPU_SAVE_STATE *) 0)->Ia32SaveState.Field))
    108 
    109 
    110 EFI_HANDLE                         mDispatchHandle;
    111 EFI_SMM_CPU_PROTOCOL               *mSmmCpu;
    112 EFI_PE32_IMAGE_PROTOCOL            *mLoadPe32Image;
    113 EFI_GUID                           mEfiSmmCpuIoGuid = EFI_SMM_CPU_IO_GUID;
    114 EFI_SMM_BASE_HELPER_READY_PROTOCOL *mSmmBaseHelperReady;
    115 EFI_SMM_SYSTEM_TABLE               *mFrameworkSmst;
    116 UINTN                              mNumberOfProcessors;
    117 BOOLEAN                            mLocked = FALSE;
    118 BOOLEAN                            mPageTableHookEnabled;
    119 BOOLEAN                            mHookInitialized;
    120 UINT64                             *mCpuStatePageTable;
    121 SPIN_LOCK                          mPFLock;
    122 UINT64                             mPhyMask;
    123 VOID                               *mOriginalHandler;
    124 EFI_SMM_CPU_SAVE_STATE             *mShadowSaveState;
    125 
    126 LIST_ENTRY mCallbackInfoListHead = INITIALIZE_LIST_HEAD_VARIABLE (mCallbackInfoListHead);
    127 
    128 CPU_SAVE_STATE_CONVERSION mCpuSaveStateConvTable[] = {
    129   {EFI_SMM_SAVE_STATE_REGISTER_LDTBASE  , CPU_SAVE_STATE_GET_OFFSET(LDTBase)},
    130   {EFI_SMM_SAVE_STATE_REGISTER_ES       , CPU_SAVE_STATE_GET_OFFSET(ES)},
    131   {EFI_SMM_SAVE_STATE_REGISTER_CS       , CPU_SAVE_STATE_GET_OFFSET(CS)},
    132   {EFI_SMM_SAVE_STATE_REGISTER_SS       , CPU_SAVE_STATE_GET_OFFSET(SS)},
    133   {EFI_SMM_SAVE_STATE_REGISTER_DS       , CPU_SAVE_STATE_GET_OFFSET(DS)},
    134   {EFI_SMM_SAVE_STATE_REGISTER_FS       , CPU_SAVE_STATE_GET_OFFSET(FS)},
    135   {EFI_SMM_SAVE_STATE_REGISTER_GS       , CPU_SAVE_STATE_GET_OFFSET(GS)},
    136   {EFI_SMM_SAVE_STATE_REGISTER_TR_SEL   , CPU_SAVE_STATE_GET_OFFSET(TR)},
    137   {EFI_SMM_SAVE_STATE_REGISTER_DR7      , CPU_SAVE_STATE_GET_OFFSET(DR7)},
    138   {EFI_SMM_SAVE_STATE_REGISTER_DR6      , CPU_SAVE_STATE_GET_OFFSET(DR6)},
    139   {EFI_SMM_SAVE_STATE_REGISTER_RAX      , CPU_SAVE_STATE_GET_OFFSET(EAX)},
    140   {EFI_SMM_SAVE_STATE_REGISTER_RBX      , CPU_SAVE_STATE_GET_OFFSET(EBX)},
    141   {EFI_SMM_SAVE_STATE_REGISTER_RCX      , CPU_SAVE_STATE_GET_OFFSET(ECX)},
    142   {EFI_SMM_SAVE_STATE_REGISTER_RDX      , CPU_SAVE_STATE_GET_OFFSET(EDX)},
    143   {EFI_SMM_SAVE_STATE_REGISTER_RSP      , CPU_SAVE_STATE_GET_OFFSET(ESP)},
    144   {EFI_SMM_SAVE_STATE_REGISTER_RBP      , CPU_SAVE_STATE_GET_OFFSET(EBP)},
    145   {EFI_SMM_SAVE_STATE_REGISTER_RSI      , CPU_SAVE_STATE_GET_OFFSET(ESI)},
    146   {EFI_SMM_SAVE_STATE_REGISTER_RDI      , CPU_SAVE_STATE_GET_OFFSET(EDI)},
    147   {EFI_SMM_SAVE_STATE_REGISTER_RIP      , CPU_SAVE_STATE_GET_OFFSET(EIP)},
    148   {EFI_SMM_SAVE_STATE_REGISTER_RFLAGS   , CPU_SAVE_STATE_GET_OFFSET(EFLAGS)},
    149   {EFI_SMM_SAVE_STATE_REGISTER_CR0      , CPU_SAVE_STATE_GET_OFFSET(CR0)},
    150   {EFI_SMM_SAVE_STATE_REGISTER_CR3      , CPU_SAVE_STATE_GET_OFFSET(CR3)}
    151 };
    152 
    153 /**
    154   Page fault handler.
    155 
    156 **/
    157 VOID
    158 PageFaultHandlerHook (
    159   VOID
    160   );
    161 
    162 /**
    163   Read CpuSaveStates from PI for Framework use.
    164 
    165   The function reads PI style CpuSaveStates of CpuIndex-th CPU for Framework driver use. If
    166   ToRead is specified, the CpuSaveStates will be copied to ToRead, otherwise copied to
    167   mFrameworkSmst->CpuSaveState[CpuIndex].
    168 
    169   @param[in]      CpuIndex        The zero-based CPU index.
    170   @param[in, out] ToRead          If not NULL, CpuSaveStates will be copied to it.
    171 
    172 **/
    173 VOID
    174 ReadCpuSaveState (
    175   IN     UINTN                   CpuIndex,
    176   IN OUT EFI_SMM_CPU_SAVE_STATE  *ToRead
    177   )
    178 {
    179   EFI_STATUS Status;
    180   UINTN Index;
    181   EFI_SMM_CPU_STATE *State;
    182   EFI_SMI_CPU_SAVE_STATE *SaveState;
    183 
    184   State = (EFI_SMM_CPU_STATE *)gSmst->CpuSaveState[CpuIndex];
    185   if (ToRead != NULL) {
    186     SaveState = &ToRead->Ia32SaveState;
    187   } else {
    188     SaveState = &mFrameworkSmst->CpuSaveState[CpuIndex].Ia32SaveState;
    189   }
    190 
    191   //
    192   // Note that SMBASE/SMMRevId/IORestart/AutoHALTRestart are in same location in IA32 and X64 CPU Save State Map.
    193   //
    194   SaveState->SMBASE = State->x86.SMBASE;
    195   SaveState->SMMRevId = State->x86.SMMRevId;
    196   SaveState->IORestart = State->x86.IORestart;
    197   SaveState->AutoHALTRestart = State->x86.AutoHALTRestart;
    198 
    199   for (Index = 0; Index < sizeof (mCpuSaveStateConvTable) / sizeof (CPU_SAVE_STATE_CONVERSION); Index++) {
    200     ///
    201     /// Try to use SMM CPU Protocol to access CPU save states if possible
    202     ///
    203     Status = mSmmCpu->ReadSaveState (
    204                         mSmmCpu,
    205                         (UINTN)sizeof (UINT32),
    206                         mCpuSaveStateConvTable[Index].Register,
    207                         CpuIndex,
    208                         ((UINT8 *)SaveState) + mCpuSaveStateConvTable[Index].Offset
    209                         );
    210     ASSERT_EFI_ERROR (Status);
    211   }
    212 }
    213 
    214 /**
    215   Write CpuSaveStates from Framework into PI.
    216 
    217   The function writes back CpuSaveStates of CpuIndex-th CPU from PI to Framework. If
    218   ToWrite is specified, it contains the CpuSaveStates to write from, otherwise CpuSaveStates
    219   to write from mFrameworkSmst->CpuSaveState[CpuIndex].
    220 
    221   @param[in] CpuIndex      The zero-based CPU index.
    222   @param[in] ToWrite       If not NULL, CpuSaveStates to write from.
    223 
    224 **/
    225 VOID
    226 WriteCpuSaveState (
    227   IN UINTN                   CpuIndex,
    228   IN EFI_SMM_CPU_SAVE_STATE  *ToWrite
    229   )
    230 {
    231   UINTN                  Index;
    232   EFI_SMM_CPU_STATE      *State;
    233   EFI_SMI_CPU_SAVE_STATE *SaveState;
    234 
    235   State = (EFI_SMM_CPU_STATE *)gSmst->CpuSaveState[CpuIndex];
    236 
    237   if (ToWrite != NULL) {
    238     SaveState = &ToWrite->Ia32SaveState;
    239   } else {
    240     SaveState = &mFrameworkSmst->CpuSaveState[CpuIndex].Ia32SaveState;
    241   }
    242 
    243   //
    244   // SMMRevId is read-only.
    245   // Note that SMBASE/IORestart/AutoHALTRestart are in same location in IA32 and X64 CPU Save State Map.
    246   //
    247   State->x86.SMBASE = SaveState->SMBASE;
    248   State->x86.IORestart = SaveState->IORestart;
    249   State->x86.AutoHALTRestart = SaveState->AutoHALTRestart;
    250 
    251   for (Index = 0; Index < sizeof (mCpuSaveStateConvTable) / sizeof (CPU_SAVE_STATE_CONVERSION); Index++) {
    252     mSmmCpu->WriteSaveState (
    253                mSmmCpu,
    254                (UINTN)sizeof (UINT32),
    255                mCpuSaveStateConvTable[Index].Register,
    256                CpuIndex,
    257                ((UINT8 *)SaveState) +
    258                mCpuSaveStateConvTable[Index].Offset
    259                );
    260   }
    261 }
    262 
    263 /**
    264   Read or write a page that contains CpuSaveStates. Read is from PI to Framework.
    265   Write is from Framework to PI.
    266 
    267   This function reads or writes a page that contains CpuSaveStates. The page contains Framework
    268   CpuSaveStates. On read, it reads PI style CpuSaveStates and fill the page up. On write, it
    269   writes back from the page content to PI CpuSaveStates struct.
    270   The first Framework CpuSaveStates (for CPU 0) is from mFrameworkSmst->CpuSaveState which is
    271   page aligned. Because Framework CpuSaveStates are continuous, we can know which CPUs' SaveStates
    272   are in the page start from PageAddress.
    273 
    274   @param[in] PageAddress   The base address for a page.
    275   @param[in] IsRead        TRUE for Read, FALSE for Write.
    276 
    277 **/
    278 VOID
    279 ReadWriteCpuStatePage (
    280   IN UINT64  PageAddress,
    281   IN BOOLEAN IsRead
    282   )
    283 {
    284   UINTN          FirstSSIndex;   // Index of first CpuSaveState in the page
    285   UINTN          LastSSIndex;    // Index of last CpuSaveState in the page
    286   BOOLEAN        FirstSSAligned; // Whether first CpuSaveState is page-aligned
    287   BOOLEAN        LastSSAligned;  // Whether the end of last CpuSaveState is page-aligned
    288   UINTN          ClippedSize;
    289   UINTN          CpuIndex;
    290 
    291   FirstSSIndex = ((UINTN)PageAddress - (UINTN)mFrameworkSmst->CpuSaveState) / sizeof (EFI_SMM_CPU_SAVE_STATE);
    292   FirstSSAligned = TRUE;
    293   if (((UINTN)PageAddress - (UINTN)mFrameworkSmst->CpuSaveState) % sizeof (EFI_SMM_CPU_SAVE_STATE) != 0) {
    294     FirstSSIndex++;
    295     FirstSSAligned = FALSE;
    296   }
    297   LastSSIndex = ((UINTN)PageAddress + SIZE_4KB - (UINTN)mFrameworkSmst->CpuSaveState - 1) / sizeof (EFI_SMM_CPU_SAVE_STATE);
    298   LastSSAligned = TRUE;
    299   if (((UINTN)PageAddress + SIZE_4KB - (UINTN)mFrameworkSmst->CpuSaveState) % sizeof (EFI_SMM_CPU_SAVE_STATE) != 0) {
    300     LastSSIndex--;
    301     LastSSAligned = FALSE;
    302   }
    303   for (CpuIndex = FirstSSIndex; CpuIndex <= LastSSIndex && CpuIndex < mNumberOfProcessors; CpuIndex++) {
    304     if (IsRead) {
    305       ReadCpuSaveState (CpuIndex, NULL);
    306     } else {
    307       WriteCpuSaveState (CpuIndex, NULL);
    308     }
    309   }
    310   if (!FirstSSAligned) {
    311     ReadCpuSaveState (FirstSSIndex - 1, mShadowSaveState);
    312     ClippedSize = (UINTN)&mFrameworkSmst->CpuSaveState[FirstSSIndex] & (SIZE_4KB - 1);
    313     if (IsRead) {
    314       CopyMem ((VOID*)(UINTN)PageAddress, (VOID*)((UINTN)(mShadowSaveState + 1) - ClippedSize), ClippedSize);
    315     } else {
    316       CopyMem ((VOID*)((UINTN)(mShadowSaveState + 1) - ClippedSize), (VOID*)(UINTN)PageAddress, ClippedSize);
    317       WriteCpuSaveState (FirstSSIndex - 1, mShadowSaveState);
    318     }
    319   }
    320   if (!LastSSAligned && LastSSIndex + 1 < mNumberOfProcessors) {
    321     ReadCpuSaveState (LastSSIndex + 1, mShadowSaveState);
    322     ClippedSize = SIZE_4KB - ((UINTN)&mFrameworkSmst->CpuSaveState[LastSSIndex + 1] & (SIZE_4KB - 1));
    323     if (IsRead) {
    324       CopyMem (&mFrameworkSmst->CpuSaveState[LastSSIndex + 1], mShadowSaveState, ClippedSize);
    325     } else {
    326       CopyMem (mShadowSaveState, &mFrameworkSmst->CpuSaveState[LastSSIndex + 1], ClippedSize);
    327       WriteCpuSaveState (LastSSIndex + 1, mShadowSaveState);
    328     }
    329   }
    330 }
    331 
    332 /**
    333   The page fault handler that on-demand read PI CpuSaveStates for framework use. If the fault
    334   is not targeted to mFrameworkSmst->CpuSaveState range, the function will return FALSE to let
    335   PageFaultHandlerHook know it needs to pass the fault over to original page fault handler.
    336 
    337   @retval TRUE     The page fault is correctly handled.
    338   @retval FALSE    The page fault is not handled and is passed through to original handler.
    339 
    340 **/
    341 BOOLEAN
    342 PageFaultHandler (
    343   VOID
    344   )
    345 {
    346   BOOLEAN        IsHandled;
    347   UINT64         PFAddress;
    348   UINTN          NumCpuStatePages;
    349 
    350   ASSERT (mPageTableHookEnabled);
    351   AcquireSpinLock (&mPFLock);
    352 
    353   PFAddress = AsmReadCr2 ();
    354   NumCpuStatePages = EFI_SIZE_TO_PAGES (mNumberOfProcessors * sizeof (EFI_SMM_CPU_SAVE_STATE));
    355   IsHandled = FALSE;
    356   if (((UINTN)mFrameworkSmst->CpuSaveState & ~(SIZE_2MB-1)) == (PFAddress & ~(SIZE_2MB-1))) {
    357     if ((UINTN)mFrameworkSmst->CpuSaveState <= PFAddress &&
    358         PFAddress < (UINTN)mFrameworkSmst->CpuSaveState + EFI_PAGES_TO_SIZE (NumCpuStatePages)
    359         ) {
    360       mCpuStatePageTable[BitFieldRead64 (PFAddress, 12, 20)] |= BIT0 | BIT1; // present and rw
    361       CpuFlushTlb ();
    362       ReadWriteCpuStatePage (PFAddress & ~(SIZE_4KB-1), TRUE);
    363       IsHandled = TRUE;
    364     } else {
    365       ASSERT (FALSE);
    366     }
    367   }
    368 
    369   ReleaseSpinLock (&mPFLock);
    370   return IsHandled;
    371 }
    372 
    373 /**
    374   Write back the dirty Framework CpuSaveStates to PI.
    375 
    376   The function scans the page table for dirty pages in mFrameworkSmst->CpuSaveState
    377   to write back to PI CpuSaveStates. It is meant to be called on each SmmBaseHelper SMI
    378   callback after Framework handler is called.
    379 
    380 **/
    381 VOID
    382 WriteBackDirtyPages (
    383   VOID
    384   )
    385 {
    386   UINTN  NumCpuStatePages;
    387   UINTN  PTIndex;
    388   UINTN  PTStartIndex;
    389   UINTN  PTEndIndex;
    390 
    391   NumCpuStatePages = EFI_SIZE_TO_PAGES (mNumberOfProcessors * sizeof (EFI_SMM_CPU_SAVE_STATE));
    392   PTStartIndex = (UINTN)BitFieldRead64 ((UINT64) (UINTN) mFrameworkSmst->CpuSaveState, 12, 20);
    393   PTEndIndex   = (UINTN)BitFieldRead64 ((UINT64) (UINTN) mFrameworkSmst->CpuSaveState + EFI_PAGES_TO_SIZE(NumCpuStatePages) - 1, 12, 20);
    394   for (PTIndex = PTStartIndex; PTIndex <= PTEndIndex; PTIndex++) {
    395     if ((mCpuStatePageTable[PTIndex] & (BIT0|BIT6)) == (BIT0|BIT6)) { // present and dirty?
    396       ReadWriteCpuStatePage (mCpuStatePageTable[PTIndex] & mPhyMask, FALSE);
    397     }
    398   }
    399 }
    400 
    401 /**
    402   Hook IDT with our page fault handler so that the on-demand paging works on page fault.
    403 
    404   The function hooks the IDT with PageFaultHandlerHook to get on-demand paging work for
    405   PI<->Framework CpuSaveStates marshalling. It also saves original handler for pass-through
    406   purpose.
    407 
    408 **/
    409 VOID
    410 HookPageFaultHandler (
    411   VOID
    412   )
    413 {
    414   IA32_DESCRIPTOR           Idtr;
    415   IA32_IDT_GATE_DESCRIPTOR  *IdtGateDesc;
    416   UINT32                    OffsetUpper;
    417 
    418   InitializeSpinLock (&mPFLock);
    419 
    420   AsmReadIdtr (&Idtr);
    421   IdtGateDesc = (IA32_IDT_GATE_DESCRIPTOR *) Idtr.Base;
    422   OffsetUpper = *(UINT32*)((UINT64*)IdtGateDesc + 1);
    423   mOriginalHandler = (VOID *)(UINTN)(LShiftU64 (OffsetUpper, 32) + IdtGateDesc[14].Bits.OffsetLow + (IdtGateDesc[14].Bits.OffsetHigh << 16));
    424   IdtGateDesc[14].Bits.OffsetLow = (UINT32)((UINTN)PageFaultHandlerHook & ((1 << 16) - 1));
    425   IdtGateDesc[14].Bits.OffsetHigh = (UINT32)(((UINTN)PageFaultHandlerHook >> 16) & ((1 << 16) - 1));
    426 }
    427 
    428 /**
    429   Initialize page table for pages contain HookData.
    430 
    431   The function initialize PDE for 2MB range that contains HookData. If the related PDE points
    432   to a 2MB page, a page table will be allocated and initialized for 4KB pages. Otherwise we juse
    433   use the original page table.
    434 
    435   @param[in] HookData   Based on which to initialize page table.
    436 
    437   @return    The pointer to a Page Table that points to 4KB pages which contain HookData.
    438 **/
    439 UINT64 *
    440 InitCpuStatePageTable (
    441   IN VOID *HookData
    442   )
    443 {
    444   UINTN  Index;
    445   UINT64 *PageTable;
    446   UINT64 *Pdpte;
    447   UINT64 HookAddress;
    448   UINT64 Pde;
    449   UINT64 Address;
    450 
    451   //
    452   // Initialize physical address mask
    453   // NOTE: Physical memory above virtual address limit is not supported !!!
    454   //
    455   AsmCpuid (0x80000008, (UINT32*)&Index, NULL, NULL, NULL);
    456   mPhyMask = LShiftU64 (1, (UINT8)Index) - 1;
    457   mPhyMask &= (1ull << 48) - EFI_PAGE_SIZE;
    458 
    459   HookAddress = (UINT64)(UINTN)HookData;
    460   PageTable   = (UINT64 *)(UINTN)(AsmReadCr3 () & mPhyMask);
    461   PageTable = (UINT64 *)(UINTN)(PageTable[BitFieldRead64 (HookAddress, 39, 47)] & mPhyMask);
    462   PageTable = (UINT64 *)(UINTN)(PageTable[BitFieldRead64 (HookAddress, 30, 38)] & mPhyMask);
    463 
    464   Pdpte = (UINT64 *)(UINTN)PageTable;
    465   Pde = Pdpte[BitFieldRead64 (HookAddress, 21, 29)];
    466   ASSERT ((Pde & BIT0) != 0); // Present and 2M Page
    467 
    468   if ((Pde & BIT7) == 0) { // 4KB Page Directory
    469     PageTable = (UINT64 *)(UINTN)(Pde & mPhyMask);
    470   } else {
    471     ASSERT ((Pde & mPhyMask) == (HookAddress & ~(SIZE_2MB-1))); // 2MB Page Point to HookAddress
    472     PageTable = AllocatePages (1);
    473     ASSERT (PageTable != NULL);
    474     Address = HookAddress & ~(SIZE_2MB-1);
    475     for (Index = 0; Index < 512; Index++) {
    476       PageTable[Index] = Address | BIT0 | BIT1; // Present and RW
    477       Address += SIZE_4KB;
    478     }
    479     Pdpte[BitFieldRead64 (HookAddress, 21, 29)] = (UINT64)(UINTN)PageTable | BIT0 | BIT1; // Present and RW
    480   }
    481   return PageTable;
    482 }
    483 
    484 /**
    485   Mark all the CpuSaveStates as not present.
    486 
    487   The function marks all CpuSaveStates memory range as not present so that page fault can be triggered
    488   on CpuSaveStates access. It is meant to be called on each SmmBaseHelper SMI callback before Framework
    489   handler is called.
    490 
    491   @param[in] CpuSaveState   The base of CpuSaveStates.
    492 
    493 **/
    494 VOID
    495 HookCpuStateMemory (
    496   IN EFI_SMM_CPU_SAVE_STATE *CpuSaveState
    497   )
    498 {
    499   UINT64 Index;
    500   UINT64 PTStartIndex;
    501   UINT64 PTEndIndex;
    502 
    503   PTStartIndex = BitFieldRead64 ((UINTN)CpuSaveState, 12, 20);
    504   PTEndIndex = BitFieldRead64 ((UINTN)CpuSaveState + mNumberOfProcessors * sizeof (EFI_SMM_CPU_SAVE_STATE) - 1, 12, 20);
    505   for (Index = PTStartIndex; Index <= PTEndIndex; Index++) {
    506     mCpuStatePageTable[Index] &= ~(BIT0|BIT5|BIT6); // not present nor accessed nor dirty
    507   }
    508 }
    509 
    510 /**
    511   Framework SMST SmmInstallConfigurationTable() Thunk.
    512 
    513   This thunk calls the PI SMM SmmInstallConfigurationTable() and then update the configuration
    514   table related fields in the Framework SMST because the PI SMM SmmInstallConfigurationTable()
    515   function may modify these fields.
    516 
    517   @param[in] SystemTable         A pointer to the SMM System Table.
    518   @param[in] Guid                A pointer to the GUID for the entry to add, update, or remove.
    519   @param[in] Table               A pointer to the buffer of the table to add.
    520   @param[in] TableSize           The size of the table to install.
    521 
    522   @retval EFI_SUCCESS            The (Guid, Table) pair was added, updated, or removed.
    523   @retval EFI_INVALID_PARAMETER  Guid is not valid.
    524   @retval EFI_NOT_FOUND          An attempt was made to delete a non-existent entry.
    525   @retval EFI_OUT_OF_RESOURCES   There is not enough memory available to complete the operation.
    526 **/
    527 EFI_STATUS
    528 EFIAPI
    529 SmmInstallConfigurationTable (
    530   IN EFI_SMM_SYSTEM_TABLE  *SystemTable,
    531   IN EFI_GUID              *Guid,
    532   IN VOID                  *Table,
    533   IN UINTN                 TableSize
    534   )
    535 {
    536   EFI_STATUS  Status;
    537 
    538   Status = gSmst->SmmInstallConfigurationTable (gSmst, Guid, Table, TableSize);
    539   if (!EFI_ERROR (Status)) {
    540     mFrameworkSmst->NumberOfTableEntries = gSmst->NumberOfTableEntries;
    541     mFrameworkSmst->SmmConfigurationTable = gSmst->SmmConfigurationTable;
    542   }
    543   return Status;
    544 }
    545 
    546 /**
    547   Initialize all the stuff needed for on-demand paging hooks for PI<->Framework
    548   CpuSaveStates marshalling.
    549 
    550   @param[in] FrameworkSmst   Framework SMM system table pointer.
    551 
    552 **/
    553 VOID
    554 InitHook (
    555   IN EFI_SMM_SYSTEM_TABLE  *FrameworkSmst
    556   )
    557 {
    558   UINTN                 NumCpuStatePages;
    559   UINTN                 CpuStatePage;
    560   UINTN                 Bottom2MPage;
    561   UINTN                 Top2MPage;
    562 
    563   mPageTableHookEnabled = FALSE;
    564   NumCpuStatePages = EFI_SIZE_TO_PAGES (mNumberOfProcessors * sizeof (EFI_SMM_CPU_SAVE_STATE));
    565   //
    566   // Only hook page table for X64 image and less than 2MB needed to hold all CPU Save States
    567   //
    568   if (EFI_IMAGE_MACHINE_TYPE_SUPPORTED(EFI_IMAGE_MACHINE_X64) && NumCpuStatePages <= EFI_SIZE_TO_PAGES (SIZE_2MB)) {
    569     //
    570     // Allocate double page size to make sure all CPU Save States are in one 2MB page.
    571     //
    572     CpuStatePage = (UINTN)AllocatePages (NumCpuStatePages * 2);
    573     ASSERT (CpuStatePage != 0);
    574     Bottom2MPage = CpuStatePage & ~(SIZE_2MB-1);
    575     Top2MPage    = (CpuStatePage + EFI_PAGES_TO_SIZE (NumCpuStatePages * 2) - 1) & ~(SIZE_2MB-1);
    576     if (Bottom2MPage == Top2MPage ||
    577         CpuStatePage + EFI_PAGES_TO_SIZE (NumCpuStatePages * 2) - Top2MPage >= EFI_PAGES_TO_SIZE (NumCpuStatePages)
    578         ) {
    579       //
    580       // If the allocated 4KB pages are within the same 2MB page or higher portion is larger, use higher portion pages.
    581       //
    582       FrameworkSmst->CpuSaveState = (EFI_SMM_CPU_SAVE_STATE *)(CpuStatePage + EFI_PAGES_TO_SIZE (NumCpuStatePages));
    583       FreePages ((VOID*)CpuStatePage, NumCpuStatePages);
    584     } else {
    585       FrameworkSmst->CpuSaveState = (EFI_SMM_CPU_SAVE_STATE *)CpuStatePage;
    586       FreePages ((VOID*)(CpuStatePage + EFI_PAGES_TO_SIZE (NumCpuStatePages)), NumCpuStatePages);
    587     }
    588     //
    589     // Add temporary working buffer for hooking
    590     //
    591     mShadowSaveState = (EFI_SMM_CPU_SAVE_STATE*) AllocatePool (sizeof (EFI_SMM_CPU_SAVE_STATE));
    592     ASSERT (mShadowSaveState != NULL);
    593     //
    594     // Allocate and initialize 4KB Page Table for hooking CpuSaveState.
    595     // Replace the original 2MB PDE with new 4KB page table.
    596     //
    597     mCpuStatePageTable = InitCpuStatePageTable (FrameworkSmst->CpuSaveState);
    598     //
    599     // Mark PTE for CpuSaveState as non-exist.
    600     //
    601     HookCpuStateMemory (FrameworkSmst->CpuSaveState);
    602     HookPageFaultHandler ();
    603     CpuFlushTlb ();
    604     mPageTableHookEnabled = TRUE;
    605   }
    606   mHookInitialized = TRUE;
    607 }
    608 
    609 /**
    610   Construct a Framework SMST based on the PI SMM SMST.
    611 
    612   @return  Pointer to the constructed Framework SMST.
    613 **/
    614 EFI_SMM_SYSTEM_TABLE *
    615 ConstructFrameworkSmst (
    616   VOID
    617   )
    618 {
    619   EFI_SMM_SYSTEM_TABLE  *FrameworkSmst;
    620 
    621   FrameworkSmst = (EFI_SMM_SYSTEM_TABLE  *)AllocatePool (sizeof (EFI_SMM_SYSTEM_TABLE));
    622   ASSERT (FrameworkSmst != NULL);
    623 
    624   ///
    625   /// Copy same things from PI SMST to Framework SMST
    626   ///
    627   CopyMem (FrameworkSmst, gSmst, (UINTN)(&((EFI_SMM_SYSTEM_TABLE *)0)->SmmIo));
    628   CopyMem (
    629     &FrameworkSmst->SmmIo,
    630     &gSmst->SmmIo,
    631     sizeof (EFI_SMM_SYSTEM_TABLE) - (UINTN)(&((EFI_SMM_SYSTEM_TABLE *)0)->SmmIo)
    632     );
    633 
    634   ///
    635   /// Update Framework SMST
    636   ///
    637   FrameworkSmst->Hdr.Revision = EFI_SMM_SYSTEM_TABLE_REVISION;
    638   CopyGuid (&FrameworkSmst->EfiSmmCpuIoGuid, &mEfiSmmCpuIoGuid);
    639 
    640   mHookInitialized = FALSE;
    641   FrameworkSmst->CpuSaveState = (EFI_SMM_CPU_SAVE_STATE *)AllocateZeroPool (mNumberOfProcessors * sizeof (EFI_SMM_CPU_SAVE_STATE));
    642   ASSERT (FrameworkSmst->CpuSaveState != NULL);
    643 
    644   ///
    645   /// Do not support floating point state now
    646   ///
    647   FrameworkSmst->CpuOptionalFloatingPointState = NULL;
    648 
    649   FrameworkSmst->SmmInstallConfigurationTable = SmmInstallConfigurationTable;
    650 
    651   return FrameworkSmst;
    652 }
    653 
    654 /**
    655   Load a given Framework SMM driver into SMRAM and invoke its entry point.
    656 
    657   @param[in]   ParentImageHandle     Parent Image Handle.
    658   @param[in]   FilePath              Location of the image to be installed as the handler.
    659   @param[in]   SourceBuffer          Optional source buffer in case the image file
    660                                      is in memory.
    661   @param[in]   SourceSize            Size of the source image file, if in memory.
    662   @param[out]  ImageHandle           The handle that the base driver uses to decode
    663                                      the handler. Unique among SMM handlers only,
    664                                      not unique across DXE/EFI.
    665 
    666   @retval      EFI_SUCCESS           The operation was successful.
    667   @retval      EFI_OUT_OF_RESOURCES  There were no additional SMRAM resources to load the handler
    668   @retval      EFI_UNSUPPORTED       Can not find its copy in normal memory.
    669   @retval      EFI_INVALID_PARAMETER The handlers was not the correct image type
    670 **/
    671 EFI_STATUS
    672 LoadImage (
    673   IN      EFI_HANDLE                ParentImageHandle,
    674   IN      EFI_DEVICE_PATH_PROTOCOL  *FilePath,
    675   IN      VOID                      *SourceBuffer,
    676   IN      UINTN                     SourceSize,
    677   OUT     EFI_HANDLE                *ImageHandle
    678   )
    679 {
    680   EFI_STATUS            Status;
    681   UINTN                 PageCount;
    682   UINTN                 OrgPageCount;
    683   EFI_PHYSICAL_ADDRESS  DstBuffer;
    684 
    685   if (FilePath == NULL || ImageHandle == NULL) {
    686     return EFI_INVALID_PARAMETER;
    687   }
    688 
    689   PageCount = 1;
    690   do {
    691     OrgPageCount = PageCount;
    692     DstBuffer = (UINTN)-1;
    693     Status = gSmst->SmmAllocatePages (
    694                       AllocateMaxAddress,
    695                       EfiRuntimeServicesCode,
    696                       PageCount,
    697                       &DstBuffer
    698                       );
    699     if (EFI_ERROR (Status)) {
    700       return Status;
    701     }
    702 
    703     Status = mLoadPe32Image->LoadPeImage (
    704                                mLoadPe32Image,
    705                                ParentImageHandle,
    706                                FilePath,
    707                                SourceBuffer,
    708                                SourceSize,
    709                                DstBuffer,
    710                                &PageCount,
    711                                ImageHandle,
    712                                NULL,
    713                                EFI_LOAD_PE_IMAGE_ATTRIBUTE_NONE
    714                                );
    715     if (EFI_ERROR (Status)) {
    716       FreePages ((VOID *)(UINTN)DstBuffer, OrgPageCount);
    717     }
    718   } while (Status == EFI_BUFFER_TOO_SMALL);
    719 
    720   if (!EFI_ERROR (Status)) {
    721     ///
    722     /// Update MP state in Framework SMST before transferring control to Framework SMM driver entry point
    723     ///
    724     mFrameworkSmst->SmmStartupThisAp      = gSmst->SmmStartupThisAp;
    725     mFrameworkSmst->NumberOfCpus          = mNumberOfProcessors;
    726     mFrameworkSmst->CurrentlyExecutingCpu = gSmst->CurrentlyExecutingCpu;
    727 
    728     RegisterSmramProfileImage (FilePath, DstBuffer, PageCount);
    729     Status = gBS->StartImage (*ImageHandle, NULL, NULL);
    730     if (EFI_ERROR (Status)) {
    731       UnregisterSmramProfileImage (FilePath, DstBuffer, PageCount);
    732       mLoadPe32Image->UnLoadPeImage (mLoadPe32Image, *ImageHandle);
    733       *ImageHandle = NULL;
    734       FreePages ((VOID *)(UINTN)DstBuffer, PageCount);
    735     }
    736   }
    737 
    738   return Status;
    739 }
    740 
    741 /**
    742   Thunk service of EFI_SMM_BASE_PROTOCOL.Register().
    743 
    744   @param[in, out] FunctionData  Pointer to SMMBASE_FUNCTION_DATA.
    745 **/
    746 VOID
    747 Register (
    748   IN OUT SMMBASE_FUNCTION_DATA *FunctionData
    749   )
    750 {
    751   EFI_STATUS Status;
    752 
    753   if (mLocked || FunctionData->Args.Register.LegacyIA32Binary) {
    754     Status = EFI_UNSUPPORTED;
    755   } else {
    756     Status = LoadImage (
    757                FunctionData->SmmBaseImageHandle,
    758                FunctionData->Args.Register.FilePath,
    759                FunctionData->Args.Register.SourceBuffer,
    760                FunctionData->Args.Register.SourceSize,
    761                FunctionData->Args.Register.ImageHandle
    762                );
    763   }
    764   FunctionData->Status = Status;
    765 }
    766 
    767 /**
    768   Thunk service of EFI_SMM_BASE_PROTOCOL.UnRegister().
    769 
    770   @param[in, out] FunctionData  Pointer to SMMBASE_FUNCTION_DATA.
    771 **/
    772 VOID
    773 UnRegister (
    774   IN OUT SMMBASE_FUNCTION_DATA *FunctionData
    775   )
    776 {
    777   ///
    778   /// Unregister not supported now
    779   ///
    780   FunctionData->Status = EFI_UNSUPPORTED;
    781 }
    782 
    783 /**
    784   Search for Framework SMI handler information according to specific PI SMM dispatch handle.
    785 
    786   @param[in] DispatchHandle  The unique handle assigned by SmiHandlerRegister().
    787 
    788   @return  Pointer to CALLBACK_INFO. If NULL, no callback info record is found.
    789 **/
    790 CALLBACK_INFO *
    791 GetCallbackInfo (
    792   IN EFI_HANDLE  DispatchHandle
    793   )
    794 {
    795   LIST_ENTRY  *Node;
    796 
    797   Node = GetFirstNode (&mCallbackInfoListHead);
    798   while (!IsNull (&mCallbackInfoListHead, Node)) {
    799     if (((CALLBACK_INFO *)Node)->DispatchHandle == DispatchHandle) {
    800       return (CALLBACK_INFO *)Node;
    801     }
    802     Node = GetNextNode (&mCallbackInfoListHead, Node);
    803   }
    804   return NULL;
    805 }
    806 
    807 /**
    808   Callback thunk for Framework SMI handler.
    809 
    810   This thunk functions calls the Framework SMI handler and converts the return value
    811   defined from Framework SMI handlers to a correpsonding return value defined by PI SMM.
    812 
    813   @param[in]     DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().
    814   @param[in]     Context         Points to an optional handler context which was specified when the
    815                                  handler was registered.
    816   @param[in, out] CommBuffer      A pointer to a collection of data in memory that will
    817                                  be conveyed from a non-SMM environment into an SMM environment.
    818   @param[in, out] CommBufferSize  The size of the CommBuffer.
    819 
    820   @retval EFI_SUCCESS                         The interrupt was handled and quiesced. No other handlers
    821                                               should still be called.
    822   @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED  The interrupt has been quiesced but other handlers should
    823                                               still be called.
    824   @retval EFI_WARN_INTERRUPT_SOURCE_PENDING   The interrupt is still pending and other handlers should still
    825                                               be called.
    826   @retval EFI_INTERRUPT_PENDING               The interrupt could not be quiesced.
    827 **/
    828 EFI_STATUS
    829 EFIAPI
    830 CallbackThunk (
    831   IN EFI_HANDLE  DispatchHandle,
    832   IN CONST VOID  *Context         OPTIONAL,
    833   IN OUT VOID    *CommBuffer      OPTIONAL,
    834   IN OUT UINTN   *CommBufferSize  OPTIONAL
    835   )
    836 {
    837   EFI_STATUS        Status;
    838   CALLBACK_INFO     *CallbackInfo;
    839   UINTN             CpuIndex;
    840 
    841   ///
    842   /// Before transferring the control into the Framework SMI handler, update CPU Save States
    843   /// and MP states in the Framework SMST.
    844   ///
    845 
    846   if (!mHookInitialized) {
    847     InitHook (mFrameworkSmst);
    848   }
    849   if (mPageTableHookEnabled) {
    850     HookCpuStateMemory (mFrameworkSmst->CpuSaveState);
    851     CpuFlushTlb ();
    852   } else {
    853     for (CpuIndex = 0; CpuIndex < mNumberOfProcessors; CpuIndex++) {
    854       ReadCpuSaveState (CpuIndex, NULL);
    855     }
    856   }
    857 
    858   mFrameworkSmst->SmmStartupThisAp      = gSmst->SmmStartupThisAp;
    859   mFrameworkSmst->NumberOfCpus          = mNumberOfProcessors;
    860   mFrameworkSmst->CurrentlyExecutingCpu = gSmst->CurrentlyExecutingCpu;
    861 
    862   ///
    863   /// Search for Framework SMI handler information
    864   ///
    865   CallbackInfo = GetCallbackInfo (DispatchHandle);
    866   ASSERT (CallbackInfo != NULL);
    867 
    868   ///
    869   /// Thunk into original Framwork SMI handler
    870   ///
    871   Status = (CallbackInfo->CallbackAddress) (
    872                             CallbackInfo->SmmImageHandle,
    873                             CallbackInfo->CommunicationBuffer,
    874                             CallbackInfo->SourceSize
    875                             );
    876   ///
    877   /// Save CPU Save States in case any of them was modified
    878   ///
    879   if (mPageTableHookEnabled) {
    880     WriteBackDirtyPages ();
    881   } else {
    882     for (CpuIndex = 0; CpuIndex < mNumberOfProcessors; CpuIndex++) {
    883       WriteCpuSaveState (CpuIndex, NULL);
    884     }
    885   }
    886 
    887   ///
    888   /// Conversion of returned status code
    889   ///
    890   switch (Status) {
    891     case EFI_HANDLER_SUCCESS:
    892       Status = EFI_WARN_INTERRUPT_SOURCE_QUIESCED;
    893       break;
    894     case EFI_HANDLER_CRITICAL_EXIT:
    895     case EFI_HANDLER_SOURCE_QUIESCED:
    896       Status = EFI_SUCCESS;
    897       break;
    898     case EFI_HANDLER_SOURCE_PENDING:
    899       Status = EFI_WARN_INTERRUPT_SOURCE_PENDING;
    900       break;
    901   }
    902   return Status;
    903 }
    904 
    905 /**
    906   Thunk service of EFI_SMM_BASE_PROTOCOL.RegisterCallback().
    907 
    908   @param[in, out] FunctionData  Pointer to SMMBASE_FUNCTION_DATA.
    909 **/
    910 VOID
    911 RegisterCallback (
    912   IN OUT SMMBASE_FUNCTION_DATA  *FunctionData
    913   )
    914 {
    915   CALLBACK_INFO  *Buffer;
    916 
    917   if (mLocked) {
    918     FunctionData->Status = EFI_UNSUPPORTED;
    919     return;
    920   }
    921 
    922   ///
    923   /// Note that MakeLast and FloatingPointSave options are not supported in PI SMM
    924   ///
    925 
    926   ///
    927   /// Allocate buffer for callback thunk information
    928   ///
    929   Buffer = (CALLBACK_INFO *)AllocateZeroPool (sizeof (CALLBACK_INFO));
    930   if (Buffer == NULL) {
    931     FunctionData->Status = EFI_OUT_OF_RESOURCES;
    932     return;
    933   }
    934 
    935   ///
    936   /// Fill SmmImageHandle and CallbackAddress into the thunk
    937   ///
    938   Buffer->SmmImageHandle = FunctionData->Args.RegisterCallback.SmmImageHandle;
    939   Buffer->CallbackAddress = FunctionData->Args.RegisterCallback.CallbackAddress;
    940 
    941   ///
    942   /// Register the thunk code as a root SMI handler
    943   ///
    944   FunctionData->Status = gSmst->SmiHandlerRegister (
    945                                   CallbackThunk,
    946                                   NULL,
    947                                   &Buffer->DispatchHandle
    948                                   );
    949   if (EFI_ERROR (FunctionData->Status)) {
    950     FreePool (Buffer);
    951     return;
    952   }
    953 
    954   ///
    955   /// Save this callback info
    956   ///
    957   InsertTailList (&mCallbackInfoListHead, &Buffer->Link);
    958 }
    959 
    960 
    961 /**
    962   Thunk service of EFI_SMM_BASE_PROTOCOL.SmmAllocatePool().
    963 
    964   @param[in, out] FunctionData  Pointer to SMMBASE_FUNCTION_DATA.
    965 **/
    966 VOID
    967 HelperAllocatePool (
    968   IN OUT SMMBASE_FUNCTION_DATA *FunctionData
    969   )
    970 {
    971   if (mLocked) {
    972     FunctionData->Status =  EFI_UNSUPPORTED;
    973   } else {
    974     FunctionData->Status = gSmst->SmmAllocatePool (
    975                                     FunctionData->Args.AllocatePool.PoolType,
    976                                     FunctionData->Args.AllocatePool.Size,
    977                                     FunctionData->Args.AllocatePool.Buffer
    978                                     );
    979   }
    980 }
    981 
    982 /**
    983   Thunk service of EFI_SMM_BASE_PROTOCOL.SmmFreePool().
    984 
    985   @param[in, out] FunctionData  Pointer to SMMBASE_FUNCTION_DATA.
    986 **/
    987 VOID
    988 HelperFreePool (
    989   IN OUT SMMBASE_FUNCTION_DATA *FunctionData
    990   )
    991 {
    992   if (mLocked) {
    993     FunctionData->Status =  EFI_UNSUPPORTED;
    994   } else {
    995     FreePool (FunctionData->Args.FreePool.Buffer);
    996     FunctionData->Status = EFI_SUCCESS;
    997   }
    998 }
    999 
   1000 /**
   1001   Thunk service of EFI_SMM_BASE_PROTOCOL.Communicate().
   1002 
   1003   @param[in, out] FunctionData  Pointer to SMMBASE_FUNCTION_DATA.
   1004 **/
   1005 VOID
   1006 HelperCommunicate (
   1007   IN OUT SMMBASE_FUNCTION_DATA *FunctionData
   1008   )
   1009 {
   1010   LIST_ENTRY     *Node;
   1011   CALLBACK_INFO  *CallbackInfo;
   1012 
   1013   if (FunctionData->Args.Communicate.CommunicationBuffer == NULL) {
   1014     FunctionData->Status = EFI_INVALID_PARAMETER;
   1015     return;
   1016   }
   1017 
   1018   Node = GetFirstNode (&mCallbackInfoListHead);
   1019   while (!IsNull (&mCallbackInfoListHead, Node)) {
   1020     CallbackInfo = (CALLBACK_INFO *)Node;
   1021 
   1022     if (FunctionData->Args.Communicate.ImageHandle == CallbackInfo->SmmImageHandle) {
   1023       CallbackInfo->CommunicationBuffer = FunctionData->Args.Communicate.CommunicationBuffer;
   1024       CallbackInfo->SourceSize          = FunctionData->Args.Communicate.SourceSize;
   1025 
   1026       ///
   1027       /// The message was successfully posted.
   1028       ///
   1029       FunctionData->Status = EFI_SUCCESS;
   1030       return;
   1031     }
   1032     Node = GetNextNode (&mCallbackInfoListHead, Node);
   1033   }
   1034 
   1035   FunctionData->Status = EFI_INVALID_PARAMETER;
   1036 }
   1037 
   1038 /**
   1039   Communication service SMI Handler entry.
   1040 
   1041   This SMI handler provides services for the SMM Base Thunk driver.
   1042 
   1043   Caution: This function may receive untrusted input during runtime.
   1044   The communicate buffer is external input, so this function will do operations only if the communicate
   1045   buffer is outside of SMRAM so that returning the status code in the buffer won't overwrite anywhere in SMRAM.
   1046 
   1047   @param[in]     DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().
   1048   @param[in]     RegisterContext Points to an optional handler context which was specified when the
   1049                                  handler was registered.
   1050   @param[in, out] CommBuffer      A pointer to a collection of data in memory that will
   1051                                  be conveyed from a non-SMM environment into an SMM environment.
   1052   @param[in, out] CommBufferSize  The size of the CommBuffer.
   1053 
   1054   @retval EFI_SUCCESS                         The interrupt was handled and quiesced. No other handlers
   1055                                               should still be called.
   1056   @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED  The interrupt has been quiesced but other handlers should
   1057                                               still be called.
   1058   @retval EFI_WARN_INTERRUPT_SOURCE_PENDING   The interrupt is still pending and other handlers should still
   1059                                               be called.
   1060   @retval EFI_INTERRUPT_PENDING               The interrupt could not be quiesced.
   1061 **/
   1062 EFI_STATUS
   1063 EFIAPI
   1064 SmmHandlerEntry (
   1065   IN     EFI_HANDLE               DispatchHandle,
   1066   IN     CONST VOID               *RegisterContext,
   1067   IN OUT VOID                     *CommBuffer,
   1068   IN OUT UINTN                    *CommBufferSize
   1069   )
   1070 {
   1071   SMMBASE_FUNCTION_DATA *FunctionData;
   1072 
   1073   ASSERT (CommBuffer != NULL);
   1074   ASSERT (CommBufferSize != NULL);
   1075 
   1076   if (*CommBufferSize == sizeof (SMMBASE_FUNCTION_DATA) &&
   1077       SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)CommBuffer, (UINT64)*CommBufferSize)) {
   1078     FunctionData = (SMMBASE_FUNCTION_DATA *)CommBuffer;
   1079 
   1080     switch (FunctionData->Function) {
   1081       case SmmBaseFunctionRegister:
   1082         Register (FunctionData);
   1083         break;
   1084       case SmmBaseFunctionUnregister:
   1085         UnRegister (FunctionData);
   1086         break;
   1087       case SmmBaseFunctionRegisterCallback:
   1088         RegisterCallback (FunctionData);
   1089         break;
   1090       case SmmBaseFunctionAllocatePool:
   1091         HelperAllocatePool (FunctionData);
   1092         break;
   1093       case SmmBaseFunctionFreePool:
   1094         HelperFreePool (FunctionData);
   1095         break;
   1096       case SmmBaseFunctionCommunicate:
   1097         HelperCommunicate (FunctionData);
   1098         break;
   1099       default:
   1100         DEBUG ((EFI_D_WARN, "SmmBaseHelper: invalid SMM Base function.\n"));
   1101         FunctionData->Status = EFI_UNSUPPORTED;
   1102     }
   1103   }
   1104   return EFI_SUCCESS;
   1105 }
   1106 
   1107 /**
   1108   Smm Ready To Lock event notification handler.
   1109 
   1110   It sets a flag indicating that SMRAM has been locked.
   1111 
   1112   @param[in] Protocol   Points to the protocol's unique identifier.
   1113   @param[in] Interface  Points to the interface instance.
   1114   @param[in] Handle     The handle on which the interface was installed.
   1115 
   1116   @retval EFI_SUCCESS   Notification handler runs successfully.
   1117  **/
   1118 EFI_STATUS
   1119 EFIAPI
   1120 SmmReadyToLockEventNotify (
   1121   IN CONST EFI_GUID  *Protocol,
   1122   IN VOID            *Interface,
   1123   IN EFI_HANDLE      Handle
   1124   )
   1125 {
   1126   mLocked = TRUE;
   1127   return EFI_SUCCESS;
   1128 }
   1129 
   1130 /**
   1131   Entry point function of the SMM Base Helper SMM driver.
   1132 
   1133   @param[in] ImageHandle  The firmware allocated handle for the EFI image.
   1134   @param[in] SystemTable  A pointer to the EFI System Table.
   1135 
   1136   @retval EFI_SUCCESS     The entry point is executed successfully.
   1137   @retval other           Some error occurs when executing this entry point.
   1138 **/
   1139 EFI_STATUS
   1140 EFIAPI
   1141 SmmBaseHelperMain (
   1142   IN EFI_HANDLE        ImageHandle,
   1143   IN EFI_SYSTEM_TABLE  *SystemTable
   1144   )
   1145 {
   1146   EFI_STATUS  Status;
   1147   EFI_MP_SERVICES_PROTOCOL   *MpServices;
   1148   EFI_HANDLE                 Handle;
   1149   UINTN                      NumberOfEnabledProcessors;
   1150   VOID                       *Registration;
   1151 
   1152   Handle = NULL;
   1153   ///
   1154   /// Locate SMM CPU Protocol which is used later to retrieve/update CPU Save States
   1155   ///
   1156   Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **) &mSmmCpu);
   1157   ASSERT_EFI_ERROR (Status);
   1158 
   1159   ///
   1160   /// Locate PE32 Image Protocol which is used later to load Framework SMM driver
   1161   ///
   1162   Status = SystemTable->BootServices->LocateProtocol (&gEfiLoadPeImageProtocolGuid, NULL, (VOID **) &mLoadPe32Image);
   1163   ASSERT_EFI_ERROR (Status);
   1164 
   1165   //
   1166   // Get MP Services Protocol
   1167   //
   1168   Status = SystemTable->BootServices->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpServices);
   1169   ASSERT_EFI_ERROR (Status);
   1170 
   1171   //
   1172   // Use MP Services Protocol to retrieve the number of processors and number of enabled processors
   1173   //
   1174   Status = MpServices->GetNumberOfProcessors (MpServices, &mNumberOfProcessors, &NumberOfEnabledProcessors);
   1175   ASSERT_EFI_ERROR (Status);
   1176 
   1177   ///
   1178   /// Interface structure of SMM BASE Helper Ready Protocol is allocated from UEFI pool
   1179   /// instead of SMM pool so that SMM Base Thunk driver can access it in Non-SMM mode.
   1180   ///
   1181   Status = gBS->AllocatePool (
   1182                   EfiBootServicesData,
   1183                   sizeof (EFI_SMM_BASE_HELPER_READY_PROTOCOL),
   1184                   (VOID **)&mSmmBaseHelperReady
   1185                   );
   1186   ASSERT_EFI_ERROR (Status);
   1187 
   1188   ///
   1189   /// Construct Framework SMST from PI SMST
   1190   ///
   1191   mFrameworkSmst = ConstructFrameworkSmst ();
   1192   mSmmBaseHelperReady->FrameworkSmst = mFrameworkSmst;
   1193   mSmmBaseHelperReady->ServiceEntry = SmmHandlerEntry;
   1194 
   1195   //
   1196   // Register SMM Ready To Lock Protocol notification
   1197   //
   1198   Status = gSmst->SmmRegisterProtocolNotify (
   1199                     &gEfiSmmReadyToLockProtocolGuid,
   1200                     SmmReadyToLockEventNotify,
   1201                     &Registration
   1202                     );
   1203   ASSERT_EFI_ERROR (Status);
   1204 
   1205   ///
   1206   /// Register SMM Base Helper services for SMM Base Thunk driver
   1207   ///
   1208   Status = gSmst->SmiHandlerRegister (SmmHandlerEntry, &gEfiSmmBaseThunkCommunicationGuid, &mDispatchHandle);
   1209   ASSERT_EFI_ERROR (Status);
   1210 
   1211   ///
   1212   /// Install EFI SMM Base Helper Protocol in the UEFI handle database
   1213   ///
   1214   Status = gBS->InstallProtocolInterface (
   1215                   &Handle,
   1216                   &gEfiSmmBaseHelperReadyProtocolGuid,
   1217                   EFI_NATIVE_INTERFACE,
   1218                   mSmmBaseHelperReady
   1219                   );
   1220   ASSERT_EFI_ERROR (Status);
   1221 
   1222   return Status;
   1223 }
   1224 
   1225