ia64/xen-unstable

view xen/arch/x86/vmx_io.c @ 4632:1caa83c98dee

bitkeeper revision 1.1365 (42682a52hWoXmZEjWb2-0Ly05egFKg)

Hand merged...

Signed-off-by: michael.fetterman@cl.cam.ac.uk
author maf46@burn.cl.cam.ac.uk
date Thu Apr 21 22:33:54 2005 +0000 (2005-04-21)
parents 9a768d11cc7b 2fdf5cc2b79b
children 38a02ee9a9c8 65b28c74cec2
line source
1 /*
2 * vmx_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 */
19 #include <xen/config.h>
20 #include <xen/init.h>
21 #include <xen/mm.h>
22 #include <xen/lib.h>
23 #include <xen/errno.h>
24 #include <xen/trace.h>
26 #include <asm/cpufeature.h>
27 #include <asm/processor.h>
28 #include <asm/msr.h>
29 #include <asm/vmx.h>
30 #include <asm/vmx_vmcs.h>
31 #include <xen/event.h>
32 #include <public/io/ioreq.h>
33 #include <asm/vmx_platform.h>
34 #include <asm/vmx_virpit.h>
36 #ifdef CONFIG_VMX
38 extern long do_block();
40 #if defined (__i386__)
41 static void load_xen_regs(struct xen_regs *regs)
42 {
43 /*
44 * Write the guest register value into VMCS
45 */
46 __vmwrite(GUEST_SS_SELECTOR, regs->ss);
47 __vmwrite(GUEST_ESP, regs->esp);
48 __vmwrite(GUEST_EFLAGS, regs->eflags);
49 __vmwrite(GUEST_CS_SELECTOR, regs->cs);
50 __vmwrite(GUEST_EIP, regs->eip);
51 }
53 static void set_reg_value (int size, int index, int seg, struct xen_regs *regs, long value)
54 {
55 switch (size) {
56 case BYTE:
57 switch (index) {
58 case 0:
59 regs->eax &= 0xFFFFFF00;
60 regs->eax |= (value & 0xFF);
61 break;
62 case 1:
63 regs->ecx &= 0xFFFFFF00;
64 regs->ecx |= (value & 0xFF);
65 break;
66 case 2:
67 regs->edx &= 0xFFFFFF00;
68 regs->edx |= (value & 0xFF);
69 break;
70 case 3:
71 regs->ebx &= 0xFFFFFF00;
72 regs->ebx |= (value & 0xFF);
73 break;
74 case 4:
75 regs->eax &= 0xFFFF00FF;
76 regs->eax |= ((value & 0xFF) << 8);
77 break;
78 case 5:
79 regs->ecx &= 0xFFFF00FF;
80 regs->ecx |= ((value & 0xFF) << 8);
81 break;
82 case 6:
83 regs->edx &= 0xFFFF00FF;
84 regs->edx |= ((value & 0xFF) << 8);
85 break;
86 case 7:
87 regs->ebx &= 0xFFFF00FF;
88 regs->ebx |= ((value & 0xFF) << 8);
89 break;
90 default:
91 printk("size:%x, index:%x are invalid!\n", size, index);
92 break;
94 }
95 break;
96 case WORD:
97 switch (index) {
98 case 0:
99 regs->eax &= 0xFFFF0000;
100 regs->eax |= (value & 0xFFFF);
101 break;
102 case 1:
103 regs->ecx &= 0xFFFF0000;
104 regs->ecx |= (value & 0xFFFF);
105 break;
106 case 2:
107 regs->edx &= 0xFFFF0000;
108 regs->edx |= (value & 0xFFFF);
109 break;
110 case 3:
111 regs->ebx &= 0xFFFF0000;
112 regs->ebx |= (value & 0xFFFF);
113 break;
114 case 4:
115 regs->esp &= 0xFFFF0000;
116 regs->esp |= (value & 0xFFFF);
117 break;
119 case 5:
120 regs->ebp &= 0xFFFF0000;
121 regs->ebp |= (value & 0xFFFF);
122 break;
123 case 6:
124 regs->esi &= 0xFFFF0000;
125 regs->esi |= (value & 0xFFFF);
126 break;
127 case 7:
128 regs->edi &= 0xFFFF0000;
129 regs->edi |= (value & 0xFFFF);
130 break;
131 default:
132 printk("size:%x, index:%x are invalid!\n", size, index);
133 break;
134 }
135 break;
136 case LONG:
137 switch (index) {
138 case 0:
139 regs->eax = value;
140 break;
141 case 1:
142 regs->ecx = value;
143 break;
144 case 2:
145 regs->edx = value;
146 break;
147 case 3:
148 regs->ebx = value;
149 break;
150 case 4:
151 regs->esp = value;
152 break;
153 case 5:
154 regs->ebp = value;
155 break;
156 case 6:
157 regs->esi = value;
158 break;
159 case 7:
160 regs->edi = value;
161 break;
162 default:
163 printk("size:%x, index:%x are invalid!\n", size, index);
164 break;
165 }
166 break;
167 default:
168 printk("size:%x, index:%x are invalid!\n", size, index);
169 break;
170 }
171 }
172 #else
173 static void load_xen_regs(struct xen_regs *regs)
174 {
175 /* XXX: TBD */
176 return;
177 }
178 static void set_reg_value (int size, int index, int seg, struct xen_regs *regs, long value)
179 {
180 /* XXX: TBD */
181 return;
182 }
183 #endif
185 void vmx_io_assist(struct exec_domain *ed)
186 {
187 vcpu_iodata_t *vio;
188 ioreq_t *p;
189 struct domain *d = ed->domain;
190 execution_context_t *ec = get_execution_context();
191 unsigned long old_eax;
192 int sign;
193 struct mi_per_cpu_info *mpci_p;
194 struct xen_regs *inst_decoder_regs;
196 mpci_p = &ed->arch.arch_vmx.vmx_platform.mpci;
197 inst_decoder_regs = mpci_p->inst_decoder_regs;
199 /* clear the pending event */
200 ed->vcpu_info->evtchn_upcall_pending = 0;
201 /* clear the pending bit for port 2 */
202 clear_bit(IOPACKET_PORT>>5, &ed->vcpu_info->evtchn_pending_sel);
203 clear_bit(IOPACKET_PORT, &d->shared_info->evtchn_pending[0]);
205 vio = (vcpu_iodata_t *) ed->arch.arch_vmx.vmx_platform.shared_page_va;
206 if (vio == 0) {
207 VMX_DBG_LOG(DBG_LEVEL_1,
208 "bad shared page: %lx", (unsigned long) vio);
209 domain_crash_synchronous();
210 }
211 p = &vio->vp_ioreq;
213 if (p->state == STATE_IORESP_HOOK){
214 vmx_hooks_assist(ed);
215 }
217 /* clear IO wait VMX flag */
218 if (test_bit(ARCH_VMX_IO_WAIT, &ed->arch.arch_vmx.flags)) {
219 if (p->state != STATE_IORESP_READY) {
220 printk("got a false I/O reponse\n");
221 do_block();
222 } else {
223 p->state = STATE_INVALID;
224 }
225 clear_bit(ARCH_VMX_IO_WAIT, &ed->arch.arch_vmx.flags);
226 } else {
227 return;
228 }
230 sign = (p->df) ? -1 : 1;
231 if (p->port_mm) {
232 if (p->pdata_valid) {
233 ec->esi += sign * p->count * p->size;
234 ec->edi += sign * p->count * p->size;
235 } else {
236 if (p->dir == IOREQ_WRITE) {
237 return;
238 }
239 int size = -1, index = -1;
241 size = operand_size(ed->arch.arch_vmx.vmx_platform.mpci.mmio_target);
242 index = operand_index(ed->arch.arch_vmx.vmx_platform.mpci.mmio_target);
244 if (ed->arch.arch_vmx.vmx_platform.mpci.mmio_target & WZEROEXTEND) {
245 p->u.data = p->u.data & 0xffff;
246 }
247 set_reg_value(size, index, 0, (struct xen_regs *)ec, p->u.data);
249 }
250 load_xen_regs((struct xen_regs *)ec);
251 return;
252 }
254 if (p->dir == IOREQ_WRITE) {
255 if (p->pdata_valid) {
256 ec->esi += sign * p->count * p->size;
257 ec->ecx -= p->count;
258 }
259 return;
260 } else {
261 if (p->pdata_valid) {
262 ec->edi += sign * p->count * p->size;
263 ec->ecx -= p->count;
264 return;
265 }
266 }
268 old_eax = ec->eax;
270 switch(p->size) {
271 case 1:
272 ec->eax = (old_eax & 0xffffff00) | (p->u.data & 0xff);
273 break;
274 case 2:
275 ec->eax = (old_eax & 0xffff0000) | (p->u.data & 0xffff);
276 break;
277 case 4:
278 ec->eax = (p->u.data & 0xffffffff);
279 break;
280 default:
281 BUG();
282 }
283 }
285 #if defined(__i386__) || defined(__x86_64__)
286 static inline int __fls(u32 word)
287 {
288 int bit;
290 __asm__("bsrl %1,%0"
291 :"=r" (bit)
292 :"rm" (word));
293 return word ? bit : -1;
294 }
295 #else
296 #define __fls(x) generic_fls(x)
297 static __inline__ int generic_fls(u32 x)
298 {
299 int r = 31;
301 if (!x)
302 return -1;
303 if (!(x & 0xffff0000u)) {
304 x <<= 16;
305 r -= 16;
306 }
307 if (!(x & 0xff000000u)) {
308 x <<= 8;
309 r -= 8;
310 }
311 if (!(x & 0xf0000000u)) {
312 x <<= 4;
313 r -= 4;
314 }
315 if (!(x & 0xc0000000u)) {
316 x <<= 2;
317 r -= 2;
318 }
319 if (!(x & 0x80000000u)) {
320 x <<= 1;
321 r -= 1;
322 }
323 return r;
324 }
325 #endif
327 /* Simple minded Local APIC priority implementation. Fix later */
328 static __inline__ int find_highest_irq(u32 *pintr)
329 {
330 if (pintr[7])
331 return __fls(pintr[7]) + (256-32*1);
332 if (pintr[6])
333 return __fls(pintr[6]) + (256-32*2);
334 if (pintr[5])
335 return __fls(pintr[5]) + (256-32*3);
336 if (pintr[4])
337 return __fls(pintr[4]) + (256-32*4);
338 if (pintr[3])
339 return __fls(pintr[3]) + (256-32*5);
340 if (pintr[2])
341 return __fls(pintr[2]) + (256-32*6);
342 if (pintr[1])
343 return __fls(pintr[1]) + (256-32*7);
344 return __fls(pintr[0]);
345 }
347 /*
348 * Return 0-255 for pending irq.
349 * -1 when no pending.
350 */
351 static inline int find_highest_pending_irq(struct exec_domain *d)
352 {
353 vcpu_iodata_t *vio;
355 vio = (vcpu_iodata_t *) d->arch.arch_vmx.vmx_platform.shared_page_va;
356 if (vio == 0) {
357 VMX_DBG_LOG(DBG_LEVEL_1,
358 "bad shared page: %lx", (unsigned long) vio);
359 domain_crash_synchronous();
360 }
362 return find_highest_irq((unsigned int *)&vio->vp_intr[0]);
363 }
365 static inline void clear_highest_bit(struct exec_domain *d, int vector)
366 {
367 vcpu_iodata_t *vio;
369 vio = (vcpu_iodata_t *) d->arch.arch_vmx.vmx_platform.shared_page_va;
370 if (vio == 0) {
371 VMX_DBG_LOG(DBG_LEVEL_1,
372 "bad shared page: %lx", (unsigned long) vio);
373 domain_crash_synchronous();
374 }
376 clear_bit(vector, &vio->vp_intr[0]);
377 }
379 static inline int irq_masked(unsigned long eflags)
380 {
381 return ((eflags & X86_EFLAGS_IF) == 0);
382 }
384 void vmx_intr_assist(struct exec_domain *d)
385 {
386 int highest_vector = find_highest_pending_irq(d);
387 unsigned long intr_fields, eflags;
388 struct vmx_virpit_t *vpit = &(d->arch.arch_vmx.vmx_platform.vmx_pit);
390 if (highest_vector == -1)
391 return;
393 __vmread(VM_ENTRY_INTR_INFO_FIELD, &intr_fields);
394 if (intr_fields & INTR_INFO_VALID_MASK) {
395 VMX_DBG_LOG(DBG_LEVEL_1, "vmx_intr_assist: intr_fields: %lx",
396 intr_fields);
397 return;
398 }
400 __vmread(GUEST_EFLAGS, &eflags);
401 if (irq_masked(eflags)) {
402 VMX_DBG_LOG(DBG_LEVEL_1, "guesting pending: %x, eflags: %lx",
403 highest_vector, eflags);
404 return;
405 }
407 if (vpit->pending_intr_nr && highest_vector == vpit->vector)
408 vpit->pending_intr_nr--;
409 else
410 clear_highest_bit(d, highest_vector);
412 /* close the window between guest PIT initialization and sti */
413 if (highest_vector == vpit->vector && !vpit->first_injected){
414 vpit->first_injected = 1;
415 vpit->pending_intr_nr = 0;
416 }
418 intr_fields = (INTR_INFO_VALID_MASK | INTR_TYPE_EXT_INTR | highest_vector);
419 __vmwrite(VM_ENTRY_INTR_INFO_FIELD, intr_fields);
421 __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
423 TRACE_2D(TRC_VMX_INT, d, highest_vector);
424 if (highest_vector == vpit->vector)
425 vpit->inject_point = NOW();
427 return;
428 }
430 void vmx_do_resume(struct exec_domain *d)
431 {
432 if ( test_bit(VMX_CPU_STATE_PG_ENABLED, &d->arch.arch_vmx.cpu_state) )
433 __vmwrite(GUEST_CR3, pagetable_val(d->arch.shadow_table));
434 else
435 // paging is not enabled in the guest
436 __vmwrite(GUEST_CR3, pagetable_val(d->domain->arch.phys_table));
438 __vmwrite(HOST_CR3, pagetable_val(d->arch.monitor_table));
439 __vmwrite(HOST_ESP, (unsigned long)get_stack_bottom());
441 if (event_pending(d)) {
442 if (test_bit(IOPACKET_PORT, &d->domain->shared_info->evtchn_pending[0]))
443 vmx_io_assist(d);
445 else if (test_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags)) {
446 printk("got an event while blocked on I/O\n");
447 do_block();
448 }
450 /* Assumption: device model will not inject an interrupt
451 * while an ioreq_t is pending i.e. the response and
452 * interrupt can come together. But an interrupt without
453 * a response to ioreq_t is not ok.
454 */
455 }
456 if (!test_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags))
457 vmx_intr_assist(d);
458 }
460 #endif /* CONFIG_VMX */
462 /*
463 * Local variables:
464 * mode: C
465 * c-set-style: "BSD"
466 * c-basic-offset: 4
467 * tab-width: 4
468 * indent-tabs-mode: nil
469 * End:
470 */