]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c
UefiCpuPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / PiSmmCpuDxeSmm.c
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
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
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
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
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
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
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
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
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
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
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
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 *
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 *
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 *
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
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
1445 PerformPreTasks (
1446 VOID
1447 )
1448 {
1449 RestoreSmmConfigurationInS3 ();
1450 }