# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1206529446 0
# Node ID ced23158093a48a85c2538272b882643eac2de40
# Parent 5d25187bac941611a8a836b668a398a72df0afb0
hvm: Correctly combine hardware exceptions when one is raised during
attempted delivery of another.
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
xen/arch/x86/hvm/hvm.c | 52 +++++++++++++++++++++++++++++++++++
xen/arch/x86/hvm/svm/svm.c | 10 ++++++
xen/arch/x86/hvm/vmx/vmx.c | 56 ++++++++++++++++++++++++++++++++++++++
xen/include/asm-x86/hvm/hvm.h | 29 ++-----------------
xen/include/asm-x86/hvm/vmx/vmx.h | 47 ++-----------------------------
5 files changed, 123 insertions(+), 71 deletions(-)
diff -r 5d25187bac94 -r ced23158093a xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c Wed Mar 26 10:14:50 2008 +0000
+++ b/xen/arch/x86/hvm/hvm.c Wed Mar 26 11:04:06 2008 +0000
@@ -79,6 +79,58 @@ void hvm_enable(struct hvm_function_tabl
if ( hvm_funcs.hap_supported )
printk("HVM: Hardware Assisted Paging detected.\n");
+}
+
+/*
+ * Need to re-inject a given event? We avoid re-injecting software exceptions
+ * and interrupts because the faulting/trapping instruction can simply be
+ * re-executed (neither VMX nor SVM update RIP when they VMEXIT during
+ * INT3/INTO/INTn).
+ */
+int hvm_event_needs_reinjection(uint8_t type, uint8_t vector)
+{
+ switch ( type )
+ {
+ case X86_EVENTTYPE_EXT_INTR:
+ case X86_EVENTTYPE_NMI:
+ return 1;
+ case X86_EVENTTYPE_HW_EXCEPTION:
+ /*
+ * SVM uses type 3 ("HW Exception") for #OF and #BP. We explicitly
+ * check for these vectors, as they are really SW Exceptions. SVM has
+ * not updated RIP to point after the trapping instruction (INT3/INTO).
+ */
+ return (vector != 3) && (vector != 4);
+ default:
+ /* Software exceptions/interrupts can be re-executed (e.g., INT n). */
+ break;
+ }
+ return 0;
+}
+
+/*
+ * Combine two hardware exceptions: @vec2 was raised during delivery of @vec1.
+ * This means we can assume that @vec2 is contributory or a page fault.
+ */
+uint8_t hvm_combine_hw_exceptions(uint8_t vec1, uint8_t vec2)
+{
+ /* Exception during double-fault delivery always causes a triple fault. */
+ if ( vec1 == TRAP_double_fault )
+ {
+ hvm_triple_fault();
+ return TRAP_double_fault; /* dummy return */
+ }
+
+ /* Exception during page-fault delivery always causes a double fault. */
+ if ( vec1 == TRAP_page_fault )
+ return TRAP_double_fault;
+
+ /* Discard the first exception if it's benign or if we now have a #PF. */
+ if ( !((1u << vec1) & 0x7c01u) || (vec2 == TRAP_page_fault) )
+ return vec2;
+
+ /* Cannot combine the exceptions: double fault. */
+ return TRAP_double_fault;
}
void hvm_set_guest_tsc(struct vcpu *v, u64 guest_tsc)
diff -r 5d25187bac94 -r ced23158093a xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c Wed Mar 26 10:14:50 2008 +0000
+++ b/xen/arch/x86/hvm/svm/svm.c Wed Mar 26 11:04:06 2008 +0000
@@ -725,7 +725,15 @@ static void svm_inject_exception(
{
struct vcpu *curr = current;
struct vmcb_struct *vmcb = curr->arch.hvm_svm.vmcb;
- eventinj_t event;
+ eventinj_t event = vmcb->eventinj;
+
+ if ( unlikely(event.fields.v) &&
+ (event.fields.type == X86_EVENTTYPE_HW_EXCEPTION) )
+ {
+ trapnr = hvm_combine_hw_exceptions(event.fields.vector, trapnr);
+ if ( trapnr == TRAP_double_fault )
+ errcode = 0;
+ }
event.bytes = 0;
event.fields.v = 1;
diff -r 5d25187bac94 -r ced23158093a xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c Wed Mar 26 10:14:50 2008 +0000
+++ b/xen/arch/x86/hvm/vmx/vmx.c Wed Mar 26 11:04:06 2008 +0000
@@ -983,6 +983,62 @@ static void vmx_flush_guest_tlbs(void)
* because VMRESUME will flush it for us. */
}
+
+
+static void __vmx_inject_exception(
+ struct vcpu *v, int trap, int type, int error_code)
+{
+ unsigned long intr_fields;
+
+ /*
+ * NB. Callers do not need to worry about clearing STI/MOV-SS blocking:
+ * "If the VM entry is injecting, there is no blocking by STI or by
+ * MOV SS following the VM entry, regardless of the contents of the
+ * interruptibility-state field [in the guest-state area before the
+ * VM entry]", PRM Vol. 3, 22.6.1 (Interruptibility State).
+ */
+
+ intr_fields = (INTR_INFO_VALID_MASK | (type<<8) | trap);
+ if ( error_code != HVM_DELIVER_NO_ERROR_CODE ) {
+ __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
+ intr_fields |= INTR_INFO_DELIVER_CODE_MASK;
+ }
+
+ __vmwrite(VM_ENTRY_INTR_INFO, intr_fields);
+
+ if ( trap == TRAP_page_fault )
+ HVMTRACE_2D(PF_INJECT, v, v->arch.hvm_vcpu.guest_cr[2], error_code);
+ else
+ HVMTRACE_2D(INJ_EXC, v, trap, error_code);
+}
+
+void vmx_inject_hw_exception(struct vcpu *v, int trap, int error_code)
+{
+ unsigned long intr_info = __vmread(VM_ENTRY_INTR_INFO);
+
+ if ( unlikely(intr_info & INTR_INFO_VALID_MASK) &&
+ (((intr_info >> 8) & 7) == X86_EVENTTYPE_HW_EXCEPTION) )
+ {
+ trap = hvm_combine_hw_exceptions((uint8_t)intr_info, trap);
+ if ( trap == TRAP_double_fault )
+ error_code = 0;
+ }
+
+ __vmx_inject_exception(v, trap, X86_EVENTTYPE_HW_EXCEPTION, error_code);
+}
+
+void vmx_inject_extint(struct vcpu *v, int trap)
+{
+ __vmx_inject_exception(v, trap, X86_EVENTTYPE_EXT_INTR,
+ HVM_DELIVER_NO_ERROR_CODE);
+}
+
+void vmx_inject_nmi(struct vcpu *v)
+{
+ __vmx_inject_exception(v, 2, X86_EVENTTYPE_NMI,
+ HVM_DELIVER_NO_ERROR_CODE);
+}
+
static void vmx_inject_exception(
unsigned int trapnr, int errcode, unsigned long cr2)
{
diff -r 5d25187bac94 -r ced23158093a xen/include/asm-x86/hvm/hvm.h
--- a/xen/include/asm-x86/hvm/hvm.h Wed Mar 26 10:14:50 2008 +0000
+++ b/xen/include/asm-x86/hvm/hvm.h Wed Mar 26 11:04:06 2008 +0000
@@ -270,32 +270,9 @@ static inline int hvm_do_pmu_interrupt(s
#define X86_EVENTTYPE_SW_INTERRUPT 4 /* software interrupt */
#define X86_EVENTTYPE_SW_EXCEPTION 6 /* software exception */
-/*
- * Need to re-inject a given event? We avoid re-injecting software exceptions
- * and interrupts because the faulting/trapping instruction can simply be
- * re-executed (neither VMX nor SVM update RIP when they VMEXIT during
- * INT3/INTO/INTn).
- */
-static inline int hvm_event_needs_reinjection(uint8_t type, uint8_t vector)
-{
- switch ( type )
- {
- case X86_EVENTTYPE_EXT_INTR:
- case X86_EVENTTYPE_NMI:
- return 1;
- case X86_EVENTTYPE_HW_EXCEPTION:
- /*
- * SVM uses type 3 ("HW Exception") for #OF and #BP. We explicitly
- * check for these vectors, as they are really SW Exceptions. SVM has
- * not updated RIP to point after the trapping instruction (INT3/INTO).
- */
- return (vector != 3) && (vector != 4);
- default:
- /* Software exceptions/interrupts can be re-executed (e.g., INT n). */
- break;
- }
- return 0;
-}
+int hvm_event_needs_reinjection(uint8_t type, uint8_t vector);
+
+uint8_t hvm_combine_hw_exceptions(uint8_t vec1, uint8_t vec2);
static inline int hvm_cpu_up(void)
{
diff -r 5d25187bac94 -r ced23158093a xen/include/asm-x86/hvm/vmx/vmx.h
--- a/xen/include/asm-x86/hvm/vmx/vmx.h Wed Mar 26 10:14:50 2008 +0000
+++ b/xen/include/asm-x86/hvm/vmx/vmx.h Wed Mar 26 11:04:06 2008 +0000
@@ -264,49 +264,8 @@ static inline int __vmxon(u64 addr)
return rc;
}
-static inline void __vmx_inject_exception(
- struct vcpu *v, int trap, int type, int error_code)
-{
- unsigned long intr_fields;
-
- /*
- * NB. Callers do not need to worry about clearing STI/MOV-SS blocking:
- * "If the VM entry is injecting, there is no blocking by STI or by
- * MOV SS following the VM entry, regardless of the contents of the
- * interruptibility-state field [in the guest-state area before the
- * VM entry]", PRM Vol. 3, 22.6.1 (Interruptibility State).
- */
-
- intr_fields = (INTR_INFO_VALID_MASK | (type<<8) | trap);
- if ( error_code != HVM_DELIVER_NO_ERROR_CODE ) {
- __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
- intr_fields |= INTR_INFO_DELIVER_CODE_MASK;
- }
-
- __vmwrite(VM_ENTRY_INTR_INFO, intr_fields);
-
- if ( trap == TRAP_page_fault )
- HVMTRACE_2D(PF_INJECT, v, v->arch.hvm_vcpu.guest_cr[2], error_code);
- else
- HVMTRACE_2D(INJ_EXC, v, trap, error_code);
-}
-
-static inline void vmx_inject_hw_exception(
- struct vcpu *v, int trap, int error_code)
-{
- __vmx_inject_exception(v, trap, X86_EVENTTYPE_HW_EXCEPTION, error_code);
-}
-
-static inline void vmx_inject_extint(struct vcpu *v, int trap)
-{
- __vmx_inject_exception(v, trap, X86_EVENTTYPE_EXT_INTR,
- HVM_DELIVER_NO_ERROR_CODE);
-}
-
-static inline void vmx_inject_nmi(struct vcpu *v)
-{
- __vmx_inject_exception(v, 2, X86_EVENTTYPE_NMI,
- HVM_DELIVER_NO_ERROR_CODE);
-}
+void vmx_inject_hw_exception(struct vcpu *v, int trap, int error_code);
+void vmx_inject_extint(struct vcpu *v, int trap);
+void vmx_inject_nmi(struct vcpu *v);
#endif /* __ASM_X86_HVM_VMX_VMX_H__ */
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|