From 64f61961bf3051e6869ff00f9e5b23ad01e5ef4b Mon Sep 17 00:00:00 2001 From: Sainath Grandhi Date: Thu, 1 Nov 2018 13:59:37 -0700 Subject: [PATCH] hv: add missing support to intercept x2APIC MSRs Accessing x2APIC MSRs in xAPIC mode should result in GP exception according to SDM section 10.12.2. Adding support to ACRN to inject GP into guests for the same reason. Tracked-On: #1626 Signed-off-by: Sainath Grandhi Reviewed-by: Xu Anthony --- hypervisor/arch/x86/guest/vlapic.c | 44 +++++++++++-- hypervisor/arch/x86/guest/vmsr.c | 100 +++++++++++++++++++++++++---- hypervisor/include/arch/x86/msr.h | 12 ++++ 3 files changed, 139 insertions(+), 17 deletions(-) diff --git a/hypervisor/arch/x86/guest/vlapic.c b/hypervisor/arch/x86/guest/vlapic.c index 27c88e448..46c140c0d 100644 --- a/hypervisor/arch/x86/guest/vlapic.c +++ b/hypervisor/arch/x86/guest/vlapic.c @@ -1936,6 +1936,32 @@ static void vlapic_timer_expired(void *data) } } +static inline bool is_x2apic_enabled(const struct acrn_vlapic *vlapic) +{ + if ((vlapic_get_apicbase(vlapic) & APICBASE_X2APIC) == 0UL) { + return false; + } else { + return true; + } +} + +static int vlapic_x2apic_access(struct vcpu *vcpu) +{ + struct acrn_vlapic *vlapic; + int error = 0; + + 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; + } + + return error; +} + int vlapic_rdmsr(struct vcpu *vcpu, uint32_t msr, uint64_t *rval) { @@ -1955,8 +1981,13 @@ vlapic_rdmsr(struct vcpu *vcpu, uint32_t msr, uint64_t *rval) break; default: - dev_dbg(ACRN_DBG_LAPIC, - "Invalid vlapic msr 0x%x access\n", msr); + if (is_x2apic_msr(msr)) { + error = vlapic_x2apic_access(vcpu); + } else { + error = -1; + dev_dbg(ACRN_DBG_LAPIC, + "Invalid vlapic msr 0x%x access\n", msr); + } break; } @@ -1981,8 +2012,13 @@ vlapic_wrmsr(struct vcpu *vcpu, uint32_t msr, uint64_t wval) break; default: - dev_dbg(ACRN_DBG_LAPIC, - "Invalid vlapic msr 0x%x access\n", msr); + if (is_x2apic_msr(msr)) { + error = vlapic_x2apic_access(vcpu); + } else { + error = -1; + dev_dbg(ACRN_DBG_LAPIC, + "Invalid vlapic msr 0x%x access\n", msr); + } break; } diff --git a/hypervisor/arch/x86/guest/vmsr.c b/hypervisor/arch/x86/guest/vmsr.c index f68548f21..96847c913 100644 --- a/hypervisor/arch/x86/guest/vmsr.c +++ b/hypervisor/arch/x86/guest/vmsr.c @@ -25,6 +25,53 @@ static const uint32_t emulated_msrs[] = { */ }; +static const uint32_t x2apic_msrs[] = { + MSR_IA32_EXT_XAPICID, + MSR_IA32_EXT_APIC_VERSION, + MSR_IA32_EXT_APIC_TPR, + MSR_IA32_EXT_APIC_PPR, + MSR_IA32_EXT_APIC_EOI, + MSR_IA32_EXT_APIC_LDR, + MSR_IA32_EXT_APIC_SIVR, + MSR_IA32_EXT_APIC_ISR0, + MSR_IA32_EXT_APIC_ISR1, + MSR_IA32_EXT_APIC_ISR2, + MSR_IA32_EXT_APIC_ISR3, + MSR_IA32_EXT_APIC_ISR4, + MSR_IA32_EXT_APIC_ISR5, + MSR_IA32_EXT_APIC_ISR6, + MSR_IA32_EXT_APIC_ISR7, + MSR_IA32_EXT_APIC_TMR0, + MSR_IA32_EXT_APIC_TMR1, + MSR_IA32_EXT_APIC_TMR2, + MSR_IA32_EXT_APIC_TMR3, + MSR_IA32_EXT_APIC_TMR4, + MSR_IA32_EXT_APIC_TMR5, + MSR_IA32_EXT_APIC_TMR6, + MSR_IA32_EXT_APIC_TMR7, + MSR_IA32_EXT_APIC_IRR0, + MSR_IA32_EXT_APIC_IRR1, + MSR_IA32_EXT_APIC_IRR2, + MSR_IA32_EXT_APIC_IRR3, + MSR_IA32_EXT_APIC_IRR4, + MSR_IA32_EXT_APIC_IRR5, + MSR_IA32_EXT_APIC_IRR6, + MSR_IA32_EXT_APIC_IRR7, + MSR_IA32_EXT_APIC_ESR, + MSR_IA32_EXT_APIC_LVT_CMCI, + MSR_IA32_EXT_APIC_ICR, + MSR_IA32_EXT_APIC_LVT_TIMER, + MSR_IA32_EXT_APIC_LVT_THERMAL, + MSR_IA32_EXT_APIC_LVT_PMI, + MSR_IA32_EXT_APIC_LVT_LINT0, + MSR_IA32_EXT_APIC_LVT_LINT1, + MSR_IA32_EXT_APIC_LVT_ERROR, + MSR_IA32_EXT_APIC_INIT_COUNT, + MSR_IA32_EXT_APIC_CUR_COUNT, + MSR_IA32_EXT_APIC_DIV_CONF, + MSR_IA32_EXT_APIC_SELF_IPI, +}; + static void enable_msr_interception(uint8_t *bitmap, uint32_t msr_arg) { uint8_t *read_map; @@ -51,6 +98,23 @@ static void enable_msr_interception(uint8_t *bitmap, uint32_t msr_arg) write_map[(msr >> 3U)] = value; } +/* + * Enable read and write msr interception for x2APIC MSRs + * MSRs that are not supported in the x2APIC range of MSRs, + * i.e. anything other than the ones below and between + * 0x802 and 0x83F, are not intercepted + */ + +static void intercept_x2apic_msrs(uint8_t *msr_bitmap_arg) +{ + uint8_t *msr_bitmap = msr_bitmap_arg; + uint32_t i; + + for (i = 0U; i < ARRAY_SIZE(x2apic_msrs); i++) { + enable_msr_interception(msr_bitmap, x2apic_msrs[i]); + } +} + void init_msr_emulation(struct vcpu *vcpu) { uint32_t i; @@ -93,6 +157,8 @@ void init_msr_emulation(struct vcpu *vcpu) i <= MSR_IA32_VMX_TRUE_ENTRY_CTLS; i++) { enable_msr_interception(msr_bitmap, i); } + + intercept_x2apic_msrs(msr_bitmap); } /* Set up MSR bitmap - pg 2904 24.6.9 */ @@ -189,14 +255,18 @@ int rdmsr_vmexit_handler(struct vcpu *vcpu) } default: { - if (!(((msr >= MSR_IA32_MTRR_PHYSBASE_0) && - (msr <= MSR_IA32_MTRR_PHYSMASK_9)) || - ((msr >= MSR_IA32_VMX_BASIC) && - (msr <= MSR_IA32_VMX_TRUE_ENTRY_CTLS)))) { - pr_warn("rdmsr: %lx should not come here!", msr); + if (is_x2apic_msr(msr)) { + err = vlapic_rdmsr(vcpu, msr, &v); + } else { + if (!(((msr >= MSR_IA32_MTRR_PHYSBASE_0) && + (msr <= MSR_IA32_MTRR_PHYSMASK_9)) || + ((msr >= MSR_IA32_VMX_BASIC) && + (msr <= MSR_IA32_VMX_TRUE_ENTRY_CTLS)))) { + pr_warn("rdmsr: %lx should not come here!", msr); + } + vcpu_inject_gp(vcpu, 0U); + v = 0UL; } - vcpu_inject_gp(vcpu, 0U); - v = 0UL; break; } } @@ -321,13 +391,17 @@ int wrmsr_vmexit_handler(struct vcpu *vcpu) } default: { - if (!(((msr >= MSR_IA32_MTRR_PHYSBASE_0) && - (msr <= MSR_IA32_MTRR_PHYSMASK_9)) || - ((msr >= MSR_IA32_VMX_BASIC) && - (msr <= MSR_IA32_VMX_TRUE_ENTRY_CTLS)))) { - pr_warn("rdmsr: %lx should not come here!", msr); + if (is_x2apic_msr(msr)) { + err = vlapic_wrmsr(vcpu, msr, v); + } else { + if (!(((msr >= MSR_IA32_MTRR_PHYSBASE_0) && + (msr <= MSR_IA32_MTRR_PHYSMASK_9)) || + ((msr >= MSR_IA32_VMX_BASIC) && + (msr <= MSR_IA32_VMX_TRUE_ENTRY_CTLS)))) { + pr_warn("wrmsr: %lx should not come here!", msr); + } + vcpu_inject_gp(vcpu, 0U); } - vcpu_inject_gp(vcpu, 0U); break; } } diff --git a/hypervisor/include/arch/x86/msr.h b/hypervisor/include/arch/x86/msr.h index e3ac804d2..eeefeaae8 100644 --- a/hypervisor/include/arch/x86/msr.h +++ b/hypervisor/include/arch/x86/msr.h @@ -529,6 +529,18 @@ static inline bool pat_mem_type_invalid(uint64_t x) (x != PAT_MEM_TYPE_WT) && (x != PAT_MEM_TYPE_WP) && (x != PAT_MEM_TYPE_WB) && (x != PAT_MEM_TYPE_UCM)); } + +static inline bool is_x2apic_msr(uint32_t msr) +{ + bool ret = false; + /* + * if msr is in the range of x2APIC MSRs + */ + if ((msr >= MSR_IA32_EXT_XAPICID) && (msr <= MSR_IA32_EXT_APIC_SELF_IPI)) { + ret = true; + } + return ret; +} #endif /* ASSEMBLER */ /* 5 high-order bits in every field are reserved */