BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3275 An SEV-SNP guest requires that the physical address of the GHCB must be registered with the hypervisor before using it. See the GHCB specification section 2.3.2 for more details. Cc: Michael Roth <michael.roth@amd.com> Cc: Eric Dong <eric.dong@intel.com> Cc: Ray Ni <ray.ni@intel.com> Cc: Rahul Kumar <rahul1.kumar@intel.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Min Xu <min.m.xu@intel.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Jordan Justen <jordan.l.justen@intel.com> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org> Cc: Erdem Aktas <erdemaktas@google.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Acked-by: Gerd Hoffmann <kraxel@redhat.com> Acked-by: Ray Ni <ray.ni@Intel.com> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
174 lines
4.8 KiB
NASM
174 lines
4.8 KiB
NASM
;------------------------------------------------------------------------------ ;
|
|
; Copyright (c) 2021, AMD Inc. All rights reserved.<BR>
|
|
; SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
;
|
|
; Module Name:
|
|
;
|
|
; AmdSev.nasm
|
|
;
|
|
; Abstract:
|
|
;
|
|
; This provides helper used by the MpFunc.nasm. If AMD SEV-ES is active
|
|
; then helpers perform the additional setups (such as GHCB).
|
|
;
|
|
;-------------------------------------------------------------------------------
|
|
|
|
%define SIZE_4KB 0x1000
|
|
|
|
RegisterGhcbGpa:
|
|
;
|
|
; Register GHCB GPA when SEV-SNP is enabled
|
|
;
|
|
lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevSnpIsEnabled)]
|
|
cmp byte [edi], 1 ; SevSnpIsEnabled
|
|
jne RegisterGhcbGpaDone
|
|
|
|
; Save the rdi and rsi to used for later comparison
|
|
push rdi
|
|
push rsi
|
|
mov edi, eax
|
|
mov esi, edx
|
|
or eax, 18 ; Ghcb registration request
|
|
wrmsr
|
|
rep vmmcall
|
|
rdmsr
|
|
mov r12, rax
|
|
and r12, 0fffh
|
|
cmp r12, 19 ; Ghcb registration response
|
|
jne GhcbGpaRegisterFailure
|
|
|
|
; Verify that GPA is not changed
|
|
and eax, 0fffff000h
|
|
cmp edi, eax
|
|
jne GhcbGpaRegisterFailure
|
|
cmp esi, edx
|
|
jne GhcbGpaRegisterFailure
|
|
pop rsi
|
|
pop rdi
|
|
jmp RegisterGhcbGpaDone
|
|
|
|
;
|
|
; Request the guest termination
|
|
;
|
|
GhcbGpaRegisterFailure:
|
|
xor edx, edx
|
|
mov eax, 256 ; GHCB terminate
|
|
wrmsr
|
|
rep vmmcall
|
|
|
|
; We should not return from the above terminate request, but if we do
|
|
; then enter into the hlt loop.
|
|
DoHltLoop:
|
|
cli
|
|
hlt
|
|
jmp DoHltLoop
|
|
|
|
RegisterGhcbGpaDone:
|
|
OneTimeCallRet RegisterGhcbGpa
|
|
|
|
;
|
|
; The function checks whether SEV-ES is enabled, if enabled
|
|
; then setup the GHCB page.
|
|
;
|
|
SevEsSetupGhcb:
|
|
lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevEsIsEnabled)]
|
|
cmp byte [edi], 1 ; SevEsIsEnabled
|
|
jne SevEsSetupGhcbExit
|
|
|
|
;
|
|
; program GHCB
|
|
; Each page after the GHCB is a per-CPU page, so the calculation programs
|
|
; a GHCB to be every 8KB.
|
|
;
|
|
mov eax, SIZE_4KB
|
|
shl eax, 1 ; EAX = SIZE_4K * 2
|
|
mov ecx, ebx
|
|
mul ecx ; EAX = SIZE_4K * 2 * CpuNumber
|
|
mov edi, esi
|
|
add edi, MP_CPU_EXCHANGE_INFO_FIELD (GhcbBase)
|
|
add rax, qword [edi]
|
|
mov rdx, rax
|
|
shr rdx, 32
|
|
mov rcx, 0xc0010130
|
|
|
|
OneTimeCall RegisterGhcbGpa
|
|
|
|
wrmsr
|
|
|
|
SevEsSetupGhcbExit:
|
|
OneTimeCallRet SevEsSetupGhcb
|
|
|
|
;
|
|
; The function checks whether SEV-ES is enabled, if enabled, use
|
|
; the GHCB
|
|
;
|
|
SevEsGetApicId:
|
|
lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevEsIsEnabled)]
|
|
cmp byte [edi], 1 ; SevEsIsEnabled
|
|
jne SevEsGetApicIdExit
|
|
|
|
;
|
|
; Since we don't have a stack yet, we can't take a #VC
|
|
; exception. Use the GHCB protocol to perform the CPUID
|
|
; calls.
|
|
;
|
|
mov rcx, 0xc0010130
|
|
rdmsr
|
|
shl rdx, 32
|
|
or rax, rdx
|
|
mov rdi, rax ; RDI now holds the original GHCB GPA
|
|
|
|
mov rdx, 0 ; CPUID function 0
|
|
mov rax, 0 ; RAX register requested
|
|
or rax, 4
|
|
wrmsr
|
|
rep vmmcall
|
|
rdmsr
|
|
cmp edx, 0bh
|
|
jb NoX2ApicSevEs ; CPUID level below CPUID_EXTENDED_TOPOLOGY
|
|
|
|
mov rdx, 0bh ; CPUID function 0x0b
|
|
mov rax, 040000000h ; RBX register requested
|
|
or rax, 4
|
|
wrmsr
|
|
rep vmmcall
|
|
rdmsr
|
|
test edx, 0ffffh
|
|
jz NoX2ApicSevEs ; CPUID.0BH:EBX[15:0] is zero
|
|
|
|
mov rdx, 0bh ; CPUID function 0x0b
|
|
mov rax, 0c0000000h ; RDX register requested
|
|
or rax, 4
|
|
wrmsr
|
|
rep vmmcall
|
|
rdmsr
|
|
|
|
; Processor is x2APIC capable; 32-bit x2APIC ID is now in EDX
|
|
jmp RestoreGhcb
|
|
|
|
NoX2ApicSevEs:
|
|
; Processor is not x2APIC capable, so get 8-bit APIC ID
|
|
mov rdx, 1 ; CPUID function 1
|
|
mov rax, 040000000h ; RBX register requested
|
|
or rax, 4
|
|
wrmsr
|
|
rep vmmcall
|
|
rdmsr
|
|
shr edx, 24
|
|
|
|
RestoreGhcb:
|
|
mov rbx, rdx ; Save x2APIC/APIC ID
|
|
|
|
mov rdx, rdi ; RDI holds the saved GHCB GPA
|
|
shr rdx, 32
|
|
mov eax, edi
|
|
wrmsr
|
|
|
|
mov rdx, rbx
|
|
|
|
; x2APIC ID or APIC ID is in EDX
|
|
jmp GetProcessorNumber
|
|
|
|
SevEsGetApicIdExit:
|
|
OneTimeCallRet SevEsGetApicId
|