Home | History | Annotate | Download | only in PiSmmCpuDxeSmm
      1 /** @file
      2 
      3 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
      4 This program and the accompanying materials
      5 are licensed and made available under the terms and conditions of the BSD License
      6 which accompanies this distribution.  The full text of the license may be found at
      7 http://opensource.org/licenses/bsd-license.php
      8 
      9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 
     12 **/
     13 
     14 #include "PiSmmCpuDxeSmm.h"
     15 
     16 #define NEXT_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
     17   ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) + (Size)))
     18 
     19 #define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
     20   ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
     21 
     22 EFI_MEMORY_DESCRIPTOR *mUefiMemoryMap;
     23 UINTN                 mUefiMemoryMapSize;
     24 UINTN                 mUefiDescriptorSize;
     25 
     26 PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] = {
     27   {Page4K,  SIZE_4KB, PAGING_4K_ADDRESS_MASK_64},
     28   {Page2M,  SIZE_2MB, PAGING_2M_ADDRESS_MASK_64},
     29   {Page1G,  SIZE_1GB, PAGING_1G_ADDRESS_MASK_64},
     30 };
     31 
     32 /**
     33   Return page table base.
     34 
     35   @return page table base.
     36 **/
     37 UINTN
     38 GetPageTableBase (
     39   VOID
     40   )
     41 {
     42   return (AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64);
     43 }
     44 
     45 /**
     46   Return length according to page attributes.
     47 
     48   @param[in]  PageAttributes   The page attribute of the page entry.
     49 
     50   @return The length of page entry.
     51 **/
     52 UINTN
     53 PageAttributeToLength (
     54   IN PAGE_ATTRIBUTE  PageAttribute
     55   )
     56 {
     57   UINTN  Index;
     58   for (Index = 0; Index < sizeof(mPageAttributeTable)/sizeof(mPageAttributeTable[0]); Index++) {
     59     if (PageAttribute == mPageAttributeTable[Index].Attribute) {
     60       return (UINTN)mPageAttributeTable[Index].Length;
     61     }
     62   }
     63   return 0;
     64 }
     65 
     66 /**
     67   Return address mask according to page attributes.
     68 
     69   @param[in]  PageAttributes   The page attribute of the page entry.
     70 
     71   @return The address mask of page entry.
     72 **/
     73 UINTN
     74 PageAttributeToMask (
     75   IN PAGE_ATTRIBUTE  PageAttribute
     76   )
     77 {
     78   UINTN  Index;
     79   for (Index = 0; Index < sizeof(mPageAttributeTable)/sizeof(mPageAttributeTable[0]); Index++) {
     80     if (PageAttribute == mPageAttributeTable[Index].Attribute) {
     81       return (UINTN)mPageAttributeTable[Index].AddressMask;
     82     }
     83   }
     84   return 0;
     85 }
     86 
     87 /**
     88   Return page table entry to match the address.
     89 
     90   @param[in]   Address          The address to be checked.
     91   @param[out]  PageAttributes   The page attribute of the page entry.
     92 
     93   @return The page entry.
     94 **/
     95 VOID *
     96 GetPageTableEntry (
     97   IN  PHYSICAL_ADDRESS                  Address,
     98   OUT PAGE_ATTRIBUTE                    *PageAttribute
     99   )
    100 {
    101   UINTN                 Index1;
    102   UINTN                 Index2;
    103   UINTN                 Index3;
    104   UINTN                 Index4;
    105   UINT64                *L1PageTable;
    106   UINT64                *L2PageTable;
    107   UINT64                *L3PageTable;
    108   UINT64                *L4PageTable;
    109 
    110   Index4 = ((UINTN)RShiftU64 (Address, 39)) & PAGING_PAE_INDEX_MASK;
    111   Index3 = ((UINTN)Address >> 30) & PAGING_PAE_INDEX_MASK;
    112   Index2 = ((UINTN)Address >> 21) & PAGING_PAE_INDEX_MASK;
    113   Index1 = ((UINTN)Address >> 12) & PAGING_PAE_INDEX_MASK;
    114 
    115   if (sizeof(UINTN) == sizeof(UINT64)) {
    116     L4PageTable = (UINT64 *)GetPageTableBase ();
    117     if (L4PageTable[Index4] == 0) {
    118       *PageAttribute = PageNone;
    119       return NULL;
    120     }
    121 
    122     L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] & PAGING_4K_ADDRESS_MASK_64);
    123   } else {
    124     L3PageTable = (UINT64 *)GetPageTableBase ();
    125   }
    126   if (L3PageTable[Index3] == 0) {
    127     *PageAttribute = PageNone;
    128     return NULL;
    129   }
    130   if ((L3PageTable[Index3] & IA32_PG_PS) != 0) {
    131     // 1G
    132     *PageAttribute = Page1G;
    133     return &L3PageTable[Index3];
    134   }
    135 
    136   L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & PAGING_4K_ADDRESS_MASK_64);
    137   if (L2PageTable[Index2] == 0) {
    138     *PageAttribute = PageNone;
    139     return NULL;
    140   }
    141   if ((L2PageTable[Index2] & IA32_PG_PS) != 0) {
    142     // 2M
    143     *PageAttribute = Page2M;
    144     return &L2PageTable[Index2];
    145   }
    146 
    147   // 4k
    148   L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & PAGING_4K_ADDRESS_MASK_64);
    149   if ((L1PageTable[Index1] == 0) && (Address != 0)) {
    150     *PageAttribute = PageNone;
    151     return NULL;
    152   }
    153   *PageAttribute = Page4K;
    154   return &L1PageTable[Index1];
    155 }
    156 
    157 /**
    158   Return memory attributes of page entry.
    159 
    160   @param[in]  PageEntry        The page entry.
    161 
    162   @return Memory attributes of page entry.
    163 **/
    164 UINT64
    165 GetAttributesFromPageEntry (
    166   IN  UINT64                            *PageEntry
    167   )
    168 {
    169   UINT64  Attributes;
    170   Attributes = 0;
    171   if ((*PageEntry & IA32_PG_P) == 0) {
    172     Attributes |= EFI_MEMORY_RP;
    173   }
    174   if ((*PageEntry & IA32_PG_RW) == 0) {
    175     Attributes |= EFI_MEMORY_RO;
    176   }
    177   if ((*PageEntry & IA32_PG_NX) != 0) {
    178     Attributes |= EFI_MEMORY_XP;
    179   }
    180   return Attributes;
    181 }
    182 
    183 /**
    184   Modify memory attributes of page entry.
    185 
    186   @param[in]   PageEntry        The page entry.
    187   @param[in]   Attributes       The bit mask of attributes to modify for the memory region.
    188   @param[in]   IsSet            TRUE means to set attributes. FALSE means to clear attributes.
    189   @param[out]  IsModified       TRUE means page table modified. FALSE means page table not modified.
    190 **/
    191 VOID
    192 ConvertPageEntryAttribute (
    193   IN  UINT64                            *PageEntry,
    194   IN  UINT64                            Attributes,
    195   IN  BOOLEAN                           IsSet,
    196   OUT BOOLEAN                           *IsModified
    197   )
    198 {
    199   UINT64  CurrentPageEntry;
    200   UINT64  NewPageEntry;
    201 
    202   CurrentPageEntry = *PageEntry;
    203   NewPageEntry = CurrentPageEntry;
    204   if ((Attributes & EFI_MEMORY_RP) != 0) {
    205     if (IsSet) {
    206       NewPageEntry &= ~(UINT64)IA32_PG_P;
    207     } else {
    208       NewPageEntry |= IA32_PG_P;
    209     }
    210   }
    211   if ((Attributes & EFI_MEMORY_RO) != 0) {
    212     if (IsSet) {
    213       NewPageEntry &= ~(UINT64)IA32_PG_RW;
    214     } else {
    215       NewPageEntry |= IA32_PG_RW;
    216     }
    217   }
    218   if ((Attributes & EFI_MEMORY_XP) != 0) {
    219     if (mXdSupported) {
    220       if (IsSet) {
    221         NewPageEntry |= IA32_PG_NX;
    222       } else {
    223         NewPageEntry &= ~IA32_PG_NX;
    224       }
    225     }
    226   }
    227   *PageEntry = NewPageEntry;
    228   if (CurrentPageEntry != NewPageEntry) {
    229     *IsModified = TRUE;
    230     DEBUG ((DEBUG_VERBOSE, "ConvertPageEntryAttribute 0x%lx", CurrentPageEntry));
    231     DEBUG ((DEBUG_VERBOSE, "->0x%lx\n", NewPageEntry));
    232   } else {
    233     *IsModified = FALSE;
    234   }
    235 }
    236 
    237 /**
    238   This function returns if there is need to split page entry.
    239 
    240   @param[in]  BaseAddress      The base address to be checked.
    241   @param[in]  Length           The length to be checked.
    242   @param[in]  PageEntry        The page entry to be checked.
    243   @param[in]  PageAttribute    The page attribute of the page entry.
    244 
    245   @retval SplitAttributes on if there is need to split page entry.
    246 **/
    247 PAGE_ATTRIBUTE
    248 NeedSplitPage (
    249   IN  PHYSICAL_ADDRESS                  BaseAddress,
    250   IN  UINT64                            Length,
    251   IN  UINT64                            *PageEntry,
    252   IN  PAGE_ATTRIBUTE                    PageAttribute
    253   )
    254 {
    255   UINT64                PageEntryLength;
    256 
    257   PageEntryLength = PageAttributeToLength (PageAttribute);
    258 
    259   if (((BaseAddress & (PageEntryLength - 1)) == 0) && (Length >= PageEntryLength)) {
    260     return PageNone;
    261   }
    262 
    263   if (((BaseAddress & PAGING_2M_MASK) != 0) || (Length < SIZE_2MB)) {
    264     return Page4K;
    265   }
    266 
    267   return Page2M;
    268 }
    269 
    270 /**
    271   This function splits one page entry to small page entries.
    272 
    273   @param[in]  PageEntry        The page entry to be splitted.
    274   @param[in]  PageAttribute    The page attribute of the page entry.
    275   @param[in]  SplitAttribute   How to split the page entry.
    276 
    277   @retval RETURN_SUCCESS            The page entry is splitted.
    278   @retval RETURN_UNSUPPORTED        The page entry does not support to be splitted.
    279   @retval RETURN_OUT_OF_RESOURCES   No resource to split page entry.
    280 **/
    281 RETURN_STATUS
    282 SplitPage (
    283   IN  UINT64                            *PageEntry,
    284   IN  PAGE_ATTRIBUTE                    PageAttribute,
    285   IN  PAGE_ATTRIBUTE                    SplitAttribute
    286   )
    287 {
    288   UINT64   BaseAddress;
    289   UINT64   *NewPageEntry;
    290   UINTN    Index;
    291 
    292   ASSERT (PageAttribute == Page2M || PageAttribute == Page1G);
    293 
    294   if (PageAttribute == Page2M) {
    295     //
    296     // Split 2M to 4K
    297     //
    298     ASSERT (SplitAttribute == Page4K);
    299     if (SplitAttribute == Page4K) {
    300       NewPageEntry = AllocatePageTableMemory (1);
    301       DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));
    302       if (NewPageEntry == NULL) {
    303         return RETURN_OUT_OF_RESOURCES;
    304       }
    305       BaseAddress = *PageEntry & PAGING_2M_ADDRESS_MASK_64;
    306       for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {
    307         NewPageEntry[Index] = BaseAddress + SIZE_4KB * Index + ((*PageEntry) & PAGE_PROGATE_BITS);
    308       }
    309       (*PageEntry) = (UINT64)(UINTN)NewPageEntry + PAGE_ATTRIBUTE_BITS;
    310       return RETURN_SUCCESS;
    311     } else {
    312       return RETURN_UNSUPPORTED;
    313     }
    314   } else if (PageAttribute == Page1G) {
    315     //
    316     // Split 1G to 2M
    317     // No need support 1G->4K directly, we should use 1G->2M, then 2M->4K to get more compact page table.
    318     //
    319     ASSERT (SplitAttribute == Page2M || SplitAttribute == Page4K);
    320     if ((SplitAttribute == Page2M || SplitAttribute == Page4K)) {
    321       NewPageEntry = AllocatePageTableMemory (1);
    322       DEBUG ((DEBUG_VERBOSE, "Split - 0x%x\n", NewPageEntry));
    323       if (NewPageEntry == NULL) {
    324         return RETURN_OUT_OF_RESOURCES;
    325       }
    326       BaseAddress = *PageEntry & PAGING_1G_ADDRESS_MASK_64;
    327       for (Index = 0; Index < SIZE_4KB / sizeof(UINT64); Index++) {
    328         NewPageEntry[Index] = BaseAddress + SIZE_2MB * Index + IA32_PG_PS + ((*PageEntry) & PAGE_PROGATE_BITS);
    329       }
    330       (*PageEntry) = (UINT64)(UINTN)NewPageEntry + PAGE_ATTRIBUTE_BITS;
    331       return RETURN_SUCCESS;
    332     } else {
    333       return RETURN_UNSUPPORTED;
    334     }
    335   } else {
    336     return RETURN_UNSUPPORTED;
    337   }
    338 }
    339 
    340 /**
    341   This function modifies the page attributes for the memory region specified by BaseAddress and
    342   Length from their current attributes to the attributes specified by Attributes.
    343 
    344   Caller should make sure BaseAddress and Length is at page boundary.
    345 
    346   @param[in]   BaseAddress      The physical address that is the start address of a memory region.
    347   @param[in]   Length           The size in bytes of the memory region.
    348   @param[in]   Attributes       The bit mask of attributes to modify for the memory region.
    349   @param[in]   IsSet            TRUE means to set attributes. FALSE means to clear attributes.
    350   @param[out]  IsSplitted       TRUE means page table splitted. FALSE means page table not splitted.
    351   @param[out]  IsModified       TRUE means page table modified. FALSE means page table not modified.
    352 
    353   @retval RETURN_SUCCESS           The attributes were modified for the memory region.
    354   @retval RETURN_ACCESS_DENIED     The attributes for the memory resource range specified by
    355                                    BaseAddress and Length cannot be modified.
    356   @retval RETURN_INVALID_PARAMETER Length is zero.
    357                                    Attributes specified an illegal combination of attributes that
    358                                    cannot be set together.
    359   @retval RETURN_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
    360                                    the memory resource range.
    361   @retval RETURN_UNSUPPORTED       The processor does not support one or more bytes of the memory
    362                                    resource range specified by BaseAddress and Length.
    363                                    The bit mask of attributes is not support for the memory resource
    364                                    range specified by BaseAddress and Length.
    365 **/
    366 RETURN_STATUS
    367 EFIAPI
    368 ConvertMemoryPageAttributes (
    369   IN  PHYSICAL_ADDRESS                  BaseAddress,
    370   IN  UINT64                            Length,
    371   IN  UINT64                            Attributes,
    372   IN  BOOLEAN                           IsSet,
    373   OUT BOOLEAN                           *IsSplitted,  OPTIONAL
    374   OUT BOOLEAN                           *IsModified   OPTIONAL
    375   )
    376 {
    377   UINT64                            *PageEntry;
    378   PAGE_ATTRIBUTE                    PageAttribute;
    379   UINTN                             PageEntryLength;
    380   PAGE_ATTRIBUTE                    SplitAttribute;
    381   RETURN_STATUS                     Status;
    382   BOOLEAN                           IsEntryModified;
    383 
    384   ASSERT (Attributes != 0);
    385   ASSERT ((Attributes & ~(EFI_MEMORY_RP | EFI_MEMORY_RO | EFI_MEMORY_XP)) == 0);
    386 
    387   ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);
    388   ASSERT ((Length & (SIZE_4KB - 1)) == 0);
    389 
    390   if (Length == 0) {
    391     return RETURN_INVALID_PARAMETER;
    392   }
    393 
    394 //  DEBUG ((DEBUG_ERROR, "ConvertMemoryPageAttributes(%x) - %016lx, %016lx, %02lx\n", IsSet, BaseAddress, Length, Attributes));
    395 
    396   if (IsSplitted != NULL) {
    397     *IsSplitted = FALSE;
    398   }
    399   if (IsModified != NULL) {
    400     *IsModified = FALSE;
    401   }
    402 
    403   //
    404   // Below logic is to check 2M/4K page to make sure we donot waist memory.
    405   //
    406   while (Length != 0) {
    407     PageEntry = GetPageTableEntry (BaseAddress, &PageAttribute);
    408     if (PageEntry == NULL) {
    409       return RETURN_UNSUPPORTED;
    410     }
    411     PageEntryLength = PageAttributeToLength (PageAttribute);
    412     SplitAttribute = NeedSplitPage (BaseAddress, Length, PageEntry, PageAttribute);
    413     if (SplitAttribute == PageNone) {
    414       ConvertPageEntryAttribute (PageEntry, Attributes, IsSet, &IsEntryModified);
    415       if (IsEntryModified) {
    416         if (IsModified != NULL) {
    417           *IsModified = TRUE;
    418         }
    419       }
    420       //
    421       // Convert success, move to next
    422       //
    423       BaseAddress += PageEntryLength;
    424       Length -= PageEntryLength;
    425     } else {
    426       Status = SplitPage (PageEntry, PageAttribute, SplitAttribute);
    427       if (RETURN_ERROR (Status)) {
    428         return RETURN_UNSUPPORTED;
    429       }
    430       if (IsSplitted != NULL) {
    431         *IsSplitted = TRUE;
    432       }
    433       if (IsModified != NULL) {
    434         *IsModified = TRUE;
    435       }
    436       //
    437       // Just split current page
    438       // Convert success in next around
    439       //
    440     }
    441   }
    442 
    443   return RETURN_SUCCESS;
    444 }
    445 
    446 /**
    447   FlushTlb on current processor.
    448 
    449   @param[in,out] Buffer  Pointer to private data buffer.
    450 **/
    451 VOID
    452 EFIAPI
    453 FlushTlbOnCurrentProcessor (
    454   IN OUT VOID  *Buffer
    455   )
    456 {
    457   CpuFlushTlb ();
    458 }
    459 
    460 /**
    461   FlushTlb for all processors.
    462 **/
    463 VOID
    464 FlushTlbForAll (
    465   VOID
    466   )
    467 {
    468   UINTN       Index;
    469 
    470   FlushTlbOnCurrentProcessor (NULL);
    471 
    472   for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
    473     if (Index != gSmst->CurrentlyExecutingCpu) {
    474       // Force to start up AP in blocking mode,
    475       SmmBlockingStartupThisAp (FlushTlbOnCurrentProcessor, Index, NULL);
    476       // Do not check return status, because AP might not be present in some corner cases.
    477     }
    478   }
    479 }
    480 
    481 /**
    482   This function sets the attributes for the memory region specified by BaseAddress and
    483   Length from their current attributes to the attributes specified by Attributes.
    484 
    485   @param[in]   BaseAddress      The physical address that is the start address of a memory region.
    486   @param[in]   Length           The size in bytes of the memory region.
    487   @param[in]   Attributes       The bit mask of attributes to set for the memory region.
    488   @param[out]  IsSplitted       TRUE means page table splitted. FALSE means page table not splitted.
    489 
    490   @retval EFI_SUCCESS           The attributes were set for the memory region.
    491   @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by
    492                                 BaseAddress and Length cannot be modified.
    493   @retval EFI_INVALID_PARAMETER Length is zero.
    494                                 Attributes specified an illegal combination of attributes that
    495                                 cannot be set together.
    496   @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
    497                                 the memory resource range.
    498   @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
    499                                 resource range specified by BaseAddress and Length.
    500                                 The bit mask of attributes is not support for the memory resource
    501                                 range specified by BaseAddress and Length.
    502 
    503 **/
    504 EFI_STATUS
    505 EFIAPI
    506 SmmSetMemoryAttributesEx (
    507   IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,
    508   IN  UINT64                                     Length,
    509   IN  UINT64                                     Attributes,
    510   OUT BOOLEAN                                    *IsSplitted  OPTIONAL
    511   )
    512 {
    513   EFI_STATUS  Status;
    514   BOOLEAN     IsModified;
    515 
    516   Status = ConvertMemoryPageAttributes (BaseAddress, Length, Attributes, TRUE, IsSplitted, &IsModified);
    517   if (!EFI_ERROR(Status)) {
    518     if (IsModified) {
    519       //
    520       // Flush TLB as last step
    521       //
    522       FlushTlbForAll();
    523     }
    524   }
    525 
    526   return Status;
    527 }
    528 
    529 /**
    530   This function clears the attributes for the memory region specified by BaseAddress and
    531   Length from their current attributes to the attributes specified by Attributes.
    532 
    533   @param[in]   BaseAddress      The physical address that is the start address of a memory region.
    534   @param[in]   Length           The size in bytes of the memory region.
    535   @param[in]   Attributes       The bit mask of attributes to clear for the memory region.
    536   @param[out]  IsSplitted       TRUE means page table splitted. FALSE means page table not splitted.
    537 
    538   @retval EFI_SUCCESS           The attributes were cleared for the memory region.
    539   @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by
    540                                 BaseAddress and Length cannot be modified.
    541   @retval EFI_INVALID_PARAMETER Length is zero.
    542                                 Attributes specified an illegal combination of attributes that
    543                                 cannot be set together.
    544   @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
    545                                 the memory resource range.
    546   @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
    547                                 resource range specified by BaseAddress and Length.
    548                                 The bit mask of attributes is not support for the memory resource
    549                                 range specified by BaseAddress and Length.
    550 
    551 **/
    552 EFI_STATUS
    553 EFIAPI
    554 SmmClearMemoryAttributesEx (
    555   IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,
    556   IN  UINT64                                     Length,
    557   IN  UINT64                                     Attributes,
    558   OUT BOOLEAN                                    *IsSplitted  OPTIONAL
    559   )
    560 {
    561   EFI_STATUS  Status;
    562   BOOLEAN     IsModified;
    563 
    564   Status = ConvertMemoryPageAttributes (BaseAddress, Length, Attributes, FALSE, IsSplitted, &IsModified);
    565   if (!EFI_ERROR(Status)) {
    566     if (IsModified) {
    567       //
    568       // Flush TLB as last step
    569       //
    570       FlushTlbForAll();
    571     }
    572   }
    573 
    574   return Status;
    575 }
    576 
    577 /**
    578   This function sets the attributes for the memory region specified by BaseAddress and
    579   Length from their current attributes to the attributes specified by Attributes.
    580 
    581   @param[in]  BaseAddress      The physical address that is the start address of a memory region.
    582   @param[in]  Length           The size in bytes of the memory region.
    583   @param[in]  Attributes       The bit mask of attributes to set for the memory region.
    584 
    585   @retval EFI_SUCCESS           The attributes were set for the memory region.
    586   @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by
    587                                 BaseAddress and Length cannot be modified.
    588   @retval EFI_INVALID_PARAMETER Length is zero.
    589                                 Attributes specified an illegal combination of attributes that
    590                                 cannot be set together.
    591   @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
    592                                 the memory resource range.
    593   @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
    594                                 resource range specified by BaseAddress and Length.
    595                                 The bit mask of attributes is not support for the memory resource
    596                                 range specified by BaseAddress and Length.
    597 
    598 **/
    599 EFI_STATUS
    600 EFIAPI
    601 SmmSetMemoryAttributes (
    602   IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,
    603   IN  UINT64                                     Length,
    604   IN  UINT64                                     Attributes
    605   )
    606 {
    607   return SmmSetMemoryAttributesEx (BaseAddress, Length, Attributes, NULL);
    608 }
    609 
    610 /**
    611   This function clears the attributes for the memory region specified by BaseAddress and
    612   Length from their current attributes to the attributes specified by Attributes.
    613 
    614   @param[in]  BaseAddress      The physical address that is the start address of a memory region.
    615   @param[in]  Length           The size in bytes of the memory region.
    616   @param[in]  Attributes       The bit mask of attributes to clear for the memory region.
    617 
    618   @retval EFI_SUCCESS           The attributes were cleared for the memory region.
    619   @retval EFI_ACCESS_DENIED     The attributes for the memory resource range specified by
    620                                 BaseAddress and Length cannot be modified.
    621   @retval EFI_INVALID_PARAMETER Length is zero.
    622                                 Attributes specified an illegal combination of attributes that
    623                                 cannot be set together.
    624   @retval EFI_OUT_OF_RESOURCES  There are not enough system resources to modify the attributes of
    625                                 the memory resource range.
    626   @retval EFI_UNSUPPORTED       The processor does not support one or more bytes of the memory
    627                                 resource range specified by BaseAddress and Length.
    628                                 The bit mask of attributes is not support for the memory resource
    629                                 range specified by BaseAddress and Length.
    630 
    631 **/
    632 EFI_STATUS
    633 EFIAPI
    634 SmmClearMemoryAttributes (
    635   IN  EFI_PHYSICAL_ADDRESS                       BaseAddress,
    636   IN  UINT64                                     Length,
    637   IN  UINT64                                     Attributes
    638   )
    639 {
    640   return SmmClearMemoryAttributesEx (BaseAddress, Length, Attributes, NULL);
    641 }
    642 
    643 
    644 
    645 /**
    646   Retrieves a pointer to the system configuration table from the SMM System Table
    647   based on a specified GUID.
    648 
    649   @param[in]   TableGuid       The pointer to table's GUID type.
    650   @param[out]  Table           The pointer to the table associated with TableGuid in the EFI System Table.
    651 
    652   @retval EFI_SUCCESS     A configuration table matching TableGuid was found.
    653   @retval EFI_NOT_FOUND   A configuration table matching TableGuid could not be found.
    654 
    655 **/
    656 EFI_STATUS
    657 EFIAPI
    658 SmmGetSystemConfigurationTable (
    659   IN  EFI_GUID  *TableGuid,
    660   OUT VOID      **Table
    661   )
    662 {
    663   UINTN             Index;
    664 
    665   ASSERT (TableGuid != NULL);
    666   ASSERT (Table != NULL);
    667 
    668   *Table = NULL;
    669   for (Index = 0; Index < gSmst->NumberOfTableEntries; Index++) {
    670     if (CompareGuid (TableGuid, &(gSmst->SmmConfigurationTable[Index].VendorGuid))) {
    671       *Table = gSmst->SmmConfigurationTable[Index].VendorTable;
    672       return EFI_SUCCESS;
    673     }
    674   }
    675 
    676   return EFI_NOT_FOUND;
    677 }
    678 
    679 /**
    680   This function sets SMM save state buffer to be RW and XP.
    681 **/
    682 VOID
    683 PatchSmmSaveStateMap (
    684   VOID
    685   )
    686 {
    687   UINTN  Index;
    688   UINTN  TileCodeSize;
    689   UINTN  TileDataSize;
    690   UINTN  TileSize;
    691 
    692   TileCodeSize = GetSmiHandlerSize ();
    693   TileCodeSize = ALIGN_VALUE(TileCodeSize, SIZE_4KB);
    694   TileDataSize = (SMRAM_SAVE_STATE_MAP_OFFSET - SMM_PSD_OFFSET) + sizeof (SMRAM_SAVE_STATE_MAP);
    695   TileDataSize = ALIGN_VALUE(TileDataSize, SIZE_4KB);
    696   TileSize = TileDataSize + TileCodeSize - 1;
    697   TileSize = 2 * GetPowerOfTwo32 ((UINT32)TileSize);
    698 
    699   DEBUG ((DEBUG_INFO, "PatchSmmSaveStateMap:\n"));
    700   for (Index = 0; Index < mMaxNumberOfCpus - 1; Index++) {
    701     //
    702     // Code
    703     //
    704     SmmSetMemoryAttributes (
    705       mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET,
    706       TileCodeSize,
    707       EFI_MEMORY_RO
    708       );
    709     SmmClearMemoryAttributes (
    710       mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET,
    711       TileCodeSize,
    712       EFI_MEMORY_XP
    713       );
    714 
    715     //
    716     // Data
    717     //
    718     SmmClearMemoryAttributes (
    719       mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET + TileCodeSize,
    720       TileSize - TileCodeSize,
    721       EFI_MEMORY_RO
    722       );
    723     SmmSetMemoryAttributes (
    724       mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET + TileCodeSize,
    725       TileSize - TileCodeSize,
    726       EFI_MEMORY_XP
    727       );
    728   }
    729 
    730   //
    731   // Code
    732   //
    733   SmmSetMemoryAttributes (
    734     mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET,
    735     TileCodeSize,
    736     EFI_MEMORY_RO
    737     );
    738   SmmClearMemoryAttributes (
    739     mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET,
    740     TileCodeSize,
    741     EFI_MEMORY_XP
    742     );
    743 
    744   //
    745   // Data
    746   //
    747   SmmClearMemoryAttributes (
    748     mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET + TileCodeSize,
    749     SIZE_32KB - TileCodeSize,
    750     EFI_MEMORY_RO
    751     );
    752   SmmSetMemoryAttributes (
    753     mCpuHotPlugData.SmBase[mMaxNumberOfCpus - 1] + SMM_HANDLER_OFFSET + TileCodeSize,
    754     SIZE_32KB - TileCodeSize,
    755     EFI_MEMORY_XP
    756     );
    757 }
    758 
    759 /**
    760   This function sets memory attribute according to MemoryAttributesTable.
    761 **/
    762 VOID
    763 SetMemMapAttributes (
    764   VOID
    765   )
    766 {
    767   EFI_MEMORY_DESCRIPTOR                     *MemoryMap;
    768   EFI_MEMORY_DESCRIPTOR                     *MemoryMapStart;
    769   UINTN                                     MemoryMapEntryCount;
    770   UINTN                                     DescriptorSize;
    771   UINTN                                     Index;
    772   EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE      *MemoryAttributesTable;
    773 
    774   SmmGetSystemConfigurationTable (&gEdkiiPiSmmMemoryAttributesTableGuid, (VOID **)&MemoryAttributesTable);
    775   if (MemoryAttributesTable == NULL) {
    776     DEBUG ((DEBUG_INFO, "MemoryAttributesTable - NULL\n"));
    777     return ;
    778   }
    779 
    780   DEBUG ((DEBUG_INFO, "MemoryAttributesTable:\n"));
    781   DEBUG ((DEBUG_INFO, "  Version                   - 0x%08x\n", MemoryAttributesTable->Version));
    782   DEBUG ((DEBUG_INFO, "  NumberOfEntries           - 0x%08x\n", MemoryAttributesTable->NumberOfEntries));
    783   DEBUG ((DEBUG_INFO, "  DescriptorSize            - 0x%08x\n", MemoryAttributesTable->DescriptorSize));
    784 
    785   MemoryMapEntryCount = MemoryAttributesTable->NumberOfEntries;
    786   DescriptorSize = MemoryAttributesTable->DescriptorSize;
    787   MemoryMapStart = (EFI_MEMORY_DESCRIPTOR *)(MemoryAttributesTable + 1);
    788   MemoryMap = MemoryMapStart;
    789   for (Index = 0; Index < MemoryMapEntryCount; Index++) {
    790     DEBUG ((DEBUG_INFO, "Entry (0x%x)\n", MemoryMap));
    791     DEBUG ((DEBUG_INFO, "  Type              - 0x%x\n", MemoryMap->Type));
    792     DEBUG ((DEBUG_INFO, "  PhysicalStart     - 0x%016lx\n", MemoryMap->PhysicalStart));
    793     DEBUG ((DEBUG_INFO, "  VirtualStart      - 0x%016lx\n", MemoryMap->VirtualStart));
    794     DEBUG ((DEBUG_INFO, "  NumberOfPages     - 0x%016lx\n", MemoryMap->NumberOfPages));
    795     DEBUG ((DEBUG_INFO, "  Attribute         - 0x%016lx\n", MemoryMap->Attribute));
    796     MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);
    797   }
    798 
    799   MemoryMap = MemoryMapStart;
    800   for (Index = 0; Index < MemoryMapEntryCount; Index++) {
    801     DEBUG ((DEBUG_VERBOSE, "SetAttribute: Memory Entry - 0x%lx, 0x%x\n", MemoryMap->PhysicalStart, MemoryMap->NumberOfPages));
    802     switch (MemoryMap->Type) {
    803     case EfiRuntimeServicesCode:
    804       SmmSetMemoryAttributes (
    805         MemoryMap->PhysicalStart,
    806         EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages),
    807         EFI_MEMORY_RO
    808         );
    809       break;
    810     case EfiRuntimeServicesData:
    811       SmmSetMemoryAttributes (
    812         MemoryMap->PhysicalStart,
    813         EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages),
    814         EFI_MEMORY_XP
    815         );
    816       break;
    817     default:
    818       SmmSetMemoryAttributes (
    819         MemoryMap->PhysicalStart,
    820         EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages),
    821         EFI_MEMORY_XP
    822         );
    823       break;
    824     }
    825     MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);
    826   }
    827 
    828   PatchSmmSaveStateMap ();
    829   PatchGdtIdtMap ();
    830 
    831   return ;
    832 }
    833 
    834 /**
    835   Sort memory map entries based upon PhysicalStart, from low to high.
    836 
    837   @param  MemoryMap              A pointer to the buffer in which firmware places
    838                                  the current memory map.
    839   @param  MemoryMapSize          Size, in bytes, of the MemoryMap buffer.
    840   @param  DescriptorSize         Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
    841 **/
    842 STATIC
    843 VOID
    844 SortMemoryMap (
    845   IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,
    846   IN UINTN                      MemoryMapSize,
    847   IN UINTN                      DescriptorSize
    848   )
    849 {
    850   EFI_MEMORY_DESCRIPTOR       *MemoryMapEntry;
    851   EFI_MEMORY_DESCRIPTOR       *NextMemoryMapEntry;
    852   EFI_MEMORY_DESCRIPTOR       *MemoryMapEnd;
    853   EFI_MEMORY_DESCRIPTOR       TempMemoryMap;
    854 
    855   MemoryMapEntry = MemoryMap;
    856   NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
    857   MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + MemoryMapSize);
    858   while (MemoryMapEntry < MemoryMapEnd) {
    859     while (NextMemoryMapEntry < MemoryMapEnd) {
    860       if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {
    861         CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
    862         CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
    863         CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof(EFI_MEMORY_DESCRIPTOR));
    864       }
    865 
    866       NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
    867     }
    868 
    869     MemoryMapEntry      = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
    870     NextMemoryMapEntry  = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
    871   }
    872 }
    873 
    874 /**
    875   Return if a UEFI memory page should be marked as not present in SMM page table.
    876   If the memory map entries type is
    877   EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
    878   EfiUnusableMemory, EfiACPIReclaimMemory, return TRUE.
    879   Or return FALSE.
    880 
    881   @param[in]  MemoryMap              A pointer to the memory descriptor.
    882 
    883   @return TRUE  The memory described will be marked as not present in SMM page table.
    884   @return FALSE The memory described will not be marked as not present in SMM page table.
    885 **/
    886 BOOLEAN
    887 IsUefiPageNotPresent (
    888   IN EFI_MEMORY_DESCRIPTOR  *MemoryMap
    889   )
    890 {
    891   switch (MemoryMap->Type) {
    892   case EfiLoaderCode:
    893   case EfiLoaderData:
    894   case EfiBootServicesCode:
    895   case EfiBootServicesData:
    896   case EfiConventionalMemory:
    897   case EfiUnusableMemory:
    898   case EfiACPIReclaimMemory:
    899     return TRUE;
    900   default:
    901     return FALSE;
    902   }
    903 }
    904 
    905 /**
    906   Merge continous memory map entries whose type is
    907   EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
    908   EfiUnusableMemory, EfiACPIReclaimMemory, because the memory described by
    909   these entries will be set as NOT present in SMM page table.
    910 
    911   @param[in, out]  MemoryMap              A pointer to the buffer in which firmware places
    912                                           the current memory map.
    913   @param[in, out]  MemoryMapSize          A pointer to the size, in bytes, of the
    914                                           MemoryMap buffer. On input, this is the size of
    915                                           the current memory map.  On output,
    916                                           it is the size of new memory map after merge.
    917   @param[in]       DescriptorSize         Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
    918 **/
    919 STATIC
    920 VOID
    921 MergeMemoryMapForNotPresentEntry (
    922   IN OUT EFI_MEMORY_DESCRIPTOR  *MemoryMap,
    923   IN OUT UINTN                  *MemoryMapSize,
    924   IN UINTN                      DescriptorSize
    925   )
    926 {
    927   EFI_MEMORY_DESCRIPTOR       *MemoryMapEntry;
    928   EFI_MEMORY_DESCRIPTOR       *MemoryMapEnd;
    929   UINT64                      MemoryBlockLength;
    930   EFI_MEMORY_DESCRIPTOR       *NewMemoryMapEntry;
    931   EFI_MEMORY_DESCRIPTOR       *NextMemoryMapEntry;
    932 
    933   MemoryMapEntry = MemoryMap;
    934   NewMemoryMapEntry = MemoryMap;
    935   MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) MemoryMap + *MemoryMapSize);
    936   while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
    937     CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR));
    938     NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
    939 
    940     do {
    941       MemoryBlockLength = (UINT64) (EFI_PAGES_TO_SIZE((UINTN)MemoryMapEntry->NumberOfPages));
    942       if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&
    943           IsUefiPageNotPresent(MemoryMapEntry) && IsUefiPageNotPresent(NextMemoryMapEntry) &&
    944           ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) {
    945         MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
    946         if (NewMemoryMapEntry != MemoryMapEntry) {
    947           NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
    948         }
    949 
    950         NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
    951         continue;
    952       } else {
    953         MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
    954         break;
    955       }
    956     } while (TRUE);
    957 
    958     MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
    959     NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);
    960   }
    961 
    962   *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;
    963 
    964   return ;
    965 }
    966 
    967 /**
    968   This function caches the UEFI memory map information.
    969 **/
    970 VOID
    971 GetUefiMemoryMap (
    972   VOID
    973   )
    974 {
    975   EFI_STATUS            Status;
    976   UINTN                 MapKey;
    977   UINT32                DescriptorVersion;
    978   EFI_MEMORY_DESCRIPTOR *MemoryMap;
    979   UINTN                 UefiMemoryMapSize;
    980 
    981   DEBUG ((DEBUG_INFO, "GetUefiMemoryMap\n"));
    982 
    983   UefiMemoryMapSize = 0;
    984   MemoryMap = NULL;
    985   Status = gBS->GetMemoryMap (
    986                   &UefiMemoryMapSize,
    987                   MemoryMap,
    988                   &MapKey,
    989                   &mUefiDescriptorSize,
    990                   &DescriptorVersion
    991                   );
    992   ASSERT (Status == EFI_BUFFER_TOO_SMALL);
    993 
    994   do {
    995     Status = gBS->AllocatePool (EfiBootServicesData, UefiMemoryMapSize, (VOID **)&MemoryMap);
    996     ASSERT (MemoryMap != NULL);
    997     if (MemoryMap == NULL) {
    998       return ;
    999     }
   1000 
   1001     Status = gBS->GetMemoryMap (
   1002                     &UefiMemoryMapSize,
   1003                     MemoryMap,
   1004                     &MapKey,
   1005                     &mUefiDescriptorSize,
   1006                     &DescriptorVersion
   1007                     );
   1008     if (EFI_ERROR (Status)) {
   1009       gBS->FreePool (MemoryMap);
   1010       MemoryMap = NULL;
   1011     }
   1012   } while (Status == EFI_BUFFER_TOO_SMALL);
   1013 
   1014   if (MemoryMap == NULL) {
   1015     return ;
   1016   }
   1017 
   1018   SortMemoryMap (MemoryMap, UefiMemoryMapSize, mUefiDescriptorSize);
   1019   MergeMemoryMapForNotPresentEntry (MemoryMap, &UefiMemoryMapSize, mUefiDescriptorSize);
   1020 
   1021   mUefiMemoryMapSize = UefiMemoryMapSize;
   1022   mUefiMemoryMap = AllocateCopyPool (UefiMemoryMapSize, MemoryMap);
   1023   ASSERT (mUefiMemoryMap != NULL);
   1024 
   1025   gBS->FreePool (MemoryMap);
   1026 }
   1027 
   1028 /**
   1029   This function sets UEFI memory attribute according to UEFI memory map.
   1030 
   1031   The normal memory region is marked as not present, such as
   1032   EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
   1033   EfiUnusableMemory, EfiACPIReclaimMemory.
   1034 **/
   1035 VOID
   1036 SetUefiMemMapAttributes (
   1037   VOID
   1038   )
   1039 {
   1040   EFI_MEMORY_DESCRIPTOR *MemoryMap;
   1041   UINTN                 MemoryMapEntryCount;
   1042   UINTN                 Index;
   1043 
   1044   DEBUG ((DEBUG_INFO, "SetUefiMemMapAttributes\n"));
   1045 
   1046   if (mUefiMemoryMap == NULL) {
   1047     DEBUG ((DEBUG_INFO, "UefiMemoryMap - NULL\n"));
   1048     return ;
   1049   }
   1050 
   1051   MemoryMapEntryCount = mUefiMemoryMapSize/mUefiDescriptorSize;
   1052   MemoryMap = mUefiMemoryMap;
   1053   for (Index = 0; Index < MemoryMapEntryCount; Index++) {
   1054     if (IsUefiPageNotPresent(MemoryMap)) {
   1055       DEBUG ((DEBUG_INFO, "UefiMemory protection: 0x%lx - 0x%lx\n", MemoryMap->PhysicalStart, MemoryMap->PhysicalStart + (UINT64)EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages)));
   1056       SmmSetMemoryAttributes (
   1057         MemoryMap->PhysicalStart,
   1058         EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages),
   1059         EFI_MEMORY_RP
   1060         );
   1061     }
   1062     MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, mUefiDescriptorSize);
   1063   }
   1064 
   1065   //
   1066   // Do free mUefiMemoryMap, it will be checked in IsSmmCommBufferForbiddenAddress().
   1067   //
   1068 }
   1069 
   1070 /**
   1071   Return if the Address is forbidden as SMM communication buffer.
   1072 
   1073   @param[in] Address the address to be checked
   1074 
   1075   @return TRUE  The address is forbidden as SMM communication buffer.
   1076   @return FALSE The address is allowed as SMM communication buffer.
   1077 **/
   1078 BOOLEAN
   1079 IsSmmCommBufferForbiddenAddress (
   1080   IN UINT64  Address
   1081   )
   1082 {
   1083   EFI_MEMORY_DESCRIPTOR *MemoryMap;
   1084   UINTN                 MemoryMapEntryCount;
   1085   UINTN                 Index;
   1086 
   1087   if (mUefiMemoryMap == NULL) {
   1088     return FALSE;
   1089   }
   1090 
   1091   MemoryMap = mUefiMemoryMap;
   1092   MemoryMapEntryCount = mUefiMemoryMapSize/mUefiDescriptorSize;
   1093   for (Index = 0; Index < MemoryMapEntryCount; Index++) {
   1094     if (IsUefiPageNotPresent (MemoryMap)) {
   1095       if ((Address >= MemoryMap->PhysicalStart) &&
   1096           (Address < MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages)) ) {
   1097         return TRUE;
   1098       }
   1099     }
   1100     MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, mUefiDescriptorSize);
   1101   }
   1102   return FALSE;
   1103 }
   1104