Allow vlapic_set_intr_ready() to return a value that indicates whether or not

the vcpu should be kicked to process a pending interrupt. This will be useful
in the implementation of the Posted Interrupt APICv feature.

Change the return value of 'vlapic_pending_intr()' to indicate whether or not
an interrupt is available to be delivered to the vcpu depending on the value
of the PPR.

Add KTR tracepoints to debug guest IPI delivery.
This commit is contained in:
Neel Natu 2014-01-07 00:38:22 +00:00
parent 448cffc859
commit 4d1e82a88e
5 changed files with 51 additions and 29 deletions

View file

@ -989,8 +989,7 @@ vmx_inject_interrupts(struct vmx *vmx, int vcpu, struct vlapic *vlapic)
return;
/* Ask the local apic for a vector to inject */
vector = vlapic_pending_intr(vlapic);
if (vector < 0)
if (!vlapic_pending_intr(vlapic, &vector))
return;
if (vector < 32 || vector > 255)

View file

@ -289,27 +289,29 @@ vlapic_esr_write_handler(struct vlapic *vlapic)
vlapic->esr_pending = 0;
}
void
int
vlapic_set_intr_ready(struct vlapic *vlapic, int vector, bool level)
{
struct LAPIC *lapic = vlapic->apic_page;
uint32_t *irrptr, *tmrptr, mask;
int idx;
struct LAPIC *lapic;
uint32_t *irrptr, *tmrptr, mask;
int idx;
if (vector < 0 || vector >= 256)
panic("vlapic_set_intr_ready: invalid vector %d\n", vector);
KASSERT(vector >= 0 && vector < 256, ("invalid vector %d", vector));
lapic = vlapic->apic_page;
if (!(lapic->svr & APIC_SVR_ENABLE)) {
VLAPIC_CTR1(vlapic, "vlapic is software disabled, ignoring "
"interrupt %d", vector);
return;
return (0);
}
if (vector < 16) {
vlapic_set_error(vlapic, APIC_ESR_RECEIVE_ILLEGAL_VECTOR);
return;
VLAPIC_CTR1(vlapic, "vlapic ignoring interrupt to vector %d",
vector);
return (1);
}
idx = (vector / 32) * 4;
mask = 1 << (vector % 32);
@ -328,6 +330,7 @@ vlapic_set_intr_ready(struct vlapic *vlapic, int vector, bool level)
atomic_clear_int(&tmrptr[idx], mask);
VLAPIC_CTR_IRR(vlapic, "vlapic_set_intr_ready");
return (1);
}
static __inline uint32_t *
@ -473,8 +476,8 @@ vlapic_fire_lvt(struct vlapic *vlapic, uint32_t lvt)
vlapic_set_error(vlapic, APIC_ESR_SEND_ILLEGAL_VECTOR);
return (0);
}
vlapic_set_intr_ready(vlapic, vec, false);
vcpu_notify_event(vlapic->vm, vlapic->vcpuid, true);
if (vlapic_set_intr_ready(vlapic, vec, false))
vcpu_notify_event(vlapic->vm, vlapic->vcpuid, true);
break;
case APIC_LVT_DM_NMI:
vm_inject_nmi(vlapic->vm, vlapic->vcpuid);
@ -935,9 +938,12 @@ vlapic_icrlo_write_handler(struct vlapic *vlapic, bool *retu)
if (mode == APIC_DELMODE_FIXED && vec < 16) {
vlapic_set_error(vlapic, APIC_ESR_SEND_ILLEGAL_VECTOR);
VLAPIC_CTR1(vlapic, "Ignoring invalid IPI %d", vec);
return (0);
}
VLAPIC_CTR2(vlapic, "icrlo 0x%016lx triggered ipi %d", icrval, vec);
if (mode == APIC_DELMODE_FIXED || mode == APIC_DELMODE_NMI) {
switch (icrval & APIC_DEST_MASK) {
case APIC_DEST_DESTFLD:
@ -967,8 +973,13 @@ vlapic_icrlo_write_handler(struct vlapic *vlapic, bool *retu)
lapic_intr_edge(vlapic->vm, i, vec);
vmm_stat_array_incr(vlapic->vm, vlapic->vcpuid,
IPIS_SENT, i, 1);
} else
VLAPIC_CTR2(vlapic, "vlapic sending ipi %d "
"to vcpuid %d", vec, i);
} else {
vm_inject_nmi(vlapic->vm, i);
VLAPIC_CTR1(vlapic, "vlapic sending ipi nmi "
"to vcpuid %d", i);
}
}
return (0); /* handled completely in the kernel */
@ -1023,7 +1034,7 @@ vlapic_icrlo_write_handler(struct vlapic *vlapic, bool *retu)
}
int
vlapic_pending_intr(struct vlapic *vlapic)
vlapic_pending_intr(struct vlapic *vlapic, int *vecptr)
{
struct LAPIC *lapic = vlapic->apic_page;
int idx, i, bitpos, vector;
@ -1043,12 +1054,14 @@ vlapic_pending_intr(struct vlapic *vlapic)
vector = i * 32 + (bitpos - 1);
if (PRIO(vector) > PRIO(lapic->ppr)) {
VLAPIC_CTR1(vlapic, "pending intr %d", vector);
return (vector);
if (vecptr != NULL)
*vecptr = vector;
return (1);
} else
break;
}
}
return (-1);
return (0);
}
void

View file

@ -38,16 +38,16 @@ int vlapic_read(struct vlapic *vlapic, uint64_t offset, uint64_t *data,
bool *retu);
/*
* Returns a vector between 32 and 255 if an interrupt is pending in the
* IRR that can be delivered based on the current state of ISR and TPR.
* Returns 0 if there is no eligible vector that can be delivered to the
* guest at this time and non-zero otherwise.
*
* If an eligible vector number is found and 'vecptr' is not NULL then it will
* be stored in the location pointed to by 'vecptr'.
*
* Note that the vector does not automatically transition to the ISR as a
* result of calling this function.
*
* Returns -1 if there is no eligible vector that can be delivered to the
* guest at this time.
*/
int vlapic_pending_intr(struct vlapic *vlapic);
int vlapic_pending_intr(struct vlapic *vlapic, int *vecptr);
/*
* Transition 'vector' from IRR to ISR. This function is called with the
@ -57,7 +57,18 @@ int vlapic_pending_intr(struct vlapic *vlapic);
*/
void vlapic_intr_accepted(struct vlapic *vlapic, int vector);
void vlapic_set_intr_ready(struct vlapic *vlapic, int vector, bool level);
/*
* Returns 1 if the vcpu needs to be notified of the interrupt and 0 otherwise.
*/
int vlapic_set_intr_ready(struct vlapic *vlapic, int vector, bool level);
/*
* Post an interrupt to the vcpu running on 'hostcpu'. This will use a
* hardware assist if available (e.g. Posted Interrupt) or fall back to
* sending an IPI to interrupt the 'hostcpu'.
*/
void vlapic_post_intr(struct vlapic *vlapic, int hostcpu);
void vlapic_set_error(struct vlapic *vlapic, uint32_t mask);
void vlapic_fire_cmci(struct vlapic *vlapic);
int vlapic_trigger_lvt(struct vlapic *vlapic, int vector);
@ -69,7 +80,6 @@ bool vlapic_enabled(struct vlapic *vlapic);
void vlapic_deliver_intr(struct vm *vm, bool level, uint32_t dest, bool phys,
int delmode, int vec);
void vlapic_post_intr(struct vlapic *vlapic, int hostcpu);
/* APIC write handlers */
void vlapic_id_write_handler(struct vlapic *vlapic);

View file

@ -910,7 +910,7 @@ vm_handle_hlt(struct vm *vm, int vcpuid, bool intr_disabled, bool *retu)
* returned from VMRUN() and before we grabbed the vcpu lock.
*/
if (!vm_nmi_pending(vm, vcpuid) &&
(intr_disabled || vlapic_pending_intr(vcpu->vlapic) < 0)) {
(intr_disabled || !vlapic_pending_intr(vcpu->vlapic, NULL))) {
t = ticks;
vcpu_require_state_locked(vcpu, VCPU_SLEEPING);
if (vlapic_enabled(vcpu->vlapic)) {

View file

@ -62,8 +62,8 @@ lapic_set_intr(struct vm *vm, int cpu, int vector, bool level)
return (EINVAL);
vlapic = vm_lapic(vm, cpu);
vlapic_set_intr_ready(vlapic, vector, level);
vcpu_notify_event(vm, cpu, true);
if (vlapic_set_intr_ready(vlapic, vector, level))
vcpu_notify_event(vm, cpu, true);
return (0);
}