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
GetPageTableBase(VOID)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
PageAttributeToLength(IN PAGE_ATTRIBUTE PageAttribute)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
PageAttributeToMask(IN PAGE_ATTRIBUTE PageAttribute)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 *
GetPageTableEntry(IN PHYSICAL_ADDRESS Address,OUT PAGE_ATTRIBUTE * PageAttribute)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
GetAttributesFromPageEntry(IN UINT64 * PageEntry)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
ConvertPageEntryAttribute(IN UINT64 * PageEntry,IN UINT64 Attributes,IN BOOLEAN IsSet,OUT BOOLEAN * IsModified)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
NeedSplitPage(IN PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN UINT64 * PageEntry,IN PAGE_ATTRIBUTE PageAttribute)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
SplitPage(IN UINT64 * PageEntry,IN PAGE_ATTRIBUTE PageAttribute,IN PAGE_ATTRIBUTE SplitAttribute)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
ConvertMemoryPageAttributes(IN PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN UINT64 Attributes,IN BOOLEAN IsSet,OUT BOOLEAN * IsSplitted,OPTIONAL OUT BOOLEAN * IsModified OPTIONAL)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
FlushTlbOnCurrentProcessor(IN OUT VOID * Buffer)453 FlushTlbOnCurrentProcessor (
454   IN OUT VOID  *Buffer
455   )
456 {
457   CpuFlushTlb ();
458 }
459 
460 /**
461   FlushTlb for all processors.
462 **/
463 VOID
FlushTlbForAll(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
SmmSetMemoryAttributesEx(IN EFI_PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN UINT64 Attributes,OUT BOOLEAN * IsSplitted OPTIONAL)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
SmmClearMemoryAttributesEx(IN EFI_PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN UINT64 Attributes,OUT BOOLEAN * IsSplitted OPTIONAL)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
SmmSetMemoryAttributes(IN EFI_PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN UINT64 Attributes)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
SmmClearMemoryAttributes(IN EFI_PHYSICAL_ADDRESS BaseAddress,IN UINT64 Length,IN UINT64 Attributes)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
SmmGetSystemConfigurationTable(IN EFI_GUID * TableGuid,OUT VOID ** Table)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
PatchSmmSaveStateMap(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
SetMemMapAttributes(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
SortMemoryMap(IN OUT EFI_MEMORY_DESCRIPTOR * MemoryMap,IN UINTN MemoryMapSize,IN UINTN DescriptorSize)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
IsUefiPageNotPresent(IN EFI_MEMORY_DESCRIPTOR * MemoryMap)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
MergeMemoryMapForNotPresentEntry(IN OUT EFI_MEMORY_DESCRIPTOR * MemoryMap,IN OUT UINTN * MemoryMapSize,IN UINTN DescriptorSize)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
GetUefiMemoryMap(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
SetUefiMemMapAttributes(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
IsSmmCommBufferForbiddenAddress(IN UINT64 Address)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