]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c
b0e387401c9fc7b1d1faa75df1baa0028a754497
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / PiSmmIpl.c
1 /** @file
2 SMM IPL that produces SMM related runtime protocols and load the SMM Core into SMRAM
3
4 Copyright (c) 2009 - 2014, 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 //
250 // Table of Protocol notification and GUIDed Event notifications that the SMM IPL requires
251 //
252 SMM_IPL_EVENT_NOTIFICATION mSmmIplEvents[] = {
253 //
254 // Declare protocol notification on the SMM Configuration protocol. When this notification is etablished,
255 // the associated event is immediately signalled, so the notification function will be executed and the
256 // SMM Configuration Protocol will be found if it is already in the handle database.
257 //
258 { TRUE, FALSE, &gEfiSmmConfigurationProtocolGuid, SmmIplSmmConfigurationEventNotify, &gEfiSmmConfigurationProtocolGuid, TPL_NOTIFY, NULL },
259 //
260 // Declare protocl notification on DxeSmmReadyToLock protocols. When this notification is etablished,
261 // the associated event is immediately signalled, so the notification function will be executed and the
262 // DXE SMM Ready To Lock Protocol will be found if it is already in the handle database.
263 //
264 { TRUE, TRUE, &gEfiDxeSmmReadyToLockProtocolGuid, SmmIplReadyToLockEventNotify, &gEfiDxeSmmReadyToLockProtocolGuid, TPL_CALLBACK, NULL },
265 //
266 // Declare event notification on EndOfDxe event. When this notification is etablished,
267 // the associated event is immediately signalled, so the notification function will be executed and the
268 // SMM End Of Dxe Protocol will be found if it is already in the handle database.
269 //
270 { FALSE, FALSE, &gEfiEndOfDxeEventGroupGuid, SmmIplGuidedEventNotify, &gEfiEndOfDxeEventGroupGuid, TPL_CALLBACK, NULL },
271 //
272 // Declare event notification on the DXE Dispatch Event Group. This event is signaled by the DXE Core
273 // each time the DXE Core dispatcher has completed its work. When this event is signalled, the SMM Core
274 // if notified, so the SMM Core can dispatch SMM drivers.
275 //
276 { FALSE, TRUE, &gEfiEventDxeDispatchGuid, SmmIplDxeDispatchEventNotify, &gEfiEventDxeDispatchGuid, TPL_CALLBACK, NULL },
277 //
278 // Declare event notification on Ready To Boot Event Group. This is an extra event notification that is
279 // used to make sure SMRAM is locked before any boot options are processed.
280 //
281 { FALSE, TRUE, &gEfiEventReadyToBootGuid, SmmIplReadyToLockEventNotify, &gEfiEventReadyToBootGuid, TPL_CALLBACK, NULL },
282 //
283 // Declare event notification on Legacy Boot Event Group. This is used to inform the SMM Core that the platform
284 // is performing a legacy boot operation, and that the UEFI environment is no longer available and the SMM Core
285 // must guarantee that it does not access any UEFI related structures outside of SMRAM.
286 //
287 { FALSE, FALSE, &gEfiEventLegacyBootGuid, SmmIplGuidedEventNotify, &gEfiEventLegacyBootGuid, TPL_CALLBACK, NULL },
288 //
289 // Declare event notification on SetVirtualAddressMap() Event Group. This is used to convert gSmmCorePrivate
290 // and mSmmControl2 from physical addresses to virtual addresses.
291 //
292 { FALSE, FALSE, &gEfiEventVirtualAddressChangeGuid, SmmIplSetVirtualAddressNotify, NULL, TPL_CALLBACK, NULL },
293 //
294 // Terminate the table of event notifications
295 //
296 { FALSE, FALSE, NULL, NULL, NULL, TPL_CALLBACK, NULL }
297 };
298
299 /**
300 Find the maximum SMRAM cache range that covers the range specified by SmramRange.
301
302 This function searches and joins all adjacent ranges of SmramRange into a range to be cached.
303
304 @param SmramRange The SMRAM range to search from.
305 @param SmramCacheBase The returned cache range base.
306 @param SmramCacheSize The returned cache range size.
307
308 **/
309 VOID
310 GetSmramCacheRange (
311 IN EFI_SMRAM_DESCRIPTOR *SmramRange,
312 OUT EFI_PHYSICAL_ADDRESS *SmramCacheBase,
313 OUT UINT64 *SmramCacheSize
314 )
315 {
316 UINTN Index;
317 EFI_PHYSICAL_ADDRESS RangeCpuStart;
318 UINT64 RangePhysicalSize;
319 BOOLEAN FoundAjacentRange;
320
321 *SmramCacheBase = SmramRange->CpuStart;
322 *SmramCacheSize = SmramRange->PhysicalSize;
323
324 do {
325 FoundAjacentRange = FALSE;
326 for (Index = 0; Index < gSmmCorePrivate->SmramRangeCount; Index++) {
327 RangeCpuStart = gSmmCorePrivate->SmramRanges[Index].CpuStart;
328 RangePhysicalSize = gSmmCorePrivate->SmramRanges[Index].PhysicalSize;
329 if (RangeCpuStart < *SmramCacheBase && *SmramCacheBase == (RangeCpuStart + RangePhysicalSize)) {
330 *SmramCacheBase = RangeCpuStart;
331 *SmramCacheSize += RangePhysicalSize;
332 FoundAjacentRange = TRUE;
333 } else if ((*SmramCacheBase + *SmramCacheSize) == RangeCpuStart && RangePhysicalSize > 0) {
334 *SmramCacheSize += RangePhysicalSize;
335 FoundAjacentRange = TRUE;
336 }
337 }
338 } while (FoundAjacentRange);
339
340 }
341
342 /**
343 Indicate whether the driver is currently executing in the SMM Initialization phase.
344
345 @param This The EFI_SMM_BASE2_PROTOCOL instance.
346 @param InSmram Pointer to a Boolean which, on return, indicates that the driver is currently executing
347 inside of SMRAM (TRUE) or outside of SMRAM (FALSE).
348
349 @retval EFI_INVALID_PARAMETER InSmram was NULL.
350 @retval EFI_SUCCESS The call returned successfully.
351
352 **/
353 EFI_STATUS
354 EFIAPI
355 SmmBase2InSmram (
356 IN CONST EFI_SMM_BASE2_PROTOCOL *This,
357 OUT BOOLEAN *InSmram
358 )
359 {
360 if (InSmram == NULL) {
361 return EFI_INVALID_PARAMETER;
362 }
363
364 *InSmram = gSmmCorePrivate->InSmm;
365
366 return EFI_SUCCESS;
367 }
368
369 /**
370 Retrieves the location of the System Management System Table (SMST).
371
372 @param This The EFI_SMM_BASE2_PROTOCOL instance.
373 @param Smst On return, points to a pointer to the System Management Service Table (SMST).
374
375 @retval EFI_INVALID_PARAMETER Smst or This was invalid.
376 @retval EFI_SUCCESS The memory was returned to the system.
377 @retval EFI_UNSUPPORTED Not in SMM.
378
379 **/
380 EFI_STATUS
381 EFIAPI
382 SmmBase2GetSmstLocation (
383 IN CONST EFI_SMM_BASE2_PROTOCOL *This,
384 OUT EFI_SMM_SYSTEM_TABLE2 **Smst
385 )
386 {
387 if ((This == NULL) ||(Smst == NULL)) {
388 return EFI_INVALID_PARAMETER;
389 }
390
391 if (!gSmmCorePrivate->InSmm) {
392 return EFI_UNSUPPORTED;
393 }
394
395 *Smst = gSmmCorePrivate->Smst;
396
397 return EFI_SUCCESS;
398 }
399
400 /**
401 Communicates with a registered handler.
402
403 This function provides a service to send and receive messages from a registered
404 UEFI service. This function is part of the SMM Communication Protocol that may
405 be called in physical mode prior to SetVirtualAddressMap() and in virtual mode
406 after SetVirtualAddressMap().
407
408 @param[in] This The EFI_SMM_COMMUNICATION_PROTOCOL instance.
409 @param[in, out] CommBuffer A pointer to the buffer to convey into SMRAM.
410 @param[in, out] CommSize The size of the data buffer being passed in.On exit, the size of data
411 being returned. Zero if the handler does not wish to reply with any data.
412
413 @retval EFI_SUCCESS The message was successfully posted.
414 @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.
415 **/
416 EFI_STATUS
417 EFIAPI
418 SmmCommunicationCommunicate (
419 IN CONST EFI_SMM_COMMUNICATION_PROTOCOL *This,
420 IN OUT VOID *CommBuffer,
421 IN OUT UINTN *CommSize
422 )
423 {
424 EFI_STATUS Status;
425 EFI_SMM_COMMUNICATE_HEADER *CommunicateHeader;
426 BOOLEAN OldInSmm;
427
428 //
429 // Check parameters
430 //
431 if ((CommBuffer == NULL) || (CommSize == NULL)) {
432 return EFI_INVALID_PARAMETER;
433 }
434
435 //
436 // CommSize must hold HeaderGuid and MessageLength
437 //
438 if (*CommSize < OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)) {
439 return EFI_INVALID_PARAMETER;
440 }
441
442 //
443 // If not already in SMM, then generate a Software SMI
444 //
445 if (!gSmmCorePrivate->InSmm && gSmmCorePrivate->SmmEntryPointRegistered) {
446 //
447 // Put arguments for Software SMI in gSmmCorePrivate
448 //
449 gSmmCorePrivate->CommunicationBuffer = CommBuffer;
450 gSmmCorePrivate->BufferSize = *CommSize;
451
452 //
453 // Generate Software SMI
454 //
455 Status = mSmmControl2->Trigger (mSmmControl2, NULL, NULL, FALSE, 0);
456 if (EFI_ERROR (Status)) {
457 return EFI_UNSUPPORTED;
458 }
459
460 //
461 // Return status from software SMI
462 //
463 *CommSize = gSmmCorePrivate->BufferSize;
464 return gSmmCorePrivate->ReturnStatus;
465 }
466
467 //
468 // If we are in SMM, then the execution mode must be physical, which means that
469 // OS established virtual addresses can not be used. If SetVirtualAddressMap()
470 // has been called, then a direct invocation of the Software SMI is not
471 // not allowed so return EFI_INVALID_PARAMETER.
472 //
473 if (EfiGoneVirtual()) {
474 return EFI_INVALID_PARAMETER;
475 }
476
477 //
478 // If we are not in SMM, don't allow call SmiManage() directly when SMRAM is closed or locked.
479 //
480 if ((!gSmmCorePrivate->InSmm) && (!mSmmAccess->OpenState || mSmmAccess->LockState)) {
481 return EFI_INVALID_PARAMETER;
482 }
483
484 //
485 // Save current InSmm state and set InSmm state to TRUE
486 //
487 OldInSmm = gSmmCorePrivate->InSmm;
488 gSmmCorePrivate->InSmm = TRUE;
489
490 //
491 // Already in SMM and before SetVirtualAddressMap(), so call SmiManage() directly.
492 //
493 CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)CommBuffer;
494 *CommSize -= OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);
495 Status = gSmmCorePrivate->Smst->SmiManage (
496 &CommunicateHeader->HeaderGuid,
497 NULL,
498 CommunicateHeader->Data,
499 CommSize
500 );
501
502 //
503 // Update CommunicationBuffer, BufferSize and ReturnStatus
504 // Communicate service finished, reset the pointer to CommBuffer to NULL
505 //
506 *CommSize += OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);
507
508 //
509 // Restore original InSmm state
510 //
511 gSmmCorePrivate->InSmm = OldInSmm;
512
513 return (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_NOT_FOUND;
514 }
515
516 /**
517 Event notification that is fired when GUIDed Event Group is signaled.
518
519 @param Event The Event that is being processed, not used.
520 @param Context Event Context, not used.
521
522 **/
523 VOID
524 EFIAPI
525 SmmIplGuidedEventNotify (
526 IN EFI_EVENT Event,
527 IN VOID *Context
528 )
529 {
530 EFI_SMM_COMMUNICATE_HEADER CommunicateHeader;
531 UINTN Size;
532
533 //
534 // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure
535 //
536 CopyGuid (&CommunicateHeader.HeaderGuid, (EFI_GUID *)Context);
537 CommunicateHeader.MessageLength = 1;
538 CommunicateHeader.Data[0] = 0;
539
540 //
541 // Generate the Software SMI and return the result
542 //
543 Size = sizeof (CommunicateHeader);
544 SmmCommunicationCommunicate (&mSmmCommunication, &CommunicateHeader, &Size);
545 }
546
547 /**
548 Event notification that is fired when DxeDispatch Event Group is signaled.
549
550 @param Event The Event that is being processed, not used.
551 @param Context Event Context, not used.
552
553 **/
554 VOID
555 EFIAPI
556 SmmIplDxeDispatchEventNotify (
557 IN EFI_EVENT Event,
558 IN VOID *Context
559 )
560 {
561 EFI_SMM_COMMUNICATE_HEADER CommunicateHeader;
562 UINTN Size;
563 EFI_STATUS Status;
564
565 //
566 // Keep calling the SMM Core Dispatcher until there is no request to restart it.
567 //
568 while (TRUE) {
569 //
570 // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure
571 // Clear the buffer passed into the Software SMI. This buffer will return
572 // the status of the SMM Core Dispatcher.
573 //
574 CopyGuid (&CommunicateHeader.HeaderGuid, (EFI_GUID *)Context);
575 CommunicateHeader.MessageLength = 1;
576 CommunicateHeader.Data[0] = 0;
577
578 //
579 // Generate the Software SMI and return the result
580 //
581 Size = sizeof (CommunicateHeader);
582 SmmCommunicationCommunicate (&mSmmCommunication, &CommunicateHeader, &Size);
583
584 //
585 // Return if there is no request to restart the SMM Core Dispatcher
586 //
587 if (CommunicateHeader.Data[0] != COMM_BUFFER_SMM_DISPATCH_RESTART) {
588 return;
589 }
590
591 //
592 // Attempt to reset SMRAM cacheability to UC
593 // Assume CPU AP is available at this time
594 //
595 Status = gDS->SetMemorySpaceAttributes(
596 mSmramCacheBase,
597 mSmramCacheSize,
598 EFI_MEMORY_UC
599 );
600 if (EFI_ERROR (Status)) {
601 DEBUG ((DEBUG_WARN, "SMM IPL failed to reset SMRAM window to EFI_MEMORY_UC\n"));
602 }
603
604 //
605 // Close all SMRAM ranges to protect SMRAM
606 //
607 Status = mSmmAccess->Close (mSmmAccess);
608 ASSERT_EFI_ERROR (Status);
609
610 //
611 // Print debug message that the SMRAM window is now closed.
612 //
613 DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));
614 }
615 }
616
617 /**
618 Event notification that is fired every time a gEfiSmmConfigurationProtocol installs.
619
620 @param Event The Event that is being processed, not used.
621 @param Context Event Context, not used.
622
623 **/
624 VOID
625 EFIAPI
626 SmmIplSmmConfigurationEventNotify (
627 IN EFI_EVENT Event,
628 IN VOID *Context
629 )
630 {
631 EFI_STATUS Status;
632 EFI_SMM_CONFIGURATION_PROTOCOL *SmmConfiguration;
633
634 //
635 // Make sure this notification is for this handler
636 //
637 Status = gBS->LocateProtocol (Context, NULL, (VOID **)&SmmConfiguration);
638 if (EFI_ERROR (Status)) {
639 return;
640 }
641
642 //
643 // Register the SMM Entry Point provided by the SMM Core with the SMM COnfiguration protocol
644 //
645 Status = SmmConfiguration->RegisterSmmEntry (SmmConfiguration, gSmmCorePrivate->SmmEntryPoint);
646 ASSERT_EFI_ERROR (Status);
647
648 //
649 // Set flag to indicate that the SMM Entry Point has been registered which
650 // means that SMIs are now fully operational.
651 //
652 gSmmCorePrivate->SmmEntryPointRegistered = TRUE;
653
654 //
655 // Print debug message showing SMM Core entry point address.
656 //
657 DEBUG ((DEBUG_INFO, "SMM IPL registered SMM Entry Point address %p\n", (VOID *)(UINTN)gSmmCorePrivate->SmmEntryPoint));
658 }
659
660 /**
661 Event notification that is fired every time a DxeSmmReadyToLock protocol is added
662 or if gEfiEventReadyToBootGuid is signalled.
663
664 @param Event The Event that is being processed, not used.
665 @param Context Event Context, not used.
666
667 **/
668 VOID
669 EFIAPI
670 SmmIplReadyToLockEventNotify (
671 IN EFI_EVENT Event,
672 IN VOID *Context
673 )
674 {
675 EFI_STATUS Status;
676 VOID *Interface;
677 UINTN Index;
678
679 //
680 // See if we are already locked
681 //
682 if (mSmmLocked) {
683 return;
684 }
685
686 //
687 // Make sure this notification is for this handler
688 //
689 if (CompareGuid ((EFI_GUID *)Context, &gEfiDxeSmmReadyToLockProtocolGuid)) {
690 Status = gBS->LocateProtocol (&gEfiDxeSmmReadyToLockProtocolGuid, NULL, &Interface);
691 if (EFI_ERROR (Status)) {
692 return;
693 }
694 } else {
695 //
696 // If SMM is not locked yet and we got here from gEfiEventReadyToBootGuid being
697 // signalled, then gEfiDxeSmmReadyToLockProtocolGuid was not installed as expected.
698 // Print a warning on debug builds.
699 //
700 DEBUG ((DEBUG_WARN, "SMM IPL! DXE SMM Ready To Lock Protocol not installed before Ready To Boot signal\n"));
701 }
702
703 //
704 // Lock the SMRAM (Note: Locking SMRAM may not be supported on all platforms)
705 //
706 mSmmAccess->Lock (mSmmAccess);
707
708 //
709 // Close protocol and event notification events that do not apply after the
710 // DXE SMM Ready To Lock Protocol has been installed or the Ready To Boot
711 // event has been signalled.
712 //
713 for (Index = 0; mSmmIplEvents[Index].NotifyFunction != NULL; Index++) {
714 if (mSmmIplEvents[Index].CloseOnLock) {
715 gBS->CloseEvent (mSmmIplEvents[Index].Event);
716 }
717 }
718
719 //
720 // Inform SMM Core that the DxeSmmReadyToLock protocol was installed
721 //
722 SmmIplGuidedEventNotify (Event, (VOID *)&gEfiDxeSmmReadyToLockProtocolGuid);
723
724 //
725 // Print debug message that the SMRAM window is now locked.
726 //
727 DEBUG ((DEBUG_INFO, "SMM IPL locked SMRAM window\n"));
728
729 //
730 // Set flag so this operation will not be performed again
731 //
732 mSmmLocked = TRUE;
733 }
734
735 /**
736 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
737
738 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
739 It convers pointer to new virtual address.
740
741 @param Event Event whose notification function is being invoked.
742 @param Context Pointer to the notification function's context.
743
744 **/
745 VOID
746 EFIAPI
747 SmmIplSetVirtualAddressNotify (
748 IN EFI_EVENT Event,
749 IN VOID *Context
750 )
751 {
752 EfiConvertPointer (0x0, (VOID **)&mSmmControl2);
753 }
754
755 /**
756 Get the fixed loadding address from image header assigned by build tool. This function only be called
757 when Loading module at Fixed address feature enabled.
758
759 @param ImageContext Pointer to the image context structure that describes the PE/COFF
760 image that needs to be examined by this function.
761 @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .
762 @retval EFI_NOT_FOUND The image has no assigned fixed loadding address.
763 **/
764 EFI_STATUS
765 GetPeCoffImageFixLoadingAssignedAddress(
766 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
767 )
768 {
769 UINTN SectionHeaderOffset;
770 EFI_STATUS Status;
771 EFI_IMAGE_SECTION_HEADER SectionHeader;
772 EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
773 EFI_PHYSICAL_ADDRESS FixLoaddingAddress;
774 UINT16 Index;
775 UINTN Size;
776 UINT16 NumberOfSections;
777 EFI_PHYSICAL_ADDRESS SmramBase;
778 UINT64 SmmCodeSize;
779 UINT64 ValueInSectionHeader;
780 //
781 // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
782 //
783 SmmCodeSize = EFI_PAGES_TO_SIZE (PcdGet32(PcdLoadFixAddressSmmCodePageNumber));
784
785 FixLoaddingAddress = 0;
786 Status = EFI_NOT_FOUND;
787 SmramBase = mCurrentSmramRange->CpuStart;
788 //
789 // Get PeHeader pointer
790 //
791 ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
792 SectionHeaderOffset = (UINTN)(
793 ImageContext->PeCoffHeaderOffset +
794 sizeof (UINT32) +
795 sizeof (EFI_IMAGE_FILE_HEADER) +
796 ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
797 );
798 NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
799
800 //
801 // Get base address from the first section header that doesn't point to code section.
802 //
803 for (Index = 0; Index < NumberOfSections; Index++) {
804 //
805 // Read section header from file
806 //
807 Size = sizeof (EFI_IMAGE_SECTION_HEADER);
808 Status = ImageContext->ImageRead (
809 ImageContext->Handle,
810 SectionHeaderOffset,
811 &Size,
812 &SectionHeader
813 );
814 if (EFI_ERROR (Status)) {
815 return Status;
816 }
817
818 Status = EFI_NOT_FOUND;
819
820 if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
821 //
822 // Build tool saves the offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields in the
823 // first section header that doesn't point to code section in image header. And there is an assumption that when the
824 // feature is enabled, if a module is assigned a loading address by tools, PointerToRelocations & PointerToLineNumbers
825 // fields should NOT be Zero, or else, these 2 fileds should be set to Zero
826 //
827 ValueInSectionHeader = ReadUnaligned64((UINT64*)&SectionHeader.PointerToRelocations);
828 if (ValueInSectionHeader != 0) {
829 //
830 // Found first section header that doesn't point to code section in which uild tool saves the
831 // offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields
832 //
833 FixLoaddingAddress = (EFI_PHYSICAL_ADDRESS)(SmramBase + (INT64)ValueInSectionHeader);
834
835 if (SmramBase + SmmCodeSize > FixLoaddingAddress && SmramBase <= FixLoaddingAddress) {
836 //
837 // The assigned address is valid. Return the specified loadding address
838 //
839 ImageContext->ImageAddress = FixLoaddingAddress;
840 Status = EFI_SUCCESS;
841 }
842 }
843 break;
844 }
845 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
846 }
847 DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address %x, Status = %r \n", FixLoaddingAddress, Status));
848 return Status;
849 }
850 /**
851 Load the SMM Core image into SMRAM and executes the SMM Core from SMRAM.
852
853 @param[in] SmramRange Descriptor for the range of SMRAM to reload the
854 currently executing image.
855 @param[in] Context Context to pass into SMM Core
856
857 @return EFI_STATUS
858
859 **/
860 EFI_STATUS
861 ExecuteSmmCoreFromSmram (
862 IN EFI_SMRAM_DESCRIPTOR *SmramRange,
863 IN VOID *Context
864 )
865 {
866 EFI_STATUS Status;
867 VOID *SourceBuffer;
868 UINTN SourceSize;
869 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
870 UINTN PageCount;
871 EFI_PHYSICAL_ADDRESS DestinationBuffer;
872 EFI_IMAGE_ENTRY_POINT EntryPoint;
873
874 //
875 // Search all Firmware Volumes for a PE/COFF image in a file of type SMM_CORE
876 //
877 Status = GetSectionFromAnyFvByFileType (
878 EFI_FV_FILETYPE_SMM_CORE,
879 0,
880 EFI_SECTION_PE32,
881 0,
882 &SourceBuffer,
883 &SourceSize
884 );
885 if (EFI_ERROR (Status)) {
886 return Status;
887 }
888
889 //
890 // Initilize ImageContext
891 //
892 ImageContext.Handle = SourceBuffer;
893 ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
894
895 //
896 // Get information about the image being loaded
897 //
898 Status = PeCoffLoaderGetImageInfo (&ImageContext);
899 if (EFI_ERROR (Status)) {
900 return Status;
901 }
902 //
903 // if Loading module at Fixed Address feature is enabled, the SMM core driver will be loaded to
904 // the address assigned by build tool.
905 //
906 if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
907 //
908 // Get the fixed loading address assigned by Build tool
909 //
910 Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext);
911 if (!EFI_ERROR (Status)) {
912 //
913 // Since the memory range to load SMM CORE will be cut out in SMM core, so no need to allocate and free this range
914 //
915 PageCount = 0;
916 } else {
917 DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR: Loading module at fixed address at address failed\n"));
918 //
919 // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR
920 // specified by SmramRange
921 //
922 PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
923
924 ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
925 ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));
926
927 SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount);
928 DestinationBuffer = SmramRange->CpuStart + SmramRange->PhysicalSize;
929
930 //
931 // Align buffer on section boundry
932 //
933 ImageContext.ImageAddress = DestinationBuffer;
934 }
935 } else {
936 //
937 // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR
938 // specified by SmramRange
939 //
940 PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
941
942 ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
943 ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));
944
945 SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount);
946 DestinationBuffer = SmramRange->CpuStart + SmramRange->PhysicalSize;
947
948 //
949 // Align buffer on section boundry
950 //
951 ImageContext.ImageAddress = DestinationBuffer;
952 }
953
954 ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
955 ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext.SectionAlignment - 1));
956
957 //
958 // Print debug message showing SMM Core load address.
959 //
960 DEBUG ((DEBUG_INFO, "SMM IPL loading SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.ImageAddress));
961
962 //
963 // Load the image to our new buffer
964 //
965 Status = PeCoffLoaderLoadImage (&ImageContext);
966 if (!EFI_ERROR (Status)) {
967 //
968 // Relocate the image in our new buffer
969 //
970 Status = PeCoffLoaderRelocateImage (&ImageContext);
971 if (!EFI_ERROR (Status)) {
972 //
973 // Flush the instruction cache so the image data are written before we execute it
974 //
975 InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
976
977 //
978 // Print debug message showing SMM Core entry point address.
979 //
980 DEBUG ((DEBUG_INFO, "SMM IPL calling SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.EntryPoint));
981
982 //
983 // Execute image
984 //
985 EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)ImageContext.EntryPoint;
986 Status = EntryPoint ((EFI_HANDLE)Context, gST);
987 }
988 }
989
990 //
991 // If the load operation, relocate operation, or the image execution return an
992 // error, then free memory allocated from the EFI_SRAM_DESCRIPTOR specified by
993 // SmramRange
994 //
995 if (EFI_ERROR (Status)) {
996 SmramRange->PhysicalSize += EFI_PAGES_TO_SIZE (PageCount);
997 }
998
999 //
1000 // Always free memory allocted by GetFileBufferByFilePath ()
1001 //
1002 FreePool (SourceBuffer);
1003
1004 return Status;
1005 }
1006
1007 /**
1008 The Entry Point for SMM IPL
1009
1010 Load SMM Core into SMRAM, register SMM Core entry point for SMIs, install
1011 SMM Base 2 Protocol and SMM Communication Protocol, and register for the
1012 critical events required to coordinate between DXE and SMM environments.
1013
1014 @param ImageHandle The firmware allocated handle for the EFI image.
1015 @param SystemTable A pointer to the EFI System Table.
1016
1017 @retval EFI_SUCCESS The entry point is executed successfully.
1018 @retval Other Some error occurred when executing this entry point.
1019
1020 **/
1021 EFI_STATUS
1022 EFIAPI
1023 SmmIplEntry (
1024 IN EFI_HANDLE ImageHandle,
1025 IN EFI_SYSTEM_TABLE *SystemTable
1026 )
1027 {
1028 EFI_STATUS Status;
1029 EFI_SMM_CONFIGURATION_PROTOCOL *SmmConfiguration;
1030 UINTN Size;
1031 UINTN Index;
1032 EFI_SMM_RESERVED_SMRAM_REGION *SmramResRegion;
1033 UINT64 MaxSize;
1034 VOID *Registration;
1035 UINT64 SmmCodeSize;
1036 EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE *LMFAConfigurationTable;
1037 EFI_CPU_ARCH_PROTOCOL *CpuArch;
1038
1039 //
1040 // Fill in the image handle of the SMM IPL so the SMM Core can use this as the
1041 // ParentImageHandle field of the Load Image Protocol for all SMM Drivers loaded
1042 // by the SMM Core
1043 //
1044 mSmmCorePrivateData.SmmIplImageHandle = ImageHandle;
1045
1046 //
1047 // Get SMM Access Protocol
1048 //
1049 Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&mSmmAccess);
1050 ASSERT_EFI_ERROR (Status);
1051
1052 //
1053 // Get SMM Control2 Protocol
1054 //
1055 Status = gBS->LocateProtocol (&gEfiSmmControl2ProtocolGuid, NULL, (VOID **)&mSmmControl2);
1056 ASSERT_EFI_ERROR (Status);
1057
1058 //
1059 // Get SMM Configuration Protocol if it is present
1060 //
1061 SmmConfiguration = NULL;
1062 Status = gBS->LocateProtocol (&gEfiSmmConfigurationProtocolGuid, NULL, (VOID **) &SmmConfiguration);
1063
1064 //
1065 // Get SMRAM information
1066 //
1067 Size = 0;
1068 Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, NULL);
1069 ASSERT (Status == EFI_BUFFER_TOO_SMALL);
1070
1071 gSmmCorePrivate->SmramRanges = (EFI_SMRAM_DESCRIPTOR *)AllocatePool (Size);
1072 ASSERT (gSmmCorePrivate->SmramRanges != NULL);
1073
1074 Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, gSmmCorePrivate->SmramRanges);
1075 ASSERT_EFI_ERROR (Status);
1076
1077 gSmmCorePrivate->SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
1078
1079 //
1080 // Open all SMRAM ranges
1081 //
1082 Status = mSmmAccess->Open (mSmmAccess);
1083 ASSERT_EFI_ERROR (Status);
1084
1085 //
1086 // Print debug message that the SMRAM window is now open.
1087 //
1088 DEBUG ((DEBUG_INFO, "SMM IPL opened SMRAM window\n"));
1089
1090 //
1091 // Subtract SMRAM any reserved SMRAM regions.
1092 //
1093 if (SmmConfiguration != NULL) {
1094 SmramResRegion = SmmConfiguration->SmramReservedRegions;
1095 while (SmramResRegion->SmramReservedSize != 0) {
1096 for (Index = 0; Index < gSmmCorePrivate->SmramRangeCount; Index ++) {
1097 if ((SmramResRegion->SmramReservedStart >= gSmmCorePrivate->SmramRanges[Index].CpuStart) && \
1098 ((SmramResRegion->SmramReservedStart + SmramResRegion->SmramReservedSize) <= \
1099 (gSmmCorePrivate->SmramRanges[Index].CpuStart + gSmmCorePrivate->SmramRanges[Index].PhysicalSize))) {
1100 //
1101 // This range has reserved area, calculate the left free size
1102 //
1103 gSmmCorePrivate->SmramRanges[Index].PhysicalSize = SmramResRegion->SmramReservedStart - gSmmCorePrivate->SmramRanges[Index].CpuStart;
1104 }
1105 }
1106 SmramResRegion++;
1107 }
1108 }
1109
1110 //
1111 // Find the largest SMRAM range between 1MB and 4GB that is at least 256KB - 4K in size
1112 //
1113 mCurrentSmramRange = NULL;
1114 for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < gSmmCorePrivate->SmramRangeCount; Index++) {
1115 //
1116 // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization
1117 //
1118 if ((gSmmCorePrivate->SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
1119 continue;
1120 }
1121
1122 if (gSmmCorePrivate->SmramRanges[Index].CpuStart >= BASE_1MB) {
1123 if ((gSmmCorePrivate->SmramRanges[Index].CpuStart + gSmmCorePrivate->SmramRanges[Index].PhysicalSize) <= BASE_4GB) {
1124 if (gSmmCorePrivate->SmramRanges[Index].PhysicalSize >= MaxSize) {
1125 MaxSize = gSmmCorePrivate->SmramRanges[Index].PhysicalSize;
1126 mCurrentSmramRange = &gSmmCorePrivate->SmramRanges[Index];
1127 }
1128 }
1129 }
1130 }
1131
1132 if (mCurrentSmramRange != NULL) {
1133 //
1134 // Print debug message showing SMRAM window that will be used by SMM IPL and SMM Core
1135 //
1136 DEBUG ((DEBUG_INFO, "SMM IPL found SMRAM window %p - %p\n",
1137 (VOID *)(UINTN)mCurrentSmramRange->CpuStart,
1138 (VOID *)(UINTN)(mCurrentSmramRange->CpuStart + mCurrentSmramRange->PhysicalSize - 1)
1139 ));
1140
1141 GetSmramCacheRange (mCurrentSmramRange, &mSmramCacheBase, &mSmramCacheSize);
1142 //
1143 // If CPU AP is present, attempt to set SMRAM cacheability to WB
1144 // Note that it is expected that cacheability of SMRAM has been set to WB if CPU AP
1145 // is not available here.
1146 //
1147 CpuArch = NULL;
1148 Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&CpuArch);
1149 if (!EFI_ERROR (Status)) {
1150 Status = gDS->SetMemorySpaceAttributes(
1151 mSmramCacheBase,
1152 mSmramCacheSize,
1153 EFI_MEMORY_WB
1154 );
1155 if (EFI_ERROR (Status)) {
1156 DEBUG ((DEBUG_WARN, "SMM IPL failed to set SMRAM window to EFI_MEMORY_WB\n"));
1157 }
1158 }
1159 //
1160 // if Loading module at Fixed Address feature is enabled, save the SMRAM base to Load
1161 // Modules At Fixed Address Configuration Table.
1162 //
1163 if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
1164 //
1165 // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
1166 //
1167 SmmCodeSize = LShiftU64 (PcdGet32(PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT);
1168 //
1169 // The SMRAM available memory is assumed to be larger than SmmCodeSize
1170 //
1171 ASSERT (mCurrentSmramRange->PhysicalSize > SmmCodeSize);
1172 //
1173 // Retrieve Load modules At fixed address configuration table and save the SMRAM base.
1174 //
1175 Status = EfiGetSystemConfigurationTable (
1176 &gLoadFixedAddressConfigurationTableGuid,
1177 (VOID **) &LMFAConfigurationTable
1178 );
1179 if (!EFI_ERROR (Status) && LMFAConfigurationTable != NULL) {
1180 LMFAConfigurationTable->SmramBase = mCurrentSmramRange->CpuStart;
1181 //
1182 // Print the SMRAM base
1183 //
1184 DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: TSEG BASE is %x. \n", LMFAConfigurationTable->SmramBase));
1185 }
1186 }
1187 //
1188 // Load SMM Core into SMRAM and execute it from SMRAM
1189 //
1190 Status = ExecuteSmmCoreFromSmram (mCurrentSmramRange, gSmmCorePrivate);
1191 if (EFI_ERROR (Status)) {
1192 //
1193 // Print error message that the SMM Core failed to be loaded and executed.
1194 //
1195 DEBUG ((DEBUG_ERROR, "SMM IPL could not load and execute SMM Core from SMRAM\n"));
1196
1197 //
1198 // Attempt to reset SMRAM cacheability to UC
1199 //
1200 if (CpuArch != NULL) {
1201 Status = gDS->SetMemorySpaceAttributes(
1202 mSmramCacheBase,
1203 mSmramCacheSize,
1204 EFI_MEMORY_UC
1205 );
1206 if (EFI_ERROR (Status)) {
1207 DEBUG ((DEBUG_WARN, "SMM IPL failed to reset SMRAM window to EFI_MEMORY_UC\n"));
1208 }
1209 }
1210 }
1211 } else {
1212 //
1213 // Print error message that there are not enough SMRAM resources to load the SMM Core.
1214 //
1215 DEBUG ((DEBUG_ERROR, "SMM IPL could not find a large enough SMRAM region to load SMM Core\n"));
1216 }
1217
1218 //
1219 // If the SMM Core could not be loaded then close SMRAM window, free allocated
1220 // resources, and return an error so SMM IPL will be unloaded.
1221 //
1222 if (mCurrentSmramRange == NULL || EFI_ERROR (Status)) {
1223 //
1224 // Close all SMRAM ranges
1225 //
1226 Status = mSmmAccess->Close (mSmmAccess);
1227 ASSERT_EFI_ERROR (Status);
1228
1229 //
1230 // Print debug message that the SMRAM window is now closed.
1231 //
1232 DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));
1233
1234 //
1235 // Free all allocated resources
1236 //
1237 FreePool (gSmmCorePrivate->SmramRanges);
1238
1239 return EFI_UNSUPPORTED;
1240 }
1241
1242 //
1243 // Install SMM Base2 Protocol and SMM Communication Protocol
1244 //
1245 Status = gBS->InstallMultipleProtocolInterfaces (
1246 &mSmmIplHandle,
1247 &gEfiSmmBase2ProtocolGuid, &mSmmBase2,
1248 &gEfiSmmCommunicationProtocolGuid, &mSmmCommunication,
1249 NULL
1250 );
1251 ASSERT_EFI_ERROR (Status);
1252
1253 //
1254 // Create the set of protocol and event notififcations that the SMM IPL requires
1255 //
1256 for (Index = 0; mSmmIplEvents[Index].NotifyFunction != NULL; Index++) {
1257 if (mSmmIplEvents[Index].Protocol) {
1258 mSmmIplEvents[Index].Event = EfiCreateProtocolNotifyEvent (
1259 mSmmIplEvents[Index].Guid,
1260 mSmmIplEvents[Index].NotifyTpl,
1261 mSmmIplEvents[Index].NotifyFunction,
1262 mSmmIplEvents[Index].NotifyContext,
1263 &Registration
1264 );
1265 } else {
1266 Status = gBS->CreateEventEx (
1267 EVT_NOTIFY_SIGNAL,
1268 mSmmIplEvents[Index].NotifyTpl,
1269 mSmmIplEvents[Index].NotifyFunction,
1270 mSmmIplEvents[Index].NotifyContext,
1271 mSmmIplEvents[Index].Guid,
1272 &mSmmIplEvents[Index].Event
1273 );
1274 ASSERT_EFI_ERROR (Status);
1275 }
1276 }
1277
1278 return EFI_SUCCESS;
1279 }