mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 02:24:24 +02:00
KVM: TDX: Handle TDX PV port I/O hypercall
Emulate port I/O requested by TDX guest via TDVMCALL with leaf Instruction.IO (same value as EXIT_REASON_IO_INSTRUCTION) according to TDX Guest Host Communication Interface (GHCI). All port I/O instructions inside the TDX guest trigger the #VE exception. On #VE triggered by I/O instructions, TDX guest can call TDVMCALL with leaf Instruction.IO to request VMM to emulate I/O instructions. Similar to normal port I/O emulation, try to handle the port I/O in kernel first, if kernel can't support it, forward the request to userspace. Note string I/O operations are not supported in TDX. Guest should unroll them before calling the TDVMCALL. Suggested-by: Sean Christopherson <seanjc@google.com> Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com> Co-developed-by: Binbin Wu <binbin.wu@linux.intel.com> Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-ID: <20250222014225.897298-9-binbin.wu@linux.intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
79462faa2b
commit
33608aaf71
|
|
@ -808,6 +808,8 @@ int tdx_vcpu_pre_run(struct kvm_vcpu *vcpu)
|
|||
static __always_inline u32 tdcall_to_vmx_exit_reason(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
switch (tdvmcall_leaf(vcpu)) {
|
||||
case EXIT_REASON_IO_INSTRUCTION:
|
||||
return tdvmcall_leaf(vcpu);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -1130,6 +1132,64 @@ static int tdx_report_fatal_error(struct kvm_vcpu *vcpu)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int tdx_complete_pio_out(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
vcpu->arch.pio.count = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int tdx_complete_pio_in(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct x86_emulate_ctxt *ctxt = vcpu->arch.emulate_ctxt;
|
||||
unsigned long val = 0;
|
||||
int ret;
|
||||
|
||||
ret = ctxt->ops->pio_in_emulated(ctxt, vcpu->arch.pio.size,
|
||||
vcpu->arch.pio.port, &val, 1);
|
||||
|
||||
WARN_ON_ONCE(!ret);
|
||||
|
||||
tdvmcall_set_return_val(vcpu, val);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int tdx_emulate_io(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vcpu_tdx *tdx = to_tdx(vcpu);
|
||||
struct x86_emulate_ctxt *ctxt = vcpu->arch.emulate_ctxt;
|
||||
unsigned long val = 0;
|
||||
unsigned int port;
|
||||
u64 size, write;
|
||||
int ret;
|
||||
|
||||
++vcpu->stat.io_exits;
|
||||
|
||||
size = tdx->vp_enter_args.r12;
|
||||
write = tdx->vp_enter_args.r13;
|
||||
port = tdx->vp_enter_args.r14;
|
||||
|
||||
if ((write != 0 && write != 1) || (size != 1 && size != 2 && size != 4)) {
|
||||
tdvmcall_set_return_code(vcpu, TDVMCALL_STATUS_INVALID_OPERAND);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (write) {
|
||||
val = tdx->vp_enter_args.r15;
|
||||
ret = ctxt->ops->pio_out_emulated(ctxt, size, port, &val, 1);
|
||||
} else {
|
||||
ret = ctxt->ops->pio_in_emulated(ctxt, size, port, &val, 1);
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
vcpu->arch.complete_userspace_io = write ? tdx_complete_pio_out :
|
||||
tdx_complete_pio_in;
|
||||
else if (!write)
|
||||
tdvmcall_set_return_val(vcpu, val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int handle_tdvmcall(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
switch (tdvmcall_leaf(vcpu)) {
|
||||
|
|
@ -1507,6 +1567,8 @@ int tdx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t fastpath)
|
|||
return handle_tdvmcall(vcpu);
|
||||
case EXIT_REASON_VMCALL:
|
||||
return tdx_emulate_vmcall(vcpu);
|
||||
case EXIT_REASON_IO_INSTRUCTION:
|
||||
return tdx_emulate_io(vcpu);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user