debuggers.hg
changeset 16436: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>
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 )