~ubuntu-branches/ubuntu/saucy/qemu/saucy

« back to all changes in this revision

Viewing changes to hw/i8259.c

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn
  • Date: 2013-05-28 08:18:30 UTC
  • mfrom: (1.8.2) (10.1.37 sid)
  • Revision ID: package-import@ubuntu.com-20130528081830-87xl2z9fq516a814
Tags: 1.5.0+dfsg-2ubuntu1
* Merge 1.5.0+dfs-2 from debian unstable.  Remaining changes:
  - debian/control
    * update maintainer
    * remove libiscsi, usb-redir, vde, vnc-jpeg, and libssh2-1-dev
      from build-deps
    * enable rbd
    * add qemu-system and qemu-common B/R to qemu-keymaps
    * add D:udev, R:qemu, R:qemu-common and B:qemu-common to
      qemu-system-common
    * qemu-system-arm, qemu-system-ppc, qemu-system-sparc:
      - add qemu-kvm to Provides
      - add qemu-common, qemu-kvm, kvm to B/R
      - remove openbios-sparc from qemu-system-sparc D
    * qemu-system-x86:
      - add qemu-common to Breaks/Replaces.
      - add cpu-checker to Recommends.
    * qemu-user: add B/R:qemu-kvm
    * qemu-kvm:
      - add armhf armel powerpc sparc to Architecture
      - C/R/P: qemu-kvm-spice
    * add qemu-common package
    * drop qemu-slof which is not packaged in ubuntu
  - add qemu-system-common.links for tap ifup/down scripts and OVMF link.
  - qemu-system-x86.links:
    * remove pxe rom links which are in kvm-ipxe
    * add symlink for kvm.1 manpage
  - debian/rules
    * add kvm-spice symlink to qemu-kvm
    * call dh_installmodules for qemu-system-x86
    * update dh_installinit to install upstart script
    * run dh_installman (Closes: #709241) (cherrypicked from 1.5.0+dfsg-2)
  - Add qemu-utils.links for kvm-* symlinks.
  - Add qemu-system-x86.qemu-kvm.upstart and .default
  - Add qemu-system-x86.modprobe to set nesting=1
  - Add qemu-system-common.preinst to add kvm group
  - qemu-system-common.postinst: remove bad group acl if there, then have
    udev relabel /dev/kvm.
  - Dropped patches:
    * 0001-fix-wrong-output-with-info-chardev-for-tcp-socket.patch
  - Kept patches:
    * expose_vms_qemu64cpu.patch - updated
    * gridcentric patch - updated
    * linaro arm patches from qemu-linaro rebasing branch

Show diffs side-by-side

added added

removed removed

Lines of Context:
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/monitor.h"
28
 
#include "qemu/timer.h"
29
 
#include "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
 
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
45
 
static int irq_level[16];
46
 
#endif
47
 
#ifdef DEBUG_IRQ_COUNT
48
 
static uint64_t irq_count[16];
49
 
#endif
50
 
#ifdef DEBUG_IRQ_LATENCY
51
 
static int64_t irq_time[16];
52
 
#endif
53
 
DeviceState *isa_pic;
54
 
static PICCommonState *slave_pic;
55
 
 
56
 
/* return the highest priority found in mask (highest = smallest
57
 
   number). Return 8 if no irq */
58
 
static int get_priority(PICCommonState *s, int mask)
59
 
{
60
 
    int priority;
61
 
 
62
 
    if (mask == 0) {
63
 
        return 8;
64
 
    }
65
 
    priority = 0;
66
 
    while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) {
67
 
        priority++;
68
 
    }
69
 
    return priority;
70
 
}
71
 
 
72
 
/* return the pic wanted interrupt. return -1 if none */
73
 
static int pic_get_irq(PICCommonState *s)
74
 
{
75
 
    int mask, cur_priority, priority;
76
 
 
77
 
    mask = s->irr & ~s->imr;
78
 
    priority = get_priority(s, mask);
79
 
    if (priority == 8) {
80
 
        return -1;
81
 
    }
82
 
    /* compute current priority. If special fully nested mode on the
83
 
       master, the IRQ coming from the slave is not taken into account
84
 
       for the priority computation. */
85
 
    mask = s->isr;
86
 
    if (s->special_mask) {
87
 
        mask &= ~s->imr;
88
 
    }
89
 
    if (s->special_fully_nested_mode && s->master) {
90
 
        mask &= ~(1 << 2);
91
 
    }
92
 
    cur_priority = get_priority(s, mask);
93
 
    if (priority < cur_priority) {
94
 
        /* higher priority found: an irq should be generated */
95
 
        return (priority + s->priority_add) & 7;
96
 
    } else {
97
 
        return -1;
98
 
    }
99
 
}
100
 
 
101
 
/* Update INT output. Must be called every time the output may have changed. */
102
 
static void pic_update_irq(PICCommonState *s)
103
 
{
104
 
    int irq;
105
 
 
106
 
    irq = pic_get_irq(s);
107
 
    if (irq >= 0) {
108
 
        DPRINTF("pic%d: imr=%x irr=%x padd=%d\n",
109
 
                s->master ? 0 : 1, s->imr, s->irr, s->priority_add);
110
 
        qemu_irq_raise(s->int_out[0]);
111
 
    } else {
112
 
        qemu_irq_lower(s->int_out[0]);
113
 
    }
114
 
}
115
 
 
116
 
/* set irq level. If an edge is detected, then the IRR is set to 1 */
117
 
static void pic_set_irq(void *opaque, int irq, int level)
118
 
{
119
 
    PICCommonState *s = opaque;
120
 
    int mask = 1 << irq;
121
 
 
122
 
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) || \
123
 
    defined(DEBUG_IRQ_LATENCY)
124
 
    int irq_index = s->master ? irq : irq + 8;
125
 
#endif
126
 
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
127
 
    if (level != irq_level[irq_index]) {
128
 
        DPRINTF("pic_set_irq: irq=%d level=%d\n", irq_index, level);
129
 
        irq_level[irq_index] = level;
130
 
#ifdef DEBUG_IRQ_COUNT
131
 
        if (level == 1) {
132
 
            irq_count[irq_index]++;
133
 
        }
134
 
#endif
135
 
    }
136
 
#endif
137
 
#ifdef DEBUG_IRQ_LATENCY
138
 
    if (level) {
139
 
        irq_time[irq_index] = qemu_get_clock_ns(vm_clock);
140
 
    }
141
 
#endif
142
 
 
143
 
    if (s->elcr & mask) {
144
 
        /* level triggered */
145
 
        if (level) {
146
 
            s->irr |= mask;
147
 
            s->last_irr |= mask;
148
 
        } else {
149
 
            s->irr &= ~mask;
150
 
            s->last_irr &= ~mask;
151
 
        }
152
 
    } else {
153
 
        /* edge triggered */
154
 
        if (level) {
155
 
            if ((s->last_irr & mask) == 0) {
156
 
                s->irr |= mask;
157
 
            }
158
 
            s->last_irr |= mask;
159
 
        } else {
160
 
            s->last_irr &= ~mask;
161
 
        }
162
 
    }
163
 
    pic_update_irq(s);
164
 
}
165
 
 
166
 
/* acknowledge interrupt 'irq' */
167
 
static void pic_intack(PICCommonState *s, int irq)
168
 
{
169
 
    if (s->auto_eoi) {
170
 
        if (s->rotate_on_auto_eoi) {
171
 
            s->priority_add = (irq + 1) & 7;
172
 
        }
173
 
    } else {
174
 
        s->isr |= (1 << irq);
175
 
    }
176
 
    /* We don't clear a level sensitive interrupt here */
177
 
    if (!(s->elcr & (1 << irq))) {
178
 
        s->irr &= ~(1 << irq);
179
 
    }
180
 
    pic_update_irq(s);
181
 
}
182
 
 
183
 
int pic_read_irq(DeviceState *d)
184
 
{
185
 
    PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, d);
186
 
    int irq, irq2, intno;
187
 
 
188
 
    irq = pic_get_irq(s);
189
 
    if (irq >= 0) {
190
 
        if (irq == 2) {
191
 
            irq2 = pic_get_irq(slave_pic);
192
 
            if (irq2 >= 0) {
193
 
                pic_intack(slave_pic, irq2);
194
 
            } else {
195
 
                /* spurious IRQ on slave controller */
196
 
                irq2 = 7;
197
 
            }
198
 
            intno = slave_pic->irq_base + irq2;
199
 
        } else {
200
 
            intno = s->irq_base + irq;
201
 
        }
202
 
        pic_intack(s, irq);
203
 
    } else {
204
 
        /* spurious IRQ on host controller */
205
 
        irq = 7;
206
 
        intno = s->irq_base + irq;
207
 
    }
208
 
 
209
 
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_LATENCY)
210
 
    if (irq == 2) {
211
 
        irq = irq2 + 8;
212
 
    }
213
 
#endif
214
 
#ifdef DEBUG_IRQ_LATENCY
215
 
    printf("IRQ%d latency=%0.3fus\n",
216
 
           irq,
217
 
           (double)(qemu_get_clock_ns(vm_clock) -
218
 
                    irq_time[irq]) * 1000000.0 / get_ticks_per_sec());
219
 
#endif
220
 
    DPRINTF("pic_interrupt: irq=%d\n", irq);
221
 
    return intno;
222
 
}
223
 
 
224
 
static void pic_init_reset(PICCommonState *s)
225
 
{
226
 
    pic_reset_common(s);
227
 
    pic_update_irq(s);
228
 
}
229
 
 
230
 
static void pic_reset(DeviceState *dev)
231
 
{
232
 
    PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, dev);
233
 
 
234
 
    s->elcr = 0;
235
 
    pic_init_reset(s);
236
 
}
237
 
 
238
 
static void pic_ioport_write(void *opaque, hwaddr addr64,
239
 
                             uint64_t val64, unsigned size)
240
 
{
241
 
    PICCommonState *s = opaque;
242
 
    uint32_t addr = addr64;
243
 
    uint32_t val = val64;
244
 
    int priority, cmd, irq;
245
 
 
246
 
    DPRINTF("write: addr=0x%02x val=0x%02x\n", addr, val);
247
 
    if (addr == 0) {
248
 
        if (val & 0x10) {
249
 
            pic_init_reset(s);
250
 
            s->init_state = 1;
251
 
            s->init4 = val & 1;
252
 
            s->single_mode = val & 2;
253
 
            if (val & 0x08) {
254
 
                hw_error("level sensitive irq not supported");
255
 
            }
256
 
        } else if (val & 0x08) {
257
 
            if (val & 0x04) {
258
 
                s->poll = 1;
259
 
            }
260
 
            if (val & 0x02) {
261
 
                s->read_reg_select = val & 1;
262
 
            }
263
 
            if (val & 0x40) {
264
 
                s->special_mask = (val >> 5) & 1;
265
 
            }
266
 
        } else {
267
 
            cmd = val >> 5;
268
 
            switch (cmd) {
269
 
            case 0:
270
 
            case 4:
271
 
                s->rotate_on_auto_eoi = cmd >> 2;
272
 
                break;
273
 
            case 1: /* end of interrupt */
274
 
            case 5:
275
 
                priority = get_priority(s, s->isr);
276
 
                if (priority != 8) {
277
 
                    irq = (priority + s->priority_add) & 7;
278
 
                    s->isr &= ~(1 << irq);
279
 
                    if (cmd == 5) {
280
 
                        s->priority_add = (irq + 1) & 7;
281
 
                    }
282
 
                    pic_update_irq(s);
283
 
                }
284
 
                break;
285
 
            case 3:
286
 
                irq = val & 7;
287
 
                s->isr &= ~(1 << irq);
288
 
                pic_update_irq(s);
289
 
                break;
290
 
            case 6:
291
 
                s->priority_add = (val + 1) & 7;
292
 
                pic_update_irq(s);
293
 
                break;
294
 
            case 7:
295
 
                irq = val & 7;
296
 
                s->isr &= ~(1 << irq);
297
 
                s->priority_add = (irq + 1) & 7;
298
 
                pic_update_irq(s);
299
 
                break;
300
 
            default:
301
 
                /* no operation */
302
 
                break;
303
 
            }
304
 
        }
305
 
    } else {
306
 
        switch (s->init_state) {
307
 
        case 0:
308
 
            /* normal mode */
309
 
            s->imr = val;
310
 
            pic_update_irq(s);
311
 
            break;
312
 
        case 1:
313
 
            s->irq_base = val & 0xf8;
314
 
            s->init_state = s->single_mode ? (s->init4 ? 3 : 0) : 2;
315
 
            break;
316
 
        case 2:
317
 
            if (s->init4) {
318
 
                s->init_state = 3;
319
 
            } else {
320
 
                s->init_state = 0;
321
 
            }
322
 
            break;
323
 
        case 3:
324
 
            s->special_fully_nested_mode = (val >> 4) & 1;
325
 
            s->auto_eoi = (val >> 1) & 1;
326
 
            s->init_state = 0;
327
 
            break;
328
 
        }
329
 
    }
330
 
}
331
 
 
332
 
static uint64_t pic_ioport_read(void *opaque, hwaddr addr,
333
 
                                unsigned size)
334
 
{
335
 
    PICCommonState *s = opaque;
336
 
    int ret;
337
 
 
338
 
    if (s->poll) {
339
 
        ret = pic_get_irq(s);
340
 
        if (ret >= 0) {
341
 
            pic_intack(s, ret);
342
 
            ret |= 0x80;
343
 
        } else {
344
 
            ret = 0;
345
 
        }
346
 
        s->poll = 0;
347
 
    } else {
348
 
        if (addr == 0) {
349
 
            if (s->read_reg_select) {
350
 
                ret = s->isr;
351
 
            } else {
352
 
                ret = s->irr;
353
 
            }
354
 
        } else {
355
 
            ret = s->imr;
356
 
        }
357
 
    }
358
 
    DPRINTF("read: addr=0x%02x val=0x%02x\n", addr, ret);
359
 
    return ret;
360
 
}
361
 
 
362
 
int pic_get_output(DeviceState *d)
363
 
{
364
 
    PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, d);
365
 
 
366
 
    return (pic_get_irq(s) >= 0);
367
 
}
368
 
 
369
 
static void elcr_ioport_write(void *opaque, hwaddr addr,
370
 
                              uint64_t val, unsigned size)
371
 
{
372
 
    PICCommonState *s = opaque;
373
 
    s->elcr = val & s->elcr_mask;
374
 
}
375
 
 
376
 
static uint64_t elcr_ioport_read(void *opaque, hwaddr addr,
377
 
                                 unsigned size)
378
 
{
379
 
    PICCommonState *s = opaque;
380
 
    return s->elcr;
381
 
}
382
 
 
383
 
static const MemoryRegionOps pic_base_ioport_ops = {
384
 
    .read = pic_ioport_read,
385
 
    .write = pic_ioport_write,
386
 
    .impl = {
387
 
        .min_access_size = 1,
388
 
        .max_access_size = 1,
389
 
    },
390
 
};
391
 
 
392
 
static const MemoryRegionOps pic_elcr_ioport_ops = {
393
 
    .read = elcr_ioport_read,
394
 
    .write = elcr_ioport_write,
395
 
    .impl = {
396
 
        .min_access_size = 1,
397
 
        .max_access_size = 1,
398
 
    },
399
 
};
400
 
 
401
 
static void pic_init(PICCommonState *s)
402
 
{
403
 
    memory_region_init_io(&s->base_io, &pic_base_ioport_ops, s, "pic", 2);
404
 
    memory_region_init_io(&s->elcr_io, &pic_elcr_ioport_ops, s, "elcr", 1);
405
 
 
406
 
    qdev_init_gpio_out(&s->dev.qdev, s->int_out, ARRAY_SIZE(s->int_out));
407
 
    qdev_init_gpio_in(&s->dev.qdev, pic_set_irq, 8);
408
 
}
409
 
 
410
 
void pic_info(Monitor *mon, const QDict *qdict)
411
 
{
412
 
    int i;
413
 
    PICCommonState *s;
414
 
 
415
 
    if (!isa_pic) {
416
 
        return;
417
 
    }
418
 
    for (i = 0; i < 2; i++) {
419
 
        s = i == 0 ? DO_UPCAST(PICCommonState, dev.qdev, isa_pic) : slave_pic;
420
 
        monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
421
 
                       "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
422
 
                       i, s->irr, s->imr, s->isr, s->priority_add,
423
 
                       s->irq_base, s->read_reg_select, s->elcr,
424
 
                       s->special_fully_nested_mode);
425
 
    }
426
 
}
427
 
 
428
 
void irq_info(Monitor *mon, const QDict *qdict)
429
 
{
430
 
#ifndef DEBUG_IRQ_COUNT
431
 
    monitor_printf(mon, "irq statistic code not compiled.\n");
432
 
#else
433
 
    int i;
434
 
    int64_t count;
435
 
 
436
 
    monitor_printf(mon, "IRQ statistics:\n");
437
 
    for (i = 0; i < 16; i++) {
438
 
        count = irq_count[i];
439
 
        if (count > 0) {
440
 
            monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
441
 
        }
442
 
    }
443
 
#endif
444
 
}
445
 
 
446
 
qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
447
 
{
448
 
    qemu_irq *irq_set;
449
 
    ISADevice *dev;
450
 
    int i;
451
 
 
452
 
    irq_set = g_malloc(ISA_NUM_IRQS * sizeof(qemu_irq));
453
 
 
454
 
    dev = i8259_init_chip("isa-i8259", bus, true);
455
 
 
456
 
    qdev_connect_gpio_out(&dev->qdev, 0, parent_irq);
457
 
    for (i = 0 ; i < 8; i++) {
458
 
        irq_set[i] = qdev_get_gpio_in(&dev->qdev, i);
459
 
    }
460
 
 
461
 
    isa_pic = &dev->qdev;
462
 
 
463
 
    dev = i8259_init_chip("isa-i8259", bus, false);
464
 
 
465
 
    qdev_connect_gpio_out(&dev->qdev, 0, irq_set[2]);
466
 
    for (i = 0 ; i < 8; i++) {
467
 
        irq_set[i + 8] = qdev_get_gpio_in(&dev->qdev, i);
468
 
    }
469
 
 
470
 
    slave_pic = DO_UPCAST(PICCommonState, dev, dev);
471
 
 
472
 
    return irq_set;
473
 
}
474
 
 
475
 
static void i8259_class_init(ObjectClass *klass, void *data)
476
 
{
477
 
    PICCommonClass *k = PIC_COMMON_CLASS(klass);
478
 
    DeviceClass *dc = DEVICE_CLASS(klass);
479
 
 
480
 
    k->init = pic_init;
481
 
    dc->reset = pic_reset;
482
 
}
483
 
 
484
 
static const TypeInfo i8259_info = {
485
 
    .name       = "isa-i8259",
486
 
    .instance_size = sizeof(PICCommonState),
487
 
    .parent     = TYPE_PIC_COMMON,
488
 
    .class_init = i8259_class_init,
489
 
};
490
 
 
491
 
static void pic_register_types(void)
492
 
{
493
 
    type_register_static(&i8259_info);
494
 
}
495
 
 
496
 
type_init(pic_register_types)