aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--xen/arch/x86/hvm/hvm.c2
-rw-r--r--xen/arch/x86/hvm/irq.c60
-rw-r--r--xen/arch/x86/hvm/svm/intr.c91
-rw-r--r--xen/arch/x86/hvm/svm/svm.c103
-rw-r--r--xen/arch/x86/hvm/svm/vmcb.c9
-rw-r--r--xen/arch/x86/hvm/vlapic.c25
-rw-r--r--xen/arch/x86/hvm/vmx/intr.c88
-rw-r--r--xen/arch/x86/hvm/vmx/vmx.c32
-rw-r--r--xen/arch/x86/hvm/vpic.c2
-rw-r--r--xen/arch/x86/hvm/vpt.c15
-rw-r--r--xen/include/asm-x86/hvm/hvm.h33
-rw-r--r--xen/include/asm-x86/hvm/irq.h8
-rw-r--r--xen/include/asm-x86/hvm/vlapic.h4
-rw-r--r--xen/include/asm-x86/hvm/vpic.h2
-rw-r--r--xen/include/asm-x86/hvm/vpt.h2
15 files changed, 211 insertions, 265 deletions
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 2e2d6c7096..0c48418032 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -737,7 +737,7 @@ int hvm_set_cr4(unsigned long value)
old_cr = v->arch.hvm_vcpu.guest_cr[4];
v->arch.hvm_vcpu.guest_cr[4] = value;
hvm_update_guest_cr(v, 4);
-
+
/* Modifying CR4.{PSE,PAE,PGE} invalidates all TLB entries, inc. Global. */
if ( (old_cr ^ value) & (X86_CR4_PSE | X86_CR4_PGE | X86_CR4_PAE) )
paging_update_paging_modes(v);
diff --git a/xen/arch/x86/hvm/irq.c b/xen/arch/x86/hvm/irq.c
index 60b89764db..c19d23724e 100644
--- a/xen/arch/x86/hvm/irq.c
+++ b/xen/arch/x86/hvm/irq.c
@@ -285,49 +285,63 @@ void hvm_set_callback_via(struct domain *d, uint64_t via)
}
}
-enum hvm_intack hvm_vcpu_has_pending_irq(struct vcpu *v)
+struct hvm_intack hvm_vcpu_has_pending_irq(struct vcpu *v)
{
struct hvm_domain *plat = &v->domain->arch.hvm_domain;
+ int vector;
if ( unlikely(v->nmi_pending) )
return hvm_intack_nmi;
- if ( vlapic_has_interrupt(v) != -1 )
- return hvm_intack_lapic;
+ if ( vlapic_accept_pic_intr(v) && plat->vpic[0].int_output )
+ return hvm_intack_pic(0);
- if ( !vlapic_accept_pic_intr(v) )
- return hvm_intack_none;
+ vector = vlapic_has_pending_irq(v);
+ if ( vector != -1 )
+ return hvm_intack_lapic(vector);
- return plat->vpic[0].int_output ? hvm_intack_pic : hvm_intack_none;
+ return hvm_intack_none;
}
-int hvm_vcpu_ack_pending_irq(struct vcpu *v, enum hvm_intack type, int *vector)
+struct hvm_intack hvm_vcpu_ack_pending_irq(
+ struct vcpu *v, struct hvm_intack intack)
{
- switch ( type )
+ int vector;
+
+ switch ( intack.source )
{
- case hvm_intack_nmi:
- return test_and_clear_bool(v->nmi_pending);
- case hvm_intack_lapic:
- return ((*vector = cpu_get_apic_interrupt(v)) != -1);
- case hvm_intack_pic:
+ case hvm_intsrc_nmi:
+ if ( !test_and_clear_bool(v->nmi_pending) )
+ intack = hvm_intack_none;
+ break;
+ case hvm_intsrc_pic:
ASSERT(v->vcpu_id == 0);
- return ((*vector = cpu_get_pic_interrupt(v)) != -1);
+ if ( (vector = vpic_ack_pending_irq(v)) == -1 )
+ intack = hvm_intack_none;
+ else
+ intack.vector = (uint8_t)vector;
+ break;
+ case hvm_intsrc_lapic:
+ if ( !vlapic_ack_pending_irq(v, intack.vector) )
+ intack = hvm_intack_none;
+ break;
default:
+ intack = hvm_intack_none;
break;
}
- return 0;
+ return intack;
}
-int get_isa_irq_vector(struct vcpu *v, int isa_irq, enum hvm_intack src)
+int get_isa_irq_vector(struct vcpu *v, int isa_irq, enum hvm_intsrc src)
{
unsigned int gsi = hvm_isa_irq_to_gsi(isa_irq);
- if ( src == hvm_intack_pic )
+ if ( src == hvm_intsrc_pic )
return (v->domain->arch.hvm_domain.vpic[isa_irq >> 3].irq_base
+ (isa_irq & 7));
- ASSERT(src == hvm_intack_lapic);
+ ASSERT(src == hvm_intsrc_lapic);
return domain_vioapic(v->domain)->redirtbl[gsi].fields.vector;
}
@@ -345,18 +359,18 @@ int is_isa_irq_masked(struct vcpu *v, int isa_irq)
int hvm_local_events_need_delivery(struct vcpu *v)
{
- enum hvm_intack type;
+ struct hvm_intack intack;
/* TODO: Get rid of event-channel special case. */
if ( vcpu_info(v, evtchn_upcall_pending) )
- type = hvm_intack_pic;
+ intack = hvm_intack_pic(0);
else
- type = hvm_vcpu_has_pending_irq(v);
+ intack = hvm_vcpu_has_pending_irq(v);
- if ( likely(type == hvm_intack_none) )
+ if ( likely(intack.source == hvm_intsrc_none) )
return 0;
- return hvm_interrupts_enabled(v, type);
+ return !hvm_interrupt_blocked(v, intack);
}
#if 0 /* Keep for debugging */
diff --git a/xen/arch/x86/hvm/svm/intr.c b/xen/arch/x86/hvm/svm/intr.c
index 7667cf9a31..268f900459 100644
--- a/xen/arch/x86/hvm/svm/intr.c
+++ b/xen/arch/x86/hvm/svm/intr.c
@@ -39,19 +39,6 @@
#include <xen/domain_page.h>
#include <asm/hvm/trace.h>
-static void svm_inject_dummy_vintr(struct vcpu *v)
-{
- struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
- vintr_t intr = vmcb->vintr;
-
- intr.fields.irq = 1;
- intr.fields.intr_masking = 1;
- intr.fields.vector = 0;
- intr.fields.prio = 0xF;
- intr.fields.ign_tpr = 1;
- vmcb->vintr = intr;
-}
-
static void svm_inject_nmi(struct vcpu *v)
{
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
@@ -80,11 +67,14 @@ static void svm_inject_extint(struct vcpu *v, int vector)
vmcb->eventinj = event;
}
-static void enable_intr_window(struct vcpu *v, enum hvm_intack intr_source)
+static void enable_intr_window(struct vcpu *v, struct hvm_intack intack)
{
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
+ vintr_t intr;
+
+ ASSERT(intack.source != hvm_intsrc_none);
- ASSERT(intr_source != hvm_intack_none);
+ HVMTRACE_2D(INJ_VIRQ, v, 0x0, /*fake=*/ 1);
/*
* Create a dummy virtual interrupt to intercept as soon as the
@@ -95,53 +85,29 @@ static void enable_intr_window(struct vcpu *v, enum hvm_intack intr_source)
* track 'NMI blocking' from NMI injection until IRET. This can be done
* quite easily in software by intercepting the unblocking IRET.
*/
+ intr = vmcb->vintr;
+ intr.fields.irq = 1;
+ intr.fields.vector = 0;
+ intr.fields.prio = intack.vector >> 4;
+ intr.fields.ign_tpr = (intack.source != hvm_intsrc_lapic);
+ vmcb->vintr = intr;
vmcb->general1_intercepts |= GENERAL1_INTERCEPT_VINTR;
- HVMTRACE_2D(INJ_VIRQ, v, 0x0, /*fake=*/ 1);
- svm_inject_dummy_vintr(v);
-}
-
-static void update_cr8_intercept(
- struct vcpu *v, enum hvm_intack masked_intr_source)
-{
- struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
- struct vlapic *vlapic = vcpu_vlapic(v);
- int max_irr;
-
- vmcb->cr_intercepts &= ~CR_INTERCEPT_CR8_WRITE;
-
- /*
- * If ExtInts are masked then that dominates the TPR --- the 'interrupt
- * window' has already been enabled in this case.
- */
- if ( (masked_intr_source == hvm_intack_lapic) ||
- (masked_intr_source == hvm_intack_pic) )
- return;
-
- /* Is there an interrupt pending at the LAPIC? Nothing to do if not. */
- if ( !vlapic_enabled(vlapic) ||
- ((max_irr = vlapic_find_highest_irr(vlapic)) == -1) )
- return;
-
- /* Highest-priority pending interrupt is masked by the TPR? */
- if ( (vmcb->vintr.fields.tpr & 0xf) >= (max_irr >> 4) )
- vmcb->cr_intercepts |= CR_INTERCEPT_CR8_WRITE;
}
asmlinkage void svm_intr_assist(void)
{
struct vcpu *v = current;
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
- enum hvm_intack intr_source;
- int intr_vector;
+ struct hvm_intack intack;
/* Crank the handle on interrupt state. */
pt_update_irq(v);
hvm_set_callback_irq_level();
do {
- intr_source = hvm_vcpu_has_pending_irq(v);
- if ( likely(intr_source == hvm_intack_none) )
- goto out;
+ intack = hvm_vcpu_has_pending_irq(v);
+ if ( likely(intack.source == hvm_intsrc_none) )
+ return;
/*
* Pending IRQs must be delayed if:
@@ -158,31 +124,30 @@ asmlinkage void svm_intr_assist(void)
* 2. The IRQ is masked.
*/
if ( unlikely(vmcb->eventinj.fields.v) ||
- !hvm_interrupts_enabled(v, intr_source) )
+ hvm_interrupt_blocked(v, intack) )
{
- enable_intr_window(v, intr_source);
- goto out;
+ enable_intr_window(v, intack);
+ return;
}
- } while ( !hvm_vcpu_ack_pending_irq(v, intr_source, &intr_vector) );
- if ( intr_source == hvm_intack_nmi )
+ intack = hvm_vcpu_ack_pending_irq(v, intack);
+ } while ( intack.source == hvm_intsrc_none );
+
+ if ( intack.source == hvm_intsrc_nmi )
{
svm_inject_nmi(v);
}
else
{
- HVMTRACE_2D(INJ_VIRQ, v, intr_vector, /*fake=*/ 0);
- svm_inject_extint(v, intr_vector);
- pt_intr_post(v, intr_vector, intr_source);
+ HVMTRACE_2D(INJ_VIRQ, v, intack.vector, /*fake=*/ 0);
+ svm_inject_extint(v, intack.vector);
+ pt_intr_post(v, intack);
}
/* Is there another IRQ to queue up behind this one? */
- intr_source = hvm_vcpu_has_pending_irq(v);
- if ( unlikely(intr_source != hvm_intack_none) )
- enable_intr_window(v, intr_source);
-
- out:
- update_cr8_intercept(v, intr_source);
+ intack = hvm_vcpu_has_pending_irq(v);
+ if ( unlikely(intack.source != hvm_intsrc_none) )
+ enable_intr_window(v, intack);
}
/*
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index 90b1eba7cc..5b3288ba03 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -425,16 +425,28 @@ static void svm_restore_dr(struct vcpu *v)
__restore_debug_registers(v);
}
-static int svm_interrupts_enabled(struct vcpu *v, enum hvm_intack type)
+static enum hvm_intblk svm_interrupt_blocked(
+ struct vcpu *v, struct hvm_intack intack)
{
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
- if ( type == hvm_intack_nmi )
- return !vmcb->interrupt_shadow;
+ if ( vmcb->interrupt_shadow )
+ return hvm_intblk_shadow;
- ASSERT((type == hvm_intack_pic) || (type == hvm_intack_lapic));
- return (!irq_masked(guest_cpu_user_regs()->eflags) &&
- !vmcb->interrupt_shadow);
+ if ( intack.source == hvm_intsrc_nmi )
+ return hvm_intblk_none;
+
+ ASSERT((intack.source == hvm_intsrc_pic) ||
+ (intack.source == hvm_intsrc_lapic));
+
+ if ( irq_masked(guest_cpu_user_regs()->eflags) )
+ return hvm_intblk_rflags_ie;
+
+ if ( (intack.source == hvm_intsrc_lapic) &&
+ ((vmcb->vintr.fields.tpr & 0xf) >= (intack.vector >> 4)) )
+ return hvm_intblk_tpr;
+
+ return hvm_intblk_none;
}
static int svm_guest_x86_mode(struct vcpu *v)
@@ -855,7 +867,7 @@ static struct hvm_function_table svm_function_table = {
.vcpu_destroy = svm_vcpu_destroy,
.save_cpu_ctxt = svm_save_vmcb_ctxt,
.load_cpu_ctxt = svm_load_vmcb_ctxt,
- .interrupts_enabled = svm_interrupts_enabled,
+ .interrupt_blocked = svm_interrupt_blocked,
.guest_x86_mode = svm_guest_x86_mode,
.get_segment_base = svm_get_segment_base,
.get_segment_register = svm_get_segment_register,
@@ -1552,7 +1564,6 @@ static void mov_from_cr(int cr, int gp, struct cpu_user_regs *regs)
{
unsigned long value = 0;
struct vcpu *v = current;
- struct vlapic *vlapic = vcpu_vlapic(v);
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
switch ( cr )
@@ -1560,21 +1571,14 @@ static void mov_from_cr(int cr, int gp, struct cpu_user_regs *regs)
case 0:
value = v->arch.hvm_vcpu.guest_cr[0];
break;
- case 2:
- value = vmcb->cr2;
- break;
case 3:
value = (unsigned long)v->arch.hvm_vcpu.guest_cr[3];
break;
case 4:
value = (unsigned long)v->arch.hvm_vcpu.guest_cr[4];
break;
- case 8:
- value = (unsigned long)vlapic_get_reg(vlapic, APIC_TASKPRI);
- value = (value & 0xF0) >> 4;
- break;
-
default:
+ gdprintk(XENLOG_ERR, "invalid cr: %d\n", cr);
domain_crash(v->domain);
return;
}
@@ -1590,7 +1594,6 @@ static int mov_to_cr(int gpreg, int cr, struct cpu_user_regs *regs)
{
unsigned long value;
struct vcpu *v = current;
- struct vlapic *vlapic = vcpu_vlapic(v);
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
value = get_reg(gpreg, regs, vmcb);
@@ -1604,18 +1607,10 @@ static int mov_to_cr(int gpreg, int cr, struct cpu_user_regs *regs)
{
case 0:
return svm_set_cr0(value);
-
case 3:
return hvm_set_cr3(value);
-
case 4:
return hvm_set_cr4(value);
-
- case 8:
- vlapic_set_reg(vlapic, APIC_TASKPRI, ((value & 0x0F) << 4));
- vmcb->vintr.fields.tpr = value & 0x0F;
- break;
-
default:
gdprintk(XENLOG_ERR, "invalid cr: %d\n", cr);
domain_crash(v->domain);
@@ -1894,13 +1889,14 @@ static void svm_do_msr_access(
static void svm_vmexit_do_hlt(struct vmcb_struct *vmcb,
struct cpu_user_regs *regs)
{
- enum hvm_intack type = hvm_vcpu_has_pending_irq(current);
+ struct hvm_intack intack = hvm_vcpu_has_pending_irq(current);
__update_guest_eip(regs, 1);
/* Check for interrupt not handled or new interrupt. */
if ( vmcb->eventinj.fields.v ||
- ((type != hvm_intack_none) && svm_interrupts_enabled(current, type)) )
+ ((intack.source != hvm_intsrc_none) &&
+ !svm_interrupt_blocked(current, intack)) )
{
HVMTRACE_1D(HLT, current, /*int pending=*/ 1);
return;
@@ -2080,13 +2076,11 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs *regs)
/*
* Before doing anything else, we need to sync up the VLAPIC's TPR with
- * SVM's vTPR if CR8 writes are currently disabled. It's OK if the
- * guest doesn't touch the CR8 (e.g. 32-bit Windows) because we update
- * the vTPR on MMIO writes to the TPR
+ * SVM's vTPR. It's OK if the guest doesn't touch CR8 (e.g. 32-bit Windows)
+ * because we update the vTPR on MMIO writes to the TPR.
*/
- if ( !(vmcb->cr_intercepts & CR_INTERCEPT_CR8_WRITE) )
- vlapic_set_reg(vcpu_vlapic(v), APIC_TASKPRI,
- (vmcb->vintr.fields.tpr & 0x0F) << 4);
+ vlapic_set_reg(vcpu_vlapic(v), APIC_TASKPRI,
+ (vmcb->vintr.fields.tpr & 0x0F) << 4);
exit_reason = vmcb->exitcode;
@@ -2222,45 +2216,14 @@ asmlinkage void svm_vmexit_handler(struct cpu_user_regs *regs)
}
break;
- case VMEXIT_CR0_READ:
- svm_cr_access(v, 0, TYPE_MOV_FROM_CR, regs);
- break;
-
- case VMEXIT_CR2_READ:
- svm_cr_access(v, 2, TYPE_MOV_FROM_CR, regs);
- break;
-
- case VMEXIT_CR3_READ:
- svm_cr_access(v, 3, TYPE_MOV_FROM_CR, regs);
- break;
-
- case VMEXIT_CR4_READ:
- svm_cr_access(v, 4, TYPE_MOV_FROM_CR, regs);
- break;
-
- case VMEXIT_CR8_READ:
- svm_cr_access(v, 8, TYPE_MOV_FROM_CR, regs);
- break;
-
- case VMEXIT_CR0_WRITE:
- svm_cr_access(v, 0, TYPE_MOV_TO_CR, regs);
- break;
-
- case VMEXIT_CR2_WRITE:
- svm_cr_access(v, 2, TYPE_MOV_TO_CR, regs);
- break;
-
- case VMEXIT_CR3_WRITE:
- svm_cr_access(v, 3, TYPE_MOV_TO_CR, regs);
- local_flush_tlb();
- break;
-
- case VMEXIT_CR4_WRITE:
- svm_cr_access(v, 4, TYPE_MOV_TO_CR, regs);
+ case VMEXIT_CR0_READ ... VMEXIT_CR15_READ:
+ svm_cr_access(v, exit_reason - VMEXIT_CR0_READ,
+ TYPE_MOV_FROM_CR, regs);
break;
- case VMEXIT_CR8_WRITE:
- svm_cr_access(v, 8, TYPE_MOV_TO_CR, regs);
+ case VMEXIT_CR0_WRITE ... VMEXIT_CR15_WRITE:
+ svm_cr_access(v, exit_reason - VMEXIT_CR0_WRITE,
+ TYPE_MOV_TO_CR, regs);
break;
case VMEXIT_DR0_WRITE ... VMEXIT_DR7_WRITE:
diff --git a/xen/arch/x86/hvm/svm/vmcb.c b/xen/arch/x86/hvm/svm/vmcb.c
index a7d93b003f..d7de03d1cb 100644
--- a/xen/arch/x86/hvm/svm/vmcb.c
+++ b/xen/arch/x86/hvm/svm/vmcb.c
@@ -130,14 +130,11 @@ static int construct_vmcb(struct vcpu *v)
/* Intercept all debug-register writes. */
vmcb->dr_intercepts = DR_INTERCEPT_ALL_WRITES;
- /*
- * Intercept all control-register accesses except for CR2 reads/writes
- * and CR8 reads (and actually CR8 writes, but that's a special case
- * that's handled in svm/intr.c).
- */
+ /* Intercept all control-register accesses except for CR2 and CR8. */
vmcb->cr_intercepts = ~(CR_INTERCEPT_CR2_READ |
CR_INTERCEPT_CR2_WRITE |
- CR_INTERCEPT_CR8_READ);
+ CR_INTERCEPT_CR8_READ |
+ CR_INTERCEPT_CR8_WRITE);
/* I/O and MSR permission bitmaps. */
arch_svm->msrpm = alloc_xenheap_pages(get_order_from_bytes(MSRPM_SIZE));
diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c
index 5d2fc73a36..cc63c89df3 100644
--- a/xen/arch/x86/hvm/vlapic.c
+++ b/xen/arch/x86/hvm/vlapic.c
@@ -732,33 +732,34 @@ int vlapic_accept_pic_intr(struct vcpu *v)
vlapic_hw_disabled(vlapic)));
}
-int vlapic_has_interrupt(struct vcpu *v)
+int vlapic_has_pending_irq(struct vcpu *v)
{
struct vlapic *vlapic = vcpu_vlapic(v);
- int highest_irr;
+ int irr, isr;
if ( !vlapic_enabled(vlapic) )
return -1;
- highest_irr = vlapic_find_highest_irr(vlapic);
- if ( (highest_irr == -1) ||
- ((highest_irr & 0xF0) <= vlapic_get_ppr(vlapic)) )
+ irr = vlapic_find_highest_irr(vlapic);
+ if ( irr == -1 )
return -1;
- return highest_irr;
+ isr = vlapic_find_highest_isr(vlapic);
+ isr = (isr != -1) ? isr : 0;
+ if ( (isr & 0xf0) >= (irr & 0xf0) )
+ return -1;
+
+ return irr;
}
-int cpu_get_apic_interrupt(struct vcpu *v)
+int vlapic_ack_pending_irq(struct vcpu *v, int vector)
{
- int vector = vlapic_has_interrupt(v);
struct vlapic *vlapic = vcpu_vlapic(v);
- if ( vector == -1 )
- return -1;
-
vlapic_set_vector(vector, &vlapic->regs->data[APIC_ISR]);
vlapic_clear_irr(vector, vlapic);
- return vector;
+
+ return 1;
}
/* Reset the VLPAIC back to its power-on/reset state. */
diff --git a/xen/arch/x86/hvm/vmx/intr.c b/xen/arch/x86/hvm/vmx/intr.c
index 1fdad07c3d..d10910f62a 100644
--- a/xen/arch/x86/hvm/vmx/intr.c
+++ b/xen/arch/x86/hvm/vmx/intr.c
@@ -71,14 +71,14 @@
* the effect is cleared. (i.e., MOV-SS-blocking 'dominates' STI-blocking).
*/
-static void enable_intr_window(struct vcpu *v, enum hvm_intack intr_source)
+static void enable_intr_window(struct vcpu *v, struct hvm_intack intack)
{
u32 *cpu_exec_control = &v->arch.hvm_vmx.exec_control;
u32 ctl = CPU_BASED_VIRTUAL_INTR_PENDING;
- ASSERT(intr_source != hvm_intack_none);
+ ASSERT(intack.source != hvm_intsrc_none);
- if ( (intr_source == hvm_intack_nmi) && cpu_has_vmx_vnmi )
+ if ( (intack.source == hvm_intsrc_nmi) && cpu_has_vmx_vnmi )
{
/*
* We set MOV-SS blocking in lieu of STI blocking when delivering an
@@ -107,37 +107,6 @@ static void enable_intr_window(struct vcpu *v, enum hvm_intack intr_source)
}
}
-static void update_tpr_threshold(
- struct vcpu *v, enum hvm_intack masked_intr_source)
-{
- struct vlapic *vlapic = vcpu_vlapic(v);
- int max_irr, tpr, threshold = 0;
-
- if ( !cpu_has_vmx_tpr_shadow )
- return;
-
- /*
- * If ExtInts are masked then that dominates the TPR --- the 'interrupt
- * window' has already been enabled in this case.
- */
- if ( (masked_intr_source == hvm_intack_lapic) ||
- (masked_intr_source == hvm_intack_pic) )
- goto out;
-
- /* Is there an interrupt pending at the LAPIC? Nothing to do if not. */
- if ( !vlapic_enabled(vlapic) ||
- ((max_irr = vlapic_find_highest_irr(vlapic)) == -1) )
- goto out;
-
- /* Highest-priority pending interrupt is masked by the TPR? */
- tpr = vlapic_get_reg(vlapic, APIC_TASKPRI) & 0xF0;
- if ( (tpr >> 4) >= (max_irr >> 4) )
- threshold = max_irr >> 4;
-
- out:
- __vmwrite(TPR_THRESHOLD, threshold);
-}
-
static void vmx_dirq_assist(struct domain *d)
{
unsigned int irq;
@@ -157,10 +126,10 @@ static void vmx_dirq_assist(struct domain *d)
asmlinkage void vmx_intr_assist(void)
{
- int intr_vector;
- enum hvm_intack intr_source;
+ struct hvm_intack intack;
struct vcpu *v = current;
- unsigned int intr_info;
+ unsigned int tpr_threshold = 0;
+ enum hvm_intblk intblk;
/* Crank the handle on interrupt state. */
pt_update_irq(v);
@@ -171,41 +140,48 @@ asmlinkage void vmx_intr_assist(void)
hvm_set_callback_irq_level();
do {
- intr_source = hvm_vcpu_has_pending_irq(v);
- if ( likely(intr_source == hvm_intack_none) )
+ intack = hvm_vcpu_has_pending_irq(v);
+ if ( likely(intack.source == hvm_intsrc_none) )
goto out;
- /*
- * An event is already pending or the pending interrupt is masked?
- * Then the pending interrupt must be delayed.
- */
- intr_info = __vmread(VM_ENTRY_INTR_INFO);
- if ( unlikely(intr_info & INTR_INFO_VALID_MASK) ||
- !hvm_interrupts_enabled(v, intr_source) )
+ intblk = hvm_interrupt_blocked(v, intack);
+ if ( intblk == hvm_intblk_tpr )
+ {
+ ASSERT(vlapic_enabled(vcpu_vlapic(v)));
+ ASSERT(intack.source == hvm_intsrc_lapic);
+ tpr_threshold = intack.vector >> 4;
+ goto out;
+ }
+
+ if ( (intblk != hvm_intblk_none) ||
+ (__vmread(VM_ENTRY_INTR_INFO) & INTR_INFO_VALID_MASK) )
{
- enable_intr_window(v, intr_source);
+ enable_intr_window(v, intack);
goto out;
}
- } while ( !hvm_vcpu_ack_pending_irq(v, intr_source, &intr_vector) );
- if ( intr_source == hvm_intack_nmi )
+ intack = hvm_vcpu_ack_pending_irq(v, intack);
+ } while ( intack.source == hvm_intsrc_none );
+
+ if ( intack.source == hvm_intsrc_nmi )
{
vmx_inject_nmi(v);
}
else
{
- HVMTRACE_2D(INJ_VIRQ, v, intr_vector, /*fake=*/ 0);
- vmx_inject_extint(v, intr_vector);
- pt_intr_post(v, intr_vector, intr_source);
+ HVMTRACE_2D(INJ_VIRQ, v, intack.vector, /*fake=*/ 0);
+ vmx_inject_extint(v, intack.vector);
+ pt_intr_post(v, intack);
}
/* Is there another IRQ to queue up behind this one? */
- intr_source = hvm_vcpu_has_pending_irq(v);
- if ( unlikely(intr_source != hvm_intack_none) )
- enable_intr_window(v, intr_source);
+ intack = hvm_vcpu_has_pending_irq(v);
+ if ( unlikely(intack.source != hvm_intsrc_none) )
+ enable_intr_window(v, intack);
out:
- update_tpr_threshold(v, intr_source);
+ if ( cpu_has_vmx_tpr_shadow )
+ __vmwrite(TPR_THRESHOLD, tpr_threshold);
}
/*
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index 0a18ee2631..b56d765092 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -975,20 +975,34 @@ static void vmx_init_hypercall_page(struct domain *d, void *hypercall_page)
*(u16 *)(hypercall_page + (__HYPERVISOR_iret * 32)) = 0x0b0f; /* ud2 */
}
-static int vmx_interrupts_enabled(struct vcpu *v, enum hvm_intack type)
+static enum hvm_intblk vmx_interrupt_blocked(
+ struct vcpu *v, struct hvm_intack intack)
{
unsigned long intr_shadow;
intr_shadow = __vmread(GUEST_INTERRUPTIBILITY_INFO);
- if ( type == hvm_intack_nmi )
- return !(intr_shadow & (VMX_INTR_SHADOW_STI|
- VMX_INTR_SHADOW_MOV_SS|
- VMX_INTR_SHADOW_NMI));
+ if ( intr_shadow & (VMX_INTR_SHADOW_STI|VMX_INTR_SHADOW_MOV_SS) )
+ return hvm_intblk_shadow;
- ASSERT((type == hvm_intack_pic) || (type == hvm_intack_lapic));
- return (!irq_masked(guest_cpu_user_regs()->eflags) &&
- !(intr_shadow & (VMX_INTR_SHADOW_STI|VMX_INTR_SHADOW_MOV_SS)));
+ if ( intack.source == hvm_intsrc_nmi )
+ return ((intr_shadow & VMX_INTR_SHADOW_NMI) ?
+ hvm_intblk_nmi_iret : hvm_intblk_none);
+
+ ASSERT((intack.source == hvm_intsrc_pic) ||
+ (intack.source == hvm_intsrc_lapic));
+
+ if ( irq_masked(guest_cpu_user_regs()->eflags) )
+ return hvm_intblk_rflags_ie;
+
+ if ( intack.source == hvm_intsrc_lapic )
+ {
+ uint32_t tpr = vlapic_get_reg(vcpu_vlapic(v), APIC_TASKPRI) & 0xF0;
+ if ( (tpr >> 4) >= (intack.vector >> 4) )
+ return hvm_intblk_tpr;
+ }
+
+ return hvm_intblk_none;
}
static void vmx_update_host_cr3(struct vcpu *v)
@@ -1112,7 +1126,7 @@ static struct hvm_function_table vmx_function_table = {
.vcpu_destroy = vmx_vcpu_destroy,
.save_cpu_ctxt = vmx_save_vmcs_ctxt,
.load_cpu_ctxt = vmx_load_vmcs_ctxt,
- .interrupts_enabled = vmx_interrupts_enabled,
+ .interrupt_blocked = vmx_interrupt_blocked,
.guest_x86_mode = vmx_guest_x86_mode,
.get_segment_base = vmx_get_segment_base,
.get_segment_register = vmx_get_segment_register,
diff --git a/xen/arch/x86/hvm/vpic.c b/xen/arch/x86/hvm/vpic.c
index 1ac08320fa..ba264bb163 100644
--- a/xen/arch/x86/hvm/vpic.c
+++ b/xen/arch/x86/hvm/vpic.c
@@ -503,7 +503,7 @@ void vpic_irq_negative_edge(struct domain *d, int irq)
vpic_update_int_output(vpic);
}
-int cpu_get_pic_interrupt(struct vcpu *v)
+int vpic_ack_pending_irq(struct vcpu *v)
{
int irq, vector;
struct hvm_hw_vpic *vpic = &v->domain->arch.hvm_domain.vpic[0];
diff --git a/xen/arch/x86/hvm/vpt.c b/xen/arch/x86/hvm/vpt.c
index 13124f1750..5ca2968d3c 100644
--- a/xen/arch/x86/hvm/vpt.c
+++ b/xen/arch/x86/hvm/vpt.c
@@ -165,12 +165,12 @@ void pt_update_irq(struct vcpu *v)
}
static struct periodic_time *is_pt_irq(
- struct vcpu *v, int vector, enum hvm_intack src)
+ struct vcpu *v, struct hvm_intack intack)
{
struct list_head *head = &v->arch.hvm_vcpu.tm_list;
struct periodic_time *pt;
struct RTCState *rtc = &v->domain->arch.hvm_domain.pl_time.vrtc;
- int vec;
+ int vector;
list_for_each_entry ( pt, head, list )
{
@@ -179,15 +179,16 @@ static struct periodic_time *is_pt_irq(
if ( is_lvtt(v, pt->irq) )
{
- if ( pt->irq != vector )
+ if ( pt->irq != intack.vector )
continue;
return pt;
}
- vec = get_isa_irq_vector(v, pt->irq, src);
+ vector = get_isa_irq_vector(v, pt->irq, intack.source);
/* RTC irq need special care */
- if ( (vector != vec) || (pt->irq == 8 && !is_rtc_periodic_irq(rtc)) )
+ if ( (intack.vector != vector) ||
+ ((pt->irq == 8) && !is_rtc_periodic_irq(rtc)) )
continue;
return pt;
@@ -196,7 +197,7 @@ static struct periodic_time *is_pt_irq(
return NULL;
}
-void pt_intr_post(struct vcpu *v, int vector, enum hvm_intack src)
+void pt_intr_post(struct vcpu *v, struct hvm_intack intack)
{
struct periodic_time *pt;
time_cb *cb;
@@ -204,7 +205,7 @@ void pt_intr_post(struct vcpu *v, int vector, enum hvm_intack src)
spin_lock(&v->arch.hvm_vcpu.tm_lock);
- pt = is_pt_irq(v, vector, src);
+ pt = is_pt_irq(v, intack);
if ( pt == NULL )
{
spin_unlock(&v->arch.hvm_vcpu.tm_lock);
diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h
index e1af3c20be..52a59fc463 100644
--- a/xen/include/asm-x86/hvm/hvm.h
+++ b/xen/include/asm-x86/hvm/hvm.h
@@ -57,11 +57,26 @@ typedef struct segment_register {
} __attribute__ ((packed)) segment_register_t;
/* Interrupt acknowledgement sources. */
-enum hvm_intack {
- hvm_intack_none,
- hvm_intack_pic,
- hvm_intack_lapic,
- hvm_intack_nmi
+enum hvm_intsrc {
+ hvm_intsrc_none,
+ hvm_intsrc_pic,
+ hvm_intsrc_lapic,
+ hvm_intsrc_nmi
+};
+struct hvm_intack {
+ uint8_t source; /* enum hvm_intsrc */
+ uint8_t vector;
+};
+#define hvm_intack_none ( (struct hvm_intack) { hvm_intsrc_none, 0 } )
+#define hvm_intack_pic(vec) ( (struct hvm_intack) { hvm_intsrc_pic, vec } )
+#define hvm_intack_lapic(vec) ( (struct hvm_intack) { hvm_intsrc_lapic, vec } )
+#define hvm_intack_nmi ( (struct hvm_intack) { hvm_intsrc_nmi, 2 } )
+enum hvm_intblk {
+ hvm_intblk_none, /* not blocked (deliverable) */
+ hvm_intblk_shadow, /* MOV-SS or STI shadow */
+ hvm_intblk_rflags_ie, /* RFLAGS.IE == 0 */
+ hvm_intblk_tpr, /* LAPIC TPR too high */
+ hvm_intblk_nmi_iret /* NMI blocked until IRET */
};
/*
@@ -94,7 +109,7 @@ struct hvm_function_table {
* 3) return the current guest segment descriptor base
* 4) return the current guest segment descriptor
*/
- int (*interrupts_enabled)(struct vcpu *v, enum hvm_intack);
+ enum hvm_intblk (*interrupt_blocked)(struct vcpu *v, struct hvm_intack);
int (*guest_x86_mode)(struct vcpu *v);
unsigned long (*get_segment_base)(struct vcpu *v, enum x86_segment seg);
void (*get_segment_register)(struct vcpu *v, enum x86_segment seg,
@@ -177,11 +192,11 @@ u64 hvm_get_guest_time(struct vcpu *v);
#define hvm_long_mode_enabled(v) (v,0)
#endif
-static inline int
-hvm_interrupts_enabled(struct vcpu *v, enum hvm_intack type)
+static inline enum hvm_intblk
+hvm_interrupt_blocked(struct vcpu *v, struct hvm_intack intack)
{
ASSERT(v == current);
- return hvm_funcs.interrupts_enabled(v, type);
+ return hvm_funcs.interrupt_blocked(v, intack);
}
static inline int
diff --git a/xen/include/asm-x86/hvm/irq.h b/xen/include/asm-x86/hvm/irq.h
index 142aeadd41..829b1266e2 100644
--- a/xen/include/asm-x86/hvm/irq.h
+++ b/xen/include/asm-x86/hvm/irq.h
@@ -135,11 +135,11 @@ void hvm_set_callback_irq_level(void);
void hvm_set_callback_via(struct domain *d, uint64_t via);
/* Check/Acknowledge next pending interrupt. */
-enum hvm_intack hvm_vcpu_has_pending_irq(struct vcpu *v);
-int hvm_vcpu_ack_pending_irq(
- struct vcpu *v, enum hvm_intack type, int *vector);
+struct hvm_intack hvm_vcpu_has_pending_irq(struct vcpu *v);
+struct hvm_intack hvm_vcpu_ack_pending_irq(struct vcpu *v,
+ struct hvm_intack intack);
-int get_isa_irq_vector(struct vcpu *vcpu, int irq, enum hvm_intack src);
+int get_isa_irq_vector(struct vcpu *vcpu, int irq, enum hvm_intsrc src);
int is_isa_irq_masked(struct vcpu *v, int isa_irq);
#endif /* __ASM_X86_HVM_IRQ_H__ */
diff --git a/xen/include/asm-x86/hvm/vlapic.h b/xen/include/asm-x86/hvm/vlapic.h
index ca09df2bcb..856b532637 100644
--- a/xen/include/asm-x86/hvm/vlapic.h
+++ b/xen/include/asm-x86/hvm/vlapic.h
@@ -75,8 +75,8 @@ int vlapic_set_irq(struct vlapic *vlapic, uint8_t vec, uint8_t trig);
int vlapic_find_highest_irr(struct vlapic *vlapic);
-int vlapic_has_interrupt(struct vcpu *v);
-int cpu_get_apic_interrupt(struct vcpu *v);
+int vlapic_has_pending_irq(struct vcpu *v);
+int vlapic_ack_pending_irq(struct vcpu *v, int vector);
int vlapic_init(struct vcpu *v);
void vlapic_destroy(struct vcpu *v);
diff --git a/xen/include/asm-x86/hvm/vpic.h b/xen/include/asm-x86/hvm/vpic.h
index 59dad65c24..15a34966d6 100644
--- a/xen/include/asm-x86/hvm/vpic.h
+++ b/xen/include/asm-x86/hvm/vpic.h
@@ -32,7 +32,7 @@
void vpic_irq_positive_edge(struct domain *d, int irq);
void vpic_irq_negative_edge(struct domain *d, int irq);
void vpic_init(struct domain *d);
-int cpu_get_pic_interrupt(struct vcpu *v);
+int vpic_ack_pending_irq(struct vcpu *v);
int is_periodic_irq(struct vcpu *v, int irq, int type);
#endif /* __ASM_X86_HVM_VPIC_H__ */
diff --git a/xen/include/asm-x86/hvm/vpt.h b/xen/include/asm-x86/hvm/vpt.h
index 929fd4b306..bb25818ae8 100644
--- a/xen/include/asm-x86/hvm/vpt.h
+++ b/xen/include/asm-x86/hvm/vpt.h
@@ -120,7 +120,7 @@ struct pl_time { /* platform time */
void pt_freeze_time(struct vcpu *v);
void pt_thaw_time(struct vcpu *v);
void pt_update_irq(struct vcpu *v);
-void pt_intr_post(struct vcpu *v, int vector, enum hvm_intack src);
+void pt_intr_post(struct vcpu *v, struct hvm_intack intack);
void pt_reset(struct vcpu *v);
void pt_migrate(struct vcpu *v);
void create_periodic_time(