Statistics
| Branch: | Revision:

root / hw / i8259.c @ b068d6a7

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