#include "pc.h"
#include "isa.h"
#include "monitor.h"
+#include "qemu-timer.h"
/* debug PIC */
//#define DEBUG_PIC
+#ifdef DEBUG_PIC
+#define DPRINTF(fmt, ...) \
+ do { printf("pic: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
//#define DEBUG_IRQ_LATENCY
//#define DEBUG_IRQ_COUNT
uint8_t elcr; /* PIIX edge/trigger selection*/
uint8_t elcr_mask;
PicState2 *pics_state;
+ MemoryRegion base_io;
+ MemoryRegion elcr_io;
} PicState;
struct PicState2 {
PicState pics[2];
qemu_irq parent_irq;
void *irq_request_opaque;
- /* IOAPIC callback support */
- SetIRQFunc *alt_irq_func;
- void *alt_irq_opaque;
};
#if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT)
#ifdef DEBUG_IRQ_COUNT
static uint64_t irq_count[16];
#endif
+PicState2 *isa_pic;
/* set irq level. If an edge is detected, then the IRR is set to 1 */
static inline void pic_set_irq1(PicState *s, int irq, int level)
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
if (level != irq_level[irq]) {
-#if defined(DEBUG_PIC)
- printf("i8259_set_irq: irq=%d level=%d\n", irq, level);
-#endif
+ DPRINTF("i8259_set_irq: irq=%d level=%d\n", irq, level);
irq_level[irq] = level;
#ifdef DEBUG_IRQ_COUNT
if (level == 1)
#endif
#ifdef DEBUG_IRQ_LATENCY
if (level) {
- irq_time[irq] = qemu_get_clock(vm_clock);
+ irq_time[irq] = qemu_get_clock_ns(vm_clock);
}
#endif
pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
- /* used for IOAPIC irqs */
- if (s->alt_irq_func)
- s->alt_irq_func(s->alt_irq_opaque, irq, level);
pic_update_irq(s);
}
irq2 = 7;
}
intno = s->pics[1].irq_base + irq2;
+#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_LATENCY)
irq = irq2 + 8;
+#endif
} else {
intno = s->pics[0].irq_base + irq;
}
#ifdef DEBUG_IRQ_LATENCY
printf("IRQ%d latency=%0.3fus\n",
irq,
- (double)(qemu_get_clock(vm_clock) - irq_time[irq]) * 1000000.0 / ticks_per_sec);
-#endif
-#if defined(DEBUG_PIC)
- printf("pic_interrupt: irq=%d\n", irq);
+ (double)(qemu_get_clock_ns(vm_clock) -
+ irq_time[irq]) * 1000000.0 / get_ticks_per_sec());
#endif
+ DPRINTF("pic_interrupt: irq=%d\n", irq);
return intno;
}
/* Note: ELCR is not reset */
}
-static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void pic_ioport_write(void *opaque, target_phys_addr_t addr64,
+ uint64_t val64, unsigned size)
{
PicState *s = opaque;
+ uint32_t addr = addr64;
+ uint32_t val = val64;
int priority, cmd, irq;
-#ifdef DEBUG_PIC
- printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val);
-#endif
- addr &= 1;
+ DPRINTF("write: addr=0x%02x val=0x%02x\n", addr, val);
if (addr == 0) {
if (val & 0x10) {
/* init */
}
}
-static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
+static uint32_t pic_poll_read(PicState *s)
{
int ret;
ret = pic_get_irq(s);
if (ret >= 0) {
- if (addr1 >> 7) {
+ bool slave = (s == &isa_pic->pics[1]);
+
+ if (slave) {
s->pics_state->pics[0].isr &= ~(1 << 2);
s->pics_state->pics[0].irr &= ~(1 << 2);
}
s->irr &= ~(1 << ret);
s->isr &= ~(1 << ret);
- if (addr1 >> 7 || ret != 2)
+ if (slave || ret != 2)
pic_update_irq(s->pics_state);
} else {
ret = 0x07;
return ret;
}
-static uint32_t pic_ioport_read(void *opaque, uint32_t addr1)
+static uint64_t pic_ioport_read(void *opaque, target_phys_addr_t addr1,
+ unsigned size)
{
PicState *s = opaque;
- unsigned int addr;
+ unsigned int addr = addr1;
int ret;
- addr = addr1;
- addr &= 1;
if (s->poll) {
- ret = pic_poll_read(s, addr1);
+ ret = pic_poll_read(s);
s->poll = 0;
} else {
if (addr == 0) {
ret = s->imr;
}
}
-#ifdef DEBUG_PIC
- printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret);
-#endif
+ DPRINTF("read: addr=0x%02x val=0x%02x\n", addr, ret);
return ret;
}
{
int ret;
- ret = pic_poll_read(&s->pics[0], 0x00);
+ ret = pic_poll_read(&s->pics[0]);
if (ret == 2)
- ret = pic_poll_read(&s->pics[1], 0x80) + 8;
+ ret = pic_poll_read(&s->pics[1]) + 8;
/* Prepare for ISR read */
s->pics[0].read_reg_select = 1;
return ret;
}
-static void elcr_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void elcr_ioport_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val, unsigned size)
{
PicState *s = opaque;
s->elcr = val & s->elcr_mask;
}
-static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1)
+static uint64_t elcr_ioport_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
{
PicState *s = opaque;
return s->elcr;
}
-static void pic_save(QEMUFile *f, void *opaque)
-{
- PicState *s = opaque;
-
- qemu_put_8s(f, &s->last_irr);
- qemu_put_8s(f, &s->irr);
- qemu_put_8s(f, &s->imr);
- qemu_put_8s(f, &s->isr);
- qemu_put_8s(f, &s->priority_add);
- qemu_put_8s(f, &s->irq_base);
- qemu_put_8s(f, &s->read_reg_select);
- qemu_put_8s(f, &s->poll);
- qemu_put_8s(f, &s->special_mask);
- qemu_put_8s(f, &s->init_state);
- qemu_put_8s(f, &s->auto_eoi);
- qemu_put_8s(f, &s->rotate_on_auto_eoi);
- qemu_put_8s(f, &s->special_fully_nested_mode);
- qemu_put_8s(f, &s->init4);
- qemu_put_8s(f, &s->single_mode);
- qemu_put_8s(f, &s->elcr);
-}
+static const VMStateDescription vmstate_pic = {
+ .name = "i8259",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT8(last_irr, PicState),
+ VMSTATE_UINT8(irr, PicState),
+ VMSTATE_UINT8(imr, PicState),
+ VMSTATE_UINT8(isr, PicState),
+ VMSTATE_UINT8(priority_add, PicState),
+ VMSTATE_UINT8(irq_base, PicState),
+ VMSTATE_UINT8(read_reg_select, PicState),
+ VMSTATE_UINT8(poll, PicState),
+ VMSTATE_UINT8(special_mask, PicState),
+ VMSTATE_UINT8(init_state, PicState),
+ VMSTATE_UINT8(auto_eoi, PicState),
+ VMSTATE_UINT8(rotate_on_auto_eoi, PicState),
+ VMSTATE_UINT8(special_fully_nested_mode, PicState),
+ VMSTATE_UINT8(init4, PicState),
+ VMSTATE_UINT8(single_mode, PicState),
+ VMSTATE_UINT8(elcr, PicState),
+ VMSTATE_END_OF_LIST()
+ }
+};
-static int pic_load(QEMUFile *f, void *opaque, int version_id)
-{
- PicState *s = opaque;
+static const MemoryRegionOps pic_base_ioport_ops = {
+ .read = pic_ioport_read,
+ .write = pic_ioport_write,
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 1,
+ },
+};
- if (version_id != 1)
- return -EINVAL;
-
- qemu_get_8s(f, &s->last_irr);
- qemu_get_8s(f, &s->irr);
- qemu_get_8s(f, &s->imr);
- qemu_get_8s(f, &s->isr);
- qemu_get_8s(f, &s->priority_add);
- qemu_get_8s(f, &s->irq_base);
- qemu_get_8s(f, &s->read_reg_select);
- qemu_get_8s(f, &s->poll);
- qemu_get_8s(f, &s->special_mask);
- qemu_get_8s(f, &s->init_state);
- qemu_get_8s(f, &s->auto_eoi);
- qemu_get_8s(f, &s->rotate_on_auto_eoi);
- qemu_get_8s(f, &s->special_fully_nested_mode);
- qemu_get_8s(f, &s->init4);
- qemu_get_8s(f, &s->single_mode);
- qemu_get_8s(f, &s->elcr);
- return 0;
-}
+static const MemoryRegionOps pic_elcr_ioport_ops = {
+ .read = elcr_ioport_read,
+ .write = elcr_ioport_write,
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 1,
+ },
+};
/* XXX: add generic master/slave system */
static void pic_init1(int io_addr, int elcr_addr, PicState *s)
{
- register_ioport_write(io_addr, 2, 1, pic_ioport_write, s);
- register_ioport_read(io_addr, 2, 1, pic_ioport_read, s);
+ memory_region_init_io(&s->base_io, &pic_base_ioport_ops, s, "pic", 2);
+ memory_region_init_io(&s->elcr_io, &pic_elcr_ioport_ops, s, "elcr", 1);
+
+ isa_register_ioport(NULL, &s->base_io, io_addr);
if (elcr_addr >= 0) {
- register_ioport_write(elcr_addr, 1, 1, elcr_ioport_write, s);
- register_ioport_read(elcr_addr, 1, 1, elcr_ioport_read, s);
+ isa_register_ioport(NULL, &s->elcr_io, elcr_addr);
}
- register_savevm("i8259", io_addr, 1, pic_save, pic_load, s);
- qemu_register_reset(pic_reset, 0, s);
+
+ vmstate_register(NULL, io_addr, &vmstate_pic, s);
+ qemu_register_reset(pic_reset, s);
}
void pic_info(Monitor *mon)
{
PicState2 *s;
- s = qemu_mallocz(sizeof(PicState2));
+ s = g_malloc0(sizeof(PicState2));
pic_init1(0x20, 0x4d0, &s->pics[0]);
pic_init1(0xa0, 0x4d1, &s->pics[1]);
s->pics[0].elcr_mask = 0xf8;
isa_pic = s;
return qemu_allocate_irqs(i8259_set_irq, s, 16);
}
-
-void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func,
- void *alt_irq_opaque)
-{
- s->alt_irq_func = alt_irq_func;
- s->alt_irq_opaque = alt_irq_opaque;
-}