1 /** @file
2   Instance of SMM memory check library.
3 
4   SMM memory check library library implementation. This library consumes SMM_ACCESS2_PROTOCOL
5   to get SMRAM information. In order to use this library instance, the platform should produce
6   all SMRAM range via SMM_ACCESS2_PROTOCOL, including the range for firmware (like SMM Core
7   and SMM driver) and/or specific dedicated hardware.
8 
9   Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
10   SPDX-License-Identifier: BSD-2-Clause-Patent
11 
12 **/
13 
14 
15 #include <PiSmm.h>
16 
17 #include <Library/BaseLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/MemoryAllocationLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 #include <Library/DxeServicesTableLib.h>
23 #include <Library/SmmServicesTableLib.h>
24 #include <Library/UefiLib.h>
25 #include <Library/HobLib.h>
26 #include <Protocol/SmmAccess2.h>
27 #include <Protocol/SmmReadyToLock.h>
28 #include <Protocol/SmmEndOfDxe.h>
29 #include <Guid/MemoryAttributesTable.h>
30 
31 //
32 // attributes for reserved memory before it is promoted to system memory
33 //
34 #define EFI_MEMORY_PRESENT      0x0100000000000000ULL
35 #define EFI_MEMORY_INITIALIZED  0x0200000000000000ULL
36 #define EFI_MEMORY_TESTED       0x0400000000000000ULL
37 
38 EFI_SMRAM_DESCRIPTOR *mSmmMemLibInternalSmramRanges;
39 UINTN                mSmmMemLibInternalSmramCount;
40 
41 //
42 // Maximum support address used to check input buffer
43 //
44 EFI_PHYSICAL_ADDRESS  mSmmMemLibInternalMaximumSupportAddress = 0;
45 
46 UINTN                 mMemoryMapEntryCount;
47 EFI_MEMORY_DESCRIPTOR *mMemoryMap;
48 UINTN                 mDescriptorSize;
49 
50 EFI_GCD_MEMORY_SPACE_DESCRIPTOR   *mSmmMemLibGcdMemSpace       = NULL;
51 UINTN                             mSmmMemLibGcdMemNumberOfDesc = 0;
52 
53 EFI_MEMORY_ATTRIBUTES_TABLE  *mSmmMemLibMemoryAttributesTable = NULL;
54 
55 VOID                  *mRegistrationEndOfDxe;
56 VOID                  *mRegistrationReadyToLock;
57 
58 BOOLEAN               mSmmMemLibSmmReadyToLock = FALSE;
59 
60 /**
61   Calculate and save the maximum support address.
62 
63 **/
64 VOID
SmmMemLibInternalCalculateMaximumSupportAddress(VOID)65 SmmMemLibInternalCalculateMaximumSupportAddress (
66   VOID
67   )
68 {
69   VOID         *Hob;
70   UINT32       RegEax;
71   UINT8        PhysicalAddressBits;
72 
73   //
74   // Get physical address bits supported.
75   //
76   Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
77   if (Hob != NULL) {
78     PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
79   } else {
80     AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
81     if (RegEax >= 0x80000008) {
82       AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
83       PhysicalAddressBits = (UINT8) RegEax;
84     } else {
85       PhysicalAddressBits = 36;
86     }
87   }
88   //
89   // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
90   //
91   ASSERT (PhysicalAddressBits <= 52);
92   if (PhysicalAddressBits > 48) {
93     PhysicalAddressBits = 48;
94   }
95 
96   //
97   // Save the maximum support address in one global variable
98   //
99   mSmmMemLibInternalMaximumSupportAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)(LShiftU64 (1, PhysicalAddressBits) - 1);
100   DEBUG ((EFI_D_INFO, "mSmmMemLibInternalMaximumSupportAddress = 0x%lx\n", mSmmMemLibInternalMaximumSupportAddress));
101 }
102 
103 /**
104   This function check if the buffer is valid per processor architecture and not overlap with SMRAM.
105 
106   @param Buffer  The buffer start address to be checked.
107   @param Length  The buffer length to be checked.
108 
109   @retval TRUE  This buffer is valid per processor architecture and not overlap with SMRAM.
110   @retval FALSE This buffer is not valid per processor architecture or overlap with SMRAM.
111 **/
112 BOOLEAN
113 EFIAPI
SmmIsBufferOutsideSmmValid(IN EFI_PHYSICAL_ADDRESS Buffer,IN UINT64 Length)114 SmmIsBufferOutsideSmmValid (
115   IN EFI_PHYSICAL_ADDRESS  Buffer,
116   IN UINT64                Length
117   )
118 {
119   UINTN  Index;
120 
121   //
122   // Check override.
123   // NOTE: (B:0->L:4G) is invalid for IA32, but (B:1->L:4G-1)/(B:4G-1->L:1) is valid.
124   //
125   if ((Length > mSmmMemLibInternalMaximumSupportAddress) ||
126       (Buffer > mSmmMemLibInternalMaximumSupportAddress) ||
127       ((Length != 0) && (Buffer > (mSmmMemLibInternalMaximumSupportAddress - (Length - 1)))) ) {
128     //
129     // Overflow happen
130     //
131     DEBUG ((
132       EFI_D_ERROR,
133       "SmmIsBufferOutsideSmmValid: Overflow: Buffer (0x%lx) - Length (0x%lx), MaximumSupportAddress (0x%lx)\n",
134       Buffer,
135       Length,
136       mSmmMemLibInternalMaximumSupportAddress
137       ));
138     return FALSE;
139   }
140 
141   for (Index = 0; Index < mSmmMemLibInternalSmramCount; Index ++) {
142     if (((Buffer >= mSmmMemLibInternalSmramRanges[Index].CpuStart) && (Buffer < mSmmMemLibInternalSmramRanges[Index].CpuStart + mSmmMemLibInternalSmramRanges[Index].PhysicalSize)) ||
143         ((mSmmMemLibInternalSmramRanges[Index].CpuStart >= Buffer) && (mSmmMemLibInternalSmramRanges[Index].CpuStart < Buffer + Length))) {
144       DEBUG ((
145         EFI_D_ERROR,
146         "SmmIsBufferOutsideSmmValid: Overlap: Buffer (0x%lx) - Length (0x%lx), ",
147         Buffer,
148         Length
149         ));
150       DEBUG ((
151         EFI_D_ERROR,
152         "CpuStart (0x%lx) - PhysicalSize (0x%lx)\n",
153         mSmmMemLibInternalSmramRanges[Index].CpuStart,
154         mSmmMemLibInternalSmramRanges[Index].PhysicalSize
155         ));
156       return FALSE;
157     }
158   }
159 
160   //
161   // Check override for Valid Communication Region
162   //
163   if (mSmmMemLibSmmReadyToLock) {
164     EFI_MEMORY_DESCRIPTOR          *MemoryMap;
165     BOOLEAN                        InValidCommunicationRegion;
166 
167     InValidCommunicationRegion = FALSE;
168     MemoryMap = mMemoryMap;
169     for (Index = 0; Index < mMemoryMapEntryCount; Index++) {
170       if ((Buffer >= MemoryMap->PhysicalStart) &&
171           (Buffer + Length <= MemoryMap->PhysicalStart + LShiftU64 (MemoryMap->NumberOfPages, EFI_PAGE_SHIFT))) {
172         InValidCommunicationRegion = TRUE;
173       }
174       MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, mDescriptorSize);
175     }
176 
177     if (!InValidCommunicationRegion) {
178       DEBUG ((
179         EFI_D_ERROR,
180         "SmmIsBufferOutsideSmmValid: Not in ValidCommunicationRegion: Buffer (0x%lx) - Length (0x%lx)\n",
181         Buffer,
182         Length
183         ));
184       return FALSE;
185     }
186 
187     //
188     // Check untested memory as invalid communication buffer.
189     //
190     for (Index = 0; Index < mSmmMemLibGcdMemNumberOfDesc; Index++) {
191       if (((Buffer >= mSmmMemLibGcdMemSpace[Index].BaseAddress) && (Buffer < mSmmMemLibGcdMemSpace[Index].BaseAddress + mSmmMemLibGcdMemSpace[Index].Length)) ||
192           ((mSmmMemLibGcdMemSpace[Index].BaseAddress >= Buffer) && (mSmmMemLibGcdMemSpace[Index].BaseAddress < Buffer + Length))) {
193         DEBUG ((
194           EFI_D_ERROR,
195           "SmmIsBufferOutsideSmmValid: In Untested Memory Region: Buffer (0x%lx) - Length (0x%lx)\n",
196           Buffer,
197           Length
198           ));
199         return FALSE;
200       }
201     }
202 
203     //
204     // Check UEFI runtime memory with EFI_MEMORY_RO as invalid communication buffer.
205     //
206     if (mSmmMemLibMemoryAttributesTable != NULL) {
207       EFI_MEMORY_DESCRIPTOR *Entry;
208 
209       Entry = (EFI_MEMORY_DESCRIPTOR *)(mSmmMemLibMemoryAttributesTable + 1);
210       for (Index = 0; Index < mSmmMemLibMemoryAttributesTable->NumberOfEntries; Index++) {
211         if (Entry->Type == EfiRuntimeServicesCode || Entry->Type == EfiRuntimeServicesData) {
212           if ((Entry->Attribute & EFI_MEMORY_RO) != 0) {
213             if (((Buffer >= Entry->PhysicalStart) && (Buffer < Entry->PhysicalStart + LShiftU64 (Entry->NumberOfPages, EFI_PAGE_SHIFT))) ||
214                 ((Entry->PhysicalStart >= Buffer) && (Entry->PhysicalStart < Buffer + Length))) {
215               DEBUG ((
216                 EFI_D_ERROR,
217                 "SmmIsBufferOutsideSmmValid: In RuntimeCode Region: Buffer (0x%lx) - Length (0x%lx)\n",
218                 Buffer,
219                 Length
220                 ));
221               return FALSE;
222             }
223           }
224         }
225         Entry = NEXT_MEMORY_DESCRIPTOR (Entry, mSmmMemLibMemoryAttributesTable->DescriptorSize);
226       }
227     }
228   }
229   return TRUE;
230 }
231 
232 /**
233   Copies a source buffer (non-SMRAM) to a destination buffer (SMRAM).
234 
235   This function copies a source buffer (non-SMRAM) to a destination buffer (SMRAM).
236   It checks if source buffer is valid per processor architecture and not overlap with SMRAM.
237   If the check passes, it copies memory and returns EFI_SUCCESS.
238   If the check fails, it return EFI_SECURITY_VIOLATION.
239   The implementation must be reentrant.
240 
241   @param  DestinationBuffer   The pointer to the destination buffer of the memory copy.
242   @param  SourceBuffer        The pointer to the source buffer of the memory copy.
243   @param  Length              The number of bytes to copy from SourceBuffer to DestinationBuffer.
244 
245   @retval EFI_SECURITY_VIOLATION The SourceBuffer is invalid per processor architecture or overlap with SMRAM.
246   @retval EFI_SUCCESS            Memory is copied.
247 
248 **/
249 EFI_STATUS
250 EFIAPI
SmmCopyMemToSmram(OUT VOID * DestinationBuffer,IN CONST VOID * SourceBuffer,IN UINTN Length)251 SmmCopyMemToSmram (
252   OUT VOID       *DestinationBuffer,
253   IN CONST VOID  *SourceBuffer,
254   IN UINTN       Length
255   )
256 {
257   if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)SourceBuffer, Length)) {
258     DEBUG ((EFI_D_ERROR, "SmmCopyMemToSmram: Security Violation: Source (0x%x), Length (0x%x)\n", SourceBuffer, Length));
259     return EFI_SECURITY_VIOLATION;
260   }
261   CopyMem (DestinationBuffer, SourceBuffer, Length);
262   return EFI_SUCCESS;
263 }
264 
265 /**
266   Copies a source buffer (SMRAM) to a destination buffer (NON-SMRAM).
267 
268   This function copies a source buffer (non-SMRAM) to a destination buffer (SMRAM).
269   It checks if destination buffer is valid per processor architecture and not overlap with SMRAM.
270   If the check passes, it copies memory and returns EFI_SUCCESS.
271   If the check fails, it returns EFI_SECURITY_VIOLATION.
272   The implementation must be reentrant.
273 
274   @param  DestinationBuffer   The pointer to the destination buffer of the memory copy.
275   @param  SourceBuffer        The pointer to the source buffer of the memory copy.
276   @param  Length              The number of bytes to copy from SourceBuffer to DestinationBuffer.
277 
278   @retval EFI_SECURITY_VIOLATION The DestinationBuffer is invalid per processor architecture or overlap with SMRAM.
279   @retval EFI_SUCCESS            Memory is copied.
280 
281 **/
282 EFI_STATUS
283 EFIAPI
SmmCopyMemFromSmram(OUT VOID * DestinationBuffer,IN CONST VOID * SourceBuffer,IN UINTN Length)284 SmmCopyMemFromSmram (
285   OUT VOID       *DestinationBuffer,
286   IN CONST VOID  *SourceBuffer,
287   IN UINTN       Length
288   )
289 {
290   if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)DestinationBuffer, Length)) {
291     DEBUG ((EFI_D_ERROR, "SmmCopyMemFromSmram: Security Violation: Destination (0x%x), Length (0x%x)\n", DestinationBuffer, Length));
292     return EFI_SECURITY_VIOLATION;
293   }
294   CopyMem (DestinationBuffer, SourceBuffer, Length);
295   return EFI_SUCCESS;
296 }
297 
298 /**
299   Copies a source buffer (NON-SMRAM) to a destination buffer (NON-SMRAM).
300 
301   This function copies a source buffer (non-SMRAM) to a destination buffer (SMRAM).
302   It checks if source buffer and destination buffer are valid per processor architecture and not overlap with SMRAM.
303   If the check passes, it copies memory and returns EFI_SUCCESS.
304   If the check fails, it returns EFI_SECURITY_VIOLATION.
305   The implementation must be reentrant, and it must handle the case where source buffer overlaps destination buffer.
306 
307   @param  DestinationBuffer   The pointer to the destination buffer of the memory copy.
308   @param  SourceBuffer        The pointer to the source buffer of the memory copy.
309   @param  Length              The number of bytes to copy from SourceBuffer to DestinationBuffer.
310 
311   @retval EFI_SECURITY_VIOLATION The DestinationBuffer is invalid per processor architecture or overlap with SMRAM.
312   @retval EFI_SECURITY_VIOLATION The SourceBuffer is invalid per processor architecture or overlap with SMRAM.
313   @retval EFI_SUCCESS            Memory is copied.
314 
315 **/
316 EFI_STATUS
317 EFIAPI
SmmCopyMem(OUT VOID * DestinationBuffer,IN CONST VOID * SourceBuffer,IN UINTN Length)318 SmmCopyMem (
319   OUT VOID       *DestinationBuffer,
320   IN CONST VOID  *SourceBuffer,
321   IN UINTN       Length
322   )
323 {
324   if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)DestinationBuffer, Length)) {
325     DEBUG ((EFI_D_ERROR, "SmmCopyMem: Security Violation: Destination (0x%x), Length (0x%x)\n", DestinationBuffer, Length));
326     return EFI_SECURITY_VIOLATION;
327   }
328   if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)SourceBuffer, Length)) {
329     DEBUG ((EFI_D_ERROR, "SmmCopyMem: Security Violation: Source (0x%x), Length (0x%x)\n", SourceBuffer, Length));
330     return EFI_SECURITY_VIOLATION;
331   }
332   CopyMem (DestinationBuffer, SourceBuffer, Length);
333   return EFI_SUCCESS;
334 }
335 
336 /**
337   Fills a target buffer (NON-SMRAM) with a byte value.
338 
339   This function fills a target buffer (non-SMRAM) with a byte value.
340   It checks if target buffer is valid per processor architecture and not overlap with SMRAM.
341   If the check passes, it fills memory and returns EFI_SUCCESS.
342   If the check fails, it returns EFI_SECURITY_VIOLATION.
343 
344   @param  Buffer    The memory to set.
345   @param  Length    The number of bytes to set.
346   @param  Value     The value with which to fill Length bytes of Buffer.
347 
348   @retval EFI_SECURITY_VIOLATION The Buffer is invalid per processor architecture or overlap with SMRAM.
349   @retval EFI_SUCCESS            Memory is set.
350 
351 **/
352 EFI_STATUS
353 EFIAPI
SmmSetMem(OUT VOID * Buffer,IN UINTN Length,IN UINT8 Value)354 SmmSetMem (
355   OUT VOID  *Buffer,
356   IN UINTN  Length,
357   IN UINT8  Value
358   )
359 {
360   if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, Length)) {
361     DEBUG ((EFI_D_ERROR, "SmmSetMem: Security Violation: Source (0x%x), Length (0x%x)\n", Buffer, Length));
362     return EFI_SECURITY_VIOLATION;
363   }
364   SetMem (Buffer, Length, Value);
365   return EFI_SUCCESS;
366 }
367 
368 /**
369   Get GCD memory map.
370   Only record untested memory as invalid communication buffer.
371 **/
372 VOID
SmmMemLibInternalGetGcdMemoryMap(VOID)373 SmmMemLibInternalGetGcdMemoryMap (
374   VOID
375   )
376 {
377   UINTN                            NumberOfDescriptors;
378   EFI_GCD_MEMORY_SPACE_DESCRIPTOR  *MemSpaceMap;
379   EFI_STATUS                       Status;
380   UINTN                            Index;
381 
382   Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemSpaceMap);
383   if (EFI_ERROR (Status)) {
384     return ;
385   }
386 
387   mSmmMemLibGcdMemNumberOfDesc = 0;
388   for (Index = 0; Index < NumberOfDescriptors; Index++) {
389     if (MemSpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeReserved &&
390         (MemSpaceMap[Index].Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
391           (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)
392           ) {
393       mSmmMemLibGcdMemNumberOfDesc++;
394     }
395   }
396 
397   mSmmMemLibGcdMemSpace = AllocateZeroPool (mSmmMemLibGcdMemNumberOfDesc * sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR));
398   ASSERT (mSmmMemLibGcdMemSpace != NULL);
399   if (mSmmMemLibGcdMemSpace == NULL) {
400     mSmmMemLibGcdMemNumberOfDesc = 0;
401     gBS->FreePool (MemSpaceMap);
402     return ;
403   }
404 
405   mSmmMemLibGcdMemNumberOfDesc = 0;
406   for (Index = 0; Index < NumberOfDescriptors; Index++) {
407     if (MemSpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeReserved &&
408         (MemSpaceMap[Index].Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
409           (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)
410           ) {
411       CopyMem (
412         &mSmmMemLibGcdMemSpace[mSmmMemLibGcdMemNumberOfDesc],
413         &MemSpaceMap[Index],
414         sizeof(EFI_GCD_MEMORY_SPACE_DESCRIPTOR)
415         );
416       mSmmMemLibGcdMemNumberOfDesc++;
417     }
418   }
419 
420   gBS->FreePool (MemSpaceMap);
421 }
422 
423 /**
424   Get UEFI MemoryAttributesTable.
425 **/
426 VOID
SmmMemLibInternalGetUefiMemoryAttributesTable(VOID)427 SmmMemLibInternalGetUefiMemoryAttributesTable (
428   VOID
429   )
430 {
431   EFI_STATUS                   Status;
432   EFI_MEMORY_ATTRIBUTES_TABLE  *MemoryAttributesTable;
433   UINTN                        MemoryAttributesTableSize;
434 
435   Status = EfiGetSystemConfigurationTable (&gEfiMemoryAttributesTableGuid, (VOID **)&MemoryAttributesTable);
436   if (!EFI_ERROR (Status) && (MemoryAttributesTable != NULL)) {
437     MemoryAttributesTableSize = sizeof(EFI_MEMORY_ATTRIBUTES_TABLE) + MemoryAttributesTable->DescriptorSize * MemoryAttributesTable->NumberOfEntries;
438     mSmmMemLibMemoryAttributesTable = AllocateCopyPool (MemoryAttributesTableSize, MemoryAttributesTable);
439     ASSERT (mSmmMemLibMemoryAttributesTable != NULL);
440   }
441 }
442 
443 /**
444   Notification for SMM EndOfDxe protocol.
445 
446   @param[in] Protocol   Points to the protocol's unique identifier.
447   @param[in] Interface  Points to the interface instance.
448   @param[in] Handle     The handle on which the interface was installed.
449 
450   @retval EFI_SUCCESS   Notification runs successfully.
451 **/
452 EFI_STATUS
453 EFIAPI
SmmLibInternalEndOfDxeNotify(IN CONST EFI_GUID * Protocol,IN VOID * Interface,IN EFI_HANDLE Handle)454 SmmLibInternalEndOfDxeNotify (
455   IN CONST EFI_GUID  *Protocol,
456   IN VOID            *Interface,
457   IN EFI_HANDLE      Handle
458   )
459 {
460   EFI_STATUS            Status;
461   UINTN                 MapKey;
462   UINTN                 MemoryMapSize;
463   EFI_MEMORY_DESCRIPTOR *MemoryMap;
464   EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
465   EFI_MEMORY_DESCRIPTOR *SmmMemoryMapStart;
466   UINTN                 MemoryMapEntryCount;
467   UINTN                 DescriptorSize;
468   UINT32                DescriptorVersion;
469   UINTN                 Index;
470 
471   MemoryMapSize = 0;
472   MemoryMap = NULL;
473   Status = gBS->GetMemoryMap (
474              &MemoryMapSize,
475              MemoryMap,
476              &MapKey,
477              &DescriptorSize,
478              &DescriptorVersion
479              );
480   ASSERT (Status == EFI_BUFFER_TOO_SMALL);
481 
482   do {
483     Status = gBS->AllocatePool (EfiBootServicesData, MemoryMapSize, (VOID **)&MemoryMap);
484     ASSERT (MemoryMap != NULL);
485 
486     Status = gBS->GetMemoryMap (
487                &MemoryMapSize,
488                MemoryMap,
489                &MapKey,
490                &DescriptorSize,
491                &DescriptorVersion
492                );
493     if (EFI_ERROR (Status)) {
494       gBS->FreePool (MemoryMap);
495     }
496   } while (Status == EFI_BUFFER_TOO_SMALL);
497 
498   //
499   // Get Count
500   //
501   mDescriptorSize = DescriptorSize;
502   MemoryMapEntryCount = MemoryMapSize/DescriptorSize;
503   MemoryMapStart = MemoryMap;
504   mMemoryMapEntryCount = 0;
505   for (Index = 0; Index < MemoryMapEntryCount; Index++) {
506     switch (MemoryMap->Type) {
507     case EfiReservedMemoryType:
508     case EfiRuntimeServicesCode:
509     case EfiRuntimeServicesData:
510     case EfiACPIMemoryNVS:
511       mMemoryMapEntryCount++;
512       break;
513     }
514     MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);
515   }
516   MemoryMap = MemoryMapStart;
517 
518   //
519   // Get Data
520   //
521   mMemoryMap = AllocatePool (mMemoryMapEntryCount*DescriptorSize);
522   ASSERT (mMemoryMap != NULL);
523   SmmMemoryMapStart = mMemoryMap;
524   for (Index = 0; Index < MemoryMapEntryCount; Index++) {
525     switch (MemoryMap->Type) {
526     case EfiReservedMemoryType:
527     case EfiRuntimeServicesCode:
528     case EfiRuntimeServicesData:
529     case EfiACPIMemoryNVS:
530       CopyMem (mMemoryMap, MemoryMap, DescriptorSize);
531       mMemoryMap = NEXT_MEMORY_DESCRIPTOR(mMemoryMap, DescriptorSize);
532       break;
533     }
534     MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);
535   }
536   mMemoryMap = SmmMemoryMapStart;
537   MemoryMap = MemoryMapStart;
538 
539   gBS->FreePool (MemoryMap);
540 
541   //
542   // Get additional information from GCD memory map.
543   //
544   SmmMemLibInternalGetGcdMemoryMap ();
545 
546   //
547   // Get UEFI memory attributes table.
548   //
549   SmmMemLibInternalGetUefiMemoryAttributesTable ();
550 
551   return EFI_SUCCESS;
552 }
553 
554 /**
555   Notification for SMM ReadyToLock protocol.
556 
557   @param[in] Protocol   Points to the protocol's unique identifier.
558   @param[in] Interface  Points to the interface instance.
559   @param[in] Handle     The handle on which the interface was installed.
560 
561   @retval EFI_SUCCESS   Notification runs successfully.
562 **/
563 EFI_STATUS
564 EFIAPI
SmmLibInternalReadyToLockNotify(IN CONST EFI_GUID * Protocol,IN VOID * Interface,IN EFI_HANDLE Handle)565 SmmLibInternalReadyToLockNotify (
566   IN CONST EFI_GUID  *Protocol,
567   IN VOID            *Interface,
568   IN EFI_HANDLE      Handle
569   )
570 {
571   mSmmMemLibSmmReadyToLock = TRUE;
572   return EFI_SUCCESS;
573 }
574 /**
575   The constructor function initializes the Smm Mem library
576 
577   @param  ImageHandle   The firmware allocated handle for the EFI image.
578   @param  SystemTable   A pointer to the EFI System Table.
579 
580   @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.
581 
582 **/
583 EFI_STATUS
584 EFIAPI
SmmMemLibConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)585 SmmMemLibConstructor (
586   IN EFI_HANDLE        ImageHandle,
587   IN EFI_SYSTEM_TABLE  *SystemTable
588   )
589 {
590   EFI_STATUS                    Status;
591   EFI_SMM_ACCESS2_PROTOCOL      *SmmAccess;
592   UINTN                         Size;
593 
594   //
595   // Get SMRAM information
596   //
597   Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess);
598   ASSERT_EFI_ERROR (Status);
599 
600   Size = 0;
601   Status = SmmAccess->GetCapabilities (SmmAccess, &Size, NULL);
602   ASSERT (Status == EFI_BUFFER_TOO_SMALL);
603 
604   mSmmMemLibInternalSmramRanges = AllocatePool (Size);
605   ASSERT (mSmmMemLibInternalSmramRanges != NULL);
606 
607   Status = SmmAccess->GetCapabilities (SmmAccess, &Size, mSmmMemLibInternalSmramRanges);
608   ASSERT_EFI_ERROR (Status);
609 
610   mSmmMemLibInternalSmramCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
611 
612   //
613   // Calculate and save maximum support address
614   //
615   SmmMemLibInternalCalculateMaximumSupportAddress ();
616 
617   //
618   // Register EndOfDxe to get UEFI memory map
619   //
620   Status = gSmst->SmmRegisterProtocolNotify (&gEfiSmmEndOfDxeProtocolGuid, SmmLibInternalEndOfDxeNotify, &mRegistrationEndOfDxe);
621   ASSERT_EFI_ERROR (Status);
622 
623   //
624   // Register ready to lock so that we can know when to check valid SMRAM region
625   //
626   Status = gSmst->SmmRegisterProtocolNotify (&gEfiSmmReadyToLockProtocolGuid, SmmLibInternalReadyToLockNotify, &mRegistrationReadyToLock);
627   ASSERT_EFI_ERROR (Status);
628 
629   return EFI_SUCCESS;
630 }
631 
632 /**
633   The destructor function frees resource used in the Smm Mem library
634 
635   @param[in]  ImageHandle   The firmware allocated handle for the EFI image.
636   @param[in]  SystemTable   A pointer to the EFI System Table.
637 
638   @retval     EFI_SUCCESS   The deconstructor always returns EFI_SUCCESS.
639 **/
640 EFI_STATUS
641 EFIAPI
SmmMemLibDestructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)642 SmmMemLibDestructor (
643   IN EFI_HANDLE        ImageHandle,
644   IN EFI_SYSTEM_TABLE  *SystemTable
645   )
646 {
647   FreePool (mSmmMemLibInternalSmramRanges);
648 
649   gSmst->SmmRegisterProtocolNotify (&gEfiSmmEndOfDxeProtocolGuid, NULL, &mRegistrationEndOfDxe);
650   gSmst->SmmRegisterProtocolNotify (&gEfiSmmReadyToLockProtocolGuid, NULL, &mRegistrationReadyToLock);
651   return EFI_SUCCESS;
652 }
653