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