mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-01 16:14:13 +08:00
KVM: SVM: Support string IO operations for an SEV-ES guest
For an SEV-ES guest, string-based port IO is performed to a shared (un-encrypted) page so that both the hypervisor and guest can read or write to it and each see the contents. For string-based port IO operations, invoke SEV-ES specific routines that can complete the operation using common KVM port IO support. Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com> Message-Id: <9d61daf0ffda496703717218f415cdc8fd487100.1607620209.git.thomas.lendacky@amd.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
8f423a80d2
commit
7ed9abfe8e
@ -614,6 +614,7 @@ struct kvm_vcpu_arch {
|
|||||||
|
|
||||||
struct kvm_pio_request pio;
|
struct kvm_pio_request pio;
|
||||||
void *pio_data;
|
void *pio_data;
|
||||||
|
void *guest_ins_data;
|
||||||
|
|
||||||
u8 event_exit_inst_len;
|
u8 event_exit_inst_len;
|
||||||
|
|
||||||
|
@ -1406,9 +1406,14 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
|
|||||||
case SVM_EXIT_INVD:
|
case SVM_EXIT_INVD:
|
||||||
break;
|
break;
|
||||||
case SVM_EXIT_IOIO:
|
case SVM_EXIT_IOIO:
|
||||||
|
if (ghcb_get_sw_exit_info_1(ghcb) & SVM_IOIO_STR_MASK) {
|
||||||
|
if (!ghcb_sw_scratch_is_valid(ghcb))
|
||||||
|
goto vmgexit_err;
|
||||||
|
} else {
|
||||||
if (!(ghcb_get_sw_exit_info_1(ghcb) & SVM_IOIO_TYPE_MASK))
|
if (!(ghcb_get_sw_exit_info_1(ghcb) & SVM_IOIO_TYPE_MASK))
|
||||||
if (!ghcb_rax_is_valid(ghcb))
|
if (!ghcb_rax_is_valid(ghcb))
|
||||||
goto vmgexit_err;
|
goto vmgexit_err;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case SVM_EXIT_MSR:
|
case SVM_EXIT_MSR:
|
||||||
if (!ghcb_rcx_is_valid(ghcb))
|
if (!ghcb_rcx_is_valid(ghcb))
|
||||||
@ -1776,3 +1781,12 @@ int sev_handle_vmgexit(struct vcpu_svm *svm)
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sev_es_string_io(struct vcpu_svm *svm, int size, unsigned int port, int in)
|
||||||
|
{
|
||||||
|
if (!setup_vmgexit_scratch(svm, in, svm->vmcb->control.exit_info_2))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return kvm_sev_es_string_io(&svm->vcpu, size, port,
|
||||||
|
svm->ghcb_sa, svm->ghcb_sa_len, in);
|
||||||
|
}
|
||||||
|
@ -2038,11 +2038,16 @@ static int io_interception(struct vcpu_svm *svm)
|
|||||||
++svm->vcpu.stat.io_exits;
|
++svm->vcpu.stat.io_exits;
|
||||||
string = (io_info & SVM_IOIO_STR_MASK) != 0;
|
string = (io_info & SVM_IOIO_STR_MASK) != 0;
|
||||||
in = (io_info & SVM_IOIO_TYPE_MASK) != 0;
|
in = (io_info & SVM_IOIO_TYPE_MASK) != 0;
|
||||||
if (string)
|
|
||||||
return kvm_emulate_instruction(vcpu, 0);
|
|
||||||
|
|
||||||
port = io_info >> 16;
|
port = io_info >> 16;
|
||||||
size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT;
|
size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT;
|
||||||
|
|
||||||
|
if (string) {
|
||||||
|
if (sev_es_guest(vcpu->kvm))
|
||||||
|
return sev_es_string_io(svm, size, port, in);
|
||||||
|
else
|
||||||
|
return kvm_emulate_instruction(vcpu, 0);
|
||||||
|
}
|
||||||
|
|
||||||
svm->next_rip = svm->vmcb->control.exit_info_2;
|
svm->next_rip = svm->vmcb->control.exit_info_2;
|
||||||
|
|
||||||
return kvm_fast_pio(&svm->vcpu, size, port, in);
|
return kvm_fast_pio(&svm->vcpu, size, port, in);
|
||||||
|
@ -573,5 +573,6 @@ void __init sev_hardware_setup(void);
|
|||||||
void sev_hardware_teardown(void);
|
void sev_hardware_teardown(void);
|
||||||
void sev_free_vcpu(struct kvm_vcpu *vcpu);
|
void sev_free_vcpu(struct kvm_vcpu *vcpu);
|
||||||
int sev_handle_vmgexit(struct vcpu_svm *svm);
|
int sev_handle_vmgexit(struct vcpu_svm *svm);
|
||||||
|
int sev_es_string_io(struct vcpu_svm *svm, int size, unsigned int port, int in);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -10783,6 +10783,10 @@ int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu)
|
|||||||
|
|
||||||
unsigned long kvm_get_linear_rip(struct kvm_vcpu *vcpu)
|
unsigned long kvm_get_linear_rip(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
|
/* Can't read the RIP when guest state is protected, just return 0 */
|
||||||
|
if (vcpu->arch.guest_state_protected)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (is_64_bit_mode(vcpu))
|
if (is_64_bit_mode(vcpu))
|
||||||
return kvm_rip_read(vcpu);
|
return kvm_rip_read(vcpu);
|
||||||
return (u32)(get_segment_base(vcpu, VCPU_SREG_CS) +
|
return (u32)(get_segment_base(vcpu, VCPU_SREG_CS) +
|
||||||
@ -11415,6 +11419,56 @@ int kvm_sev_es_mmio_read(struct kvm_vcpu *vcpu, gpa_t gpa, unsigned int bytes,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(kvm_sev_es_mmio_read);
|
EXPORT_SYMBOL_GPL(kvm_sev_es_mmio_read);
|
||||||
|
|
||||||
|
static int complete_sev_es_emulated_ins(struct kvm_vcpu *vcpu)
|
||||||
|
{
|
||||||
|
memcpy(vcpu->arch.guest_ins_data, vcpu->arch.pio_data,
|
||||||
|
vcpu->arch.pio.count * vcpu->arch.pio.size);
|
||||||
|
vcpu->arch.pio.count = 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kvm_sev_es_outs(struct kvm_vcpu *vcpu, unsigned int size,
|
||||||
|
unsigned int port, void *data, unsigned int count)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = emulator_pio_out_emulated(vcpu->arch.emulate_ctxt, size, port,
|
||||||
|
data, count);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
vcpu->arch.pio.count = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kvm_sev_es_ins(struct kvm_vcpu *vcpu, unsigned int size,
|
||||||
|
unsigned int port, void *data, unsigned int count)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = emulator_pio_in_emulated(vcpu->arch.emulate_ctxt, size, port,
|
||||||
|
data, count);
|
||||||
|
if (ret) {
|
||||||
|
vcpu->arch.pio.count = 0;
|
||||||
|
} else {
|
||||||
|
vcpu->arch.guest_ins_data = data;
|
||||||
|
vcpu->arch.complete_userspace_io = complete_sev_es_emulated_ins;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int kvm_sev_es_string_io(struct kvm_vcpu *vcpu, unsigned int size,
|
||||||
|
unsigned int port, void *data, unsigned int count,
|
||||||
|
int in)
|
||||||
|
{
|
||||||
|
return in ? kvm_sev_es_ins(vcpu, size, port, data, count)
|
||||||
|
: kvm_sev_es_outs(vcpu, size, port, data, count);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(kvm_sev_es_string_io);
|
||||||
|
|
||||||
EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_exit);
|
EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_exit);
|
||||||
EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_fast_mmio);
|
EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_fast_mmio);
|
||||||
EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_inj_virq);
|
EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_inj_virq);
|
||||||
|
@ -431,5 +431,8 @@ int kvm_sev_es_mmio_write(struct kvm_vcpu *vcpu, gpa_t src, unsigned int bytes,
|
|||||||
void *dst);
|
void *dst);
|
||||||
int kvm_sev_es_mmio_read(struct kvm_vcpu *vcpu, gpa_t src, unsigned int bytes,
|
int kvm_sev_es_mmio_read(struct kvm_vcpu *vcpu, gpa_t src, unsigned int bytes,
|
||||||
void *dst);
|
void *dst);
|
||||||
|
int kvm_sev_es_string_io(struct kvm_vcpu *vcpu, unsigned int size,
|
||||||
|
unsigned int port, void *data, unsigned int count,
|
||||||
|
int in);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user