ia64/xen-unstable

view xen/arch/x86/vmx_io.c @ 5369:6410a7fd8ff8

bitkeeper revision 1.1691.1.4 (42a6af07Q4gVBgwNowk1mRBYhuAX_A)

[PATCH] vmx-io-events.patch

- Handle the case where the VMX domains get events from ports other than
IOPACKET_PORT (because of paravirtualized drivers)

- Use clear_bit() to operate on evtchn_upcall_pending

Signed-off-by: Xiaofeng Ling <xiaofeng.ling@intel.com>
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Arun Sharma <arun.sharma@intel.com>
author arun.sharma@intel.com[kaf24]
date Wed Jun 08 08:40:39 2005 +0000 (2005-06-08)
parents 8651a99cdc09
children 5cc07785693b
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/current.h>
27 #include <asm/cpufeature.h>
28 #include <asm/processor.h>
29 #include <asm/msr.h>
30 #include <asm/vmx.h>
31 #include <asm/vmx_vmcs.h>
32 #include <xen/event.h>
33 #include <public/io/ioreq.h>
34 #include <asm/vmx_platform.h>
35 #include <asm/vmx_virpit.h>
37 #ifdef CONFIG_VMX
38 #if defined (__i386__)
39 static void load_cpu_user_regs(struct cpu_user_regs *regs)
40 {
41 /*
42 * Write the guest register value into VMCS
43 */
44 __vmwrite(GUEST_SS_SELECTOR, regs->ss);
45 __vmwrite(GUEST_ESP, regs->esp);
46 __vmwrite(GUEST_EFLAGS, regs->eflags);
47 __vmwrite(GUEST_CS_SELECTOR, regs->cs);
48 __vmwrite(GUEST_EIP, regs->eip);
49 }
51 static void set_reg_value (int size, int index, int seg, struct cpu_user_regs *regs, long value)
52 {
53 switch (size) {
54 case BYTE:
55 switch (index) {
56 case 0:
57 regs->eax &= 0xFFFFFF00;
58 regs->eax |= (value & 0xFF);
59 break;
60 case 1:
61 regs->ecx &= 0xFFFFFF00;
62 regs->ecx |= (value & 0xFF);
63 break;
64 case 2:
65 regs->edx &= 0xFFFFFF00;
66 regs->edx |= (value & 0xFF);
67 break;
68 case 3:
69 regs->ebx &= 0xFFFFFF00;
70 regs->ebx |= (value & 0xFF);
71 break;
72 case 4:
73 regs->eax &= 0xFFFF00FF;
74 regs->eax |= ((value & 0xFF) << 8);
75 break;
76 case 5:
77 regs->ecx &= 0xFFFF00FF;
78 regs->ecx |= ((value & 0xFF) << 8);
79 break;
80 case 6:
81 regs->edx &= 0xFFFF00FF;
82 regs->edx |= ((value & 0xFF) << 8);
83 break;
84 case 7:
85 regs->ebx &= 0xFFFF00FF;
86 regs->ebx |= ((value & 0xFF) << 8);
87 break;
88 default:
89 printk("size:%x, index:%x are invalid!\n", size, index);
90 break;
92 }
93 break;
94 case WORD:
95 switch (index) {
96 case 0:
97 regs->eax &= 0xFFFF0000;
98 regs->eax |= (value & 0xFFFF);
99 break;
100 case 1:
101 regs->ecx &= 0xFFFF0000;
102 regs->ecx |= (value & 0xFFFF);
103 break;
104 case 2:
105 regs->edx &= 0xFFFF0000;
106 regs->edx |= (value & 0xFFFF);
107 break;
108 case 3:
109 regs->ebx &= 0xFFFF0000;
110 regs->ebx |= (value & 0xFFFF);
111 break;
112 case 4:
113 regs->esp &= 0xFFFF0000;
114 regs->esp |= (value & 0xFFFF);
115 break;
117 case 5:
118 regs->ebp &= 0xFFFF0000;
119 regs->ebp |= (value & 0xFFFF);
120 break;
121 case 6:
122 regs->esi &= 0xFFFF0000;
123 regs->esi |= (value & 0xFFFF);
124 break;
125 case 7:
126 regs->edi &= 0xFFFF0000;
127 regs->edi |= (value & 0xFFFF);
128 break;
129 default:
130 printk("size:%x, index:%x are invalid!\n", size, index);
131 break;
132 }
133 break;
134 case LONG:
135 switch (index) {
136 case 0:
137 regs->eax = value;
138 break;
139 case 1:
140 regs->ecx = value;
141 break;
142 case 2:
143 regs->edx = value;
144 break;
145 case 3:
146 regs->ebx = value;
147 break;
148 case 4:
149 regs->esp = value;
150 break;
151 case 5:
152 regs->ebp = value;
153 break;
154 case 6:
155 regs->esi = value;
156 break;
157 case 7:
158 regs->edi = value;
159 break;
160 default:
161 printk("size:%x, index:%x are invalid!\n", size, index);
162 break;
163 }
164 break;
165 default:
166 printk("size:%x, index:%x are invalid!\n", size, index);
167 break;
168 }
169 }
170 #else
171 static void load_cpu_user_regs(struct cpu_user_regs *regs)
172 {
173 /* XXX: TBD */
174 return;
175 }
176 static void set_reg_value (int size, int index, int seg, struct cpu_user_regs *regs, long value)
177 {
178 /* XXX: TBD */
179 return;
180 }
181 #endif
183 void vmx_io_assist(struct vcpu *v)
184 {
185 vcpu_iodata_t *vio;
186 ioreq_t *p;
187 struct cpu_user_regs *regs = guest_cpu_user_regs();
188 unsigned long old_eax;
189 int sign;
190 struct mi_per_cpu_info *mpci_p;
191 struct cpu_user_regs *inst_decoder_regs;
193 mpci_p = &v->arch.arch_vmx.vmx_platform.mpci;
194 inst_decoder_regs = mpci_p->inst_decoder_regs;
196 vio = (vcpu_iodata_t *) v->arch.arch_vmx.vmx_platform.shared_page_va;
197 if (vio == 0) {
198 VMX_DBG_LOG(DBG_LEVEL_1,
199 "bad shared page: %lx", (unsigned long) vio);
200 domain_crash_synchronous();
201 }
202 p = &vio->vp_ioreq;
204 if (p->state == STATE_IORESP_HOOK){
205 vmx_hooks_assist(v);
206 }
208 /* clear IO wait VMX flag */
209 if (test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)) {
210 if (p->state != STATE_IORESP_READY) {
211 /* An interrupt send event raced us */
212 return;
213 } else {
214 p->state = STATE_INVALID;
215 }
216 clear_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags);
217 } else {
218 return;
219 }
221 sign = (p->df) ? -1 : 1;
222 if (p->port_mm) {
223 if (p->pdata_valid) {
224 regs->esi += sign * p->count * p->size;
225 regs->edi += sign * p->count * p->size;
226 } else {
227 if (p->dir == IOREQ_WRITE) {
228 return;
229 }
230 int size = -1, index = -1;
232 size = operand_size(v->arch.arch_vmx.vmx_platform.mpci.mmio_target);
233 index = operand_index(v->arch.arch_vmx.vmx_platform.mpci.mmio_target);
235 if (v->arch.arch_vmx.vmx_platform.mpci.mmio_target & WZEROEXTEND) {
236 p->u.data = p->u.data & 0xffff;
237 }
238 set_reg_value(size, index, 0, regs, p->u.data);
240 }
241 load_cpu_user_regs(regs);
242 return;
243 }
245 if (p->dir == IOREQ_WRITE) {
246 if (p->pdata_valid) {
247 regs->esi += sign * p->count * p->size;
248 regs->ecx -= p->count;
249 }
250 return;
251 } else {
252 if (p->pdata_valid) {
253 regs->edi += sign * p->count * p->size;
254 regs->ecx -= p->count;
255 return;
256 }
257 }
259 old_eax = regs->eax;
261 switch(p->size) {
262 case 1:
263 regs->eax = (old_eax & 0xffffff00) | (p->u.data & 0xff);
264 break;
265 case 2:
266 regs->eax = (old_eax & 0xffff0000) | (p->u.data & 0xffff);
267 break;
268 case 4:
269 regs->eax = (p->u.data & 0xffffffff);
270 break;
271 default:
272 BUG();
273 }
274 }
276 int vmx_clear_pending_io_event(struct vcpu *v)
277 {
278 struct domain *d = v->domain;
280 /* evtchn_pending is shared by other event channels in 0-31 range */
281 if (!d->shared_info->evtchn_pending[IOPACKET_PORT>>5])
282 clear_bit(IOPACKET_PORT>>5, &v->vcpu_info->evtchn_pending_sel);
284 /* Note: VMX domains may need upcalls as well */
285 if (!v->vcpu_info->evtchn_pending_sel)
286 clear_bit(0, &v->vcpu_info->evtchn_upcall_pending);
288 /* clear the pending bit for IOPACKET_PORT */
289 return test_and_clear_bit(IOPACKET_PORT,
290 &d->shared_info->evtchn_pending[0]);
291 }
293 /* Because we've cleared the pending events first, we need to guarantee that
294 * all events to be handled by xen for VMX domains are taken care of here.
295 *
296 * interrupts are guaranteed to be checked before resuming guest.
297 * VMX upcalls have been already arranged for if necessary.
298 */
299 void vmx_check_events(struct vcpu *d)
300 {
301 /* clear the event *before* checking for work. This should avoid
302 the set-and-check races */
303 if (vmx_clear_pending_io_event(current))
304 vmx_io_assist(d);
305 }
307 /* On exit from vmx_wait_io, we're guaranteed to have a I/O response from
308 the device model */
309 void vmx_wait_io()
310 {
311 extern void do_block();
313 do {
314 if(!test_bit(IOPACKET_PORT,
315 &current->domain->shared_info->evtchn_pending[0]))
316 do_block();
317 vmx_check_events(current);
318 if (!test_bit(ARCH_VMX_IO_WAIT, &current->arch.arch_vmx.flags))
319 break;
320 /* Events other than IOPACKET_PORT might have woken us up. In that
321 case, safely go back to sleep. */
322 clear_bit(IOPACKET_PORT>>5, &current->vcpu_info->evtchn_pending_sel);
323 clear_bit(0, &current->vcpu_info->evtchn_upcall_pending);
324 } while(1);
325 }
327 #if defined(__i386__) || defined(__x86_64__)
328 static inline int __fls(u32 word)
329 {
330 int bit;
332 __asm__("bsrl %1,%0"
333 :"=r" (bit)
334 :"rm" (word));
335 return word ? bit : -1;
336 }
337 #else
338 #define __fls(x) generic_fls(x)
339 static __inline__ int generic_fls(u32 x)
340 {
341 int r = 31;
343 if (!x)
344 return -1;
345 if (!(x & 0xffff0000u)) {
346 x <<= 16;
347 r -= 16;
348 }
349 if (!(x & 0xff000000u)) {
350 x <<= 8;
351 r -= 8;
352 }
353 if (!(x & 0xf0000000u)) {
354 x <<= 4;
355 r -= 4;
356 }
357 if (!(x & 0xc0000000u)) {
358 x <<= 2;
359 r -= 2;
360 }
361 if (!(x & 0x80000000u)) {
362 x <<= 1;
363 r -= 1;
364 }
365 return r;
366 }
367 #endif
369 /* Simple minded Local APIC priority implementation. Fix later */
370 static __inline__ int find_highest_irq(u32 *pintr)
371 {
372 if (pintr[7])
373 return __fls(pintr[7]) + (256-32*1);
374 if (pintr[6])
375 return __fls(pintr[6]) + (256-32*2);
376 if (pintr[5])
377 return __fls(pintr[5]) + (256-32*3);
378 if (pintr[4])
379 return __fls(pintr[4]) + (256-32*4);
380 if (pintr[3])
381 return __fls(pintr[3]) + (256-32*5);
382 if (pintr[2])
383 return __fls(pintr[2]) + (256-32*6);
384 if (pintr[1])
385 return __fls(pintr[1]) + (256-32*7);
386 return __fls(pintr[0]);
387 }
389 /*
390 * Return 0-255 for pending irq.
391 * -1 when no pending.
392 */
393 static inline int find_highest_pending_irq(struct vcpu *d)
394 {
395 vcpu_iodata_t *vio;
397 vio = (vcpu_iodata_t *) d->arch.arch_vmx.vmx_platform.shared_page_va;
398 if (vio == 0) {
399 VMX_DBG_LOG(DBG_LEVEL_1,
400 "bad shared page: %lx", (unsigned long) vio);
401 domain_crash_synchronous();
402 }
404 return find_highest_irq((unsigned int *)&vio->vp_intr[0]);
405 }
407 static inline void clear_highest_bit(struct vcpu *d, int vector)
408 {
409 vcpu_iodata_t *vio;
411 vio = (vcpu_iodata_t *) d->arch.arch_vmx.vmx_platform.shared_page_va;
412 if (vio == 0) {
413 VMX_DBG_LOG(DBG_LEVEL_1,
414 "bad shared page: %lx", (unsigned long) vio);
415 domain_crash_synchronous();
416 }
418 clear_bit(vector, &vio->vp_intr[0]);
419 }
421 static inline int irq_masked(unsigned long eflags)
422 {
423 return ((eflags & X86_EFLAGS_IF) == 0);
424 }
426 void vmx_intr_assist(struct vcpu *d)
427 {
428 int highest_vector = find_highest_pending_irq(d);
429 unsigned long intr_fields, eflags;
430 struct vmx_virpit_t *vpit = &(d->arch.arch_vmx.vmx_platform.vmx_pit);
432 if (highest_vector == -1)
433 return;
435 __vmread(VM_ENTRY_INTR_INFO_FIELD, &intr_fields);
436 if (intr_fields & INTR_INFO_VALID_MASK) {
437 VMX_DBG_LOG(DBG_LEVEL_1, "vmx_intr_assist: intr_fields: %lx",
438 intr_fields);
439 return;
440 }
442 __vmread(GUEST_EFLAGS, &eflags);
443 if (irq_masked(eflags)) {
444 VMX_DBG_LOG(DBG_LEVEL_1, "guesting pending: %x, eflags: %lx",
445 highest_vector, eflags);
446 return;
447 }
449 if (vpit->pending_intr_nr && highest_vector == vpit->vector)
450 vpit->pending_intr_nr--;
451 else
452 clear_highest_bit(d, highest_vector);
454 /* close the window between guest PIT initialization and sti */
455 if (highest_vector == vpit->vector && !vpit->first_injected){
456 vpit->first_injected = 1;
457 vpit->pending_intr_nr = 0;
458 }
460 intr_fields = (INTR_INFO_VALID_MASK | INTR_TYPE_EXT_INTR | highest_vector);
461 __vmwrite(VM_ENTRY_INTR_INFO_FIELD, intr_fields);
463 __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
465 TRACE_3D(TRC_VMX_INT, d->domain->domain_id, highest_vector, 0);
466 if (highest_vector == vpit->vector)
467 vpit->inject_point = NOW();
469 return;
470 }
472 void vmx_do_resume(struct vcpu *d)
473 {
474 vmx_stts();
475 if ( vmx_paging_enabled(d) )
476 __vmwrite(GUEST_CR3, pagetable_get_paddr(d->arch.shadow_table));
477 else
478 // paging is not enabled in the guest
479 __vmwrite(GUEST_CR3, pagetable_get_paddr(d->domain->arch.phys_table));
481 __vmwrite(HOST_CR3, pagetable_get_paddr(d->arch.monitor_table));
482 __vmwrite(HOST_ESP, (unsigned long)get_stack_bottom());
484 if (event_pending(d)) {
485 vmx_check_events(d);
487 if (test_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags))
488 vmx_wait_io();
489 }
491 /* We can't resume the guest if we're waiting on I/O */
492 ASSERT(!test_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags));
494 /* We always check for interrupts before resuming guest */
495 vmx_intr_assist(d);
496 }
498 #endif /* CONFIG_VMX */
500 /*
501 * Local variables:
502 * mode: C
503 * c-set-style: "BSD"
504 * c-basic-offset: 4
505 * tab-width: 4
506 * indent-tabs-mode: nil
507 * End:
508 */