@@ -7162,6 +7162,31 @@ The valid value for 'flags' is:
- KVM_NOTIFY_CONTEXT_INVALID -- the VM context is corrupted and not valid
in VMCS. It would run into unknown result if resume the target VM.
+::
+
+ /* KVM_EXIT_TDX_GET_QUOTE */
+ struct tdx_get_quote {
+ __u64 ret;
+ __u64 gpa;
+ __u64 size;
+ };
+
+If the exit reason is KVM_EXIT_TDX_GET_QUOTE, then it indicates that a TDX
+guest has requested to generate a TD-Quote signed by a service hosting
+TD-Quoting Enclave operating on the host. The 'gpa' field and 'size' specify
+the guest physical address and size of a shared-memory buffer, in which the
+TDX guest passes a TD Report. KVM checks the GPA from the TDX guest has the
+shared-bit set and drops the shared-bit in 'gpa' field before exiting to
+userspace. KVM doesn't do other sanity checks. The 'ret' field represents the
+return value of the GetQuote request. KVM only bridges the request to the
+userspace VMM, and the userspace VMM is responsible for setting up the return
+value since only userspace knows whether the request has been queued
+successfully or not. KVM sets the return code according to the 'ret' field
+before returning back to the TDX guest. When the request has been queued
+successfully, the TDX guest can poll the status field in the shared-memory area
+to check whether the Quote generation is completed or not. When completed, the
+generated Quote is returned via the same buffer.
+
::
/* Fix the size of the union. */
@@ -1463,6 +1463,34 @@ static int tdx_get_td_vm_call_info(struct kvm_vcpu *vcpu)
return 1;
}
+static int tdx_complete_get_quote(struct kvm_vcpu *vcpu)
+{
+ tdvmcall_set_return_code(vcpu, vcpu->run->tdx_get_quote.ret);
+ return 1;
+}
+
+static int tdx_get_quote(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_tdx *tdx = to_tdx(vcpu);
+
+ u64 gpa = tdx->vp_enter_args.r12;
+ u64 size = tdx->vp_enter_args.r13;
+
+ /* The gpa of buffer must have shared bit set. */
+ if (vt_is_tdx_private_gpa(vcpu->kvm, gpa)) {
+ tdvmcall_set_return_code(vcpu, TDVMCALL_STATUS_INVALID_OPERAND);
+ return 1;
+ }
+
+ vcpu->run->exit_reason = KVM_EXIT_TDX_GET_QUOTE;
+ vcpu->run->tdx_get_quote.gpa = gpa & ~gfn_to_gpa(kvm_gfn_direct_bits(tdx->vcpu.kvm));
+ vcpu->run->tdx_get_quote.size = size;
+
+ vcpu->arch.complete_userspace_io = tdx_complete_get_quote;
+
+ return 0;
+}
+
static int handle_tdvmcall(struct kvm_vcpu *vcpu)
{
switch (tdvmcall_leaf(vcpu)) {
@@ -1472,6 +1500,8 @@ static int handle_tdvmcall(struct kvm_vcpu *vcpu)
return tdx_report_fatal_error(vcpu);
case TDVMCALL_GET_TD_VM_CALL_INFO:
return tdx_get_td_vm_call_info(vcpu);
+ case TDVMCALL_GET_QUOTE:
+ return tdx_get_quote(vcpu);
default:
break;
}
@@ -178,6 +178,7 @@ struct kvm_xen_exit {
#define KVM_EXIT_NOTIFY 37
#define KVM_EXIT_LOONGARCH_IOCSR 38
#define KVM_EXIT_MEMORY_FAULT 39
+#define KVM_EXIT_TDX_GET_QUOTE 40
/* For KVM_EXIT_INTERNAL_ERROR */
/* Emulate instruction failed. */
@@ -447,6 +448,12 @@ struct kvm_run {
__u64 gpa;
__u64 size;
} memory_fault;
+ /* KVM_EXIT_TDX_GET_QUOTE */
+ struct {
+ __u64 ret;
+ __u64 gpa;
+ __u64 size;
+ } tdx_get_quote;
/* Fix the size of the union. */
char padding[256];
};