ia64/xen-unstable

changeset 17676:2ada81810ddb

svm: Better handling of NMI injection -- avoid nested NMIs.

We do this by emulating the NMI mask which blocks NMI delivery until
next IRET on native hardware.

Signed-off-by: Gianluca Guida <gianluca.guida@eu.citrix.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon May 19 10:03:26 2008 +0100 (2008-05-19)
parents 8dce20be0bd5
children 4269ab4b37ee 13dda75739f2
files xen/arch/x86/hvm/svm/intr.c xen/arch/x86/hvm/svm/svm.c
line diff
     1.1 --- a/xen/arch/x86/hvm/svm/intr.c	Mon May 19 09:46:02 2008 +0100
     1.2 +++ b/xen/arch/x86/hvm/svm/intr.c	Mon May 19 10:03:26 2008 +0100
     1.3 @@ -51,6 +51,12 @@ static void svm_inject_nmi(struct vcpu *
     1.4  
     1.5      ASSERT(vmcb->eventinj.fields.v == 0);
     1.6      vmcb->eventinj = event;
     1.7 +
     1.8 +    /*
     1.9 +     * SVM does not virtualise the NMI mask, so we emulate it by intercepting
    1.10 +     * the next IRET and blocking NMI injection until the intercept triggers.
    1.11 +     */
    1.12 +    vmcb->general1_intercepts |= GENERAL1_INTERCEPT_IRET;
    1.13  }
    1.14      
    1.15  static void svm_inject_extint(struct vcpu *v, int vector)
     2.1 --- a/xen/arch/x86/hvm/svm/svm.c	Mon May 19 09:46:02 2008 +0100
     2.2 +++ b/xen/arch/x86/hvm/svm/svm.c	Mon May 19 10:03:26 2008 +0100
     2.3 @@ -367,15 +367,27 @@ static void svm_fpu_leave(struct vcpu *v
     2.4  static unsigned int svm_get_interrupt_shadow(struct vcpu *v)
     2.5  {
     2.6      struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
     2.7 -    return (vmcb->interrupt_shadow ?
     2.8 -            (HVM_INTR_SHADOW_MOV_SS|HVM_INTR_SHADOW_STI) : 0);
     2.9 +    unsigned int intr_shadow = 0;
    2.10 +
    2.11 +    if ( vmcb->interrupt_shadow )
    2.12 +        intr_shadow |= HVM_INTR_SHADOW_MOV_SS | HVM_INTR_SHADOW_STI;
    2.13 +
    2.14 +    if ( vmcb->general1_intercepts & GENERAL1_INTERCEPT_IRET )
    2.15 +        intr_shadow |= HVM_INTR_SHADOW_NMI;
    2.16 +
    2.17 +    return intr_shadow;
    2.18  }
    2.19  
    2.20  static void svm_set_interrupt_shadow(struct vcpu *v, unsigned int intr_shadow)
    2.21  {
    2.22      struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
    2.23 +
    2.24      vmcb->interrupt_shadow =
    2.25          !!(intr_shadow & (HVM_INTR_SHADOW_MOV_SS|HVM_INTR_SHADOW_STI));
    2.26 +
    2.27 +    vmcb->general1_intercepts &= ~GENERAL1_INTERCEPT_IRET;
    2.28 +    if ( intr_shadow & HVM_INTR_SHADOW_NMI )
    2.29 +        vmcb->general1_intercepts |= GENERAL1_INTERCEPT_IRET;
    2.30  }
    2.31  
    2.32  static int svm_guest_x86_mode(struct vcpu *v)
    2.33 @@ -1266,6 +1278,15 @@ asmlinkage void svm_vmexit_handler(struc
    2.34              reason = TSW_call_or_int;
    2.35          if ( (vmcb->exitinfo2 >> 44) & 1 )
    2.36              errcode = (uint32_t)vmcb->exitinfo2;
    2.37 +
    2.38 +        /*
    2.39 +         * Some processors set the EXITINTINFO field when the task switch
    2.40 +         * is caused by a task gate in the IDT. In this case we will be
    2.41 +         * emulating the event injection, so we do not want the processor
    2.42 +         * to re-inject the original event!
    2.43 +         */
    2.44 +        vmcb->eventinj.bytes = 0;
    2.45 +
    2.46          hvm_task_switch((uint16_t)vmcb->exitinfo1, reason, errcode);
    2.47          break;
    2.48      }
    2.49 @@ -1331,6 +1352,19 @@ asmlinkage void svm_vmexit_handler(struc
    2.50          svm_do_nested_pgfault(vmcb->exitinfo2, regs);
    2.51          break;
    2.52  
    2.53 +    case VMEXIT_IRET:
    2.54 +        /*
    2.55 +         * IRET clears the NMI mask. However because we clear the mask
    2.56 +         * /before/ executing IRET, we set the interrupt shadow to prevent
    2.57 +         * a pending NMI from being injected immediately. This will work
    2.58 +         * perfectly unless the IRET instruction faults: in that case we
    2.59 +         * may inject an NMI before the NMI handler's IRET instruction is
    2.60 +         * retired.
    2.61 +         */
    2.62 +        vmcb->general1_intercepts &= ~GENERAL1_INTERCEPT_IRET;
    2.63 +        vmcb->interrupt_shadow = 1;
    2.64 +        break;
    2.65 +
    2.66      default:
    2.67      exit_and_crash:
    2.68          gdprintk(XENLOG_ERR, "unexpected VMEXIT: exit reason = 0x%x, "