]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
UefiCpuPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / X64 / SmmFuncsArch.c
CommitLineData
fe5f1949
JY
1/** @file\r
2 SMM CPU misc functions for x64 arch specific.\r
7367cc6c 3\r
3eb69b08 4Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>\r
0acd8697 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
fe5f1949
JY
6\r
7**/\r
8\r
9#include "PiSmmCpuDxeSmm.h"\r
10\r
717fb604
JY
11EFI_PHYSICAL_ADDRESS mGdtBuffer;\r
12UINTN mGdtBufferSize;\r
13\r
3eb69b08
JY
14extern BOOLEAN mCetSupported;\r
15extern UINTN mSmmShadowStackSize;\r
16\r
17X86_ASSEMBLY_PATCH_LABEL mPatchCetPl0Ssp;\r
18X86_ASSEMBLY_PATCH_LABEL mPatchCetInterruptSsp;\r
19X86_ASSEMBLY_PATCH_LABEL mPatchCetInterruptSspTable;\r
20UINT32 mCetPl0Ssp;\r
21UINT32 mCetInterruptSsp;\r
22UINT32 mCetInterruptSspTable;\r
23\r
24UINTN mSmmInterruptSspTables;\r
25\r
717fb604
JY
26/**\r
27 Initialize IDT for SMM Stack Guard.\r
28\r
29**/\r
30VOID\r
31EFIAPI\r
32InitializeIDTSmmStackGuard (\r
33 VOID\r
34 )\r
35{\r
36 IA32_IDT_GATE_DESCRIPTOR *IdtGate;\r
37\r
38 //\r
39 // If SMM Stack Guard feature is enabled, set the IST field of\r
40 // the interrupt gate for Page Fault Exception to be 1\r
41 //\r
42 IdtGate = (IA32_IDT_GATE_DESCRIPTOR *)gcSmiIdtr.Base;\r
43 IdtGate += EXCEPT_IA32_PAGE_FAULT;\r
44 IdtGate->Bits.Reserved_0 = 1;\r
45}\r
46\r
fe5f1949
JY
47/**\r
48 Initialize Gdt for all processors.\r
7367cc6c 49\r
fe5f1949
JY
50 @param[in] Cr3 CR3 value.\r
51 @param[out] GdtStepSize The step size for GDT table.\r
52\r
53 @return GdtBase for processor 0.\r
54 GdtBase for processor X is: GdtBase + (GdtStepSize * X)\r
55**/\r
56VOID *\r
57InitGdt (\r
58 IN UINTN Cr3,\r
59 OUT UINTN *GdtStepSize\r
60 )\r
61{\r
62 UINTN Index;\r
63 IA32_SEGMENT_DESCRIPTOR *GdtDescriptor;\r
64 UINTN TssBase;\r
65 UINTN GdtTssTableSize;\r
66 UINT8 *GdtTssTables;\r
67 UINTN GdtTableStepSize;\r
68\r
69 //\r
70 // For X64 SMM, we allocate separate GDT/TSS for each CPUs to avoid TSS load contention\r
71 // on each SMI entry.\r
72 //\r
73 GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE + 7) & ~7; // 8 bytes aligned\r
717fb604
JY
74 mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;\r
75 GdtTssTables = (UINT8*)AllocateCodePages (EFI_SIZE_TO_PAGES (mGdtBufferSize));\r
fe5f1949 76 ASSERT (GdtTssTables != NULL);\r
717fb604 77 mGdtBuffer = (UINTN)GdtTssTables;\r
fe5f1949
JY
78 GdtTableStepSize = GdtTssTableSize;\r
79\r
80 for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {\r
81 CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE);\r
82\r
83 //\r
84 // Fixup TSS descriptors\r
85 //\r
86 TssBase = (UINTN)(GdtTssTables + GdtTableStepSize * Index + gcSmiGdtr.Limit + 1);\r
87 GdtDescriptor = (IA32_SEGMENT_DESCRIPTOR *)(TssBase) - 2;\r
88 GdtDescriptor->Bits.BaseLow = (UINT16)(UINTN)TssBase;\r
89 GdtDescriptor->Bits.BaseMid = (UINT8)((UINTN)TssBase >> 16);\r
90 GdtDescriptor->Bits.BaseHigh = (UINT8)((UINTN)TssBase >> 24);\r
91\r
92 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
93 //\r
94 // Setup top of known good stack as IST1 for each processor.\r
95 //\r
96 *(UINTN *)(TssBase + TSS_X64_IST1_OFFSET) = (mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize);\r
97 }\r
98 }\r
99\r
100 *GdtStepSize = GdtTableStepSize;\r
101 return GdtTssTables;\r
102}\r
4a0f88dd 103\r
45e3440a
JF
104/**\r
105 Get Protected mode code segment from current GDT table.\r
106\r
107 @return Protected mode code segment value.\r
108**/\r
109UINT16\r
110GetProtectedModeCS (\r
111 VOID\r
112 )\r
113{\r
114 IA32_DESCRIPTOR GdtrDesc;\r
115 IA32_SEGMENT_DESCRIPTOR *GdtEntry;\r
116 UINTN GdtEntryCount;\r
117 UINT16 Index;\r
118\r
45e3440a
JF
119 AsmReadGdtr (&GdtrDesc);\r
120 GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);\r
121 GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;\r
122 for (Index = 0; Index < GdtEntryCount; Index++) {\r
123 if (GdtEntry->Bits.L == 0) {\r
124 if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.L == 0) {\r
125 break;\r
126 }\r
127 }\r
128 GdtEntry++;\r
129 }\r
4222e8e7 130 ASSERT (Index != GdtEntryCount);\r
45e3440a
JF
131 return Index * 8;\r
132}\r
133\r
4a0f88dd
JF
134/**\r
135 Transfer AP to safe hlt-loop after it finished restore CPU features on S3 patch.\r
136\r
672b80c8
MK
137 @param[in] ApHltLoopCode The address of the safe hlt-loop function.\r
138 @param[in] TopOfStack A pointer to the new stack to use for the ApHltLoopCode.\r
139 @param[in] NumberToFinishAddress Address of Semaphore of APs finish count.\r
4a0f88dd
JF
140\r
141**/\r
142VOID\r
143TransferApToSafeState (\r
672b80c8
MK
144 IN UINTN ApHltLoopCode,\r
145 IN UINTN TopOfStack,\r
146 IN UINTN NumberToFinishAddress\r
4a0f88dd
JF
147 )\r
148{\r
45e3440a
JF
149 AsmDisablePaging64 (\r
150 GetProtectedModeCS (),\r
672b80c8
MK
151 (UINT32)ApHltLoopCode,\r
152 (UINT32)NumberToFinishAddress,\r
45e3440a 153 0,\r
672b80c8 154 (UINT32)TopOfStack\r
4a0f88dd
JF
155 );\r
156 //\r
157 // It should never reach here\r
158 //\r
159 ASSERT (FALSE);\r
160}\r
161\r
3eb69b08
JY
162/**\r
163 Initialize the shadow stack related data structure.\r
164\r
165 @param CpuIndex The index of CPU.\r
166 @param ShadowStack The bottom of the shadow stack for this CPU.\r
167**/\r
168VOID\r
169InitShadowStack (\r
170 IN UINTN CpuIndex,\r
171 IN VOID *ShadowStack\r
172 )\r
173{\r
174 UINTN SmmShadowStackSize;\r
175 UINT64 *InterruptSspTable;\r
176\r
177 if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) {\r
178 SmmShadowStackSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmShadowStackSize)));\r
179 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
180 SmmShadowStackSize += EFI_PAGES_TO_SIZE (2);\r
181 }\r
182 mCetPl0Ssp = (UINT32)((UINTN)ShadowStack + SmmShadowStackSize - sizeof(UINT64));\r
183 PatchInstructionX86 (mPatchCetPl0Ssp, mCetPl0Ssp, 4);\r
184 DEBUG ((DEBUG_INFO, "mCetPl0Ssp - 0x%x\n", mCetPl0Ssp));\r
185 DEBUG ((DEBUG_INFO, "ShadowStack - 0x%x\n", ShadowStack));\r
186 DEBUG ((DEBUG_INFO, " SmmShadowStackSize - 0x%x\n", SmmShadowStackSize));\r
187\r
188 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
189 if (mSmmInterruptSspTables == 0) {\r
190 mSmmInterruptSspTables = (UINTN)AllocateZeroPool(sizeof(UINT64) * 8 * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus);\r
191 ASSERT (mSmmInterruptSspTables != 0);\r
192 DEBUG ((DEBUG_INFO, "mSmmInterruptSspTables - 0x%x\n", mSmmInterruptSspTables));\r
193 }\r
194 mCetInterruptSsp = (UINT32)((UINTN)ShadowStack + EFI_PAGES_TO_SIZE(1) - sizeof(UINT64));\r
195 mCetInterruptSspTable = (UINT32)(UINTN)(mSmmInterruptSspTables + sizeof(UINT64) * 8 * CpuIndex);\r
196 InterruptSspTable = (UINT64 *)(UINTN)mCetInterruptSspTable;\r
197 InterruptSspTable[1] = mCetInterruptSsp;\r
198 PatchInstructionX86 (mPatchCetInterruptSsp, mCetInterruptSsp, 4);\r
199 PatchInstructionX86 (mPatchCetInterruptSspTable, mCetInterruptSspTable, 4);\r
200 DEBUG ((DEBUG_INFO, "mCetInterruptSsp - 0x%x\n", mCetInterruptSsp));\r
201 DEBUG ((DEBUG_INFO, "mCetInterruptSspTable - 0x%x\n", mCetInterruptSspTable));\r
202 }\r
203 }\r
204}\r
205\r