hv: vlapic: clear up where needs atomic operation in vLAPIC

In almost case, vLAPIC will only be accessed by the related vCPU. There's no
synchronization issue in this case. However, other vCPUs could deliver interrupts
to the current vCPU, in this case, the IRR (for APICv base situation) or PIR
(for APICv advanced situation) and TMR for both cases could be accessed by more
than one vCPUS simultaneously. So operations on IRR or PIR should be atomical
and visible to other vCPUs immediately. In another case, vLAPIC could be accessed
by another vCPU when create vCPU or reset vCPU which could be supposed to be
consequently.

Tracked-On: #1842
Signed-off-by: Li, Fei1 <fei1.li@intel.com>
This commit is contained in:
Li, Fei1 2019-07-04 21:13:55 +08:00 committed by wenlingz
parent 05a4ee8074
commit 5d6c9c33ca
2 changed files with 15 additions and 17 deletions

View File

@ -691,11 +691,10 @@ vlapic_get_lvtptr(struct acrn_vlapic *vlapic, uint32_t offset)
static inline uint32_t static inline uint32_t
vlapic_get_lvt(const struct acrn_vlapic *vlapic, uint32_t offset) vlapic_get_lvt(const struct acrn_vlapic *vlapic, uint32_t offset)
{ {
uint32_t idx, val; uint32_t idx;
idx = lvt_off_to_idx(offset); idx = lvt_off_to_idx(offset);
val = atomic_load32(&vlapic->lvt_last[idx]); return vlapic->lvt_last[idx];
return val;
} }
static void static void
@ -764,7 +763,7 @@ vlapic_lvt_write_handler(struct acrn_vlapic *vlapic, uint32_t offset)
if (error == false) { if (error == false) {
*lvtptr = val; *lvtptr = val;
idx = lvt_off_to_idx(offset); idx = lvt_off_to_idx(offset);
atomic_store32(&vlapic->lvt_last[idx], val); vlapic->lvt_last[idx] = val;
} }
} }
@ -864,7 +863,7 @@ vlapic_process_eoi(struct acrn_vlapic *vlapic)
vector = vlapic->isrv; vector = vlapic->isrv;
i = (vector >> 5U); i = (vector >> 5U);
bitpos = (vector & 0x1fU); bitpos = (vector & 0x1fU);
isrptr[i].v &= ~(1U << bitpos); bitmap32_clear_nolock((uint16_t)bitpos, &isrptr[i].v);
dev_dbg(ACRN_DBG_LAPIC, "EOI vector %u", vector); dev_dbg(ACRN_DBG_LAPIC, "EOI vector %u", vector);
vlapic_dump_isr(vlapic, "vlapic_process_eoi"); vlapic_dump_isr(vlapic, "vlapic_process_eoi");
@ -872,7 +871,7 @@ vlapic_process_eoi(struct acrn_vlapic *vlapic)
vlapic->isrv = vlapic_find_isrv(vlapic); vlapic->isrv = vlapic_find_isrv(vlapic);
vlapic_update_ppr(vlapic); vlapic_update_ppr(vlapic);
if ((tmrptr[i].v & (1U << bitpos)) != 0U) { if (bitmap32_test((uint16_t)bitpos, &tmrptr[i].v)) {
/* hook to vIOAPIC */ /* hook to vIOAPIC */
vioapic_process_eoi(vlapic->vm, vector); vioapic_process_eoi(vlapic->vm, vector);
} }
@ -1268,9 +1267,8 @@ static inline uint32_t vlapic_find_highest_irr(const struct acrn_vlapic *vlapic)
irrptr = &lapic->irr[0]; irrptr = &lapic->irr[0];
/* i ranges effectively from 7 to 1 */ /* i ranges effectively from 7 to 1 */
for (i = 8U; i > 1U; ) { for (i = 7U; i > 0U; i--) {
i--; val = irrptr[i].v;
val = atomic_load32(&irrptr[i].v);
if (val != 0U) { if (val != 0U) {
bitpos = (uint32_t)fls32(val); bitpos = (uint32_t)fls32(val);
vec = (i * 32U) + bitpos; vec = (i * 32U) + bitpos;
@ -1340,11 +1338,12 @@ static void vlapic_get_deliverable_intr(struct acrn_vlapic *vlapic, uint32_t vec
idx = vector >> 5U; idx = vector >> 5U;
irrptr = &lapic->irr[0]; irrptr = &lapic->irr[0];
atomic_clear32(&irrptr[idx].v, 1U << (vector & 0x1fU)); bitmap32_clear_lock((uint16_t)(vector & 0x1fU), &irrptr[idx].v);
vlapic_dump_irr(vlapic, "vlapic_get_deliverable_intr"); vlapic_dump_irr(vlapic, "vlapic_get_deliverable_intr");
isrptr = &lapic->isr[0]; isrptr = &lapic->isr[0];
isrptr[idx].v |= 1U << (vector & 0x1fU); bitmap32_set_nolock((uint16_t)(vector & 0x1fU), &isrptr[idx].v);
vlapic_dump_isr(vlapic, "vlapic_get_deliverable_intr"); vlapic_dump_isr(vlapic, "vlapic_get_deliverable_intr");
vlapic->isrv = vector; vlapic->isrv = vector;
@ -2140,16 +2139,14 @@ static int32_t
apicv_set_intr_ready(struct acrn_vlapic *vlapic, uint32_t vector) apicv_set_intr_ready(struct acrn_vlapic *vlapic, uint32_t vector)
{ {
struct vlapic_pir_desc *pir_desc; struct vlapic_pir_desc *pir_desc;
uint64_t mask;
uint32_t idx; uint32_t idx;
int32_t notify; int32_t notify;
pir_desc = &(vlapic->pir_desc); pir_desc = &(vlapic->pir_desc);
idx = vector >> 6U; idx = vector >> 6U;
mask = 1UL << (vector & 0x3fU);
atomic_set64(&pir_desc->pir[idx], mask); bitmap_set_lock((uint16_t)(vector & 0x3fU), &pir_desc->pir[idx]);
notify = (atomic_cmpxchg64(&pir_desc->pending, 0UL, 1UL) == 0UL) ? 1 : 0; notify = (atomic_cmpxchg64(&pir_desc->pending, 0UL, 1UL) == 0UL) ? 1 : 0;
return notify; return notify;
} }
@ -2394,7 +2391,7 @@ int32_t veoi_vmexit_handler(struct acrn_vcpu *vcpu)
uint32_t vector; uint32_t vector;
struct lapic_regs *lapic; struct lapic_regs *lapic;
struct lapic_reg *tmrptr; struct lapic_reg *tmrptr;
uint32_t idx, mask; uint32_t idx;
vcpu_retain_rip(vcpu); vcpu_retain_rip(vcpu);
@ -2404,9 +2401,8 @@ int32_t veoi_vmexit_handler(struct acrn_vcpu *vcpu)
tmrptr = &lapic->tmr[0]; tmrptr = &lapic->tmr[0];
idx = vector >> 5U; idx = vector >> 5U;
mask = 1U << (vector & 0x1fU);
if ((tmrptr[idx].v & mask) != 0U) { if (bitmap32_test((uint16_t)(vector & 0x1fU), &tmrptr[idx].v)) {
/* hook to vIOAPIC */ /* hook to vIOAPIC */
vioapic_process_eoi(vlapic->vm, vector); vioapic_process_eoi(vlapic->vm, vector);
} }

View File

@ -64,6 +64,8 @@ struct acrn_vlapic {
* to support APICv features: * to support APICv features:
* - 'apic_page' MUST be 4KB aligned. * - 'apic_page' MUST be 4KB aligned.
* - 'pir_desc' MUST be 64 bytes aligned. * - 'pir_desc' MUST be 64 bytes aligned.
* IRR, TMR and PIR could be accessed by other vCPUs when deliver
* an interrupt to vLAPIC.
*/ */
struct lapic_regs apic_page; struct lapic_regs apic_page;
struct vlapic_pir_desc pir_desc; struct vlapic_pir_desc pir_desc;