Statistics
| Branch: | Revision:

root / hw / i8259.c @ 098d314a

History | View | Annotate | Download (15.4 kB)

1
/*
2
 * QEMU 8259 interrupt controller emulation
3
 *
4
 * Copyright (c) 2003-2004 Fabrice Bellard
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24
#include "hw.h"
25
#include "pc.h"
26
#include "isa.h"
27
#include "monitor.h"
28
#include "qemu-timer.h"
29

    
30
/* debug PIC */
31
//#define DEBUG_PIC
32

    
33
#ifdef DEBUG_PIC
34
#define DPRINTF(fmt, ...)                                       \
35
    do { printf("pic: " fmt , ## __VA_ARGS__); } while (0)
36
#else
37
#define DPRINTF(fmt, ...)
38
#endif
39

    
40
//#define DEBUG_IRQ_LATENCY
41
//#define DEBUG_IRQ_COUNT
42

    
43
typedef struct PicState {
44
    uint8_t last_irr; /* edge detection */
45
    uint8_t irr; /* interrupt request register */
46
    uint8_t imr; /* interrupt mask register */
47
    uint8_t isr; /* interrupt service register */
48
    uint8_t priority_add; /* highest irq priority */
49
    uint8_t irq_base;
50
    uint8_t read_reg_select;
51
    uint8_t poll;
52
    uint8_t special_mask;
53
    uint8_t init_state;
54
    uint8_t auto_eoi;
55
    uint8_t rotate_on_auto_eoi;
56
    uint8_t special_fully_nested_mode;
57
    uint8_t init4; /* true if 4 byte init */
58
    uint8_t single_mode; /* true if slave pic is not initialized */
59
    uint8_t elcr; /* PIIX edge/trigger selection*/
60
    uint8_t elcr_mask;
61
    PicState2 *pics_state;
62
    MemoryRegion base_io;
63
    MemoryRegion elcr_io;
64
} PicState;
65

    
66
struct PicState2 {
67
    /* 0 is master pic, 1 is slave pic */
68
    /* XXX: better separation between the two pics */
69
    PicState pics[2];
70
    qemu_irq parent_irq;
71
    void *irq_request_opaque;
72
};
73

    
74
#if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT)
75
static int irq_level[16];
76
#endif
77
#ifdef DEBUG_IRQ_COUNT
78
static uint64_t irq_count[16];
79
#endif
80
PicState2 *isa_pic;
81

    
82
/* set irq level. If an edge is detected, then the IRR is set to 1 */
83
static inline void pic_set_irq1(PicState *s, int irq, int level)
84
{
85
    int mask;
86
    mask = 1 << irq;
87
    if (s->elcr & mask) {
88
        /* level triggered */
89
        if (level) {
90
            s->irr |= mask;
91
            s->last_irr |= mask;
92
        } else {
93
            s->irr &= ~mask;
94
            s->last_irr &= ~mask;
95
        }
96
    } else {
97
        /* edge triggered */
98
        if (level) {
99
            if ((s->last_irr & mask) == 0)
100
                s->irr |= mask;
101
            s->last_irr |= mask;
102
        } else {
103
            s->last_irr &= ~mask;
104
        }
105
    }
106
}
107

    
108
/* return the highest priority found in mask (highest = smallest
109
   number). Return 8 if no irq */
110
static inline int get_priority(PicState *s, int mask)
111
{
112
    int priority;
113
    if (mask == 0)
114
        return 8;
115
    priority = 0;
116
    while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
117
        priority++;
118
    return priority;
119
}
120

    
121
/* return the pic wanted interrupt. return -1 if none */
122
static int pic_get_irq(PicState *s)
123
{
124
    int mask, cur_priority, priority;
125

    
126
    mask = s->irr & ~s->imr;
127
    priority = get_priority(s, mask);
128
    if (priority == 8)
129
        return -1;
130
    /* compute current priority. If special fully nested mode on the
131
       master, the IRQ coming from the slave is not taken into account
132
       for the priority computation. */
133
    mask = s->isr;
134
    if (s->special_mask)
135
        mask &= ~s->imr;
136
    if (s->special_fully_nested_mode && s == &s->pics_state->pics[0])
137
        mask &= ~(1 << 2);
138
    cur_priority = get_priority(s, mask);
139
    if (priority < cur_priority) {
140
        /* higher priority found: an irq should be generated */
141
        return (priority + s->priority_add) & 7;
142
    } else {
143
        return -1;
144
    }
145
}
146

    
147
/* raise irq to CPU if necessary. must be called every time the active
148
   irq may change */
149
/* XXX: should not export it, but it is needed for an APIC kludge */
150
void pic_update_irq(PicState2 *s)
151
{
152
    int irq2, irq;
153

    
154
    /* first look at slave pic */
155
    irq2 = pic_get_irq(&s->pics[1]);
156
    if (irq2 >= 0) {
157
        /* if irq request by slave pic, signal master PIC */
158
        pic_set_irq1(&s->pics[0], 2, 1);
159
        pic_set_irq1(&s->pics[0], 2, 0);
160
    }
161
    /* look at requested irq */
162
    irq = pic_get_irq(&s->pics[0]);
163
    if (irq >= 0) {
164
#if defined(DEBUG_PIC)
165
        {
166
            int i;
167
            for(i = 0; i < 2; i++) {
168
                printf("pic%d: imr=%x irr=%x padd=%d\n",
169
                       i, s->pics[i].imr, s->pics[i].irr,
170
                       s->pics[i].priority_add);
171

    
172
            }
173
        }
174
        printf("pic: cpu_interrupt\n");
175
#endif
176
        qemu_irq_raise(s->parent_irq);
177
    }
178

    
179
/* all targets should do this rather than acking the IRQ in the cpu */
180
#if defined(TARGET_MIPS) || defined(TARGET_PPC) || defined(TARGET_ALPHA)
181
    else {
182
        qemu_irq_lower(s->parent_irq);
183
    }
184
#endif
185
}
186

    
187
#ifdef DEBUG_IRQ_LATENCY
188
int64_t irq_time[16];
189
#endif
190

    
191
static void i8259_set_irq(void *opaque, int irq, int level)
192
{
193
    PicState2 *s = opaque;
194

    
195
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
196
    if (level != irq_level[irq]) {
197
        DPRINTF("i8259_set_irq: irq=%d level=%d\n", irq, level);
198
        irq_level[irq] = level;
199
#ifdef DEBUG_IRQ_COUNT
200
        if (level == 1)
201
            irq_count[irq]++;
202
#endif
203
    }
204
#endif
205
#ifdef DEBUG_IRQ_LATENCY
206
    if (level) {
207
        irq_time[irq] = qemu_get_clock_ns(vm_clock);
208
    }
209
#endif
210
    pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
211
    pic_update_irq(s);
212
}
213

    
214
/* acknowledge interrupt 'irq' */
215
static inline void pic_intack(PicState *s, int irq)
216
{
217
    if (s->auto_eoi) {
218
        if (s->rotate_on_auto_eoi)
219
            s->priority_add = (irq + 1) & 7;
220
    } else {
221
        s->isr |= (1 << irq);
222
    }
223
    /* We don't clear a level sensitive interrupt here */
224
    if (!(s->elcr & (1 << irq)))
225
        s->irr &= ~(1 << irq);
226
}
227

    
228
int pic_read_irq(PicState2 *s)
229
{
230
    int irq, irq2, intno;
231

    
232
    irq = pic_get_irq(&s->pics[0]);
233
    if (irq >= 0) {
234
        pic_intack(&s->pics[0], irq);
235
        if (irq == 2) {
236
            irq2 = pic_get_irq(&s->pics[1]);
237
            if (irq2 >= 0) {
238
                pic_intack(&s->pics[1], irq2);
239
            } else {
240
                /* spurious IRQ on slave controller */
241
                irq2 = 7;
242
            }
243
            intno = s->pics[1].irq_base + irq2;
244
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_LATENCY)
245
            irq = irq2 + 8;
246
#endif
247
        } else {
248
            intno = s->pics[0].irq_base + irq;
249
        }
250
    } else {
251
        /* spurious IRQ on host controller */
252
        irq = 7;
253
        intno = s->pics[0].irq_base + irq;
254
    }
255
    pic_update_irq(s);
256

    
257
#ifdef DEBUG_IRQ_LATENCY
258
    printf("IRQ%d latency=%0.3fus\n",
259
           irq,
260
           (double)(qemu_get_clock_ns(vm_clock) -
261
                    irq_time[irq]) * 1000000.0 / get_ticks_per_sec());
262
#endif
263
    DPRINTF("pic_interrupt: irq=%d\n", irq);
264
    return intno;
265
}
266

    
267
static void pic_reset(void *opaque)
268
{
269
    PicState *s = opaque;
270

    
271
    s->last_irr = 0;
272
    s->irr = 0;
273
    s->imr = 0;
274
    s->isr = 0;
275
    s->priority_add = 0;
276
    s->irq_base = 0;
277
    s->read_reg_select = 0;
278
    s->poll = 0;
279
    s->special_mask = 0;
280
    s->init_state = 0;
281
    s->auto_eoi = 0;
282
    s->rotate_on_auto_eoi = 0;
283
    s->special_fully_nested_mode = 0;
284
    s->init4 = 0;
285
    s->single_mode = 0;
286
    /* Note: ELCR is not reset */
287
}
288

    
289
static void pic_ioport_write(void *opaque, target_phys_addr_t addr64,
290
                             uint64_t val64, unsigned size)
291
{
292
    PicState *s = opaque;
293
    uint32_t addr = addr64;
294
    uint32_t val = val64;
295
    int priority, cmd, irq;
296

    
297
    DPRINTF("write: addr=0x%02x val=0x%02x\n", addr, val);
298
    if (addr == 0) {
299
        if (val & 0x10) {
300
            /* init */
301
            pic_reset(s);
302
            /* deassert a pending interrupt */
303
            qemu_irq_lower(s->pics_state->parent_irq);
304
            s->init_state = 1;
305
            s->init4 = val & 1;
306
            s->single_mode = val & 2;
307
            if (val & 0x08)
308
                hw_error("level sensitive irq not supported");
309
        } else if (val & 0x08) {
310
            if (val & 0x04)
311
                s->poll = 1;
312
            if (val & 0x02)
313
                s->read_reg_select = val & 1;
314
            if (val & 0x40)
315
                s->special_mask = (val >> 5) & 1;
316
        } else {
317
            cmd = val >> 5;
318
            switch(cmd) {
319
            case 0:
320
            case 4:
321
                s->rotate_on_auto_eoi = cmd >> 2;
322
                break;
323
            case 1: /* end of interrupt */
324
            case 5:
325
                priority = get_priority(s, s->isr);
326
                if (priority != 8) {
327
                    irq = (priority + s->priority_add) & 7;
328
                    s->isr &= ~(1 << irq);
329
                    if (cmd == 5)
330
                        s->priority_add = (irq + 1) & 7;
331
                    pic_update_irq(s->pics_state);
332
                }
333
                break;
334
            case 3:
335
                irq = val & 7;
336
                s->isr &= ~(1 << irq);
337
                pic_update_irq(s->pics_state);
338
                break;
339
            case 6:
340
                s->priority_add = (val + 1) & 7;
341
                pic_update_irq(s->pics_state);
342
                break;
343
            case 7:
344
                irq = val & 7;
345
                s->isr &= ~(1 << irq);
346
                s->priority_add = (irq + 1) & 7;
347
                pic_update_irq(s->pics_state);
348
                break;
349
            default:
350
                /* no operation */
351
                break;
352
            }
353
        }
354
    } else {
355
        switch(s->init_state) {
356
        case 0:
357
            /* normal mode */
358
            s->imr = val;
359
            pic_update_irq(s->pics_state);
360
            break;
361
        case 1:
362
            s->irq_base = val & 0xf8;
363
            s->init_state = s->single_mode ? (s->init4 ? 3 : 0) : 2;
364
            break;
365
        case 2:
366
            if (s->init4) {
367
                s->init_state = 3;
368
            } else {
369
                s->init_state = 0;
370
            }
371
            break;
372
        case 3:
373
            s->special_fully_nested_mode = (val >> 4) & 1;
374
            s->auto_eoi = (val >> 1) & 1;
375
            s->init_state = 0;
376
            break;
377
        }
378
    }
379
}
380

    
381
static uint32_t pic_poll_read(PicState *s)
382
{
383
    int ret;
384

    
385
    ret = pic_get_irq(s);
386
    if (ret >= 0) {
387
        bool slave = (s == &isa_pic->pics[1]);
388

    
389
        if (slave) {
390
            s->pics_state->pics[0].isr &= ~(1 << 2);
391
            s->pics_state->pics[0].irr &= ~(1 << 2);
392
        }
393
        s->irr &= ~(1 << ret);
394
        s->isr &= ~(1 << ret);
395
        if (slave || ret != 2)
396
            pic_update_irq(s->pics_state);
397
    } else {
398
        ret = 0x07;
399
        pic_update_irq(s->pics_state);
400
    }
401

    
402
    return ret;
403
}
404

    
405
static uint64_t pic_ioport_read(void *opaque, target_phys_addr_t addr1,
406
                                unsigned size)
407
{
408
    PicState *s = opaque;
409
    unsigned int addr = addr1;
410
    int ret;
411

    
412
    if (s->poll) {
413
        ret = pic_poll_read(s);
414
        s->poll = 0;
415
    } else {
416
        if (addr == 0) {
417
            if (s->read_reg_select)
418
                ret = s->isr;
419
            else
420
                ret = s->irr;
421
        } else {
422
            ret = s->imr;
423
        }
424
    }
425
    DPRINTF("read: addr=0x%02x val=0x%02x\n", addr, ret);
426
    return ret;
427
}
428

    
429
/* memory mapped interrupt status */
430
/* XXX: may be the same than pic_read_irq() */
431
uint32_t pic_intack_read(PicState2 *s)
432
{
433
    int ret;
434

    
435
    ret = pic_poll_read(&s->pics[0]);
436
    if (ret == 2)
437
        ret = pic_poll_read(&s->pics[1]) + 8;
438
    /* Prepare for ISR read */
439
    s->pics[0].read_reg_select = 1;
440

    
441
    return ret;
442
}
443

    
444
static void elcr_ioport_write(void *opaque, target_phys_addr_t addr,
445
                              uint64_t val, unsigned size)
446
{
447
    PicState *s = opaque;
448
    s->elcr = val & s->elcr_mask;
449
}
450

    
451
static uint64_t elcr_ioport_read(void *opaque, target_phys_addr_t addr,
452
                                 unsigned size)
453
{
454
    PicState *s = opaque;
455
    return s->elcr;
456
}
457

    
458
static const VMStateDescription vmstate_pic = {
459
    .name = "i8259",
460
    .version_id = 1,
461
    .minimum_version_id = 1,
462
    .minimum_version_id_old = 1,
463
    .fields      = (VMStateField []) {
464
        VMSTATE_UINT8(last_irr, PicState),
465
        VMSTATE_UINT8(irr, PicState),
466
        VMSTATE_UINT8(imr, PicState),
467
        VMSTATE_UINT8(isr, PicState),
468
        VMSTATE_UINT8(priority_add, PicState),
469
        VMSTATE_UINT8(irq_base, PicState),
470
        VMSTATE_UINT8(read_reg_select, PicState),
471
        VMSTATE_UINT8(poll, PicState),
472
        VMSTATE_UINT8(special_mask, PicState),
473
        VMSTATE_UINT8(init_state, PicState),
474
        VMSTATE_UINT8(auto_eoi, PicState),
475
        VMSTATE_UINT8(rotate_on_auto_eoi, PicState),
476
        VMSTATE_UINT8(special_fully_nested_mode, PicState),
477
        VMSTATE_UINT8(init4, PicState),
478
        VMSTATE_UINT8(single_mode, PicState),
479
        VMSTATE_UINT8(elcr, PicState),
480
        VMSTATE_END_OF_LIST()
481
    }
482
};
483

    
484
static const MemoryRegionOps pic_base_ioport_ops = {
485
    .read = pic_ioport_read,
486
    .write = pic_ioport_write,
487
    .impl = {
488
        .min_access_size = 1,
489
        .max_access_size = 1,
490
    },
491
};
492

    
493
static const MemoryRegionOps pic_elcr_ioport_ops = {
494
    .read = elcr_ioport_read,
495
    .write = elcr_ioport_write,
496
    .impl = {
497
        .min_access_size = 1,
498
        .max_access_size = 1,
499
    },
500
};
501

    
502
/* XXX: add generic master/slave system */
503
static void pic_init1(int io_addr, int elcr_addr, PicState *s)
504
{
505
    memory_region_init_io(&s->base_io, &pic_base_ioport_ops, s, "pic", 2);
506
    memory_region_init_io(&s->elcr_io, &pic_elcr_ioport_ops, s, "elcr", 1);
507

    
508
    isa_register_ioport(NULL, &s->base_io, io_addr);
509
    if (elcr_addr >= 0) {
510
        isa_register_ioport(NULL, &s->elcr_io, elcr_addr);
511
    }
512

    
513
    vmstate_register(NULL, io_addr, &vmstate_pic, s);
514
    qemu_register_reset(pic_reset, s);
515
}
516

    
517
void pic_info(Monitor *mon)
518
{
519
    int i;
520
    PicState *s;
521

    
522
    if (!isa_pic)
523
        return;
524

    
525
    for(i=0;i<2;i++) {
526
        s = &isa_pic->pics[i];
527
        monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
528
                       "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
529
                       i, s->irr, s->imr, s->isr, s->priority_add,
530
                       s->irq_base, s->read_reg_select, s->elcr,
531
                       s->special_fully_nested_mode);
532
    }
533
}
534

    
535
void irq_info(Monitor *mon)
536
{
537
#ifndef DEBUG_IRQ_COUNT
538
    monitor_printf(mon, "irq statistic code not compiled.\n");
539
#else
540
    int i;
541
    int64_t count;
542

    
543
    monitor_printf(mon, "IRQ statistics:\n");
544
    for (i = 0; i < 16; i++) {
545
        count = irq_count[i];
546
        if (count > 0)
547
            monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
548
    }
549
#endif
550
}
551

    
552
qemu_irq *i8259_init(qemu_irq parent_irq)
553
{
554
    PicState2 *s;
555

    
556
    s = g_malloc0(sizeof(PicState2));
557
    pic_init1(0x20, 0x4d0, &s->pics[0]);
558
    pic_init1(0xa0, 0x4d1, &s->pics[1]);
559
    s->pics[0].elcr_mask = 0xf8;
560
    s->pics[1].elcr_mask = 0xde;
561
    s->parent_irq = parent_irq;
562
    s->pics[0].pics_state = s;
563
    s->pics[1].pics_state = s;
564
    isa_pic = s;
565
    return qemu_allocate_irqs(i8259_set_irq, s, 16);
566
}