From c8dc56e08be84b830ba7ad959b56cdbc3f99c5d6 Mon Sep 17 00:00:00 2001 From: Yonghua Huang Date: Wed, 21 Mar 2018 01:05:50 +0800 Subject: [PATCH] Add APIC ACCESS VMexit handler Update 'apic_access_exit_handler()' function to emulate guest instruments to read/write guest's lapic registers page Signed-off-by: Yonghua Huang --- arch/x86/guest/vlapic.c | 30 ++++++++++++++++++++++++++++-- arch/x86/vmexit.c | 2 +- include/arch/x86/guest/vlapic.h | 2 +- include/arch/x86/vmx.h | 14 ++++++++++++++ 4 files changed, 44 insertions(+), 4 deletions(-) diff --git a/arch/x86/guest/vlapic.c b/arch/x86/guest/vlapic.c index bc6e7498b..7b403669d 100644 --- a/arch/x86/guest/vlapic.c +++ b/arch/x86/guest/vlapic.c @@ -37,6 +37,9 @@ #include #include +#include "instr_emul_wrapper.h" +#include "instr_emul.h" + #include "time.h" #include "vlapic_priv.h" @@ -2331,9 +2334,32 @@ apicv_inject_pir(struct vlapic *vlapic) } } -int apicv_access_exit_handler(__unused struct vcpu *vcpu) +int apic_access_exit_handler(struct vcpu *vcpu) { - TRACE_2L(TRC_VMEXIT_APICV_ACCESS, 0, 0); + bool ret; + int access_type, offset; + uint64_t qual; + struct vlapic *vlapic; + + qual = vcpu->arch_vcpu.exit_qualification; + access_type = APIC_ACCESS_TYPE(qual); + + /*parse offset if linear access*/ + if (access_type <= 3) + offset = APIC_ACCESS_OFFSET(qual); + + vlapic = vcpu->arch_vcpu.vlapic; + + analyze_instruction(vcpu, &vcpu->mmio); + if (access_type == 1) { + if (!emulate_instruction(vcpu, &vcpu->mmio)) + vlapic_write(vlapic, 1, offset, vcpu->mmio.value, &ret); + } else if (access_type == 0) { + vlapic_read(vlapic, 1, offset, &vcpu->mmio.value, &ret); + emulate_instruction(vcpu, &vcpu->mmio); + } + + TRACE_2L(TRC_VMEXIT_APICV_ACCESS, qual, (uint64_t)vlapic); return 0; } diff --git a/arch/x86/vmexit.c b/arch/x86/vmexit.c index 6c3be515b..2464fe9e4 100644 --- a/arch/x86/vmexit.c +++ b/arch/x86/vmexit.c @@ -125,7 +125,7 @@ static const struct vm_exit_dispatch dispatch_table[] = { [VMX_EXIT_REASON_TPR_BELOW_THRESHOLD] = { .handler = unhandled_vmexit_handler}, [VMX_EXIT_REASON_APIC_ACCESS] = { - .handler = apicv_access_exit_handler, + .handler = apic_access_exit_handler, .need_exit_qualification = 1}, [VMX_EXIT_REASON_VIRTUALIZED_EOI] = { .handler = apicv_virtualized_eoi_exit_handler, diff --git a/include/arch/x86/guest/vlapic.h b/include/arch/x86/guest/vlapic.h index 0ef8eb93c..61f9dbb34 100644 --- a/include/arch/x86/guest/vlapic.h +++ b/include/arch/x86/guest/vlapic.h @@ -125,7 +125,7 @@ uint64_t apicv_get_apic_access_addr(struct vm *vm); uint64_t apicv_get_apic_page_addr(struct vlapic *vlapic); bool vlapic_apicv_enabled(struct vcpu *vcpu); void apicv_inject_pir(struct vlapic *vlapic); -int apicv_access_exit_handler(struct vcpu *vcpu); +int apic_access_exit_handler(struct vcpu *vcpu); int apicv_write_exit_handler(struct vcpu *vcpu); int apicv_virtualized_eoi_exit_handler(struct vcpu *vcpu); diff --git a/include/arch/x86/vmx.h b/include/arch/x86/vmx.h index 284f13495..34507d625 100644 --- a/include/arch/x86/vmx.h +++ b/include/arch/x86/vmx.h @@ -351,6 +351,20 @@ #define VMX_INT_TYPE_HW_EXP 3 #define VMX_INT_TYPE_SW_EXP 6 +/*VM exit qulifications for APIC-access + * Access type: + * 0 = linear access for a data read during instruction execution + * 1 = linear access for a data write during instruction execution + * 2 = linear access for an instruction fetch + * 3 = linear access (read or write) during event delivery + * 10 = guest-physical access during event delivery + * 15 = guest-physical access for an instructon fetch or during + * instruction execution + */ +#define APIC_ACCESS_TYPE(qual) (((qual) >> 12) & 0xF) +#define APIC_ACCESS_OFFSET(qual) ((qual) & 0xFFF) + + #define VM_SUCCESS 0 #define VM_FAIL -1