From 0e046c7a0a210c88e7897ecd77a38b817e259d5c Mon Sep 17 00:00:00 2001 From: "Li, Fei1" Date: Fri, 14 Jun 2019 23:13:55 +0800 Subject: [PATCH] hv: vlapic: clear which access type we support for APIC-Access VM Exit The current implement doesn't clear which access type we support for APIC-Access VM Exit: 1) linear access for an instruction fetch -- APIC-access page is mapped as UC which doesn't support fetch 2) linear access (read or write) during event delivery -- Which is not happened in normal case except the guest went wrong, such as, set the IDT table in APIC-access page. In this case, we don't need to support. 3) guest-physical access during event delivery; guest-physical access for an instruction fetch or during instruction execution -- Do we plan to support enable APIC in real mode ? I don't think so. Tracked-On: #1842 Signed-off-by: Li, Fei1 Acked-by: Anthony Xu --- hypervisor/arch/x86/guest/vlapic.c | 51 ++++++++++++++---------- hypervisor/include/arch/x86/guest/vmcs.h | 11 +++-- 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/hypervisor/arch/x86/guest/vlapic.c b/hypervisor/arch/x86/guest/vlapic.c index f61e3b48f..4173b66f5 100644 --- a/hypervisor/arch/x86/guest/vlapic.c +++ b/hypervisor/arch/x86/guest/vlapic.c @@ -2397,45 +2397,54 @@ static bool apicv_advanced_apic_write_access_may_valid(uint32_t offset) int32_t apic_access_vmexit_handler(struct acrn_vcpu *vcpu) { - int32_t err = 0; - uint32_t offset = 0U; + int32_t err; + uint32_t offset; uint64_t qual, access_type; struct acrn_vlapic *vlapic; - struct mmio_request *mmio = &vcpu->req.reqs.mmio; + struct mmio_request *mmio; qual = vcpu->arch.exit_qualification; access_type = apic_access_type(qual); - /*parse offset if linear access*/ - if (access_type <= 3UL) { - offset = (uint32_t)apic_access_offset(qual); - } - - vlapic = vcpu_vlapic(vcpu); - - err = decode_instruction(vcpu); - /* apic access should already fetched instruction, decode_instruction - * will not trigger #PF, so if it failed, just return error_no + /* + * We only support linear access for a data read/write during instruction execution. + * for other access types: + * a) we don't support vLAPIC work in real mode; + * 10 = guest-physical access during event delivery + * 15 = guest-physical access for an instruction fetch or during instruction execution + * b) we don't support fetch from APIC-access page since its memory type is UC; + * 2 = linear access for an instruction fetch + * c) we suppose the guest goes wrong when it will access the APIC-access page + * when process event-delivery. According chap 26.5.1.2 VM Exits During Event Injection, + * vol 3, sdm: If the “virtualize APIC accesses” VM-execution control is 1 and + * event delivery generates an access to the APIC-access page, that access is treated as + * described in Section 29.4 and may cause a VM exit. + * 3 = linear access (read or write) during event delivery */ - if (err >= 0) { - if (access_type == 1UL) { - if (emulate_instruction(vcpu) == 0) { + if (((access_type == TYPE_LINEAR_APIC_INST_READ) || (access_type == TYPE_LINEAR_APIC_INST_WRITE)) && + (decode_instruction(vcpu) >= 0)) { + vlapic = vcpu_vlapic(vcpu); + offset = (uint32_t)apic_access_offset(qual); + mmio = &vcpu->req.reqs.mmio; + if (access_type == TYPE_LINEAR_APIC_INST_WRITE) { + err = emulate_instruction(vcpu); + if (err == 0) { if (apicv_ops->apic_write_access_may_valid(offset)) { (void)vlapic_write(vlapic, offset, mmio->value); } } - } else if (access_type == 0UL) { + } else { if (apicv_ops->apic_read_access_may_valid(offset)) { (void)vlapic_read(vlapic, offset, &mmio->value); } else { - mmio->value = 0ULL; + mmio->value = 0UL; } err = emulate_instruction(vcpu); - } else { - pr_err("Unhandled APIC access type: %lu\n", access_type); - err = -EINVAL; } TRACE_2L(TRACE_VMEXIT_APICV_ACCESS, qual, (uint64_t)vlapic); + } else { + pr_err("%s, unhandled access type: %lu\n", __func__, access_type); + err = -EINVAL; } return err; diff --git a/hypervisor/include/arch/x86/guest/vmcs.h b/hypervisor/include/arch/x86/guest/vmcs.h index fcc9b0e75..354d2f6e0 100644 --- a/hypervisor/include/arch/x86/guest/vmcs.h +++ b/hypervisor/include/arch/x86/guest/vmcs.h @@ -15,7 +15,12 @@ #include #include -#define VMX_VMENTRY_FAIL 0x80000000U +#define VMX_VMENTRY_FAIL 0x80000000U + +#define APIC_ACCESS_OFFSET 0xFFFUL /* 11:0, offset within the APIC page */ +#define APIC_ACCESS_TYPE 0xF000UL /* 15:12, access type */ +#define TYPE_LINEAR_APIC_INST_READ (0UL << 12U) +#define TYPE_LINEAR_APIC_INST_WRITE (1UL << 12U) static inline uint32_t vmx_eoi_exit(uint32_t vector) { @@ -34,12 +39,12 @@ static inline uint32_t vmx_eoi_exit(uint32_t vector) */ static inline uint64_t apic_access_type(uint64_t qual) { - return ((qual >> 12U) & 0xFUL); + return (qual & APIC_ACCESS_TYPE); } static inline uint64_t apic_access_offset(uint64_t qual) { - return (qual & 0xFFFUL); + return (qual & APIC_ACCESS_OFFSET); } #define RFLAGS_C (1U<<0U)