diff --git a/hypervisor/arch/x86/guest/vlapic.c b/hypervisor/arch/x86/guest/vlapic.c index d1b2a54df..b9f0c93b9 100644 --- a/hypervisor/arch/x86/guest/vlapic.c +++ b/hypervisor/arch/x86/guest/vlapic.c @@ -1996,18 +1996,34 @@ static inline bool is_x2apic_enabled(const struct acrn_vlapic *vlapic) } } -static int vlapic_x2apic_access(struct vcpu *vcpu) +static inline uint32_t x2apic_msr_to_regoff(uint32_t msr) +{ + + return (((msr - 0x800U) & 0x3FFU) << 4U); +} + +static int vlapic_x2apic_access(struct vcpu *vcpu, uint32_t msr, bool write, uint64_t *val) { struct acrn_vlapic *vlapic; - int error = 0; + uint32_t offset; + int error = -1; + /* + * If vLAPIC is in xAPIC mode and guest tries to access x2APIC MSRs + * inject a GP to guest + */ vlapic = vcpu_vlapic(vcpu); - if (is_x2apic_enabled(vlapic) == false) { - /* - * If vLAPIC is in xAPIC mode and guest tries to access x2APIC MSRs - * inject a GP to guest - */ - error = -1; + if (is_x2apic_enabled(vlapic)) { + offset = x2apic_msr_to_regoff(msr); + if (write) { + if (!is_x2apic_read_only_msr(msr)) { + error = vlapic_write(vlapic, offset, *val); + } + } else { + if (!is_x2apic_write_only_msr(msr)) { + error = vlapic_read(vlapic, offset, val); + } + } } return error; @@ -2033,7 +2049,7 @@ vlapic_rdmsr(struct vcpu *vcpu, uint32_t msr, uint64_t *rval) default: if (is_x2apic_msr(msr)) { - error = vlapic_x2apic_access(vcpu); + error = vlapic_x2apic_access(vcpu, msr, false, rval); } else { error = -1; dev_dbg(ACRN_DBG_LAPIC, @@ -2064,7 +2080,7 @@ vlapic_wrmsr(struct vcpu *vcpu, uint32_t msr, uint64_t wval) default: if (is_x2apic_msr(msr)) { - error = vlapic_x2apic_access(vcpu); + error = vlapic_x2apic_access(vcpu, msr, true, &wval); } else { error = -1; dev_dbg(ACRN_DBG_LAPIC, diff --git a/hypervisor/include/arch/x86/msr.h b/hypervisor/include/arch/x86/msr.h index eeefeaae8..13cfbc120 100644 --- a/hypervisor/include/arch/x86/msr.h +++ b/hypervisor/include/arch/x86/msr.h @@ -541,6 +541,31 @@ static inline bool is_x2apic_msr(uint32_t msr) } return ret; } + +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; +} #endif /* ASSEMBLER */ /* 5 high-order bits in every field are reserved */