ia64/xen-unstable

changeset 16403:bc6aaa44e296

svm: Fix __update_guest_eip() to clear interrupt shadow.
Get rid of assertions about return value of get_instruction_length()
-- instead test in __update_guest_eip() and crash the domain.
Cache value of 'current' in svm_do_hlt().

The mismanagement of the interrupt shadow was found by Christoph
Egger of AMD.

Signed-off-by: Keir Fraser <keir@xensource.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Nov 20 15:05:36 2007 +0000 (2007-11-20)
parents 64fbef22f86a
children 2022cbc842af
files xen/arch/x86/hvm/svm/svm.c
line diff
     1.1 --- a/xen/arch/x86/hvm/svm/svm.c	Tue Nov 20 14:35:36 2007 +0000
     1.2 +++ b/xen/arch/x86/hvm/svm/svm.c	Tue Nov 20 15:05:36 2007 +0000
     1.3 @@ -74,11 +74,21 @@ static void *root_vmcb[NR_CPUS] __read_m
     1.4  static void svm_update_guest_efer(struct vcpu *v);
     1.5  
     1.6  static void inline __update_guest_eip(
     1.7 -    struct cpu_user_regs *regs, int inst_len) 
     1.8 +    struct cpu_user_regs *regs, unsigned int inst_len)
     1.9  {
    1.10 -    ASSERT(inst_len > 0);
    1.11 +    if ( unlikely((inst_len == 0) || (inst_len > 15)) )
    1.12 +    {
    1.13 +        gdprintk(XENLOG_ERR, "Bad instruction length %u\n", inst_len);
    1.14 +        domain_crash(current->domain);
    1.15 +        return;
    1.16 +    }
    1.17 +
    1.18 +    ASSERT(regs == guest_cpu_user_regs());
    1.19 +
    1.20      regs->eip += inst_len;
    1.21      regs->eflags &= ~X86_EFLAGS_RF;
    1.22 +
    1.23 +    current->arch.hvm_svm.vmcb->interrupt_shadow = 0;
    1.24  }
    1.25  
    1.26  static void svm_inject_exception(
    1.27 @@ -1061,7 +1071,6 @@ static void svm_vmexit_do_cpuid(struct v
    1.28                  ((uint64_t)eax << 32) | ebx, ((uint64_t)ecx << 32) | edx);
    1.29  
    1.30      inst_len = __get_instruction_length(v, INSTR_CPUID, NULL);
    1.31 -    ASSERT(inst_len > 0);
    1.32      __update_guest_eip(regs, inst_len);
    1.33  }
    1.34  
    1.35 @@ -1643,8 +1652,6 @@ static void svm_cr_access(
    1.36              v, list_b, ARRAY_SIZE(list_b), &buffer[index], &match);
    1.37      }
    1.38  
    1.39 -    ASSERT(inst_len > 0);
    1.40 -
    1.41      inst_len += index;
    1.42  
    1.43      /* Check for REX prefix - it's ALWAYS the last byte of any prefix bytes */
    1.44 @@ -1745,8 +1752,6 @@ static void svm_cr_access(
    1.45          BUG();
    1.46      }
    1.47  
    1.48 -    ASSERT(inst_len);
    1.49 -
    1.50      if ( result )
    1.51          __update_guest_eip(regs, inst_len);
    1.52  }
    1.53 @@ -1925,20 +1930,23 @@ static void svm_do_msr_access(
    1.54  static void svm_vmexit_do_hlt(struct vmcb_struct *vmcb,
    1.55                                struct cpu_user_regs *regs)
    1.56  {
    1.57 -    struct hvm_intack intack = hvm_vcpu_has_pending_irq(current);
    1.58 +    struct vcpu *curr = current;
    1.59 +    struct hvm_intack intack = hvm_vcpu_has_pending_irq(curr);
    1.60 +    unsigned int inst_len;
    1.61  
    1.62 -    __update_guest_eip(regs, 1);
    1.63 +    inst_len = __get_instruction_length(curr, INSTR_HLT, NULL);
    1.64 +    __update_guest_eip(regs, inst_len);
    1.65  
    1.66      /* Check for interrupt not handled or new interrupt. */
    1.67      if ( vmcb->eventinj.fields.v ||
    1.68           ((intack.source != hvm_intsrc_none) &&
    1.69            !svm_interrupt_blocked(current, intack)) )
    1.70      {
    1.71 -        HVMTRACE_1D(HLT, current, /*int pending=*/ 1);
    1.72 +        HVMTRACE_1D(HLT, curr, /*int pending=*/ 1);
    1.73          return;
    1.74      }
    1.75  
    1.76 -    HVMTRACE_1D(HLT, current, /*int pending=*/ 0);
    1.77 +    HVMTRACE_1D(HLT, curr, /*int pending=*/ 0);
    1.78      hvm_hlt(regs->eflags);
    1.79  }
    1.80  
    1.81 @@ -1971,17 +1979,15 @@ void svm_handle_invlpg(const short invlp
    1.82       * Unknown how many bytes the invlpg instruction will take.  Use the
    1.83       * maximum instruction length here
    1.84       */
    1.85 -    if (inst_copy_from_guest(opcode, svm_rip2pointer(v), length) < length)
    1.86 +    if ( inst_copy_from_guest(opcode, svm_rip2pointer(v), length) < length )
    1.87      {
    1.88          gdprintk(XENLOG_ERR, "Error reading memory %d bytes\n", length);
    1.89 -        domain_crash(v->domain);
    1.90 -        return;
    1.91 +        goto crash;
    1.92      }
    1.93  
    1.94 -    if (invlpga)
    1.95 +    if ( invlpga )
    1.96      {
    1.97          inst_len = __get_instruction_length(v, INSTR_INVLPGA, opcode);
    1.98 -        ASSERT(inst_len > 0);
    1.99          __update_guest_eip(regs, inst_len);
   1.100  
   1.101          /* 
   1.102 @@ -1993,9 +1999,13 @@ void svm_handle_invlpg(const short invlp
   1.103      else
   1.104      {
   1.105          /* What about multiple prefix codes? */
   1.106 -        prefix = (is_prefix(opcode[0])?opcode[0]:0);
   1.107 +        prefix = (is_prefix(opcode[0]) ? opcode[0] : 0);
   1.108          inst_len = __get_instruction_length(v, INSTR_INVLPG, opcode);
   1.109 -        ASSERT(inst_len > 0);
   1.110 +        if ( inst_len <= 0 )
   1.111 +        {
   1.112 +            gdprintk(XENLOG_ERR, "Error getting invlpg instr len\n");
   1.113 +            goto crash;
   1.114 +        }
   1.115  
   1.116          inst_len--;
   1.117          length -= inst_len;
   1.118 @@ -2012,10 +2022,14 @@ void svm_handle_invlpg(const short invlp
   1.119          __update_guest_eip(regs, inst_len);
   1.120      }
   1.121  
   1.122 -    HVMTRACE_3D(INVLPG, v, (invlpga?1:0), g_vaddr, (invlpga?regs->ecx:0));
   1.123 +    HVMTRACE_3D(INVLPG, v, !!invlpga, g_vaddr, (invlpga ? regs->ecx : 0));
   1.124  
   1.125      paging_invlpg(v, g_vaddr);
   1.126      svm_asid_g_invlpg(v, g_vaddr);
   1.127 +    return;
   1.128 +
   1.129 + crash:
   1.130 +    domain_crash(v->domain);
   1.131  }
   1.132  
   1.133  
   1.134 @@ -2242,7 +2256,6 @@ asmlinkage void svm_vmexit_handler(struc
   1.135  
   1.136      case VMEXIT_VMMCALL:
   1.137          inst_len = __get_instruction_length(v, INSTR_VMCALL, NULL);
   1.138 -        ASSERT(inst_len > 0);
   1.139          HVMTRACE_1D(VMMCALL, v, regs->eax);
   1.140          rc = hvm_do_hypercall(regs);
   1.141          if ( rc != HVM_HCALL_preempted )