KVM: TDX: Add new TDVMCALL status code for unsupported subfuncs

Add the new TDVMCALL status code TDVMCALL_STATUS_SUBFUNC_UNSUPPORTED and
return it for unimplemented TDVMCALL subfunctions.

Returning TDVMCALL_STATUS_INVALID_OPERAND when a subfunction is not
implemented is vague because TDX guests can't tell the error is due to
the subfunction is not supported or an invalid input of the subfunction.
New GHCI spec adds TDVMCALL_STATUS_SUBFUNC_UNSUPPORTED to avoid the
ambiguity. Use it instead of TDVMCALL_STATUS_INVALID_OPERAND.

Before the change, for common guest implementations, when a TDX guest
receives TDVMCALL_STATUS_INVALID_OPERAND, it has two cases:
1. Some operand is invalid. It could change the operand to another value
retry.
2. The subfunction is not supported.

For case 1, an invalid operand usually means the guest implementation bug.
Since the TDX guest can't tell which case is, the best practice for
handling TDVMCALL_STATUS_INVALID_OPERAND is stopping calling such leaf,
treating the failure as fatal if the TDVMCALL is essential or ignoring
it if the TDVMCALL is optional.

With this change, TDVMCALL_STATUS_SUBFUNC_UNSUPPORTED could be sent to
old TDX guest that do not know about it, but it is expected that the
guest will make the same action as TDVMCALL_STATUS_INVALID_OPERAND.
Currently, no known TDX guest checks TDVMCALL_STATUS_INVALID_OPERAND
specifically; for example Linux just checks for success.

Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
[Return it for untrapped KVM_HC_MAP_GPA_RANGE. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by Binbin Wu and committed by Paolo Bonzini b5aafcb4 2f3fc29a

+7 -4
+1
arch/x86/include/asm/shared/tdx.h
··· 80 80 #define TDVMCALL_STATUS_RETRY 0x0000000000000001ULL 81 81 #define TDVMCALL_STATUS_INVALID_OPERAND 0x8000000000000000ULL 82 82 #define TDVMCALL_STATUS_ALIGN_ERROR 0x8000000000000002ULL 83 + #define TDVMCALL_STATUS_SUBFUNC_UNSUPPORTED 0x8000000000000003ULL 83 84 84 85 /* 85 86 * Bitmasks of exposed registers (with VMM).
+6 -4
arch/x86/kvm/vmx/tdx.c
··· 1212 1212 /* 1213 1213 * Converting TDVMCALL_MAP_GPA to KVM_HC_MAP_GPA_RANGE requires 1214 1214 * userspace to enable KVM_CAP_EXIT_HYPERCALL with KVM_HC_MAP_GPA_RANGE 1215 - * bit set. If not, the error code is not defined in GHCI for TDX, use 1216 - * TDVMCALL_STATUS_INVALID_OPERAND for this case. 1215 + * bit set. This is a base call so it should always be supported, but 1216 + * KVM has no way to ensure that userspace implements the GHCI correctly. 1217 + * So if KVM_HC_MAP_GPA_RANGE does not cause a VMEXIT, return an error 1218 + * to the guest. 1217 1219 */ 1218 1220 if (!user_exit_on_hypercall(vcpu->kvm, KVM_HC_MAP_GPA_RANGE)) { 1219 - ret = TDVMCALL_STATUS_INVALID_OPERAND; 1221 + ret = TDVMCALL_STATUS_SUBFUNC_UNSUPPORTED; 1220 1222 goto error; 1221 1223 } 1222 1224 ··· 1478 1476 break; 1479 1477 } 1480 1478 1481 - tdvmcall_set_return_code(vcpu, TDVMCALL_STATUS_INVALID_OPERAND); 1479 + tdvmcall_set_return_code(vcpu, TDVMCALL_STATUS_SUBFUNC_UNSUPPORTED); 1482 1480 return 1; 1483 1481 } 1484 1482