diff --git a/hypervisor/arch/x86/guest/vcpu.c b/hypervisor/arch/x86/guest/vcpu.c index 29e3a48f4..544f36634 100644 --- a/hypervisor/arch/x86/guest/vcpu.c +++ b/hypervisor/arch/x86/guest/vcpu.c @@ -194,7 +194,7 @@ void vcpu_reset_eoi_exit_bitmaps(struct acrn_vcpu *vcpu) } /* As a vcpu reset internal API, DO NOT touch any vcpu state transition in this function. */ -static void vcpu_reset_internal(struct acrn_vcpu *vcpu, __unused enum reset_mode mode) +static void vcpu_reset_internal(struct acrn_vcpu *vcpu, enum reset_mode mode) { int32_t i; struct acrn_vlapic *vlapic; @@ -217,7 +217,7 @@ static void vcpu_reset_internal(struct acrn_vcpu *vcpu, __unused enum reset_mode vcpu->thread_obj.notify_mode = SCHED_NOTIFY_IPI; vlapic = vcpu_vlapic(vcpu); - vlapic_reset(vlapic, apicv_ops); + vlapic_reset(vlapic, apicv_ops, mode); reset_vcpu_regs(vcpu); } diff --git a/hypervisor/arch/x86/guest/vlapic.c b/hypervisor/arch/x86/guest/vlapic.c index e1fca5e82..824c36784 100644 --- a/hypervisor/arch/x86/guest/vlapic.c +++ b/hypervisor/arch/x86/guest/vlapic.c @@ -55,8 +55,8 @@ static inline uint32_t prio(uint32_t x) #define VLAPIC_VERSION (16U) #define APICBASE_BSP 0x00000100UL -#define APICBASE_X2APIC 0x00000400U -#define APICBASE_XAPIC 0x00000800U +#define APICBASE_X2APIC 0x00000400UL +#define APICBASE_XAPIC 0x00000800UL #define APICBASE_LAPIC_MODE (APICBASE_XAPIC | APICBASE_X2APIC) #define APICBASE_ENABLED 0x00000800UL #define LOGICAL_ID_MASK 0xFU @@ -1643,24 +1643,39 @@ static int32_t vlapic_write(struct acrn_vlapic *vlapic, uint32_t offset, uint64_ * @pre vlapic != NULL && ops != NULL */ void -vlapic_reset(struct acrn_vlapic *vlapic, const struct acrn_apicv_ops *ops) +vlapic_reset(struct acrn_vlapic *vlapic, const struct acrn_apicv_ops *ops, enum reset_mode mode) { struct lapic_regs *lapic; + uint64_t preserved_lapic_mode = vlapic->msr_apicbase & APICBASE_LAPIC_MODE; + uint32_t preserved_apic_id = vlapic->apic_page.id.v; - /* - * Upon reset, vlapic is set to xAPIC mode. - */ - vlapic->msr_apicbase = DEFAULT_APIC_BASE | APICBASE_ENABLED; + vlapic->msr_apicbase = DEFAULT_APIC_BASE; if (vlapic->vcpu->vcpu_id == BOOT_CPU_ID) { vlapic->msr_apicbase |= APICBASE_BSP; } + if (mode == INIT_RESET) { + if ((preserved_lapic_mode & APICBASE_ENABLED) != 0U ) { + /* Per SDM 10.12.5.1 vol.3, need to preserve lapic mode after INIT */ + vlapic->msr_apicbase |= preserved_lapic_mode; + } + } else { + /* Upon reset, vlapic is set to xAPIC mode. */ + vlapic->msr_apicbase |= APICBASE_XAPIC; + } lapic = &(vlapic->apic_page); (void)memset((void *)lapic, 0U, sizeof(struct lapic_regs)); (void)memset((void *)&(vlapic->pir_desc), 0U, sizeof(vlapic->pir_desc)); - lapic->id.v = vlapic_build_id(vlapic); + if (mode == INIT_RESET) { + if ((preserved_lapic_mode & APICBASE_ENABLED) != 0U ) { + /* the local APIC ID register should be preserved in XAPIC or X2APIC mode */ + lapic->id.v = preserved_apic_id; + } + } else { + lapic->id.v = vlapic_build_id(vlapic); + } lapic->version.v = VLAPIC_VERSION; lapic->version.v |= (VLAPIC_MAXLVT_INDEX << MAXLVTSHIFT); lapic->dfr.v = 0xffffffffU; @@ -1779,7 +1794,8 @@ int32_t vlapic_set_apicbase(struct acrn_vlapic *vlapic, uint64_t new) if ((new & APICBASE_LAPIC_MODE) == (APICBASE_XAPIC | APICBASE_X2APIC)) { if (is_lapic_pt_configured(vcpu->vm)) { - vlapic_reset(vlapic, &ptapic_ops); + /* vlapic need to be reset to make sure it is in correct state */ + vlapic_reset(vlapic, &ptapic_ops, SOFTWARE_RESET); } vlapic->msr_apicbase = new; vlapic_build_x2apic_id(vlapic); diff --git a/hypervisor/include/arch/x86/guest/vlapic.h b/hypervisor/include/arch/x86/guest/vlapic.h index f271a4e0f..cd12d656b 100644 --- a/hypervisor/include/arch/x86/guest/vlapic.h +++ b/hypervisor/include/arch/x86/guest/vlapic.h @@ -106,6 +106,7 @@ struct acrn_apicv_ops { bool (*x2apic_write_msr_may_valid)(uint32_t offset); }; +enum reset_mode; extern const struct acrn_apicv_ops *apicv_ops; void vlapic_set_apicv_ops(void); @@ -194,7 +195,7 @@ void vlapic_free(struct acrn_vcpu *vcpu); * @pre vlapic->vcpu->vcpu_id < MAX_VCPUS_PER_VM */ void vlapic_init(struct acrn_vlapic *vlapic); -void vlapic_reset(struct acrn_vlapic *vlapic, const struct acrn_apicv_ops *ops); +void vlapic_reset(struct acrn_vlapic *vlapic, const struct acrn_apicv_ops *ops, enum reset_mode mode); void vlapic_restore(struct acrn_vlapic *vlapic, const struct lapic_regs *regs); uint64_t vlapic_apicv_get_apic_access_addr(void); uint64_t vlapic_apicv_get_apic_page_addr(struct acrn_vlapic *vlapic);