1 /** @file
2 Agent Module to load other modules to deploy SMM Entry Vector for X86 CPU.
3 
4 Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
6 
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8 
9 **/
10 
11 #include "PiSmmCpuDxeSmm.h"
12 
13 //
14 // SMM CPU Private Data structure that contains SMM Configuration Protocol
15 // along its supporting fields.
16 //
17 SMM_CPU_PRIVATE_DATA  mSmmCpuPrivateData = {
18   SMM_CPU_PRIVATE_DATA_SIGNATURE,               // Signature
19   NULL,                                         // SmmCpuHandle
20   NULL,                                         // Pointer to ProcessorInfo array
21   NULL,                                         // Pointer to Operation array
22   NULL,                                         // Pointer to CpuSaveStateSize array
23   NULL,                                         // Pointer to CpuSaveState array
24   { {0} },                                      // SmmReservedSmramRegion
25   {
26     SmmStartupThisAp,                           // SmmCoreEntryContext.SmmStartupThisAp
27     0,                                          // SmmCoreEntryContext.CurrentlyExecutingCpu
28     0,                                          // SmmCoreEntryContext.NumberOfCpus
29     NULL,                                       // SmmCoreEntryContext.CpuSaveStateSize
30     NULL                                        // SmmCoreEntryContext.CpuSaveState
31   },
32   NULL,                                         // SmmCoreEntry
33   {
34     mSmmCpuPrivateData.SmmReservedSmramRegion,  // SmmConfiguration.SmramReservedRegions
35     RegisterSmmEntry                            // SmmConfiguration.RegisterSmmEntry
36   },
37 };
38 
39 CPU_HOT_PLUG_DATA mCpuHotPlugData = {
40   CPU_HOT_PLUG_DATA_REVISION_1,                 // Revision
41   0,                                            // Array Length of SmBase and APIC ID
42   NULL,                                         // Pointer to APIC ID array
43   NULL,                                         // Pointer to SMBASE array
44   0,                                            // Reserved
45   0,                                            // SmrrBase
46   0                                             // SmrrSize
47 };
48 
49 //
50 // Global pointer used to access mSmmCpuPrivateData from outside and inside SMM
51 //
52 SMM_CPU_PRIVATE_DATA  *gSmmCpuPrivate = &mSmmCpuPrivateData;
53 
54 //
55 // SMM Relocation variables
56 //
57 volatile BOOLEAN  *mRebased;
58 volatile BOOLEAN  mIsBsp;
59 
60 ///
61 /// Handle for the SMM CPU Protocol
62 ///
63 EFI_HANDLE  mSmmCpuHandle = NULL;
64 
65 ///
66 /// SMM CPU Protocol instance
67 ///
68 EFI_SMM_CPU_PROTOCOL  mSmmCpu  = {
69   SmmReadSaveState,
70   SmmWriteSaveState
71 };
72 
73 ///
74 /// SMM Memory Attribute Protocol instance
75 ///
76 EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL  mSmmMemoryAttribute  = {
77   EdkiiSmmGetMemoryAttributes,
78   EdkiiSmmSetMemoryAttributes,
79   EdkiiSmmClearMemoryAttributes
80 };
81 
82 EFI_CPU_INTERRUPT_HANDLER   mExternalVectorTable[EXCEPTION_VECTOR_NUMBER];
83 
84 //
85 // SMM stack information
86 //
87 UINTN mSmmStackArrayBase;
88 UINTN mSmmStackArrayEnd;
89 UINTN mSmmStackSize;
90 
91 UINTN mSmmShadowStackSize;
92 BOOLEAN mCetSupported = TRUE;
93 
94 UINTN mMaxNumberOfCpus = 1;
95 UINTN mNumberOfCpus = 1;
96 
97 //
98 // SMM ready to lock flag
99 //
100 BOOLEAN mSmmReadyToLock = FALSE;
101 
102 //
103 // Global used to cache PCD for SMM Code Access Check enable
104 //
105 BOOLEAN                  mSmmCodeAccessCheckEnable = FALSE;
106 
107 //
108 // Global copy of the PcdPteMemoryEncryptionAddressOrMask
109 //
110 UINT64                   mAddressEncMask = 0;
111 
112 //
113 // Spin lock used to serialize setting of SMM Code Access Check feature
114 //
115 SPIN_LOCK                *mConfigSmmCodeAccessCheckLock = NULL;
116 
117 //
118 // Saved SMM ranges information
119 //
120 EFI_SMRAM_DESCRIPTOR     *mSmmCpuSmramRanges;
121 UINTN                    mSmmCpuSmramRangeCount;
122 
123 UINT8                    mPhysicalAddressBits;
124 
125 //
126 // Control register contents saved for SMM S3 resume state initialization.
127 //
128 UINT32                   mSmmCr0;
129 UINT32                   mSmmCr4;
130 
131 /**
132   Initialize IDT to setup exception handlers for SMM.
133 
134 **/
135 VOID
InitializeSmmIdt(VOID)136 InitializeSmmIdt (
137   VOID
138   )
139 {
140   EFI_STATUS               Status;
141   BOOLEAN                  InterruptState;
142   IA32_DESCRIPTOR          DxeIdtr;
143 
144   //
145   // There are 32 (not 255) entries in it since only processor
146   // generated exceptions will be handled.
147   //
148   gcSmiIdtr.Limit = (sizeof(IA32_IDT_GATE_DESCRIPTOR) * 32) - 1;
149   //
150   // Allocate page aligned IDT, because it might be set as read only.
151   //
152   gcSmiIdtr.Base = (UINTN)AllocateCodePages (EFI_SIZE_TO_PAGES(gcSmiIdtr.Limit + 1));
153   ASSERT (gcSmiIdtr.Base != 0);
154   ZeroMem ((VOID *)gcSmiIdtr.Base, gcSmiIdtr.Limit + 1);
155 
156   //
157   // Disable Interrupt and save DXE IDT table
158   //
159   InterruptState = SaveAndDisableInterrupts ();
160   AsmReadIdtr (&DxeIdtr);
161   //
162   // Load SMM temporary IDT table
163   //
164   AsmWriteIdtr (&gcSmiIdtr);
165   //
166   // Setup SMM default exception handlers, SMM IDT table
167   // will be updated and saved in gcSmiIdtr
168   //
169   Status = InitializeCpuExceptionHandlers (NULL);
170   ASSERT_EFI_ERROR (Status);
171   //
172   // Restore DXE IDT table and CPU interrupt
173   //
174   AsmWriteIdtr ((IA32_DESCRIPTOR *) &DxeIdtr);
175   SetInterruptState (InterruptState);
176 }
177 
178 /**
179   Search module name by input IP address and output it.
180 
181   @param CallerIpAddress   Caller instruction pointer.
182 
183 **/
184 VOID
DumpModuleInfoByIp(IN UINTN CallerIpAddress)185 DumpModuleInfoByIp (
186   IN  UINTN              CallerIpAddress
187   )
188 {
189   UINTN                                Pe32Data;
190   VOID                                 *PdbPointer;
191 
192   //
193   // Find Image Base
194   //
195   Pe32Data = PeCoffSearchImageBase (CallerIpAddress);
196   if (Pe32Data != 0) {
197     DEBUG ((DEBUG_ERROR, "It is invoked from the instruction before IP(0x%p)", (VOID *) CallerIpAddress));
198     PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *) Pe32Data);
199     if (PdbPointer != NULL) {
200       DEBUG ((DEBUG_ERROR, " in module (%a)\n", PdbPointer));
201     }
202   }
203 }
204 
205 /**
206   Read information from the CPU save state.
207 
208   @param  This      EFI_SMM_CPU_PROTOCOL instance
209   @param  Width     The number of bytes to read from the CPU save state.
210   @param  Register  Specifies the CPU register to read form the save state.
211   @param  CpuIndex  Specifies the zero-based index of the CPU save state.
212   @param  Buffer    Upon return, this holds the CPU register value read from the save state.
213 
214   @retval EFI_SUCCESS   The register was read from Save State
215   @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor
216   @retval EFI_INVALID_PARAMTER   This or Buffer is NULL.
217 
218 **/
219 EFI_STATUS
220 EFIAPI
SmmReadSaveState(IN CONST EFI_SMM_CPU_PROTOCOL * This,IN UINTN Width,IN EFI_SMM_SAVE_STATE_REGISTER Register,IN UINTN CpuIndex,OUT VOID * Buffer)221 SmmReadSaveState (
222   IN CONST EFI_SMM_CPU_PROTOCOL         *This,
223   IN UINTN                              Width,
224   IN EFI_SMM_SAVE_STATE_REGISTER        Register,
225   IN UINTN                              CpuIndex,
226   OUT VOID                              *Buffer
227   )
228 {
229   EFI_STATUS  Status;
230 
231   //
232   // Retrieve pointer to the specified CPU's SMM Save State buffer
233   //
234   if ((CpuIndex >= gSmst->NumberOfCpus) || (Buffer == NULL)) {
235     return EFI_INVALID_PARAMETER;
236   }
237   //
238   // The SpeculationBarrier() call here is to ensure the above check for the
239   // CpuIndex has been completed before the execution of subsequent codes.
240   //
241   SpeculationBarrier ();
242 
243   //
244   // Check for special EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID
245   //
246   if (Register == EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID) {
247     //
248     // The pseudo-register only supports the 64-bit size specified by Width.
249     //
250     if (Width != sizeof (UINT64)) {
251       return EFI_INVALID_PARAMETER;
252     }
253     //
254     // If the processor is in SMM at the time the SMI occurred,
255     // the pseudo register value for EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID is returned in Buffer.
256     // Otherwise, EFI_NOT_FOUND is returned.
257     //
258     if (*(mSmmMpSyncData->CpuData[CpuIndex].Present)) {
259       *(UINT64 *)Buffer = gSmmCpuPrivate->ProcessorInfo[CpuIndex].ProcessorId;
260       return EFI_SUCCESS;
261     } else {
262       return EFI_NOT_FOUND;
263     }
264   }
265 
266   if (!(*(mSmmMpSyncData->CpuData[CpuIndex].Present))) {
267     return EFI_INVALID_PARAMETER;
268   }
269 
270   Status = SmmCpuFeaturesReadSaveStateRegister (CpuIndex, Register, Width, Buffer);
271   if (Status == EFI_UNSUPPORTED) {
272     Status = ReadSaveStateRegister (CpuIndex, Register, Width, Buffer);
273   }
274   return Status;
275 }
276 
277 /**
278   Write data to the CPU save state.
279 
280   @param  This      EFI_SMM_CPU_PROTOCOL instance
281   @param  Width     The number of bytes to read from the CPU save state.
282   @param  Register  Specifies the CPU register to write to the save state.
283   @param  CpuIndex  Specifies the zero-based index of the CPU save state
284   @param  Buffer    Upon entry, this holds the new CPU register value.
285 
286   @retval EFI_SUCCESS   The register was written from Save State
287   @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor
288   @retval EFI_INVALID_PARAMTER   ProcessorIndex or Width is not correct
289 
290 **/
291 EFI_STATUS
292 EFIAPI
SmmWriteSaveState(IN CONST EFI_SMM_CPU_PROTOCOL * This,IN UINTN Width,IN EFI_SMM_SAVE_STATE_REGISTER Register,IN UINTN CpuIndex,IN CONST VOID * Buffer)293 SmmWriteSaveState (
294   IN CONST EFI_SMM_CPU_PROTOCOL         *This,
295   IN UINTN                              Width,
296   IN EFI_SMM_SAVE_STATE_REGISTER        Register,
297   IN UINTN                              CpuIndex,
298   IN CONST VOID                         *Buffer
299   )
300 {
301   EFI_STATUS  Status;
302 
303   //
304   // Retrieve pointer to the specified CPU's SMM Save State buffer
305   //
306   if ((CpuIndex >= gSmst->NumberOfCpus) || (Buffer == NULL)) {
307     return EFI_INVALID_PARAMETER;
308   }
309 
310   //
311   // Writes to EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID are ignored
312   //
313   if (Register == EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID) {
314     return EFI_SUCCESS;
315   }
316 
317   if (!mSmmMpSyncData->CpuData[CpuIndex].Present) {
318     return EFI_INVALID_PARAMETER;
319   }
320 
321   Status = SmmCpuFeaturesWriteSaveStateRegister (CpuIndex, Register, Width, Buffer);
322   if (Status == EFI_UNSUPPORTED) {
323     Status = WriteSaveStateRegister (CpuIndex, Register, Width, Buffer);
324   }
325   return Status;
326 }
327 
328 
329 /**
330   C function for SMI handler. To change all processor's SMMBase Register.
331 
332 **/
333 VOID
334 EFIAPI
SmmInitHandler(VOID)335 SmmInitHandler (
336   VOID
337   )
338 {
339   UINT32                            ApicId;
340   UINTN                             Index;
341 
342   //
343   // Update SMM IDT entries' code segment and load IDT
344   //
345   AsmWriteIdtr (&gcSmiIdtr);
346   ApicId = GetApicId ();
347 
348   ASSERT (mNumberOfCpus <= mMaxNumberOfCpus);
349 
350   for (Index = 0; Index < mNumberOfCpus; Index++) {
351     if (ApicId == (UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId) {
352       //
353       // Initialize SMM specific features on the currently executing CPU
354       //
355       SmmCpuFeaturesInitializeProcessor (
356         Index,
357         mIsBsp,
358         gSmmCpuPrivate->ProcessorInfo,
359         &mCpuHotPlugData
360         );
361 
362       if (!mSmmS3Flag) {
363         //
364         // Check XD and BTS features on each processor on normal boot
365         //
366         CheckFeatureSupported ();
367       }
368 
369       if (mIsBsp) {
370         //
371         // BSP rebase is already done above.
372         // Initialize private data during S3 resume
373         //
374         InitializeMpSyncData ();
375       }
376 
377       //
378       // Hook return after RSM to set SMM re-based flag
379       //
380       SemaphoreHook (Index, &mRebased[Index]);
381 
382       return;
383     }
384   }
385   ASSERT (FALSE);
386 }
387 
388 /**
389   Relocate SmmBases for each processor.
390 
391   Execute on first boot and all S3 resumes
392 
393 **/
394 VOID
395 EFIAPI
SmmRelocateBases(VOID)396 SmmRelocateBases (
397   VOID
398   )
399 {
400   UINT8                 BakBuf[BACK_BUF_SIZE];
401   SMRAM_SAVE_STATE_MAP  BakBuf2;
402   SMRAM_SAVE_STATE_MAP  *CpuStatePtr;
403   UINT8                 *U8Ptr;
404   UINT32                ApicId;
405   UINTN                 Index;
406   UINTN                 BspIndex;
407 
408   //
409   // Make sure the reserved size is large enough for procedure SmmInitTemplate.
410   //
411   ASSERT (sizeof (BakBuf) >= gcSmmInitSize);
412 
413   //
414   // Patch ASM code template with current CR0, CR3, and CR4 values
415   //
416   mSmmCr0 = (UINT32)AsmReadCr0 ();
417   PatchInstructionX86 (gPatchSmmCr0, mSmmCr0, 4);
418   PatchInstructionX86 (gPatchSmmCr3, AsmReadCr3 (), 4);
419   mSmmCr4 = (UINT32)AsmReadCr4 ();
420   PatchInstructionX86 (gPatchSmmCr4, mSmmCr4 & (~CR4_CET_ENABLE), 4);
421 
422   //
423   // Patch GDTR for SMM base relocation
424   //
425   gcSmiInitGdtr.Base  = gcSmiGdtr.Base;
426   gcSmiInitGdtr.Limit = gcSmiGdtr.Limit;
427 
428   U8Ptr = (UINT8*)(UINTN)(SMM_DEFAULT_SMBASE + SMM_HANDLER_OFFSET);
429   CpuStatePtr = (SMRAM_SAVE_STATE_MAP *)(UINTN)(SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET);
430 
431   //
432   // Backup original contents at address 0x38000
433   //
434   CopyMem (BakBuf, U8Ptr, sizeof (BakBuf));
435   CopyMem (&BakBuf2, CpuStatePtr, sizeof (BakBuf2));
436 
437   //
438   // Load image for relocation
439   //
440   CopyMem (U8Ptr, gcSmmInitTemplate, gcSmmInitSize);
441 
442   //
443   // Retrieve the local APIC ID of current processor
444   //
445   ApicId = GetApicId ();
446 
447   //
448   // Relocate SM bases for all APs
449   // This is APs' 1st SMI - rebase will be done here, and APs' default SMI handler will be overridden by gcSmmInitTemplate
450   //
451   mIsBsp   = FALSE;
452   BspIndex = (UINTN)-1;
453   for (Index = 0; Index < mNumberOfCpus; Index++) {
454     mRebased[Index] = FALSE;
455     if (ApicId != (UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId) {
456       SendSmiIpi ((UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId);
457       //
458       // Wait for this AP to finish its 1st SMI
459       //
460       while (!mRebased[Index]);
461     } else {
462       //
463       // BSP will be Relocated later
464       //
465       BspIndex = Index;
466     }
467   }
468 
469   //
470   // Relocate BSP's SMM base
471   //
472   ASSERT (BspIndex != (UINTN)-1);
473   mIsBsp = TRUE;
474   SendSmiIpi (ApicId);
475   //
476   // Wait for the BSP to finish its 1st SMI
477   //
478   while (!mRebased[BspIndex]);
479 
480   //
481   // Restore contents at address 0x38000
482   //
483   CopyMem (CpuStatePtr, &BakBuf2, sizeof (BakBuf2));
484   CopyMem (U8Ptr, BakBuf, sizeof (BakBuf));
485 }
486 
487 /**
488   SMM Ready To Lock event notification handler.
489 
490   The CPU S3 data is copied to SMRAM for security and mSmmReadyToLock is set to
491   perform additional lock actions that must be performed from SMM on the next SMI.
492 
493   @param[in] Protocol   Points to the protocol's unique identifier.
494   @param[in] Interface  Points to the interface instance.
495   @param[in] Handle     The handle on which the interface was installed.
496 
497   @retval EFI_SUCCESS   Notification handler runs successfully.
498  **/
499 EFI_STATUS
500 EFIAPI
SmmReadyToLockEventNotify(IN CONST EFI_GUID * Protocol,IN VOID * Interface,IN EFI_HANDLE Handle)501 SmmReadyToLockEventNotify (
502   IN CONST EFI_GUID  *Protocol,
503   IN VOID            *Interface,
504   IN EFI_HANDLE      Handle
505   )
506 {
507   GetAcpiCpuData ();
508 
509   //
510   // Cache a copy of UEFI memory map before we start profiling feature.
511   //
512   GetUefiMemoryMap ();
513 
514   //
515   // Set SMM ready to lock flag and return
516   //
517   mSmmReadyToLock = TRUE;
518   return EFI_SUCCESS;
519 }
520 
521 /**
522   The module Entry Point of the CPU SMM driver.
523 
524   @param  ImageHandle    The firmware allocated handle for the EFI image.
525   @param  SystemTable    A pointer to the EFI System Table.
526 
527   @retval EFI_SUCCESS    The entry point is executed successfully.
528   @retval Other          Some error occurs when executing this entry point.
529 
530 **/
531 EFI_STATUS
532 EFIAPI
PiCpuSmmEntry(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)533 PiCpuSmmEntry (
534   IN EFI_HANDLE        ImageHandle,
535   IN EFI_SYSTEM_TABLE  *SystemTable
536   )
537 {
538   EFI_STATUS                 Status;
539   EFI_MP_SERVICES_PROTOCOL   *MpServices;
540   UINTN                      NumberOfEnabledProcessors;
541   UINTN                      Index;
542   VOID                       *Buffer;
543   UINTN                      BufferPages;
544   UINTN                      TileCodeSize;
545   UINTN                      TileDataSize;
546   UINTN                      TileSize;
547   UINT8                      *Stacks;
548   VOID                       *Registration;
549   UINT32                     RegEax;
550   UINT32                     RegEbx;
551   UINT32                     RegEcx;
552   UINT32                     RegEdx;
553   UINTN                      FamilyId;
554   UINTN                      ModelId;
555   UINT32                     Cr3;
556 
557   //
558   // Initialize address fixup
559   //
560   PiSmmCpuSmmInitFixupAddress ();
561   PiSmmCpuSmiEntryFixupAddress ();
562 
563   //
564   // Initialize Debug Agent to support source level debug in SMM code
565   //
566   InitializeDebugAgent (DEBUG_AGENT_INIT_SMM, NULL, NULL);
567 
568   //
569   // Report the start of CPU SMM initialization.
570   //
571   REPORT_STATUS_CODE (
572     EFI_PROGRESS_CODE,
573     EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_PC_SMM_INIT
574     );
575 
576   //
577   // Find out SMRR Base and SMRR Size
578   //
579   FindSmramInfo (&mCpuHotPlugData.SmrrBase, &mCpuHotPlugData.SmrrSize);
580 
581   //
582   // Get MP Services Protocol
583   //
584   Status = SystemTable->BootServices->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpServices);
585   ASSERT_EFI_ERROR (Status);
586 
587   //
588   // Use MP Services Protocol to retrieve the number of processors and number of enabled processors
589   //
590   Status = MpServices->GetNumberOfProcessors (MpServices, &mNumberOfCpus, &NumberOfEnabledProcessors);
591   ASSERT_EFI_ERROR (Status);
592   ASSERT (mNumberOfCpus <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));
593 
594   //
595   // If support CPU hot plug, PcdCpuSmmEnableBspElection should be set to TRUE.
596   // A constant BSP index makes no sense because it may be hot removed.
597   //
598   DEBUG_CODE (
599     if (FeaturePcdGet (PcdCpuHotPlugSupport)) {
600 
601       ASSERT (FeaturePcdGet (PcdCpuSmmEnableBspElection));
602     }
603   );
604 
605   //
606   // Save the PcdCpuSmmCodeAccessCheckEnable value into a global variable.
607   //
608   mSmmCodeAccessCheckEnable = PcdGetBool (PcdCpuSmmCodeAccessCheckEnable);
609   DEBUG ((EFI_D_INFO, "PcdCpuSmmCodeAccessCheckEnable = %d\n", mSmmCodeAccessCheckEnable));
610 
611   //
612   // Save the PcdPteMemoryEncryptionAddressOrMask value into a global variable.
613   // Make sure AddressEncMask is contained to smallest supported address field.
614   //
615   mAddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;
616   DEBUG ((EFI_D_INFO, "mAddressEncMask = 0x%lx\n", mAddressEncMask));
617 
618   //
619   // If support CPU hot plug, we need to allocate resources for possibly hot-added processors
620   //
621   if (FeaturePcdGet (PcdCpuHotPlugSupport)) {
622     mMaxNumberOfCpus = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
623   } else {
624     mMaxNumberOfCpus = mNumberOfCpus;
625   }
626   gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus = mMaxNumberOfCpus;
627 
628   //
629   // The CPU save state and code for the SMI entry point are tiled within an SMRAM
630   // allocated buffer.  The minimum size of this buffer for a uniprocessor system
631   // is 32 KB, because the entry point is SMBASE + 32KB, and CPU save state area
632   // just below SMBASE + 64KB.  If more than one CPU is present in the platform,
633   // then the SMI entry point and the CPU save state areas can be tiles to minimize
634   // the total amount SMRAM required for all the CPUs.  The tile size can be computed
635   // by adding the   // CPU save state size, any extra CPU specific context, and
636   // the size of code that must be placed at the SMI entry point to transfer
637   // control to a C function in the native SMM execution mode.  This size is
638   // rounded up to the nearest power of 2 to give the tile size for a each CPU.
639   // The total amount of memory required is the maximum number of CPUs that
640   // platform supports times the tile size.  The picture below shows the tiling,
641   // where m is the number of tiles that fit in 32KB.
642   //
643   //  +-----------------------------+  <-- 2^n offset from Base of allocated buffer
644   //  |   CPU m+1 Save State        |
645   //  +-----------------------------+
646   //  |   CPU m+1 Extra Data        |
647   //  +-----------------------------+
648   //  |   Padding                   |
649   //  +-----------------------------+
650   //  |   CPU 2m  SMI Entry         |
651   //  +#############################+  <-- Base of allocated buffer + 64 KB
652   //  |   CPU m-1 Save State        |
653   //  +-----------------------------+
654   //  |   CPU m-1 Extra Data        |
655   //  +-----------------------------+
656   //  |   Padding                   |
657   //  +-----------------------------+
658   //  |   CPU 2m-1 SMI Entry        |
659   //  +=============================+  <-- 2^n offset from Base of allocated buffer
660   //  |   . . . . . . . . . . . .   |
661   //  +=============================+  <-- 2^n offset from Base of allocated buffer
662   //  |   CPU 2 Save State          |
663   //  +-----------------------------+
664   //  |   CPU 2 Extra Data          |
665   //  +-----------------------------+
666   //  |   Padding                   |
667   //  +-----------------------------+
668   //  |   CPU m+1 SMI Entry         |
669   //  +=============================+  <-- Base of allocated buffer + 32 KB
670   //  |   CPU 1 Save State          |
671   //  +-----------------------------+
672   //  |   CPU 1 Extra Data          |
673   //  +-----------------------------+
674   //  |   Padding                   |
675   //  +-----------------------------+
676   //  |   CPU m SMI Entry           |
677   //  +#############################+  <-- Base of allocated buffer + 32 KB == CPU 0 SMBASE + 64 KB
678   //  |   CPU 0 Save State          |
679   //  +-----------------------------+
680   //  |   CPU 0 Extra Data          |
681   //  +-----------------------------+
682   //  |   Padding                   |
683   //  +-----------------------------+
684   //  |   CPU m-1 SMI Entry         |
685   //  +=============================+  <-- 2^n offset from Base of allocated buffer
686   //  |   . . . . . . . . . . . .   |
687   //  +=============================+  <-- 2^n offset from Base of allocated buffer
688   //  |   Padding                   |
689   //  +-----------------------------+
690   //  |   CPU 1 SMI Entry           |
691   //  +=============================+  <-- 2^n offset from Base of allocated buffer
692   //  |   Padding                   |
693   //  +-----------------------------+
694   //  |   CPU 0 SMI Entry           |
695   //  +#############################+  <-- Base of allocated buffer == CPU 0 SMBASE + 32 KB
696   //
697 
698   //
699   // Retrieve CPU Family
700   //
701   AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);
702   FamilyId = (RegEax >> 8) & 0xf;
703   ModelId = (RegEax >> 4) & 0xf;
704   if (FamilyId == 0x06 || FamilyId == 0x0f) {
705     ModelId = ModelId | ((RegEax >> 12) & 0xf0);
706   }
707 
708   RegEdx = 0;
709   AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);
710   if (RegEax >= CPUID_EXTENDED_CPU_SIG) {
711     AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx);
712   }
713   //
714   // Determine the mode of the CPU at the time an SMI occurs
715   //   Intel(R) 64 and IA-32 Architectures Software Developer's Manual
716   //   Volume 3C, Section 34.4.1.1
717   //
718   mSmmSaveStateRegisterLma = EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT;
719   if ((RegEdx & BIT29) != 0) {
720     mSmmSaveStateRegisterLma = EFI_SMM_SAVE_STATE_REGISTER_LMA_64BIT;
721   }
722   if (FamilyId == 0x06) {
723     if (ModelId == 0x17 || ModelId == 0x0f || ModelId == 0x1c) {
724       mSmmSaveStateRegisterLma = EFI_SMM_SAVE_STATE_REGISTER_LMA_64BIT;
725     }
726   }
727 
728   DEBUG ((DEBUG_INFO, "PcdControlFlowEnforcementPropertyMask = %d\n", PcdGet32 (PcdControlFlowEnforcementPropertyMask)));
729   if (PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) {
730     AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);
731     if (RegEax > CPUID_EXTENDED_FUNCTION) {
732       AsmCpuidEx (CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS, CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_SUB_LEAF_INFO, NULL, NULL, &RegEcx, &RegEdx);
733       DEBUG ((DEBUG_INFO, "CPUID[7/0] ECX - 0x%08x\n", RegEcx));
734       DEBUG ((DEBUG_INFO, "  CET_SS  - 0x%08x\n", RegEcx & CPUID_CET_SS));
735       DEBUG ((DEBUG_INFO, "  CET_IBT - 0x%08x\n", RegEdx & CPUID_CET_IBT));
736       if ((RegEcx & CPUID_CET_SS) == 0) {
737         mCetSupported = FALSE;
738         PatchInstructionX86 (mPatchCetSupported, mCetSupported, 1);
739       }
740       if (mCetSupported) {
741         AsmCpuidEx (CPUID_EXTENDED_STATE, CPUID_EXTENDED_STATE_SUB_LEAF, NULL, &RegEbx, &RegEcx, NULL);
742         DEBUG ((DEBUG_INFO, "CPUID[D/1] EBX - 0x%08x, ECX - 0x%08x\n", RegEbx, RegEcx));
743         AsmCpuidEx (CPUID_EXTENDED_STATE, 11, &RegEax, NULL, &RegEcx, NULL);
744         DEBUG ((DEBUG_INFO, "CPUID[D/11] EAX - 0x%08x, ECX - 0x%08x\n", RegEax, RegEcx));
745         AsmCpuidEx(CPUID_EXTENDED_STATE, 12, &RegEax, NULL, &RegEcx, NULL);
746         DEBUG ((DEBUG_INFO, "CPUID[D/12] EAX - 0x%08x, ECX - 0x%08x\n", RegEax, RegEcx));
747       }
748     }
749   } else {
750     mCetSupported = FALSE;
751     PatchInstructionX86 (mPatchCetSupported, mCetSupported, 1);
752   }
753 
754   //
755   // Compute tile size of buffer required to hold the CPU SMRAM Save State Map, extra CPU
756   // specific context start starts at SMBASE + SMM_PSD_OFFSET, and the SMI entry point.
757   // This size is rounded up to nearest power of 2.
758   //
759   TileCodeSize = GetSmiHandlerSize ();
760   TileCodeSize = ALIGN_VALUE(TileCodeSize, SIZE_4KB);
761   TileDataSize = (SMRAM_SAVE_STATE_MAP_OFFSET - SMM_PSD_OFFSET) + sizeof (SMRAM_SAVE_STATE_MAP);
762   TileDataSize = ALIGN_VALUE(TileDataSize, SIZE_4KB);
763   TileSize = TileDataSize + TileCodeSize - 1;
764   TileSize = 2 * GetPowerOfTwo32 ((UINT32)TileSize);
765   DEBUG ((EFI_D_INFO, "SMRAM TileSize = 0x%08x (0x%08x, 0x%08x)\n", TileSize, TileCodeSize, TileDataSize));
766 
767   //
768   // If the TileSize is larger than space available for the SMI Handler of
769   // CPU[i], the extra CPU specific context of CPU[i+1], and the SMRAM Save
770   // State Map of CPU[i+1], then ASSERT().  If this ASSERT() is triggered, then
771   // the SMI Handler size must be reduced or the size of the extra CPU specific
772   // context must be reduced.
773   //
774   ASSERT (TileSize <= (SMRAM_SAVE_STATE_MAP_OFFSET + sizeof (SMRAM_SAVE_STATE_MAP) - SMM_HANDLER_OFFSET));
775 
776   //
777   // Allocate buffer for all of the tiles.
778   //
779   // Intel(R) 64 and IA-32 Architectures Software Developer's Manual
780   // Volume 3C, Section 34.11 SMBASE Relocation
781   //   For Pentium and Intel486 processors, the SMBASE values must be
782   //   aligned on a 32-KByte boundary or the processor will enter shutdown
783   //   state during the execution of a RSM instruction.
784   //
785   // Intel486 processors: FamilyId is 4
786   // Pentium processors : FamilyId is 5
787   //
788   BufferPages = EFI_SIZE_TO_PAGES (SIZE_32KB + TileSize * (mMaxNumberOfCpus - 1));
789   if ((FamilyId == 4) || (FamilyId == 5)) {
790     Buffer = AllocateAlignedCodePages (BufferPages, SIZE_32KB);
791   } else {
792     Buffer = AllocateAlignedCodePages (BufferPages, SIZE_4KB);
793   }
794   ASSERT (Buffer != NULL);
795   DEBUG ((EFI_D_INFO, "SMRAM SaveState Buffer (0x%08x, 0x%08x)\n", Buffer, EFI_PAGES_TO_SIZE(BufferPages)));
796 
797   //
798   // Allocate buffer for pointers to array in  SMM_CPU_PRIVATE_DATA.
799   //
800   gSmmCpuPrivate->ProcessorInfo = (EFI_PROCESSOR_INFORMATION *)AllocatePool (sizeof (EFI_PROCESSOR_INFORMATION) * mMaxNumberOfCpus);
801   ASSERT (gSmmCpuPrivate->ProcessorInfo != NULL);
802 
803   gSmmCpuPrivate->Operation = (SMM_CPU_OPERATION *)AllocatePool (sizeof (SMM_CPU_OPERATION) * mMaxNumberOfCpus);
804   ASSERT (gSmmCpuPrivate->Operation != NULL);
805 
806   gSmmCpuPrivate->CpuSaveStateSize = (UINTN *)AllocatePool (sizeof (UINTN) * mMaxNumberOfCpus);
807   ASSERT (gSmmCpuPrivate->CpuSaveStateSize != NULL);
808 
809   gSmmCpuPrivate->CpuSaveState = (VOID **)AllocatePool (sizeof (VOID *) * mMaxNumberOfCpus);
810   ASSERT (gSmmCpuPrivate->CpuSaveState != NULL);
811 
812   mSmmCpuPrivateData.SmmCoreEntryContext.CpuSaveStateSize = gSmmCpuPrivate->CpuSaveStateSize;
813   mSmmCpuPrivateData.SmmCoreEntryContext.CpuSaveState     = gSmmCpuPrivate->CpuSaveState;
814 
815   //
816   // Allocate buffer for pointers to array in CPU_HOT_PLUG_DATA.
817   //
818   mCpuHotPlugData.ApicId = (UINT64 *)AllocatePool (sizeof (UINT64) * mMaxNumberOfCpus);
819   ASSERT (mCpuHotPlugData.ApicId != NULL);
820   mCpuHotPlugData.SmBase = (UINTN *)AllocatePool (sizeof (UINTN) * mMaxNumberOfCpus);
821   ASSERT (mCpuHotPlugData.SmBase != NULL);
822   mCpuHotPlugData.ArrayLength = (UINT32)mMaxNumberOfCpus;
823 
824   //
825   // Retrieve APIC ID of each enabled processor from the MP Services protocol.
826   // Also compute the SMBASE address, CPU Save State address, and CPU Save state
827   // size for each CPU in the platform
828   //
829   for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
830     mCpuHotPlugData.SmBase[Index]          = (UINTN)Buffer + Index * TileSize - SMM_HANDLER_OFFSET;
831     gSmmCpuPrivate->CpuSaveStateSize[Index] = sizeof(SMRAM_SAVE_STATE_MAP);
832     gSmmCpuPrivate->CpuSaveState[Index]     = (VOID *)(mCpuHotPlugData.SmBase[Index] + SMRAM_SAVE_STATE_MAP_OFFSET);
833     gSmmCpuPrivate->Operation[Index] = SmmCpuNone;
834 
835     if (Index < mNumberOfCpus) {
836       Status = MpServices->GetProcessorInfo (MpServices, Index, &gSmmCpuPrivate->ProcessorInfo[Index]);
837       ASSERT_EFI_ERROR (Status);
838       mCpuHotPlugData.ApicId[Index] = gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId;
839 
840       DEBUG ((EFI_D_INFO, "CPU[%03x]  APIC ID=%04x  SMBASE=%08x  SaveState=%08x  Size=%08x\n",
841         Index,
842         (UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId,
843         mCpuHotPlugData.SmBase[Index],
844         gSmmCpuPrivate->CpuSaveState[Index],
845         gSmmCpuPrivate->CpuSaveStateSize[Index]
846         ));
847     } else {
848       gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId = INVALID_APIC_ID;
849       mCpuHotPlugData.ApicId[Index] = INVALID_APIC_ID;
850     }
851   }
852 
853   //
854   // Allocate SMI stacks for all processors.
855   //
856   mSmmStackSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStackSize)));
857   if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
858     //
859     // 2 more pages is allocated for each processor.
860     // one is guard page and the other is known good stack.
861     //
862     // +-------------------------------------------+-----+-------------------------------------------+
863     // | Known Good Stack | Guard Page | SMM Stack | ... | Known Good Stack | Guard Page | SMM Stack |
864     // +-------------------------------------------+-----+-------------------------------------------+
865     // |                                           |     |                                           |
866     // |<-------------- Processor 0 -------------->|     |<-------------- Processor n -------------->|
867     //
868     mSmmStackSize += EFI_PAGES_TO_SIZE (2);
869   }
870 
871   mSmmShadowStackSize = 0;
872   if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) {
873     //
874     // Append Shadow Stack after normal stack
875     //
876     // |= Stacks
877     // +--------------------------------------------------+---------------------------------------------------------------+
878     // | Known Good Stack | Guard Page |    SMM Stack     | Known Good Shadow Stack | Guard Page |    SMM Shadow Stack    |
879     // +--------------------------------------------------+---------------------------------------------------------------+
880     // |                               |PcdCpuSmmStackSize|                                      |PcdCpuSmmShadowStackSize|
881     // |<---------------- mSmmStackSize ----------------->|<--------------------- mSmmShadowStackSize ------------------->|
882     // |                                                                                                                  |
883     // |<-------------------------------------------- Processor N ------------------------------------------------------->|
884     //
885     mSmmShadowStackSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmShadowStackSize)));
886     if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
887       mSmmShadowStackSize += EFI_PAGES_TO_SIZE (2);
888     }
889   }
890 
891   Stacks = (UINT8 *) AllocatePages (gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus * (EFI_SIZE_TO_PAGES (mSmmStackSize + mSmmShadowStackSize)));
892   ASSERT (Stacks != NULL);
893   mSmmStackArrayBase = (UINTN)Stacks;
894   mSmmStackArrayEnd = mSmmStackArrayBase + gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus * (mSmmStackSize + mSmmShadowStackSize) - 1;
895 
896   DEBUG ((DEBUG_INFO, "Stacks                   - 0x%x\n", Stacks));
897   DEBUG ((DEBUG_INFO, "mSmmStackSize            - 0x%x\n", mSmmStackSize));
898   DEBUG ((DEBUG_INFO, "PcdCpuSmmStackGuard      - 0x%x\n", FeaturePcdGet (PcdCpuSmmStackGuard)));
899   if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) {
900     DEBUG ((DEBUG_INFO, "mSmmShadowStackSize      - 0x%x\n", mSmmShadowStackSize));
901   }
902 
903   //
904   // Set SMI stack for SMM base relocation
905   //
906   PatchInstructionX86 (
907     gPatchSmmInitStack,
908     (UINTN) (Stacks + mSmmStackSize - sizeof (UINTN)),
909     sizeof (UINTN)
910     );
911 
912   //
913   // Initialize IDT
914   //
915   InitializeSmmIdt ();
916 
917   //
918   // Relocate SMM Base addresses to the ones allocated from SMRAM
919   //
920   mRebased = (BOOLEAN *)AllocateZeroPool (sizeof (BOOLEAN) * mMaxNumberOfCpus);
921   ASSERT (mRebased != NULL);
922   SmmRelocateBases ();
923 
924   //
925   // Call hook for BSP to perform extra actions in normal mode after all
926   // SMM base addresses have been relocated on all CPUs
927   //
928   SmmCpuFeaturesSmmRelocationComplete ();
929 
930   DEBUG ((DEBUG_INFO, "mXdSupported - 0x%x\n", mXdSupported));
931 
932   //
933   // SMM Time initialization
934   //
935   InitializeSmmTimer ();
936 
937   //
938   // Initialize MP globals
939   //
940   Cr3 = InitializeMpServiceData (Stacks, mSmmStackSize, mSmmShadowStackSize);
941 
942   if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) {
943     for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
944       SetShadowStack (
945         Cr3,
946         (EFI_PHYSICAL_ADDRESS)(UINTN)Stacks + mSmmStackSize + (mSmmStackSize + mSmmShadowStackSize) * Index,
947         mSmmShadowStackSize
948         );
949       if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
950         SetNotPresentPage (
951           Cr3,
952           (EFI_PHYSICAL_ADDRESS)(UINTN)Stacks + mSmmStackSize + EFI_PAGES_TO_SIZE(1) + (mSmmStackSize + mSmmShadowStackSize) * Index,
953           EFI_PAGES_TO_SIZE(1)
954           );
955       }
956     }
957   }
958 
959   //
960   // Fill in SMM Reserved Regions
961   //
962   gSmmCpuPrivate->SmmReservedSmramRegion[0].SmramReservedStart = 0;
963   gSmmCpuPrivate->SmmReservedSmramRegion[0].SmramReservedSize  = 0;
964 
965   //
966   // Install the SMM Configuration Protocol onto a new handle on the handle database.
967   // The entire SMM Configuration Protocol is allocated from SMRAM, so only a pointer
968   // to an SMRAM address will be present in the handle database
969   //
970   Status = SystemTable->BootServices->InstallMultipleProtocolInterfaces (
971                                         &gSmmCpuPrivate->SmmCpuHandle,
972                                         &gEfiSmmConfigurationProtocolGuid, &gSmmCpuPrivate->SmmConfiguration,
973                                         NULL
974                                         );
975   ASSERT_EFI_ERROR (Status);
976 
977   //
978   // Install the SMM CPU Protocol into SMM protocol database
979   //
980   Status = gSmst->SmmInstallProtocolInterface (
981                     &mSmmCpuHandle,
982                     &gEfiSmmCpuProtocolGuid,
983                     EFI_NATIVE_INTERFACE,
984                     &mSmmCpu
985                     );
986   ASSERT_EFI_ERROR (Status);
987 
988   //
989   // Install the SMM Memory Attribute Protocol into SMM protocol database
990   //
991   Status = gSmst->SmmInstallProtocolInterface (
992                     &mSmmCpuHandle,
993                     &gEdkiiSmmMemoryAttributeProtocolGuid,
994                     EFI_NATIVE_INTERFACE,
995                     &mSmmMemoryAttribute
996                     );
997   ASSERT_EFI_ERROR (Status);
998 
999   //
1000   // Expose address of CPU Hot Plug Data structure if CPU hot plug is supported.
1001   //
1002   if (FeaturePcdGet (PcdCpuHotPlugSupport)) {
1003     Status = PcdSet64S (PcdCpuHotPlugDataAddress, (UINT64)(UINTN)&mCpuHotPlugData);
1004     ASSERT_EFI_ERROR (Status);
1005   }
1006 
1007   //
1008   // Initialize SMM CPU Services Support
1009   //
1010   Status = InitializeSmmCpuServices (mSmmCpuHandle);
1011   ASSERT_EFI_ERROR (Status);
1012 
1013   //
1014   // register SMM Ready To Lock Protocol notification
1015   //
1016   Status = gSmst->SmmRegisterProtocolNotify (
1017                     &gEfiSmmReadyToLockProtocolGuid,
1018                     SmmReadyToLockEventNotify,
1019                     &Registration
1020                     );
1021   ASSERT_EFI_ERROR (Status);
1022 
1023   //
1024   // Initialize SMM Profile feature
1025   //
1026   InitSmmProfile (Cr3);
1027 
1028   GetAcpiS3EnableFlag ();
1029   InitSmmS3ResumeState (Cr3);
1030 
1031   DEBUG ((EFI_D_INFO, "SMM CPU Module exit from SMRAM with EFI_SUCCESS\n"));
1032 
1033   return EFI_SUCCESS;
1034 }
1035 
1036 /**
1037 
1038   Find out SMRAM information including SMRR base and SMRR size.
1039 
1040   @param          SmrrBase          SMRR base
1041   @param          SmrrSize          SMRR size
1042 
1043 **/
1044 VOID
FindSmramInfo(OUT UINT32 * SmrrBase,OUT UINT32 * SmrrSize)1045 FindSmramInfo (
1046   OUT UINT32   *SmrrBase,
1047   OUT UINT32   *SmrrSize
1048   )
1049 {
1050   EFI_STATUS                        Status;
1051   UINTN                             Size;
1052   EFI_SMM_ACCESS2_PROTOCOL          *SmmAccess;
1053   EFI_SMRAM_DESCRIPTOR              *CurrentSmramRange;
1054   UINTN                             Index;
1055   UINT64                            MaxSize;
1056   BOOLEAN                           Found;
1057 
1058   //
1059   // Get SMM Access Protocol
1060   //
1061   Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess);
1062   ASSERT_EFI_ERROR (Status);
1063 
1064   //
1065   // Get SMRAM information
1066   //
1067   Size = 0;
1068   Status = SmmAccess->GetCapabilities (SmmAccess, &Size, NULL);
1069   ASSERT (Status == EFI_BUFFER_TOO_SMALL);
1070 
1071   mSmmCpuSmramRanges = (EFI_SMRAM_DESCRIPTOR *)AllocatePool (Size);
1072   ASSERT (mSmmCpuSmramRanges != NULL);
1073 
1074   Status = SmmAccess->GetCapabilities (SmmAccess, &Size, mSmmCpuSmramRanges);
1075   ASSERT_EFI_ERROR (Status);
1076 
1077   mSmmCpuSmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
1078 
1079   //
1080   // Find the largest SMRAM range between 1MB and 4GB that is at least 256K - 4K in size
1081   //
1082   CurrentSmramRange = NULL;
1083   for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < mSmmCpuSmramRangeCount; Index++) {
1084     //
1085     // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization
1086     //
1087     if ((mSmmCpuSmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
1088       continue;
1089     }
1090 
1091     if (mSmmCpuSmramRanges[Index].CpuStart >= BASE_1MB) {
1092       if ((mSmmCpuSmramRanges[Index].CpuStart + mSmmCpuSmramRanges[Index].PhysicalSize) <= SMRR_MAX_ADDRESS) {
1093         if (mSmmCpuSmramRanges[Index].PhysicalSize >= MaxSize) {
1094           MaxSize = mSmmCpuSmramRanges[Index].PhysicalSize;
1095           CurrentSmramRange = &mSmmCpuSmramRanges[Index];
1096         }
1097       }
1098     }
1099   }
1100 
1101   ASSERT (CurrentSmramRange != NULL);
1102 
1103   *SmrrBase = (UINT32)CurrentSmramRange->CpuStart;
1104   *SmrrSize = (UINT32)CurrentSmramRange->PhysicalSize;
1105 
1106   do {
1107     Found = FALSE;
1108     for (Index = 0; Index < mSmmCpuSmramRangeCount; Index++) {
1109       if (mSmmCpuSmramRanges[Index].CpuStart < *SmrrBase &&
1110           *SmrrBase == (mSmmCpuSmramRanges[Index].CpuStart + mSmmCpuSmramRanges[Index].PhysicalSize)) {
1111         *SmrrBase = (UINT32)mSmmCpuSmramRanges[Index].CpuStart;
1112         *SmrrSize = (UINT32)(*SmrrSize + mSmmCpuSmramRanges[Index].PhysicalSize);
1113         Found = TRUE;
1114       } else if ((*SmrrBase + *SmrrSize) == mSmmCpuSmramRanges[Index].CpuStart && mSmmCpuSmramRanges[Index].PhysicalSize > 0) {
1115         *SmrrSize = (UINT32)(*SmrrSize + mSmmCpuSmramRanges[Index].PhysicalSize);
1116         Found = TRUE;
1117       }
1118     }
1119   } while (Found);
1120 
1121   DEBUG ((EFI_D_INFO, "SMRR Base: 0x%x, SMRR Size: 0x%x\n", *SmrrBase, *SmrrSize));
1122 }
1123 
1124 /**
1125 Configure SMM Code Access Check feature on an AP.
1126 SMM Feature Control MSR will be locked after configuration.
1127 
1128 @param[in,out] Buffer  Pointer to private data buffer.
1129 **/
1130 VOID
1131 EFIAPI
ConfigSmmCodeAccessCheckOnCurrentProcessor(IN OUT VOID * Buffer)1132 ConfigSmmCodeAccessCheckOnCurrentProcessor (
1133   IN OUT VOID  *Buffer
1134   )
1135 {
1136   UINTN   CpuIndex;
1137   UINT64  SmmFeatureControlMsr;
1138   UINT64  NewSmmFeatureControlMsr;
1139 
1140   //
1141   // Retrieve the CPU Index from the context passed in
1142   //
1143   CpuIndex = *(UINTN *)Buffer;
1144 
1145   //
1146   // Get the current SMM Feature Control MSR value
1147   //
1148   SmmFeatureControlMsr = SmmCpuFeaturesGetSmmRegister (CpuIndex, SmmRegFeatureControl);
1149 
1150   //
1151   // Compute the new SMM Feature Control MSR value
1152   //
1153   NewSmmFeatureControlMsr = SmmFeatureControlMsr;
1154   if (mSmmCodeAccessCheckEnable) {
1155     NewSmmFeatureControlMsr |= SMM_CODE_CHK_EN_BIT;
1156     if (FeaturePcdGet (PcdCpuSmmFeatureControlMsrLock)) {
1157       NewSmmFeatureControlMsr |= SMM_FEATURE_CONTROL_LOCK_BIT;
1158     }
1159   }
1160 
1161   //
1162   // Only set the SMM Feature Control MSR value if the new value is different than the current value
1163   //
1164   if (NewSmmFeatureControlMsr != SmmFeatureControlMsr) {
1165     SmmCpuFeaturesSetSmmRegister (CpuIndex, SmmRegFeatureControl, NewSmmFeatureControlMsr);
1166   }
1167 
1168   //
1169   // Release the spin lock user to serialize the updates to the SMM Feature Control MSR
1170   //
1171   ReleaseSpinLock (mConfigSmmCodeAccessCheckLock);
1172 }
1173 
1174 /**
1175 Configure SMM Code Access Check feature for all processors.
1176 SMM Feature Control MSR will be locked after configuration.
1177 **/
1178 VOID
ConfigSmmCodeAccessCheck(VOID)1179 ConfigSmmCodeAccessCheck (
1180   VOID
1181   )
1182 {
1183   UINTN       Index;
1184   EFI_STATUS  Status;
1185 
1186   //
1187   // Check to see if the Feature Control MSR is supported on this CPU
1188   //
1189   Index = gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu;
1190   if (!SmmCpuFeaturesIsSmmRegisterSupported (Index, SmmRegFeatureControl)) {
1191     mSmmCodeAccessCheckEnable = FALSE;
1192     return;
1193   }
1194 
1195   //
1196   // Check to see if the CPU supports the SMM Code Access Check feature
1197   // Do not access this MSR unless the CPU supports the SmmRegFeatureControl
1198   //
1199   if ((AsmReadMsr64 (EFI_MSR_SMM_MCA_CAP) & SMM_CODE_ACCESS_CHK_BIT) == 0) {
1200     mSmmCodeAccessCheckEnable = FALSE;
1201     return;
1202   }
1203 
1204   //
1205   // Initialize the lock used to serialize the MSR programming in BSP and all APs
1206   //
1207   InitializeSpinLock (mConfigSmmCodeAccessCheckLock);
1208 
1209   //
1210   // Acquire Config SMM Code Access Check spin lock.  The BSP will release the
1211   // spin lock when it is done executing ConfigSmmCodeAccessCheckOnCurrentProcessor().
1212   //
1213   AcquireSpinLock (mConfigSmmCodeAccessCheckLock);
1214 
1215   //
1216   // Enable SMM Code Access Check feature on the BSP.
1217   //
1218   ConfigSmmCodeAccessCheckOnCurrentProcessor (&Index);
1219 
1220   //
1221   // Enable SMM Code Access Check feature for the APs.
1222   //
1223   for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
1224     if (Index != gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu) {
1225       if (gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId == INVALID_APIC_ID) {
1226         //
1227         // If this processor does not exist
1228         //
1229         continue;
1230       }
1231       //
1232       // Acquire Config SMM Code Access Check spin lock.  The AP will release the
1233       // spin lock when it is done executing ConfigSmmCodeAccessCheckOnCurrentProcessor().
1234       //
1235       AcquireSpinLock (mConfigSmmCodeAccessCheckLock);
1236 
1237       //
1238       // Call SmmStartupThisAp() to enable SMM Code Access Check on an AP.
1239       //
1240       Status = gSmst->SmmStartupThisAp (ConfigSmmCodeAccessCheckOnCurrentProcessor, Index, &Index);
1241       ASSERT_EFI_ERROR (Status);
1242 
1243       //
1244       // Wait for the AP to release the Config SMM Code Access Check spin lock.
1245       //
1246       while (!AcquireSpinLockOrFail (mConfigSmmCodeAccessCheckLock)) {
1247         CpuPause ();
1248       }
1249 
1250       //
1251       // Release the Config SMM Code Access Check spin lock.
1252       //
1253       ReleaseSpinLock (mConfigSmmCodeAccessCheckLock);
1254     }
1255   }
1256 }
1257 
1258 /**
1259   This API provides a way to allocate memory for page table.
1260 
1261   This API can be called more once to allocate memory for page tables.
1262 
1263   Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
1264   allocated buffer.  The buffer returned is aligned on a 4KB boundary.  If Pages is 0, then NULL
1265   is returned.  If there is not enough memory remaining to satisfy the request, then NULL is
1266   returned.
1267 
1268   @param  Pages                 The number of 4 KB pages to allocate.
1269 
1270   @return A pointer to the allocated buffer or NULL if allocation fails.
1271 
1272 **/
1273 VOID *
AllocatePageTableMemory(IN UINTN Pages)1274 AllocatePageTableMemory (
1275   IN UINTN           Pages
1276   )
1277 {
1278   VOID  *Buffer;
1279 
1280   Buffer = SmmCpuFeaturesAllocatePageTableMemory (Pages);
1281   if (Buffer != NULL) {
1282     return Buffer;
1283   }
1284   return AllocatePages (Pages);
1285 }
1286 
1287 /**
1288   Allocate pages for code.
1289 
1290   @param[in]  Pages Number of pages to be allocated.
1291 
1292   @return Allocated memory.
1293 **/
1294 VOID *
AllocateCodePages(IN UINTN Pages)1295 AllocateCodePages (
1296   IN UINTN           Pages
1297   )
1298 {
1299   EFI_STATUS            Status;
1300   EFI_PHYSICAL_ADDRESS  Memory;
1301 
1302   if (Pages == 0) {
1303     return NULL;
1304   }
1305 
1306   Status = gSmst->SmmAllocatePages (AllocateAnyPages, EfiRuntimeServicesCode, Pages, &Memory);
1307   if (EFI_ERROR (Status)) {
1308     return NULL;
1309   }
1310   return (VOID *) (UINTN) Memory;
1311 }
1312 
1313 /**
1314   Allocate aligned pages for code.
1315 
1316   @param[in]  Pages                 Number of pages to be allocated.
1317   @param[in]  Alignment             The requested alignment of the allocation.
1318                                     Must be a power of two.
1319                                     If Alignment is zero, then byte alignment is used.
1320 
1321   @return Allocated memory.
1322 **/
1323 VOID *
AllocateAlignedCodePages(IN UINTN Pages,IN UINTN Alignment)1324 AllocateAlignedCodePages (
1325   IN UINTN            Pages,
1326   IN UINTN            Alignment
1327   )
1328 {
1329   EFI_STATUS            Status;
1330   EFI_PHYSICAL_ADDRESS  Memory;
1331   UINTN                 AlignedMemory;
1332   UINTN                 AlignmentMask;
1333   UINTN                 UnalignedPages;
1334   UINTN                 RealPages;
1335 
1336   //
1337   // Alignment must be a power of two or zero.
1338   //
1339   ASSERT ((Alignment & (Alignment - 1)) == 0);
1340 
1341   if (Pages == 0) {
1342     return NULL;
1343   }
1344   if (Alignment > EFI_PAGE_SIZE) {
1345     //
1346     // Calculate the total number of pages since alignment is larger than page size.
1347     //
1348     AlignmentMask  = Alignment - 1;
1349     RealPages      = Pages + EFI_SIZE_TO_PAGES (Alignment);
1350     //
1351     // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.
1352     //
1353     ASSERT (RealPages > Pages);
1354 
1355     Status         = gSmst->SmmAllocatePages (AllocateAnyPages, EfiRuntimeServicesCode, RealPages, &Memory);
1356     if (EFI_ERROR (Status)) {
1357       return NULL;
1358     }
1359     AlignedMemory  = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;
1360     UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);
1361     if (UnalignedPages > 0) {
1362       //
1363       // Free first unaligned page(s).
1364       //
1365       Status = gSmst->SmmFreePages (Memory, UnalignedPages);
1366       ASSERT_EFI_ERROR (Status);
1367     }
1368     Memory         = AlignedMemory + EFI_PAGES_TO_SIZE (Pages);
1369     UnalignedPages = RealPages - Pages - UnalignedPages;
1370     if (UnalignedPages > 0) {
1371       //
1372       // Free last unaligned page(s).
1373       //
1374       Status = gSmst->SmmFreePages (Memory, UnalignedPages);
1375       ASSERT_EFI_ERROR (Status);
1376     }
1377   } else {
1378     //
1379     // Do not over-allocate pages in this case.
1380     //
1381     Status = gSmst->SmmAllocatePages (AllocateAnyPages, EfiRuntimeServicesCode, Pages, &Memory);
1382     if (EFI_ERROR (Status)) {
1383       return NULL;
1384     }
1385     AlignedMemory  = (UINTN) Memory;
1386   }
1387   return (VOID *) AlignedMemory;
1388 }
1389 
1390 /**
1391   Perform the remaining tasks.
1392 
1393 **/
1394 VOID
PerformRemainingTasks(VOID)1395 PerformRemainingTasks (
1396   VOID
1397   )
1398 {
1399   if (mSmmReadyToLock) {
1400     //
1401     // Start SMM Profile feature
1402     //
1403     if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
1404       SmmProfileStart ();
1405     }
1406     //
1407     // Create a mix of 2MB and 4KB page table. Update some memory ranges absent and execute-disable.
1408     //
1409     InitPaging ();
1410 
1411     //
1412     // Mark critical region to be read-only in page table
1413     //
1414     SetMemMapAttributes ();
1415 
1416     //
1417     // For outside SMRAM, we only map SMM communication buffer or MMIO.
1418     //
1419     SetUefiMemMapAttributes ();
1420 
1421     //
1422     // Set page table itself to be read-only
1423     //
1424     SetPageTableAttributes ();
1425 
1426     //
1427     // Configure SMM Code Access Check feature if available.
1428     //
1429     ConfigSmmCodeAccessCheck ();
1430 
1431     SmmCpuFeaturesCompleteSmmReadyToLock ();
1432 
1433     //
1434     // Clean SMM ready to lock flag
1435     //
1436     mSmmReadyToLock = FALSE;
1437   }
1438 }
1439 
1440 /**
1441   Perform the pre tasks.
1442 
1443 **/
1444 VOID
PerformPreTasks(VOID)1445 PerformPreTasks (
1446   VOID
1447   )
1448 {
1449   RestoreSmmConfigurationInS3 ();
1450 }
1451