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