ia64/xen-unstable

view xen/arch/x86/hvm/vmx/io.c @ 9334:56a775219c88

This patch fix HVM/VMX time resolution issue that cause IA32E complain
"loss tick" occationally and APIC time calibration issue.

Signed-off-by: Xiaowei Yang <xiaowei.yang@intel.com>
Signed-off-by: Eddie Dong <eddie.dong@intel.com>
author kaf24@firebug.cl.cam.ac.uk
date Sun Mar 19 18:52:20 2006 +0100 (2006-03-19)
parents 3f8123ae34ba
children bb8a5d7e72a2
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_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
55 u64 host_tsc;
57 rdtscll(host_tsc);
58 return host_tsc + vpit->cache_tsc_offset;
59 }
61 void set_guest_time(struct vcpu *v, u64 gtime)
62 {
63 struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
64 u64 host_tsc;
66 rdtscll(host_tsc);
68 vpit->cache_tsc_offset = gtime - host_tsc;
69 __set_tsc_offset(vpit->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);
77 if ( is_pit_irq(v, vector, type) ) {
78 if ( !vpit->first_injected ) {
79 vpit->pending_intr_nr = 0;
80 vpit->last_pit_gtime = get_guest_time(v);
81 vpit->scheduled = NOW() + vpit->period;
82 set_timer(&vpit->pit_timer, vpit->scheduled);
83 vpit->first_injected = 1;
84 } else {
85 vpit->pending_intr_nr--;
86 }
87 vpit->inject_point = NOW();
89 vpit->last_pit_gtime += vpit->period;
90 set_guest_time(v, vpit->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_virpit *vpit = &plat->vpit;
155 struct hvm_virpic *pic= &plat->vpic;
157 if ( v->vcpu_id == 0 )
158 hvm_pic_assist(v);
160 if ( (v->vcpu_id == 0) && vpit->pending_intr_nr ) {
161 pic_set_irq(pic, 0, 0);
162 pic_set_irq(pic, 0, 1);
163 }
165 if ( !cpu_has_pending_irq(v) ) return;
167 if ( is_interruptibility_state() ) { /* pre-cleared for emulated instruction */
168 enable_irq_window(v);
169 HVM_DBG_LOG(DBG_LEVEL_1, "interruptibility");
170 return;
171 }
173 __vmread(GUEST_RFLAGS, &eflags);
174 if (irq_masked(eflags)) {
175 enable_irq_window(v);
176 return;
177 }
179 highest_vector = cpu_get_interrupt(v, &intr_type);
180 switch (intr_type) {
181 case VLAPIC_DELIV_MODE_EXT:
182 case VLAPIC_DELIV_MODE_FIXED:
183 case VLAPIC_DELIV_MODE_LPRI:
184 vmx_inject_extint(v, highest_vector, VMX_DELIVER_NO_ERROR_CODE);
185 TRACE_3D(TRC_VMX_INT, v->domain->domain_id, highest_vector, 0);
186 break;
187 case VLAPIC_DELIV_MODE_SMI:
188 case VLAPIC_DELIV_MODE_NMI:
189 case VLAPIC_DELIV_MODE_INIT:
190 case VLAPIC_DELIV_MODE_STARTUP:
191 default:
192 printk("Unsupported interrupt type\n");
193 BUG();
194 break;
195 }
197 interrupt_post_injection(v, highest_vector, intr_type);
198 return;
199 }
201 void vmx_do_resume(struct vcpu *v)
202 {
203 struct domain *d = v->domain;
204 struct hvm_virpit *vpit = &v->domain->arch.hvm_domain.vpit;
206 vmx_stts();
208 /* pick up the elapsed PIT ticks and re-enable pit_timer */
209 if ( vpit->first_injected) {
210 set_guest_time(v, v->domain->arch.hvm_domain.guest_time);
211 pickup_deactive_ticks(vpit);
212 }
214 if ( test_bit(iopacket_port(v), &d->shared_info->evtchn_pending[0]) ||
215 test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags) )
216 hvm_wait_io();
218 /* We can't resume the guest if we're waiting on I/O */
219 ASSERT(!test_bit(ARCH_HVM_IO_WAIT, &v->arch.hvm_vcpu.ioflags));
220 }
222 /*
223 * Local variables:
224 * mode: C
225 * c-set-style: "BSD"
226 * c-basic-offset: 4
227 * tab-width: 4
228 * indent-tabs-mode: nil
229 * End:
230 */