2 SMM CPU misc functions for x64 arch specific.
4 Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "PiSmmCpuDxeSmm.h"
17 EFI_PHYSICAL_ADDRESS mGdtBuffer
;
20 extern BOOLEAN mCetSupported
;
21 extern UINTN mSmmShadowStackSize
;
23 X86_ASSEMBLY_PATCH_LABEL mPatchCetPl0Ssp
;
24 X86_ASSEMBLY_PATCH_LABEL mPatchCetInterruptSsp
;
25 X86_ASSEMBLY_PATCH_LABEL mPatchCetInterruptSspTable
;
27 UINT32 mCetInterruptSsp
;
28 UINT32 mCetInterruptSspTable
;
30 UINTN mSmmInterruptSspTables
;
33 Initialize IDT for SMM Stack Guard.
38 InitializeIDTSmmStackGuard (
42 IA32_IDT_GATE_DESCRIPTOR
*IdtGate
;
45 // If SMM Stack Guard feature is enabled, set the IST field of
46 // the interrupt gate for Page Fault Exception to be 1
48 IdtGate
= (IA32_IDT_GATE_DESCRIPTOR
*)gcSmiIdtr
.Base
;
49 IdtGate
+= EXCEPT_IA32_PAGE_FAULT
;
50 IdtGate
->Bits
.Reserved_0
= 1;
54 Initialize Gdt for all processors.
56 @param[in] Cr3 CR3 value.
57 @param[out] GdtStepSize The step size for GDT table.
59 @return GdtBase for processor 0.
60 GdtBase for processor X is: GdtBase + (GdtStepSize * X)
65 OUT UINTN
*GdtStepSize
69 IA32_SEGMENT_DESCRIPTOR
*GdtDescriptor
;
71 UINTN GdtTssTableSize
;
73 UINTN GdtTableStepSize
;
76 // For X64 SMM, we allocate separate GDT/TSS for each CPUs to avoid TSS load contention
79 GdtTssTableSize
= (gcSmiGdtr
.Limit
+ 1 + TSS_SIZE
+ 7) & ~7; // 8 bytes aligned
80 mGdtBufferSize
= GdtTssTableSize
* gSmmCpuPrivate
->SmmCoreEntryContext
.NumberOfCpus
;
81 GdtTssTables
= (UINT8
*)AllocateCodePages (EFI_SIZE_TO_PAGES (mGdtBufferSize
));
82 ASSERT (GdtTssTables
!= NULL
);
83 mGdtBuffer
= (UINTN
)GdtTssTables
;
84 GdtTableStepSize
= GdtTssTableSize
;
86 for (Index
= 0; Index
< gSmmCpuPrivate
->SmmCoreEntryContext
.NumberOfCpus
; Index
++) {
87 CopyMem (GdtTssTables
+ GdtTableStepSize
* Index
, (VOID
*)(UINTN
)gcSmiGdtr
.Base
, gcSmiGdtr
.Limit
+ 1 + TSS_SIZE
);
90 // Fixup TSS descriptors
92 TssBase
= (UINTN
)(GdtTssTables
+ GdtTableStepSize
* Index
+ gcSmiGdtr
.Limit
+ 1);
93 GdtDescriptor
= (IA32_SEGMENT_DESCRIPTOR
*)(TssBase
) - 2;
94 GdtDescriptor
->Bits
.BaseLow
= (UINT16
)(UINTN
)TssBase
;
95 GdtDescriptor
->Bits
.BaseMid
= (UINT8
)((UINTN
)TssBase
>> 16);
96 GdtDescriptor
->Bits
.BaseHigh
= (UINT8
)((UINTN
)TssBase
>> 24);
98 if (FeaturePcdGet (PcdCpuSmmStackGuard
)) {
100 // Setup top of known good stack as IST1 for each processor.
102 *(UINTN
*)(TssBase
+ TSS_X64_IST1_OFFSET
) = (mSmmStackArrayBase
+ EFI_PAGE_SIZE
+ Index
* mSmmStackSize
);
106 *GdtStepSize
= GdtTableStepSize
;
111 Get Protected mode code segment from current GDT table.
113 @return Protected mode code segment value.
120 IA32_DESCRIPTOR GdtrDesc
;
121 IA32_SEGMENT_DESCRIPTOR
*GdtEntry
;
125 AsmReadGdtr (&GdtrDesc
);
126 GdtEntryCount
= (GdtrDesc
.Limit
+ 1) / sizeof (IA32_SEGMENT_DESCRIPTOR
);
127 GdtEntry
= (IA32_SEGMENT_DESCRIPTOR
*) GdtrDesc
.Base
;
128 for (Index
= 0; Index
< GdtEntryCount
; Index
++) {
129 if (GdtEntry
->Bits
.L
== 0) {
130 if (GdtEntry
->Bits
.Type
> 8 && GdtEntry
->Bits
.L
== 0) {
136 ASSERT (Index
!= GdtEntryCount
);
141 Transfer AP to safe hlt-loop after it finished restore CPU features on S3 patch.
143 @param[in] ApHltLoopCode The address of the safe hlt-loop function.
144 @param[in] TopOfStack A pointer to the new stack to use for the ApHltLoopCode.
145 @param[in] NumberToFinishAddress Address of Semaphore of APs finish count.
149 TransferApToSafeState (
150 IN UINTN ApHltLoopCode
,
152 IN UINTN NumberToFinishAddress
156 GetProtectedModeCS (),
157 (UINT32
)ApHltLoopCode
,
158 (UINT32
)NumberToFinishAddress
,
163 // It should never reach here
169 Initialize the shadow stack related data structure.
171 @param CpuIndex The index of CPU.
172 @param ShadowStack The bottom of the shadow stack for this CPU.
180 UINTN SmmShadowStackSize
;
181 UINT64
*InterruptSspTable
;
183 if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask
) != 0) && mCetSupported
) {
184 SmmShadowStackSize
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmShadowStackSize
)));
185 if (FeaturePcdGet (PcdCpuSmmStackGuard
)) {
186 SmmShadowStackSize
+= EFI_PAGES_TO_SIZE (2);
188 mCetPl0Ssp
= (UINT32
)((UINTN
)ShadowStack
+ SmmShadowStackSize
- sizeof(UINT64
));
189 PatchInstructionX86 (mPatchCetPl0Ssp
, mCetPl0Ssp
, 4);
190 DEBUG ((DEBUG_INFO
, "mCetPl0Ssp - 0x%x\n", mCetPl0Ssp
));
191 DEBUG ((DEBUG_INFO
, "ShadowStack - 0x%x\n", ShadowStack
));
192 DEBUG ((DEBUG_INFO
, " SmmShadowStackSize - 0x%x\n", SmmShadowStackSize
));
194 if (FeaturePcdGet (PcdCpuSmmStackGuard
)) {
195 if (mSmmInterruptSspTables
== 0) {
196 mSmmInterruptSspTables
= (UINTN
)AllocateZeroPool(sizeof(UINT64
) * 8 * gSmmCpuPrivate
->SmmCoreEntryContext
.NumberOfCpus
);
197 ASSERT (mSmmInterruptSspTables
!= 0);
198 DEBUG ((DEBUG_INFO
, "mSmmInterruptSspTables - 0x%x\n", mSmmInterruptSspTables
));
200 mCetInterruptSsp
= (UINT32
)((UINTN
)ShadowStack
+ EFI_PAGES_TO_SIZE(1) - sizeof(UINT64
));
201 mCetInterruptSspTable
= (UINT32
)(UINTN
)(mSmmInterruptSspTables
+ sizeof(UINT64
) * 8 * CpuIndex
);
202 InterruptSspTable
= (UINT64
*)(UINTN
)mCetInterruptSspTable
;
203 InterruptSspTable
[1] = mCetInterruptSsp
;
204 PatchInstructionX86 (mPatchCetInterruptSsp
, mCetInterruptSsp
, 4);
205 PatchInstructionX86 (mPatchCetInterruptSspTable
, mCetInterruptSspTable
, 4);
206 DEBUG ((DEBUG_INFO
, "mCetInterruptSsp - 0x%x\n", mCetInterruptSsp
));
207 DEBUG ((DEBUG_INFO
, "mCetInterruptSspTable - 0x%x\n", mCetInterruptSspTable
));