diff options
-rw-r--r-- | xen/arch/x86/hvm/irq.c | 2 | ||||
-rw-r--r-- | xen/arch/x86/hvm/vlapic.c | 20 | ||||
-rw-r--r-- | xen/arch/x86/hvm/vmx/intr.c | 4 | ||||
-rw-r--r-- | xen/arch/x86/hvm/vmx/vmx.c | 14 | ||||
-rw-r--r-- | xen/arch/x86/hvm/vmx/vvmx.c | 33 | ||||
-rw-r--r-- | xen/include/asm-x86/hvm/vlapic.h | 3 | ||||
-rw-r--r-- | xen/include/asm-x86/hvm/vmx/vmx.h | 2 | ||||
-rw-r--r-- | xen/include/asm-x86/hvm/vmx/vvmx.h | 1 |
8 files changed, 62 insertions, 17 deletions
diff --git a/xen/arch/x86/hvm/irq.c b/xen/arch/x86/hvm/irq.c index 9eae5de21a..6a6fb68eab 100644 --- a/xen/arch/x86/hvm/irq.c +++ b/xen/arch/x86/hvm/irq.c @@ -437,7 +437,7 @@ struct hvm_intack hvm_vcpu_ack_pending_irq( intack.vector = (uint8_t)vector; break; case hvm_intsrc_lapic: - if ( !vlapic_ack_pending_irq(v, intack.vector) ) + if ( !vlapic_ack_pending_irq(v, intack.vector, 0) ) intack = hvm_intack_none; break; case hvm_intsrc_vector: diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c index 7ea0475000..26f2c893d3 100644 --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -168,6 +168,14 @@ static uint32_t vlapic_get_ppr(struct vlapic *vlapic) return ppr; } +uint32_t vlapic_set_ppr(struct vlapic *vlapic) +{ + uint32_t ppr = vlapic_get_ppr(vlapic); + + vlapic_set_reg(vlapic, APIC_PROCPRI, ppr); + return ppr; +} + static int vlapic_match_logical_addr(struct vlapic *vlapic, uint8_t mda) { int result = 0; @@ -1048,15 +1056,15 @@ int vlapic_has_pending_irq(struct vcpu *v) return irr; } -int vlapic_ack_pending_irq(struct vcpu *v, int vector) +int vlapic_ack_pending_irq(struct vcpu *v, int vector, bool_t force_ack) { struct vlapic *vlapic = vcpu_vlapic(v); - if ( vlapic_virtual_intr_delivery_enabled() ) - return 1; - - vlapic_set_vector(vector, &vlapic->regs->data[APIC_ISR]); - vlapic_clear_irr(vector, vlapic); + if ( force_ack || !vlapic_virtual_intr_delivery_enabled() ) + { + vlapic_set_vector(vector, &vlapic->regs->data[APIC_ISR]); + vlapic_clear_irr(vector, vlapic); + } return 1; } diff --git a/xen/arch/x86/hvm/vmx/intr.c b/xen/arch/x86/hvm/vmx/intr.c index cab91094f4..45942ab43a 100644 --- a/xen/arch/x86/hvm/vmx/intr.c +++ b/xen/arch/x86/hvm/vmx/intr.c @@ -185,7 +185,7 @@ static int nvmx_intr_intercept(struct vcpu *v, struct hvm_intack intack) if ( !(ctrl & PIN_BASED_EXT_INTR_MASK) ) return 0; - vmx_inject_extint(intack.vector); + vmx_inject_extint(intack.vector, intack.source); ctrl = __get_vvmcs(vcpu_nestedhvm(v).nv_vvmcx, VM_EXIT_CONTROLS); if ( ctrl & VM_EXIT_ACK_INTR_ON_EXIT ) @@ -314,7 +314,7 @@ void vmx_intr_assist(void) else { HVMTRACE_2D(INJ_VIRQ, intack.vector, /*fake=*/ 0); - vmx_inject_extint(intack.vector); + vmx_inject_extint(intack.vector, intack.source); pt_intr_post(v, intack); } diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 059d258d2d..fa9e79ecb5 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -1205,7 +1205,7 @@ static void vmx_update_guest_efer(struct vcpu *v) } void nvmx_enqueue_n2_exceptions(struct vcpu *v, - unsigned long intr_fields, int error_code) + unsigned long intr_fields, int error_code, uint8_t source) { struct nestedvmx *nvmx = &vcpu_2_nvmx(v); @@ -1213,6 +1213,7 @@ void nvmx_enqueue_n2_exceptions(struct vcpu *v, /* enqueue the exception till the VMCS switch back to L1 */ nvmx->intr.intr_info = intr_fields; nvmx->intr.error_code = error_code; + nvmx->intr.source = source; vcpu_nestedhvm(v).nv_vmexit_pending = 1; return; } @@ -1224,7 +1225,8 @@ void nvmx_enqueue_n2_exceptions(struct vcpu *v, static int nvmx_vmexit_trap(struct vcpu *v, struct hvm_trap *trap) { - nvmx_enqueue_n2_exceptions(v, trap->vector, trap->error_code); + nvmx_enqueue_n2_exceptions(v, trap->vector, trap->error_code, + hvm_intsrc_none); return NESTEDHVM_VMEXIT_DONE; } @@ -1255,7 +1257,7 @@ static void __vmx_inject_exception(int trap, int type, int error_code) curr->arch.hvm_vmx.vmx_emulate = 1; } -void vmx_inject_extint(int trap) +void vmx_inject_extint(int trap, uint8_t source) { struct vcpu *v = current; u32 pin_based_cntrl; @@ -1266,7 +1268,7 @@ void vmx_inject_extint(int trap) if ( pin_based_cntrl & PIN_BASED_EXT_INTR_MASK ) { nvmx_enqueue_n2_exceptions (v, INTR_INFO_VALID_MASK | (X86_EVENTTYPE_EXT_INTR<<8) | trap, - HVM_DELIVER_NO_ERROR_CODE); + HVM_DELIVER_NO_ERROR_CODE, source); return; } } @@ -1285,7 +1287,7 @@ void vmx_inject_nmi(void) if ( pin_based_cntrl & PIN_BASED_NMI_EXITING ) { nvmx_enqueue_n2_exceptions (v, INTR_INFO_VALID_MASK | (X86_EVENTTYPE_NMI<<8) | TRAP_nmi, - HVM_DELIVER_NO_ERROR_CODE); + HVM_DELIVER_NO_ERROR_CODE, hvm_intsrc_nmi); return; } } @@ -1353,7 +1355,7 @@ static void vmx_inject_trap(struct hvm_trap *trap) { nvmx_enqueue_n2_exceptions (curr, INTR_INFO_VALID_MASK | (_trap.type<<8) | _trap.vector, - _trap.error_code); + _trap.error_code, hvm_intsrc_none); return; } else diff --git a/xen/arch/x86/hvm/vmx/vvmx.c b/xen/arch/x86/hvm/vmx/vvmx.c index 0dc567a972..cecc72f053 100644 --- a/xen/arch/x86/hvm/vmx/vvmx.c +++ b/xen/arch/x86/hvm/vmx/vvmx.c @@ -1295,6 +1295,36 @@ static void sync_exception_state(struct vcpu *v) } } +static void nvmx_update_apicv(struct vcpu *v) +{ + struct nestedvmx *nvmx = &vcpu_2_nvmx(v); + struct nestedvcpu *nvcpu = &vcpu_nestedhvm(v); + unsigned long reason = __get_vvmcs(nvcpu->nv_vvmcx, VM_EXIT_REASON); + uint32_t intr_info = __get_vvmcs(nvcpu->nv_vvmcx, VM_EXIT_INTR_INFO); + + if ( reason == EXIT_REASON_EXTERNAL_INTERRUPT && + nvmx->intr.source == hvm_intsrc_lapic && + (intr_info & INTR_INFO_VALID_MASK) ) + { + uint16_t status; + uint32_t rvi, ppr; + uint32_t vector = intr_info & 0xff; + struct vlapic *vlapic = vcpu_vlapic(v); + + vlapic_ack_pending_irq(v, vector, 1); + + ppr = vlapic_set_ppr(vlapic); + WARN_ON((ppr & 0xf0) != (vector & 0xf0)); + + status = vector << 8; + rvi = vlapic_has_pending_irq(v); + if ( rvi != -1 ) + status |= rvi & 0xff; + + __vmwrite(GUEST_INTR_STATUS, status); + } +} + static void virtual_vmexit(struct cpu_user_regs *regs) { struct vcpu *v = current; @@ -1340,6 +1370,9 @@ static void virtual_vmexit(struct cpu_user_regs *regs) /* updating host cr0 to sync TS bit */ __vmwrite(HOST_CR0, v->arch.hvm_vmx.host_cr0); + if ( cpu_has_vmx_virtual_intr_delivery ) + nvmx_update_apicv(v); + vmreturn(regs, VMSUCCEED); } diff --git a/xen/include/asm-x86/hvm/vlapic.h b/xen/include/asm-x86/hvm/vlapic.h index 3277125a4b..4ef0570342 100644 --- a/xen/include/asm-x86/hvm/vlapic.h +++ b/xen/include/asm-x86/hvm/vlapic.h @@ -98,7 +98,7 @@ bool_t is_vlapic_lvtpc_enabled(struct vlapic *vlapic); void vlapic_set_irq(struct vlapic *vlapic, uint8_t vec, uint8_t trig); int vlapic_has_pending_irq(struct vcpu *v); -int vlapic_ack_pending_irq(struct vcpu *v, int vector); +int vlapic_ack_pending_irq(struct vcpu *v, int vector, bool_t force_ack); int vlapic_init(struct vcpu *v); void vlapic_destroy(struct vcpu *v); @@ -110,6 +110,7 @@ void vlapic_tdt_msr_set(struct vlapic *vlapic, uint64_t value); uint64_t vlapic_tdt_msr_get(struct vlapic *vlapic); int vlapic_accept_pic_intr(struct vcpu *v); +uint32_t vlapic_set_ppr(struct vlapic *vlapic); void vlapic_adjust_i8259_target(struct domain *d); diff --git a/xen/include/asm-x86/hvm/vmx/vmx.h b/xen/include/asm-x86/hvm/vmx/vmx.h index c33b9f9a7e..f4d759bd5a 100644 --- a/xen/include/asm-x86/hvm/vmx/vmx.h +++ b/xen/include/asm-x86/hvm/vmx/vmx.h @@ -448,7 +448,7 @@ static inline int __vmxon(u64 addr) void vmx_get_segment_register(struct vcpu *, enum x86_segment, struct segment_register *); -void vmx_inject_extint(int trap); +void vmx_inject_extint(int trap, uint8_t source); void vmx_inject_nmi(void); int ept_p2m_init(struct p2m_domain *p2m); diff --git a/xen/include/asm-x86/hvm/vmx/vvmx.h b/xen/include/asm-x86/hvm/vmx/vvmx.h index 3874525c1a..848be75796 100644 --- a/xen/include/asm-x86/hvm/vmx/vvmx.h +++ b/xen/include/asm-x86/hvm/vmx/vvmx.h @@ -36,6 +36,7 @@ struct nestedvmx { struct { unsigned long intr_info; u32 error_code; + u8 source; } intr; struct { bool_t enabled; |