hv: fix SOS vapic_id assignment issue

Currently vlapic_build_id() uses vcpu_id to retrieve the lapic_id
per_cpu variable:

  vlapic_id = per_cpu(lapic_id, vcpu->vcpu_id);

SOS vcpu_id may not equal to pcpu_id, and in that case it runs into
problems. For example, if any pre-launched VMs are launched on PCPUs
whose IDs are smaller than any PCPU IDs that are used by SOS.

This patch fixes the issue and simplify the code to create or get
vapic_id by:

- assign vapic_id in create_vlapic(), which now takes pcpu_id as input
  argument, and save it in the new field: vlapic->vapic_id, which will
  never be changed.
- simplify vlapic_get_apicid() by returning te saved vapid_id directly.
- remove vlapic_build_id().
- vlapic_init() is only called once, merge it into vlapic_create().

Tracked-On: #4268
Signed-off-by: Zide Chen <zide.chen@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Zide Chen 2020-04-02 13:57:41 -07:00 committed by wenlingz
parent 00ad3863a1
commit 6040d8f6a2
3 changed files with 38 additions and 68 deletions

View File

@ -505,7 +505,7 @@ int32_t create_vcpu(uint16_t pcpu_id, struct acrn_vm *vm, struct acrn_vcpu **rtn
vcpu->arch.pid.control.bits.ndst = per_cpu(lapic_id, pcpu_id); vcpu->arch.pid.control.bits.ndst = per_cpu(lapic_id, pcpu_id);
/* Create per vcpu vlapic */ /* Create per vcpu vlapic */
vlapic_create(vcpu); vlapic_create(vcpu, pcpu_id);
if (!vm_hide_mtrr(vm)) { if (!vm_hide_mtrr(vm)) {
init_vmtrr(vcpu); init_vmtrr(vcpu);

View File

@ -135,8 +135,7 @@ static uint16_t vm_apicid2vcpu_id(struct acrn_vm *vm, uint32_t lapicid)
uint16_t cpu_id = INVALID_CPU_ID; uint16_t cpu_id = INVALID_CPU_ID;
foreach_vcpu(i, vm, vcpu) { foreach_vcpu(i, vm, vcpu) {
const struct acrn_vlapic *vlapic = vcpu_vlapic(vcpu); if (vcpu_vlapic(vcpu)->vapic_id == lapicid) {
if (vlapic_get_apicid(vlapic) == lapicid) {
cpu_id = vcpu->vcpu_id; cpu_id = vcpu->vcpu_id;
break; break;
} }
@ -150,57 +149,13 @@ static uint16_t vm_apicid2vcpu_id(struct acrn_vm *vm, uint32_t lapicid)
} }
/*
* @pre vlapic != NULL
*/
uint32_t
vlapic_get_apicid(const struct acrn_vlapic *vlapic)
{
uint32_t apicid;
if (is_x2apic_enabled(vlapic)) {
apicid = vlapic->apic_page.id.v;
} else {
apicid = (vlapic->apic_page.id.v) >> APIC_ID_SHIFT;
}
return apicid;
}
static inline uint32_t
vlapic_build_id(const struct acrn_vlapic *vlapic)
{
const struct acrn_vcpu *vcpu = vlapic2vcpu(vlapic);
uint32_t vlapic_id, lapic_regs_id;
if (is_sos_vm(vcpu->vm)) {
/*
* For SOS_VM type, pLAPIC IDs need to be used because
* host ACPI tables are passthru to SOS.
* Get APIC ID sequence format from cpu_storage
*/
vlapic_id = per_cpu(lapic_id, vcpu->vcpu_id);
} else {
vlapic_id = (uint32_t)vcpu->vcpu_id;
}
if (is_x2apic_enabled(vlapic)) {
lapic_regs_id = vlapic_id;
} else {
lapic_regs_id = vlapic_id << APIC_ID_SHIFT;
}
dev_dbg(DBG_LEVEL_VLAPIC, "vlapic APIC PAGE ID : 0x%08x", lapic_regs_id);
return lapic_regs_id;
}
static inline void vlapic_build_x2apic_id(struct acrn_vlapic *vlapic) static inline void vlapic_build_x2apic_id(struct acrn_vlapic *vlapic)
{ {
struct lapic_regs *lapic; struct lapic_regs *lapic;
uint32_t logical_id, cluster_id; uint32_t logical_id, cluster_id;
lapic = &(vlapic->apic_page); lapic = &(vlapic->apic_page);
lapic->id.v = vlapic_build_id(vlapic); lapic->id.v = vlapic->vapic_id;
logical_id = lapic->id.v & LOGICAL_ID_MASK; logical_id = lapic->id.v & LOGICAL_ID_MASK;
cluster_id = (lapic->id.v & CLUSTER_ID_MASK) >> 4U; cluster_id = (lapic->id.v & CLUSTER_ID_MASK) >> 4U;
lapic->ldr.v = (cluster_id << 16U) | (1U << logical_id); lapic->ldr.v = (cluster_id << 16U) | (1U << logical_id);
@ -1667,7 +1622,10 @@ vlapic_reset(struct acrn_vlapic *vlapic, const struct acrn_apicv_ops *ops, enum
lapic->id.v = preserved_apic_id; lapic->id.v = preserved_apic_id;
} }
} else { } else {
lapic->id.v = vlapic_build_id(vlapic); lapic->id.v = vlapic->vapic_id;
if (!is_x2apic_enabled(vlapic)) {
lapic->id.v <<= APIC_ID_SHIFT;
}
} }
lapic->version.v = VLAPIC_VERSION; lapic->version.v = VLAPIC_VERSION;
lapic->version.v |= (VLAPIC_MAXLVT_INDEX << MAXLVTSHIFT); lapic->version.v |= (VLAPIC_MAXLVT_INDEX << MAXLVTSHIFT);
@ -1688,16 +1646,6 @@ vlapic_reset(struct acrn_vlapic *vlapic, const struct acrn_apicv_ops *ops, enum
vlapic->ops = ops; vlapic->ops = ops;
} }
/**
* @pre vlapic2vcpu(vlapic)->vm != NULL
* @pre vlapic2vcpu(vlapic)->vcpu_id < MAX_VCPUS_PER_VM
*/
void
vlapic_init(struct acrn_vlapic *vlapic)
{
vlapic_init_timer(vlapic);
}
void vlapic_restore(struct acrn_vlapic *vlapic, const struct lapic_regs *regs) void vlapic_restore(struct acrn_vlapic *vlapic, const struct lapic_regs *regs)
{ {
struct lapic_regs *lapic; struct lapic_regs *lapic;
@ -2174,8 +2122,13 @@ int32_t vlapic_x2apic_write(struct acrn_vcpu *vcpu, uint32_t msr, uint64_t val)
return error; return error;
} }
void vlapic_create(struct acrn_vcpu *vcpu) /**
* @pre vcpu != NULL
*/
void vlapic_create(struct acrn_vcpu *vcpu, uint16_t pcpu_id)
{ {
struct acrn_vlapic *vlapic = vcpu_vlapic(vcpu);
if (is_vcpu_bsp(vcpu)) { if (is_vcpu_bsp(vcpu)) {
uint64_t *pml4_page = uint64_t *pml4_page =
(uint64_t *)vcpu->vm->arch_vm.nworld_eptp; (uint64_t *)vcpu->vm->arch_vm.nworld_eptp;
@ -2191,7 +2144,20 @@ void vlapic_create(struct acrn_vcpu *vcpu)
EPT_WR | EPT_RD | EPT_UNCACHED); EPT_WR | EPT_RD | EPT_UNCACHED);
} }
vlapic_init(vcpu_vlapic(vcpu)); vlapic_init_timer(vlapic);
if (is_sos_vm(vcpu->vm)) {
/*
* For SOS_VM type, pLAPIC IDs need to be used because
* host ACPI tables are passthru to SOS.
* Get APIC ID sequence format from cpu_storage
*/
vlapic->vapic_id = per_cpu(lapic_id, pcpu_id);
} else {
vlapic->vapic_id = (uint32_t)vcpu->vcpu_id;
}
dev_dbg(DBG_LEVEL_VLAPIC, "vlapic APIC ID : 0x%04x", vlapic->vapic_id);
} }
/* /*

View File

@ -61,6 +61,7 @@ struct acrn_vlapic {
*/ */
struct lapic_regs apic_page; struct lapic_regs apic_page;
uint32_t vapic_id;
uint32_t esr_pending; uint32_t esr_pending;
int32_t esr_firing; int32_t esr_firing;
@ -163,17 +164,20 @@ int32_t vlapic_intr_msi(struct acrn_vm *vm, uint64_t addr, uint64_t msg);
void vlapic_receive_intr(struct acrn_vm *vm, bool level, uint32_t dest, void vlapic_receive_intr(struct acrn_vm *vm, bool level, uint32_t dest,
bool phys, uint32_t delmode, uint32_t vec, bool rh); bool phys, uint32_t delmode, uint32_t vec, bool rh);
uint32_t vlapic_get_apicid(const struct acrn_vlapic *vlapic); /**
void vlapic_create(struct acrn_vcpu *vcpu); * @pre vlapic != NULL
*/
static inline uint32_t vlapic_get_apicid(const struct acrn_vlapic *vlapic)
{
return vlapic->vapic_id;
}
void vlapic_create(struct acrn_vcpu *vcpu, uint16_t pcpu_id);
/* /*
* @pre vcpu != NULL * @pre vcpu != NULL
*/ */
void vlapic_free(struct acrn_vcpu *vcpu); void vlapic_free(struct acrn_vcpu *vcpu);
/**
* @pre vlapic->vm != NULL
* @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, enum reset_mode mode); 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); 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_access_addr(void);