]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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
053e878b
MK
11EFI_PHYSICAL_ADDRESS mGdtBuffer;\r
12UINTN mGdtBufferSize;\r
717fb604 13\r
053e878b
MK
14extern BOOLEAN mCetSupported;\r
15extern UINTN mSmmShadowStackSize;\r
3eb69b08 16\r
053e878b
MK
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
3eb69b08
JY
23\r
24UINTN mSmmInterruptSspTables;\r
25\r
717fb604 26/**\r
455b0347
S
27 Initialize IDT IST Field.\r
28\r
29 @param[in] ExceptionType Exception type.\r
30 @param[in] Ist IST value.\r
717fb604
JY
31\r
32**/\r
33VOID\r
34EFIAPI\r
455b0347 35InitializeIdtIst (\r
053e878b
MK
36 IN EFI_EXCEPTION_TYPE ExceptionType,\r
37 IN UINT8 Ist\r
717fb604
JY
38 )\r
39{\r
40 IA32_IDT_GATE_DESCRIPTOR *IdtGate;\r
41\r
053e878b
MK
42 IdtGate = (IA32_IDT_GATE_DESCRIPTOR *)gcSmiIdtr.Base;\r
43 IdtGate += ExceptionType;\r
455b0347 44 IdtGate->Bits.Reserved_0 = Ist;\r
717fb604
JY
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
053e878b
MK
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
fe5f1949
JY
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
053e878b
MK
74 mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;\r
75 GdtTssTables = (UINT8 *)AllocateCodePages (EFI_SIZE_TO_PAGES (mGdtBufferSize));\r
fe5f1949 76 ASSERT (GdtTssTables != NULL);\r
053e878b 77 mGdtBuffer = (UINTN)GdtTssTables;\r
fe5f1949
JY
78 GdtTableStepSize = GdtTssTableSize;\r
79\r
80 for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {\r
053e878b 81 CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID *)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE);\r
fe5f1949
JY
82\r
83 //\r
84 // Fixup TSS descriptors\r
85 //\r
053e878b
MK
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
fe5f1949
JY
90 GdtDescriptor->Bits.BaseHigh = (UINT8)((UINTN)TssBase >> 24);\r
91\r
455b0347 92 if ((FeaturePcdGet (PcdCpuSmmStackGuard)) || ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported)) {\r
fe5f1949
JY
93 //\r
94 // Setup top of known good stack as IST1 for each processor.\r
95 //\r
ef91b073 96 *(UINTN *)(TssBase + TSS_X64_IST1_OFFSET) = (mSmmStackArrayBase + EFI_PAGE_SIZE + Index * (mSmmStackSize + mSmmShadowStackSize));\r
fe5f1949
JY
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
053e878b 121 GdtEntry = (IA32_SEGMENT_DESCRIPTOR *)GdtrDesc.Base;\r
45e3440a
JF
122 for (Index = 0; Index < GdtEntryCount; Index++) {\r
123 if (GdtEntry->Bits.L == 0) {\r
053e878b 124 if ((GdtEntry->Bits.Type > 8) && (GdtEntry->Bits.DB == 1)) {\r
45e3440a
JF
125 break;\r
126 }\r
127 }\r
053e878b 128\r
45e3440a
JF
129 GdtEntry++;\r
130 }\r
053e878b 131\r
4222e8e7 132 ASSERT (Index != GdtEntryCount);\r
45e3440a
JF
133 return Index * 8;\r
134}\r
135\r
4a0f88dd
JF
136/**\r
137 Transfer AP to safe hlt-loop after it finished restore CPU features on S3 patch.\r
138\r
672b80c8
MK
139 @param[in] ApHltLoopCode The address of the safe hlt-loop function.\r
140 @param[in] TopOfStack A pointer to the new stack to use for the ApHltLoopCode.\r
141 @param[in] NumberToFinishAddress Address of Semaphore of APs finish count.\r
4a0f88dd
JF
142\r
143**/\r
144VOID\r
145TransferApToSafeState (\r
672b80c8
MK
146 IN UINTN ApHltLoopCode,\r
147 IN UINTN TopOfStack,\r
148 IN UINTN NumberToFinishAddress\r
4a0f88dd
JF
149 )\r
150{\r
45e3440a
JF
151 AsmDisablePaging64 (\r
152 GetProtectedModeCS (),\r
672b80c8
MK
153 (UINT32)ApHltLoopCode,\r
154 (UINT32)NumberToFinishAddress,\r
45e3440a 155 0,\r
672b80c8 156 (UINT32)TopOfStack\r
4a0f88dd
JF
157 );\r
158 //\r
159 // It should never reach here\r
160 //\r
161 ASSERT (FALSE);\r
162}\r
163\r
3eb69b08
JY
164/**\r
165 Initialize the shadow stack related data structure.\r
166\r
167 @param CpuIndex The index of CPU.\r
168 @param ShadowStack The bottom of the shadow stack for this CPU.\r
169**/\r
170VOID\r
171InitShadowStack (\r
172 IN UINTN CpuIndex,\r
173 IN VOID *ShadowStack\r
174 )\r
175{\r
053e878b
MK
176 UINTN SmmShadowStackSize;\r
177 UINT64 *InterruptSspTable;\r
178 UINT32 InterruptSsp;\r
3eb69b08
JY
179\r
180 if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) {\r
181 SmmShadowStackSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmShadowStackSize)));\r
455b0347
S
182 //\r
183 // Add 1 page as known good shadow stack\r
184 //\r
185 SmmShadowStackSize += EFI_PAGES_TO_SIZE (1);\r
186\r
3eb69b08 187 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
455b0347
S
188 //\r
189 // Add one guard page between Known Good Shadow Stack and SMM Shadow Stack.\r
190 //\r
191 SmmShadowStackSize += EFI_PAGES_TO_SIZE (1);\r
3eb69b08 192 }\r
053e878b
MK
193\r
194 mCetPl0Ssp = (UINT32)((UINTN)ShadowStack + SmmShadowStackSize - sizeof (UINT64));\r
3eb69b08
JY
195 PatchInstructionX86 (mPatchCetPl0Ssp, mCetPl0Ssp, 4);\r
196 DEBUG ((DEBUG_INFO, "mCetPl0Ssp - 0x%x\n", mCetPl0Ssp));\r
197 DEBUG ((DEBUG_INFO, "ShadowStack - 0x%x\n", ShadowStack));\r
198 DEBUG ((DEBUG_INFO, " SmmShadowStackSize - 0x%x\n", SmmShadowStackSize));\r
199\r
455b0347 200 if (mSmmInterruptSspTables == 0) {\r
053e878b 201 mSmmInterruptSspTables = (UINTN)AllocateZeroPool (sizeof (UINT64) * 8 * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus);\r
455b0347
S
202 ASSERT (mSmmInterruptSspTables != 0);\r
203 DEBUG ((DEBUG_INFO, "mSmmInterruptSspTables - 0x%x\n", mSmmInterruptSspTables));\r
3eb69b08 204 }\r
455b0347
S
205\r
206 //\r
207 // The highest address on the stack (0xFE0) is a save-previous-ssp token pointing to a location that is 40 bytes away - 0xFB8.\r
208 // The supervisor shadow stack token is just above it at address 0xFD8. This is where the interrupt SSP table points.\r
209 // So when an interrupt of exception occurs, we can use SAVESSP/RESTORESSP/CLEARSSBUSY for the supervisor shadow stack,\r
210 // due to the reason the RETF in SMM exception handler cannot clear the BUSY flag with same CPL.\r
211 // (only IRET or RETF with different CPL can clear BUSY flag)\r
212 // Please refer to UefiCpuPkg/Library/CpuExceptionHandlerLib/X64 for the full stack frame at runtime.\r
213 // According to SDM (ver. 075 June 2021), shadow stack should be 32 bytes aligned.\r
214 //\r
053e878b
MK
215 InterruptSsp = (UINT32)(((UINTN)ShadowStack + EFI_PAGES_TO_SIZE (1) - (sizeof (UINT64) * 4)) & ~0x1f);\r
216 *(UINT64 *)(UINTN)InterruptSsp = (InterruptSsp - sizeof (UINT64) * 4) | 0x2;\r
217 mCetInterruptSsp = InterruptSsp - sizeof (UINT64);\r
455b0347 218\r
053e878b
MK
219 mCetInterruptSspTable = (UINT32)(UINTN)(mSmmInterruptSspTables + sizeof (UINT64) * 8 * CpuIndex);\r
220 InterruptSspTable = (UINT64 *)(UINTN)mCetInterruptSspTable;\r
221 InterruptSspTable[1] = mCetInterruptSsp;\r
455b0347
S
222 PatchInstructionX86 (mPatchCetInterruptSsp, mCetInterruptSsp, 4);\r
223 PatchInstructionX86 (mPatchCetInterruptSspTable, mCetInterruptSspTable, 4);\r
224 DEBUG ((DEBUG_INFO, "mCetInterruptSsp - 0x%x\n", mCetInterruptSsp));\r
225 DEBUG ((DEBUG_INFO, "mCetInterruptSspTable - 0x%x\n", mCetInterruptSspTable));\r
3eb69b08
JY
226 }\r
227}\r