audk/MdePkg/Library/BaseLib/X64/TdVmcall.nasm
Ceping Sun 68e37f4578 MdePkg/BaseLib: Update TdVmcall to always output the value in R11
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4572

According to section 3.2 of the [GHCI] spec, if the return status
of MapGPA is "TDG.VP.VMCALL_RETRY", TD must retry this operation
for the pages in the region starting at the GPA specified in R11.

Currently, TDVF has not handled the retry results and always clears
the R11 on unsuccessful return status. For this, the TdVmcall needs
to output the value of R11 on unsuccessful return status to handle
the retry results of MapGPA.

Reference:
[GHCI]: TDX Guest-Host-Communication Interface v1.0
https://cdrdv2.intel.com/v1/dl/getContent/726790

Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Erdem Aktas <erdemaktas@google.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Cc: Min Xu <min.m.xu@intel.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Michael Roth <michael.roth@amd.com>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
Signed-off-by: Ceping Sun <cepingx.sun@intel.com>
2023-11-09 17:15:39 +00:00

144 lines
3.0 KiB
NASM

;------------------------------------------------------------------------------
;*
;* Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
;* SPDX-License-Identifier: BSD-2-Clause-Patent
;*
;*
;------------------------------------------------------------------------------
DEFAULT REL
SECTION .text
%define TDVMCALL_EXPOSE_REGS_MASK 0xffec
%define TDVMCALL 0x0
%macro tdcall 0
db 0x66,0x0f,0x01,0xcc
%endmacro
%macro tdcall_push_regs 0
push rbp
mov rbp, rsp
push r15
push r14
push r13
push r12
push rbx
push rsi
push rdi
%endmacro
%macro tdcall_pop_regs 0
pop rdi
pop rsi
pop rbx
pop r12
pop r13
pop r14
pop r15
pop rbp
%endmacro
%define number_of_regs_pushed 8
%define number_of_parameters 4
;
; Keep these in sync for push_regs/pop_regs, code below
; uses them to find 5th or greater parameters
;
%define first_variable_on_stack_offset \
((number_of_regs_pushed * 8) + (number_of_parameters * 8) + 8)
%define second_variable_on_stack_offset \
((first_variable_on_stack_offset) + 8)
%macro tdcall_regs_preamble 2
mov rax, %1
xor rcx, rcx
mov ecx, %2
; R10 = 0 (standard TDVMCALL)
xor r10d, r10d
; Zero out unused (for standard TDVMCALL) registers to avoid leaking
; secrets to the VMM.
xor ebx, ebx
xor esi, esi
xor edi, edi
xor edx, edx
xor ebp, ebp
xor r8d, r8d
xor r9d, r9d
%endmacro
%macro tdcall_regs_postamble 0
xor ebx, ebx
xor esi, esi
xor edi, edi
xor ecx, ecx
xor edx, edx
xor r8d, r8d
xor r9d, r9d
xor r10d, r10d
xor r11d, r11d
%endmacro
;------------------------------------------------------------------------------
; 0 => RAX = TDCALL leaf
; M => RCX = TDVMCALL register behavior
; 1 => R10 = standard vs. vendor
; RDI => R11 = TDVMCALL function / nr
; RSI = R12 = p1
; RDX => R13 = p2
; RCX => R14 = p3
; R8 => R15 = p4
; UINT64
; EFIAPI
; TdVmCall (
; UINT64 Leaf, // Rcx
; UINT64 P1, // Rdx
; UINT64 P2, // R8
; UINT64 P3, // R9
; UINT64 P4, // rsp + 0x28
; UINT64 *Val // rsp + 0x30
; )
global ASM_PFX(TdVmCall)
ASM_PFX(TdVmCall):
tdcall_push_regs
mov r11, rcx
mov r12, rdx
mov r13, r8
mov r14, r9
mov r15, [rsp + first_variable_on_stack_offset ]
tdcall_regs_preamble TDVMCALL, TDVMCALL_EXPOSE_REGS_MASK
tdcall
; ignore return dataif TDCALL reports failure.
test rax, rax
jnz .no_return_data
; Propagate TDVMCALL success/failure to return value.
mov rax, r10
; Retrieve the Val pointer.
mov r9, [rsp + second_variable_on_stack_offset ]
test r9, r9
jz .no_return_data
; Propagate TDVMCALL output value to output param
mov [r9], r11
.no_return_data:
tdcall_regs_postamble
tdcall_pop_regs
ret