Statistics
| Branch: | Revision:

root / hw / intc / i8259.c @ 8935a442

History | View | Annotate | Download (13.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/hw.h"
25
#include "hw/i386/pc.h"
26
#include "hw/isa/isa.h"
27
#include "monitor/monitor.h"
28
#include "qemu/timer.h"
29
#include "hw/isa/i8259_internal.h"
30

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

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

    
41
//#define DEBUG_IRQ_LATENCY
42
//#define DEBUG_IRQ_COUNT
43

    
44
#define TYPE_I8259 "isa-i8259"
45
#define PIC_CLASS(class) OBJECT_CLASS_CHECK(PICClass, (class), TYPE_I8259)
46
#define PIC_GET_CLASS(obj) OBJECT_GET_CLASS(PICClass, (obj), TYPE_I8259)
47

    
48
/**
49
 * PICClass:
50
 * @parent_realize: The parent's realizefn.
51
 */
52
typedef struct PICClass {
53
    PICCommonClass parent_class;
54

    
55
    DeviceRealize parent_realize;
56
} PICClass;
57

    
58
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
59
static int irq_level[16];
60
#endif
61
#ifdef DEBUG_IRQ_COUNT
62
static uint64_t irq_count[16];
63
#endif
64
#ifdef DEBUG_IRQ_LATENCY
65
static int64_t irq_time[16];
66
#endif
67
DeviceState *isa_pic;
68
static PICCommonState *slave_pic;
69

    
70
/* return the highest priority found in mask (highest = smallest
71
   number). Return 8 if no irq */
72
static int get_priority(PICCommonState *s, int mask)
73
{
74
    int priority;
75

    
76
    if (mask == 0) {
77
        return 8;
78
    }
79
    priority = 0;
80
    while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) {
81
        priority++;
82
    }
83
    return priority;
84
}
85

    
86
/* return the pic wanted interrupt. return -1 if none */
87
static int pic_get_irq(PICCommonState *s)
88
{
89
    int mask, cur_priority, priority;
90

    
91
    mask = s->irr & ~s->imr;
92
    priority = get_priority(s, mask);
93
    if (priority == 8) {
94
        return -1;
95
    }
96
    /* compute current priority. If special fully nested mode on the
97
       master, the IRQ coming from the slave is not taken into account
98
       for the priority computation. */
99
    mask = s->isr;
100
    if (s->special_mask) {
101
        mask &= ~s->imr;
102
    }
103
    if (s->special_fully_nested_mode && s->master) {
104
        mask &= ~(1 << 2);
105
    }
106
    cur_priority = get_priority(s, mask);
107
    if (priority < cur_priority) {
108
        /* higher priority found: an irq should be generated */
109
        return (priority + s->priority_add) & 7;
110
    } else {
111
        return -1;
112
    }
113
}
114

    
115
/* Update INT output. Must be called every time the output may have changed. */
116
static void pic_update_irq(PICCommonState *s)
117
{
118
    int irq;
119

    
120
    irq = pic_get_irq(s);
121
    if (irq >= 0) {
122
        DPRINTF("pic%d: imr=%x irr=%x padd=%d\n",
123
                s->master ? 0 : 1, s->imr, s->irr, s->priority_add);
124
        qemu_irq_raise(s->int_out[0]);
125
    } else {
126
        qemu_irq_lower(s->int_out[0]);
127
    }
128
}
129

    
130
/* set irq level. If an edge is detected, then the IRR is set to 1 */
131
static void pic_set_irq(void *opaque, int irq, int level)
132
{
133
    PICCommonState *s = opaque;
134
    int mask = 1 << irq;
135

    
136
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) || \
137
    defined(DEBUG_IRQ_LATENCY)
138
    int irq_index = s->master ? irq : irq + 8;
139
#endif
140
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
141
    if (level != irq_level[irq_index]) {
142
        DPRINTF("pic_set_irq: irq=%d level=%d\n", irq_index, level);
143
        irq_level[irq_index] = level;
144
#ifdef DEBUG_IRQ_COUNT
145
        if (level == 1) {
146
            irq_count[irq_index]++;
147
        }
148
#endif
149
    }
150
#endif
151
#ifdef DEBUG_IRQ_LATENCY
152
    if (level) {
153
        irq_time[irq_index] = qemu_get_clock_ns(vm_clock);
154
    }
155
#endif
156

    
157
    if (s->elcr & mask) {
158
        /* level triggered */
159
        if (level) {
160
            s->irr |= mask;
161
            s->last_irr |= mask;
162
        } else {
163
            s->irr &= ~mask;
164
            s->last_irr &= ~mask;
165
        }
166
    } else {
167
        /* edge triggered */
168
        if (level) {
169
            if ((s->last_irr & mask) == 0) {
170
                s->irr |= mask;
171
            }
172
            s->last_irr |= mask;
173
        } else {
174
            s->last_irr &= ~mask;
175
        }
176
    }
177
    pic_update_irq(s);
178
}
179

    
180
/* acknowledge interrupt 'irq' */
181
static void pic_intack(PICCommonState *s, int irq)
182
{
183
    if (s->auto_eoi) {
184
        if (s->rotate_on_auto_eoi) {
185
            s->priority_add = (irq + 1) & 7;
186
        }
187
    } else {
188
        s->isr |= (1 << irq);
189
    }
190
    /* We don't clear a level sensitive interrupt here */
191
    if (!(s->elcr & (1 << irq))) {
192
        s->irr &= ~(1 << irq);
193
    }
194
    pic_update_irq(s);
195
}
196

    
197
int pic_read_irq(DeviceState *d)
198
{
199
    PICCommonState *s = PIC_COMMON(d);
200
    int irq, irq2, intno;
201

    
202
    irq = pic_get_irq(s);
203
    if (irq >= 0) {
204
        if (irq == 2) {
205
            irq2 = pic_get_irq(slave_pic);
206
            if (irq2 >= 0) {
207
                pic_intack(slave_pic, irq2);
208
            } else {
209
                /* spurious IRQ on slave controller */
210
                irq2 = 7;
211
            }
212
            intno = slave_pic->irq_base + irq2;
213
        } else {
214
            intno = s->irq_base + irq;
215
        }
216
        pic_intack(s, irq);
217
    } else {
218
        /* spurious IRQ on host controller */
219
        irq = 7;
220
        intno = s->irq_base + irq;
221
    }
222

    
223
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_LATENCY)
224
    if (irq == 2) {
225
        irq = irq2 + 8;
226
    }
227
#endif
228
#ifdef DEBUG_IRQ_LATENCY
229
    printf("IRQ%d latency=%0.3fus\n",
230
           irq,
231
           (double)(qemu_get_clock_ns(vm_clock) -
232
                    irq_time[irq]) * 1000000.0 / get_ticks_per_sec());
233
#endif
234
    DPRINTF("pic_interrupt: irq=%d\n", irq);
235
    return intno;
236
}
237

    
238
static void pic_init_reset(PICCommonState *s)
239
{
240
    pic_reset_common(s);
241
    pic_update_irq(s);
242
}
243

    
244
static void pic_reset(DeviceState *dev)
245
{
246
    PICCommonState *s = PIC_COMMON(dev);
247

    
248
    s->elcr = 0;
249
    pic_init_reset(s);
250
}
251

    
252
static void pic_ioport_write(void *opaque, hwaddr addr64,
253
                             uint64_t val64, unsigned size)
254
{
255
    PICCommonState *s = opaque;
256
    uint32_t addr = addr64;
257
    uint32_t val = val64;
258
    int priority, cmd, irq;
259

    
260
    DPRINTF("write: addr=0x%02x val=0x%02x\n", addr, val);
261
    if (addr == 0) {
262
        if (val & 0x10) {
263
            pic_init_reset(s);
264
            s->init_state = 1;
265
            s->init4 = val & 1;
266
            s->single_mode = val & 2;
267
            if (val & 0x08) {
268
                hw_error("level sensitive irq not supported");
269
            }
270
        } else if (val & 0x08) {
271
            if (val & 0x04) {
272
                s->poll = 1;
273
            }
274
            if (val & 0x02) {
275
                s->read_reg_select = val & 1;
276
            }
277
            if (val & 0x40) {
278
                s->special_mask = (val >> 5) & 1;
279
            }
280
        } else {
281
            cmd = val >> 5;
282
            switch (cmd) {
283
            case 0:
284
            case 4:
285
                s->rotate_on_auto_eoi = cmd >> 2;
286
                break;
287
            case 1: /* end of interrupt */
288
            case 5:
289
                priority = get_priority(s, s->isr);
290
                if (priority != 8) {
291
                    irq = (priority + s->priority_add) & 7;
292
                    s->isr &= ~(1 << irq);
293
                    if (cmd == 5) {
294
                        s->priority_add = (irq + 1) & 7;
295
                    }
296
                    pic_update_irq(s);
297
                }
298
                break;
299
            case 3:
300
                irq = val & 7;
301
                s->isr &= ~(1 << irq);
302
                pic_update_irq(s);
303
                break;
304
            case 6:
305
                s->priority_add = (val + 1) & 7;
306
                pic_update_irq(s);
307
                break;
308
            case 7:
309
                irq = val & 7;
310
                s->isr &= ~(1 << irq);
311
                s->priority_add = (irq + 1) & 7;
312
                pic_update_irq(s);
313
                break;
314
            default:
315
                /* no operation */
316
                break;
317
            }
318
        }
319
    } else {
320
        switch (s->init_state) {
321
        case 0:
322
            /* normal mode */
323
            s->imr = val;
324
            pic_update_irq(s);
325
            break;
326
        case 1:
327
            s->irq_base = val & 0xf8;
328
            s->init_state = s->single_mode ? (s->init4 ? 3 : 0) : 2;
329
            break;
330
        case 2:
331
            if (s->init4) {
332
                s->init_state = 3;
333
            } else {
334
                s->init_state = 0;
335
            }
336
            break;
337
        case 3:
338
            s->special_fully_nested_mode = (val >> 4) & 1;
339
            s->auto_eoi = (val >> 1) & 1;
340
            s->init_state = 0;
341
            break;
342
        }
343
    }
344
}
345

    
346
static uint64_t pic_ioport_read(void *opaque, hwaddr addr,
347
                                unsigned size)
348
{
349
    PICCommonState *s = opaque;
350
    int ret;
351

    
352
    if (s->poll) {
353
        ret = pic_get_irq(s);
354
        if (ret >= 0) {
355
            pic_intack(s, ret);
356
            ret |= 0x80;
357
        } else {
358
            ret = 0;
359
        }
360
        s->poll = 0;
361
    } else {
362
        if (addr == 0) {
363
            if (s->read_reg_select) {
364
                ret = s->isr;
365
            } else {
366
                ret = s->irr;
367
            }
368
        } else {
369
            ret = s->imr;
370
        }
371
    }
372
    DPRINTF("read: addr=0x%02x val=0x%02x\n", addr, ret);
373
    return ret;
374
}
375

    
376
int pic_get_output(DeviceState *d)
377
{
378
    PICCommonState *s = PIC_COMMON(d);
379

    
380
    return (pic_get_irq(s) >= 0);
381
}
382

    
383
static void elcr_ioport_write(void *opaque, hwaddr addr,
384
                              uint64_t val, unsigned size)
385
{
386
    PICCommonState *s = opaque;
387
    s->elcr = val & s->elcr_mask;
388
}
389

    
390
static uint64_t elcr_ioport_read(void *opaque, hwaddr addr,
391
                                 unsigned size)
392
{
393
    PICCommonState *s = opaque;
394
    return s->elcr;
395
}
396

    
397
static const MemoryRegionOps pic_base_ioport_ops = {
398
    .read = pic_ioport_read,
399
    .write = pic_ioport_write,
400
    .impl = {
401
        .min_access_size = 1,
402
        .max_access_size = 1,
403
    },
404
};
405

    
406
static const MemoryRegionOps pic_elcr_ioport_ops = {
407
    .read = elcr_ioport_read,
408
    .write = elcr_ioport_write,
409
    .impl = {
410
        .min_access_size = 1,
411
        .max_access_size = 1,
412
    },
413
};
414

    
415
static void pic_realize(DeviceState *dev, Error **err)
416
{
417
    PICCommonState *s = PIC_COMMON(dev);
418
    PICClass *pc = PIC_GET_CLASS(dev);
419

    
420
    memory_region_init_io(&s->base_io, &pic_base_ioport_ops, s, "pic", 2);
421
    memory_region_init_io(&s->elcr_io, &pic_elcr_ioport_ops, s, "elcr", 1);
422

    
423
    qdev_init_gpio_out(dev, s->int_out, ARRAY_SIZE(s->int_out));
424
    qdev_init_gpio_in(dev, pic_set_irq, 8);
425

    
426
    pc->parent_realize(dev, err);
427
}
428

    
429
void pic_info(Monitor *mon, const QDict *qdict)
430
{
431
    int i;
432
    PICCommonState *s;
433

    
434
    if (!isa_pic) {
435
        return;
436
    }
437
    for (i = 0; i < 2; i++) {
438
        s = i == 0 ? PIC_COMMON(isa_pic) : slave_pic;
439
        monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
440
                       "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
441
                       i, s->irr, s->imr, s->isr, s->priority_add,
442
                       s->irq_base, s->read_reg_select, s->elcr,
443
                       s->special_fully_nested_mode);
444
    }
445
}
446

    
447
void irq_info(Monitor *mon, const QDict *qdict)
448
{
449
#ifndef DEBUG_IRQ_COUNT
450
    monitor_printf(mon, "irq statistic code not compiled.\n");
451
#else
452
    int i;
453
    int64_t count;
454

    
455
    monitor_printf(mon, "IRQ statistics:\n");
456
    for (i = 0; i < 16; i++) {
457
        count = irq_count[i];
458
        if (count > 0) {
459
            monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
460
        }
461
    }
462
#endif
463
}
464

    
465
qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
466
{
467
    qemu_irq *irq_set;
468
    DeviceState *dev;
469
    ISADevice *isadev;
470
    int i;
471

    
472
    irq_set = g_malloc(ISA_NUM_IRQS * sizeof(qemu_irq));
473

    
474
    isadev = i8259_init_chip(TYPE_I8259, bus, true);
475
    dev = DEVICE(isadev);
476

    
477
    qdev_connect_gpio_out(dev, 0, parent_irq);
478
    for (i = 0 ; i < 8; i++) {
479
        irq_set[i] = qdev_get_gpio_in(dev, i);
480
    }
481

    
482
    isa_pic = dev;
483

    
484
    isadev = i8259_init_chip(TYPE_I8259, bus, false);
485
    dev = DEVICE(isadev);
486

    
487
    qdev_connect_gpio_out(dev, 0, irq_set[2]);
488
    for (i = 0 ; i < 8; i++) {
489
        irq_set[i + 8] = qdev_get_gpio_in(dev, i);
490
    }
491

    
492
    slave_pic = PIC_COMMON(dev);
493

    
494
    return irq_set;
495
}
496

    
497
static void i8259_class_init(ObjectClass *klass, void *data)
498
{
499
    PICClass *k = PIC_CLASS(klass);
500
    DeviceClass *dc = DEVICE_CLASS(klass);
501

    
502
    k->parent_realize = dc->realize;
503
    dc->realize = pic_realize;
504
    dc->reset = pic_reset;
505
}
506

    
507
static const TypeInfo i8259_info = {
508
    .name       = TYPE_I8259,
509
    .instance_size = sizeof(PICCommonState),
510
    .parent     = TYPE_PIC_COMMON,
511
    .class_init = i8259_class_init,
512
    .class_size = sizeof(PICClass),
513
};
514

    
515
static void pic_register_types(void)
516
{
517
    type_register_static(&i8259_info);
518
}
519

    
520
type_init(pic_register_types)