]>
Commit | Line | Data |
---|---|---|
e2289d19 BS |
1 | /** @file\r |
2 | CPU MP Initialize helper function for AMD SEV.\r | |
3 | \r | |
4 | Copyright (c) 2021, AMD Inc. All rights reserved.<BR>\r | |
5 | \r | |
6 | SPDX-License-Identifier: BSD-2-Clause-Patent\r | |
7 | \r | |
8 | **/\r | |
9 | \r | |
10 | #include "MpLib.h"\r | |
11 | #include <Library/VmgExitLib.h>\r | |
12 | \r | |
13 | /**\r | |
14 | Get Protected mode code segment with 16-bit default addressing\r | |
15 | from current GDT table.\r | |
16 | \r | |
17 | @return Protected mode 16-bit code segment value.\r | |
18 | **/\r | |
19 | STATIC\r | |
20 | UINT16\r | |
21 | GetProtectedMode16CS (\r | |
22 | VOID\r | |
23 | )\r | |
24 | {\r | |
25 | IA32_DESCRIPTOR GdtrDesc;\r | |
26 | IA32_SEGMENT_DESCRIPTOR *GdtEntry;\r | |
27 | UINTN GdtEntryCount;\r | |
28 | UINT16 Index;\r | |
29 | \r | |
30 | Index = (UINT16)-1;\r | |
31 | AsmReadGdtr (&GdtrDesc);\r | |
32 | GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);\r | |
33 | GdtEntry = (IA32_SEGMENT_DESCRIPTOR *)GdtrDesc.Base;\r | |
34 | for (Index = 0; Index < GdtEntryCount; Index++) {\r | |
35 | if ((GdtEntry->Bits.L == 0) &&\r | |
36 | (GdtEntry->Bits.DB == 0) &&\r | |
37 | (GdtEntry->Bits.Type > 8))\r | |
38 | {\r | |
39 | break;\r | |
40 | }\r | |
41 | \r | |
42 | GdtEntry++;\r | |
43 | }\r | |
44 | \r | |
45 | ASSERT (Index != GdtEntryCount);\r | |
46 | return Index * 8;\r | |
47 | }\r | |
48 | \r | |
49 | /**\r | |
50 | Get Protected mode code segment with 32-bit default addressing\r | |
51 | from current GDT table.\r | |
52 | \r | |
53 | @return Protected mode 32-bit code segment value.\r | |
54 | **/\r | |
55 | STATIC\r | |
56 | UINT16\r | |
57 | GetProtectedMode32CS (\r | |
58 | VOID\r | |
59 | )\r | |
60 | {\r | |
61 | IA32_DESCRIPTOR GdtrDesc;\r | |
62 | IA32_SEGMENT_DESCRIPTOR *GdtEntry;\r | |
63 | UINTN GdtEntryCount;\r | |
64 | UINT16 Index;\r | |
65 | \r | |
66 | Index = (UINT16)-1;\r | |
67 | AsmReadGdtr (&GdtrDesc);\r | |
68 | GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);\r | |
69 | GdtEntry = (IA32_SEGMENT_DESCRIPTOR *)GdtrDesc.Base;\r | |
70 | for (Index = 0; Index < GdtEntryCount; Index++) {\r | |
71 | if ((GdtEntry->Bits.L == 0) &&\r | |
72 | (GdtEntry->Bits.DB == 1) &&\r | |
73 | (GdtEntry->Bits.Type > 8))\r | |
74 | {\r | |
75 | break;\r | |
76 | }\r | |
77 | \r | |
78 | GdtEntry++;\r | |
79 | }\r | |
80 | \r | |
81 | ASSERT (Index != GdtEntryCount);\r | |
82 | return Index * 8;\r | |
83 | }\r | |
84 | \r | |
85 | /**\r | |
86 | Reset an AP when in SEV-ES mode.\r | |
87 | \r | |
88 | If successful, this function never returns.\r | |
89 | \r | |
90 | @param[in] Ghcb Pointer to the GHCB\r | |
91 | @param[in] CpuMpData Pointer to CPU MP Data\r | |
92 | \r | |
93 | **/\r | |
94 | VOID\r | |
95 | MpInitLibSevEsAPReset (\r | |
96 | IN GHCB *Ghcb,\r | |
97 | IN CPU_MP_DATA *CpuMpData\r | |
98 | )\r | |
99 | {\r | |
100 | EFI_STATUS Status;\r | |
101 | UINTN ProcessorNumber;\r | |
102 | UINT16 Code16, Code32;\r | |
103 | AP_RESET *APResetFn;\r | |
104 | UINTN BufferStart;\r | |
105 | UINTN StackStart;\r | |
106 | \r | |
107 | Status = GetProcessorNumber (CpuMpData, &ProcessorNumber);\r | |
108 | ASSERT_EFI_ERROR (Status);\r | |
109 | \r | |
110 | Code16 = GetProtectedMode16CS ();\r | |
111 | Code32 = GetProtectedMode32CS ();\r | |
112 | \r | |
113 | if (CpuMpData->WakeupBufferHigh != 0) {\r | |
114 | APResetFn = (AP_RESET *)(CpuMpData->WakeupBufferHigh + CpuMpData->AddressMap.SwitchToRealNoNxOffset);\r | |
115 | } else {\r | |
116 | APResetFn = (AP_RESET *)(CpuMpData->MpCpuExchangeInfo->BufferStart + CpuMpData->AddressMap.SwitchToRealOffset);\r | |
117 | }\r | |
118 | \r | |
119 | BufferStart = CpuMpData->MpCpuExchangeInfo->BufferStart;\r | |
120 | StackStart = CpuMpData->SevEsAPResetStackStart -\r | |
121 | (AP_RESET_STACK_SIZE * ProcessorNumber);\r | |
122 | \r | |
123 | //\r | |
124 | // This call never returns.\r | |
125 | //\r | |
126 | APResetFn (BufferStart, Code16, Code32, StackStart);\r | |
127 | }\r | |
128 | \r | |
129 | /**\r | |
130 | Allocate the SEV-ES AP jump table buffer.\r | |
131 | \r | |
132 | @param[in, out] CpuMpData The pointer to CPU MP Data structure.\r | |
133 | **/\r | |
134 | VOID\r | |
135 | AllocateSevEsAPMemory (\r | |
136 | IN OUT CPU_MP_DATA *CpuMpData\r | |
137 | )\r | |
138 | {\r | |
139 | if (CpuMpData->SevEsAPBuffer == (UINTN)-1) {\r | |
140 | CpuMpData->SevEsAPBuffer =\r | |
141 | CpuMpData->SevEsIsEnabled ? GetSevEsAPMemory () : 0;\r | |
142 | }\r | |
143 | }\r | |
144 | \r | |
145 | /**\r | |
146 | Program the SEV-ES AP jump table buffer.\r | |
147 | \r | |
148 | @param[in] SipiVector The SIPI vector used for the AP Reset\r | |
149 | **/\r | |
150 | VOID\r | |
151 | SetSevEsJumpTable (\r | |
152 | IN UINTN SipiVector\r | |
153 | )\r | |
154 | {\r | |
155 | SEV_ES_AP_JMP_FAR *JmpFar;\r | |
156 | UINT32 Offset, InsnByte;\r | |
157 | UINT8 LoNib, HiNib;\r | |
158 | \r | |
159 | JmpFar = (SEV_ES_AP_JMP_FAR *)(UINTN)FixedPcdGet32 (PcdSevEsWorkAreaBase);\r | |
160 | ASSERT (JmpFar != NULL);\r | |
161 | \r | |
162 | //\r | |
163 | // Obtain the address of the Segment/Rip location in the workarea.\r | |
164 | // This will be set to a value derived from the SIPI vector and will\r | |
165 | // be the memory address used for the far jump below.\r | |
166 | //\r | |
167 | Offset = FixedPcdGet32 (PcdSevEsWorkAreaBase);\r | |
168 | Offset += sizeof (JmpFar->InsnBuffer);\r | |
169 | LoNib = (UINT8)Offset;\r | |
170 | HiNib = (UINT8)(Offset >> 8);\r | |
171 | \r | |
172 | //\r | |
173 | // Program the workarea (which is the initial AP boot address) with\r | |
174 | // far jump to the SIPI vector (where XX and YY represent the\r | |
175 | // address of where the SIPI vector is stored.\r | |
176 | //\r | |
177 | // JMP FAR [CS:XXYY] => 2E FF 2E YY XX\r | |
178 | //\r | |
179 | InsnByte = 0;\r | |
180 | JmpFar->InsnBuffer[InsnByte++] = 0x2E; // CS override prefix\r | |
181 | JmpFar->InsnBuffer[InsnByte++] = 0xFF; // JMP (FAR)\r | |
182 | JmpFar->InsnBuffer[InsnByte++] = 0x2E; // ModRM (JMP memory location)\r | |
183 | JmpFar->InsnBuffer[InsnByte++] = LoNib; // YY offset ...\r | |
184 | JmpFar->InsnBuffer[InsnByte++] = HiNib; // XX offset ...\r | |
185 | \r | |
186 | //\r | |
187 | // Program the Segment/Rip based on the SIPI vector (always at least\r | |
188 | // 16-byte aligned, so Rip is set to 0).\r | |
189 | //\r | |
190 | JmpFar->Rip = 0;\r | |
191 | JmpFar->Segment = (UINT16)(SipiVector >> 4);\r | |
192 | }\r | |
193 | \r | |
194 | /**\r | |
195 | The function puts the AP in halt loop.\r | |
196 | \r | |
197 | @param[in] CpuMpData The pointer to CPU MP Data structure.\r | |
198 | **/\r | |
199 | VOID\r | |
200 | SevEsPlaceApHlt (\r | |
201 | CPU_MP_DATA *CpuMpData\r | |
202 | )\r | |
203 | {\r | |
204 | MSR_SEV_ES_GHCB_REGISTER Msr;\r | |
205 | GHCB *Ghcb;\r | |
206 | UINT64 Status;\r | |
207 | BOOLEAN DoDecrement;\r | |
208 | BOOLEAN InterruptState;\r | |
209 | \r | |
210 | DoDecrement = (BOOLEAN)(CpuMpData->InitFlag == ApInitConfig);\r | |
211 | \r | |
212 | while (TRUE) {\r | |
213 | Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);\r | |
214 | Ghcb = Msr.Ghcb;\r | |
215 | \r | |
216 | VmgInit (Ghcb, &InterruptState);\r | |
217 | \r | |
218 | if (DoDecrement) {\r | |
219 | DoDecrement = FALSE;\r | |
220 | \r | |
221 | //\r | |
222 | // Perform the delayed decrement just before issuing the first\r | |
223 | // VMGEXIT with AP_RESET_HOLD.\r | |
224 | //\r | |
225 | InterlockedDecrement ((UINT32 *)&CpuMpData->MpCpuExchangeInfo->NumApsExecuting);\r | |
226 | }\r | |
227 | \r | |
228 | Status = VmgExit (Ghcb, SVM_EXIT_AP_RESET_HOLD, 0, 0);\r | |
229 | if ((Status == 0) && (Ghcb->SaveArea.SwExitInfo2 != 0)) {\r | |
230 | VmgDone (Ghcb, InterruptState);\r | |
231 | break;\r | |
232 | }\r | |
233 | \r | |
234 | VmgDone (Ghcb, InterruptState);\r | |
235 | }\r | |
236 | \r | |
237 | //\r | |
238 | // Awakened in a new phase? Use the new CpuMpData\r | |
239 | //\r | |
240 | if (CpuMpData->NewCpuMpData != NULL) {\r | |
241 | CpuMpData = CpuMpData->NewCpuMpData;\r | |
242 | }\r | |
243 | \r | |
244 | MpInitLibSevEsAPReset (Ghcb, CpuMpData);\r | |
245 | }\r |