]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/X64/AmdSev.nasm
b2d95adf6ddb9f9a0fa2a5fae662d056df54f162
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / X64 / AmdSev.nasm
1 ;------------------------------------------------------------------------------ ;
2 ; Copyright (c) 2021, AMD Inc. All rights reserved.<BR>
3 ; SPDX-License-Identifier: BSD-2-Clause-Patent
4 ;
5 ; Module Name:
6 ;
7 ; AmdSev.nasm
8 ;
9 ; Abstract:
10 ;
11 ; This provides helper used by the MpFunc.nasm. If AMD SEV-ES is active
12 ; then helpers perform the additional setups (such as GHCB).
13 ;
14 ;-------------------------------------------------------------------------------
15
16 %define SIZE_4KB 0x1000
17
18 RegisterGhcbGpa:
19 ;
20 ; Register GHCB GPA when SEV-SNP is enabled
21 ;
22 lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevSnpIsEnabled)]
23 cmp byte [edi], 1 ; SevSnpIsEnabled
24 jne RegisterGhcbGpaDone
25
26 ; Save the rdi and rsi to used for later comparison
27 push rdi
28 push rsi
29 mov edi, eax
30 mov esi, edx
31 or eax, 18 ; Ghcb registration request
32 wrmsr
33 rep vmmcall
34 rdmsr
35 mov r12, rax
36 and r12, 0fffh
37 cmp r12, 19 ; Ghcb registration response
38 jne GhcbGpaRegisterFailure
39
40 ; Verify that GPA is not changed
41 and eax, 0fffff000h
42 cmp edi, eax
43 jne GhcbGpaRegisterFailure
44 cmp esi, edx
45 jne GhcbGpaRegisterFailure
46 pop rsi
47 pop rdi
48 jmp RegisterGhcbGpaDone
49
50 ;
51 ; Request the guest termination
52 ;
53 GhcbGpaRegisterFailure:
54 xor edx, edx
55 mov eax, 256 ; GHCB terminate
56 wrmsr
57 rep vmmcall
58
59 ; We should not return from the above terminate request, but if we do
60 ; then enter into the hlt loop.
61 DoHltLoop:
62 cli
63 hlt
64 jmp DoHltLoop
65
66 RegisterGhcbGpaDone:
67 OneTimeCallRet RegisterGhcbGpa
68
69 ;
70 ; The function checks whether SEV-ES is enabled, if enabled
71 ; then setup the GHCB page.
72 ;
73 SevEsSetupGhcb:
74 lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevEsIsEnabled)]
75 cmp byte [edi], 1 ; SevEsIsEnabled
76 jne SevEsSetupGhcbExit
77
78 ;
79 ; program GHCB
80 ; Each page after the GHCB is a per-CPU page, so the calculation programs
81 ; a GHCB to be every 8KB.
82 ;
83 mov eax, SIZE_4KB
84 shl eax, 1 ; EAX = SIZE_4K * 2
85 mov ecx, ebx
86 mul ecx ; EAX = SIZE_4K * 2 * CpuNumber
87 mov edi, esi
88 add edi, MP_CPU_EXCHANGE_INFO_FIELD (GhcbBase)
89 add rax, qword [edi]
90 mov rdx, rax
91 shr rdx, 32
92 mov rcx, 0xc0010130
93
94 OneTimeCall RegisterGhcbGpa
95
96 wrmsr
97
98 SevEsSetupGhcbExit:
99 OneTimeCallRet SevEsSetupGhcb
100
101 ;
102 ; The function checks whether SEV-ES is enabled, if enabled, use
103 ; the GHCB
104 ;
105 SevEsGetApicId:
106 lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevEsIsEnabled)]
107 cmp byte [edi], 1 ; SevEsIsEnabled
108 jne SevEsGetApicIdExit
109
110 ;
111 ; Since we don't have a stack yet, we can't take a #VC
112 ; exception. Use the GHCB protocol to perform the CPUID
113 ; calls.
114 ;
115 mov rcx, 0xc0010130
116 rdmsr
117 shl rdx, 32
118 or rax, rdx
119 mov rdi, rax ; RDI now holds the original GHCB GPA
120
121 ;
122 ; For SEV-SNP, the recommended handling for getting the x2APIC ID
123 ; would be to use the SNP CPUID table to fetch CPUID.00H:EAX and
124 ; CPUID:0BH:EBX[15:0] instead of the GHCB MSR protocol vmgexits
125 ; below.
126 ;
127 ; To avoid the unecessary ugliness to accomplish that here, the BSP
128 ; has performed these checks in advance (where #VC handler handles
129 ; the CPUID table lookups automatically) and cached them in a flag
130 ; so those checks can be skipped here.
131 ;
132 mov eax, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevSnpIsEnabled)]
133 cmp al, 1
134 jne CheckExtTopoAvail
135
136 ;
137 ; Even with SEV-SNP, the actual x2APIC ID in CPUID.0BH:EDX
138 ; fetched from the hypervisor the same way SEV-ES does it.
139 ;
140 mov eax, [esi + MP_CPU_EXCHANGE_INFO_FIELD (ExtTopoAvail)]
141 cmp al, 1
142 je GetApicIdSevEs
143 ; The 8-bit APIC ID fallback is also the same as with SEV-ES
144 jmp NoX2ApicSevEs
145
146 CheckExtTopoAvail:
147 mov rdx, 0 ; CPUID function 0
148 mov rax, 0 ; RAX register requested
149 or rax, 4
150 wrmsr
151 rep vmmcall
152 rdmsr
153 cmp edx, 0bh
154 jb NoX2ApicSevEs ; CPUID level below CPUID_EXTENDED_TOPOLOGY
155
156 mov rdx, 0bh ; CPUID function 0x0b
157 mov rax, 040000000h ; RBX register requested
158 or rax, 4
159 wrmsr
160 rep vmmcall
161 rdmsr
162 test edx, 0ffffh
163 jz NoX2ApicSevEs ; CPUID.0BH:EBX[15:0] is zero
164
165 GetApicIdSevEs:
166 mov rdx, 0bh ; CPUID function 0x0b
167 mov rax, 0c0000000h ; RDX register requested
168 or rax, 4
169 wrmsr
170 rep vmmcall
171 rdmsr
172
173 ; Processor is x2APIC capable; 32-bit x2APIC ID is now in EDX
174 jmp RestoreGhcb
175
176 NoX2ApicSevEs:
177 ; Processor is not x2APIC capable, so get 8-bit APIC ID
178 mov rdx, 1 ; CPUID function 1
179 mov rax, 040000000h ; RBX register requested
180 or rax, 4
181 wrmsr
182 rep vmmcall
183 rdmsr
184 shr edx, 24
185
186 RestoreGhcb:
187 mov rbx, rdx ; Save x2APIC/APIC ID
188
189 mov rdx, rdi ; RDI holds the saved GHCB GPA
190 shr rdx, 32
191 mov eax, edi
192 wrmsr
193
194 mov rdx, rbx
195
196 ; x2APIC ID or APIC ID is in EDX
197 jmp GetProcessorNumber
198
199 SevEsGetApicIdExit:
200 OneTimeCallRet SevEsGetApicId
201
202
203 ;-------------------------------------------------------------------------------------
204 ;SwitchToRealProc procedure follows.
205 ;ALSO THIS PROCEDURE IS EXECUTED BY APs TRANSITIONING TO 16 BIT MODE. HENCE THIS PROC
206 ;IS IN MACHINE CODE.
207 ; SwitchToRealProc (UINTN BufferStart, UINT16 Code16, UINT16 Code32, UINTN StackStart)
208 ; rcx - Buffer Start
209 ; rdx - Code16 Selector Offset
210 ; r8 - Code32 Selector Offset
211 ; r9 - Stack Start
212 ;-------------------------------------------------------------------------------------
213 SwitchToRealProcStart:
214 BITS 64
215 cli
216
217 ;
218 ; Get RDX reset value before changing stacks since the
219 ; new stack won't be able to accomodate a #VC exception.
220 ;
221 push rax
222 push rbx
223 push rcx
224 push rdx
225
226 mov rax, 1
227 cpuid
228 mov rsi, rax ; Save off the reset value for RDX
229
230 pop rdx
231 pop rcx
232 pop rbx
233 pop rax
234
235 ;
236 ; Establish stack below 1MB
237 ;
238 mov rsp, r9
239
240 ;
241 ; Push ultimate Reset Vector onto the stack
242 ;
243 mov rax, rcx
244 shr rax, 4
245 push word 0x0002 ; RFLAGS
246 push ax ; CS
247 push word 0x0000 ; RIP
248 push word 0x0000 ; For alignment, will be discarded
249
250 ;
251 ; Get address of "16-bit operand size" label
252 ;
253 lea rbx, [PM16Mode]
254
255 ;
256 ; Push addresses used to change to compatibility mode
257 ;
258 lea rax, [CompatMode]
259 push r8
260 push rax
261
262 ;
263 ; Clear R8 - R15, for reset, before going into 32-bit mode
264 ;
265 xor r8, r8
266 xor r9, r9
267 xor r10, r10
268 xor r11, r11
269 xor r12, r12
270 xor r13, r13
271 xor r14, r14
272 xor r15, r15
273
274 ;
275 ; Far return into 32-bit mode
276 ;
277 retfq
278
279 BITS 32
280 CompatMode:
281 ;
282 ; Set up stack to prepare for exiting protected mode
283 ;
284 push edx ; Code16 CS
285 push ebx ; PM16Mode label address
286
287 ;
288 ; Disable paging
289 ;
290 mov eax, cr0 ; Read CR0
291 btr eax, 31 ; Set PG=0
292 mov cr0, eax ; Write CR0
293
294 ;
295 ; Disable long mode
296 ;
297 mov ecx, 0c0000080h ; EFER MSR number
298 rdmsr ; Read EFER
299 btr eax, 8 ; Set LME=0
300 wrmsr ; Write EFER
301
302 ;
303 ; Disable PAE
304 ;
305 mov eax, cr4 ; Read CR4
306 btr eax, 5 ; Set PAE=0
307 mov cr4, eax ; Write CR4
308
309 mov edx, esi ; Restore RDX reset value
310
311 ;
312 ; Switch to 16-bit operand size
313 ;
314 retf
315
316 BITS 16
317 ;
318 ; At entry to this label
319 ; - RDX will have its reset value
320 ; - On the top of the stack
321 ; - Alignment data (two bytes) to be discarded
322 ; - IP for Real Mode (two bytes)
323 ; - CS for Real Mode (two bytes)
324 ;
325 ; This label is also used with AsmRelocateApLoop. During MP finalization,
326 ; the code from PM16Mode to SwitchToRealProcEnd is copied to the start of
327 ; the WakeupBuffer, allowing a parked AP to be booted by an OS.
328 ;
329 PM16Mode:
330 mov eax, cr0 ; Read CR0
331 btr eax, 0 ; Set PE=0
332 mov cr0, eax ; Write CR0
333
334 pop ax ; Discard alignment data
335
336 ;
337 ; Clear registers (except RDX and RSP) before going into 16-bit mode
338 ;
339 xor eax, eax
340 xor ebx, ebx
341 xor ecx, ecx
342 xor esi, esi
343 xor edi, edi
344 xor ebp, ebp
345
346 iret
347
348 SwitchToRealProcEnd:
349 ;-------------------------------------------------------------------------------------
350 ; AsmRelocateApLoopAmd (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish, Pm16CodeSegment, SevEsAPJumpTable, WakeupBuffer);
351 ;-------------------------------------------------------------------------------------
352
353 AsmRelocateApLoopStartAmd:
354 BITS 64
355 cmp qword [rsp + 56], 0 ; SevEsAPJumpTable
356 je NoSevEsAmd
357
358 ;
359 ; Perform some SEV-ES related setup before leaving 64-bit mode
360 ;
361 push rcx
362 push rdx
363
364 ;
365 ; Get the RDX reset value using CPUID
366 ;
367 mov rax, 1
368 cpuid
369 mov rsi, rax ; Save off the reset value for RDX
370
371 ;
372 ; Prepare the GHCB for the AP_HLT_LOOP VMGEXIT call
373 ; - Must be done while in 64-bit long mode so that writes to
374 ; the GHCB memory will be unencrypted.
375 ; - No NAE events can be generated once this is set otherwise
376 ; the AP_RESET_HOLD SW_EXITCODE will be overwritten.
377 ;
378 mov rcx, 0xc0010130
379 rdmsr ; Retrieve current GHCB address
380 shl rdx, 32
381 or rdx, rax
382
383 mov rdi, rdx
384 xor rax, rax
385 mov rcx, 0x800
386 shr rcx, 3
387 rep stosq ; Clear the GHCB
388
389 mov rax, 0x80000004 ; VMGEXIT AP_RESET_HOLD
390 mov [rdx + 0x390], rax
391 mov rax, 114 ; Set SwExitCode valid bit
392 bts [rdx + 0x3f0], rax
393 inc rax ; Set SwExitInfo1 valid bit
394 bts [rdx + 0x3f0], rax
395 inc rax ; Set SwExitInfo2 valid bit
396 bts [rdx + 0x3f0], rax
397
398 pop rdx
399 pop rcx
400
401 NoSevEsAmd:
402 cli ; Disable interrupt before switching to 32-bit mode
403 mov rax, [rsp + 40] ; CountTofinish
404 lock dec dword [rax] ; (*CountTofinish)--
405
406 mov r10, [rsp + 48] ; Pm16CodeSegment
407 mov rax, [rsp + 56] ; SevEsAPJumpTable
408 mov rbx, [rsp + 64] ; WakeupBuffer
409 mov rsp, r9 ; TopOfApStack
410
411 push rax ; Save SevEsAPJumpTable
412 push rbx ; Save WakeupBuffer
413 push r10 ; Save Pm16CodeSegment
414 push rcx ; Save MwaitSupport
415 push rdx ; Save ApTargetCState
416
417 lea rax, [PmEntryAmd] ; rax <- The start address of transition code
418
419 push r8
420 push rax
421
422 ;
423 ; Clear R8 - R15, for reset, before going into 32-bit mode
424 ;
425 xor r8, r8
426 xor r9, r9
427 xor r10, r10
428 xor r11, r11
429 xor r12, r12
430 xor r13, r13
431 xor r14, r14
432 xor r15, r15
433
434 ;
435 ; Far return into 32-bit mode
436 ;
437 o64 retf
438
439 BITS 32
440 PmEntryAmd:
441 mov eax, cr0
442 btr eax, 31 ; Clear CR0.PG
443 mov cr0, eax ; Disable paging and caches
444
445 mov ecx, 0xc0000080
446 rdmsr
447 and ah, ~ 1 ; Clear LME
448 wrmsr
449 mov eax, cr4
450 and al, ~ (1 << 5) ; Clear PAE
451 mov cr4, eax
452
453 pop edx
454 add esp, 4
455 pop ecx,
456 add esp, 4
457
458 MwaitCheckAmd:
459 cmp cl, 1 ; Check mwait-monitor support
460 jnz HltLoopAmd
461 mov ebx, edx ; Save C-State to ebx
462 MwaitLoopAmd:
463 cli
464 mov eax, esp ; Set Monitor Address
465 xor ecx, ecx ; ecx = 0
466 xor edx, edx ; edx = 0
467 monitor
468 mov eax, ebx ; Mwait Cx, Target C-State per eax[7:4]
469 shl eax, 4
470 mwait
471 jmp MwaitLoopAmd
472
473 HltLoopAmd:
474 pop edx ; PM16CodeSegment
475 add esp, 4
476 pop ebx ; WakeupBuffer
477 add esp, 4
478 pop eax ; SevEsAPJumpTable
479 add esp, 4
480 cmp eax, 0 ; Check for SEV-ES
481 je DoHltAmd
482
483 cli
484 ;
485 ; SEV-ES is enabled, use VMGEXIT (GHCB information already
486 ; set by caller)
487 ;
488 BITS 64
489 rep vmmcall
490 BITS 32
491
492 ;
493 ; Back from VMGEXIT AP_HLT_LOOP
494 ; Push the FLAGS/CS/IP values to use
495 ;
496 push word 0x0002 ; EFLAGS
497 xor ecx, ecx
498 mov cx, [eax + 2] ; CS
499 push cx
500 mov cx, [eax] ; IP
501 push cx
502 push word 0x0000 ; For alignment, will be discarded
503
504 push edx
505 push ebx
506
507 mov edx, esi ; Restore RDX reset value
508
509 retf
510
511 DoHltAmd:
512 cli
513 hlt
514 jmp DoHltAmd
515
516 BITS 64
517 AsmRelocateApLoopEndAmd: