Re: [PATCH] KVM: TDX: Allow userspace to return errors to guest for MAPGPA

From: Sagi Shahar

Date: Wed Jan 14 2026 - 20:22:31 EST


On Wed, Jan 14, 2026 at 3:48 PM Sean Christopherson <seanjc@xxxxxxxxxx> wrote:
>
> +Mike
>
> On Wed, Jan 14, 2026, Sean Christopherson wrote:
> > On Wed, Jan 14, 2026, Xiaoyao Li wrote:
> > > On 1/14/2026 8:30 AM, Sagi Shahar wrote:
> > > So it needs to be
> > >
> > > if (vcpu->run->hypercall.ret == -EBUSY)
> > > tdvmcall_set_return_code(vcpu, TDVMCALL_STATUS_RETRY);
> > > else
> > > tdvmcall_set_return_code(vcpu, TDVMCALL_STATUS_INVALID_OPERAND);
> >
> > No, because assuming everything except -EBUSY translates to
> > TDVMCALL_STATUS_INVALID_OPERAND paints KVM back into the same corner its already
> > in. What I care most about is eliminating KVM's assumption that a non-zero
> > hypercall.ret means TDVMCALL_STATUS_INVALID_OPERAND.
> >
> > For the new ABI, I see two options:
> >
> > 1. Translate -errno as done in this patch.
> > 2. Propagate hypercall.ret directly to the TDVMCALL return code, i.e. let
> > userspace set any return code it wants.
> >
> > #1 has the downside of needing KVM changes and new uAPI every time a new return
> > code is supported.
> >
> > #2 has the downside of preventing KVM from establishing its own ABI around the
> > return code, and making the return code vendor specific. E.g. if KVM ever wanted
> > to do something in response to -EBUSY beyond propagating the error to the guest,
> > then we can't reasonably do that with #2.
> >
> > Whatever we do, I want to change snp_complete_psc_msr() and snp_complete_one_psc()
> > in the same patch, so that whatever ABI we establish is common to TDX and SNP.
> >
> > See also https://lore.kernel.org/all/Zn8YM-s0TRUk-6T-@xxxxxxxxxx.
>
> Aha! Finally. I *knew* we had discussed this more recently. The SNP series to
> add KVM_EXIT_SNP_REQ_CERTS uses a similar pattern. Note its intentional use of
> positive values, because that's what userspace sees in errno. This code should
> do the same. Oh, and we need to choose between EAGAIN and EBUSY...
>
> switch (READ_ONCE(vcpu->run->snp_req_certs.ret)) {
> case 0:
> return snp_handle_guest_req(svm, control->exit_info_1,
> control->exit_info_2);
> case ENOSPC:
> vcpu->arch.regs[VCPU_REGS_RBX] = vcpu->run->snp_req_certs.npages;
> return snp_req_certs_err(svm, SNP_GUEST_VMM_ERR_INVALID_LEN);
> case EAGAIN:
> return snp_req_certs_err(svm, SNP_GUEST_VMM_ERR_BUSY);
> case EIO:
> return snp_req_certs_err(svm, SNP_GUEST_VMM_ERR_GENERIC);
> default:
> break;
> }
>

I think EAGAIN makes more sense semantically in this case. So
something like this?

- tdvmcall_set_return_code(vcpu, TDVMCALL_STATUS_INVALID_OPERAND);
+ if (vcpu->run->hypercall.ret == EAGAIN)
+ tdvmcall_set_return_code(vcpu, TDVMCALL_STATUS_RETRY);
+ else if (vcpu->run->hypercall.ret == EINVAL)
+ tdvmcall_set_return_code(vcpu,
TDVMCALL_STATUS_INVALID_OPERAND);
+ else
+ return -EINVAL;
+

>
> https://lore.kernel.org/all/20260109231732.1160759-2-michael.roth@xxxxxxx