]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MpInitLib/X64/AmdSev.nasm
Revert "UefiCpuPkg: Duplicated AsmRelocateApLoop as AsmRelocateApLoopAmd"
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / X64 / AmdSev.nasm
CommitLineData
e2289d19
BS
1;------------------------------------------------------------------------------ ;\r
2; Copyright (c) 2021, AMD Inc. All rights reserved.<BR>\r
3; SPDX-License-Identifier: BSD-2-Clause-Patent\r
4;\r
5; Module Name:\r
6;\r
7; AmdSev.nasm\r
8;\r
9; Abstract:\r
10;\r
11; This provides helper used by the MpFunc.nasm. If AMD SEV-ES is active\r
12; then helpers perform the additional setups (such as GHCB).\r
13;\r
14;-------------------------------------------------------------------------------\r
15\r
16%define SIZE_4KB 0x1000\r
17\r
9c703bc0
BS
18RegisterGhcbGpa:\r
19 ;\r
20 ; Register GHCB GPA when SEV-SNP is enabled\r
21 ;\r
22 lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevSnpIsEnabled)]\r
23 cmp byte [edi], 1 ; SevSnpIsEnabled\r
24 jne RegisterGhcbGpaDone\r
25\r
26 ; Save the rdi and rsi to used for later comparison\r
27 push rdi\r
28 push rsi\r
29 mov edi, eax\r
30 mov esi, edx\r
31 or eax, 18 ; Ghcb registration request\r
32 wrmsr\r
33 rep vmmcall\r
34 rdmsr\r
35 mov r12, rax\r
36 and r12, 0fffh\r
37 cmp r12, 19 ; Ghcb registration response\r
38 jne GhcbGpaRegisterFailure\r
39\r
40 ; Verify that GPA is not changed\r
41 and eax, 0fffff000h\r
42 cmp edi, eax\r
43 jne GhcbGpaRegisterFailure\r
44 cmp esi, edx\r
45 jne GhcbGpaRegisterFailure\r
46 pop rsi\r
47 pop rdi\r
48 jmp RegisterGhcbGpaDone\r
49\r
50 ;\r
51 ; Request the guest termination\r
52 ;\r
53GhcbGpaRegisterFailure:\r
54 xor edx, edx\r
55 mov eax, 256 ; GHCB terminate\r
56 wrmsr\r
57 rep vmmcall\r
58\r
59 ; We should not return from the above terminate request, but if we do\r
60 ; then enter into the hlt loop.\r
61DoHltLoop:\r
62 cli\r
63 hlt\r
64 jmp DoHltLoop\r
65\r
66RegisterGhcbGpaDone:\r
67 OneTimeCallRet RegisterGhcbGpa\r
68\r
e2289d19
BS
69;\r
70; The function checks whether SEV-ES is enabled, if enabled\r
71; then setup the GHCB page.\r
72;\r
73SevEsSetupGhcb:\r
74 lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevEsIsEnabled)]\r
75 cmp byte [edi], 1 ; SevEsIsEnabled\r
76 jne SevEsSetupGhcbExit\r
77\r
78 ;\r
79 ; program GHCB\r
80 ; Each page after the GHCB is a per-CPU page, so the calculation programs\r
81 ; a GHCB to be every 8KB.\r
82 ;\r
83 mov eax, SIZE_4KB\r
84 shl eax, 1 ; EAX = SIZE_4K * 2\r
85 mov ecx, ebx\r
86 mul ecx ; EAX = SIZE_4K * 2 * CpuNumber\r
87 mov edi, esi\r
88 add edi, MP_CPU_EXCHANGE_INFO_FIELD (GhcbBase)\r
89 add rax, qword [edi]\r
90 mov rdx, rax\r
91 shr rdx, 32\r
92 mov rcx, 0xc0010130\r
9c703bc0
BS
93\r
94 OneTimeCall RegisterGhcbGpa\r
95\r
e2289d19
BS
96 wrmsr\r
97\r
98SevEsSetupGhcbExit:\r
99 OneTimeCallRet SevEsSetupGhcb\r
100\r
101;\r
102; The function checks whether SEV-ES is enabled, if enabled, use\r
103; the GHCB\r
104;\r
105SevEsGetApicId:\r
106 lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevEsIsEnabled)]\r
107 cmp byte [edi], 1 ; SevEsIsEnabled\r
108 jne SevEsGetApicIdExit\r
109\r
110 ;\r
111 ; Since we don't have a stack yet, we can't take a #VC\r
112 ; exception. Use the GHCB protocol to perform the CPUID\r
113 ; calls.\r
114 ;\r
115 mov rcx, 0xc0010130\r
116 rdmsr\r
117 shl rdx, 32\r
118 or rax, rdx\r
119 mov rdi, rax ; RDI now holds the original GHCB GPA\r
120\r
d4d7c9ad
MR
121 ;\r
122 ; For SEV-SNP, the recommended handling for getting the x2APIC ID\r
123 ; would be to use the SNP CPUID table to fetch CPUID.00H:EAX and\r
124 ; CPUID:0BH:EBX[15:0] instead of the GHCB MSR protocol vmgexits\r
125 ; below.\r
126 ;\r
127 ; To avoid the unecessary ugliness to accomplish that here, the BSP\r
128 ; has performed these checks in advance (where #VC handler handles\r
129 ; the CPUID table lookups automatically) and cached them in a flag\r
130 ; so those checks can be skipped here.\r
131 ;\r
132 mov eax, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevSnpIsEnabled)]\r
133 cmp al, 1\r
134 jne CheckExtTopoAvail\r
135\r
136 ;\r
137 ; Even with SEV-SNP, the actual x2APIC ID in CPUID.0BH:EDX\r
138 ; fetched from the hypervisor the same way SEV-ES does it.\r
139 ;\r
140 mov eax, [esi + MP_CPU_EXCHANGE_INFO_FIELD (ExtTopoAvail)]\r
141 cmp al, 1\r
142 je GetApicIdSevEs\r
143 ; The 8-bit APIC ID fallback is also the same as with SEV-ES\r
144 jmp NoX2ApicSevEs\r
145\r
146CheckExtTopoAvail:\r
e2289d19
BS
147 mov rdx, 0 ; CPUID function 0\r
148 mov rax, 0 ; RAX register requested\r
149 or rax, 4\r
150 wrmsr\r
151 rep vmmcall\r
152 rdmsr\r
153 cmp edx, 0bh\r
154 jb NoX2ApicSevEs ; CPUID level below CPUID_EXTENDED_TOPOLOGY\r
155\r
156 mov rdx, 0bh ; CPUID function 0x0b\r
157 mov rax, 040000000h ; RBX register requested\r
158 or rax, 4\r
159 wrmsr\r
160 rep vmmcall\r
161 rdmsr\r
162 test edx, 0ffffh\r
163 jz NoX2ApicSevEs ; CPUID.0BH:EBX[15:0] is zero\r
164\r
d4d7c9ad 165GetApicIdSevEs:\r
e2289d19
BS
166 mov rdx, 0bh ; CPUID function 0x0b\r
167 mov rax, 0c0000000h ; RDX register requested\r
168 or rax, 4\r
169 wrmsr\r
170 rep vmmcall\r
171 rdmsr\r
172\r
173 ; Processor is x2APIC capable; 32-bit x2APIC ID is now in EDX\r
174 jmp RestoreGhcb\r
175\r
176NoX2ApicSevEs:\r
177 ; Processor is not x2APIC capable, so get 8-bit APIC ID\r
178 mov rdx, 1 ; CPUID function 1\r
179 mov rax, 040000000h ; RBX register requested\r
180 or rax, 4\r
181 wrmsr\r
182 rep vmmcall\r
183 rdmsr\r
184 shr edx, 24\r
185\r
186RestoreGhcb:\r
187 mov rbx, rdx ; Save x2APIC/APIC ID\r
188\r
189 mov rdx, rdi ; RDI holds the saved GHCB GPA\r
190 shr rdx, 32\r
191 mov eax, edi\r
192 wrmsr\r
193\r
194 mov rdx, rbx\r
195\r
196 ; x2APIC ID or APIC ID is in EDX\r
197 jmp GetProcessorNumber\r
198\r
199SevEsGetApicIdExit:\r
200 OneTimeCallRet SevEsGetApicId\r
b4d7b9d2
RN
201\r
202\r
203;-------------------------------------------------------------------------------------\r
204;SwitchToRealProc procedure follows.\r
205;ALSO THIS PROCEDURE IS EXECUTED BY APs TRANSITIONING TO 16 BIT MODE. HENCE THIS PROC\r
206;IS IN MACHINE CODE.\r
207; SwitchToRealProc (UINTN BufferStart, UINT16 Code16, UINT16 Code32, UINTN StackStart)\r
208; rcx - Buffer Start\r
209; rdx - Code16 Selector Offset\r
210; r8 - Code32 Selector Offset\r
211; r9 - Stack Start\r
212;-------------------------------------------------------------------------------------\r
213SwitchToRealProcStart:\r
214BITS 64\r
215 cli\r
216\r
217 ;\r
218 ; Get RDX reset value before changing stacks since the\r
219 ; new stack won't be able to accomodate a #VC exception.\r
220 ;\r
221 push rax\r
222 push rbx\r
223 push rcx\r
224 push rdx\r
225\r
226 mov rax, 1\r
227 cpuid\r
228 mov rsi, rax ; Save off the reset value for RDX\r
229\r
230 pop rdx\r
231 pop rcx\r
232 pop rbx\r
233 pop rax\r
234\r
235 ;\r
236 ; Establish stack below 1MB\r
237 ;\r
238 mov rsp, r9\r
239\r
240 ;\r
241 ; Push ultimate Reset Vector onto the stack\r
242 ;\r
243 mov rax, rcx\r
244 shr rax, 4\r
245 push word 0x0002 ; RFLAGS\r
246 push ax ; CS\r
247 push word 0x0000 ; RIP\r
248 push word 0x0000 ; For alignment, will be discarded\r
249\r
250 ;\r
251 ; Get address of "16-bit operand size" label\r
252 ;\r
253 lea rbx, [PM16Mode]\r
254\r
255 ;\r
256 ; Push addresses used to change to compatibility mode\r
257 ;\r
258 lea rax, [CompatMode]\r
259 push r8\r
260 push rax\r
261\r
262 ;\r
263 ; Clear R8 - R15, for reset, before going into 32-bit mode\r
264 ;\r
265 xor r8, r8\r
266 xor r9, r9\r
267 xor r10, r10\r
268 xor r11, r11\r
269 xor r12, r12\r
270 xor r13, r13\r
271 xor r14, r14\r
272 xor r15, r15\r
273\r
274 ;\r
275 ; Far return into 32-bit mode\r
276 ;\r
277 retfq\r
278\r
279BITS 32\r
280CompatMode:\r
281 ;\r
282 ; Set up stack to prepare for exiting protected mode\r
283 ;\r
284 push edx ; Code16 CS\r
285 push ebx ; PM16Mode label address\r
286\r
287 ;\r
288 ; Disable paging\r
289 ;\r
290 mov eax, cr0 ; Read CR0\r
291 btr eax, 31 ; Set PG=0\r
292 mov cr0, eax ; Write CR0\r
293\r
294 ;\r
295 ; Disable long mode\r
296 ;\r
297 mov ecx, 0c0000080h ; EFER MSR number\r
298 rdmsr ; Read EFER\r
299 btr eax, 8 ; Set LME=0\r
300 wrmsr ; Write EFER\r
301\r
302 ;\r
303 ; Disable PAE\r
304 ;\r
305 mov eax, cr4 ; Read CR4\r
306 btr eax, 5 ; Set PAE=0\r
307 mov cr4, eax ; Write CR4\r
308\r
309 mov edx, esi ; Restore RDX reset value\r
310\r
311 ;\r
312 ; Switch to 16-bit operand size\r
313 ;\r
314 retf\r
315\r
316BITS 16\r
317 ;\r
318 ; At entry to this label\r
319 ; - RDX will have its reset value\r
320 ; - On the top of the stack\r
321 ; - Alignment data (two bytes) to be discarded\r
322 ; - IP for Real Mode (two bytes)\r
323 ; - CS for Real Mode (two bytes)\r
324 ;\r
325 ; This label is also used with AsmRelocateApLoop. During MP finalization,\r
326 ; the code from PM16Mode to SwitchToRealProcEnd is copied to the start of\r
327 ; the WakeupBuffer, allowing a parked AP to be booted by an OS.\r
328 ;\r
329PM16Mode:\r
330 mov eax, cr0 ; Read CR0\r
331 btr eax, 0 ; Set PE=0\r
332 mov cr0, eax ; Write CR0\r
333\r
334 pop ax ; Discard alignment data\r
335\r
336 ;\r
337 ; Clear registers (except RDX and RSP) before going into 16-bit mode\r
338 ;\r
339 xor eax, eax\r
340 xor ebx, ebx\r
341 xor ecx, ecx\r
342 xor esi, esi\r
343 xor edi, edi\r
344 xor ebp, ebp\r
345\r
346 iret\r
347\r
348SwitchToRealProcEnd:\r