]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/PiSmmCore/PiSmmIpl.c
MdeModulePkg PiSmmCore: Unregister end of dxe notification in SmmReadyToLock.
[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 - 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 //
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 protocol notification on DxeSmmReadyToLock protocols. When this notification is established,
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, TRUE, &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 // It is also to inform the SMM Core to notify SMM driver that system enter legacy boot.
287 //
288 { FALSE, FALSE, &gEfiEventLegacyBootGuid, SmmIplGuidedEventNotify, &gEfiEventLegacyBootGuid, TPL_CALLBACK, NULL },
289 //
290 // Declare event notification on Exit Boot Services Event Group. This is used to inform the SMM Core
291 // to notify SMM driver that system enter exit boot services.
292 //
293 { FALSE, FALSE, &gEfiEventExitBootServicesGuid, SmmIplGuidedEventNotify, &gEfiEventExitBootServicesGuid, TPL_CALLBACK, NULL },
294 //
295 // Declare event notification on Ready To Boot Event Group. This is used to inform the SMM Core
296 // to notify SMM driver that system enter ready to boot.
297 //
298 { FALSE, FALSE, &gEfiEventReadyToBootGuid, SmmIplGuidedEventNotify, &gEfiEventReadyToBootGuid, TPL_CALLBACK, NULL },
299 //
300 // Declare event notification on SetVirtualAddressMap() Event Group. This is used to convert gSmmCorePrivate
301 // and mSmmControl2 from physical addresses to virtual addresses.
302 //
303 { FALSE, FALSE, &gEfiEventVirtualAddressChangeGuid, SmmIplSetVirtualAddressNotify, NULL, TPL_CALLBACK, NULL },
304 //
305 // Terminate the table of event notifications
306 //
307 { FALSE, FALSE, NULL, NULL, NULL, TPL_CALLBACK, NULL }
308 };
309
310 /**
311 Find the maximum SMRAM cache range that covers the range specified by SmramRange.
312
313 This function searches and joins all adjacent ranges of SmramRange into a range to be cached.
314
315 @param SmramRange The SMRAM range to search from.
316 @param SmramCacheBase The returned cache range base.
317 @param SmramCacheSize The returned cache range size.
318
319 **/
320 VOID
321 GetSmramCacheRange (
322 IN EFI_SMRAM_DESCRIPTOR *SmramRange,
323 OUT EFI_PHYSICAL_ADDRESS *SmramCacheBase,
324 OUT UINT64 *SmramCacheSize
325 )
326 {
327 UINTN Index;
328 EFI_PHYSICAL_ADDRESS RangeCpuStart;
329 UINT64 RangePhysicalSize;
330 BOOLEAN FoundAjacentRange;
331
332 *SmramCacheBase = SmramRange->CpuStart;
333 *SmramCacheSize = SmramRange->PhysicalSize;
334
335 do {
336 FoundAjacentRange = FALSE;
337 for (Index = 0; Index < gSmmCorePrivate->SmramRangeCount; Index++) {
338 RangeCpuStart = gSmmCorePrivate->SmramRanges[Index].CpuStart;
339 RangePhysicalSize = gSmmCorePrivate->SmramRanges[Index].PhysicalSize;
340 if (RangeCpuStart < *SmramCacheBase && *SmramCacheBase == (RangeCpuStart + RangePhysicalSize)) {
341 *SmramCacheBase = RangeCpuStart;
342 *SmramCacheSize += RangePhysicalSize;
343 FoundAjacentRange = TRUE;
344 } else if ((*SmramCacheBase + *SmramCacheSize) == RangeCpuStart && RangePhysicalSize > 0) {
345 *SmramCacheSize += RangePhysicalSize;
346 FoundAjacentRange = TRUE;
347 }
348 }
349 } while (FoundAjacentRange);
350
351 }
352
353 /**
354 Indicate whether the driver is currently executing in the SMM Initialization phase.
355
356 @param This The EFI_SMM_BASE2_PROTOCOL instance.
357 @param InSmram Pointer to a Boolean which, on return, indicates that the driver is currently executing
358 inside of SMRAM (TRUE) or outside of SMRAM (FALSE).
359
360 @retval EFI_INVALID_PARAMETER InSmram was NULL.
361 @retval EFI_SUCCESS The call returned successfully.
362
363 **/
364 EFI_STATUS
365 EFIAPI
366 SmmBase2InSmram (
367 IN CONST EFI_SMM_BASE2_PROTOCOL *This,
368 OUT BOOLEAN *InSmram
369 )
370 {
371 if (InSmram == NULL) {
372 return EFI_INVALID_PARAMETER;
373 }
374
375 *InSmram = gSmmCorePrivate->InSmm;
376
377 return EFI_SUCCESS;
378 }
379
380 /**
381 Retrieves the location of the System Management System Table (SMST).
382
383 @param This The EFI_SMM_BASE2_PROTOCOL instance.
384 @param Smst On return, points to a pointer to the System Management Service Table (SMST).
385
386 @retval EFI_INVALID_PARAMETER Smst or This was invalid.
387 @retval EFI_SUCCESS The memory was returned to the system.
388 @retval EFI_UNSUPPORTED Not in SMM.
389
390 **/
391 EFI_STATUS
392 EFIAPI
393 SmmBase2GetSmstLocation (
394 IN CONST EFI_SMM_BASE2_PROTOCOL *This,
395 OUT EFI_SMM_SYSTEM_TABLE2 **Smst
396 )
397 {
398 if ((This == NULL) ||(Smst == NULL)) {
399 return EFI_INVALID_PARAMETER;
400 }
401
402 if (!gSmmCorePrivate->InSmm) {
403 return EFI_UNSUPPORTED;
404 }
405
406 *Smst = gSmmCorePrivate->Smst;
407
408 return EFI_SUCCESS;
409 }
410
411 /**
412 Communicates with a registered handler.
413
414 This function provides a service to send and receive messages from a registered
415 UEFI service. This function is part of the SMM Communication Protocol that may
416 be called in physical mode prior to SetVirtualAddressMap() and in virtual mode
417 after SetVirtualAddressMap().
418
419 @param[in] This The EFI_SMM_COMMUNICATION_PROTOCOL instance.
420 @param[in, out] CommBuffer A pointer to the buffer to convey into SMRAM.
421 @param[in, out] CommSize The size of the data buffer being passed in.On exit, the size of data
422 being returned. Zero if the handler does not wish to reply with any data.
423
424 @retval EFI_SUCCESS The message was successfully posted.
425 @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.
426 **/
427 EFI_STATUS
428 EFIAPI
429 SmmCommunicationCommunicate (
430 IN CONST EFI_SMM_COMMUNICATION_PROTOCOL *This,
431 IN OUT VOID *CommBuffer,
432 IN OUT UINTN *CommSize
433 )
434 {
435 EFI_STATUS Status;
436 EFI_SMM_COMMUNICATE_HEADER *CommunicateHeader;
437 BOOLEAN OldInSmm;
438
439 //
440 // Check parameters
441 //
442 if ((CommBuffer == NULL) || (CommSize == NULL)) {
443 return EFI_INVALID_PARAMETER;
444 }
445
446 //
447 // CommSize must hold HeaderGuid and MessageLength
448 //
449 if (*CommSize < OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)) {
450 return EFI_INVALID_PARAMETER;
451 }
452
453 //
454 // If not already in SMM, then generate a Software SMI
455 //
456 if (!gSmmCorePrivate->InSmm && gSmmCorePrivate->SmmEntryPointRegistered) {
457 //
458 // Put arguments for Software SMI in gSmmCorePrivate
459 //
460 gSmmCorePrivate->CommunicationBuffer = CommBuffer;
461 gSmmCorePrivate->BufferSize = *CommSize;
462
463 //
464 // Generate Software SMI
465 //
466 Status = mSmmControl2->Trigger (mSmmControl2, NULL, NULL, FALSE, 0);
467 if (EFI_ERROR (Status)) {
468 return EFI_UNSUPPORTED;
469 }
470
471 //
472 // Return status from software SMI
473 //
474 *CommSize = gSmmCorePrivate->BufferSize;
475 return gSmmCorePrivate->ReturnStatus;
476 }
477
478 //
479 // If we are in SMM, then the execution mode must be physical, which means that
480 // OS established virtual addresses can not be used. If SetVirtualAddressMap()
481 // has been called, then a direct invocation of the Software SMI is not
482 // not allowed so return EFI_INVALID_PARAMETER.
483 //
484 if (EfiGoneVirtual()) {
485 return EFI_INVALID_PARAMETER;
486 }
487
488 //
489 // If we are not in SMM, don't allow call SmiManage() directly when SMRAM is closed or locked.
490 //
491 if ((!gSmmCorePrivate->InSmm) && (!mSmmAccess->OpenState || mSmmAccess->LockState)) {
492 return EFI_INVALID_PARAMETER;
493 }
494
495 //
496 // Save current InSmm state and set InSmm state to TRUE
497 //
498 OldInSmm = gSmmCorePrivate->InSmm;
499 gSmmCorePrivate->InSmm = TRUE;
500
501 //
502 // Already in SMM and before SetVirtualAddressMap(), so call SmiManage() directly.
503 //
504 CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)CommBuffer;
505 *CommSize -= OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);
506 Status = gSmmCorePrivate->Smst->SmiManage (
507 &CommunicateHeader->HeaderGuid,
508 NULL,
509 CommunicateHeader->Data,
510 CommSize
511 );
512
513 //
514 // Update CommunicationBuffer, BufferSize and ReturnStatus
515 // Communicate service finished, reset the pointer to CommBuffer to NULL
516 //
517 *CommSize += OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);
518
519 //
520 // Restore original InSmm state
521 //
522 gSmmCorePrivate->InSmm = OldInSmm;
523
524 return (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_NOT_FOUND;
525 }
526
527 /**
528 Event notification that is fired when GUIDed Event Group is signaled.
529
530 @param Event The Event that is being processed, not used.
531 @param Context Event Context, not used.
532
533 **/
534 VOID
535 EFIAPI
536 SmmIplGuidedEventNotify (
537 IN EFI_EVENT Event,
538 IN VOID *Context
539 )
540 {
541 EFI_SMM_COMMUNICATE_HEADER CommunicateHeader;
542 UINTN Size;
543
544 //
545 // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure
546 //
547 CopyGuid (&CommunicateHeader.HeaderGuid, (EFI_GUID *)Context);
548 CommunicateHeader.MessageLength = 1;
549 CommunicateHeader.Data[0] = 0;
550
551 //
552 // Generate the Software SMI and return the result
553 //
554 Size = sizeof (CommunicateHeader);
555 SmmCommunicationCommunicate (&mSmmCommunication, &CommunicateHeader, &Size);
556 }
557
558 /**
559 Event notification that is fired when DxeDispatch Event Group is signaled.
560
561 @param Event The Event that is being processed, not used.
562 @param Context Event Context, not used.
563
564 **/
565 VOID
566 EFIAPI
567 SmmIplDxeDispatchEventNotify (
568 IN EFI_EVENT Event,
569 IN VOID *Context
570 )
571 {
572 EFI_SMM_COMMUNICATE_HEADER CommunicateHeader;
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 (&CommunicateHeader.HeaderGuid, (EFI_GUID *)Context);
586 CommunicateHeader.MessageLength = 1;
587 CommunicateHeader.Data[0] = 0;
588
589 //
590 // Generate the Software SMI and return the result
591 //
592 Size = sizeof (CommunicateHeader);
593 SmmCommunicationCommunicate (&mSmmCommunication, &CommunicateHeader, &Size);
594
595 //
596 // Return if there is no request to restart the SMM Core Dispatcher
597 //
598 if (CommunicateHeader.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
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
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
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
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] SmramRange Descriptor for the range of SMRAM to reload the
865 currently executing image.
866 @param[in] Context Context to pass into SMM Core
867
868 @return EFI_STATUS
869
870 **/
871 EFI_STATUS
872 ExecuteSmmCoreFromSmram (
873 IN EFI_SMRAM_DESCRIPTOR *SmramRange,
874 IN VOID *Context
875 )
876 {
877 EFI_STATUS Status;
878 VOID *SourceBuffer;
879 UINTN SourceSize;
880 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
881 UINTN PageCount;
882 EFI_PHYSICAL_ADDRESS DestinationBuffer;
883 EFI_IMAGE_ENTRY_POINT EntryPoint;
884
885 //
886 // Search all Firmware Volumes for a PE/COFF image in a file of type SMM_CORE
887 //
888 Status = GetSectionFromAnyFvByFileType (
889 EFI_FV_FILETYPE_SMM_CORE,
890 0,
891 EFI_SECTION_PE32,
892 0,
893 &SourceBuffer,
894 &SourceSize
895 );
896 if (EFI_ERROR (Status)) {
897 return Status;
898 }
899
900 //
901 // Initilize ImageContext
902 //
903 ImageContext.Handle = SourceBuffer;
904 ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
905
906 //
907 // Get information about the image being loaded
908 //
909 Status = PeCoffLoaderGetImageInfo (&ImageContext);
910 if (EFI_ERROR (Status)) {
911 return Status;
912 }
913 //
914 // if Loading module at Fixed Address feature is enabled, the SMM core driver will be loaded to
915 // the address assigned by build tool.
916 //
917 if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
918 //
919 // Get the fixed loading address assigned by Build tool
920 //
921 Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext);
922 if (!EFI_ERROR (Status)) {
923 //
924 // Since the memory range to load SMM CORE will be cut out in SMM core, so no need to allocate and free this range
925 //
926 PageCount = 0;
927 } else {
928 DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR: Loading module at fixed address at address failed\n"));
929 //
930 // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR
931 // specified by SmramRange
932 //
933 PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
934
935 ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
936 ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));
937
938 SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount);
939 DestinationBuffer = SmramRange->CpuStart + SmramRange->PhysicalSize;
940
941 //
942 // Align buffer on section boundry
943 //
944 ImageContext.ImageAddress = DestinationBuffer;
945 }
946 } else {
947 //
948 // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR
949 // specified by SmramRange
950 //
951 PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
952
953 ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);
954 ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));
955
956 SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount);
957 DestinationBuffer = SmramRange->CpuStart + SmramRange->PhysicalSize;
958
959 //
960 // Align buffer on section boundry
961 //
962 ImageContext.ImageAddress = DestinationBuffer;
963 }
964
965 ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
966 ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext.SectionAlignment - 1));
967
968 //
969 // Print debug message showing SMM Core load address.
970 //
971 DEBUG ((DEBUG_INFO, "SMM IPL loading SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.ImageAddress));
972
973 //
974 // Load the image to our new buffer
975 //
976 Status = PeCoffLoaderLoadImage (&ImageContext);
977 if (!EFI_ERROR (Status)) {
978 //
979 // Relocate the image in our new buffer
980 //
981 Status = PeCoffLoaderRelocateImage (&ImageContext);
982 if (!EFI_ERROR (Status)) {
983 //
984 // Flush the instruction cache so the image data are written before we execute it
985 //
986 InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
987
988 //
989 // Print debug message showing SMM Core entry point address.
990 //
991 DEBUG ((DEBUG_INFO, "SMM IPL calling SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.EntryPoint));
992
993 gSmmCorePrivate->PiSmmCoreImageBase = ImageContext.ImageAddress;
994 gSmmCorePrivate->PiSmmCoreImageSize = ImageContext.ImageSize;
995 DEBUG ((DEBUG_INFO, "PiSmmCoreImageBase - 0x%016lx\n", gSmmCorePrivate->PiSmmCoreImageBase));
996 DEBUG ((DEBUG_INFO, "PiSmmCoreImageSize - 0x%016lx\n", gSmmCorePrivate->PiSmmCoreImageSize));
997
998 gSmmCorePrivate->PiSmmCoreEntryPoint = ImageContext.EntryPoint;
999
1000 //
1001 // Execute image
1002 //
1003 EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)ImageContext.EntryPoint;
1004 Status = EntryPoint ((EFI_HANDLE)Context, gST);
1005 }
1006 }
1007
1008 //
1009 // If the load operation, relocate operation, or the image execution return an
1010 // error, then free memory allocated from the EFI_SRAM_DESCRIPTOR specified by
1011 // SmramRange
1012 //
1013 if (EFI_ERROR (Status)) {
1014 SmramRange->PhysicalSize += EFI_PAGES_TO_SIZE (PageCount);
1015 }
1016
1017 //
1018 // Always free memory allocted by GetFileBufferByFilePath ()
1019 //
1020 FreePool (SourceBuffer);
1021
1022 return Status;
1023 }
1024
1025 /**
1026 The Entry Point for SMM IPL
1027
1028 Load SMM Core into SMRAM, register SMM Core entry point for SMIs, install
1029 SMM Base 2 Protocol and SMM Communication Protocol, and register for the
1030 critical events required to coordinate between DXE and SMM environments.
1031
1032 @param ImageHandle The firmware allocated handle for the EFI image.
1033 @param SystemTable A pointer to the EFI System Table.
1034
1035 @retval EFI_SUCCESS The entry point is executed successfully.
1036 @retval Other Some error occurred when executing this entry point.
1037
1038 **/
1039 EFI_STATUS
1040 EFIAPI
1041 SmmIplEntry (
1042 IN EFI_HANDLE ImageHandle,
1043 IN EFI_SYSTEM_TABLE *SystemTable
1044 )
1045 {
1046 EFI_STATUS Status;
1047 EFI_SMM_CONFIGURATION_PROTOCOL *SmmConfiguration;
1048 UINTN Size;
1049 UINTN Index;
1050 EFI_SMM_RESERVED_SMRAM_REGION *SmramResRegion;
1051 UINT64 MaxSize;
1052 VOID *Registration;
1053 UINT64 SmmCodeSize;
1054 EFI_LOAD_FIXED_ADDRESS_CONFIGURATION_TABLE *LMFAConfigurationTable;
1055 EFI_CPU_ARCH_PROTOCOL *CpuArch;
1056 EFI_STATUS SetAttrStatus;
1057
1058 //
1059 // Fill in the image handle of the SMM IPL so the SMM Core can use this as the
1060 // ParentImageHandle field of the Load Image Protocol for all SMM Drivers loaded
1061 // by the SMM Core
1062 //
1063 mSmmCorePrivateData.SmmIplImageHandle = ImageHandle;
1064
1065 //
1066 // Get SMM Access Protocol
1067 //
1068 Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&mSmmAccess);
1069 ASSERT_EFI_ERROR (Status);
1070
1071 //
1072 // Get SMM Control2 Protocol
1073 //
1074 Status = gBS->LocateProtocol (&gEfiSmmControl2ProtocolGuid, NULL, (VOID **)&mSmmControl2);
1075 ASSERT_EFI_ERROR (Status);
1076
1077 //
1078 // Get SMM Configuration Protocol if it is present
1079 //
1080 SmmConfiguration = NULL;
1081 Status = gBS->LocateProtocol (&gEfiSmmConfigurationProtocolGuid, NULL, (VOID **) &SmmConfiguration);
1082
1083 //
1084 // Get SMRAM information
1085 //
1086 Size = 0;
1087 Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, NULL);
1088 ASSERT (Status == EFI_BUFFER_TOO_SMALL);
1089
1090 gSmmCorePrivate->SmramRanges = (EFI_SMRAM_DESCRIPTOR *)AllocatePool (Size);
1091 ASSERT (gSmmCorePrivate->SmramRanges != NULL);
1092
1093 Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, gSmmCorePrivate->SmramRanges);
1094 ASSERT_EFI_ERROR (Status);
1095
1096 gSmmCorePrivate->SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
1097
1098 //
1099 // Save a full copy
1100 //
1101 gSmmCorePrivate->FullSmramRangeCount = gSmmCorePrivate->SmramRangeCount;
1102 gSmmCorePrivate->FullSmramRanges = (EFI_SMRAM_DESCRIPTOR *) AllocatePool (Size);
1103 ASSERT (gSmmCorePrivate->FullSmramRanges != NULL);
1104 CopyMem (gSmmCorePrivate->FullSmramRanges, gSmmCorePrivate->SmramRanges, Size);
1105
1106 //
1107 // Open all SMRAM ranges
1108 //
1109 Status = mSmmAccess->Open (mSmmAccess);
1110 ASSERT_EFI_ERROR (Status);
1111
1112 //
1113 // Print debug message that the SMRAM window is now open.
1114 //
1115 DEBUG ((DEBUG_INFO, "SMM IPL opened SMRAM window\n"));
1116
1117 //
1118 // Subtract SMRAM any reserved SMRAM regions.
1119 //
1120 if (SmmConfiguration != NULL) {
1121 SmramResRegion = SmmConfiguration->SmramReservedRegions;
1122 while (SmramResRegion->SmramReservedSize != 0) {
1123 for (Index = 0; Index < gSmmCorePrivate->SmramRangeCount; Index ++) {
1124 if ((SmramResRegion->SmramReservedStart >= gSmmCorePrivate->SmramRanges[Index].CpuStart) && \
1125 ((SmramResRegion->SmramReservedStart + SmramResRegion->SmramReservedSize) <= \
1126 (gSmmCorePrivate->SmramRanges[Index].CpuStart + gSmmCorePrivate->SmramRanges[Index].PhysicalSize))) {
1127 //
1128 // This range has reserved area, calculate the left free size
1129 //
1130 gSmmCorePrivate->SmramRanges[Index].PhysicalSize = SmramResRegion->SmramReservedStart - gSmmCorePrivate->SmramRanges[Index].CpuStart;
1131 }
1132 }
1133 SmramResRegion++;
1134 }
1135 }
1136
1137 //
1138 // Find the largest SMRAM range between 1MB and 4GB that is at least 256KB - 4K in size
1139 //
1140 mCurrentSmramRange = NULL;
1141 for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < gSmmCorePrivate->SmramRangeCount; Index++) {
1142 //
1143 // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization
1144 //
1145 if ((gSmmCorePrivate->SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
1146 continue;
1147 }
1148
1149 if (gSmmCorePrivate->SmramRanges[Index].CpuStart >= BASE_1MB) {
1150 if ((gSmmCorePrivate->SmramRanges[Index].CpuStart + gSmmCorePrivate->SmramRanges[Index].PhysicalSize) <= BASE_4GB) {
1151 if (gSmmCorePrivate->SmramRanges[Index].PhysicalSize >= MaxSize) {
1152 MaxSize = gSmmCorePrivate->SmramRanges[Index].PhysicalSize;
1153 mCurrentSmramRange = &gSmmCorePrivate->SmramRanges[Index];
1154 }
1155 }
1156 }
1157 }
1158
1159 if (mCurrentSmramRange != NULL) {
1160 //
1161 // Print debug message showing SMRAM window that will be used by SMM IPL and SMM Core
1162 //
1163 DEBUG ((DEBUG_INFO, "SMM IPL found SMRAM window %p - %p\n",
1164 (VOID *)(UINTN)mCurrentSmramRange->CpuStart,
1165 (VOID *)(UINTN)(mCurrentSmramRange->CpuStart + mCurrentSmramRange->PhysicalSize - 1)
1166 ));
1167
1168 GetSmramCacheRange (mCurrentSmramRange, &mSmramCacheBase, &mSmramCacheSize);
1169 //
1170 // If CPU AP is present, attempt to set SMRAM cacheability to WB
1171 // Note that it is expected that cacheability of SMRAM has been set to WB if CPU AP
1172 // is not available here.
1173 //
1174 CpuArch = NULL;
1175 Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&CpuArch);
1176 if (!EFI_ERROR (Status)) {
1177 Status = gDS->SetMemorySpaceAttributes(
1178 mSmramCacheBase,
1179 mSmramCacheSize,
1180 EFI_MEMORY_WB
1181 );
1182 if (EFI_ERROR (Status)) {
1183 DEBUG ((DEBUG_WARN, "SMM IPL failed to set SMRAM window to EFI_MEMORY_WB\n"));
1184 }
1185 }
1186 //
1187 // if Loading module at Fixed Address feature is enabled, save the SMRAM base to Load
1188 // Modules At Fixed Address Configuration Table.
1189 //
1190 if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
1191 //
1192 // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
1193 //
1194 SmmCodeSize = LShiftU64 (PcdGet32(PcdLoadFixAddressSmmCodePageNumber), EFI_PAGE_SHIFT);
1195 //
1196 // The SMRAM available memory is assumed to be larger than SmmCodeSize
1197 //
1198 ASSERT (mCurrentSmramRange->PhysicalSize > SmmCodeSize);
1199 //
1200 // Retrieve Load modules At fixed address configuration table and save the SMRAM base.
1201 //
1202 Status = EfiGetSystemConfigurationTable (
1203 &gLoadFixedAddressConfigurationTableGuid,
1204 (VOID **) &LMFAConfigurationTable
1205 );
1206 if (!EFI_ERROR (Status) && LMFAConfigurationTable != NULL) {
1207 LMFAConfigurationTable->SmramBase = mCurrentSmramRange->CpuStart;
1208 //
1209 // Print the SMRAM base
1210 //
1211 DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED INFO: TSEG BASE is %x. \n", LMFAConfigurationTable->SmramBase));
1212 }
1213 }
1214 //
1215 // Load SMM Core into SMRAM and execute it from SMRAM
1216 //
1217 Status = ExecuteSmmCoreFromSmram (mCurrentSmramRange, gSmmCorePrivate);
1218 if (EFI_ERROR (Status)) {
1219 //
1220 // Print error message that the SMM Core failed to be loaded and executed.
1221 //
1222 DEBUG ((DEBUG_ERROR, "SMM IPL could not load and execute SMM Core from SMRAM\n"));
1223
1224 //
1225 // Attempt to reset SMRAM cacheability to UC
1226 //
1227 if (CpuArch != NULL) {
1228 SetAttrStatus = gDS->SetMemorySpaceAttributes(
1229 mSmramCacheBase,
1230 mSmramCacheSize,
1231 EFI_MEMORY_UC
1232 );
1233 if (EFI_ERROR (SetAttrStatus)) {
1234 DEBUG ((DEBUG_WARN, "SMM IPL failed to reset SMRAM window to EFI_MEMORY_UC\n"));
1235 }
1236 }
1237 }
1238 } else {
1239 //
1240 // Print error message that there are not enough SMRAM resources to load the SMM Core.
1241 //
1242 DEBUG ((DEBUG_ERROR, "SMM IPL could not find a large enough SMRAM region to load SMM Core\n"));
1243 }
1244
1245 //
1246 // If the SMM Core could not be loaded then close SMRAM window, free allocated
1247 // resources, and return an error so SMM IPL will be unloaded.
1248 //
1249 if (mCurrentSmramRange == NULL || EFI_ERROR (Status)) {
1250 //
1251 // Close all SMRAM ranges
1252 //
1253 Status = mSmmAccess->Close (mSmmAccess);
1254 ASSERT_EFI_ERROR (Status);
1255
1256 //
1257 // Print debug message that the SMRAM window is now closed.
1258 //
1259 DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));
1260
1261 //
1262 // Free all allocated resources
1263 //
1264 FreePool (gSmmCorePrivate->SmramRanges);
1265 FreePool (gSmmCorePrivate->FullSmramRanges);
1266
1267 return EFI_UNSUPPORTED;
1268 }
1269
1270 //
1271 // Install SMM Base2 Protocol and SMM Communication Protocol
1272 //
1273 Status = gBS->InstallMultipleProtocolInterfaces (
1274 &mSmmIplHandle,
1275 &gEfiSmmBase2ProtocolGuid, &mSmmBase2,
1276 &gEfiSmmCommunicationProtocolGuid, &mSmmCommunication,
1277 NULL
1278 );
1279 ASSERT_EFI_ERROR (Status);
1280
1281 //
1282 // Create the set of protocol and event notififcations that the SMM IPL requires
1283 //
1284 for (Index = 0; mSmmIplEvents[Index].NotifyFunction != NULL; Index++) {
1285 if (mSmmIplEvents[Index].Protocol) {
1286 mSmmIplEvents[Index].Event = EfiCreateProtocolNotifyEvent (
1287 mSmmIplEvents[Index].Guid,
1288 mSmmIplEvents[Index].NotifyTpl,
1289 mSmmIplEvents[Index].NotifyFunction,
1290 mSmmIplEvents[Index].NotifyContext,
1291 &Registration
1292 );
1293 } else {
1294 Status = gBS->CreateEventEx (
1295 EVT_NOTIFY_SIGNAL,
1296 mSmmIplEvents[Index].NotifyTpl,
1297 mSmmIplEvents[Index].NotifyFunction,
1298 mSmmIplEvents[Index].NotifyContext,
1299 mSmmIplEvents[Index].Guid,
1300 &mSmmIplEvents[Index].Event
1301 );
1302 ASSERT_EFI_ERROR (Status);
1303 }
1304 }
1305
1306 return EFI_SUCCESS;
1307 }