ia64/xen-unstable

view xen/arch/x86/hvm/vpic.c @ 19244:e5c696aaf2a6

x86, hvm: gcc44 build fix.

Broken constrain in inline asm. Bytewise access works with a, b, c, d
registers only, thus "r" is wrong, it must be "q". gcc 4.4 tries to
use the si register, which doesn't work and thus fails the build.

From: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Sun Mar 01 14:58:07 2009 +0000 (2009-03-01)
parents fd5b2ed9574a
children 2f9e1348aa98
line source
1 /*
2 * i8259 interrupt controller emulation
3 *
4 * Copyright (c) 2003-2004 Fabrice Bellard
5 * Copyright (c) 2005 Intel Corperation
6 * Copyright (c) 2006 Keir Fraser, XenSource Inc.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to
10 * deal in the Software without restriction, including without limitation the
11 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12 * sell copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 * IN THE SOFTWARE.
25 */
27 #include <xen/config.h>
28 #include <xen/types.h>
29 #include <xen/event.h>
30 #include <xen/lib.h>
31 #include <xen/errno.h>
32 #include <xen/sched.h>
33 #include <asm/hvm/hvm.h>
34 #include <asm/hvm/io.h>
35 #include <asm/hvm/support.h>
37 #define vpic_domain(v) (container_of((v), struct domain, \
38 arch.hvm_domain.vpic[!vpic->is_master]))
39 #define __vpic_lock(v) &container_of((v), struct hvm_domain, \
40 vpic[!(v)->is_master])->irq_lock
41 #define vpic_lock(v) spin_lock(__vpic_lock(v))
42 #define vpic_unlock(v) spin_unlock(__vpic_lock(v))
43 #define vpic_is_locked(v) spin_is_locked(__vpic_lock(v))
44 #define vpic_elcr_mask(v) (vpic->is_master ? (uint8_t)0xf8 : (uint8_t)0xde);
46 /* Return the highest priority found in mask. Return 8 if none. */
47 #define VPIC_PRIO_NONE 8
48 static int vpic_get_priority(struct hvm_hw_vpic *vpic, uint8_t mask)
49 {
50 int prio;
52 ASSERT(vpic_is_locked(vpic));
54 if ( mask == 0 )
55 return VPIC_PRIO_NONE;
57 /* prio = ffs(mask ROR vpic->priority_add); */
58 asm ( "ror %%cl,%b1 ; bsf %1,%0"
59 : "=r" (prio) : "q" ((uint32_t)mask), "c" (vpic->priority_add) );
60 return prio;
61 }
63 /* Return the PIC's highest priority pending interrupt. Return -1 if none. */
64 static int vpic_get_highest_priority_irq(struct hvm_hw_vpic *vpic)
65 {
66 int cur_priority, priority, irq;
67 uint8_t mask;
69 ASSERT(vpic_is_locked(vpic));
71 mask = vpic->irr & ~vpic->imr;
72 priority = vpic_get_priority(vpic, mask);
73 if ( priority == VPIC_PRIO_NONE )
74 return -1;
76 irq = (priority + vpic->priority_add) & 7;
78 /*
79 * Compute current priority. If special fully nested mode on the master,
80 * the IRQ coming from the slave is not taken into account for the
81 * priority computation. In special mask mode, masked interrupts do not
82 * block lower-priority interrupts even if their IS bit is set.
83 */
84 mask = vpic->isr;
85 if ( vpic->special_fully_nested_mode && vpic->is_master && (irq == 2) )
86 mask &= ~(1 << 2);
87 if ( vpic->special_mask_mode )
88 mask &= ~vpic->imr;
89 cur_priority = vpic_get_priority(vpic, mask);
91 /* If a higher priority is found then an irq should be generated. */
92 return (priority < cur_priority) ? irq : -1;
93 }
95 static void vpic_update_int_output(struct hvm_hw_vpic *vpic)
96 {
97 int irq;
99 ASSERT(vpic_is_locked(vpic));
101 irq = vpic_get_highest_priority_irq(vpic);
102 if ( vpic->int_output == (irq >= 0) )
103 return;
105 /* INT line transition L->H or H->L. */
106 vpic->int_output = !vpic->int_output;
108 if ( vpic->int_output )
109 {
110 if ( vpic->is_master )
111 {
112 /* Master INT line is connected to VCPU0's VLAPIC LVT0. */
113 struct vcpu *v = vpic_domain(vpic)->vcpu[0];
114 if ( (v != NULL) && vlapic_accept_pic_intr(v) )
115 vcpu_kick(v);
116 }
117 else
118 {
119 /* Assert slave line in master PIC. */
120 (--vpic)->irr |= 1 << 2;
121 vpic_update_int_output(vpic);
122 }
123 }
124 else if ( !vpic->is_master )
125 {
126 /* Clear slave line in master PIC. */
127 (--vpic)->irr &= ~(1 << 2);
128 vpic_update_int_output(vpic);
129 }
130 }
132 static void __vpic_intack(struct hvm_hw_vpic *vpic, int irq)
133 {
134 uint8_t mask = 1 << irq;
136 ASSERT(vpic_is_locked(vpic));
138 /* Edge-triggered: clear the IRR (forget the edge). */
139 if ( !(vpic->elcr & mask) )
140 vpic->irr &= ~mask;
142 if ( !vpic->auto_eoi )
143 vpic->isr |= mask;
144 else if ( vpic->rotate_on_auto_eoi )
145 vpic->priority_add = (irq + 1) & 7;
147 vpic_update_int_output(vpic);
148 }
150 static int vpic_intack(struct hvm_hw_vpic *vpic)
151 {
152 int irq = -1;
154 vpic_lock(vpic);
156 if ( !vpic->int_output )
157 goto out;
159 irq = vpic_get_highest_priority_irq(vpic);
160 BUG_ON(irq < 0);
161 __vpic_intack(vpic, irq);
163 if ( (irq == 2) && vpic->is_master )
164 {
165 vpic++; /* Slave PIC */
166 irq = vpic_get_highest_priority_irq(vpic);
167 BUG_ON(irq < 0);
168 __vpic_intack(vpic, irq);
169 irq += 8;
170 }
172 out:
173 vpic_unlock(vpic);
174 return irq;
175 }
177 static void vpic_ioport_write(
178 struct hvm_hw_vpic *vpic, uint32_t addr, uint32_t val)
179 {
180 int priority, cmd, irq;
181 uint8_t mask;
183 vpic_lock(vpic);
185 if ( (addr & 1) == 0 )
186 {
187 if ( val & 0x10 )
188 {
189 /* ICW1 */
190 /* Clear edge-sensing logic. */
191 vpic->irr &= vpic->elcr;
193 /* No interrupts masked or in service. */
194 vpic->imr = vpic->isr = 0;
196 /* IR7 is lowest priority. */
197 vpic->priority_add = 0;
198 vpic->rotate_on_auto_eoi = 0;
200 vpic->special_mask_mode = 0;
201 vpic->readsel_isr = 0;
202 vpic->poll = 0;
204 if ( !(val & 1) )
205 {
206 /* NO ICW4: ICW4 features are cleared. */
207 vpic->auto_eoi = 0;
208 vpic->special_fully_nested_mode = 0;
209 }
211 vpic->init_state = ((val & 3) << 2) | 1;
212 }
213 else if ( val & 0x08 )
214 {
215 /* OCW3 */
216 if ( val & 0x04 )
217 vpic->poll = 1;
218 if ( val & 0x02 )
219 vpic->readsel_isr = val & 1;
220 if ( val & 0x40 )
221 vpic->special_mask_mode = (val >> 5) & 1;
222 }
223 else
224 {
225 /* OCW2 */
226 cmd = val >> 5;
227 switch ( cmd )
228 {
229 case 0: /* Rotate in AEOI Mode (Clear) */
230 case 4: /* Rotate in AEOI Mode (Set) */
231 vpic->rotate_on_auto_eoi = cmd >> 2;
232 break;
233 case 1: /* Non-Specific EOI */
234 case 5: /* Non-Specific EOI & Rotate */
235 mask = vpic->isr;
236 if ( vpic->special_mask_mode )
237 mask &= ~vpic->imr; /* SMM: ignore masked IRs. */
238 priority = vpic_get_priority(vpic, mask);
239 if ( priority == VPIC_PRIO_NONE )
240 break;
241 irq = (priority + vpic->priority_add) & 7;
242 vpic->isr &= ~(1 << irq);
243 if ( cmd == 5 )
244 vpic->priority_add = (irq + 1) & 7;
245 break;
246 case 3: /* Specific EOI */
247 case 7: /* Specific EOI & Rotate */
248 irq = val & 7;
249 vpic->isr &= ~(1 << irq);
250 if ( cmd == 7 )
251 vpic->priority_add = (irq + 1) & 7;
252 /* Release lock and EOI the physical interrupt (if any). */
253 vpic_update_int_output(vpic);
254 vpic_unlock(vpic);
255 hvm_dpci_eoi(current->domain,
256 hvm_isa_irq_to_gsi((addr >> 7) ? (irq|8) : irq),
257 NULL);
258 return; /* bail immediately */
259 case 6: /* Set Priority */
260 vpic->priority_add = (val + 1) & 7;
261 break;
262 }
263 }
264 }
265 else
266 {
267 switch ( vpic->init_state & 3 )
268 {
269 case 0:
270 /* OCW1 */
271 vpic->imr = val;
272 break;
273 case 1:
274 /* ICW2 */
275 vpic->irq_base = val & 0xf8;
276 vpic->init_state++;
277 if ( !(vpic->init_state & 8) )
278 break; /* CASCADE mode: wait for write to ICW3. */
279 /* SNGL mode: fall through (no ICW3). */
280 case 2:
281 /* ICW3 */
282 vpic->init_state++;
283 if ( !(vpic->init_state & 4) )
284 vpic->init_state = 0; /* No ICW4: init done */
285 break;
286 case 3:
287 /* ICW4 */
288 vpic->special_fully_nested_mode = (val >> 4) & 1;
289 vpic->auto_eoi = (val >> 1) & 1;
290 vpic->init_state = 0;
291 break;
292 }
293 }
295 vpic_update_int_output(vpic);
297 vpic_unlock(vpic);
298 }
300 static uint32_t vpic_ioport_read(struct hvm_hw_vpic *vpic, uint32_t addr)
301 {
302 if ( vpic->poll )
303 {
304 vpic->poll = 0;
305 return vpic_intack(vpic);
306 }
308 if ( (addr & 1) == 0 )
309 return (vpic->readsel_isr ? vpic->isr : vpic->irr);
311 return vpic->imr;
312 }
314 static int vpic_intercept_pic_io(
315 int dir, uint32_t port, uint32_t bytes, uint32_t *val)
316 {
317 struct hvm_hw_vpic *vpic;
319 if ( bytes != 1 )
320 {
321 gdprintk(XENLOG_WARNING, "PIC_IO bad access size %d\n", bytes);
322 return X86EMUL_OKAY;
323 }
325 vpic = &current->domain->arch.hvm_domain.vpic[port >> 7];
327 if ( dir == IOREQ_WRITE )
328 vpic_ioport_write(vpic, port, (uint8_t)*val);
329 else
330 *val = (uint8_t)vpic_ioport_read(vpic, port);
332 return X86EMUL_OKAY;
333 }
335 static int vpic_intercept_elcr_io(
336 int dir, uint32_t port, uint32_t bytes, uint32_t *val)
337 {
338 struct hvm_hw_vpic *vpic;
339 uint32_t data;
341 BUG_ON(bytes != 1);
343 vpic = &current->domain->arch.hvm_domain.vpic[port & 1];
345 if ( dir == IOREQ_WRITE )
346 {
347 /* Some IRs are always edge trig. Slave IR is always level trig. */
348 data = *val & vpic_elcr_mask(vpic);
349 if ( vpic->is_master )
350 data |= 1 << 2;
351 vpic->elcr = data;
352 }
353 else
354 {
355 /* Reader should not see hardcoded level-triggered slave IR. */
356 *val = vpic->elcr & vpic_elcr_mask(vpic);
357 }
359 return X86EMUL_OKAY;
360 }
362 static int vpic_save(struct domain *d, hvm_domain_context_t *h)
363 {
364 struct hvm_hw_vpic *s;
365 int i;
367 /* Save the state of both PICs */
368 for ( i = 0; i < 2 ; i++ )
369 {
370 s = &d->arch.hvm_domain.vpic[i];
371 if ( hvm_save_entry(PIC, i, h, s) )
372 return 1;
373 }
375 return 0;
376 }
378 static int vpic_load(struct domain *d, hvm_domain_context_t *h)
379 {
380 struct hvm_hw_vpic *s;
381 uint16_t inst;
383 /* Which PIC is this? */
384 inst = hvm_load_instance(h);
385 if ( inst > 1 )
386 return -EINVAL;
387 s = &d->arch.hvm_domain.vpic[inst];
389 /* Load the state */
390 if ( hvm_load_entry(PIC, h, s) != 0 )
391 return -EINVAL;
393 return 0;
394 }
396 HVM_REGISTER_SAVE_RESTORE(PIC, vpic_save, vpic_load, 2, HVMSR_PER_DOM);
398 void vpic_reset(struct domain *d)
399 {
400 struct hvm_hw_vpic *vpic;
402 /* Master PIC. */
403 vpic = &d->arch.hvm_domain.vpic[0];
404 memset(vpic, 0, sizeof(*vpic));
405 vpic->is_master = 1;
406 vpic->elcr = 1 << 2;
408 /* Slave PIC. */
409 vpic++;
410 memset(vpic, 0, sizeof(*vpic));
411 }
413 void vpic_init(struct domain *d)
414 {
415 vpic_reset(d);
417 register_portio_handler(d, 0x20, 2, vpic_intercept_pic_io);
418 register_portio_handler(d, 0xa0, 2, vpic_intercept_pic_io);
420 register_portio_handler(d, 0x4d0, 1, vpic_intercept_elcr_io);
421 register_portio_handler(d, 0x4d1, 1, vpic_intercept_elcr_io);
422 }
424 void vpic_irq_positive_edge(struct domain *d, int irq)
425 {
426 struct hvm_hw_vpic *vpic = &d->arch.hvm_domain.vpic[irq >> 3];
427 uint8_t mask = 1 << (irq & 7);
429 ASSERT(irq <= 15);
430 ASSERT(vpic_is_locked(vpic));
432 if ( irq == 2 )
433 return;
435 vpic->irr |= mask;
436 if ( !(vpic->imr & mask) )
437 vpic_update_int_output(vpic);
438 }
440 void vpic_irq_negative_edge(struct domain *d, int irq)
441 {
442 struct hvm_hw_vpic *vpic = &d->arch.hvm_domain.vpic[irq >> 3];
443 uint8_t mask = 1 << (irq & 7);
445 ASSERT(irq <= 15);
446 ASSERT(vpic_is_locked(vpic));
448 if ( irq == 2 )
449 return;
451 vpic->irr &= ~mask;
452 if ( !(vpic->imr & mask) )
453 vpic_update_int_output(vpic);
454 }
456 int vpic_ack_pending_irq(struct vcpu *v)
457 {
458 int irq, vector;
459 struct hvm_hw_vpic *vpic = &v->domain->arch.hvm_domain.vpic[0];
461 if ( !vlapic_accept_pic_intr(v) || !vpic->int_output )
462 return -1;
464 irq = vpic_intack(vpic);
465 if ( irq == -1 )
466 return -1;
468 vector = vpic[irq >> 3].irq_base + (irq & 7);
469 return vector;
470 }