1 /** @file
2   SMM IPL that produces SMM related runtime protocols and load the SMM Core into SMRAM
3 
4   Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
5   This program and the accompanying materials are licensed and made available
6   under the terms and conditions of the BSD License which accompanies this
7   distribution.  The full text of the license may be found at
8   http://opensource.org/licenses/bsd-license.php
9 
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include <PiDxe.h>
16 
17 #include <Protocol/SmmBase2.h>
18 #include <Protocol/SmmCommunication.h>
19 #include <Protocol/SmmAccess2.h>
20 #include <Protocol/SmmConfiguration.h>
21 #include <Protocol/SmmControl2.h>
22 #include <Protocol/DxeSmmReadyToLock.h>
23 #include <Protocol/Cpu.h>
24 
25 #include <Guid/EventGroup.h>
26 #include <Guid/EventLegacyBios.h>
27 #include <Guid/LoadModuleAtFixedAddress.h>
28 
29 #include <Library/BaseLib.h>
30 #include <Library/BaseMemoryLib.h>
31 #include <Library/PeCoffLib.h>
32 #include <Library/CacheMaintenanceLib.h>
33 #include <Library/MemoryAllocationLib.h>
34 #include <Library/DebugLib.h>
35 #include <Library/UefiBootServicesTableLib.h>
36 #include <Library/DxeServicesTableLib.h>
37 #include <Library/DxeServicesLib.h>
38 #include <Library/UefiLib.h>
39 #include <Library/UefiRuntimeLib.h>
40 #include <Library/PcdLib.h>
41 
42 #include "PiSmmCorePrivateData.h"
43 
44 //
45 // Function prototypes from produced protocols
46 //
47 
48 /**
49   Indicate whether the driver is currently executing in the SMM Initialization phase.
50 
51   @param   This                    The EFI_SMM_BASE2_PROTOCOL instance.
52   @param   InSmram                 Pointer to a Boolean which, on return, indicates that the driver is currently executing
53                                    inside of SMRAM (TRUE) or outside of SMRAM (FALSE).
54 
55   @retval  EFI_INVALID_PARAMETER   InSmram was NULL.
56   @retval  EFI_SUCCESS             The call returned successfully.
57 
58 **/
59 EFI_STATUS
60 EFIAPI
61 SmmBase2InSmram (
62   IN CONST EFI_SMM_BASE2_PROTOCOL  *This,
63   OUT      BOOLEAN                 *InSmram
64   );
65 
66 /**
67   Retrieves the location of the System Management System Table (SMST).
68 
69   @param   This                    The EFI_SMM_BASE2_PROTOCOL instance.
70   @param   Smst                    On return, points to a pointer to the System Management Service Table (SMST).
71 
72   @retval  EFI_INVALID_PARAMETER   Smst or This was invalid.
73   @retval  EFI_SUCCESS             The memory was returned to the system.
74   @retval  EFI_UNSUPPORTED         Not in SMM.
75 
76 **/
77 EFI_STATUS
78 EFIAPI
79 SmmBase2GetSmstLocation (
80   IN CONST EFI_SMM_BASE2_PROTOCOL  *This,
81   OUT      EFI_SMM_SYSTEM_TABLE2   **Smst
82   );
83 
84 /**
85   Communicates with a registered handler.
86 
87   This function provides a service to send and receive messages from a registered
88   UEFI service.  This function is part of the SMM Communication Protocol that may
89   be called in physical mode prior to SetVirtualAddressMap() and in virtual mode
90   after SetVirtualAddressMap().
91 
92   @param[in]     This                The EFI_SMM_COMMUNICATION_PROTOCOL instance.
93   @param[in, out] CommBuffer          A pointer to the buffer to convey into SMRAM.
94   @param[in, out] CommSize            The size of the data buffer being passed in.On exit, the size of data
95                                      being returned. Zero if the handler does not wish to reply with any data.
96 
97   @retval EFI_SUCCESS                The message was successfully posted.
98   @retval EFI_INVALID_PARAMETER      The CommBuffer was NULL.
99 **/
100 EFI_STATUS
101 EFIAPI
102 SmmCommunicationCommunicate (
103   IN CONST EFI_SMM_COMMUNICATION_PROTOCOL  *This,
104   IN OUT VOID                              *CommBuffer,
105   IN OUT UINTN                             *CommSize
106   );
107 
108 /**
109   Event notification that is fired every time a gEfiSmmConfigurationProtocol installs.
110 
111   @param  Event                 The Event that is being processed, not used.
112   @param  Context               Event Context, not used.
113 
114 **/
115 VOID
116 EFIAPI
117 SmmIplSmmConfigurationEventNotify (
118   IN EFI_EVENT  Event,
119   IN VOID       *Context
120   );
121 
122 /**
123   Event notification that is fired every time a DxeSmmReadyToLock protocol is added
124   or if gEfiEventReadyToBootGuid is signalled.
125 
126   @param  Event                 The Event that is being processed, not used.
127   @param  Context               Event Context, not used.
128 
129 **/
130 VOID
131 EFIAPI
132 SmmIplReadyToLockEventNotify (
133   IN EFI_EVENT  Event,
134   IN VOID       *Context
135   );
136 
137 /**
138   Event notification that is fired when DxeDispatch Event Group is signaled.
139 
140   @param  Event                 The Event that is being processed, not used.
141   @param  Context               Event Context, not used.
142 
143 **/
144 VOID
145 EFIAPI
146 SmmIplDxeDispatchEventNotify (
147   IN EFI_EVENT  Event,
148   IN VOID       *Context
149   );
150 
151 /**
152   Event notification that is fired when a GUIDed Event Group is signaled.
153 
154   @param  Event                 The Event that is being processed, not used.
155   @param  Context               Event Context, not used.
156 
157 **/
158 VOID
159 EFIAPI
160 SmmIplGuidedEventNotify (
161   IN EFI_EVENT  Event,
162   IN VOID       *Context
163   );
164 
165 /**
166   Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
167 
168   This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
169   It convers pointer to new virtual address.
170 
171   @param  Event        Event whose notification function is being invoked.
172   @param  Context      Pointer to the notification function's context.
173 
174 **/
175 VOID
176 EFIAPI
177 SmmIplSetVirtualAddressNotify (
178   IN EFI_EVENT  Event,
179   IN VOID       *Context
180   );
181 
182 //
183 // Data structure used to declare a table of protocol notifications and event
184 // notifications required by the SMM IPL
185 //
186 typedef struct {
187   BOOLEAN           Protocol;
188   BOOLEAN           CloseOnLock;
189   EFI_GUID          *Guid;
190   EFI_EVENT_NOTIFY  NotifyFunction;
191   VOID              *NotifyContext;
192   EFI_TPL           NotifyTpl;
193   EFI_EVENT         Event;
194 } SMM_IPL_EVENT_NOTIFICATION;
195 
196 //
197 // Handle to install the SMM Base2 Protocol and the SMM Communication Protocol
198 //
199 EFI_HANDLE  mSmmIplHandle = NULL;
200 
201 //
202 // SMM Base 2 Protocol instance
203 //
204 EFI_SMM_BASE2_PROTOCOL  mSmmBase2 = {
205   SmmBase2InSmram,
206   SmmBase2GetSmstLocation
207 };
208 
209 //
210 // SMM Communication Protocol instance
211 //
212 EFI_SMM_COMMUNICATION_PROTOCOL  mSmmCommunication = {
213   SmmCommunicationCommunicate
214 };
215 
216 //
217 // SMM Core Private Data structure that contains the data shared between
218 // the SMM IPL and the SMM Core.
219 //
220 SMM_CORE_PRIVATE_DATA  mSmmCorePrivateData = {
221   SMM_CORE_PRIVATE_DATA_SIGNATURE,    // Signature
222   NULL,                               // SmmIplImageHandle
223   0,                                  // SmramRangeCount
224   NULL,                               // SmramRanges
225   NULL,                               // SmmEntryPoint
226   FALSE,                              // SmmEntryPointRegistered
227   FALSE,                              // InSmm
228   NULL,                               // Smst
229   NULL,                               // CommunicationBuffer
230   0,                                  // BufferSize
231   EFI_SUCCESS                         // ReturnStatus
232 };
233 
234 //
235 // Global pointer used to access mSmmCorePrivateData from outside and inside SMM
236 //
237 SMM_CORE_PRIVATE_DATA  *gSmmCorePrivate = &mSmmCorePrivateData;
238 
239 //
240 // SMM IPL global variables
241 //
242 EFI_SMM_CONTROL2_PROTOCOL  *mSmmControl2;
243 EFI_SMM_ACCESS2_PROTOCOL   *mSmmAccess;
244 EFI_SMRAM_DESCRIPTOR       *mCurrentSmramRange;
245 BOOLEAN                    mSmmLocked = FALSE;
246 EFI_PHYSICAL_ADDRESS       mSmramCacheBase;
247 UINT64                     mSmramCacheSize;
248 
249 EFI_SMM_COMMUNICATE_HEADER mCommunicateHeader;
250 
251 //
252 // Table of Protocol notification and GUIDed Event notifications that the SMM IPL requires
253 //
254 SMM_IPL_EVENT_NOTIFICATION  mSmmIplEvents[] = {
255   //
256   // Declare protocol notification on the SMM Configuration protocol.  When this notification is etablished,
257   // the associated event is immediately signalled, so the notification function will be executed and the
258   // SMM Configuration Protocol will be found if it is already in the handle database.
259   //
260   { TRUE,  FALSE, &gEfiSmmConfigurationProtocolGuid,  SmmIplSmmConfigurationEventNotify, &gEfiSmmConfigurationProtocolGuid,  TPL_NOTIFY,   NULL },
261   //
262   // Declare protocol notification on DxeSmmReadyToLock protocols.  When this notification is established,
263   // the associated event is immediately signalled, so the notification function will be executed and the
264   // DXE SMM Ready To Lock Protocol will be found if it is already in the handle database.
265   //
266   { TRUE,  TRUE,  &gEfiDxeSmmReadyToLockProtocolGuid, SmmIplReadyToLockEventNotify,      &gEfiDxeSmmReadyToLockProtocolGuid, TPL_CALLBACK, NULL },
267   //
268   // Declare event notification on EndOfDxe event.  When this notification is etablished,
269   // the associated event is immediately signalled, so the notification function will be executed and the
270   // SMM End Of Dxe Protocol will be found if it is already in the handle database.
271   //
272   { FALSE, TRUE,  &gEfiEndOfDxeEventGroupGuid,        SmmIplGuidedEventNotify,           &gEfiEndOfDxeEventGroupGuid,        TPL_CALLBACK, NULL },
273   //
274   // Declare event notification on the DXE Dispatch Event Group.  This event is signaled by the DXE Core
275   // each time the DXE Core dispatcher has completed its work.  When this event is signalled, the SMM Core
276   // if notified, so the SMM Core can dispatch SMM drivers.
277   //
278   { FALSE, TRUE,  &gEfiEventDxeDispatchGuid,          SmmIplDxeDispatchEventNotify,      &gEfiEventDxeDispatchGuid,          TPL_CALLBACK, NULL },
279   //
280   // Declare event notification on Ready To Boot Event Group.  This is an extra event notification that is
281   // used to make sure SMRAM is locked before any boot options are processed.
282   //
283   { FALSE, TRUE,  &gEfiEventReadyToBootGuid,          SmmIplReadyToLockEventNotify,      &gEfiEventReadyToBootGuid,          TPL_CALLBACK, NULL },
284   //
285   // Declare event notification on Legacy Boot Event Group.  This is used to inform the SMM Core that the platform
286   // is performing a legacy boot operation, and that the UEFI environment is no longer available and the SMM Core
287   // must guarantee that it does not access any UEFI related structures outside of SMRAM.
288   // It is also to inform the SMM Core to notify SMM driver that system enter legacy boot.
289   //
290   { FALSE, FALSE, &gEfiEventLegacyBootGuid,           SmmIplGuidedEventNotify,           &gEfiEventLegacyBootGuid,           TPL_CALLBACK, NULL },
291   //
292   // Declare event notification on Exit Boot Services Event Group.  This is used to inform the SMM Core
293   // to notify SMM driver that system enter exit boot services.
294   //
295   { FALSE, FALSE, &gEfiEventExitBootServicesGuid,     SmmIplGuidedEventNotify,           &gEfiEventExitBootServicesGuid,     TPL_CALLBACK, NULL },
296   //
297   // Declare event notification on Ready To Boot Event Group.  This is used to inform the SMM Core
298   // to notify SMM driver that system enter ready to boot.
299   //
300   { FALSE, FALSE, &gEfiEventReadyToBootGuid,          SmmIplGuidedEventNotify,           &gEfiEventReadyToBootGuid,          TPL_CALLBACK, NULL },
301   //
302   // Declare event notification on SetVirtualAddressMap() Event Group.  This is used to convert gSmmCorePrivate
303   // and mSmmControl2 from physical addresses to virtual addresses.
304   //
305   { FALSE, FALSE, &gEfiEventVirtualAddressChangeGuid, SmmIplSetVirtualAddressNotify,     NULL,                               TPL_CALLBACK, NULL },
306   //
307   // Terminate the table of event notifications
308   //
309   { FALSE, FALSE, NULL,                               NULL,                              NULL,                               TPL_CALLBACK, NULL }
310 };
311 
312 /**
313   Find the maximum SMRAM cache range that covers the range specified by SmramRange.
314 
315   This function searches and joins all adjacent ranges of SmramRange into a range to be cached.
316 
317   @param   SmramRange       The SMRAM range to search from.
318   @param   SmramCacheBase   The returned cache range base.
319   @param   SmramCacheSize   The returned cache range size.
320 
321 **/
322 VOID
GetSmramCacheRange(IN EFI_SMRAM_DESCRIPTOR * SmramRange,OUT EFI_PHYSICAL_ADDRESS * SmramCacheBase,OUT UINT64 * SmramCacheSize)323 GetSmramCacheRange (
324   IN  EFI_SMRAM_DESCRIPTOR *SmramRange,
325   OUT EFI_PHYSICAL_ADDRESS *SmramCacheBase,
326   OUT UINT64               *SmramCacheSize
327   )
328 {
329   UINTN                Index;
330   EFI_PHYSICAL_ADDRESS RangeCpuStart;
331   UINT64               RangePhysicalSize;
332   BOOLEAN              FoundAjacentRange;
333 
334   *SmramCacheBase = SmramRange->CpuStart;
335   *SmramCacheSize = SmramRange->PhysicalSize;
336 
337   do {
338     FoundAjacentRange = FALSE;
339     for (Index = 0; Index < gSmmCorePrivate->SmramRangeCount; Index++) {
340       RangeCpuStart     = gSmmCorePrivate->SmramRanges[Index].CpuStart;
341       RangePhysicalSize = gSmmCorePrivate->SmramRanges[Index].PhysicalSize;
342       if (RangeCpuStart < *SmramCacheBase && *SmramCacheBase == (RangeCpuStart + RangePhysicalSize)) {
343         *SmramCacheBase   = RangeCpuStart;
344         *SmramCacheSize  += RangePhysicalSize;
345         FoundAjacentRange = TRUE;
346       } else if ((*SmramCacheBase + *SmramCacheSize) == RangeCpuStart && RangePhysicalSize > 0) {
347         *SmramCacheSize  += RangePhysicalSize;
348         FoundAjacentRange = TRUE;
349       }
350     }
351   } while (FoundAjacentRange);
352 
353 }
354 
355 /**
356   Indicate whether the driver is currently executing in the SMM Initialization phase.
357 
358   @param   This                    The EFI_SMM_BASE2_PROTOCOL instance.
359   @param   InSmram                 Pointer to a Boolean which, on return, indicates that the driver is currently executing
360                                    inside of SMRAM (TRUE) or outside of SMRAM (FALSE).
361 
362   @retval  EFI_INVALID_PARAMETER   InSmram was NULL.
363   @retval  EFI_SUCCESS             The call returned successfully.
364 
365 **/
366 EFI_STATUS
367 EFIAPI
SmmBase2InSmram(IN CONST EFI_SMM_BASE2_PROTOCOL * This,OUT BOOLEAN * InSmram)368 SmmBase2InSmram (
369   IN CONST EFI_SMM_BASE2_PROTOCOL  *This,
370   OUT      BOOLEAN                 *InSmram
371   )
372 {
373   if (InSmram == NULL) {
374     return EFI_INVALID_PARAMETER;
375   }
376 
377   *InSmram = gSmmCorePrivate->InSmm;
378 
379   return EFI_SUCCESS;
380 }
381 
382 /**
383   Retrieves the location of the System Management System Table (SMST).
384 
385   @param   This                    The EFI_SMM_BASE2_PROTOCOL instance.
386   @param   Smst                    On return, points to a pointer to the System Management Service Table (SMST).
387 
388   @retval  EFI_INVALID_PARAMETER   Smst or This was invalid.
389   @retval  EFI_SUCCESS             The memory was returned to the system.
390   @retval  EFI_UNSUPPORTED         Not in SMM.
391 
392 **/
393 EFI_STATUS
394 EFIAPI
SmmBase2GetSmstLocation(IN CONST EFI_SMM_BASE2_PROTOCOL * This,OUT EFI_SMM_SYSTEM_TABLE2 ** Smst)395 SmmBase2GetSmstLocation (
396   IN CONST EFI_SMM_BASE2_PROTOCOL  *This,
397   OUT      EFI_SMM_SYSTEM_TABLE2   **Smst
398   )
399 {
400   if ((This == NULL) ||(Smst == NULL)) {
401     return EFI_INVALID_PARAMETER;
402   }
403 
404   if (!gSmmCorePrivate->InSmm) {
405     return EFI_UNSUPPORTED;
406   }
407 
408   *Smst = gSmmCorePrivate->Smst;
409 
410   return EFI_SUCCESS;
411 }
412 
413 /**
414   Communicates with a registered handler.
415 
416   This function provides a service to send and receive messages from a registered
417   UEFI service.  This function is part of the SMM Communication Protocol that may
418   be called in physical mode prior to SetVirtualAddressMap() and in virtual mode
419   after SetVirtualAddressMap().
420 
421   @param[in] This                The EFI_SMM_COMMUNICATION_PROTOCOL instance.
422   @param[in, out] CommBuffer          A pointer to the buffer to convey into SMRAM.
423   @param[in, out] CommSize            The size of the data buffer being passed in.On exit, the size of data
424                                  being returned. Zero if the handler does not wish to reply with any data.
425 
426   @retval EFI_SUCCESS            The message was successfully posted.
427   @retval EFI_INVALID_PARAMETER  The CommBuffer was NULL.
428 **/
429 EFI_STATUS
430 EFIAPI
SmmCommunicationCommunicate(IN CONST EFI_SMM_COMMUNICATION_PROTOCOL * This,IN OUT VOID * CommBuffer,IN OUT UINTN * CommSize)431 SmmCommunicationCommunicate (
432   IN CONST EFI_SMM_COMMUNICATION_PROTOCOL  *This,
433   IN OUT VOID                              *CommBuffer,
434   IN OUT UINTN                             *CommSize
435   )
436 {
437   EFI_STATUS                  Status;
438   EFI_SMM_COMMUNICATE_HEADER  *CommunicateHeader;
439   BOOLEAN                     OldInSmm;
440 
441   //
442   // Check parameters
443   //
444   if ((CommBuffer == NULL) || (CommSize == NULL)) {
445     return EFI_INVALID_PARAMETER;
446   }
447 
448   //
449   // CommSize must hold HeaderGuid and MessageLength
450   //
451   if (*CommSize < OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)) {
452     return EFI_INVALID_PARAMETER;
453   }
454 
455   //
456   // If not already in SMM, then generate a Software SMI
457   //
458   if (!gSmmCorePrivate->InSmm && gSmmCorePrivate->SmmEntryPointRegistered) {
459     //
460     // Put arguments for Software SMI in gSmmCorePrivate
461     //
462     gSmmCorePrivate->CommunicationBuffer = CommBuffer;
463     gSmmCorePrivate->BufferSize          = *CommSize;
464 
465     //
466     // Generate Software SMI
467     //
468     Status = mSmmControl2->Trigger (mSmmControl2, NULL, NULL, FALSE, 0);
469     if (EFI_ERROR (Status)) {
470       return EFI_UNSUPPORTED;
471     }
472 
473     //
474     // Return status from software SMI
475     //
476     *CommSize = gSmmCorePrivate->BufferSize;
477     return gSmmCorePrivate->ReturnStatus;
478   }
479 
480   //
481   // If we are in SMM, then the execution mode must be physical, which means that
482   // OS established virtual addresses can not be used.  If SetVirtualAddressMap()
483   // has been called, then a direct invocation of the Software SMI is not
484   // not allowed so return EFI_INVALID_PARAMETER.
485   //
486   if (EfiGoneVirtual()) {
487     return EFI_INVALID_PARAMETER;
488   }
489 
490   //
491   // If we are not in SMM, don't allow call SmiManage() directly when SMRAM is closed or locked.
492   //
493   if ((!gSmmCorePrivate->InSmm) && (!mSmmAccess->OpenState || mSmmAccess->LockState)) {
494     return EFI_INVALID_PARAMETER;
495   }
496 
497   //
498   // Save current InSmm state and set InSmm state to TRUE
499   //
500   OldInSmm = gSmmCorePrivate->InSmm;
501   gSmmCorePrivate->InSmm = TRUE;
502 
503   //
504   // Already in SMM and before SetVirtualAddressMap(), so call SmiManage() directly.
505   //
506   CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)CommBuffer;
507   *CommSize -= OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);
508   Status = gSmmCorePrivate->Smst->SmiManage (
509                                     &CommunicateHeader->HeaderGuid,
510                                     NULL,
511                                     CommunicateHeader->Data,
512                                     CommSize
513                                     );
514 
515   //
516   // Update CommunicationBuffer, BufferSize and ReturnStatus
517   // Communicate service finished, reset the pointer to CommBuffer to NULL
518   //
519   *CommSize += OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);
520 
521   //
522   // Restore original InSmm state
523   //
524   gSmmCorePrivate->InSmm = OldInSmm;
525 
526   return (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_NOT_FOUND;
527 }
528 
529 /**
530   Event notification that is fired when GUIDed Event Group is signaled.
531 
532   @param  Event                 The Event that is being processed, not used.
533   @param  Context               Event Context, not used.
534 
535 **/
536 VOID
537 EFIAPI
SmmIplGuidedEventNotify(IN EFI_EVENT Event,IN VOID * Context)538 SmmIplGuidedEventNotify (
539   IN EFI_EVENT  Event,
540   IN VOID       *Context
541   )
542 {
543   UINTN                       Size;
544 
545   //
546   // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure
547   //
548   CopyGuid (&mCommunicateHeader.HeaderGuid, (EFI_GUID *)Context);
549   mCommunicateHeader.MessageLength = 1;
550   mCommunicateHeader.Data[0] = 0;
551 
552   //
553   // Generate the Software SMI and return the result
554   //
555   Size = sizeof (mCommunicateHeader);
556   SmmCommunicationCommunicate (&mSmmCommunication, &mCommunicateHeader, &Size);
557 }
558 
559 /**
560   Event notification that is fired when DxeDispatch Event Group is signaled.
561 
562   @param  Event                 The Event that is being processed, not used.
563   @param  Context               Event Context, not used.
564 
565 **/
566 VOID
567 EFIAPI
SmmIplDxeDispatchEventNotify(IN EFI_EVENT Event,IN VOID * Context)568 SmmIplDxeDispatchEventNotify (
569   IN EFI_EVENT  Event,
570   IN VOID       *Context
571   )
572 {
573   UINTN                       Size;
574   EFI_STATUS                  Status;
575 
576   //
577   // Keep calling the SMM Core Dispatcher until there is no request to restart it.
578   //
579   while (TRUE) {
580     //
581     // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure
582     // Clear the buffer passed into the Software SMI.  This buffer will return
583     // the status of the SMM Core Dispatcher.
584     //
585     CopyGuid (&mCommunicateHeader.HeaderGuid, (EFI_GUID *)Context);
586     mCommunicateHeader.MessageLength = 1;
587     mCommunicateHeader.Data[0] = 0;
588 
589     //
590     // Generate the Software SMI and return the result
591     //
592     Size = sizeof (mCommunicateHeader);
593     SmmCommunicationCommunicate (&mSmmCommunication, &mCommunicateHeader, &Size);
594 
595     //
596     // Return if there is no request to restart the SMM Core Dispatcher
597     //
598     if (mCommunicateHeader.Data[0] != COMM_BUFFER_SMM_DISPATCH_RESTART) {
599       return;
600     }
601 
602     //
603     // Attempt to reset SMRAM cacheability to UC
604     // Assume CPU AP is available at this time
605     //
606     Status = gDS->SetMemorySpaceAttributes(
607                     mSmramCacheBase,
608                     mSmramCacheSize,
609                     EFI_MEMORY_UC
610                     );
611     if (EFI_ERROR (Status)) {
612       DEBUG ((DEBUG_WARN, "SMM IPL failed to reset SMRAM window to EFI_MEMORY_UC\n"));
613     }
614 
615     //
616     // Close all SMRAM ranges to protect SMRAM
617     //
618     Status = mSmmAccess->Close (mSmmAccess);
619     ASSERT_EFI_ERROR (Status);
620 
621     //
622     // Print debug message that the SMRAM window is now closed.
623     //
624     DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));
625   }
626 }
627 
628 /**
629   Event notification that is fired every time a gEfiSmmConfigurationProtocol installs.
630 
631   @param  Event                 The Event that is being processed, not used.
632   @param  Context               Event Context, not used.
633 
634 **/
635 VOID
636 EFIAPI
SmmIplSmmConfigurationEventNotify(IN EFI_EVENT Event,IN VOID * Context)637 SmmIplSmmConfigurationEventNotify (
638   IN EFI_EVENT  Event,
639   IN VOID       *Context
640   )
641 {
642   EFI_STATUS                      Status;
643   EFI_SMM_CONFIGURATION_PROTOCOL  *SmmConfiguration;
644 
645   //
646   // Make sure this notification is for this handler
647   //
648   Status = gBS->LocateProtocol (Context, NULL, (VOID **)&SmmConfiguration);
649   if (EFI_ERROR (Status)) {
650     return;
651   }
652 
653   //
654   // Register the SMM Entry Point provided by the SMM Core with the SMM COnfiguration protocol
655   //
656   Status = SmmConfiguration->RegisterSmmEntry (SmmConfiguration, gSmmCorePrivate->SmmEntryPoint);
657   ASSERT_EFI_ERROR (Status);
658 
659   //
660   // Set flag to indicate that the SMM Entry Point has been registered which
661   // means that SMIs are now fully operational.
662   //
663   gSmmCorePrivate->SmmEntryPointRegistered = TRUE;
664 
665   //
666   // Print debug message showing SMM Core entry point address.
667   //
668   DEBUG ((DEBUG_INFO, "SMM IPL registered SMM Entry Point address %p\n", (VOID *)(UINTN)gSmmCorePrivate->SmmEntryPoint));
669 }
670 
671 /**
672   Event notification that is fired every time a DxeSmmReadyToLock protocol is added
673   or if gEfiEventReadyToBootGuid is signaled.
674 
675   @param  Event                 The Event that is being processed, not used.
676   @param  Context               Event Context, not used.
677 
678 **/
679 VOID
680 EFIAPI
SmmIplReadyToLockEventNotify(IN EFI_EVENT Event,IN VOID * Context)681 SmmIplReadyToLockEventNotify (
682   IN EFI_EVENT  Event,
683   IN VOID       *Context
684   )
685 {
686   EFI_STATUS  Status;
687   VOID        *Interface;
688   UINTN       Index;
689 
690   //
691   // See if we are already locked
692   //
693   if (mSmmLocked) {
694     return;
695   }
696 
697   //
698   // Make sure this notification is for this handler
699   //
700   if (CompareGuid ((EFI_GUID *)Context, &gEfiDxeSmmReadyToLockProtocolGuid)) {
701     Status = gBS->LocateProtocol (&gEfiDxeSmmReadyToLockProtocolGuid, NULL, &Interface);
702     if (EFI_ERROR (Status)) {
703       return;
704     }
705   } else {
706     //
707     // If SMM is not locked yet and we got here from gEfiEventReadyToBootGuid being
708     // signaled, then gEfiDxeSmmReadyToLockProtocolGuid was not installed as expected.
709     // Print a warning on debug builds.
710     //
711     DEBUG ((DEBUG_WARN, "SMM IPL!  DXE SMM Ready To Lock Protocol not installed before Ready To Boot signal\n"));
712   }
713 
714   //
715   // Lock the SMRAM (Note: Locking SMRAM may not be supported on all platforms)
716   //
717   mSmmAccess->Lock (mSmmAccess);
718 
719   //
720   // Close protocol and event notification events that do not apply after the
721   // DXE SMM Ready To Lock Protocol has been installed or the Ready To Boot
722   // event has been signalled.
723   //
724   for (Index = 0; mSmmIplEvents[Index].NotifyFunction != NULL; Index++) {
725     if (mSmmIplEvents[Index].CloseOnLock) {
726       gBS->CloseEvent (mSmmIplEvents[Index].Event);
727     }
728   }
729 
730   //
731   // Inform SMM Core that the DxeSmmReadyToLock protocol was installed
732   //
733   SmmIplGuidedEventNotify (Event, (VOID *)&gEfiDxeSmmReadyToLockProtocolGuid);
734 
735   //
736   // Print debug message that the SMRAM window is now locked.
737   //
738   DEBUG ((DEBUG_INFO, "SMM IPL locked SMRAM window\n"));
739 
740   //
741   // Set flag so this operation will not be performed again
742   //
743   mSmmLocked = TRUE;
744 }
745 
746 /**
747   Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
748 
749   This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
750   It convers pointer to new virtual address.
751 
752   @param  Event        Event whose notification function is being invoked.
753   @param  Context      Pointer to the notification function's context.
754 
755 **/
756 VOID
757 EFIAPI
SmmIplSetVirtualAddressNotify(IN EFI_EVENT Event,IN VOID * Context)758 SmmIplSetVirtualAddressNotify (
759   IN EFI_EVENT  Event,
760   IN VOID       *Context
761   )
762 {
763   EfiConvertPointer (0x0, (VOID **)&mSmmControl2);
764 }
765 
766 /**
767   Get the fixed loadding address from image header assigned by build tool. This function only be called
768   when Loading module at Fixed address feature enabled.
769 
770   @param  ImageContext              Pointer to the image context structure that describes the PE/COFF
771                                     image that needs to be examined by this function.
772   @retval EFI_SUCCESS               An fixed loading address is assigned to this image by build tools .
773   @retval EFI_NOT_FOUND             The image has no assigned fixed loadding address.
774 **/
775 EFI_STATUS
GetPeCoffImageFixLoadingAssignedAddress(IN OUT PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext)776 GetPeCoffImageFixLoadingAssignedAddress(
777   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
778   )
779 {
780    UINTN                              SectionHeaderOffset;
781    EFI_STATUS                         Status;
782    EFI_IMAGE_SECTION_HEADER           SectionHeader;
783    EFI_IMAGE_OPTIONAL_HEADER_UNION    *ImgHdr;
784    EFI_PHYSICAL_ADDRESS               FixLoaddingAddress;
785    UINT16                             Index;
786    UINTN                              Size;
787    UINT16                             NumberOfSections;
788    EFI_PHYSICAL_ADDRESS               SmramBase;
789    UINT64                             SmmCodeSize;
790    UINT64                             ValueInSectionHeader;
791    //
792    // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
793    //
794    SmmCodeSize = EFI_PAGES_TO_SIZE (PcdGet32(PcdLoadFixAddressSmmCodePageNumber));
795 
796    FixLoaddingAddress = 0;
797    Status = EFI_NOT_FOUND;
798    SmramBase = mCurrentSmramRange->CpuStart;
799    //
800    // Get PeHeader pointer
801    //
802    ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
803    SectionHeaderOffset = (UINTN)(
804                                  ImageContext->PeCoffHeaderOffset +
805                                  sizeof (UINT32) +
806                                  sizeof (EFI_IMAGE_FILE_HEADER) +
807                                  ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
808                                  );
809    NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
810 
811    //
812    // Get base address from the first section header that doesn't point to code section.
813    //
814    for (Index = 0; Index < NumberOfSections; Index++) {
815      //
816      // Read section header from file
817      //
818      Size = sizeof (EFI_IMAGE_SECTION_HEADER);
819      Status = ImageContext->ImageRead (
820                               ImageContext->Handle,
821                               SectionHeaderOffset,
822                               &Size,
823                               &SectionHeader
824                               );
825      if (EFI_ERROR (Status)) {
826        return Status;
827      }
828 
829      Status = EFI_NOT_FOUND;
830 
831      if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
832        //
833        // Build tool saves the offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields in the
834        // first section header that doesn't point to code section in image header. And there is an assumption that when the
835        // feature is enabled, if a module is assigned a loading address by tools, PointerToRelocations & PointerToLineNumbers
836        // fields should NOT be Zero, or else, these 2 fileds should be set to Zero
837        //
838        ValueInSectionHeader = ReadUnaligned64((UINT64*)&SectionHeader.PointerToRelocations);
839        if (ValueInSectionHeader != 0) {
840          //
841          // Found first section header that doesn't point to code section in which uild tool saves the
842          // offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields
843          //
844          FixLoaddingAddress = (EFI_PHYSICAL_ADDRESS)(SmramBase + (INT64)ValueInSectionHeader);
845 
846          if (SmramBase + SmmCodeSize > FixLoaddingAddress && SmramBase <=  FixLoaddingAddress) {
847            //
848            // The assigned address is valid. Return the specified loadding address
849            //
850            ImageContext->ImageAddress = FixLoaddingAddress;
851            Status = EFI_SUCCESS;
852          }
853        }
854        break;
855      }
856      SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
857    }
858    DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address %x, Status = %r \n", FixLoaddingAddress, Status));
859    return Status;
860 }
861 /**
862   Load the SMM Core image into SMRAM and executes the SMM Core from SMRAM.
863 
864   @param[in, out] SmramRange            Descriptor for the range of SMRAM to reload the
865                                         currently executing image, the rang of SMRAM to
866                                         hold SMM Core will be excluded.
867   @param[in, out] SmramRangeSmmCore     Descriptor for the range of SMRAM to hold SMM Core.
868 
869   @param[in]      Context               Context to pass into SMM Core
870 
871   @return  EFI_STATUS
872 
873 **/
874 EFI_STATUS
ExecuteSmmCoreFromSmram(IN OUT EFI_SMRAM_DESCRIPTOR * SmramRange,IN OUT EFI_SMRAM_DESCRIPTOR * SmramRangeSmmCore,IN VOID * Context)875 ExecuteSmmCoreFromSmram (
876   IN OUT EFI_SMRAM_DESCRIPTOR   *SmramRange,
877   IN OUT EFI_SMRAM_DESCRIPTOR   *SmramRangeSmmCore,
878   IN     VOID                   *Context
879   )
880 {
881   EFI_STATUS                    Status;
882   VOID                          *SourceBuffer;
883   UINTN                         SourceSize;
884   PE_COFF_LOADER_IMAGE_CONTEXT  ImageContext;
885   UINTN                         PageCount;
886   EFI_IMAGE_ENTRY_POINT         EntryPoint;
887 
888   //
889   // Search all Firmware Volumes for a PE/COFF image in a file of type SMM_CORE
890   //
891   Status = GetSectionFromAnyFvByFileType (
892              EFI_FV_FILETYPE_SMM_CORE,
893              0,
894              EFI_SECTION_PE32,
895              0,
896              &SourceBuffer,
897              &SourceSize
898              );
899   if (EFI_ERROR (Status)) {
900     return Status;
901   }
902 
903   //
904   // Initilize ImageContext
905   //
906   ImageContext.Handle    = SourceBuffer;
907   ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
908 
909   //
910   // Get information about the image being loaded
911   //
912   Status = PeCoffLoaderGetImageInfo (&ImageContext);
913   if (EFI_ERROR (Status)) {
914     return Status;
915   }
916   //
917   // if Loading module at Fixed Address feature is enabled, the SMM core driver will be loaded to
918   // the address assigned by build tool.
919   //
920   if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
921     //
922     // Get the fixed loading address assigned by Build tool
923     //
924     Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext);
925     if (!EFI_ERROR (Status)) {
926       //
927       // Since the memory range to load SMM CORE will be cut out in SMM core, so no need to allocate and free this range
928       //
929       PageCount = 0;
930     } else {
931       DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR: Loading module at fixed address at address failed\n"));
932       //
933       // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR
934       // specified by SmramRange
935       //
936       PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
937 
938       ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
939       ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));
940 
941       SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount);
942       SmramRangeSmmCore->CpuStart = SmramRange->CpuStart + SmramRange->PhysicalSize;
943       SmramRangeSmmCore->PhysicalStart = SmramRange->PhysicalStart + SmramRange->PhysicalSize;
944       SmramRangeSmmCore->RegionState = SmramRange->RegionState | EFI_ALLOCATED;
945       SmramRangeSmmCore->PhysicalSize = EFI_PAGES_TO_SIZE (PageCount);
946 
947       //
948       // Align buffer on section boundary
949       //
950       ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart;
951     }
952   } else {
953     //
954     // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR
955     // specified by SmramRange
956     //
957     PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
958 
959     ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
960     ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));
961 
962     SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount);
963     SmramRangeSmmCore->CpuStart = SmramRange->CpuStart + SmramRange->PhysicalSize;
964     SmramRangeSmmCore->PhysicalStart = SmramRange->PhysicalStart + SmramRange->PhysicalSize;
965     SmramRangeSmmCore->RegionState = SmramRange->RegionState | EFI_ALLOCATED;
966     SmramRangeSmmCore->PhysicalSize = EFI_PAGES_TO_SIZE (PageCount);
967 
968     //
969     // Align buffer on section boundary
970     //
971     ImageContext.ImageAddress = SmramRangeSmmCore->CpuStart;
972   }
973 
974   ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
975   ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext.SectionAlignment - 1));
976 
977   //
978   // Print debug message showing SMM Core load address.
979   //
980   DEBUG ((DEBUG_INFO, "SMM IPL loading SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.ImageAddress));
981 
982   //
983   // Load the image to our new buffer
984   //
985   Status = PeCoffLoaderLoadImage (&ImageContext);
986   if (!EFI_ERROR (Status)) {
987     //
988     // Relocate the image in our new buffer
989     //
990     Status = PeCoffLoaderRelocateImage (&ImageContext);
991     if (!EFI_ERROR (Status)) {
992       //
993       // Flush the instruction cache so the image data are written before we execute it
994       //
995       InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
996 
997       //
998       // Print debug message showing SMM Core entry point address.
999       //
1000       DEBUG ((DEBUG_INFO, "SMM IPL calling SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.EntryPoint));
1001 
1002       gSmmCorePrivate->PiSmmCoreImageBase = ImageContext.ImageAddress;
1003       gSmmCorePrivate->PiSmmCoreImageSize = ImageContext.ImageSize;
1004       DEBUG ((DEBUG_INFO, "PiSmmCoreImageBase - 0x%016lx\n", gSmmCorePrivate->PiSmmCoreImageBase));
1005       DEBUG ((DEBUG_INFO, "PiSmmCoreImageSize - 0x%016lx\n", gSmmCorePrivate->PiSmmCoreImageSize));
1006 
1007       gSmmCorePrivate->PiSmmCoreEntryPoint = ImageContext.EntryPoint;
1008 
1009       //
1010       // Execute image
1011       //
1012       EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)ImageContext.EntryPoint;
1013       Status = EntryPoint ((EFI_HANDLE)Context, gST);
1014     }
1015   }
1016 
1017   //
1018   // Always free memory allocted by GetFileBufferByFilePath ()
1019   //
1020   FreePool (SourceBuffer);
1021 
1022   return Status;
1023 }
1024 
1025 /**
1026   SMM split SMRAM entry.
1027 
1028   @param[in, out] RangeToCompare             Pointer to EFI_SMRAM_DESCRIPTOR to compare.
1029   @param[in, out] ReservedRangeToCompare     Pointer to EFI_SMM_RESERVED_SMRAM_REGION to compare.
1030   @param[out]     Ranges                     Output pointer to hold split EFI_SMRAM_DESCRIPTOR entry.
1031   @param[in, out] RangeCount                 Pointer to range count.
1032   @param[out]     ReservedRanges             Output pointer to hold split EFI_SMM_RESERVED_SMRAM_REGION entry.
1033   @param[in, out] ReservedRangeCount         Pointer to reserved range count.
1034   @param[out]     FinalRanges                Output pointer to hold split final EFI_SMRAM_DESCRIPTOR entry
1035                                              that no need to be split anymore.
1036   @param[in, out] FinalRangeCount            Pointer to final range count.
1037 
1038 **/
1039 VOID
SmmSplitSmramEntry(IN OUT EFI_SMRAM_DESCRIPTOR * RangeToCompare,IN OUT EFI_SMM_RESERVED_SMRAM_REGION * ReservedRangeToCompare,OUT EFI_SMRAM_DESCRIPTOR * Ranges,IN OUT UINTN * RangeCount,OUT EFI_SMM_RESERVED_SMRAM_REGION * ReservedRanges,IN OUT UINTN * ReservedRangeCount,OUT EFI_SMRAM_DESCRIPTOR * FinalRanges,IN OUT UINTN * FinalRangeCount)1040 SmmSplitSmramEntry (
1041   IN OUT EFI_SMRAM_DESCRIPTOR           *RangeToCompare,
1042   IN OUT EFI_SMM_RESERVED_SMRAM_REGION  *ReservedRangeToCompare,
1043   OUT    EFI_SMRAM_DESCRIPTOR           *Ranges,
1044   IN OUT UINTN                          *RangeCount,
1045   OUT    EFI_SMM_RESERVED_SMRAM_REGION  *ReservedRanges,
1046   IN OUT UINTN                          *ReservedRangeCount,
1047   OUT    EFI_SMRAM_DESCRIPTOR           *FinalRanges,
1048   IN OUT UINTN                          *FinalRangeCount
1049   )
1050 {
1051   UINT64    RangeToCompareEnd;
1052   UINT64    ReservedRangeToCompareEnd;
1053 
1054   RangeToCompareEnd         = RangeToCompare->CpuStart + RangeToCompare->PhysicalSize;
1055   ReservedRangeToCompareEnd = ReservedRangeToCompare->SmramReservedStart + ReservedRangeToCompare->SmramReservedSize;
1056 
1057   if ((RangeToCompare->CpuStart >= ReservedRangeToCompare->SmramReservedStart) &&
1058       (RangeToCompare->CpuStart < ReservedRangeToCompareEnd)) {
1059     if (RangeToCompareEnd < ReservedRangeToCompareEnd) {
1060       //
1061       // RangeToCompare  ReservedRangeToCompare
1062       //                 ----                    ----    --------------------------------------
1063       //                 |  |                    |  | -> 1. ReservedRangeToCompare
1064       // ----            |  |                    |--|    --------------------------------------
1065       // |  |            |  |                    |  |
1066       // |  |            |  |                    |  | -> 2. FinalRanges[*FinalRangeCount] and increment *FinalRangeCount
1067       // |  |            |  |                    |  |       RangeToCompare->PhysicalSize = 0
1068       // ----            |  |                    |--|    --------------------------------------
1069       //                 |  |                    |  | -> 3. ReservedRanges[*ReservedRangeCount] and increment *ReservedRangeCount
1070       //                 ----                    ----    --------------------------------------
1071       //
1072 
1073       //
1074       // 1. Update ReservedRangeToCompare.
1075       //
1076       ReservedRangeToCompare->SmramReservedSize = RangeToCompare->CpuStart - ReservedRangeToCompare->SmramReservedStart;
1077       //
1078       // 2. Update FinalRanges[FinalRangeCount] and increment *FinalRangeCount.
1079       //    Zero RangeToCompare->PhysicalSize.
1080       //
1081       FinalRanges[*FinalRangeCount].CpuStart      = RangeToCompare->CpuStart;
1082       FinalRanges[*FinalRangeCount].PhysicalStart = RangeToCompare->PhysicalStart;
1083       FinalRanges[*FinalRangeCount].RegionState   = RangeToCompare->RegionState | EFI_ALLOCATED;
1084       FinalRanges[*FinalRangeCount].PhysicalSize  = RangeToCompare->PhysicalSize;
1085       *FinalRangeCount += 1;
1086       RangeToCompare->PhysicalSize = 0;
1087       //
1088       // 3. Update ReservedRanges[*ReservedRangeCount] and increment *ReservedRangeCount.
1089       //
1090       ReservedRanges[*ReservedRangeCount].SmramReservedStart = FinalRanges[*FinalRangeCount - 1].CpuStart + FinalRanges[*FinalRangeCount - 1].PhysicalSize;
1091       ReservedRanges[*ReservedRangeCount].SmramReservedSize  = ReservedRangeToCompareEnd - RangeToCompareEnd;
1092       *ReservedRangeCount += 1;
1093     } else {
1094       //
1095       // RangeToCompare  ReservedRangeToCompare
1096       //                 ----                    ----    --------------------------------------
1097       //                 |  |                    |  | -> 1. ReservedRangeToCompare
1098       // ----            |  |                    |--|    --------------------------------------
1099       // |  |            |  |                    |  |
1100       // |  |            |  |                    |  | -> 2. FinalRanges[*FinalRangeCount] and increment *FinalRangeCount
1101       // |  |            |  |                    |  |
1102       // |  |            ----                    |--|    --------------------------------------
1103       // |  |                                    |  | -> 3. RangeToCompare
1104       // ----                                    ----    --------------------------------------
1105       //
1106 
1107       //
1108       // 1. Update ReservedRangeToCompare.
1109       //
1110       ReservedRangeToCompare->SmramReservedSize = RangeToCompare->CpuStart - ReservedRangeToCompare->SmramReservedStart;
1111       //
1112       // 2. Update FinalRanges[FinalRangeCount] and increment *FinalRangeCount.
1113       //
1114       FinalRanges[*FinalRangeCount].CpuStart      = RangeToCompare->CpuStart;
1115       FinalRanges[*FinalRangeCount].PhysicalStart = RangeToCompare->PhysicalStart;
1116       FinalRanges[*FinalRangeCount].RegionState   = RangeToCompare->RegionState | EFI_ALLOCATED;
1117       FinalRanges[*FinalRangeCount].PhysicalSize  = ReservedRangeToCompareEnd - RangeToCompare->CpuStart;
1118       *FinalRangeCount += 1;
1119       //
1120       // 3. Update RangeToCompare.
1121       //
1122       RangeToCompare->CpuStart      += FinalRanges[*FinalRangeCount - 1].PhysicalSize;
1123       RangeToCompare->PhysicalStart += FinalRanges[*FinalRangeCount - 1].PhysicalSize;
1124       RangeToCompare->PhysicalSize  -= FinalRanges[*FinalRangeCount - 1].PhysicalSize;
1125     }
1126   } else if ((ReservedRangeToCompare->SmramReservedStart >= RangeToCompare->CpuStart) &&
1127              (ReservedRangeToCompare->SmramReservedStart < RangeToCompareEnd)) {
1128     if (ReservedRangeToCompareEnd < RangeToCompareEnd) {
1129       //
1130       // RangeToCompare  ReservedRangeToCompare
1131       // ----                                    ----    --------------------------------------
1132       // |  |                                    |  | -> 1. RangeToCompare
1133       // |  |            ----                    |--|    --------------------------------------
1134       // |  |            |  |                    |  |
1135       // |  |            |  |                    |  | -> 2. FinalRanges[*FinalRangeCount] and increment *FinalRangeCount
1136       // |  |            |  |                    |  |       ReservedRangeToCompare->SmramReservedSize = 0
1137       // |  |            ----                    |--|    --------------------------------------
1138       // |  |                                    |  | -> 3. Ranges[*RangeCount] and increment *RangeCount
1139       // ----                                    ----    --------------------------------------
1140       //
1141 
1142       //
1143       // 1. Update RangeToCompare.
1144       //
1145       RangeToCompare->PhysicalSize = ReservedRangeToCompare->SmramReservedStart - RangeToCompare->CpuStart;
1146       //
1147       // 2. Update FinalRanges[FinalRangeCount] and increment *FinalRangeCount.
1148       //    ReservedRangeToCompare->SmramReservedSize = 0
1149       //
1150       FinalRanges[*FinalRangeCount].CpuStart      = ReservedRangeToCompare->SmramReservedStart;
1151       FinalRanges[*FinalRangeCount].PhysicalStart = RangeToCompare->PhysicalStart + RangeToCompare->PhysicalSize;
1152       FinalRanges[*FinalRangeCount].RegionState   = RangeToCompare->RegionState | EFI_ALLOCATED;
1153       FinalRanges[*FinalRangeCount].PhysicalSize  = ReservedRangeToCompare->SmramReservedSize;
1154       *FinalRangeCount += 1;
1155       ReservedRangeToCompare->SmramReservedSize = 0;
1156       //
1157       // 3. Update Ranges[*RangeCount] and increment *RangeCount.
1158       //
1159       Ranges[*RangeCount].CpuStart      = FinalRanges[*FinalRangeCount - 1].CpuStart + FinalRanges[*FinalRangeCount - 1].PhysicalSize;
1160       Ranges[*RangeCount].PhysicalStart = FinalRanges[*FinalRangeCount - 1].PhysicalStart + FinalRanges[*FinalRangeCount - 1].PhysicalSize;
1161       Ranges[*RangeCount].RegionState   = RangeToCompare->RegionState;
1162       Ranges[*RangeCount].PhysicalSize  = RangeToCompareEnd - ReservedRangeToCompareEnd;
1163       *RangeCount += 1;
1164     } else {
1165       //
1166       // RangeToCompare  ReservedRangeToCompare
1167       // ----                                    ----    --------------------------------------
1168       // |  |                                    |  | -> 1. RangeToCompare
1169       // |  |            ----                    |--|    --------------------------------------
1170       // |  |            |  |                    |  |
1171       // |  |            |  |                    |  | -> 2. FinalRanges[*FinalRangeCount] and increment *FinalRangeCount
1172       // |  |            |  |                    |  |
1173       // ----            |  |                    |--|    --------------------------------------
1174       //                 |  |                    |  | -> 3. ReservedRangeToCompare
1175       //                 ----                    ----    --------------------------------------
1176       //
1177 
1178       //
1179       // 1. Update RangeToCompare.
1180       //
1181       RangeToCompare->PhysicalSize = ReservedRangeToCompare->SmramReservedStart - RangeToCompare->CpuStart;
1182       //
1183       // 2. Update FinalRanges[FinalRangeCount] and increment *FinalRangeCount.
1184       //    ReservedRangeToCompare->SmramReservedSize = 0
1185       //
1186       FinalRanges[*FinalRangeCount].CpuStart      = ReservedRangeToCompare->SmramReservedStart;
1187       FinalRanges[*FinalRangeCount].PhysicalStart = RangeToCompare->PhysicalStart + RangeToCompare->PhysicalSize;
1188       FinalRanges[*FinalRangeCount].RegionState   = RangeToCompare->RegionState | EFI_ALLOCATED;
1189       FinalRanges[*FinalRangeCount].PhysicalSize  = RangeToCompareEnd - ReservedRangeToCompare->SmramReservedStart;
1190       *FinalRangeCount += 1;
1191       //
1192       // 3. Update ReservedRangeToCompare.
1193       //
1194       ReservedRangeToCompare->SmramReservedStart += FinalRanges[*FinalRangeCount - 1].PhysicalSize;
1195       ReservedRangeToCompare->SmramReservedSize  -= FinalRanges[*FinalRangeCount - 1].PhysicalSize;
1196     }
1197   }
1198 }
1199 
1200 /**
1201   Returns if SMRAM range and SMRAM reserved range are overlapped.
1202 
1203   @param[in] RangeToCompare             Pointer to EFI_SMRAM_DESCRIPTOR to compare.
1204   @param[in] ReservedRangeToCompare     Pointer to EFI_SMM_RESERVED_SMRAM_REGION to compare.
1205 
1206   @retval TRUE  There is overlap.
1207   @retval FALSE There is no overlap.
1208 
1209 **/
1210 BOOLEAN
SmmIsSmramOverlap(IN EFI_SMRAM_DESCRIPTOR * RangeToCompare,IN EFI_SMM_RESERVED_SMRAM_REGION * ReservedRangeToCompare)1211 SmmIsSmramOverlap (
1212   IN EFI_SMRAM_DESCRIPTOR           *RangeToCompare,
1213   IN EFI_SMM_RESERVED_SMRAM_REGION  *ReservedRangeToCompare
1214   )
1215 {
1216   UINT64    RangeToCompareEnd;
1217   UINT64    ReservedRangeToCompareEnd;
1218 
1219   RangeToCompareEnd         = RangeToCompare->CpuStart + RangeToCompare->PhysicalSize;
1220   ReservedRangeToCompareEnd = ReservedRangeToCompare->SmramReservedStart + ReservedRangeToCompare->SmramReservedSize;
1221 
1222   if ((RangeToCompare->CpuStart >= ReservedRangeToCompare->SmramReservedStart) &&
1223       (RangeToCompare->CpuStart < ReservedRangeToCompareEnd)) {
1224     return TRUE;
1225   } else if ((ReservedRangeToCompare->SmramReservedStart >= RangeToCompare->CpuStart) &&
1226              (ReservedRangeToCompare->SmramReservedStart < RangeToCompareEnd)) {
1227     return TRUE;
1228   }
1229   return FALSE;
1230 }
1231 
1232 /**
1233   Get full SMRAM ranges.
1234 
1235   It will get SMRAM ranges from SmmAccess protocol and SMRAM reserved ranges from
1236   SmmConfiguration protocol, split the entries if there is overlap between them.
1237   It will also reserve one entry for SMM core.
1238 
1239   @param[out] FullSmramRangeCount   Output pointer to full SMRAM range count.
1240 
1241   @return Pointer to full SMRAM ranges.
1242 
1243 **/
1244 EFI_SMRAM_DESCRIPTOR *
GetFullSmramRanges(OUT UINTN * FullSmramRangeCount)1245 GetFullSmramRanges (
1246   OUT UINTN     *FullSmramRangeCount
1247   )
1248 {
1249   EFI_STATUS                        Status;
1250   EFI_SMM_CONFIGURATION_PROTOCOL    *SmmConfiguration;
1251   UINTN                             Size;
1252   UINTN                             Index;
1253   UINTN                             Index2;
1254   EFI_SMRAM_DESCRIPTOR              *FullSmramRanges;
1255   UINTN                             TempSmramRangeCount;
1256   EFI_SMRAM_DESCRIPTOR              *TempSmramRanges;
1257   UINTN                             SmramRangeCount;
1258   EFI_SMRAM_DESCRIPTOR              *SmramRanges;
1259   UINTN                             SmramReservedCount;
1260   EFI_SMM_RESERVED_SMRAM_REGION     *SmramReservedRanges;
1261   UINTN                             MaxCount;
1262   BOOLEAN                           Rescan;
1263 
1264   //
1265   // Get SMM Configuration Protocol if it is present.
1266   //
1267   SmmConfiguration = NULL;
1268   Status = gBS->LocateProtocol (&gEfiSmmConfigurationProtocolGuid, NULL, (VOID **) &SmmConfiguration);
1269 
1270   //
1271   // Get SMRAM information.
1272   //
1273   Size = 0;
1274   Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, NULL);
1275   ASSERT (Status == EFI_BUFFER_TOO_SMALL);
1276 
1277   SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
1278 
1279   //
1280   // Get SMRAM reserved region count.
1281   //
1282   SmramReservedCount = 0;
1283   if (SmmConfiguration != NULL) {
1284     while (SmmConfiguration->SmramReservedRegions[SmramReservedCount].SmramReservedSize != 0) {
1285       SmramReservedCount++;
1286     }
1287   }
1288 
1289   if (SmramReservedCount == 0) {
1290     //
1291     // No reserved SMRAM entry from SMM Configuration Protocol.
1292     // Reserve one entry for SMM Core in the full SMRAM ranges.
1293     //
1294     *FullSmramRangeCount = SmramRangeCount + 1;
1295     Size = (*FullSmramRangeCount) * sizeof (EFI_SMRAM_DESCRIPTOR);
1296     FullSmramRanges = (EFI_SMRAM_DESCRIPTOR *) AllocateZeroPool (Size);
1297     ASSERT (FullSmramRanges != NULL);
1298 
1299     Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, FullSmramRanges);
1300     ASSERT_EFI_ERROR (Status);
1301 
1302     return FullSmramRanges;
1303   }
1304 
1305   //
1306   // Why MaxCount = X + 2 * Y?
1307   // Take Y = 1 as example below, Y > 1 case is just the iteration of Y = 1.
1308   //
1309   //   X = 1 Y = 1     MaxCount = 3 = 1 + 2 * 1
1310   //   ----            ----
1311   //   |  |  ----      |--|
1312   //   |  |  |  |  ->  |  |
1313   //   |  |  ----      |--|
1314   //   ----            ----
1315   //
1316   //   X = 2 Y = 1     MaxCount = 4 = 2 + 2 * 1
1317   //   ----            ----
1318   //   |  |            |  |
1319   //   |  |  ----      |--|
1320   //   |  |  |  |      |  |
1321   //   |--|  |  |  ->  |--|
1322   //   |  |  |  |      |  |
1323   //   |  |  ----      |--|
1324   //   |  |            |  |
1325   //   ----            ----
1326   //
1327   //   X = 3 Y = 1     MaxCount = 5 = 3 + 2 * 1
1328   //   ----            ----
1329   //   |  |            |  |
1330   //   |  |  ----      |--|
1331   //   |--|  |  |      |--|
1332   //   |  |  |  |  ->  |  |
1333   //   |--|  |  |      |--|
1334   //   |  |  ----      |--|
1335   //   |  |            |  |
1336   //   ----            ----
1337   //
1338   //   ......
1339   //
1340   MaxCount = SmramRangeCount + 2 * SmramReservedCount;
1341 
1342   Size = MaxCount * sizeof (EFI_SMM_RESERVED_SMRAM_REGION);
1343   SmramReservedRanges = (EFI_SMM_RESERVED_SMRAM_REGION *) AllocatePool (Size);
1344   ASSERT (SmramReservedRanges != NULL);
1345   for (Index = 0; Index < SmramReservedCount; Index++) {
1346     CopyMem (&SmramReservedRanges[Index], &SmmConfiguration->SmramReservedRegions[Index], sizeof (EFI_SMM_RESERVED_SMRAM_REGION));
1347   }
1348 
1349   Size = MaxCount * sizeof (EFI_SMRAM_DESCRIPTOR);
1350   TempSmramRanges = (EFI_SMRAM_DESCRIPTOR *) AllocatePool (Size);
1351   ASSERT (TempSmramRanges != NULL);
1352   TempSmramRangeCount = 0;
1353 
1354   SmramRanges = (EFI_SMRAM_DESCRIPTOR *) AllocatePool (Size);
1355   ASSERT (SmramRanges != NULL);
1356   Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, SmramRanges);
1357   ASSERT_EFI_ERROR (Status);
1358 
1359   do {
1360     Rescan = FALSE;
1361     for (Index = 0; (Index < SmramRangeCount) && !Rescan; Index++) {
1362       //
1363       // Skip zero size entry.
1364       //
1365       if (SmramRanges[Index].PhysicalSize != 0) {
1366         for (Index2 = 0; (Index2 < SmramReservedCount) && !Rescan; Index2++) {
1367           //
1368           // Skip zero size entry.
1369           //
1370           if (SmramReservedRanges[Index2].SmramReservedSize != 0) {
1371             if (SmmIsSmramOverlap (
1372                   &SmramRanges[Index],
1373                   &SmramReservedRanges[Index2]
1374                   )) {
1375               //
1376               // There is overlap, need to split entry and then rescan.
1377               //
1378               SmmSplitSmramEntry (
1379                 &SmramRanges[Index],
1380                 &SmramReservedRanges[Index2],
1381                 SmramRanges,
1382                 &SmramRangeCount,
1383                 SmramReservedRanges,
1384                 &SmramReservedCount,
1385                 TempSmramRanges,
1386                 &TempSmramRangeCount
1387                 );
1388               Rescan = TRUE;
1389             }
1390           }
1391         }
1392         if (!Rescan) {
1393           //
1394           // No any overlap, copy the entry to the temp SMRAM ranges.
1395           // Zero SmramRanges[Index].PhysicalSize = 0;
1396           //
1397           CopyMem (&TempSmramRanges[TempSmramRangeCount++], &SmramRanges[Index], sizeof (EFI_SMRAM_DESCRIPTOR));
1398           SmramRanges[Index].PhysicalSize = 0;
1399         }
1400       }
1401     }
1402   } while (Rescan);
1403   ASSERT (TempSmramRangeCount <= MaxCount);
1404 
1405   //
1406   // Sort the entries,
1407   // and reserve one entry for SMM Core in the full SMRAM ranges.
1408   //
1409   FullSmramRanges = AllocateZeroPool ((TempSmramRangeCount + 1) * sizeof (EFI_SMRAM_DESCRIPTOR));
1410   ASSERT (FullSmramRanges != NULL);
1411   *FullSmramRangeCount = 0;
1412   do {
1413     for (Index = 0; Index < TempSmramRangeCount; Index++) {
1414       if (TempSmramRanges[Index].PhysicalSize != 0) {
1415         break;
1416       }
1417     }
1418     ASSERT (Index < TempSmramRangeCount);
1419     for (Index2 = 0; Index2 < TempSmramRangeCount; Index2++) {
1420       if ((Index2 != Index) && (TempSmramRanges[Index2].PhysicalSize != 0) && (TempSmramRanges[Index2].CpuStart < TempSmramRanges[Index].CpuStart)) {
1421         Index = Index2;
1422       }
1423     }
1424     CopyMem (&FullSmramRanges[*FullSmramRangeCount], &TempSmramRanges[Index], sizeof (EFI_SMRAM_DESCRIPTOR));
1425     *FullSmramRangeCount += 1;
1426     TempSmramRanges[Index].PhysicalSize = 0;
1427   } while (*FullSmramRangeCount < TempSmramRangeCount);
1428   ASSERT (*FullSmramRangeCount == TempSmramRangeCount);
1429   *FullSmramRangeCount += 1;
1430 
1431   FreePool (SmramRanges);
1432   FreePool (SmramReservedRanges);
1433   FreePool (TempSmramRanges);
1434 
1435   return FullSmramRanges;
1436 }
1437 
1438 /**
1439   The Entry Point for SMM IPL
1440 
1441   Load SMM Core into SMRAM, register SMM Core entry point for SMIs, install
1442   SMM Base 2 Protocol and SMM Communication Protocol, and register for the
1443   critical events required to coordinate between DXE and SMM environments.
1444 
1445   @param  ImageHandle    The firmware allocated handle for the EFI image.
1446   @param  SystemTable    A pointer to the EFI System Table.
1447 
1448   @retval EFI_SUCCESS    The entry point is executed successfully.
1449   @retval Other          Some error occurred when executing this entry point.
1450 
1451 **/
1452 EFI_STATUS
1453 EFIAPI
SmmIplEntry(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1454 SmmIplEntry (
1455   IN EFI_HANDLE        ImageHandle,
1456   IN EFI_SYSTEM_TABLE  *SystemTable
1457   )
1458 {
1459   EFI_STATUS                      Status;
1460   UINTN                           Index;
1461   UINT64                          MaxSize;
1462   VOID                            *Registration;
1463   UINT64                          SmmCodeSize;
1464   EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE    *LMFAConfigurationTable;
1465   EFI_CPU_ARCH_PROTOCOL           *CpuArch;
1466   EFI_STATUS                      SetAttrStatus;
1467 
1468   //
1469   // Fill in the image handle of the SMM IPL so the SMM Core can use this as the
1470   // ParentImageHandle field of the Load Image Protocol for all SMM Drivers loaded
1471   // by the SMM Core
1472   //
1473   mSmmCorePrivateData.SmmIplImageHandle = ImageHandle;
1474 
1475   //
1476   // Get SMM Access Protocol
1477   //
1478   Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&mSmmAccess);
1479   ASSERT_EFI_ERROR (Status);
1480 
1481   //
1482   // Get SMM Control2 Protocol
1483   //
1484   Status = gBS->LocateProtocol (&gEfiSmmControl2ProtocolGuid, NULL, (VOID **)&mSmmControl2);
1485   ASSERT_EFI_ERROR (Status);
1486 
1487   gSmmCorePrivate->SmramRanges = GetFullSmramRanges (&gSmmCorePrivate->SmramRangeCount);
1488 
1489   //
1490   // Open all SMRAM ranges
1491   //
1492   Status = mSmmAccess->Open (mSmmAccess);
1493   ASSERT_EFI_ERROR (Status);
1494 
1495   //
1496   // Print debug message that the SMRAM window is now open.
1497   //
1498   DEBUG ((DEBUG_INFO, "SMM IPL opened SMRAM window\n"));
1499 
1500   //
1501   // Find the largest SMRAM range between 1MB and 4GB that is at least 256KB - 4K in size
1502   //
1503   mCurrentSmramRange = NULL;
1504   for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < gSmmCorePrivate->SmramRangeCount; Index++) {
1505     //
1506     // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization
1507     //
1508     if ((gSmmCorePrivate->SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
1509       continue;
1510     }
1511 
1512     if (gSmmCorePrivate->SmramRanges[Index].CpuStart >= BASE_1MB) {
1513       if ((gSmmCorePrivate->SmramRanges[Index].CpuStart + gSmmCorePrivate->SmramRanges[Index].PhysicalSize) <= BASE_4GB) {
1514         if (gSmmCorePrivate->SmramRanges[Index].PhysicalSize >= MaxSize) {
1515           MaxSize = gSmmCorePrivate->SmramRanges[Index].PhysicalSize;
1516           mCurrentSmramRange = &gSmmCorePrivate->SmramRanges[Index];
1517         }
1518       }
1519     }
1520   }
1521 
1522   if (mCurrentSmramRange != NULL) {
1523     //
1524     // Print debug message showing SMRAM window that will be used by SMM IPL and SMM Core
1525     //
1526     DEBUG ((DEBUG_INFO, "SMM IPL found SMRAM window %p - %p\n",
1527       (VOID *)(UINTN)mCurrentSmramRange->CpuStart,
1528       (VOID *)(UINTN)(mCurrentSmramRange->CpuStart + mCurrentSmramRange->PhysicalSize - 1)
1529       ));
1530 
1531     GetSmramCacheRange (mCurrentSmramRange, &mSmramCacheBase, &mSmramCacheSize);
1532     //
1533     // If CPU AP is present, attempt to set SMRAM cacheability to WB
1534     // Note that it is expected that cacheability of SMRAM has been set to WB if CPU AP
1535     // is not available here.
1536     //
1537     CpuArch = NULL;
1538     Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&CpuArch);
1539     if (!EFI_ERROR (Status)) {
1540       Status = gDS->SetMemorySpaceAttributes(
1541                       mSmramCacheBase,
1542                       mSmramCacheSize,
1543                       EFI_MEMORY_WB
1544                       );
1545       if (EFI_ERROR (Status)) {
1546         DEBUG ((DEBUG_WARN, "SMM IPL failed to set SMRAM window to EFI_MEMORY_WB\n"));
1547       }
1548     }
1549     //
1550     // if Loading module at Fixed Address feature is enabled, save the SMRAM base to Load
1551     // Modules At Fixed Address Configuration Table.
1552     //
1553     if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
1554       //
1555       // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
1556       //
1557       SmmCodeSize = LShiftU64 (PcdGet32(PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT);
1558       //
1559       // The SMRAM available memory is assumed to be larger than SmmCodeSize
1560       //
1561       ASSERT (mCurrentSmramRange->PhysicalSize > SmmCodeSize);
1562       //
1563       // Retrieve Load modules At fixed address configuration table and save the SMRAM base.
1564       //
1565       Status = EfiGetSystemConfigurationTable (
1566                 &gLoadFixedAddressConfigurationTableGuid,
1567                (VOID **) &LMFAConfigurationTable
1568                );
1569       if (!EFI_ERROR (Status) && LMFAConfigurationTable != NULL) {
1570         LMFAConfigurationTable->SmramBase = mCurrentSmramRange->CpuStart;
1571         //
1572         // Print the SMRAM base
1573         //
1574         DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: TSEG BASE is %x. \n", LMFAConfigurationTable->SmramBase));
1575       }
1576     }
1577     //
1578     // Load SMM Core into SMRAM and execute it from SMRAM
1579     //
1580     Status = ExecuteSmmCoreFromSmram (
1581                mCurrentSmramRange,
1582                &gSmmCorePrivate->SmramRanges[gSmmCorePrivate->SmramRangeCount - 1],
1583                gSmmCorePrivate
1584                );
1585     if (EFI_ERROR (Status)) {
1586       //
1587       // Print error message that the SMM Core failed to be loaded and executed.
1588       //
1589       DEBUG ((DEBUG_ERROR, "SMM IPL could not load and execute SMM Core from SMRAM\n"));
1590 
1591       //
1592       // Attempt to reset SMRAM cacheability to UC
1593       //
1594       if (CpuArch != NULL) {
1595         SetAttrStatus = gDS->SetMemorySpaceAttributes(
1596                                mSmramCacheBase,
1597                                mSmramCacheSize,
1598                                EFI_MEMORY_UC
1599                                );
1600         if (EFI_ERROR (SetAttrStatus)) {
1601           DEBUG ((DEBUG_WARN, "SMM IPL failed to reset SMRAM window to EFI_MEMORY_UC\n"));
1602         }
1603       }
1604     }
1605   } else {
1606     //
1607     // Print error message that there are not enough SMRAM resources to load the SMM Core.
1608     //
1609     DEBUG ((DEBUG_ERROR, "SMM IPL could not find a large enough SMRAM region to load SMM Core\n"));
1610   }
1611 
1612   //
1613   // If the SMM Core could not be loaded then close SMRAM window, free allocated
1614   // resources, and return an error so SMM IPL will be unloaded.
1615   //
1616   if (mCurrentSmramRange == NULL || EFI_ERROR (Status)) {
1617     //
1618     // Close all SMRAM ranges
1619     //
1620     Status = mSmmAccess->Close (mSmmAccess);
1621     ASSERT_EFI_ERROR (Status);
1622 
1623     //
1624     // Print debug message that the SMRAM window is now closed.
1625     //
1626     DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));
1627 
1628     //
1629     // Free all allocated resources
1630     //
1631     FreePool (gSmmCorePrivate->SmramRanges);
1632 
1633     return EFI_UNSUPPORTED;
1634   }
1635 
1636   //
1637   // Install SMM Base2 Protocol and SMM Communication Protocol
1638   //
1639   Status = gBS->InstallMultipleProtocolInterfaces (
1640                   &mSmmIplHandle,
1641                   &gEfiSmmBase2ProtocolGuid,         &mSmmBase2,
1642                   &gEfiSmmCommunicationProtocolGuid, &mSmmCommunication,
1643                   NULL
1644                   );
1645   ASSERT_EFI_ERROR (Status);
1646 
1647   //
1648   // Create the set of protocol and event notififcations that the SMM IPL requires
1649   //
1650   for (Index = 0; mSmmIplEvents[Index].NotifyFunction != NULL; Index++) {
1651     if (mSmmIplEvents[Index].Protocol) {
1652       mSmmIplEvents[Index].Event = EfiCreateProtocolNotifyEvent (
1653                                      mSmmIplEvents[Index].Guid,
1654                                      mSmmIplEvents[Index].NotifyTpl,
1655                                      mSmmIplEvents[Index].NotifyFunction,
1656                                      mSmmIplEvents[Index].NotifyContext,
1657                                     &Registration
1658                                     );
1659     } else {
1660       Status = gBS->CreateEventEx (
1661                       EVT_NOTIFY_SIGNAL,
1662                       mSmmIplEvents[Index].NotifyTpl,
1663                       mSmmIplEvents[Index].NotifyFunction,
1664                       mSmmIplEvents[Index].NotifyContext,
1665                       mSmmIplEvents[Index].Guid,
1666                       &mSmmIplEvents[Index].Event
1667                       );
1668       ASSERT_EFI_ERROR (Status);
1669     }
1670   }
1671 
1672   return EFI_SUCCESS;
1673 }
1674