ia64/xen-unstable

view xen/arch/x86/hvm/vmx/io.c @ 8840:9f662b5e7d3c

Absolutely must not return to HVM guest context until
synchronous I/O emulation is completed.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Mon Feb 13 12:16:16 2006 +0100 (2006-02-13)
parents 4a9a39d08a06
children 3cb8e672b115
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 void vmx_set_tsc_shift(struct vcpu *v, struct hvm_virpit *vpit)
44 {
45 u64 drift;
47 if ( vpit->first_injected )
48 drift = vpit->period_cycles * vpit->pending_intr_nr;
49 else
50 drift = 0;
51 vpit->shift = v->arch.hvm_vmx.tsc_offset - drift;
52 __vmwrite(TSC_OFFSET, vpit->shift);
54 #if defined (__i386__)
55 __vmwrite(TSC_OFFSET_HIGH, ((vpit->shift)>> 32));
56 #endif
57 }
59 static inline void
60 interrupt_post_injection(struct vcpu * v, int vector, int type)
61 {
62 struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
64 if ( is_pit_irq(v, vector, type) ) {
65 if ( !vpit->first_injected ) {
66 vpit->pending_intr_nr = 0;
67 vpit->scheduled = NOW() + vpit->period;
68 set_timer(&vpit->pit_timer, vpit->scheduled);
69 vpit->first_injected = 1;
70 } else {
71 vpit->pending_intr_nr--;
72 }
73 vpit->inject_point = NOW();
74 vmx_set_tsc_shift (v, vpit);
75 }
77 switch(type)
78 {
79 case VLAPIC_DELIV_MODE_EXT:
80 break;
82 default:
83 vlapic_post_injection(v, vector, type);
84 break;
85 }
86 }
88 static inline void
89 enable_irq_window(unsigned long cpu_exec_control)
90 {
91 if (!(cpu_exec_control & CPU_BASED_VIRTUAL_INTR_PENDING)) {
92 cpu_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING;
93 __vmwrite(CPU_BASED_VM_EXEC_CONTROL, cpu_exec_control);
94 }
95 }
97 static inline void
98 disable_irq_window(unsigned long cpu_exec_control)
99 {
100 if ( cpu_exec_control & CPU_BASED_VIRTUAL_INTR_PENDING ) {
101 cpu_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING;
102 __vmwrite(CPU_BASED_VM_EXEC_CONTROL, cpu_exec_control);
103 }
104 }
106 asmlinkage void vmx_intr_assist(void)
107 {
108 int intr_type = 0;
109 int highest_vector;
110 unsigned long intr_fields, eflags, interruptibility, cpu_exec_control;
111 struct vcpu *v = current;
112 struct hvm_domain *plat=&v->domain->arch.hvm_domain;
113 struct hvm_virpit *vpit = &plat->vpit;
114 struct hvm_virpic *pic= &plat->vpic;
116 hvm_pic_assist(v);
117 __vmread_vcpu(v, CPU_BASED_VM_EXEC_CONTROL, &cpu_exec_control);
118 if ( vpit->pending_intr_nr ) {
119 pic_set_irq(pic, 0, 0);
120 pic_set_irq(pic, 0, 1);
121 }
123 __vmread(VM_ENTRY_INTR_INFO_FIELD, &intr_fields);
125 if (intr_fields & INTR_INFO_VALID_MASK) {
126 enable_irq_window(cpu_exec_control);
127 HVM_DBG_LOG(DBG_LEVEL_1, "vmx_intr_assist: intr_fields: %lx",
128 intr_fields);
129 return;
130 }
132 __vmread(GUEST_INTERRUPTIBILITY_INFO, &interruptibility);
134 if (interruptibility) {
135 enable_irq_window(cpu_exec_control);
136 HVM_DBG_LOG(DBG_LEVEL_1, "interruptibility: %lx",interruptibility);
137 return;
138 }
140 __vmread(GUEST_RFLAGS, &eflags);
141 if (irq_masked(eflags)) {
142 enable_irq_window(cpu_exec_control);
143 return;
144 }
146 highest_vector = cpu_get_interrupt(v, &intr_type);
148 if (highest_vector == -1) {
149 disable_irq_window(cpu_exec_control);
150 return;
151 }
153 switch (intr_type) {
154 case VLAPIC_DELIV_MODE_EXT:
155 case VLAPIC_DELIV_MODE_FIXED:
156 case VLAPIC_DELIV_MODE_LPRI:
157 vmx_inject_extint(v, highest_vector, VMX_INVALID_ERROR_CODE);
158 TRACE_3D(TRC_VMX_INT, v->domain->domain_id, highest_vector, 0);
159 break;
160 case VLAPIC_DELIV_MODE_SMI:
161 case VLAPIC_DELIV_MODE_NMI:
162 case VLAPIC_DELIV_MODE_INIT:
163 case VLAPIC_DELIV_MODE_STARTUP:
164 default:
165 printk("Unsupported interrupt type\n");
166 BUG();
167 break;
168 }
170 interrupt_post_injection(v, highest_vector, intr_type);
171 return;
172 }
174 void vmx_do_resume(struct vcpu *v)
175 {
176 struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
178 vmx_stts();
180 if ( event_pending(v) ||
181 test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags) )
182 hvm_wait_io();
184 /* pick up the elapsed PIT ticks and re-enable pit_timer */
185 if ( vpit->first_injected )
186 pickup_deactive_ticks(vpit);
187 vmx_set_tsc_shift(v, vpit);
189 /* We can't resume the guest if we're waiting on I/O */
190 ASSERT(!test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags));
191 }
193 /*
194 * Local variables:
195 * mode: C
196 * c-set-style: "BSD"
197 * c-basic-offset: 4
198 * tab-width: 4
199 * indent-tabs-mode: nil
200 * End:
201 */