HV: restore lapic state and apic id upon INIT

Per SDM 10.12.5.1 vol.3, local APIC should keep LAPIC state after receiving
INIT. The local APIC ID register should also be preserved.

Tracked-On: #4267

Signed-off-by: Victor Sun <victor.sun@intel.com>
Reviewed-by: Jason Chen CJ <jason.cj.chen@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Victor Sun 2019-12-25 16:26:11 +08:00 committed by wenlingz
parent ab13228591
commit c6f7803f06
3 changed files with 29 additions and 12 deletions

View File

@ -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);
}

View File

@ -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);

View File

@ -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);