ia64/xen-unstable

view xen/arch/x86/hvm/vmx/io.c @ 9952:0c586a81d941

Fix injection of guest faults resulting from failed injection of a
previous event. We enter an infinite loop if the original failed
injection cannot be fixed up by Xen (e.g., because it's not a shadow
pagetable issue).

The RHEL4 HVM guest hang issue was actually a side effect of
change-set 9699. In the rhel4 guest hang rc.sysinit init-script was
calls kmodule program to probe the hardware. The kmodule uses the kudzu
library call probeDevices(). For probing the graphics hardware in the
vbe_get_mode_info() function, sets up the environment and goes into the
vm86 mode to do the int x10 call. For returning back to protected mode
it sets up a int 0xff call. At the time of calling the int 0xff the
guest process pages were not filled up. And it was causing an infinite
loop of vmexits with the IDT_VECTORING_INFO on the int 0xff instruction.

The reason for the infinite loop is changeset 9699. With that
the guest page fault was always getting overridden by the int 0xff gp
fault coming from the IDT_VECTORING_INFO. With the attached patch if VMM
is injecting exceptions like page faults or gp faults then
IDT_VECTORING_INFO field does not override it, and that breaks the
vmexit infinite loop for the rhel4.

Signed-off-by: Nitin A Kamble <nitin.a.kamble@intel.com>
Signed-off-by: Jun Nakajima <jun.nakajima@intel.com>
Signed-off-by: Edwin Zhai <edwin.zhai@intel.com>
author kaf24@firebug.cl.cam.ac.uk
date Fri May 05 14:05:31 2006 +0100 (2006-05-05)
parents 29e9a0313c09
children da7fe04d8e80
line source
1 /*
2 * io.c: handling I/O, interrupts related VMX entry/exit
3 * Copyright (c) 2004, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16 * Place - Suite 330, Boston, MA 02111-1307 USA.
17 *
18 */
20 #include <xen/config.h>
21 #include <xen/init.h>
22 #include <xen/mm.h>
23 #include <xen/lib.h>
24 #include <xen/errno.h>
25 #include <xen/trace.h>
26 #include <xen/event.h>
28 #include <asm/current.h>
29 #include <asm/cpufeature.h>
30 #include <asm/processor.h>
31 #include <asm/msr.h>
32 #include <asm/hvm/hvm.h>
33 #include <asm/hvm/io.h>
34 #include <asm/hvm/support.h>
35 #include <asm/hvm/vmx/vmx.h>
36 #include <asm/hvm/vmx/vmcs.h>
37 #include <asm/hvm/vpic.h>
38 #include <asm/hvm/vlapic.h>
39 #include <public/hvm/ioreq.h>
41 #define BSP_CPU(v) (!(v->vcpu_id))
43 static inline
44 void __set_tsc_offset(u64 offset)
45 {
46 __vmwrite(TSC_OFFSET, offset);
47 #if defined (__i386__)
48 __vmwrite(TSC_OFFSET_HIGH, offset >> 32);
49 #endif
50 }
52 u64 get_guest_time(struct vcpu *v)
53 {
54 struct hvm_time_info *time_info = &(v->domain->arch.hvm_domain.vpit.time_info);
55 u64 host_tsc;
57 rdtscll(host_tsc);
58 return host_tsc + time_info->cache_tsc_offset;
59 }
61 void set_guest_time(struct vcpu *v, u64 gtime)
62 {
63 struct hvm_time_info *time_info = &(v->domain->arch.hvm_domain.vpit.time_info);
64 u64 host_tsc;
66 rdtscll(host_tsc);
68 time_info->cache_tsc_offset = gtime - host_tsc;
69 __set_tsc_offset(time_info->cache_tsc_offset);
70 }
72 static inline void
73 interrupt_post_injection(struct vcpu * v, int vector, int type)
74 {
75 struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
76 struct hvm_time_info *time_info = &vpit->time_info;
78 if ( is_pit_irq(v, vector, type) ) {
79 if ( !time_info->first_injected ) {
80 time_info->pending_intr_nr = 0;
81 time_info->last_pit_gtime = get_guest_time(v);
82 time_info->first_injected = 1;
83 } else {
84 time_info->pending_intr_nr--;
85 }
86 time_info->count_advance = 0;
87 time_info->count_point = NOW();
89 time_info->last_pit_gtime += time_info->period_cycles;
90 set_guest_time(v, time_info->last_pit_gtime);
91 }
93 switch(type)
94 {
95 case VLAPIC_DELIV_MODE_EXT:
96 break;
98 default:
99 vlapic_post_injection(v, vector, type);
100 break;
101 }
102 }
104 static inline void
105 enable_irq_window(struct vcpu *v)
106 {
107 u32 *cpu_exec_control = &v->arch.hvm_vcpu.u.vmx.exec_control;
109 if (!(*cpu_exec_control & CPU_BASED_VIRTUAL_INTR_PENDING)) {
110 *cpu_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING;
111 __vmwrite(CPU_BASED_VM_EXEC_CONTROL, *cpu_exec_control);
112 }
113 }
115 static inline void
116 disable_irq_window(struct vcpu *v)
117 {
118 u32 *cpu_exec_control = &v->arch.hvm_vcpu.u.vmx.exec_control;
120 if ( *cpu_exec_control & CPU_BASED_VIRTUAL_INTR_PENDING ) {
121 *cpu_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
122 __vmwrite(CPU_BASED_VM_EXEC_CONTROL, *cpu_exec_control);
123 }
124 }
126 static inline int is_interruptibility_state(void)
127 {
128 int interruptibility;
129 __vmread(GUEST_INTERRUPTIBILITY_INFO, &interruptibility);
130 return interruptibility;
131 }
133 /* check to see if there is pending interrupt */
134 int cpu_has_pending_irq(struct vcpu *v)
135 {
136 struct hvm_domain *plat = &v->domain->arch.hvm_domain;
138 /* APIC */
139 if ( cpu_has_apic_interrupt(v) ) return 1;
141 /* PIC */
142 if ( !vlapic_accept_pic_intr(v) ) return 0;
144 return plat->interrupt_request;
145 }
147 asmlinkage void vmx_intr_assist(void)
148 {
149 int intr_type = 0;
150 int highest_vector;
151 unsigned long eflags;
152 struct vcpu *v = current;
153 struct hvm_domain *plat=&v->domain->arch.hvm_domain;
154 struct hvm_time_info *time_info = &plat->vpit.time_info;
155 struct hvm_virpic *pic= &plat->vpic;
156 unsigned int idtv_info_field;
157 unsigned long inst_len;
158 int has_ext_irq;
160 if ( v->vcpu_id == 0 )
161 hvm_pic_assist(v);
163 if ( (v->vcpu_id == 0) && time_info->pending_intr_nr ) {
164 pic_set_irq(pic, 0, 0);
165 pic_set_irq(pic, 0, 1);
166 }
168 has_ext_irq = cpu_has_pending_irq(v);
170 if (unlikely(v->arch.hvm_vmx.vector_injected)) {
171 v->arch.hvm_vmx.vector_injected=0;
172 if (unlikely(has_ext_irq)) enable_irq_window(v);
173 return;
174 }
176 __vmread(IDT_VECTORING_INFO_FIELD, &idtv_info_field);
177 if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) {
178 __vmwrite(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
180 __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len);
181 __vmwrite(VM_ENTRY_INSTRUCTION_LEN, inst_len);
183 if (unlikely(idtv_info_field & 0x800)) { /* valid error code */
184 unsigned long error_code;
185 __vmread(IDT_VECTORING_ERROR_CODE, &error_code);
186 __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
187 }
188 if (unlikely(has_ext_irq))
189 enable_irq_window(v);
191 HVM_DBG_LOG(DBG_LEVEL_1, "idtv_info_field=%x", idtv_info_field);
193 return;
194 }
196 if (likely(!has_ext_irq)) return;
198 if (unlikely(is_interruptibility_state())) { /* pre-cleared for emulated instruction */
199 enable_irq_window(v);
200 HVM_DBG_LOG(DBG_LEVEL_1, "interruptibility");
201 return;
202 }
204 __vmread(GUEST_RFLAGS, &eflags);
205 if (irq_masked(eflags)) {
206 enable_irq_window(v);
207 return;
208 }
210 highest_vector = cpu_get_interrupt(v, &intr_type);
211 switch (intr_type) {
212 case VLAPIC_DELIV_MODE_EXT:
213 case VLAPIC_DELIV_MODE_FIXED:
214 case VLAPIC_DELIV_MODE_LPRI:
215 vmx_inject_extint(v, highest_vector, VMX_DELIVER_NO_ERROR_CODE);
216 TRACE_3D(TRC_VMX_INT, v->domain->domain_id, highest_vector, 0);
217 break;
218 case VLAPIC_DELIV_MODE_SMI:
219 case VLAPIC_DELIV_MODE_NMI:
220 case VLAPIC_DELIV_MODE_INIT:
221 case VLAPIC_DELIV_MODE_STARTUP:
222 default:
223 printk("Unsupported interrupt type\n");
224 BUG();
225 break;
226 }
228 interrupt_post_injection(v, highest_vector, intr_type);
229 return;
230 }
232 void vmx_do_resume(struct vcpu *v)
233 {
234 struct domain *d = v->domain;
235 struct hvm_virpit *vpit = &v->domain->arch.hvm_domain.vpit;
236 struct hvm_time_info *time_info = &vpit->time_info;
238 vmx_stts();
240 /* pick up the elapsed PIT ticks and re-enable pit_timer */
241 if ( time_info->first_injected ) {
242 if ( v->domain->arch.hvm_domain.guest_time ) {
243 time_info->count_point = NOW();
244 set_guest_time(v, v->domain->arch.hvm_domain.guest_time);
245 v->domain->arch.hvm_domain.guest_time = 0;
246 }
247 pickup_deactive_ticks(vpit);
248 }
250 if ( test_bit(iopacket_port(v), &d->shared_info->evtchn_pending[0]) ||
251 test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags) )
252 hvm_wait_io();
254 /* We can't resume the guest if we're waiting on I/O */
255 ASSERT(!test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags));
256 }
258 /*
259 * Local variables:
260 * mode: C
261 * c-set-style: "BSD"
262 * c-basic-offset: 4
263 * tab-width: 4
264 * indent-tabs-mode: nil
265 * End:
266 */