Statistics
| Branch: | Revision:

root / hw / i8259.c @ c0b5b109

History | View | Annotate | Download (15.2 kB)

1 80cabfad bellard
/*
2 80cabfad bellard
 * QEMU 8259 interrupt controller emulation
3 5fafdf24 ths
 *
4 80cabfad bellard
 * Copyright (c) 2003-2004 Fabrice Bellard
5 5fafdf24 ths
 *
6 80cabfad bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 80cabfad bellard
 * of this software and associated documentation files (the "Software"), to deal
8 80cabfad bellard
 * in the Software without restriction, including without limitation the rights
9 80cabfad bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 80cabfad bellard
 * copies of the Software, and to permit persons to whom the Software is
11 80cabfad bellard
 * furnished to do so, subject to the following conditions:
12 80cabfad bellard
 *
13 80cabfad bellard
 * The above copyright notice and this permission notice shall be included in
14 80cabfad bellard
 * all copies or substantial portions of the Software.
15 80cabfad bellard
 *
16 80cabfad bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 80cabfad bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 80cabfad bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 80cabfad bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 80cabfad bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 80cabfad bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 80cabfad bellard
 * THE SOFTWARE.
23 80cabfad bellard
 */
24 87ecb68b pbrook
#include "hw.h"
25 87ecb68b pbrook
#include "pc.h"
26 87ecb68b pbrook
#include "isa.h"
27 87ecb68b pbrook
#include "console.h"
28 80cabfad bellard
29 80cabfad bellard
/* debug PIC */
30 80cabfad bellard
//#define DEBUG_PIC
31 80cabfad bellard
32 b41a2cd1 bellard
//#define DEBUG_IRQ_LATENCY
33 4a0fb71e bellard
//#define DEBUG_IRQ_COUNT
34 b41a2cd1 bellard
35 80cabfad bellard
typedef struct PicState {
36 80cabfad bellard
    uint8_t last_irr; /* edge detection */
37 80cabfad bellard
    uint8_t irr; /* interrupt request register */
38 80cabfad bellard
    uint8_t imr; /* interrupt mask register */
39 80cabfad bellard
    uint8_t isr; /* interrupt service register */
40 80cabfad bellard
    uint8_t priority_add; /* highest irq priority */
41 80cabfad bellard
    uint8_t irq_base;
42 80cabfad bellard
    uint8_t read_reg_select;
43 80cabfad bellard
    uint8_t poll;
44 80cabfad bellard
    uint8_t special_mask;
45 80cabfad bellard
    uint8_t init_state;
46 80cabfad bellard
    uint8_t auto_eoi;
47 80cabfad bellard
    uint8_t rotate_on_auto_eoi;
48 80cabfad bellard
    uint8_t special_fully_nested_mode;
49 80cabfad bellard
    uint8_t init4; /* true if 4 byte init */
50 2053152b ths
    uint8_t single_mode; /* true if slave pic is not initialized */
51 660de336 bellard
    uint8_t elcr; /* PIIX edge/trigger selection*/
52 660de336 bellard
    uint8_t elcr_mask;
53 3de388f6 bellard
    PicState2 *pics_state;
54 80cabfad bellard
} PicState;
55 80cabfad bellard
56 3de388f6 bellard
struct PicState2 {
57 3de388f6 bellard
    /* 0 is master pic, 1 is slave pic */
58 3de388f6 bellard
    /* XXX: better separation between the two pics */
59 3de388f6 bellard
    PicState pics[2];
60 d537cf6c pbrook
    qemu_irq parent_irq;
61 3de388f6 bellard
    void *irq_request_opaque;
62 d592d303 bellard
    /* IOAPIC callback support */
63 d592d303 bellard
    SetIRQFunc *alt_irq_func;
64 d592d303 bellard
    void *alt_irq_opaque;
65 3de388f6 bellard
};
66 80cabfad bellard
67 4a0fb71e bellard
#if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT)
68 4a0fb71e bellard
static int irq_level[16];
69 4a0fb71e bellard
#endif
70 4a0fb71e bellard
#ifdef DEBUG_IRQ_COUNT
71 4a0fb71e bellard
static uint64_t irq_count[16];
72 4a0fb71e bellard
#endif
73 4a0fb71e bellard
74 80cabfad bellard
/* set irq level. If an edge is detected, then the IRR is set to 1 */
75 80cabfad bellard
static inline void pic_set_irq1(PicState *s, int irq, int level)
76 80cabfad bellard
{
77 80cabfad bellard
    int mask;
78 80cabfad bellard
    mask = 1 << irq;
79 660de336 bellard
    if (s->elcr & mask) {
80 660de336 bellard
        /* level triggered */
81 660de336 bellard
        if (level) {
82 80cabfad bellard
            s->irr |= mask;
83 660de336 bellard
            s->last_irr |= mask;
84 660de336 bellard
        } else {
85 660de336 bellard
            s->irr &= ~mask;
86 660de336 bellard
            s->last_irr &= ~mask;
87 660de336 bellard
        }
88 80cabfad bellard
    } else {
89 660de336 bellard
        /* edge triggered */
90 660de336 bellard
        if (level) {
91 660de336 bellard
            if ((s->last_irr & mask) == 0)
92 660de336 bellard
                s->irr |= mask;
93 660de336 bellard
            s->last_irr |= mask;
94 660de336 bellard
        } else {
95 660de336 bellard
            s->last_irr &= ~mask;
96 660de336 bellard
        }
97 80cabfad bellard
    }
98 80cabfad bellard
}
99 80cabfad bellard
100 80cabfad bellard
/* return the highest priority found in mask (highest = smallest
101 80cabfad bellard
   number). Return 8 if no irq */
102 80cabfad bellard
static inline int get_priority(PicState *s, int mask)
103 80cabfad bellard
{
104 80cabfad bellard
    int priority;
105 80cabfad bellard
    if (mask == 0)
106 80cabfad bellard
        return 8;
107 80cabfad bellard
    priority = 0;
108 80cabfad bellard
    while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
109 80cabfad bellard
        priority++;
110 80cabfad bellard
    return priority;
111 80cabfad bellard
}
112 80cabfad bellard
113 80cabfad bellard
/* return the pic wanted interrupt. return -1 if none */
114 80cabfad bellard
static int pic_get_irq(PicState *s)
115 80cabfad bellard
{
116 80cabfad bellard
    int mask, cur_priority, priority;
117 80cabfad bellard
118 80cabfad bellard
    mask = s->irr & ~s->imr;
119 80cabfad bellard
    priority = get_priority(s, mask);
120 80cabfad bellard
    if (priority == 8)
121 80cabfad bellard
        return -1;
122 80cabfad bellard
    /* compute current priority. If special fully nested mode on the
123 80cabfad bellard
       master, the IRQ coming from the slave is not taken into account
124 80cabfad bellard
       for the priority computation. */
125 80cabfad bellard
    mask = s->isr;
126 3de388f6 bellard
    if (s->special_fully_nested_mode && s == &s->pics_state->pics[0])
127 80cabfad bellard
        mask &= ~(1 << 2);
128 80cabfad bellard
    cur_priority = get_priority(s, mask);
129 80cabfad bellard
    if (priority < cur_priority) {
130 80cabfad bellard
        /* higher priority found: an irq should be generated */
131 80cabfad bellard
        return (priority + s->priority_add) & 7;
132 80cabfad bellard
    } else {
133 80cabfad bellard
        return -1;
134 80cabfad bellard
    }
135 80cabfad bellard
}
136 80cabfad bellard
137 80cabfad bellard
/* raise irq to CPU if necessary. must be called every time the active
138 80cabfad bellard
   irq may change */
139 3de388f6 bellard
/* XXX: should not export it, but it is needed for an APIC kludge */
140 3de388f6 bellard
void pic_update_irq(PicState2 *s)
141 80cabfad bellard
{
142 80cabfad bellard
    int irq2, irq;
143 80cabfad bellard
144 80cabfad bellard
    /* first look at slave pic */
145 3de388f6 bellard
    irq2 = pic_get_irq(&s->pics[1]);
146 80cabfad bellard
    if (irq2 >= 0) {
147 80cabfad bellard
        /* if irq request by slave pic, signal master PIC */
148 3de388f6 bellard
        pic_set_irq1(&s->pics[0], 2, 1);
149 3de388f6 bellard
        pic_set_irq1(&s->pics[0], 2, 0);
150 80cabfad bellard
    }
151 80cabfad bellard
    /* look at requested irq */
152 3de388f6 bellard
    irq = pic_get_irq(&s->pics[0]);
153 80cabfad bellard
    if (irq >= 0) {
154 80cabfad bellard
#if defined(DEBUG_PIC)
155 80cabfad bellard
        {
156 80cabfad bellard
            int i;
157 80cabfad bellard
            for(i = 0; i < 2; i++) {
158 5fafdf24 ths
                printf("pic%d: imr=%x irr=%x padd=%d\n",
159 5fafdf24 ths
                       i, s->pics[i].imr, s->pics[i].irr,
160 3de388f6 bellard
                       s->pics[i].priority_add);
161 3b46e624 ths
162 80cabfad bellard
            }
163 80cabfad bellard
        }
164 2444ca41 bellard
        printf("pic: cpu_interrupt\n");
165 80cabfad bellard
#endif
166 d537cf6c pbrook
        qemu_irq_raise(s->parent_irq);
167 80cabfad bellard
    }
168 4de9b249 ths
169 4de9b249 ths
/* all targets should do this rather than acking the IRQ in the cpu */
170 5a9b7d36 j_mayer
#if defined(TARGET_MIPS) || defined(TARGET_PPC)
171 4de9b249 ths
    else {
172 d537cf6c pbrook
        qemu_irq_lower(s->parent_irq);
173 4de9b249 ths
    }
174 4de9b249 ths
#endif
175 80cabfad bellard
}
176 80cabfad bellard
177 80cabfad bellard
#ifdef DEBUG_IRQ_LATENCY
178 80cabfad bellard
int64_t irq_time[16];
179 80cabfad bellard
#endif
180 80cabfad bellard
181 9596ebb7 pbrook
static void i8259_set_irq(void *opaque, int irq, int level)
182 80cabfad bellard
{
183 3de388f6 bellard
    PicState2 *s = opaque;
184 3de388f6 bellard
185 4a0fb71e bellard
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
186 80cabfad bellard
    if (level != irq_level[irq]) {
187 4a0fb71e bellard
#if defined(DEBUG_PIC)
188 d537cf6c pbrook
        printf("i8259_set_irq: irq=%d level=%d\n", irq, level);
189 4a0fb71e bellard
#endif
190 80cabfad bellard
        irq_level[irq] = level;
191 4a0fb71e bellard
#ifdef DEBUG_IRQ_COUNT
192 4a0fb71e bellard
        if (level == 1)
193 4a0fb71e bellard
            irq_count[irq]++;
194 4a0fb71e bellard
#endif
195 80cabfad bellard
    }
196 80cabfad bellard
#endif
197 80cabfad bellard
#ifdef DEBUG_IRQ_LATENCY
198 80cabfad bellard
    if (level) {
199 2444ca41 bellard
        irq_time[irq] = qemu_get_clock(vm_clock);
200 80cabfad bellard
    }
201 80cabfad bellard
#endif
202 3de388f6 bellard
    pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
203 d592d303 bellard
    /* used for IOAPIC irqs */
204 d592d303 bellard
    if (s->alt_irq_func)
205 d592d303 bellard
        s->alt_irq_func(s->alt_irq_opaque, irq, level);
206 3de388f6 bellard
    pic_update_irq(s);
207 80cabfad bellard
}
208 80cabfad bellard
209 80cabfad bellard
/* acknowledge interrupt 'irq' */
210 80cabfad bellard
static inline void pic_intack(PicState *s, int irq)
211 80cabfad bellard
{
212 80cabfad bellard
    if (s->auto_eoi) {
213 80cabfad bellard
        if (s->rotate_on_auto_eoi)
214 80cabfad bellard
            s->priority_add = (irq + 1) & 7;
215 80cabfad bellard
    } else {
216 80cabfad bellard
        s->isr |= (1 << irq);
217 80cabfad bellard
    }
218 0ecf89aa bellard
    /* We don't clear a level sensitive interrupt here */
219 0ecf89aa bellard
    if (!(s->elcr & (1 << irq)))
220 0ecf89aa bellard
        s->irr &= ~(1 << irq);
221 80cabfad bellard
}
222 80cabfad bellard
223 3de388f6 bellard
int pic_read_irq(PicState2 *s)
224 80cabfad bellard
{
225 80cabfad bellard
    int irq, irq2, intno;
226 80cabfad bellard
227 3de388f6 bellard
    irq = pic_get_irq(&s->pics[0]);
228 15aeac38 bellard
    if (irq >= 0) {
229 3de388f6 bellard
        pic_intack(&s->pics[0], irq);
230 15aeac38 bellard
        if (irq == 2) {
231 3de388f6 bellard
            irq2 = pic_get_irq(&s->pics[1]);
232 15aeac38 bellard
            if (irq2 >= 0) {
233 3de388f6 bellard
                pic_intack(&s->pics[1], irq2);
234 15aeac38 bellard
            } else {
235 15aeac38 bellard
                /* spurious IRQ on slave controller */
236 15aeac38 bellard
                irq2 = 7;
237 15aeac38 bellard
            }
238 3de388f6 bellard
            intno = s->pics[1].irq_base + irq2;
239 15aeac38 bellard
            irq = irq2 + 8;
240 15aeac38 bellard
        } else {
241 3de388f6 bellard
            intno = s->pics[0].irq_base + irq;
242 15aeac38 bellard
        }
243 15aeac38 bellard
    } else {
244 15aeac38 bellard
        /* spurious IRQ on host controller */
245 15aeac38 bellard
        irq = 7;
246 3de388f6 bellard
        intno = s->pics[0].irq_base + irq;
247 15aeac38 bellard
    }
248 3de388f6 bellard
    pic_update_irq(s);
249 3b46e624 ths
250 80cabfad bellard
#ifdef DEBUG_IRQ_LATENCY
251 5fafdf24 ths
    printf("IRQ%d latency=%0.3fus\n",
252 5fafdf24 ths
           irq,
253 2444ca41 bellard
           (double)(qemu_get_clock(vm_clock) - irq_time[irq]) * 1000000.0 / ticks_per_sec);
254 80cabfad bellard
#endif
255 80cabfad bellard
#if defined(DEBUG_PIC)
256 80cabfad bellard
    printf("pic_interrupt: irq=%d\n", irq);
257 80cabfad bellard
#endif
258 80cabfad bellard
    return intno;
259 80cabfad bellard
}
260 80cabfad bellard
261 d7d02e3c bellard
static void pic_reset(void *opaque)
262 d7d02e3c bellard
{
263 d7d02e3c bellard
    PicState *s = opaque;
264 d7d02e3c bellard
265 3de388f6 bellard
    s->last_irr = 0;
266 3de388f6 bellard
    s->irr = 0;
267 3de388f6 bellard
    s->imr = 0;
268 3de388f6 bellard
    s->isr = 0;
269 3de388f6 bellard
    s->priority_add = 0;
270 3de388f6 bellard
    s->irq_base = 0;
271 3de388f6 bellard
    s->read_reg_select = 0;
272 3de388f6 bellard
    s->poll = 0;
273 3de388f6 bellard
    s->special_mask = 0;
274 3de388f6 bellard
    s->init_state = 0;
275 3de388f6 bellard
    s->auto_eoi = 0;
276 3de388f6 bellard
    s->rotate_on_auto_eoi = 0;
277 3de388f6 bellard
    s->special_fully_nested_mode = 0;
278 3de388f6 bellard
    s->init4 = 0;
279 2053152b ths
    s->single_mode = 0;
280 4dbe19e1 bellard
    /* Note: ELCR is not reset */
281 d7d02e3c bellard
}
282 d7d02e3c bellard
283 b41a2cd1 bellard
static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
284 80cabfad bellard
{
285 b41a2cd1 bellard
    PicState *s = opaque;
286 d7d02e3c bellard
    int priority, cmd, irq;
287 80cabfad bellard
288 80cabfad bellard
#ifdef DEBUG_PIC
289 80cabfad bellard
    printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val);
290 80cabfad bellard
#endif
291 80cabfad bellard
    addr &= 1;
292 80cabfad bellard
    if (addr == 0) {
293 80cabfad bellard
        if (val & 0x10) {
294 80cabfad bellard
            /* init */
295 d7d02e3c bellard
            pic_reset(s);
296 b54ad049 bellard
            /* deassert a pending interrupt */
297 d537cf6c pbrook
            qemu_irq_lower(s->pics_state->parent_irq);
298 80cabfad bellard
            s->init_state = 1;
299 80cabfad bellard
            s->init4 = val & 1;
300 2053152b ths
            s->single_mode = val & 2;
301 80cabfad bellard
            if (val & 0x08)
302 80cabfad bellard
                hw_error("level sensitive irq not supported");
303 80cabfad bellard
        } else if (val & 0x08) {
304 80cabfad bellard
            if (val & 0x04)
305 80cabfad bellard
                s->poll = 1;
306 80cabfad bellard
            if (val & 0x02)
307 80cabfad bellard
                s->read_reg_select = val & 1;
308 80cabfad bellard
            if (val & 0x40)
309 80cabfad bellard
                s->special_mask = (val >> 5) & 1;
310 80cabfad bellard
        } else {
311 80cabfad bellard
            cmd = val >> 5;
312 80cabfad bellard
            switch(cmd) {
313 80cabfad bellard
            case 0:
314 80cabfad bellard
            case 4:
315 80cabfad bellard
                s->rotate_on_auto_eoi = cmd >> 2;
316 80cabfad bellard
                break;
317 80cabfad bellard
            case 1: /* end of interrupt */
318 80cabfad bellard
            case 5:
319 80cabfad bellard
                priority = get_priority(s, s->isr);
320 80cabfad bellard
                if (priority != 8) {
321 80cabfad bellard
                    irq = (priority + s->priority_add) & 7;
322 80cabfad bellard
                    s->isr &= ~(1 << irq);
323 80cabfad bellard
                    if (cmd == 5)
324 80cabfad bellard
                        s->priority_add = (irq + 1) & 7;
325 3de388f6 bellard
                    pic_update_irq(s->pics_state);
326 80cabfad bellard
                }
327 80cabfad bellard
                break;
328 80cabfad bellard
            case 3:
329 80cabfad bellard
                irq = val & 7;
330 80cabfad bellard
                s->isr &= ~(1 << irq);
331 3de388f6 bellard
                pic_update_irq(s->pics_state);
332 80cabfad bellard
                break;
333 80cabfad bellard
            case 6:
334 80cabfad bellard
                s->priority_add = (val + 1) & 7;
335 3de388f6 bellard
                pic_update_irq(s->pics_state);
336 80cabfad bellard
                break;
337 80cabfad bellard
            case 7:
338 80cabfad bellard
                irq = val & 7;
339 80cabfad bellard
                s->isr &= ~(1 << irq);
340 80cabfad bellard
                s->priority_add = (irq + 1) & 7;
341 3de388f6 bellard
                pic_update_irq(s->pics_state);
342 80cabfad bellard
                break;
343 80cabfad bellard
            default:
344 80cabfad bellard
                /* no operation */
345 80cabfad bellard
                break;
346 80cabfad bellard
            }
347 80cabfad bellard
        }
348 80cabfad bellard
    } else {
349 80cabfad bellard
        switch(s->init_state) {
350 80cabfad bellard
        case 0:
351 80cabfad bellard
            /* normal mode */
352 80cabfad bellard
            s->imr = val;
353 3de388f6 bellard
            pic_update_irq(s->pics_state);
354 80cabfad bellard
            break;
355 80cabfad bellard
        case 1:
356 80cabfad bellard
            s->irq_base = val & 0xf8;
357 2bb081f7 ths
            s->init_state = s->single_mode ? (s->init4 ? 3 : 0) : 2;
358 80cabfad bellard
            break;
359 80cabfad bellard
        case 2:
360 80cabfad bellard
            if (s->init4) {
361 80cabfad bellard
                s->init_state = 3;
362 80cabfad bellard
            } else {
363 80cabfad bellard
                s->init_state = 0;
364 80cabfad bellard
            }
365 80cabfad bellard
            break;
366 80cabfad bellard
        case 3:
367 80cabfad bellard
            s->special_fully_nested_mode = (val >> 4) & 1;
368 80cabfad bellard
            s->auto_eoi = (val >> 1) & 1;
369 80cabfad bellard
            s->init_state = 0;
370 80cabfad bellard
            break;
371 80cabfad bellard
        }
372 80cabfad bellard
    }
373 80cabfad bellard
}
374 80cabfad bellard
375 80cabfad bellard
static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
376 80cabfad bellard
{
377 80cabfad bellard
    int ret;
378 80cabfad bellard
379 80cabfad bellard
    ret = pic_get_irq(s);
380 80cabfad bellard
    if (ret >= 0) {
381 80cabfad bellard
        if (addr1 >> 7) {
382 3de388f6 bellard
            s->pics_state->pics[0].isr &= ~(1 << 2);
383 3de388f6 bellard
            s->pics_state->pics[0].irr &= ~(1 << 2);
384 80cabfad bellard
        }
385 80cabfad bellard
        s->irr &= ~(1 << ret);
386 80cabfad bellard
        s->isr &= ~(1 << ret);
387 80cabfad bellard
        if (addr1 >> 7 || ret != 2)
388 3de388f6 bellard
            pic_update_irq(s->pics_state);
389 80cabfad bellard
    } else {
390 80cabfad bellard
        ret = 0x07;
391 3de388f6 bellard
        pic_update_irq(s->pics_state);
392 80cabfad bellard
    }
393 80cabfad bellard
394 80cabfad bellard
    return ret;
395 80cabfad bellard
}
396 80cabfad bellard
397 b41a2cd1 bellard
static uint32_t pic_ioport_read(void *opaque, uint32_t addr1)
398 80cabfad bellard
{
399 b41a2cd1 bellard
    PicState *s = opaque;
400 80cabfad bellard
    unsigned int addr;
401 80cabfad bellard
    int ret;
402 80cabfad bellard
403 80cabfad bellard
    addr = addr1;
404 80cabfad bellard
    addr &= 1;
405 80cabfad bellard
    if (s->poll) {
406 80cabfad bellard
        ret = pic_poll_read(s, addr1);
407 80cabfad bellard
        s->poll = 0;
408 80cabfad bellard
    } else {
409 80cabfad bellard
        if (addr == 0) {
410 80cabfad bellard
            if (s->read_reg_select)
411 80cabfad bellard
                ret = s->isr;
412 80cabfad bellard
            else
413 80cabfad bellard
                ret = s->irr;
414 80cabfad bellard
        } else {
415 80cabfad bellard
            ret = s->imr;
416 80cabfad bellard
        }
417 80cabfad bellard
    }
418 80cabfad bellard
#ifdef DEBUG_PIC
419 80cabfad bellard
    printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret);
420 80cabfad bellard
#endif
421 80cabfad bellard
    return ret;
422 80cabfad bellard
}
423 80cabfad bellard
424 80cabfad bellard
/* memory mapped interrupt status */
425 3de388f6 bellard
/* XXX: may be the same than pic_read_irq() */
426 3de388f6 bellard
uint32_t pic_intack_read(PicState2 *s)
427 80cabfad bellard
{
428 80cabfad bellard
    int ret;
429 80cabfad bellard
430 3de388f6 bellard
    ret = pic_poll_read(&s->pics[0], 0x00);
431 80cabfad bellard
    if (ret == 2)
432 3de388f6 bellard
        ret = pic_poll_read(&s->pics[1], 0x80) + 8;
433 80cabfad bellard
    /* Prepare for ISR read */
434 3de388f6 bellard
    s->pics[0].read_reg_select = 1;
435 3b46e624 ths
436 80cabfad bellard
    return ret;
437 80cabfad bellard
}
438 80cabfad bellard
439 660de336 bellard
static void elcr_ioport_write(void *opaque, uint32_t addr, uint32_t val)
440 660de336 bellard
{
441 660de336 bellard
    PicState *s = opaque;
442 660de336 bellard
    s->elcr = val & s->elcr_mask;
443 660de336 bellard
}
444 660de336 bellard
445 660de336 bellard
static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1)
446 660de336 bellard
{
447 660de336 bellard
    PicState *s = opaque;
448 660de336 bellard
    return s->elcr;
449 660de336 bellard
}
450 660de336 bellard
451 b0a21b53 bellard
static void pic_save(QEMUFile *f, void *opaque)
452 b0a21b53 bellard
{
453 b0a21b53 bellard
    PicState *s = opaque;
454 3b46e624 ths
455 b0a21b53 bellard
    qemu_put_8s(f, &s->last_irr);
456 b0a21b53 bellard
    qemu_put_8s(f, &s->irr);
457 b0a21b53 bellard
    qemu_put_8s(f, &s->imr);
458 b0a21b53 bellard
    qemu_put_8s(f, &s->isr);
459 b0a21b53 bellard
    qemu_put_8s(f, &s->priority_add);
460 b0a21b53 bellard
    qemu_put_8s(f, &s->irq_base);
461 b0a21b53 bellard
    qemu_put_8s(f, &s->read_reg_select);
462 b0a21b53 bellard
    qemu_put_8s(f, &s->poll);
463 b0a21b53 bellard
    qemu_put_8s(f, &s->special_mask);
464 b0a21b53 bellard
    qemu_put_8s(f, &s->init_state);
465 b0a21b53 bellard
    qemu_put_8s(f, &s->auto_eoi);
466 b0a21b53 bellard
    qemu_put_8s(f, &s->rotate_on_auto_eoi);
467 b0a21b53 bellard
    qemu_put_8s(f, &s->special_fully_nested_mode);
468 b0a21b53 bellard
    qemu_put_8s(f, &s->init4);
469 2053152b ths
    qemu_put_8s(f, &s->single_mode);
470 660de336 bellard
    qemu_put_8s(f, &s->elcr);
471 b0a21b53 bellard
}
472 b0a21b53 bellard
473 b0a21b53 bellard
static int pic_load(QEMUFile *f, void *opaque, int version_id)
474 b0a21b53 bellard
{
475 b0a21b53 bellard
    PicState *s = opaque;
476 3b46e624 ths
477 b0a21b53 bellard
    if (version_id != 1)
478 b0a21b53 bellard
        return -EINVAL;
479 b0a21b53 bellard
480 b0a21b53 bellard
    qemu_get_8s(f, &s->last_irr);
481 b0a21b53 bellard
    qemu_get_8s(f, &s->irr);
482 b0a21b53 bellard
    qemu_get_8s(f, &s->imr);
483 b0a21b53 bellard
    qemu_get_8s(f, &s->isr);
484 b0a21b53 bellard
    qemu_get_8s(f, &s->priority_add);
485 b0a21b53 bellard
    qemu_get_8s(f, &s->irq_base);
486 b0a21b53 bellard
    qemu_get_8s(f, &s->read_reg_select);
487 b0a21b53 bellard
    qemu_get_8s(f, &s->poll);
488 b0a21b53 bellard
    qemu_get_8s(f, &s->special_mask);
489 b0a21b53 bellard
    qemu_get_8s(f, &s->init_state);
490 b0a21b53 bellard
    qemu_get_8s(f, &s->auto_eoi);
491 b0a21b53 bellard
    qemu_get_8s(f, &s->rotate_on_auto_eoi);
492 b0a21b53 bellard
    qemu_get_8s(f, &s->special_fully_nested_mode);
493 b0a21b53 bellard
    qemu_get_8s(f, &s->init4);
494 2053152b ths
    qemu_get_8s(f, &s->single_mode);
495 660de336 bellard
    qemu_get_8s(f, &s->elcr);
496 b0a21b53 bellard
    return 0;
497 b0a21b53 bellard
}
498 b0a21b53 bellard
499 b0a21b53 bellard
/* XXX: add generic master/slave system */
500 660de336 bellard
static void pic_init1(int io_addr, int elcr_addr, PicState *s)
501 b0a21b53 bellard
{
502 b0a21b53 bellard
    register_ioport_write(io_addr, 2, 1, pic_ioport_write, s);
503 b0a21b53 bellard
    register_ioport_read(io_addr, 2, 1, pic_ioport_read, s);
504 660de336 bellard
    if (elcr_addr >= 0) {
505 660de336 bellard
        register_ioport_write(elcr_addr, 1, 1, elcr_ioport_write, s);
506 660de336 bellard
        register_ioport_read(elcr_addr, 1, 1, elcr_ioport_read, s);
507 660de336 bellard
    }
508 b0a21b53 bellard
    register_savevm("i8259", io_addr, 1, pic_save, pic_load, s);
509 d7d02e3c bellard
    qemu_register_reset(pic_reset, s);
510 b0a21b53 bellard
}
511 b0a21b53 bellard
512 ba91cd80 bellard
void pic_info(void)
513 ba91cd80 bellard
{
514 ba91cd80 bellard
    int i;
515 ba91cd80 bellard
    PicState *s;
516 3b46e624 ths
517 3de388f6 bellard
    if (!isa_pic)
518 3de388f6 bellard
        return;
519 ba91cd80 bellard
520 ba91cd80 bellard
    for(i=0;i<2;i++) {
521 3de388f6 bellard
        s = &isa_pic->pics[i];
522 15aeac38 bellard
        term_printf("pic%d: irr=%02x imr=%02x isr=%02x hprio=%d irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
523 5fafdf24 ths
                    i, s->irr, s->imr, s->isr, s->priority_add,
524 5fafdf24 ths
                    s->irq_base, s->read_reg_select, s->elcr,
525 15aeac38 bellard
                    s->special_fully_nested_mode);
526 ba91cd80 bellard
    }
527 ba91cd80 bellard
}
528 ba91cd80 bellard
529 4a0fb71e bellard
void irq_info(void)
530 4a0fb71e bellard
{
531 4a0fb71e bellard
#ifndef DEBUG_IRQ_COUNT
532 4a0fb71e bellard
    term_printf("irq statistic code not compiled.\n");
533 4a0fb71e bellard
#else
534 4a0fb71e bellard
    int i;
535 4a0fb71e bellard
    int64_t count;
536 4a0fb71e bellard
537 4a0fb71e bellard
    term_printf("IRQ statistics:\n");
538 4a0fb71e bellard
    for (i = 0; i < 16; i++) {
539 4a0fb71e bellard
        count = irq_count[i];
540 4a0fb71e bellard
        if (count > 0)
541 26a76461 bellard
            term_printf("%2d: %" PRId64 "\n", i, count);
542 4a0fb71e bellard
    }
543 4a0fb71e bellard
#endif
544 4a0fb71e bellard
}
545 ba91cd80 bellard
546 d537cf6c pbrook
qemu_irq *i8259_init(qemu_irq parent_irq)
547 80cabfad bellard
{
548 3de388f6 bellard
    PicState2 *s;
549 d537cf6c pbrook
550 3de388f6 bellard
    s = qemu_mallocz(sizeof(PicState2));
551 3de388f6 bellard
    if (!s)
552 3de388f6 bellard
        return NULL;
553 3de388f6 bellard
    pic_init1(0x20, 0x4d0, &s->pics[0]);
554 3de388f6 bellard
    pic_init1(0xa0, 0x4d1, &s->pics[1]);
555 3de388f6 bellard
    s->pics[0].elcr_mask = 0xf8;
556 3de388f6 bellard
    s->pics[1].elcr_mask = 0xde;
557 d537cf6c pbrook
    s->parent_irq = parent_irq;
558 3de388f6 bellard
    s->pics[0].pics_state = s;
559 3de388f6 bellard
    s->pics[1].pics_state = s;
560 d537cf6c pbrook
    isa_pic = s;
561 d537cf6c pbrook
    return qemu_allocate_irqs(i8259_set_irq, s, 16);
562 80cabfad bellard
}
563 d592d303 bellard
564 d592d303 bellard
void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func,
565 d592d303 bellard
                          void *alt_irq_opaque)
566 d592d303 bellard
{
567 d592d303 bellard
    s->alt_irq_func = alt_irq_func;
568 d592d303 bellard
    s->alt_irq_opaque = alt_irq_opaque;
569 d592d303 bellard
}