diff --git a/hypervisor/arch/x86/guest/vlapic.c b/hypervisor/arch/x86/guest/vlapic.c index 1df2d4d93..e2c12c410 100644 --- a/hypervisor/arch/x86/guest/vlapic.c +++ b/hypervisor/arch/x86/guest/vlapic.c @@ -2038,6 +2038,27 @@ vlapic_x2apic_pt_icr_access(struct acrn_vm *vm, uint64_t val) return ret; } +static bool apicv_basic_x2apic_read_msr_may_valid(uint32_t offset) +{ + return (offset != APIC_OFFSET_DFR) && (offset != APIC_OFFSET_ICR_HI); +} + +static bool apicv_advanced_x2apic_read_msr_may_valid(uint32_t offset) +{ + return (offset == APIC_OFFSET_TIMER_CCR); +} + +static bool apicv_basic_x2apic_write_msr_may_valid(uint32_t offset) +{ + return (offset != APIC_OFFSET_DFR) && (offset != APIC_OFFSET_ICR_HI); +} + +static bool apicv_advanced_x2apic_write_msr_may_valid(uint32_t offset) +{ + return (offset != APIC_OFFSET_DFR) && (offset != APIC_OFFSET_ICR_HI) && + (offset != APIC_OFFSET_EOI) && (offset != APIC_OFFSET_SELF_IPI); +} + int32_t vlapic_x2apic_read(struct acrn_vcpu *vcpu, uint32_t msr, uint64_t *val) { struct acrn_vlapic *vlapic; @@ -2062,8 +2083,8 @@ int32_t vlapic_x2apic_read(struct acrn_vcpu *vcpu, uint32_t msr, uint64_t *val) break; } } else { - if (!is_x2apic_write_only_msr(msr)) { - offset = x2apic_msr_to_regoff(msr); + offset = x2apic_msr_to_regoff(msr); + if (apicv_ops->x2apic_read_msr_may_valid(offset)) { error = vlapic_read(vlapic, offset, val); } } @@ -2094,8 +2115,8 @@ int32_t vlapic_x2apic_write(struct acrn_vcpu *vcpu, uint32_t msr, uint64_t val) break; } } else { - if (!is_x2apic_read_only_msr(msr)) { - offset = x2apic_msr_to_regoff(msr); + offset = x2apic_msr_to_regoff(msr); + if (apicv_ops->x2apic_write_msr_may_valid(offset)) { error = vlapic_write(vlapic, offset, val); } } @@ -2315,6 +2336,26 @@ bool vlapic_has_pending_delivery_intr(struct acrn_vcpu *vcpu) return apicv_ops->has_pending_delivery_intr(vcpu); } +static bool apicv_basic_apic_read_access_may_valid(__unused uint32_t offset) +{ + return true; +} + +static bool apicv_advanced_apic_read_access_may_valid(uint32_t offset) +{ + return ((offset == APIC_OFFSET_CMCI_LVT) || (offset == APIC_OFFSET_TIMER_CCR)); +} + +static bool apicv_basic_apic_write_access_may_valid(uint32_t offset) +{ + return (offset != APIC_OFFSET_SELF_IPI); +} + +static bool apicv_advanced_apic_write_access_may_valid(uint32_t offset) +{ + return (offset == APIC_OFFSET_CMCI_LVT); +} + int32_t apic_access_vmexit_handler(struct acrn_vcpu *vcpu) { int32_t err = 0; @@ -2340,10 +2381,16 @@ int32_t apic_access_vmexit_handler(struct acrn_vcpu *vcpu) if (err >= 0) { if (access_type == 1UL) { if (emulate_instruction(vcpu) == 0) { - (void)vlapic_write(vlapic, offset, mmio->value); + if (apicv_ops->apic_write_access_may_valid(offset)) { + (void)vlapic_write(vlapic, offset, mmio->value); + } } } else if (access_type == 0UL) { - (void)vlapic_read(vlapic, offset, &mmio->value); + if (apicv_ops->apic_read_access_may_valid(offset)) { + (void)vlapic_read(vlapic, offset, &mmio->value); + } else { + mmio->value = 0ULL; + } err = emulate_instruction(vcpu); } else { pr_err("Unhandled APIC access type: %lu\n", access_type); @@ -2502,12 +2549,20 @@ static const struct acrn_apicv_ops apicv_basic_ops = { .accept_intr = apicv_basic_accept_intr, .inject_intr = apicv_basic_inject_intr, .has_pending_delivery_intr = apicv_basic_has_pending_delivery_intr, + .apic_read_access_may_valid = apicv_basic_apic_read_access_may_valid, + .apic_write_access_may_valid = apicv_basic_apic_write_access_may_valid, + .x2apic_read_msr_may_valid = apicv_basic_x2apic_read_msr_may_valid, + .x2apic_write_msr_may_valid = apicv_basic_x2apic_write_msr_may_valid, }; static const struct acrn_apicv_ops apicv_advanced_ops = { .accept_intr = apicv_advanced_accept_intr, .inject_intr = apicv_advanced_inject_intr, .has_pending_delivery_intr = apicv_advanced_has_pending_delivery_intr, + .apic_read_access_may_valid = apicv_advanced_apic_read_access_may_valid, + .apic_write_access_may_valid = apicv_advanced_apic_write_access_may_valid, + .x2apic_read_msr_may_valid = apicv_advanced_x2apic_read_msr_may_valid, + .x2apic_write_msr_may_valid = apicv_advanced_x2apic_write_msr_may_valid, }; /* diff --git a/hypervisor/arch/x86/guest/vlapic_priv.h b/hypervisor/arch/x86/guest/vlapic_priv.h index c3bd1708d..ef585b585 100644 --- a/hypervisor/arch/x86/guest/vlapic_priv.h +++ b/hypervisor/arch/x86/guest/vlapic_priv.h @@ -86,6 +86,10 @@ struct acrn_apicv_ops { void (*accept_intr)(struct acrn_vlapic *vlapic, uint32_t vector, bool level); bool (*inject_intr)(struct acrn_vlapic *vlapic, bool guest_irq_enabled, bool injected); bool (*has_pending_delivery_intr)(struct acrn_vcpu *vcpu); + bool (*apic_read_access_may_valid)(uint32_t offset); + bool (*apic_write_access_may_valid)(uint32_t offset); + bool (*x2apic_read_msr_may_valid)(uint32_t offset); + bool (*x2apic_write_msr_may_valid)(uint32_t offset); }; #endif /* VLAPIC_PRIV_H */ diff --git a/hypervisor/include/arch/x86/msr.h b/hypervisor/include/arch/x86/msr.h index 6cbf07d86..d47fcd649 100644 --- a/hypervisor/include/arch/x86/msr.h +++ b/hypervisor/include/arch/x86/msr.h @@ -567,31 +567,6 @@ static inline bool is_x2apic_msr(uint32_t msr) return ((msr >= 0x800U) && (msr < 0x900U)); } -static inline bool is_x2apic_read_only_msr(uint32_t msr) -{ - bool ret = false; - - if ((msr == MSR_IA32_EXT_XAPICID) || - (msr == MSR_IA32_EXT_APIC_VERSION) || - (msr == MSR_IA32_EXT_APIC_PPR) || - (msr == MSR_IA32_EXT_APIC_LDR) || - ((msr >= MSR_IA32_EXT_APIC_ISR0) && - (msr <= MSR_IA32_EXT_APIC_IRR7)) || - (msr == MSR_IA32_EXT_APIC_CUR_COUNT)) { - ret = true; - } - return ret; -} - -static inline bool is_x2apic_write_only_msr(uint32_t msr) -{ - bool ret = false; - if ((msr == MSR_IA32_EXT_APIC_EOI) || (msr == MSR_IA32_EXT_APIC_SELF_IPI)) { - ret = true; - } - return ret; -} - struct acrn_vcpu; void init_msr_emulation(struct acrn_vcpu *vcpu);