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