hw: move interrupt controllers to hw/intc/, configure with default-configs/
authorPaolo Bonzini <pbonzini@redhat.com>
Tue, 5 Feb 2013 15:12:12 +0000 (16:12 +0100)
committerPaolo Bonzini <pbonzini@redhat.com>
Mon, 8 Apr 2013 16:13:16 +0000 (18:13 +0200)
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
56 files changed:
default-configs/arm-softmmu.mak
default-configs/i386-softmmu.mak
default-configs/ppc-softmmu.mak
default-configs/ppc64-softmmu.mak
default-configs/ppcemb-softmmu.mak
default-configs/x86_64-softmmu.mak
hw/apic.c [deleted file]
hw/apic_common.c [deleted file]
hw/arm/Makefile.objs
hw/arm_gic.c [deleted file]
hw/arm_gic_common.c [deleted file]
hw/armv7m_nvic.c [deleted file]
hw/cris/Makefile.objs
hw/etraxfs_pic.c [deleted file]
hw/exynos4210_combiner.c [deleted file]
hw/exynos4210_gic.c [deleted file]
hw/grlib_irqmp.c [deleted file]
hw/i386/Makefile.objs
hw/imx_avic.c [deleted file]
hw/intc/Makefile.objs
hw/intc/apic.c [new file with mode: 0644]
hw/intc/apic_common.c [new file with mode: 0644]
hw/intc/arm_gic.c [new file with mode: 0644]
hw/intc/arm_gic_common.c [new file with mode: 0644]
hw/intc/arm_gic_kvm.c [new file with mode: 0644]
hw/intc/armv7m_nvic.c [new file with mode: 0644]
hw/intc/etraxfs_pic.c [new file with mode: 0644]
hw/intc/exynos4210_combiner.c [new file with mode: 0644]
hw/intc/exynos4210_gic.c [new file with mode: 0644]
hw/intc/grlib_irqmp.c [new file with mode: 0644]
hw/intc/imx_avic.c [new file with mode: 0644]
hw/intc/ioapic.c [new file with mode: 0644]
hw/intc/ioapic_common.c [new file with mode: 0644]
hw/intc/lm32_pic.c [new file with mode: 0644]
hw/intc/omap_intc.c [new file with mode: 0644]
hw/intc/openpic.c [new file with mode: 0644]
hw/intc/realview_gic.c [new file with mode: 0644]
hw/intc/sbi.c [new file with mode: 0644]
hw/intc/sh_intc.c [new file with mode: 0644]
hw/intc/slavio_intctl.c [new file with mode: 0644]
hw/intc/sun4c_intctl.c [new file with mode: 0644]
hw/ioapic.c [deleted file]
hw/ioapic_common.c [deleted file]
hw/kvm/arm_gic.c [deleted file]
hw/lm32/Makefile.objs
hw/lm32_pic.c [deleted file]
hw/omap_intc.c [deleted file]
hw/openpic.c [deleted file]
hw/ppc/Makefile.objs
hw/realview_gic.c [deleted file]
hw/sbi.c [deleted file]
hw/sh4/Makefile.objs
hw/sh_intc.c [deleted file]
hw/slavio_intctl.c [deleted file]
hw/sparc/Makefile.objs
hw/sun4c_intctl.c [deleted file]

index 94b52da3c82cbcf4ed30c7e7ea7267f1a8b569be..93c7d95d4ac10a46ad845692ea2041e2cff38aca 100644 (file)
@@ -16,6 +16,7 @@ CONFIG_TWL92230=y
 CONFIG_TSC2005=y
 CONFIG_LM832X=y
 CONFIG_TMP105=y
+CONFIG_STELLARIS=y
 CONFIG_STELLARIS_INPUT=y
 CONFIG_STELLARIS_ENET=y
 CONFIG_SSD0303=y
@@ -33,6 +34,8 @@ CONFIG_PFLASH_CFI02=y
 CONFIG_MICRODRIVE=y
 CONFIG_USB_MUSB=y
 
+CONFIG_ARM_GIC=y
+CONFIG_ARM_GIC_KVM=$(CONFIG_KVM)
 CONFIG_ARM_TIMER=y
 CONFIG_ARM_MPTIMER=y
 CONFIG_PL011=y
@@ -62,6 +65,7 @@ CONFIG_BLIZZARD=y
 CONFIG_ONENAND=y
 CONFIG_TUSB6010=y
 CONFIG_IMX=y
+CONFIG_REALVIEW=y
 CONFIG_ZAURUS=y
 
 CONFIG_VERSATILE_PCI=y
index fa070cd981ddead89b1a12d64f03816b16ab2b98..79851bd52c8dcb32470edf3d46dfbc19f851e30f 100644 (file)
@@ -40,3 +40,5 @@ CONFIG_XEN_I386=$(CONFIG_XEN)
 CONFIG_ISA_DEBUG=y
 CONFIG_LPC_ICH9=y
 CONFIG_Q35=y
+CONFIG_APIC=y
+CONFIG_IOAPIC=y
index 36a8ed3f7b6724ff58857efd16b08d65d843e27b..50034fc87f157e1d6f066a2dbca9eea51798ce6e 100644 (file)
@@ -41,6 +41,7 @@ CONFIG_PTIMER=y
 CONFIG_I8259=y
 CONFIG_XILINX=y
 CONFIG_XILINX_ETHLITE=y
+CONFIG_OPENPIC=y
 CONFIG_E500=$(CONFIG_FDT)
 # For PReP
 CONFIG_MC146818RTC=y
index 2d5df773056d80e1571cd4f03f7c849afb4b24d9..6398d60362e72413e09dacd5f38913b433243346 100644 (file)
@@ -41,6 +41,7 @@ CONFIG_PTIMER=y
 CONFIG_I8259=y
 CONFIG_XILINX=y
 CONFIG_XILINX_ETHLITE=y
+CONFIG_OPENPIC=y
 CONFIG_PSERIES=$(CONFIG_FDT)
 CONFIG_E500=$(CONFIG_FDT)
 # For pSeries
index ce705a93c1575f7aaba05fee06785047e126cb2d..05b50d6f00029a33c38ad2a8cc1fc227c61a42ab 100644 (file)
@@ -36,6 +36,7 @@ CONFIG_PTIMER=y
 CONFIG_I8259=y
 CONFIG_XILINX=y
 CONFIG_XILINX_ETHLITE=y
+CONFIG_OPENPIC=y
 CONFIG_E500=$(CONFIG_FDT)
 # For PReP
 CONFIG_MC146818RTC=y
index 3102c09066461256204e72a9ab2b3384e7ad2a70..176f493ec4ddecc7f5a9d70d25ac26bc27c7907a 100644 (file)
@@ -40,3 +40,5 @@ CONFIG_XEN_I386=$(CONFIG_XEN)
 CONFIG_ISA_DEBUG=y
 CONFIG_LPC_ICH9=y
 CONFIG_Q35=y
+CONFIG_APIC=y
+CONFIG_IOAPIC=y
diff --git a/hw/apic.c b/hw/apic.c
deleted file mode 100644 (file)
index 2d79a9e..0000000
--- a/hw/apic.c
+++ /dev/null
@@ -1,911 +0,0 @@
-/*
- *  APIC support
- *
- *  Copyright (c) 2004-2005 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- */
-#include "qemu/thread.h"
-#include "hw/i386/apic_internal.h"
-#include "hw/i386/apic.h"
-#include "hw/i386/ioapic.h"
-#include "hw/pci/msi.h"
-#include "qemu/host-utils.h"
-#include "trace.h"
-#include "hw/i386/pc.h"
-#include "hw/i386/apic-msidef.h"
-
-#define MAX_APIC_WORDS 8
-
-#define SYNC_FROM_VAPIC                 0x1
-#define SYNC_TO_VAPIC                   0x2
-#define SYNC_ISR_IRR_TO_VAPIC           0x4
-
-static APICCommonState *local_apics[MAX_APICS + 1];
-
-static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode);
-static void apic_update_irq(APICCommonState *s);
-static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
-                                      uint8_t dest, uint8_t dest_mode);
-
-/* Find first bit starting from msb */
-static int fls_bit(uint32_t value)
-{
-    return 31 - clz32(value);
-}
-
-/* Find first bit starting from lsb */
-static int ffs_bit(uint32_t value)
-{
-    return ctz32(value);
-}
-
-static inline void set_bit(uint32_t *tab, int index)
-{
-    int i, mask;
-    i = index >> 5;
-    mask = 1 << (index & 0x1f);
-    tab[i] |= mask;
-}
-
-static inline void reset_bit(uint32_t *tab, int index)
-{
-    int i, mask;
-    i = index >> 5;
-    mask = 1 << (index & 0x1f);
-    tab[i] &= ~mask;
-}
-
-static inline int get_bit(uint32_t *tab, int index)
-{
-    int i, mask;
-    i = index >> 5;
-    mask = 1 << (index & 0x1f);
-    return !!(tab[i] & mask);
-}
-
-/* return -1 if no bit is set */
-static int get_highest_priority_int(uint32_t *tab)
-{
-    int i;
-    for (i = 7; i >= 0; i--) {
-        if (tab[i] != 0) {
-            return i * 32 + fls_bit(tab[i]);
-        }
-    }
-    return -1;
-}
-
-static void apic_sync_vapic(APICCommonState *s, int sync_type)
-{
-    VAPICState vapic_state;
-    size_t length;
-    off_t start;
-    int vector;
-
-    if (!s->vapic_paddr) {
-        return;
-    }
-    if (sync_type & SYNC_FROM_VAPIC) {
-        cpu_physical_memory_rw(s->vapic_paddr, (void *)&vapic_state,
-                               sizeof(vapic_state), 0);
-        s->tpr = vapic_state.tpr;
-    }
-    if (sync_type & (SYNC_TO_VAPIC | SYNC_ISR_IRR_TO_VAPIC)) {
-        start = offsetof(VAPICState, isr);
-        length = offsetof(VAPICState, enabled) - offsetof(VAPICState, isr);
-
-        if (sync_type & SYNC_TO_VAPIC) {
-            assert(qemu_cpu_is_self(CPU(s->cpu)));
-
-            vapic_state.tpr = s->tpr;
-            vapic_state.enabled = 1;
-            start = 0;
-            length = sizeof(VAPICState);
-        }
-
-        vector = get_highest_priority_int(s->isr);
-        if (vector < 0) {
-            vector = 0;
-        }
-        vapic_state.isr = vector & 0xf0;
-
-        vapic_state.zero = 0;
-
-        vector = get_highest_priority_int(s->irr);
-        if (vector < 0) {
-            vector = 0;
-        }
-        vapic_state.irr = vector & 0xff;
-
-        cpu_physical_memory_write_rom(s->vapic_paddr + start,
-                                      ((void *)&vapic_state) + start, length);
-    }
-}
-
-static void apic_vapic_base_update(APICCommonState *s)
-{
-    apic_sync_vapic(s, SYNC_TO_VAPIC);
-}
-
-static void apic_local_deliver(APICCommonState *s, int vector)
-{
-    uint32_t lvt = s->lvt[vector];
-    int trigger_mode;
-
-    trace_apic_local_deliver(vector, (lvt >> 8) & 7);
-
-    if (lvt & APIC_LVT_MASKED)
-        return;
-
-    switch ((lvt >> 8) & 7) {
-    case APIC_DM_SMI:
-        cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SMI);
-        break;
-
-    case APIC_DM_NMI:
-        cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_NMI);
-        break;
-
-    case APIC_DM_EXTINT:
-        cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HARD);
-        break;
-
-    case APIC_DM_FIXED:
-        trigger_mode = APIC_TRIGGER_EDGE;
-        if ((vector == APIC_LVT_LINT0 || vector == APIC_LVT_LINT1) &&
-            (lvt & APIC_LVT_LEVEL_TRIGGER))
-            trigger_mode = APIC_TRIGGER_LEVEL;
-        apic_set_irq(s, lvt & 0xff, trigger_mode);
-    }
-}
-
-void apic_deliver_pic_intr(DeviceState *d, int level)
-{
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-
-    if (level) {
-        apic_local_deliver(s, APIC_LVT_LINT0);
-    } else {
-        uint32_t lvt = s->lvt[APIC_LVT_LINT0];
-
-        switch ((lvt >> 8) & 7) {
-        case APIC_DM_FIXED:
-            if (!(lvt & APIC_LVT_LEVEL_TRIGGER))
-                break;
-            reset_bit(s->irr, lvt & 0xff);
-            /* fall through */
-        case APIC_DM_EXTINT:
-            cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_HARD);
-            break;
-        }
-    }
-}
-
-static void apic_external_nmi(APICCommonState *s)
-{
-    apic_local_deliver(s, APIC_LVT_LINT1);
-}
-
-#define foreach_apic(apic, deliver_bitmask, code) \
-{\
-    int __i, __j, __mask;\
-    for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\
-        __mask = deliver_bitmask[__i];\
-        if (__mask) {\
-            for(__j = 0; __j < 32; __j++) {\
-                if (__mask & (1 << __j)) {\
-                    apic = local_apics[__i * 32 + __j];\
-                    if (apic) {\
-                        code;\
-                    }\
-                }\
-            }\
-        }\
-    }\
-}
-
-static void apic_bus_deliver(const uint32_t *deliver_bitmask,
-                             uint8_t delivery_mode, uint8_t vector_num,
-                             uint8_t trigger_mode)
-{
-    APICCommonState *apic_iter;
-
-    switch (delivery_mode) {
-        case APIC_DM_LOWPRI:
-            /* XXX: search for focus processor, arbitration */
-            {
-                int i, d;
-                d = -1;
-                for(i = 0; i < MAX_APIC_WORDS; i++) {
-                    if (deliver_bitmask[i]) {
-                        d = i * 32 + ffs_bit(deliver_bitmask[i]);
-                        break;
-                    }
-                }
-                if (d >= 0) {
-                    apic_iter = local_apics[d];
-                    if (apic_iter) {
-                        apic_set_irq(apic_iter, vector_num, trigger_mode);
-                    }
-                }
-            }
-            return;
-
-        case APIC_DM_FIXED:
-            break;
-
-        case APIC_DM_SMI:
-            foreach_apic(apic_iter, deliver_bitmask,
-                cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_SMI)
-            );
-            return;
-
-        case APIC_DM_NMI:
-            foreach_apic(apic_iter, deliver_bitmask,
-                cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_NMI)
-            );
-            return;
-
-        case APIC_DM_INIT:
-            /* normal INIT IPI sent to processors */
-            foreach_apic(apic_iter, deliver_bitmask,
-                         cpu_interrupt(CPU(apic_iter->cpu),
-                                       CPU_INTERRUPT_INIT)
-            );
-            return;
-
-        case APIC_DM_EXTINT:
-            /* handled in I/O APIC code */
-            break;
-
-        default:
-            return;
-    }
-
-    foreach_apic(apic_iter, deliver_bitmask,
-                 apic_set_irq(apic_iter, vector_num, trigger_mode) );
-}
-
-void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode,
-                      uint8_t vector_num, uint8_t trigger_mode)
-{
-    uint32_t deliver_bitmask[MAX_APIC_WORDS];
-
-    trace_apic_deliver_irq(dest, dest_mode, delivery_mode, vector_num,
-                           trigger_mode);
-
-    apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
-    apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
-}
-
-static void apic_set_base(APICCommonState *s, uint64_t val)
-{
-    s->apicbase = (val & 0xfffff000) |
-        (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
-    /* if disabled, cannot be enabled again */
-    if (!(val & MSR_IA32_APICBASE_ENABLE)) {
-        s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
-        cpu_clear_apic_feature(&s->cpu->env);
-        s->spurious_vec &= ~APIC_SV_ENABLE;
-    }
-}
-
-static void apic_set_tpr(APICCommonState *s, uint8_t val)
-{
-    /* Updates from cr8 are ignored while the VAPIC is active */
-    if (!s->vapic_paddr) {
-        s->tpr = val << 4;
-        apic_update_irq(s);
-    }
-}
-
-static uint8_t apic_get_tpr(APICCommonState *s)
-{
-    apic_sync_vapic(s, SYNC_FROM_VAPIC);
-    return s->tpr >> 4;
-}
-
-static int apic_get_ppr(APICCommonState *s)
-{
-    int tpr, isrv, ppr;
-
-    tpr = (s->tpr >> 4);
-    isrv = get_highest_priority_int(s->isr);
-    if (isrv < 0)
-        isrv = 0;
-    isrv >>= 4;
-    if (tpr >= isrv)
-        ppr = s->tpr;
-    else
-        ppr = isrv << 4;
-    return ppr;
-}
-
-static int apic_get_arb_pri(APICCommonState *s)
-{
-    /* XXX: arbitration */
-    return 0;
-}
-
-
-/*
- * <0 - low prio interrupt,
- * 0  - no interrupt,
- * >0 - interrupt number
- */
-static int apic_irq_pending(APICCommonState *s)
-{
-    int irrv, ppr;
-    irrv = get_highest_priority_int(s->irr);
-    if (irrv < 0) {
-        return 0;
-    }
-    ppr = apic_get_ppr(s);
-    if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) {
-        return -1;
-    }
-
-    return irrv;
-}
-
-/* signal the CPU if an irq is pending */
-static void apic_update_irq(APICCommonState *s)
-{
-    CPUState *cpu;
-
-    if (!(s->spurious_vec & APIC_SV_ENABLE)) {
-        return;
-    }
-    cpu = CPU(s->cpu);
-    if (!qemu_cpu_is_self(cpu)) {
-        cpu_interrupt(cpu, CPU_INTERRUPT_POLL);
-    } else if (apic_irq_pending(s) > 0) {
-        cpu_interrupt(cpu, CPU_INTERRUPT_HARD);
-    }
-}
-
-void apic_poll_irq(DeviceState *d)
-{
-    APICCommonState *s = APIC_COMMON(d);
-
-    apic_sync_vapic(s, SYNC_FROM_VAPIC);
-    apic_update_irq(s);
-}
-
-static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode)
-{
-    apic_report_irq_delivered(!get_bit(s->irr, vector_num));
-
-    set_bit(s->irr, vector_num);
-    if (trigger_mode)
-        set_bit(s->tmr, vector_num);
-    else
-        reset_bit(s->tmr, vector_num);
-    if (s->vapic_paddr) {
-        apic_sync_vapic(s, SYNC_ISR_IRR_TO_VAPIC);
-        /*
-         * The vcpu thread needs to see the new IRR before we pull its current
-         * TPR value. That way, if we miss a lowering of the TRP, the guest
-         * has the chance to notice the new IRR and poll for IRQs on its own.
-         */
-        smp_wmb();
-        apic_sync_vapic(s, SYNC_FROM_VAPIC);
-    }
-    apic_update_irq(s);
-}
-
-static void apic_eoi(APICCommonState *s)
-{
-    int isrv;
-    isrv = get_highest_priority_int(s->isr);
-    if (isrv < 0)
-        return;
-    reset_bit(s->isr, isrv);
-    if (!(s->spurious_vec & APIC_SV_DIRECTED_IO) && get_bit(s->tmr, isrv)) {
-        ioapic_eoi_broadcast(isrv);
-    }
-    apic_sync_vapic(s, SYNC_FROM_VAPIC | SYNC_TO_VAPIC);
-    apic_update_irq(s);
-}
-
-static int apic_find_dest(uint8_t dest)
-{
-    APICCommonState *apic = local_apics[dest];
-    int i;
-
-    if (apic && apic->id == dest)
-        return dest;  /* shortcut in case apic->id == apic->idx */
-
-    for (i = 0; i < MAX_APICS; i++) {
-        apic = local_apics[i];
-       if (apic && apic->id == dest)
-            return i;
-        if (!apic)
-            break;
-    }
-
-    return -1;
-}
-
-static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
-                                      uint8_t dest, uint8_t dest_mode)
-{
-    APICCommonState *apic_iter;
-    int i;
-
-    if (dest_mode == 0) {
-        if (dest == 0xff) {
-            memset(deliver_bitmask, 0xff, MAX_APIC_WORDS * sizeof(uint32_t));
-        } else {
-            int idx = apic_find_dest(dest);
-            memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
-            if (idx >= 0)
-                set_bit(deliver_bitmask, idx);
-        }
-    } else {
-        /* XXX: cluster mode */
-        memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
-        for(i = 0; i < MAX_APICS; i++) {
-            apic_iter = local_apics[i];
-            if (apic_iter) {
-                if (apic_iter->dest_mode == 0xf) {
-                    if (dest & apic_iter->log_dest)
-                        set_bit(deliver_bitmask, i);
-                } else if (apic_iter->dest_mode == 0x0) {
-                    if ((dest & 0xf0) == (apic_iter->log_dest & 0xf0) &&
-                        (dest & apic_iter->log_dest & 0x0f)) {
-                        set_bit(deliver_bitmask, i);
-                    }
-                }
-            } else {
-                break;
-            }
-        }
-    }
-}
-
-static void apic_startup(APICCommonState *s, int vector_num)
-{
-    s->sipi_vector = vector_num;
-    cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI);
-}
-
-void apic_sipi(DeviceState *d)
-{
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-
-    cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI);
-
-    if (!s->wait_for_sipi)
-        return;
-    cpu_x86_load_seg_cache_sipi(s->cpu, s->sipi_vector);
-    s->wait_for_sipi = 0;
-}
-
-static void apic_deliver(DeviceState *d, uint8_t dest, uint8_t dest_mode,
-                         uint8_t delivery_mode, uint8_t vector_num,
-                         uint8_t trigger_mode)
-{
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-    uint32_t deliver_bitmask[MAX_APIC_WORDS];
-    int dest_shorthand = (s->icr[0] >> 18) & 3;
-    APICCommonState *apic_iter;
-
-    switch (dest_shorthand) {
-    case 0:
-        apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
-        break;
-    case 1:
-        memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask));
-        set_bit(deliver_bitmask, s->idx);
-        break;
-    case 2:
-        memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
-        break;
-    case 3:
-        memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
-        reset_bit(deliver_bitmask, s->idx);
-        break;
-    }
-
-    switch (delivery_mode) {
-        case APIC_DM_INIT:
-            {
-                int trig_mode = (s->icr[0] >> 15) & 1;
-                int level = (s->icr[0] >> 14) & 1;
-                if (level == 0 && trig_mode == 1) {
-                    foreach_apic(apic_iter, deliver_bitmask,
-                                 apic_iter->arb_id = apic_iter->id );
-                    return;
-                }
-            }
-            break;
-
-        case APIC_DM_SIPI:
-            foreach_apic(apic_iter, deliver_bitmask,
-                         apic_startup(apic_iter, vector_num) );
-            return;
-    }
-
-    apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
-}
-
-static bool apic_check_pic(APICCommonState *s)
-{
-    if (!apic_accept_pic_intr(&s->busdev.qdev) || !pic_get_output(isa_pic)) {
-        return false;
-    }
-    apic_deliver_pic_intr(&s->busdev.qdev, 1);
-    return true;
-}
-
-int apic_get_interrupt(DeviceState *d)
-{
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-    int intno;
-
-    /* if the APIC is installed or enabled, we let the 8259 handle the
-       IRQs */
-    if (!s)
-        return -1;
-    if (!(s->spurious_vec & APIC_SV_ENABLE))
-        return -1;
-
-    apic_sync_vapic(s, SYNC_FROM_VAPIC);
-    intno = apic_irq_pending(s);
-
-    if (intno == 0) {
-        apic_sync_vapic(s, SYNC_TO_VAPIC);
-        return -1;
-    } else if (intno < 0) {
-        apic_sync_vapic(s, SYNC_TO_VAPIC);
-        return s->spurious_vec & 0xff;
-    }
-    reset_bit(s->irr, intno);
-    set_bit(s->isr, intno);
-    apic_sync_vapic(s, SYNC_TO_VAPIC);
-
-    /* re-inject if there is still a pending PIC interrupt */
-    apic_check_pic(s);
-
-    apic_update_irq(s);
-
-    return intno;
-}
-
-int apic_accept_pic_intr(DeviceState *d)
-{
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-    uint32_t lvt0;
-
-    if (!s)
-        return -1;
-
-    lvt0 = s->lvt[APIC_LVT_LINT0];
-
-    if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 ||
-        (lvt0 & APIC_LVT_MASKED) == 0)
-        return 1;
-
-    return 0;
-}
-
-static uint32_t apic_get_current_count(APICCommonState *s)
-{
-    int64_t d;
-    uint32_t val;
-    d = (qemu_get_clock_ns(vm_clock) - s->initial_count_load_time) >>
-        s->count_shift;
-    if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
-        /* periodic */
-        val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
-    } else {
-        if (d >= s->initial_count)
-            val = 0;
-        else
-            val = s->initial_count - d;
-    }
-    return val;
-}
-
-static void apic_timer_update(APICCommonState *s, int64_t current_time)
-{
-    if (apic_next_timer(s, current_time)) {
-        qemu_mod_timer(s->timer, s->next_time);
-    } else {
-        qemu_del_timer(s->timer);
-    }
-}
-
-static void apic_timer(void *opaque)
-{
-    APICCommonState *s = opaque;
-
-    apic_local_deliver(s, APIC_LVT_TIMER);
-    apic_timer_update(s, s->next_time);
-}
-
-static uint32_t apic_mem_readb(void *opaque, hwaddr addr)
-{
-    return 0;
-}
-
-static uint32_t apic_mem_readw(void *opaque, hwaddr addr)
-{
-    return 0;
-}
-
-static void apic_mem_writeb(void *opaque, hwaddr addr, uint32_t val)
-{
-}
-
-static void apic_mem_writew(void *opaque, hwaddr addr, uint32_t val)
-{
-}
-
-static uint32_t apic_mem_readl(void *opaque, hwaddr addr)
-{
-    DeviceState *d;
-    APICCommonState *s;
-    uint32_t val;
-    int index;
-
-    d = cpu_get_current_apic();
-    if (!d) {
-        return 0;
-    }
-    s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-
-    index = (addr >> 4) & 0xff;
-    switch(index) {
-    case 0x02: /* id */
-        val = s->id << 24;
-        break;
-    case 0x03: /* version */
-        val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */
-        break;
-    case 0x08:
-        apic_sync_vapic(s, SYNC_FROM_VAPIC);
-        if (apic_report_tpr_access) {
-            cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_READ);
-        }
-        val = s->tpr;
-        break;
-    case 0x09:
-        val = apic_get_arb_pri(s);
-        break;
-    case 0x0a:
-        /* ppr */
-        val = apic_get_ppr(s);
-        break;
-    case 0x0b:
-        val = 0;
-        break;
-    case 0x0d:
-        val = s->log_dest << 24;
-        break;
-    case 0x0e:
-        val = s->dest_mode << 28;
-        break;
-    case 0x0f:
-        val = s->spurious_vec;
-        break;
-    case 0x10 ... 0x17:
-        val = s->isr[index & 7];
-        break;
-    case 0x18 ... 0x1f:
-        val = s->tmr[index & 7];
-        break;
-    case 0x20 ... 0x27:
-        val = s->irr[index & 7];
-        break;
-    case 0x28:
-        val = s->esr;
-        break;
-    case 0x30:
-    case 0x31:
-        val = s->icr[index & 1];
-        break;
-    case 0x32 ... 0x37:
-        val = s->lvt[index - 0x32];
-        break;
-    case 0x38:
-        val = s->initial_count;
-        break;
-    case 0x39:
-        val = apic_get_current_count(s);
-        break;
-    case 0x3e:
-        val = s->divide_conf;
-        break;
-    default:
-        s->esr |= ESR_ILLEGAL_ADDRESS;
-        val = 0;
-        break;
-    }
-    trace_apic_mem_readl(addr, val);
-    return val;
-}
-
-static void apic_send_msi(hwaddr addr, uint32_t data)
-{
-    uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
-    uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
-    uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
-    uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
-    uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
-    /* XXX: Ignore redirection hint. */
-    apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode);
-}
-
-static void apic_mem_writel(void *opaque, hwaddr addr, uint32_t val)
-{
-    DeviceState *d;
-    APICCommonState *s;
-    int index = (addr >> 4) & 0xff;
-    if (addr > 0xfff || !index) {
-        /* MSI and MMIO APIC are at the same memory location,
-         * but actually not on the global bus: MSI is on PCI bus
-         * APIC is connected directly to the CPU.
-         * Mapping them on the global bus happens to work because
-         * MSI registers are reserved in APIC MMIO and vice versa. */
-        apic_send_msi(addr, val);
-        return;
-    }
-
-    d = cpu_get_current_apic();
-    if (!d) {
-        return;
-    }
-    s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-
-    trace_apic_mem_writel(addr, val);
-
-    switch(index) {
-    case 0x02:
-        s->id = (val >> 24);
-        break;
-    case 0x03:
-        break;
-    case 0x08:
-        if (apic_report_tpr_access) {
-            cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_WRITE);
-        }
-        s->tpr = val;
-        apic_sync_vapic(s, SYNC_TO_VAPIC);
-        apic_update_irq(s);
-        break;
-    case 0x09:
-    case 0x0a:
-        break;
-    case 0x0b: /* EOI */
-        apic_eoi(s);
-        break;
-    case 0x0d:
-        s->log_dest = val >> 24;
-        break;
-    case 0x0e:
-        s->dest_mode = val >> 28;
-        break;
-    case 0x0f:
-        s->spurious_vec = val & 0x1ff;
-        apic_update_irq(s);
-        break;
-    case 0x10 ... 0x17:
-    case 0x18 ... 0x1f:
-    case 0x20 ... 0x27:
-    case 0x28:
-        break;
-    case 0x30:
-        s->icr[0] = val;
-        apic_deliver(d, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
-                     (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
-                     (s->icr[0] >> 15) & 1);
-        break;
-    case 0x31:
-        s->icr[1] = val;
-        break;
-    case 0x32 ... 0x37:
-        {
-            int n = index - 0x32;
-            s->lvt[n] = val;
-            if (n == APIC_LVT_TIMER) {
-                apic_timer_update(s, qemu_get_clock_ns(vm_clock));
-            } else if (n == APIC_LVT_LINT0 && apic_check_pic(s)) {
-                apic_update_irq(s);
-            }
-        }
-        break;
-    case 0x38:
-        s->initial_count = val;
-        s->initial_count_load_time = qemu_get_clock_ns(vm_clock);
-        apic_timer_update(s, s->initial_count_load_time);
-        break;
-    case 0x39:
-        break;
-    case 0x3e:
-        {
-            int v;
-            s->divide_conf = val & 0xb;
-            v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
-            s->count_shift = (v + 1) & 7;
-        }
-        break;
-    default:
-        s->esr |= ESR_ILLEGAL_ADDRESS;
-        break;
-    }
-}
-
-static void apic_pre_save(APICCommonState *s)
-{
-    apic_sync_vapic(s, SYNC_FROM_VAPIC);
-}
-
-static void apic_post_load(APICCommonState *s)
-{
-    if (s->timer_expiry != -1) {
-        qemu_mod_timer(s->timer, s->timer_expiry);
-    } else {
-        qemu_del_timer(s->timer);
-    }
-}
-
-static const MemoryRegionOps apic_io_ops = {
-    .old_mmio = {
-        .read = { apic_mem_readb, apic_mem_readw, apic_mem_readl, },
-        .write = { apic_mem_writeb, apic_mem_writew, apic_mem_writel, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void apic_init(APICCommonState *s)
-{
-    memory_region_init_io(&s->io_memory, &apic_io_ops, s, "apic-msi",
-                          MSI_SPACE_SIZE);
-
-    s->timer = qemu_new_timer_ns(vm_clock, apic_timer, s);
-    local_apics[s->idx] = s;
-
-    msi_supported = true;
-}
-
-static void apic_class_init(ObjectClass *klass, void *data)
-{
-    APICCommonClass *k = APIC_COMMON_CLASS(klass);
-
-    k->init = apic_init;
-    k->set_base = apic_set_base;
-    k->set_tpr = apic_set_tpr;
-    k->get_tpr = apic_get_tpr;
-    k->vapic_base_update = apic_vapic_base_update;
-    k->external_nmi = apic_external_nmi;
-    k->pre_save = apic_pre_save;
-    k->post_load = apic_post_load;
-}
-
-static const TypeInfo apic_info = {
-    .name          = "apic",
-    .instance_size = sizeof(APICCommonState),
-    .parent        = TYPE_APIC_COMMON,
-    .class_init    = apic_class_init,
-};
-
-static void apic_register_types(void)
-{
-    type_register_static(&apic_info);
-}
-
-type_init(apic_register_types)
diff --git a/hw/apic_common.c b/hw/apic_common.c
deleted file mode 100644 (file)
index e0ae07a..0000000
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- *  APIC support - common bits of emulated and KVM kernel model
- *
- *  Copyright (c) 2004-2005 Fabrice Bellard
- *  Copyright (c) 2011      Jan Kiszka, Siemens AG
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- */
-#include "hw/i386/apic.h"
-#include "hw/i386/apic_internal.h"
-#include "trace.h"
-#include "sysemu/kvm.h"
-
-static int apic_irq_delivered;
-bool apic_report_tpr_access;
-
-void cpu_set_apic_base(DeviceState *d, uint64_t val)
-{
-    trace_cpu_set_apic_base(val);
-
-    if (d) {
-        APICCommonState *s = APIC_COMMON(d);
-        APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
-        info->set_base(s, val);
-    }
-}
-
-uint64_t cpu_get_apic_base(DeviceState *d)
-{
-    if (d) {
-        APICCommonState *s = APIC_COMMON(d);
-        trace_cpu_get_apic_base((uint64_t)s->apicbase);
-        return s->apicbase;
-    } else {
-        trace_cpu_get_apic_base(MSR_IA32_APICBASE_BSP);
-        return MSR_IA32_APICBASE_BSP;
-    }
-}
-
-void cpu_set_apic_tpr(DeviceState *d, uint8_t val)
-{
-    APICCommonState *s;
-    APICCommonClass *info;
-
-    if (!d) {
-        return;
-    }
-
-    s = APIC_COMMON(d);
-    info = APIC_COMMON_GET_CLASS(s);
-
-    info->set_tpr(s, val);
-}
-
-uint8_t cpu_get_apic_tpr(DeviceState *d)
-{
-    APICCommonState *s;
-    APICCommonClass *info;
-
-    if (!d) {
-        return 0;
-    }
-
-    s = APIC_COMMON(d);
-    info = APIC_COMMON_GET_CLASS(s);
-
-    return info->get_tpr(s);
-}
-
-void apic_enable_tpr_access_reporting(DeviceState *d, bool enable)
-{
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
-
-    apic_report_tpr_access = enable;
-    if (info->enable_tpr_reporting) {
-        info->enable_tpr_reporting(s, enable);
-    }
-}
-
-void apic_enable_vapic(DeviceState *d, hwaddr paddr)
-{
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
-
-    s->vapic_paddr = paddr;
-    info->vapic_base_update(s);
-}
-
-void apic_handle_tpr_access_report(DeviceState *d, target_ulong ip,
-                                   TPRAccess access)
-{
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-
-    vapic_report_tpr_access(s->vapic, CPU(s->cpu), ip, access);
-}
-
-void apic_report_irq_delivered(int delivered)
-{
-    apic_irq_delivered += delivered;
-
-    trace_apic_report_irq_delivered(apic_irq_delivered);
-}
-
-void apic_reset_irq_delivered(void)
-{
-    trace_apic_reset_irq_delivered(apic_irq_delivered);
-
-    apic_irq_delivered = 0;
-}
-
-int apic_get_irq_delivered(void)
-{
-    trace_apic_get_irq_delivered(apic_irq_delivered);
-
-    return apic_irq_delivered;
-}
-
-void apic_deliver_nmi(DeviceState *d)
-{
-    APICCommonState *s = APIC_COMMON(d);
-    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
-
-    info->external_nmi(s);
-}
-
-bool apic_next_timer(APICCommonState *s, int64_t current_time)
-{
-    int64_t d;
-
-    /* We need to store the timer state separately to support APIC
-     * implementations that maintain a non-QEMU timer, e.g. inside the
-     * host kernel. This open-coded state allows us to migrate between
-     * both models. */
-    s->timer_expiry = -1;
-
-    if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED) {
-        return false;
-    }
-
-    d = (current_time - s->initial_count_load_time) >> s->count_shift;
-
-    if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
-        if (!s->initial_count) {
-            return false;
-        }
-        d = ((d / ((uint64_t)s->initial_count + 1)) + 1) *
-            ((uint64_t)s->initial_count + 1);
-    } else {
-        if (d >= s->initial_count) {
-            return false;
-        }
-        d = (uint64_t)s->initial_count + 1;
-    }
-    s->next_time = s->initial_count_load_time + (d << s->count_shift);
-    s->timer_expiry = s->next_time;
-    return true;
-}
-
-void apic_init_reset(DeviceState *d)
-{
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-    int i;
-
-    if (!s) {
-        return;
-    }
-    s->tpr = 0;
-    s->spurious_vec = 0xff;
-    s->log_dest = 0;
-    s->dest_mode = 0xf;
-    memset(s->isr, 0, sizeof(s->isr));
-    memset(s->tmr, 0, sizeof(s->tmr));
-    memset(s->irr, 0, sizeof(s->irr));
-    for (i = 0; i < APIC_LVT_NB; i++) {
-        s->lvt[i] = APIC_LVT_MASKED;
-    }
-    s->esr = 0;
-    memset(s->icr, 0, sizeof(s->icr));
-    s->divide_conf = 0;
-    s->count_shift = 0;
-    s->initial_count = 0;
-    s->initial_count_load_time = 0;
-    s->next_time = 0;
-    s->wait_for_sipi = 1;
-
-    if (s->timer) {
-        qemu_del_timer(s->timer);
-    }
-    s->timer_expiry = -1;
-}
-
-void apic_designate_bsp(DeviceState *d)
-{
-    if (d == NULL) {
-        return;
-    }
-
-    APICCommonState *s = APIC_COMMON(d);
-    s->apicbase |= MSR_IA32_APICBASE_BSP;
-}
-
-static void apic_reset_common(DeviceState *d)
-{
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
-    bool bsp;
-
-    bsp = cpu_is_bsp(s->cpu);
-    s->apicbase = APIC_DEFAULT_ADDRESS |
-        (bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE;
-
-    s->vapic_paddr = 0;
-    info->vapic_base_update(s);
-
-    apic_init_reset(d);
-
-    if (bsp) {
-        /*
-         * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization
-         * time typically by BIOS, so PIC interrupt can be delivered to the
-         * processor when local APIC is enabled.
-         */
-        s->lvt[APIC_LVT_LINT0] = 0x700;
-    }
-}
-
-/* This function is only used for old state version 1 and 2 */
-static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
-{
-    APICCommonState *s = opaque;
-    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
-    int i;
-
-    if (version_id > 2) {
-        return -EINVAL;
-    }
-
-    /* XXX: what if the base changes? (registered memory regions) */
-    qemu_get_be32s(f, &s->apicbase);
-    qemu_get_8s(f, &s->id);
-    qemu_get_8s(f, &s->arb_id);
-    qemu_get_8s(f, &s->tpr);
-    qemu_get_be32s(f, &s->spurious_vec);
-    qemu_get_8s(f, &s->log_dest);
-    qemu_get_8s(f, &s->dest_mode);
-    for (i = 0; i < 8; i++) {
-        qemu_get_be32s(f, &s->isr[i]);
-        qemu_get_be32s(f, &s->tmr[i]);
-        qemu_get_be32s(f, &s->irr[i]);
-    }
-    for (i = 0; i < APIC_LVT_NB; i++) {
-        qemu_get_be32s(f, &s->lvt[i]);
-    }
-    qemu_get_be32s(f, &s->esr);
-    qemu_get_be32s(f, &s->icr[0]);
-    qemu_get_be32s(f, &s->icr[1]);
-    qemu_get_be32s(f, &s->divide_conf);
-    s->count_shift = qemu_get_be32(f);
-    qemu_get_be32s(f, &s->initial_count);
-    s->initial_count_load_time = qemu_get_be64(f);
-    s->next_time = qemu_get_be64(f);
-
-    if (version_id >= 2) {
-        s->timer_expiry = qemu_get_be64(f);
-    }
-
-    if (info->post_load) {
-        info->post_load(s);
-    }
-    return 0;
-}
-
-static int apic_init_common(SysBusDevice *dev)
-{
-    APICCommonState *s = APIC_COMMON(dev);
-    APICCommonClass *info;
-    static DeviceState *vapic;
-    static int apic_no;
-
-    if (apic_no >= MAX_APICS) {
-        return -1;
-    }
-    s->idx = apic_no++;
-
-    info = APIC_COMMON_GET_CLASS(s);
-    info->init(s);
-
-    sysbus_init_mmio(dev, &s->io_memory);
-
-    /* Note: We need at least 1M to map the VAPIC option ROM */
-    if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK &&
-        ram_size >= 1024 * 1024) {
-        vapic = sysbus_create_simple("kvmvapic", -1, NULL);
-    }
-    s->vapic = vapic;
-    if (apic_report_tpr_access && info->enable_tpr_reporting) {
-        info->enable_tpr_reporting(s, true);
-    }
-
-    return 0;
-}
-
-static void apic_dispatch_pre_save(void *opaque)
-{
-    APICCommonState *s = APIC_COMMON(opaque);
-    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
-
-    if (info->pre_save) {
-        info->pre_save(s);
-    }
-}
-
-static int apic_dispatch_post_load(void *opaque, int version_id)
-{
-    APICCommonState *s = APIC_COMMON(opaque);
-    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
-
-    if (info->post_load) {
-        info->post_load(s);
-    }
-    return 0;
-}
-
-static const VMStateDescription vmstate_apic_common = {
-    .name = "apic",
-    .version_id = 3,
-    .minimum_version_id = 3,
-    .minimum_version_id_old = 1,
-    .load_state_old = apic_load_old,
-    .pre_save = apic_dispatch_pre_save,
-    .post_load = apic_dispatch_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(apicbase, APICCommonState),
-        VMSTATE_UINT8(id, APICCommonState),
-        VMSTATE_UINT8(arb_id, APICCommonState),
-        VMSTATE_UINT8(tpr, APICCommonState),
-        VMSTATE_UINT32(spurious_vec, APICCommonState),
-        VMSTATE_UINT8(log_dest, APICCommonState),
-        VMSTATE_UINT8(dest_mode, APICCommonState),
-        VMSTATE_UINT32_ARRAY(isr, APICCommonState, 8),
-        VMSTATE_UINT32_ARRAY(tmr, APICCommonState, 8),
-        VMSTATE_UINT32_ARRAY(irr, APICCommonState, 8),
-        VMSTATE_UINT32_ARRAY(lvt, APICCommonState, APIC_LVT_NB),
-        VMSTATE_UINT32(esr, APICCommonState),
-        VMSTATE_UINT32_ARRAY(icr, APICCommonState, 2),
-        VMSTATE_UINT32(divide_conf, APICCommonState),
-        VMSTATE_INT32(count_shift, APICCommonState),
-        VMSTATE_UINT32(initial_count, APICCommonState),
-        VMSTATE_INT64(initial_count_load_time, APICCommonState),
-        VMSTATE_INT64(next_time, APICCommonState),
-        VMSTATE_INT64(timer_expiry,
-                      APICCommonState), /* open-coded timer state */
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property apic_properties_common[] = {
-    DEFINE_PROP_UINT8("id", APICCommonState, id, -1),
-    DEFINE_PROP_BIT("vapic", APICCommonState, vapic_control, VAPIC_ENABLE_BIT,
-                    true),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void apic_common_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    dc->vmsd = &vmstate_apic_common;
-    dc->reset = apic_reset_common;
-    dc->no_user = 1;
-    dc->props = apic_properties_common;
-    sc->init = apic_init_common;
-}
-
-static const TypeInfo apic_common_type = {
-    .name = TYPE_APIC_COMMON,
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(APICCommonState),
-    .class_size = sizeof(APICCommonClass),
-    .class_init = apic_common_class_init,
-    .abstract = true,
-};
-
-static void register_types(void)
-{
-    type_register_static(&apic_common_type);
-}
-
-type_init(register_types)
index 59b5cf69cb4026aa4618d535b42b2ce1d1333a1c..915073bd2c194ac82ce6c795f6ce60c1f23a4670 100644 (file)
@@ -1,20 +1,16 @@
 obj-y += zynq_slcr.o
-obj-y += arm_gic.o arm_gic_common.o
 obj-y += a9scu.o
-obj-y += realview_gic.o arm_sysctl.o arm11mpcore.o a9mpcore.o
-obj-y += exynos4210_gic.o exynos4210_combiner.o
+obj-y += arm_sysctl.o arm11mpcore.o a9mpcore.o
 obj-y += exynos4210_pmu.o
 obj-y += a15mpcore.o
-obj-y += armv7m_nvic.o
 obj-y += pxa2xx_pcmcia.o
 obj-y += zaurus.o
-obj-y += omap_clk.o omap_gpio.o omap_intc.o
+obj-y += omap_clk.o omap_gpio.o
 obj-y += omap_gpmc.o omap_sdrc.o omap_tap.o omap_l4.o
 obj-y += cbus.o
 obj-y += mst_fpga.o
 obj-y += strongarm.o
-obj-y += imx_ccm.o imx_avic.o
-obj-$(CONFIG_KVM) += kvm/arm_gic.o
+obj-y += imx_ccm.o
 
 obj-y := $(addprefix ../,$(obj-y))
 
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
deleted file mode 100644 (file)
index bcb072b..0000000
+++ /dev/null
@@ -1,723 +0,0 @@
-/*
- * ARM Generic/Distributed Interrupt Controller
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-/* This file contains implementation code for the RealView EB interrupt
- * controller, MPCore distributed interrupt controller and ARMv7-M
- * Nested Vectored Interrupt Controller.
- * It is compiled in two ways:
- *  (1) as a standalone file to produce a sysbus device which is a GIC
- *  that can be used on the realview board and as one of the builtin
- *  private peripherals for the ARM MP CPUs (11MPCore, A9, etc)
- *  (2) by being directly #included into armv7m_nvic.c to produce the
- *  armv7m_nvic device.
- */
-
-#include "hw/sysbus.h"
-#include "hw/arm_gic_internal.h"
-
-//#define DEBUG_GIC
-
-#ifdef DEBUG_GIC
-#define DPRINTF(fmt, ...) \
-do { fprintf(stderr, "arm_gic: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-static const uint8_t gic_id[] = {
-    0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1
-};
-
-#define NUM_CPU(s) ((s)->num_cpu)
-
-static inline int gic_get_current_cpu(GICState *s)
-{
-    if (s->num_cpu > 1) {
-        CPUState *cpu = ENV_GET_CPU(cpu_single_env);
-        return cpu->cpu_index;
-    }
-    return 0;
-}
-
-/* TODO: Many places that call this routine could be optimized.  */
-/* Update interrupt status after enabled or pending bits have been changed.  */
-void gic_update(GICState *s)
-{
-    int best_irq;
-    int best_prio;
-    int irq;
-    int level;
-    int cpu;
-    int cm;
-
-    for (cpu = 0; cpu < NUM_CPU(s); cpu++) {
-        cm = 1 << cpu;
-        s->current_pending[cpu] = 1023;
-        if (!s->enabled || !s->cpu_enabled[cpu]) {
-            qemu_irq_lower(s->parent_irq[cpu]);
-            return;
-        }
-        best_prio = 0x100;
-        best_irq = 1023;
-        for (irq = 0; irq < s->num_irq; irq++) {
-            if (GIC_TEST_ENABLED(irq, cm) && GIC_TEST_PENDING(irq, cm)) {
-                if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
-                    best_prio = GIC_GET_PRIORITY(irq, cpu);
-                    best_irq = irq;
-                }
-            }
-        }
-        level = 0;
-        if (best_prio < s->priority_mask[cpu]) {
-            s->current_pending[cpu] = best_irq;
-            if (best_prio < s->running_priority[cpu]) {
-                DPRINTF("Raised pending IRQ %d (cpu %d)\n", best_irq, cpu);
-                level = 1;
-            }
-        }
-        qemu_set_irq(s->parent_irq[cpu], level);
-    }
-}
-
-void gic_set_pending_private(GICState *s, int cpu, int irq)
-{
-    int cm = 1 << cpu;
-
-    if (GIC_TEST_PENDING(irq, cm))
-        return;
-
-    DPRINTF("Set %d pending cpu %d\n", irq, cpu);
-    GIC_SET_PENDING(irq, cm);
-    gic_update(s);
-}
-
-/* Process a change in an external IRQ input.  */
-static void gic_set_irq(void *opaque, int irq, int level)
-{
-    /* Meaning of the 'irq' parameter:
-     *  [0..N-1] : external interrupts
-     *  [N..N+31] : PPI (internal) interrupts for CPU 0
-     *  [N+32..N+63] : PPI (internal interrupts for CPU 1
-     *  ...
-     */
-    GICState *s = (GICState *)opaque;
-    int cm, target;
-    if (irq < (s->num_irq - GIC_INTERNAL)) {
-        /* The first external input line is internal interrupt 32.  */
-        cm = ALL_CPU_MASK;
-        irq += GIC_INTERNAL;
-        target = GIC_TARGET(irq);
-    } else {
-        int cpu;
-        irq -= (s->num_irq - GIC_INTERNAL);
-        cpu = irq / GIC_INTERNAL;
-        irq %= GIC_INTERNAL;
-        cm = 1 << cpu;
-        target = cm;
-    }
-
-    if (level == GIC_TEST_LEVEL(irq, cm)) {
-        return;
-    }
-
-    if (level) {
-        GIC_SET_LEVEL(irq, cm);
-        if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) {
-            DPRINTF("Set %d pending mask %x\n", irq, target);
-            GIC_SET_PENDING(irq, target);
-        }
-    } else {
-        GIC_CLEAR_LEVEL(irq, cm);
-    }
-    gic_update(s);
-}
-
-static void gic_set_running_irq(GICState *s, int cpu, int irq)
-{
-    s->running_irq[cpu] = irq;
-    if (irq == 1023) {
-        s->running_priority[cpu] = 0x100;
-    } else {
-        s->running_priority[cpu] = GIC_GET_PRIORITY(irq, cpu);
-    }
-    gic_update(s);
-}
-
-uint32_t gic_acknowledge_irq(GICState *s, int cpu)
-{
-    int new_irq;
-    int cm = 1 << cpu;
-    new_irq = s->current_pending[cpu];
-    if (new_irq == 1023
-            || GIC_GET_PRIORITY(new_irq, cpu) >= s->running_priority[cpu]) {
-        DPRINTF("ACK no pending IRQ\n");
-        return 1023;
-    }
-    s->last_active[new_irq][cpu] = s->running_irq[cpu];
-    /* Clear pending flags for both level and edge triggered interrupts.
-       Level triggered IRQs will be reasserted once they become inactive.  */
-    GIC_CLEAR_PENDING(new_irq, GIC_TEST_MODEL(new_irq) ? ALL_CPU_MASK : cm);
-    gic_set_running_irq(s, cpu, new_irq);
-    DPRINTF("ACK %d\n", new_irq);
-    return new_irq;
-}
-
-void gic_complete_irq(GICState *s, int cpu, int irq)
-{
-    int update = 0;
-    int cm = 1 << cpu;
-    DPRINTF("EOI %d\n", irq);
-    if (irq >= s->num_irq) {
-        /* This handles two cases:
-         * 1. If software writes the ID of a spurious interrupt [ie 1023]
-         * to the GICC_EOIR, the GIC ignores that write.
-         * 2. If software writes the number of a non-existent interrupt
-         * this must be a subcase of "value written does not match the last
-         * valid interrupt value read from the Interrupt Acknowledge
-         * register" and so this is UNPREDICTABLE. We choose to ignore it.
-         */
-        return;
-    }
-    if (s->running_irq[cpu] == 1023)
-        return; /* No active IRQ.  */
-    /* Mark level triggered interrupts as pending if they are still
-       raised.  */
-    if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm)
-        && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) {
-        DPRINTF("Set %d pending mask %x\n", irq, cm);
-        GIC_SET_PENDING(irq, cm);
-        update = 1;
-    }
-    if (irq != s->running_irq[cpu]) {
-        /* Complete an IRQ that is not currently running.  */
-        int tmp = s->running_irq[cpu];
-        while (s->last_active[tmp][cpu] != 1023) {
-            if (s->last_active[tmp][cpu] == irq) {
-                s->last_active[tmp][cpu] = s->last_active[irq][cpu];
-                break;
-            }
-            tmp = s->last_active[tmp][cpu];
-        }
-        if (update) {
-            gic_update(s);
-        }
-    } else {
-        /* Complete the current running IRQ.  */
-        gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]);
-    }
-}
-
-static uint32_t gic_dist_readb(void *opaque, hwaddr offset)
-{
-    GICState *s = (GICState *)opaque;
-    uint32_t res;
-    int irq;
-    int i;
-    int cpu;
-    int cm;
-    int mask;
-
-    cpu = gic_get_current_cpu(s);
-    cm = 1 << cpu;
-    if (offset < 0x100) {
-        if (offset == 0)
-            return s->enabled;
-        if (offset == 4)
-            return ((s->num_irq / 32) - 1) | ((NUM_CPU(s) - 1) << 5);
-        if (offset < 0x08)
-            return 0;
-        if (offset >= 0x80) {
-            /* Interrupt Security , RAZ/WI */
-            return 0;
-        }
-        goto bad_reg;
-    } else if (offset < 0x200) {
-        /* Interrupt Set/Clear Enable.  */
-        if (offset < 0x180)
-            irq = (offset - 0x100) * 8;
-        else
-            irq = (offset - 0x180) * 8;
-        irq += GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        res = 0;
-        for (i = 0; i < 8; i++) {
-            if (GIC_TEST_ENABLED(irq + i, cm)) {
-                res |= (1 << i);
-            }
-        }
-    } else if (offset < 0x300) {
-        /* Interrupt Set/Clear Pending.  */
-        if (offset < 0x280)
-            irq = (offset - 0x200) * 8;
-        else
-            irq = (offset - 0x280) * 8;
-        irq += GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        res = 0;
-        mask = (irq < GIC_INTERNAL) ?  cm : ALL_CPU_MASK;
-        for (i = 0; i < 8; i++) {
-            if (GIC_TEST_PENDING(irq + i, mask)) {
-                res |= (1 << i);
-            }
-        }
-    } else if (offset < 0x400) {
-        /* Interrupt Active.  */
-        irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        res = 0;
-        mask = (irq < GIC_INTERNAL) ?  cm : ALL_CPU_MASK;
-        for (i = 0; i < 8; i++) {
-            if (GIC_TEST_ACTIVE(irq + i, mask)) {
-                res |= (1 << i);
-            }
-        }
-    } else if (offset < 0x800) {
-        /* Interrupt Priority.  */
-        irq = (offset - 0x400) + GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        res = GIC_GET_PRIORITY(irq, cpu);
-    } else if (offset < 0xc00) {
-        /* Interrupt CPU Target.  */
-        if (s->num_cpu == 1 && s->revision != REV_11MPCORE) {
-            /* For uniprocessor GICs these RAZ/WI */
-            res = 0;
-        } else {
-            irq = (offset - 0x800) + GIC_BASE_IRQ;
-            if (irq >= s->num_irq) {
-                goto bad_reg;
-            }
-            if (irq >= 29 && irq <= 31) {
-                res = cm;
-            } else {
-                res = GIC_TARGET(irq);
-            }
-        }
-    } else if (offset < 0xf00) {
-        /* Interrupt Configuration.  */
-        irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        res = 0;
-        for (i = 0; i < 4; i++) {
-            if (GIC_TEST_MODEL(irq + i))
-                res |= (1 << (i * 2));
-            if (GIC_TEST_TRIGGER(irq + i))
-                res |= (2 << (i * 2));
-        }
-    } else if (offset < 0xfe0) {
-        goto bad_reg;
-    } else /* offset >= 0xfe0 */ {
-        if (offset & 3) {
-            res = 0;
-        } else {
-            res = gic_id[(offset - 0xfe0) >> 2];
-        }
-    }
-    return res;
-bad_reg:
-    qemu_log_mask(LOG_GUEST_ERROR,
-                  "gic_dist_readb: Bad offset %x\n", (int)offset);
-    return 0;
-}
-
-static uint32_t gic_dist_readw(void *opaque, hwaddr offset)
-{
-    uint32_t val;
-    val = gic_dist_readb(opaque, offset);
-    val |= gic_dist_readb(opaque, offset + 1) << 8;
-    return val;
-}
-
-static uint32_t gic_dist_readl(void *opaque, hwaddr offset)
-{
-    uint32_t val;
-    val = gic_dist_readw(opaque, offset);
-    val |= gic_dist_readw(opaque, offset + 2) << 16;
-    return val;
-}
-
-static void gic_dist_writeb(void *opaque, hwaddr offset,
-                            uint32_t value)
-{
-    GICState *s = (GICState *)opaque;
-    int irq;
-    int i;
-    int cpu;
-
-    cpu = gic_get_current_cpu(s);
-    if (offset < 0x100) {
-        if (offset == 0) {
-            s->enabled = (value & 1);
-            DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis");
-        } else if (offset < 4) {
-            /* ignored.  */
-        } else if (offset >= 0x80) {
-            /* Interrupt Security Registers, RAZ/WI */
-        } else {
-            goto bad_reg;
-        }
-    } else if (offset < 0x180) {
-        /* Interrupt Set Enable.  */
-        irq = (offset - 0x100) * 8 + GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        if (irq < 16)
-          value = 0xff;
-        for (i = 0; i < 8; i++) {
-            if (value & (1 << i)) {
-                int mask =
-                    (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq + i);
-                int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
-
-                if (!GIC_TEST_ENABLED(irq + i, cm)) {
-                    DPRINTF("Enabled IRQ %d\n", irq + i);
-                }
-                GIC_SET_ENABLED(irq + i, cm);
-                /* If a raised level triggered IRQ enabled then mark
-                   is as pending.  */
-                if (GIC_TEST_LEVEL(irq + i, mask)
-                        && !GIC_TEST_TRIGGER(irq + i)) {
-                    DPRINTF("Set %d pending mask %x\n", irq + i, mask);
-                    GIC_SET_PENDING(irq + i, mask);
-                }
-            }
-        }
-    } else if (offset < 0x200) {
-        /* Interrupt Clear Enable.  */
-        irq = (offset - 0x180) * 8 + GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        if (irq < 16)
-          value = 0;
-        for (i = 0; i < 8; i++) {
-            if (value & (1 << i)) {
-                int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
-
-                if (GIC_TEST_ENABLED(irq + i, cm)) {
-                    DPRINTF("Disabled IRQ %d\n", irq + i);
-                }
-                GIC_CLEAR_ENABLED(irq + i, cm);
-            }
-        }
-    } else if (offset < 0x280) {
-        /* Interrupt Set Pending.  */
-        irq = (offset - 0x200) * 8 + GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        if (irq < 16)
-          irq = 0;
-
-        for (i = 0; i < 8; i++) {
-            if (value & (1 << i)) {
-                GIC_SET_PENDING(irq + i, GIC_TARGET(irq + i));
-            }
-        }
-    } else if (offset < 0x300) {
-        /* Interrupt Clear Pending.  */
-        irq = (offset - 0x280) * 8 + GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        for (i = 0; i < 8; i++) {
-            /* ??? This currently clears the pending bit for all CPUs, even
-               for per-CPU interrupts.  It's unclear whether this is the
-               corect behavior.  */
-            if (value & (1 << i)) {
-                GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK);
-            }
-        }
-    } else if (offset < 0x400) {
-        /* Interrupt Active.  */
-        goto bad_reg;
-    } else if (offset < 0x800) {
-        /* Interrupt Priority.  */
-        irq = (offset - 0x400) + GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        if (irq < GIC_INTERNAL) {
-            s->priority1[irq][cpu] = value;
-        } else {
-            s->priority2[irq - GIC_INTERNAL] = value;
-        }
-    } else if (offset < 0xc00) {
-        /* Interrupt CPU Target. RAZ/WI on uniprocessor GICs, with the
-         * annoying exception of the 11MPCore's GIC.
-         */
-        if (s->num_cpu != 1 || s->revision == REV_11MPCORE) {
-            irq = (offset - 0x800) + GIC_BASE_IRQ;
-            if (irq >= s->num_irq) {
-                goto bad_reg;
-            }
-            if (irq < 29) {
-                value = 0;
-            } else if (irq < GIC_INTERNAL) {
-                value = ALL_CPU_MASK;
-            }
-            s->irq_target[irq] = value & ALL_CPU_MASK;
-        }
-    } else if (offset < 0xf00) {
-        /* Interrupt Configuration.  */
-        irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        if (irq < GIC_INTERNAL)
-            value |= 0xaa;
-        for (i = 0; i < 4; i++) {
-            if (value & (1 << (i * 2))) {
-                GIC_SET_MODEL(irq + i);
-            } else {
-                GIC_CLEAR_MODEL(irq + i);
-            }
-            if (value & (2 << (i * 2))) {
-                GIC_SET_TRIGGER(irq + i);
-            } else {
-                GIC_CLEAR_TRIGGER(irq + i);
-            }
-        }
-    } else {
-        /* 0xf00 is only handled for 32-bit writes.  */
-        goto bad_reg;
-    }
-    gic_update(s);
-    return;
-bad_reg:
-    qemu_log_mask(LOG_GUEST_ERROR,
-                  "gic_dist_writeb: Bad offset %x\n", (int)offset);
-}
-
-static void gic_dist_writew(void *opaque, hwaddr offset,
-                            uint32_t value)
-{
-    gic_dist_writeb(opaque, offset, value & 0xff);
-    gic_dist_writeb(opaque, offset + 1, value >> 8);
-}
-
-static void gic_dist_writel(void *opaque, hwaddr offset,
-                            uint32_t value)
-{
-    GICState *s = (GICState *)opaque;
-    if (offset == 0xf00) {
-        int cpu;
-        int irq;
-        int mask;
-
-        cpu = gic_get_current_cpu(s);
-        irq = value & 0x3ff;
-        switch ((value >> 24) & 3) {
-        case 0:
-            mask = (value >> 16) & ALL_CPU_MASK;
-            break;
-        case 1:
-            mask = ALL_CPU_MASK ^ (1 << cpu);
-            break;
-        case 2:
-            mask = 1 << cpu;
-            break;
-        default:
-            DPRINTF("Bad Soft Int target filter\n");
-            mask = ALL_CPU_MASK;
-            break;
-        }
-        GIC_SET_PENDING(irq, mask);
-        gic_update(s);
-        return;
-    }
-    gic_dist_writew(opaque, offset, value & 0xffff);
-    gic_dist_writew(opaque, offset + 2, value >> 16);
-}
-
-static const MemoryRegionOps gic_dist_ops = {
-    .old_mmio = {
-        .read = { gic_dist_readb, gic_dist_readw, gic_dist_readl, },
-        .write = { gic_dist_writeb, gic_dist_writew, gic_dist_writel, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint32_t gic_cpu_read(GICState *s, int cpu, int offset)
-{
-    switch (offset) {
-    case 0x00: /* Control */
-        return s->cpu_enabled[cpu];
-    case 0x04: /* Priority mask */
-        return s->priority_mask[cpu];
-    case 0x08: /* Binary Point */
-        /* ??? Not implemented.  */
-        return 0;
-    case 0x0c: /* Acknowledge */
-        return gic_acknowledge_irq(s, cpu);
-    case 0x14: /* Running Priority */
-        return s->running_priority[cpu];
-    case 0x18: /* Highest Pending Interrupt */
-        return s->current_pending[cpu];
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "gic_cpu_read: Bad offset %x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void gic_cpu_write(GICState *s, int cpu, int offset, uint32_t value)
-{
-    switch (offset) {
-    case 0x00: /* Control */
-        s->cpu_enabled[cpu] = (value & 1);
-        DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled[cpu] ? "En" : "Dis");
-        break;
-    case 0x04: /* Priority mask */
-        s->priority_mask[cpu] = (value & 0xff);
-        break;
-    case 0x08: /* Binary Point */
-        /* ??? Not implemented.  */
-        break;
-    case 0x10: /* End Of Interrupt */
-        return gic_complete_irq(s, cpu, value & 0x3ff);
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "gic_cpu_write: Bad offset %x\n", (int)offset);
-        return;
-    }
-    gic_update(s);
-}
-
-/* Wrappers to read/write the GIC CPU interface for the current CPU */
-static uint64_t gic_thiscpu_read(void *opaque, hwaddr addr,
-                                 unsigned size)
-{
-    GICState *s = (GICState *)opaque;
-    return gic_cpu_read(s, gic_get_current_cpu(s), addr);
-}
-
-static void gic_thiscpu_write(void *opaque, hwaddr addr,
-                              uint64_t value, unsigned size)
-{
-    GICState *s = (GICState *)opaque;
-    gic_cpu_write(s, gic_get_current_cpu(s), addr, value);
-}
-
-/* Wrappers to read/write the GIC CPU interface for a specific CPU.
- * These just decode the opaque pointer into GICState* + cpu id.
- */
-static uint64_t gic_do_cpu_read(void *opaque, hwaddr addr,
-                                unsigned size)
-{
-    GICState **backref = (GICState **)opaque;
-    GICState *s = *backref;
-    int id = (backref - s->backref);
-    return gic_cpu_read(s, id, addr);
-}
-
-static void gic_do_cpu_write(void *opaque, hwaddr addr,
-                             uint64_t value, unsigned size)
-{
-    GICState **backref = (GICState **)opaque;
-    GICState *s = *backref;
-    int id = (backref - s->backref);
-    gic_cpu_write(s, id, addr, value);
-}
-
-static const MemoryRegionOps gic_thiscpu_ops = {
-    .read = gic_thiscpu_read,
-    .write = gic_thiscpu_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const MemoryRegionOps gic_cpu_ops = {
-    .read = gic_do_cpu_read,
-    .write = gic_do_cpu_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-void gic_init_irqs_and_distributor(GICState *s, int num_irq)
-{
-    int i;
-
-    i = s->num_irq - GIC_INTERNAL;
-    /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
-     * GPIO array layout is thus:
-     *  [0..N-1] SPIs
-     *  [N..N+31] PPIs for CPU 0
-     *  [N+32..N+63] PPIs for CPU 1
-     *   ...
-     */
-    if (s->revision != REV_NVIC) {
-        i += (GIC_INTERNAL * s->num_cpu);
-    }
-    qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, i);
-    for (i = 0; i < NUM_CPU(s); i++) {
-        sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
-    }
-    memory_region_init_io(&s->iomem, &gic_dist_ops, s, "gic_dist", 0x1000);
-}
-
-static void arm_gic_realize(DeviceState *dev, Error **errp)
-{
-    /* Device instance realize function for the GIC sysbus device */
-    int i;
-    GICState *s = ARM_GIC(dev);
-    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-    ARMGICClass *agc = ARM_GIC_GET_CLASS(s);
-
-    agc->parent_realize(dev, errp);
-    if (error_is_set(errp)) {
-        return;
-    }
-
-    gic_init_irqs_and_distributor(s, s->num_irq);
-
-    /* Memory regions for the CPU interfaces (NVIC doesn't have these):
-     * a region for "CPU interface for this core", then a region for
-     * "CPU interface for core 0", "for core 1", ...
-     * NB that the memory region size of 0x100 applies for the 11MPCore
-     * and also cores following the GIC v1 spec (ie A9).
-     * GIC v2 defines a larger memory region (0x1000) so this will need
-     * to be extended when we implement A15.
-     */
-    memory_region_init_io(&s->cpuiomem[0], &gic_thiscpu_ops, s,
-                          "gic_cpu", 0x100);
-    for (i = 0; i < NUM_CPU(s); i++) {
-        s->backref[i] = s;
-        memory_region_init_io(&s->cpuiomem[i+1], &gic_cpu_ops, &s->backref[i],
-                              "gic_cpu", 0x100);
-    }
-    /* Distributor */
-    sysbus_init_mmio(sbd, &s->iomem);
-    /* cpu interfaces (one for "current cpu" plus one per cpu) */
-    for (i = 0; i <= NUM_CPU(s); i++) {
-        sysbus_init_mmio(sbd, &s->cpuiomem[i]);
-    }
-}
-
-static void arm_gic_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    ARMGICClass *agc = ARM_GIC_CLASS(klass);
-
-    dc->no_user = 1;
-    agc->parent_realize = dc->realize;
-    dc->realize = arm_gic_realize;
-}
-
-static const TypeInfo arm_gic_info = {
-    .name = TYPE_ARM_GIC,
-    .parent = TYPE_ARM_GIC_COMMON,
-    .instance_size = sizeof(GICState),
-    .class_init = arm_gic_class_init,
-    .class_size = sizeof(ARMGICClass),
-};
-
-static void arm_gic_register_types(void)
-{
-    type_register_static(&arm_gic_info);
-}
-
-type_init(arm_gic_register_types)
diff --git a/hw/arm_gic_common.c b/hw/arm_gic_common.c
deleted file mode 100644 (file)
index 71594f1..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * ARM GIC support - common bits of emulated and KVM kernel model
- *
- * Copyright (c) 2012 Linaro Limited
- * Written by Peter Maydell
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "hw/arm_gic_internal.h"
-
-static void gic_pre_save(void *opaque)
-{
-    GICState *s = (GICState *)opaque;
-    ARMGICCommonClass *c = ARM_GIC_COMMON_GET_CLASS(s);
-
-    if (c->pre_save) {
-        c->pre_save(s);
-    }
-}
-
-static int gic_post_load(void *opaque, int version_id)
-{
-    GICState *s = (GICState *)opaque;
-    ARMGICCommonClass *c = ARM_GIC_COMMON_GET_CLASS(s);
-
-    if (c->post_load) {
-        c->post_load(s);
-    }
-    return 0;
-}
-
-static const VMStateDescription vmstate_gic_irq_state = {
-    .name = "arm_gic_irq_state",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT8(enabled, gic_irq_state),
-        VMSTATE_UINT8(pending, gic_irq_state),
-        VMSTATE_UINT8(active, gic_irq_state),
-        VMSTATE_UINT8(level, gic_irq_state),
-        VMSTATE_BOOL(model, gic_irq_state),
-        VMSTATE_BOOL(trigger, gic_irq_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_gic = {
-    .name = "arm_gic",
-    .version_id = 4,
-    .minimum_version_id = 4,
-    .pre_save = gic_pre_save,
-    .post_load = gic_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_BOOL(enabled, GICState),
-        VMSTATE_BOOL_ARRAY(cpu_enabled, GICState, NCPU),
-        VMSTATE_STRUCT_ARRAY(irq_state, GICState, GIC_MAXIRQ, 1,
-                             vmstate_gic_irq_state, gic_irq_state),
-        VMSTATE_UINT8_ARRAY(irq_target, GICState, GIC_MAXIRQ),
-        VMSTATE_UINT8_2DARRAY(priority1, GICState, GIC_INTERNAL, NCPU),
-        VMSTATE_UINT8_ARRAY(priority2, GICState, GIC_MAXIRQ - GIC_INTERNAL),
-        VMSTATE_UINT16_2DARRAY(last_active, GICState, GIC_MAXIRQ, NCPU),
-        VMSTATE_UINT16_ARRAY(priority_mask, GICState, NCPU),
-        VMSTATE_UINT16_ARRAY(running_irq, GICState, NCPU),
-        VMSTATE_UINT16_ARRAY(running_priority, GICState, NCPU),
-        VMSTATE_UINT16_ARRAY(current_pending, GICState, NCPU),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void arm_gic_common_realize(DeviceState *dev, Error **errp)
-{
-    GICState *s = ARM_GIC_COMMON(dev);
-    int num_irq = s->num_irq;
-
-    if (s->num_cpu > NCPU) {
-        error_setg(errp, "requested %u CPUs exceeds GIC maximum %d",
-                   s->num_cpu, NCPU);
-        return;
-    }
-    s->num_irq += GIC_BASE_IRQ;
-    if (s->num_irq > GIC_MAXIRQ) {
-        error_setg(errp,
-                   "requested %u interrupt lines exceeds GIC maximum %d",
-                   num_irq, GIC_MAXIRQ);
-        return;
-    }
-    /* ITLinesNumber is represented as (N / 32) - 1 (see
-     * gic_dist_readb) so this is an implementation imposed
-     * restriction, not an architectural one:
-     */
-    if (s->num_irq < 32 || (s->num_irq % 32)) {
-        error_setg(errp,
-                   "%d interrupt lines unsupported: not divisible by 32",
-                   num_irq);
-        return;
-    }
-}
-
-static void arm_gic_common_reset(DeviceState *dev)
-{
-    GICState *s = FROM_SYSBUS(GICState, SYS_BUS_DEVICE(dev));
-    int i;
-    memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state));
-    for (i = 0 ; i < s->num_cpu; i++) {
-        if (s->revision == REV_11MPCORE) {
-            s->priority_mask[i] = 0xf0;
-        } else {
-            s->priority_mask[i] = 0;
-        }
-        s->current_pending[i] = 1023;
-        s->running_irq[i] = 1023;
-        s->running_priority[i] = 0x100;
-        s->cpu_enabled[i] = false;
-    }
-    for (i = 0; i < 16; i++) {
-        GIC_SET_ENABLED(i, ALL_CPU_MASK);
-        GIC_SET_TRIGGER(i);
-    }
-    if (s->num_cpu == 1) {
-        /* For uniprocessor GICs all interrupts always target the sole CPU */
-        for (i = 0; i < GIC_MAXIRQ; i++) {
-            s->irq_target[i] = 1;
-        }
-    }
-    s->enabled = false;
-}
-
-static Property arm_gic_common_properties[] = {
-    DEFINE_PROP_UINT32("num-cpu", GICState, num_cpu, 1),
-    DEFINE_PROP_UINT32("num-irq", GICState, num_irq, 32),
-    /* Revision can be 1 or 2 for GIC architecture specification
-     * versions 1 or 2, or 0 to indicate the legacy 11MPCore GIC.
-     * (Internally, 0xffffffff also indicates "not a GIC but an NVIC".)
-     */
-    DEFINE_PROP_UINT32("revision", GICState, revision, 1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void arm_gic_common_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    dc->reset = arm_gic_common_reset;
-    dc->realize = arm_gic_common_realize;
-    dc->props = arm_gic_common_properties;
-    dc->vmsd = &vmstate_gic;
-    dc->no_user = 1;
-}
-
-static const TypeInfo arm_gic_common_type = {
-    .name = TYPE_ARM_GIC_COMMON,
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(GICState),
-    .class_size = sizeof(ARMGICCommonClass),
-    .class_init = arm_gic_common_class_init,
-    .abstract = true,
-};
-
-static void register_types(void)
-{
-    type_register_static(&arm_gic_common_type);
-}
-
-type_init(register_types)
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
deleted file mode 100644 (file)
index 7574260..0000000
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
- * ARM Nested Vectored Interrupt Controller
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- *
- * The ARMv7M System controller is fairly tightly tied in with the
- * NVIC.  Much of that is also implemented here.
- */
-
-#include "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "hw/arm.h"
-#include "exec/address-spaces.h"
-#include "hw/arm_gic_internal.h"
-
-typedef struct {
-    GICState gic;
-    struct {
-        uint32_t control;
-        uint32_t reload;
-        int64_t tick;
-        QEMUTimer *timer;
-    } systick;
-    MemoryRegion sysregmem;
-    MemoryRegion gic_iomem_alias;
-    MemoryRegion container;
-    uint32_t num_irq;
-} nvic_state;
-
-#define TYPE_NVIC "armv7m_nvic"
-/**
- * NVICClass:
- * @parent_reset: the parent class' reset handler.
- *
- * A model of the v7M NVIC and System Controller
- */
-typedef struct NVICClass {
-    /*< private >*/
-    ARMGICClass parent_class;
-    /*< public >*/
-    DeviceRealize parent_realize;
-    void (*parent_reset)(DeviceState *dev);
-} NVICClass;
-
-#define NVIC_CLASS(klass) \
-    OBJECT_CLASS_CHECK(NVICClass, (klass), TYPE_NVIC)
-#define NVIC_GET_CLASS(obj) \
-    OBJECT_GET_CLASS(NVICClass, (obj), TYPE_NVIC)
-#define NVIC(obj) \
-    OBJECT_CHECK(nvic_state, (obj), TYPE_NVIC)
-
-static const uint8_t nvic_id[] = {
-    0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1
-};
-
-/* qemu timers run at 1GHz.   We want something closer to 1MHz.  */
-#define SYSTICK_SCALE 1000ULL
-
-#define SYSTICK_ENABLE    (1 << 0)
-#define SYSTICK_TICKINT   (1 << 1)
-#define SYSTICK_CLKSOURCE (1 << 2)
-#define SYSTICK_COUNTFLAG (1 << 16)
-
-int system_clock_scale;
-
-/* Conversion factor from qemu timer to SysTick frequencies.  */
-static inline int64_t systick_scale(nvic_state *s)
-{
-    if (s->systick.control & SYSTICK_CLKSOURCE)
-        return system_clock_scale;
-    else
-        return 1000;
-}
-
-static void systick_reload(nvic_state *s, int reset)
-{
-    if (reset)
-        s->systick.tick = qemu_get_clock_ns(vm_clock);
-    s->systick.tick += (s->systick.reload + 1) * systick_scale(s);
-    qemu_mod_timer(s->systick.timer, s->systick.tick);
-}
-
-static void systick_timer_tick(void * opaque)
-{
-    nvic_state *s = (nvic_state *)opaque;
-    s->systick.control |= SYSTICK_COUNTFLAG;
-    if (s->systick.control & SYSTICK_TICKINT) {
-        /* Trigger the interrupt.  */
-        armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
-    }
-    if (s->systick.reload == 0) {
-        s->systick.control &= ~SYSTICK_ENABLE;
-    } else {
-        systick_reload(s, 0);
-    }
-}
-
-static void systick_reset(nvic_state *s)
-{
-    s->systick.control = 0;
-    s->systick.reload = 0;
-    s->systick.tick = 0;
-    qemu_del_timer(s->systick.timer);
-}
-
-/* The external routines use the hardware vector numbering, ie. the first
-   IRQ is #16.  The internal GIC routines use #32 as the first IRQ.  */
-void armv7m_nvic_set_pending(void *opaque, int irq)
-{
-    nvic_state *s = (nvic_state *)opaque;
-    if (irq >= 16)
-        irq += 16;
-    gic_set_pending_private(&s->gic, 0, irq);
-}
-
-/* Make pending IRQ active.  */
-int armv7m_nvic_acknowledge_irq(void *opaque)
-{
-    nvic_state *s = (nvic_state *)opaque;
-    uint32_t irq;
-
-    irq = gic_acknowledge_irq(&s->gic, 0);
-    if (irq == 1023)
-        hw_error("Interrupt but no vector\n");
-    if (irq >= 32)
-        irq -= 16;
-    return irq;
-}
-
-void armv7m_nvic_complete_irq(void *opaque, int irq)
-{
-    nvic_state *s = (nvic_state *)opaque;
-    if (irq >= 16)
-        irq += 16;
-    gic_complete_irq(&s->gic, 0, irq);
-}
-
-static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
-{
-    uint32_t val;
-    int irq;
-
-    switch (offset) {
-    case 4: /* Interrupt Control Type.  */
-        return (s->num_irq / 32) - 1;
-    case 0x10: /* SysTick Control and Status.  */
-        val = s->systick.control;
-        s->systick.control &= ~SYSTICK_COUNTFLAG;
-        return val;
-    case 0x14: /* SysTick Reload Value.  */
-        return s->systick.reload;
-    case 0x18: /* SysTick Current Value.  */
-        {
-            int64_t t;
-            if ((s->systick.control & SYSTICK_ENABLE) == 0)
-                return 0;
-            t = qemu_get_clock_ns(vm_clock);
-            if (t >= s->systick.tick)
-                return 0;
-            val = ((s->systick.tick - (t + 1)) / systick_scale(s)) + 1;
-            /* The interrupt in triggered when the timer reaches zero.
-               However the counter is not reloaded until the next clock
-               tick.  This is a hack to return zero during the first tick.  */
-            if (val > s->systick.reload)
-                val = 0;
-            return val;
-        }
-    case 0x1c: /* SysTick Calibration Value.  */
-        return 10000;
-    case 0xd00: /* CPUID Base.  */
-        return cpu_single_env->cp15.c0_cpuid;
-    case 0xd04: /* Interrypt Control State.  */
-        /* VECTACTIVE */
-        val = s->gic.running_irq[0];
-        if (val == 1023) {
-            val = 0;
-        } else if (val >= 32) {
-            val -= 16;
-        }
-        /* RETTOBASE */
-        if (s->gic.running_irq[0] == 1023
-                || s->gic.last_active[s->gic.running_irq[0]][0] == 1023) {
-            val |= (1 << 11);
-        }
-        /* VECTPENDING */
-        if (s->gic.current_pending[0] != 1023)
-            val |= (s->gic.current_pending[0] << 12);
-        /* ISRPENDING */
-        for (irq = 32; irq < s->num_irq; irq++) {
-            if (s->gic.irq_state[irq].pending) {
-                val |= (1 << 22);
-                break;
-            }
-        }
-        /* PENDSTSET */
-        if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending)
-            val |= (1 << 26);
-        /* PENDSVSET */
-        if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending)
-            val |= (1 << 28);
-        /* NMIPENDSET */
-        if (s->gic.irq_state[ARMV7M_EXCP_NMI].pending)
-            val |= (1 << 31);
-        return val;
-    case 0xd08: /* Vector Table Offset.  */
-        return cpu_single_env->v7m.vecbase;
-    case 0xd0c: /* Application Interrupt/Reset Control.  */
-        return 0xfa05000;
-    case 0xd10: /* System Control.  */
-        /* TODO: Implement SLEEPONEXIT.  */
-        return 0;
-    case 0xd14: /* Configuration Control.  */
-        /* TODO: Implement Configuration Control bits.  */
-        return 0;
-    case 0xd24: /* System Handler Status.  */
-        val = 0;
-        if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
-        if (s->gic.irq_state[ARMV7M_EXCP_BUS].active) val |= (1 << 1);
-        if (s->gic.irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3);
-        if (s->gic.irq_state[ARMV7M_EXCP_SVC].active) val |= (1 << 7);
-        if (s->gic.irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8);
-        if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10);
-        if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11);
-        if (s->gic.irq_state[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12);
-        if (s->gic.irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13);
-        if (s->gic.irq_state[ARMV7M_EXCP_BUS].pending) val |= (1 << 14);
-        if (s->gic.irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15);
-        if (s->gic.irq_state[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16);
-        if (s->gic.irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17);
-        if (s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18);
-        return val;
-    case 0xd28: /* Configurable Fault Status.  */
-        /* TODO: Implement Fault Status.  */
-        qemu_log_mask(LOG_UNIMP, "Configurable Fault Status unimplemented\n");
-        return 0;
-    case 0xd2c: /* Hard Fault Status.  */
-    case 0xd30: /* Debug Fault Status.  */
-    case 0xd34: /* Mem Manage Address.  */
-    case 0xd38: /* Bus Fault Address.  */
-    case 0xd3c: /* Aux Fault Status.  */
-        /* TODO: Implement fault status registers.  */
-        qemu_log_mask(LOG_UNIMP, "Fault status registers unimplemented\n");
-        return 0;
-    case 0xd40: /* PFR0.  */
-        return 0x00000030;
-    case 0xd44: /* PRF1.  */
-        return 0x00000200;
-    case 0xd48: /* DFR0.  */
-        return 0x00100000;
-    case 0xd4c: /* AFR0.  */
-        return 0x00000000;
-    case 0xd50: /* MMFR0.  */
-        return 0x00000030;
-    case 0xd54: /* MMFR1.  */
-        return 0x00000000;
-    case 0xd58: /* MMFR2.  */
-        return 0x00000000;
-    case 0xd5c: /* MMFR3.  */
-        return 0x00000000;
-    case 0xd60: /* ISAR0.  */
-        return 0x01141110;
-    case 0xd64: /* ISAR1.  */
-        return 0x02111000;
-    case 0xd68: /* ISAR2.  */
-        return 0x21112231;
-    case 0xd6c: /* ISAR3.  */
-        return 0x01111110;
-    case 0xd70: /* ISAR4.  */
-        return 0x01310102;
-    /* TODO: Implement debug registers.  */
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
-        return 0;
-    }
-}
-
-static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value)
-{
-    uint32_t oldval;
-    switch (offset) {
-    case 0x10: /* SysTick Control and Status.  */
-        oldval = s->systick.control;
-        s->systick.control &= 0xfffffff8;
-        s->systick.control |= value & 7;
-        if ((oldval ^ value) & SYSTICK_ENABLE) {
-            int64_t now = qemu_get_clock_ns(vm_clock);
-            if (value & SYSTICK_ENABLE) {
-                if (s->systick.tick) {
-                    s->systick.tick += now;
-                    qemu_mod_timer(s->systick.timer, s->systick.tick);
-                } else {
-                    systick_reload(s, 1);
-                }
-            } else {
-                qemu_del_timer(s->systick.timer);
-                s->systick.tick -= now;
-                if (s->systick.tick < 0)
-                  s->systick.tick = 0;
-            }
-        } else if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
-            /* This is a hack. Force the timer to be reloaded
-               when the reference clock is changed.  */
-            systick_reload(s, 1);
-        }
-        break;
-    case 0x14: /* SysTick Reload Value.  */
-        s->systick.reload = value;
-        break;
-    case 0x18: /* SysTick Current Value.  Writes reload the timer.  */
-        systick_reload(s, 1);
-        s->systick.control &= ~SYSTICK_COUNTFLAG;
-        break;
-    case 0xd04: /* Interrupt Control State.  */
-        if (value & (1 << 31)) {
-            armv7m_nvic_set_pending(s, ARMV7M_EXCP_NMI);
-        }
-        if (value & (1 << 28)) {
-            armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV);
-        } else if (value & (1 << 27)) {
-            s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending = 0;
-            gic_update(&s->gic);
-        }
-        if (value & (1 << 26)) {
-            armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
-        } else if (value & (1 << 25)) {
-            s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending = 0;
-            gic_update(&s->gic);
-        }
-        break;
-    case 0xd08: /* Vector Table Offset.  */
-        cpu_single_env->v7m.vecbase = value & 0xffffff80;
-        break;
-    case 0xd0c: /* Application Interrupt/Reset Control.  */
-        if ((value >> 16) == 0x05fa) {
-            if (value & 2) {
-                qemu_log_mask(LOG_UNIMP, "VECTCLRACTIVE unimplemented\n");
-            }
-            if (value & 5) {
-                qemu_log_mask(LOG_UNIMP, "AIRCR system reset unimplemented\n");
-            }
-        }
-        break;
-    case 0xd10: /* System Control.  */
-    case 0xd14: /* Configuration Control.  */
-        /* TODO: Implement control registers.  */
-        qemu_log_mask(LOG_UNIMP, "NVIC: SCR and CCR unimplemented\n");
-        break;
-    case 0xd24: /* System Handler Control.  */
-        /* TODO: Real hardware allows you to set/clear the active bits
-           under some circumstances.  We don't implement this.  */
-        s->gic.irq_state[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
-        s->gic.irq_state[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
-        s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0;
-        break;
-    case 0xd28: /* Configurable Fault Status.  */
-    case 0xd2c: /* Hard Fault Status.  */
-    case 0xd30: /* Debug Fault Status.  */
-    case 0xd34: /* Mem Manage Address.  */
-    case 0xd38: /* Bus Fault Address.  */
-    case 0xd3c: /* Aux Fault Status.  */
-        qemu_log_mask(LOG_UNIMP,
-                      "NVIC: fault status registers unimplemented\n");
-        break;
-    case 0xf00: /* Software Triggered Interrupt Register */
-        if ((value & 0x1ff) < s->num_irq) {
-            gic_set_pending_private(&s->gic, 0, value & 0x1ff);
-        }
-        break;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "NVIC: Bad write offset 0x%x\n", offset);
-    }
-}
-
-static uint64_t nvic_sysreg_read(void *opaque, hwaddr addr,
-                                 unsigned size)
-{
-    nvic_state *s = (nvic_state *)opaque;
-    uint32_t offset = addr;
-    int i;
-    uint32_t val;
-
-    switch (offset) {
-    case 0xd18 ... 0xd23: /* System Handler Priority.  */
-        val = 0;
-        for (i = 0; i < size; i++) {
-            val |= s->gic.priority1[(offset - 0xd14) + i][0] << (i * 8);
-        }
-        return val;
-    case 0xfe0 ... 0xfff: /* ID.  */
-        if (offset & 3) {
-            return 0;
-        }
-        return nvic_id[(offset - 0xfe0) >> 2];
-    }
-    if (size == 4) {
-        return nvic_readl(s, offset);
-    }
-    qemu_log_mask(LOG_GUEST_ERROR,
-                  "NVIC: Bad read of size %d at offset 0x%x\n", size, offset);
-    return 0;
-}
-
-static void nvic_sysreg_write(void *opaque, hwaddr addr,
-                              uint64_t value, unsigned size)
-{
-    nvic_state *s = (nvic_state *)opaque;
-    uint32_t offset = addr;
-    int i;
-
-    switch (offset) {
-    case 0xd18 ... 0xd23: /* System Handler Priority.  */
-        for (i = 0; i < size; i++) {
-            s->gic.priority1[(offset - 0xd14) + i][0] =
-                (value >> (i * 8)) & 0xff;
-        }
-        gic_update(&s->gic);
-        return;
-    }
-    if (size == 4) {
-        nvic_writel(s, offset, value);
-        return;
-    }
-    qemu_log_mask(LOG_GUEST_ERROR,
-                  "NVIC: Bad write of size %d at offset 0x%x\n", size, offset);
-}
-
-static const MemoryRegionOps nvic_sysreg_ops = {
-    .read = nvic_sysreg_read,
-    .write = nvic_sysreg_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_nvic = {
-    .name = "armv7m_nvic",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(systick.control, nvic_state),
-        VMSTATE_UINT32(systick.reload, nvic_state),
-        VMSTATE_INT64(systick.tick, nvic_state),
-        VMSTATE_TIMER(systick.timer, nvic_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void armv7m_nvic_reset(DeviceState *dev)
-{
-    nvic_state *s = NVIC(dev);
-    NVICClass *nc = NVIC_GET_CLASS(s);
-    nc->parent_reset(dev);
-    /* Common GIC reset resets to disabled; the NVIC doesn't have
-     * per-CPU interfaces so mark our non-existent CPU interface
-     * as enabled by default, and with a priority mask which allows
-     * all interrupts through.
-     */
-    s->gic.cpu_enabled[0] = true;
-    s->gic.priority_mask[0] = 0x100;
-    /* The NVIC as a whole is always enabled. */
-    s->gic.enabled = true;
-    systick_reset(s);
-}
-
-static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
-{
-    nvic_state *s = NVIC(dev);
-    NVICClass *nc = NVIC_GET_CLASS(s);
-
-    /* The NVIC always has only one CPU */
-    s->gic.num_cpu = 1;
-    /* Tell the common code we're an NVIC */
-    s->gic.revision = 0xffffffff;
-    s->num_irq = s->gic.num_irq;
-    nc->parent_realize(dev, errp);
-    if (error_is_set(errp)) {
-        return;
-    }
-    gic_init_irqs_and_distributor(&s->gic, s->num_irq);
-    /* The NVIC and system controller register area looks like this:
-     *  0..0xff : system control registers, including systick
-     *  0x100..0xcff : GIC-like registers
-     *  0xd00..0xfff : system control registers
-     * We use overlaying to put the GIC like registers
-     * over the top of the system control register region.
-     */
-    memory_region_init(&s->container, "nvic", 0x1000);
-    /* The system register region goes at the bottom of the priority
-     * stack as it covers the whole page.
-     */
-    memory_region_init_io(&s->sysregmem, &nvic_sysreg_ops, s,
-                          "nvic_sysregs", 0x1000);
-    memory_region_add_subregion(&s->container, 0, &s->sysregmem);
-    /* Alias the GIC region so we can get only the section of it
-     * we need, and layer it on top of the system register region.
-     */
-    memory_region_init_alias(&s->gic_iomem_alias, "nvic-gic", &s->gic.iomem,
-                             0x100, 0xc00);
-    memory_region_add_subregion_overlap(&s->container, 0x100,
-                                        &s->gic_iomem_alias, 1);
-    /* Map the whole thing into system memory at the location required
-     * by the v7M architecture.
-     */
-    memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->container);
-    s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s);
-}
-
-static void armv7m_nvic_instance_init(Object *obj)
-{
-    /* We have a different default value for the num-irq property
-     * than our superclass. This function runs after qdev init
-     * has set the defaults from the Property array and before
-     * any user-specified property setting, so just modify the
-     * value in the GICState struct.
-     */
-    GICState *s = ARM_GIC_COMMON(obj);
-    /* The ARM v7m may have anything from 0 to 496 external interrupt
-     * IRQ lines. We default to 64. Other boards may differ and should
-     * set the num-irq property appropriately.
-     */
-    s->num_irq = 64;
-}
-
-static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
-{
-    NVICClass *nc = NVIC_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    nc->parent_reset = dc->reset;
-    nc->parent_realize = dc->realize;
-    dc->vmsd  = &vmstate_nvic;
-    dc->reset = armv7m_nvic_reset;
-    dc->realize = armv7m_nvic_realize;
-}
-
-static const TypeInfo armv7m_nvic_info = {
-    .name          = TYPE_NVIC,
-    .parent        = TYPE_ARM_GIC_COMMON,
-    .instance_init = armv7m_nvic_instance_init,
-    .instance_size = sizeof(nvic_state),
-    .class_init    = armv7m_nvic_class_init,
-    .class_size    = sizeof(NVICClass),
-};
-
-static void armv7m_nvic_register_types(void)
-{
-    type_register_static(&armv7m_nvic_info);
-}
-
-type_init(armv7m_nvic_register_types)
index f8c85a452009c25f2c84205cc338fdb03bae2a35..776db7c5cda854d60a313cb31e2136480c44db25 100644 (file)
@@ -1,9 +1,3 @@
-# IO blocks
-obj-y += etraxfs_pic.o
-
-obj-y := $(addprefix ../,$(obj-y))
-
-# Boards
 obj-y += pic_cpu.o
 obj-y += boot.o
 obj-y += axis_dev88.o
diff --git a/hw/etraxfs_pic.c b/hw/etraxfs_pic.c
deleted file mode 100644 (file)
index 635103c..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * QEMU ETRAX Interrupt Controller.
- *
- * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/sysbus.h"
-#include "hw/hw.h"
-//#include "pc.h"
-//#include "etraxfs.h"
-
-#define D(x)
-
-#define R_RW_MASK   0
-#define R_R_VECT    1
-#define R_R_MASKED_VECT 2
-#define R_R_NMI     3
-#define R_R_GURU    4
-#define R_MAX       5
-
-struct etrax_pic
-{
-    SysBusDevice busdev;
-    MemoryRegion mmio;
-    void *interrupt_vector;
-    qemu_irq parent_irq;
-    qemu_irq parent_nmi;
-    uint32_t regs[R_MAX];
-};
-
-static void pic_update(struct etrax_pic *fs)
-{   
-    uint32_t vector = 0;
-    int i;
-
-    fs->regs[R_R_MASKED_VECT] = fs->regs[R_R_VECT] & fs->regs[R_RW_MASK];
-
-    /* The ETRAX interrupt controller signals interrupts to the core
-       through an interrupt request wire and an irq vector bus. If 
-       multiple interrupts are simultaneously active it chooses vector 
-       0x30 and lets the sw choose the priorities.  */
-    if (fs->regs[R_R_MASKED_VECT]) {
-        uint32_t mv = fs->regs[R_R_MASKED_VECT];
-        for (i = 0; i < 31; i++) {
-            if (mv & 1) {
-                vector = 0x31 + i;
-                /* Check for multiple interrupts.  */
-                if (mv > 1)
-                    vector = 0x30;
-                break;
-            }
-            mv >>= 1;
-        }
-    }
-
-    if (fs->interrupt_vector) {
-        /* hack alert: ptr property */
-        *(uint32_t*)(fs->interrupt_vector) = vector;
-    }
-    qemu_set_irq(fs->parent_irq, !!vector);
-}
-
-static uint64_t
-pic_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    struct etrax_pic *fs = opaque;
-    uint32_t rval;
-
-    rval = fs->regs[addr >> 2];
-    D(printf("%s %x=%x\n", __func__, addr, rval));
-    return rval;
-}
-
-static void pic_write(void *opaque, hwaddr addr,
-                      uint64_t value, unsigned int size)
-{
-    struct etrax_pic *fs = opaque;
-    D(printf("%s addr=%x val=%x\n", __func__, addr, value));
-
-    if (addr == R_RW_MASK) {
-        fs->regs[R_RW_MASK] = value;
-        pic_update(fs);
-    }
-}
-
-static const MemoryRegionOps pic_ops = {
-    .read = pic_read,
-    .write = pic_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4
-    }
-};
-
-static void nmi_handler(void *opaque, int irq, int level)
-{   
-    struct etrax_pic *fs = (void *)opaque;
-    uint32_t mask;
-
-    mask = 1 << irq;
-    if (level)
-        fs->regs[R_R_NMI] |= mask;
-    else
-        fs->regs[R_R_NMI] &= ~mask;
-
-    qemu_set_irq(fs->parent_nmi, !!fs->regs[R_R_NMI]);
-}
-
-static void irq_handler(void *opaque, int irq, int level)
-{   
-    struct etrax_pic *fs = (void *)opaque;
-
-    if (irq >= 30)
-        return nmi_handler(opaque, irq, level);
-
-    irq -= 1;
-    fs->regs[R_R_VECT] &= ~(1 << irq);
-    fs->regs[R_R_VECT] |= (!!level << irq);
-    pic_update(fs);
-}
-
-static int etraxfs_pic_init(SysBusDevice *dev)
-{
-    struct etrax_pic *s = FROM_SYSBUS(typeof (*s), dev);
-
-    qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
-    sysbus_init_irq(dev, &s->parent_irq);
-    sysbus_init_irq(dev, &s->parent_nmi);
-
-    memory_region_init_io(&s->mmio, &pic_ops, s, "etraxfs-pic", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->mmio);
-    return 0;
-}
-
-static Property etraxfs_pic_properties[] = {
-    DEFINE_PROP_PTR("interrupt_vector", struct etrax_pic, interrupt_vector),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void etraxfs_pic_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = etraxfs_pic_init;
-    dc->props = etraxfs_pic_properties;
-}
-
-static const TypeInfo etraxfs_pic_info = {
-    .name          = "etraxfs,pic",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(struct etrax_pic),
-    .class_init    = etraxfs_pic_class_init,
-};
-
-static void etraxfs_pic_register_types(void)
-{
-    type_register_static(&etraxfs_pic_info);
-}
-
-type_init(etraxfs_pic_register_types)
diff --git a/hw/exynos4210_combiner.c b/hw/exynos4210_combiner.c
deleted file mode 100644 (file)
index 6874287..0000000
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- * Samsung exynos4210 Interrupt Combiner
- *
- * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
- * All rights reserved.
- *
- * Evgeny Voevodin <e.voevodin@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Exynos4210 Combiner represents an OR gate for SOC's IRQ lines. It combines
- * IRQ sources into groups and provides signal output to GIC from each group. It
- * is driven by common mask and enable/disable logic. Take a note that not all
- * IRQs are passed to GIC through Combiner.
- */
-
-#include "hw/sysbus.h"
-
-#include "hw/arm/exynos4210.h"
-
-//#define DEBUG_COMBINER
-
-#ifdef DEBUG_COMBINER
-#define DPRINTF(fmt, ...) \
-        do { fprintf(stdout, "COMBINER: [%s:%d] " fmt, __func__ , __LINE__, \
-                ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-#define    IIC_NGRP        64            /* Internal Interrupt Combiner
-                                            Groups number */
-#define    IIC_NIRQ        (IIC_NGRP * 8)/* Internal Interrupt Combiner
-                                            Interrupts number */
-#define IIC_REGION_SIZE    0x108         /* Size of memory mapped region */
-#define IIC_REGSET_SIZE    0x41
-
-/*
- * State for each output signal of internal combiner
- */
-typedef struct CombinerGroupState {
-    uint8_t src_mask;            /* 1 - source enabled, 0 - disabled */
-    uint8_t src_pending;        /* Pending source interrupts before masking */
-} CombinerGroupState;
-
-typedef struct Exynos4210CombinerState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-
-    struct CombinerGroupState group[IIC_NGRP];
-    uint32_t reg_set[IIC_REGSET_SIZE];
-    uint32_t icipsr[2];
-    uint32_t external;          /* 1 means that this combiner is external */
-
-    qemu_irq output_irq[IIC_NGRP];
-} Exynos4210CombinerState;
-
-static const VMStateDescription vmstate_exynos4210_combiner_group_state = {
-    .name = "exynos4210.combiner.groupstate",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT8(src_mask, CombinerGroupState),
-        VMSTATE_UINT8(src_pending, CombinerGroupState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_exynos4210_combiner = {
-    .name = "exynos4210.combiner",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_STRUCT_ARRAY(group, Exynos4210CombinerState, IIC_NGRP, 0,
-                vmstate_exynos4210_combiner_group_state, CombinerGroupState),
-        VMSTATE_UINT32_ARRAY(reg_set, Exynos4210CombinerState,
-                IIC_REGSET_SIZE),
-        VMSTATE_UINT32_ARRAY(icipsr, Exynos4210CombinerState, 2),
-        VMSTATE_UINT32(external, Exynos4210CombinerState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-/*
- * Get Combiner input GPIO into irqs structure
- */
-void exynos4210_combiner_get_gpioin(Exynos4210Irq *irqs, DeviceState *dev,
-        int ext)
-{
-    int n;
-    int bit;
-    int max;
-    qemu_irq *irq;
-
-    max = ext ? EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ :
-        EXYNOS4210_MAX_INT_COMBINER_IN_IRQ;
-    irq = ext ? irqs->ext_combiner_irq : irqs->int_combiner_irq;
-
-    /*
-     * Some IRQs of Int/External Combiner are going to two Combiners groups,
-     * so let split them.
-     */
-    for (n = 0; n < max; n++) {
-
-        bit = EXYNOS4210_COMBINER_GET_BIT_NUM(n);
-
-        switch (n) {
-        /* MDNIE_LCD1 INTG1 */
-        case EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 0) ...
-             EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 3):
-            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
-                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(0, bit + 4)]);
-            continue;
-
-        /* TMU INTG3 */
-        case EXYNOS4210_COMBINER_GET_IRQ_NUM(3, 4):
-            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
-                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(2, bit)]);
-            continue;
-
-        /* LCD1 INTG12 */
-        case EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 0) ...
-             EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 3):
-            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
-                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(11, bit + 4)]);
-            continue;
-
-        /* Multi-Core Timer INTG12 */
-        case EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 4) ...
-             EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 8):
-               irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
-                       irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
-            continue;
-
-        /* Multi-Core Timer INTG35 */
-        case EXYNOS4210_COMBINER_GET_IRQ_NUM(35, 4) ...
-             EXYNOS4210_COMBINER_GET_IRQ_NUM(35, 8):
-            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
-                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
-            continue;
-
-        /* Multi-Core Timer INTG51 */
-        case EXYNOS4210_COMBINER_GET_IRQ_NUM(51, 4) ...
-             EXYNOS4210_COMBINER_GET_IRQ_NUM(51, 8):
-            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
-                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
-            continue;
-
-        /* Multi-Core Timer INTG53 */
-        case EXYNOS4210_COMBINER_GET_IRQ_NUM(53, 4) ...
-             EXYNOS4210_COMBINER_GET_IRQ_NUM(53, 8):
-            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
-                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
-            continue;
-        }
-
-        irq[n] = qdev_get_gpio_in(dev, n);
-    }
-}
-
-static uint64_t
-exynos4210_combiner_read(void *opaque, hwaddr offset, unsigned size)
-{
-    struct Exynos4210CombinerState *s =
-            (struct Exynos4210CombinerState *)opaque;
-    uint32_t req_quad_base_n;    /* Base of registers quad. Multiply it by 4 and
-                                   get a start of corresponding group quad */
-    uint32_t grp_quad_base_n;    /* Base of group quad */
-    uint32_t reg_n;              /* Register number inside the quad */
-    uint32_t val;
-
-    req_quad_base_n = offset >> 4;
-    grp_quad_base_n = req_quad_base_n << 2;
-    reg_n = (offset - (req_quad_base_n << 4)) >> 2;
-
-    if (req_quad_base_n >= IIC_NGRP) {
-        /* Read of ICIPSR register */
-        return s->icipsr[reg_n];
-    }
-
-    val = 0;
-
-    switch (reg_n) {
-    /* IISTR */
-    case 2:
-        val |= s->group[grp_quad_base_n].src_pending;
-        val |= s->group[grp_quad_base_n + 1].src_pending << 8;
-        val |= s->group[grp_quad_base_n + 2].src_pending << 16;
-        val |= s->group[grp_quad_base_n + 3].src_pending << 24;
-        break;
-    /* IIMSR */
-    case 3:
-        val |= s->group[grp_quad_base_n].src_mask &
-        s->group[grp_quad_base_n].src_pending;
-        val |= (s->group[grp_quad_base_n + 1].src_mask &
-                s->group[grp_quad_base_n + 1].src_pending) << 8;
-        val |= (s->group[grp_quad_base_n + 2].src_mask &
-                s->group[grp_quad_base_n + 2].src_pending) << 16;
-        val |= (s->group[grp_quad_base_n + 3].src_mask &
-                s->group[grp_quad_base_n + 3].src_pending) << 24;
-        break;
-    default:
-        if (offset >> 2 >= IIC_REGSET_SIZE) {
-            hw_error("exynos4210.combiner: overflow of reg_set by 0x"
-                    TARGET_FMT_plx "offset\n", offset);
-        }
-        val = s->reg_set[offset >> 2];
-        return 0;
-    }
-    return val;
-}
-
-static void exynos4210_combiner_update(void *opaque, uint8_t group_n)
-{
-    struct Exynos4210CombinerState *s =
-            (struct Exynos4210CombinerState *)opaque;
-
-    /* Send interrupt if needed */
-    if (s->group[group_n].src_mask & s->group[group_n].src_pending) {
-#ifdef DEBUG_COMBINER
-        if (group_n != 26) {
-            /* skip uart */
-            DPRINTF("%s raise IRQ[%d]\n", s->external ? "EXT" : "INT", group_n);
-        }
-#endif
-
-        /* Set Combiner interrupt pending status after masking */
-        if (group_n >= 32) {
-            s->icipsr[1] |= 1 << (group_n - 32);
-        } else {
-            s->icipsr[0] |= 1 << group_n;
-        }
-
-        qemu_irq_raise(s->output_irq[group_n]);
-    } else {
-#ifdef DEBUG_COMBINER
-        if (group_n != 26) {
-            /* skip uart */
-            DPRINTF("%s lower IRQ[%d]\n", s->external ? "EXT" : "INT", group_n);
-        }
-#endif
-
-        /* Set Combiner interrupt pending status after masking */
-        if (group_n >= 32) {
-            s->icipsr[1] &= ~(1 << (group_n - 32));
-        } else {
-            s->icipsr[0] &= ~(1 << group_n);
-        }
-
-        qemu_irq_lower(s->output_irq[group_n]);
-    }
-}
-
-static void exynos4210_combiner_write(void *opaque, hwaddr offset,
-        uint64_t val, unsigned size)
-{
-    struct Exynos4210CombinerState *s =
-            (struct Exynos4210CombinerState *)opaque;
-    uint32_t req_quad_base_n;    /* Base of registers quad. Multiply it by 4 and
-                                   get a start of corresponding group quad */
-    uint32_t grp_quad_base_n;    /* Base of group quad */
-    uint32_t reg_n;              /* Register number inside the quad */
-
-    req_quad_base_n = offset >> 4;
-    grp_quad_base_n = req_quad_base_n << 2;
-    reg_n = (offset - (req_quad_base_n << 4)) >> 2;
-
-    if (req_quad_base_n >= IIC_NGRP) {
-        hw_error("exynos4210.combiner: unallowed write access at offset 0x"
-                TARGET_FMT_plx "\n", offset);
-        return;
-    }
-
-    if (reg_n > 1) {
-        hw_error("exynos4210.combiner: unallowed write access at offset 0x"
-                TARGET_FMT_plx "\n", offset);
-        return;
-    }
-
-    if (offset >> 2 >= IIC_REGSET_SIZE) {
-        hw_error("exynos4210.combiner: overflow of reg_set by 0x"
-                TARGET_FMT_plx "offset\n", offset);
-    }
-    s->reg_set[offset >> 2] = val;
-
-    switch (reg_n) {
-    /* IIESR */
-    case 0:
-        /* FIXME: what if irq is pending, allowed by mask, and we allow it
-         * again. Interrupt will rise again! */
-
-        DPRINTF("%s enable IRQ for groups %d, %d, %d, %d\n",
-                s->external ? "EXT" : "INT",
-                grp_quad_base_n,
-                grp_quad_base_n + 1,
-                grp_quad_base_n + 2,
-                grp_quad_base_n + 3);
-
-        /* Enable interrupt sources */
-        s->group[grp_quad_base_n].src_mask |= val & 0xFF;
-        s->group[grp_quad_base_n + 1].src_mask |= (val & 0xFF00) >> 8;
-        s->group[grp_quad_base_n + 2].src_mask |= (val & 0xFF0000) >> 16;
-        s->group[grp_quad_base_n + 3].src_mask |= (val & 0xFF000000) >> 24;
-
-        exynos4210_combiner_update(s, grp_quad_base_n);
-        exynos4210_combiner_update(s, grp_quad_base_n + 1);
-        exynos4210_combiner_update(s, grp_quad_base_n + 2);
-        exynos4210_combiner_update(s, grp_quad_base_n + 3);
-        break;
-        /* IIECR */
-    case 1:
-        DPRINTF("%s disable IRQ for groups %d, %d, %d, %d\n",
-                s->external ? "EXT" : "INT",
-                grp_quad_base_n,
-                grp_quad_base_n + 1,
-                grp_quad_base_n + 2,
-                grp_quad_base_n + 3);
-
-        /* Disable interrupt sources */
-        s->group[grp_quad_base_n].src_mask &= ~(val & 0xFF);
-        s->group[grp_quad_base_n + 1].src_mask &= ~((val & 0xFF00) >> 8);
-        s->group[grp_quad_base_n + 2].src_mask &= ~((val & 0xFF0000) >> 16);
-        s->group[grp_quad_base_n + 3].src_mask &= ~((val & 0xFF000000) >> 24);
-
-        exynos4210_combiner_update(s, grp_quad_base_n);
-        exynos4210_combiner_update(s, grp_quad_base_n + 1);
-        exynos4210_combiner_update(s, grp_quad_base_n + 2);
-        exynos4210_combiner_update(s, grp_quad_base_n + 3);
-        break;
-    default:
-        hw_error("exynos4210.combiner: unallowed write access at offset 0x"
-                TARGET_FMT_plx "\n", offset);
-        break;
-    }
-}
-
-/* Get combiner group and bit from irq number */
-static uint8_t get_combiner_group_and_bit(int irq, uint8_t *bit)
-{
-    *bit = irq - ((irq >> 3) << 3);
-    return irq >> 3;
-}
-
-/* Process a change in an external IRQ input.  */
-static void exynos4210_combiner_handler(void *opaque, int irq, int level)
-{
-    struct Exynos4210CombinerState *s =
-            (struct Exynos4210CombinerState *)opaque;
-    uint8_t bit_n, group_n;
-
-    group_n = get_combiner_group_and_bit(irq, &bit_n);
-
-    if (s->external && group_n >= EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ) {
-        DPRINTF("%s unallowed IRQ group 0x%x\n", s->external ? "EXT" : "INT"
-                , group_n);
-        return;
-    }
-
-    if (level) {
-        s->group[group_n].src_pending |= 1 << bit_n;
-    } else {
-        s->group[group_n].src_pending &= ~(1 << bit_n);
-    }
-
-    exynos4210_combiner_update(s, group_n);
-}
-
-static void exynos4210_combiner_reset(DeviceState *d)
-{
-    struct Exynos4210CombinerState *s = (struct Exynos4210CombinerState *)d;
-
-    memset(&s->group, 0, sizeof(s->group));
-    memset(&s->reg_set, 0, sizeof(s->reg_set));
-
-    s->reg_set[0xC0 >> 2] = 0x01010101;
-    s->reg_set[0xC4 >> 2] = 0x01010101;
-    s->reg_set[0xD0 >> 2] = 0x01010101;
-    s->reg_set[0xD4 >> 2] = 0x01010101;
-}
-
-static const MemoryRegionOps exynos4210_combiner_ops = {
-    .read = exynos4210_combiner_read,
-    .write = exynos4210_combiner_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/*
- * Internal Combiner initialization.
- */
-static int exynos4210_combiner_init(SysBusDevice *dev)
-{
-    unsigned int i;
-    struct Exynos4210CombinerState *s =
-            FROM_SYSBUS(struct Exynos4210CombinerState, dev);
-
-    /* Allocate general purpose input signals and connect a handler to each of
-     * them */
-    qdev_init_gpio_in(&s->busdev.qdev, exynos4210_combiner_handler, IIC_NIRQ);
-
-    /* Connect SysBusDev irqs to device specific irqs */
-    for (i = 0; i < IIC_NIRQ; i++) {
-        sysbus_init_irq(dev, &s->output_irq[i]);
-    }
-
-    memory_region_init_io(&s->iomem, &exynos4210_combiner_ops, s,
-            "exynos4210-combiner", IIC_REGION_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static Property exynos4210_combiner_properties[] = {
-    DEFINE_PROP_UINT32("external", Exynos4210CombinerState, external, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void exynos4210_combiner_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = exynos4210_combiner_init;
-    dc->reset = exynos4210_combiner_reset;
-    dc->props = exynos4210_combiner_properties;
-    dc->vmsd = &vmstate_exynos4210_combiner;
-}
-
-static const TypeInfo exynos4210_combiner_info = {
-    .name          = "exynos4210.combiner",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(Exynos4210CombinerState),
-    .class_init    = exynos4210_combiner_class_init,
-};
-
-static void exynos4210_combiner_register_types(void)
-{
-    type_register_static(&exynos4210_combiner_info);
-}
-
-type_init(exynos4210_combiner_register_types)
diff --git a/hw/exynos4210_gic.c b/hw/exynos4210_gic.c
deleted file mode 100644 (file)
index bad6dde..0000000
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * Samsung exynos4210 GIC implementation. Based on hw/arm_gic.c
- *
- * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
- * All rights reserved.
- *
- * Evgeny Voevodin <e.voevodin@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "hw/sysbus.h"
-#include "qemu-common.h"
-#include "hw/irq.h"
-#include "hw/arm/exynos4210.h"
-
-enum ExtGicId {
-    EXT_GIC_ID_MDMA_LCD0 = 66,
-    EXT_GIC_ID_PDMA0,
-    EXT_GIC_ID_PDMA1,
-    EXT_GIC_ID_TIMER0,
-    EXT_GIC_ID_TIMER1,
-    EXT_GIC_ID_TIMER2,
-    EXT_GIC_ID_TIMER3,
-    EXT_GIC_ID_TIMER4,
-    EXT_GIC_ID_MCT_L0,
-    EXT_GIC_ID_WDT,
-    EXT_GIC_ID_RTC_ALARM,
-    EXT_GIC_ID_RTC_TIC,
-    EXT_GIC_ID_GPIO_XB,
-    EXT_GIC_ID_GPIO_XA,
-    EXT_GIC_ID_MCT_L1,
-    EXT_GIC_ID_IEM_APC,
-    EXT_GIC_ID_IEM_IEC,
-    EXT_GIC_ID_NFC,
-    EXT_GIC_ID_UART0,
-    EXT_GIC_ID_UART1,
-    EXT_GIC_ID_UART2,
-    EXT_GIC_ID_UART3,
-    EXT_GIC_ID_UART4,
-    EXT_GIC_ID_MCT_G0,
-    EXT_GIC_ID_I2C0,
-    EXT_GIC_ID_I2C1,
-    EXT_GIC_ID_I2C2,
-    EXT_GIC_ID_I2C3,
-    EXT_GIC_ID_I2C4,
-    EXT_GIC_ID_I2C5,
-    EXT_GIC_ID_I2C6,
-    EXT_GIC_ID_I2C7,
-    EXT_GIC_ID_SPI0,
-    EXT_GIC_ID_SPI1,
-    EXT_GIC_ID_SPI2,
-    EXT_GIC_ID_MCT_G1,
-    EXT_GIC_ID_USB_HOST,
-    EXT_GIC_ID_USB_DEVICE,
-    EXT_GIC_ID_MODEMIF,
-    EXT_GIC_ID_HSMMC0,
-    EXT_GIC_ID_HSMMC1,
-    EXT_GIC_ID_HSMMC2,
-    EXT_GIC_ID_HSMMC3,
-    EXT_GIC_ID_SDMMC,
-    EXT_GIC_ID_MIPI_CSI_4LANE,
-    EXT_GIC_ID_MIPI_DSI_4LANE,
-    EXT_GIC_ID_MIPI_CSI_2LANE,
-    EXT_GIC_ID_MIPI_DSI_2LANE,
-    EXT_GIC_ID_ONENAND_AUDI,
-    EXT_GIC_ID_ROTATOR,
-    EXT_GIC_ID_FIMC0,
-    EXT_GIC_ID_FIMC1,
-    EXT_GIC_ID_FIMC2,
-    EXT_GIC_ID_FIMC3,
-    EXT_GIC_ID_JPEG,
-    EXT_GIC_ID_2D,
-    EXT_GIC_ID_PCIe,
-    EXT_GIC_ID_MIXER,
-    EXT_GIC_ID_HDMI,
-    EXT_GIC_ID_HDMI_I2C,
-    EXT_GIC_ID_MFC,
-    EXT_GIC_ID_TVENC,
-};
-
-enum ExtInt {
-    EXT_GIC_ID_EXTINT0 = 48,
-    EXT_GIC_ID_EXTINT1,
-    EXT_GIC_ID_EXTINT2,
-    EXT_GIC_ID_EXTINT3,
-    EXT_GIC_ID_EXTINT4,
-    EXT_GIC_ID_EXTINT5,
-    EXT_GIC_ID_EXTINT6,
-    EXT_GIC_ID_EXTINT7,
-    EXT_GIC_ID_EXTINT8,
-    EXT_GIC_ID_EXTINT9,
-    EXT_GIC_ID_EXTINT10,
-    EXT_GIC_ID_EXTINT11,
-    EXT_GIC_ID_EXTINT12,
-    EXT_GIC_ID_EXTINT13,
-    EXT_GIC_ID_EXTINT14,
-    EXT_GIC_ID_EXTINT15
-};
-
-/*
- * External GIC sources which are not from External Interrupt Combiner or
- * External Interrupts are starting from EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ,
- * which is INTG16 in Internal Interrupt Combiner.
- */
-
-static uint32_t
-combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = {
-    /* int combiner groups 16-19 */
-    { }, { }, { }, { },
-    /* int combiner group 20 */
-    { 0, EXT_GIC_ID_MDMA_LCD0 },
-    /* int combiner group 21 */
-    { EXT_GIC_ID_PDMA0, EXT_GIC_ID_PDMA1 },
-    /* int combiner group 22 */
-    { EXT_GIC_ID_TIMER0, EXT_GIC_ID_TIMER1, EXT_GIC_ID_TIMER2,
-            EXT_GIC_ID_TIMER3, EXT_GIC_ID_TIMER4 },
-    /* int combiner group 23 */
-    { EXT_GIC_ID_RTC_ALARM, EXT_GIC_ID_RTC_TIC },
-    /* int combiner group 24 */
-    { EXT_GIC_ID_GPIO_XB, EXT_GIC_ID_GPIO_XA },
-    /* int combiner group 25 */
-    { EXT_GIC_ID_IEM_APC, EXT_GIC_ID_IEM_IEC },
-    /* int combiner group 26 */
-    { EXT_GIC_ID_UART0, EXT_GIC_ID_UART1, EXT_GIC_ID_UART2, EXT_GIC_ID_UART3,
-            EXT_GIC_ID_UART4 },
-    /* int combiner group 27 */
-    { EXT_GIC_ID_I2C0, EXT_GIC_ID_I2C1, EXT_GIC_ID_I2C2, EXT_GIC_ID_I2C3,
-            EXT_GIC_ID_I2C4, EXT_GIC_ID_I2C5, EXT_GIC_ID_I2C6,
-            EXT_GIC_ID_I2C7 },
-    /* int combiner group 28 */
-    { EXT_GIC_ID_SPI0, EXT_GIC_ID_SPI1, EXT_GIC_ID_SPI2 , EXT_GIC_ID_USB_HOST},
-    /* int combiner group 29 */
-    { EXT_GIC_ID_HSMMC0, EXT_GIC_ID_HSMMC1, EXT_GIC_ID_HSMMC2,
-     EXT_GIC_ID_HSMMC3, EXT_GIC_ID_SDMMC },
-    /* int combiner group 30 */
-    { EXT_GIC_ID_MIPI_CSI_4LANE, EXT_GIC_ID_MIPI_CSI_2LANE },
-    /* int combiner group 31 */
-    { EXT_GIC_ID_MIPI_DSI_4LANE, EXT_GIC_ID_MIPI_DSI_2LANE },
-    /* int combiner group 32 */
-    { EXT_GIC_ID_FIMC0, EXT_GIC_ID_FIMC1 },
-    /* int combiner group 33 */
-    { EXT_GIC_ID_FIMC2, EXT_GIC_ID_FIMC3 },
-    /* int combiner group 34 */
-    { EXT_GIC_ID_ONENAND_AUDI, EXT_GIC_ID_NFC },
-    /* int combiner group 35 */
-    { 0, 0, 0, EXT_GIC_ID_MCT_L1, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 },
-    /* int combiner group 36 */
-    { EXT_GIC_ID_MIXER },
-    /* int combiner group 37 */
-    { EXT_GIC_ID_EXTINT4, EXT_GIC_ID_EXTINT5, EXT_GIC_ID_EXTINT6,
-     EXT_GIC_ID_EXTINT7 },
-    /* groups 38-50 */
-    { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { },
-    /* int combiner group 51 */
-    { EXT_GIC_ID_MCT_L0, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 },
-    /* group 52 */
-    { },
-    /* int combiner group 53 */
-    { EXT_GIC_ID_WDT, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 },
-    /* groups 54-63 */
-    { }, { }, { }, { }, { }, { }, { }, { }, { }, { }
-};
-
-#define EXYNOS4210_GIC_NIRQ 160
-
-#define EXYNOS4210_EXT_GIC_CPU_REGION_SIZE     0x10000
-#define EXYNOS4210_EXT_GIC_DIST_REGION_SIZE    0x10000
-
-#define EXYNOS4210_EXT_GIC_PER_CPU_OFFSET      0x8000
-#define EXYNOS4210_EXT_GIC_CPU_GET_OFFSET(n) \
-    ((n) * EXYNOS4210_EXT_GIC_PER_CPU_OFFSET)
-#define EXYNOS4210_EXT_GIC_DIST_GET_OFFSET(n) \
-    ((n) * EXYNOS4210_EXT_GIC_PER_CPU_OFFSET)
-
-#define EXYNOS4210_GIC_CPU_REGION_SIZE  0x100
-#define EXYNOS4210_GIC_DIST_REGION_SIZE 0x1000
-
-static void exynos4210_irq_handler(void *opaque, int irq, int level)
-{
-    Exynos4210Irq *s = (Exynos4210Irq *)opaque;
-
-    /* Bypass */
-    qemu_set_irq(s->board_irqs[irq], level);
-}
-
-/*
- * Initialize exynos4210 IRQ subsystem stub.
- */
-qemu_irq *exynos4210_init_irq(Exynos4210Irq *s)
-{
-    return qemu_allocate_irqs(exynos4210_irq_handler, s,
-            EXYNOS4210_MAX_INT_COMBINER_IN_IRQ);
-}
-
-/*
- * Initialize board IRQs.
- * These IRQs contain splitted Int/External Combiner and External Gic IRQs.
- */
-void exynos4210_init_board_irqs(Exynos4210Irq *s)
-{
-    uint32_t grp, bit, irq_id, n;
-
-    for (n = 0; n < EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ; n++) {
-        s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
-                s->ext_combiner_irq[n]);
-
-        irq_id = 0;
-        if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 4) ||
-                n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 4)) {
-            /* MCT_G0 is passed to External GIC */
-            irq_id = EXT_GIC_ID_MCT_G0;
-        }
-        if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 5) ||
-                n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 5)) {
-            /* MCT_G1 is passed to External and GIC */
-            irq_id = EXT_GIC_ID_MCT_G1;
-        }
-        if (irq_id) {
-            s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
-                    s->ext_gic_irq[irq_id-32]);
-        }
-
-    }
-    for (; n < EXYNOS4210_MAX_INT_COMBINER_IN_IRQ; n++) {
-        /* these IDs are passed to Internal Combiner and External GIC */
-        grp = EXYNOS4210_COMBINER_GET_GRP_NUM(n);
-        bit = EXYNOS4210_COMBINER_GET_BIT_NUM(n);
-        irq_id = combiner_grp_to_gic_id[grp -
-                     EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][bit];
-
-        if (irq_id) {
-            s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
-                    s->ext_gic_irq[irq_id-32]);
-        }
-    }
-}
-
-/*
- * Get IRQ number from exynos4210 IRQ subsystem stub.
- * To identify IRQ source use internal combiner group and bit number
- *  grp - group number
- *  bit - bit number inside group
- */
-uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit)
-{
-    return EXYNOS4210_COMBINER_GET_IRQ_NUM(grp, bit);
-}
-
-/********* GIC part *********/
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion cpu_container;
-    MemoryRegion dist_container;
-    MemoryRegion cpu_alias[EXYNOS4210_NCPUS];
-    MemoryRegion dist_alias[EXYNOS4210_NCPUS];
-    uint32_t num_cpu;
-    DeviceState *gic;
-} Exynos4210GicState;
-
-static void exynos4210_gic_set_irq(void *opaque, int irq, int level)
-{
-    Exynos4210GicState *s = (Exynos4210GicState *)opaque;
-    qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
-}
-
-static int exynos4210_gic_init(SysBusDevice *dev)
-{
-    Exynos4210GicState *s = FROM_SYSBUS(Exynos4210GicState, dev);
-    uint32_t i;
-    const char cpu_prefix[] = "exynos4210-gic-alias_cpu";
-    const char dist_prefix[] = "exynos4210-gic-alias_dist";
-    char cpu_alias_name[sizeof(cpu_prefix) + 3];
-    char dist_alias_name[sizeof(cpu_prefix) + 3];
-    SysBusDevice *busdev;
-
-    s->gic = qdev_create(NULL, "arm_gic");
-    qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
-    qdev_prop_set_uint32(s->gic, "num-irq", EXYNOS4210_GIC_NIRQ);
-    qdev_init_nofail(s->gic);
-    busdev = SYS_BUS_DEVICE(s->gic);
-
-    /* Pass through outbound IRQ lines from the GIC */
-    sysbus_pass_irq(dev, busdev);
-
-    /* Pass through inbound GPIO lines to the GIC */
-    qdev_init_gpio_in(&s->busdev.qdev, exynos4210_gic_set_irq,
-                      EXYNOS4210_GIC_NIRQ - 32);
-
-    memory_region_init(&s->cpu_container, "exynos4210-cpu-container",
-            EXYNOS4210_EXT_GIC_CPU_REGION_SIZE);
-    memory_region_init(&s->dist_container, "exynos4210-dist-container",
-            EXYNOS4210_EXT_GIC_DIST_REGION_SIZE);
-
-    for (i = 0; i < s->num_cpu; i++) {
-        /* Map CPU interface per SMP Core */
-        sprintf(cpu_alias_name, "%s%x", cpu_prefix, i);
-        memory_region_init_alias(&s->cpu_alias[i],
-                                 cpu_alias_name,
-                                 sysbus_mmio_get_region(busdev, 1),
-                                 0,
-                                 EXYNOS4210_GIC_CPU_REGION_SIZE);
-        memory_region_add_subregion(&s->cpu_container,
-                EXYNOS4210_EXT_GIC_CPU_GET_OFFSET(i), &s->cpu_alias[i]);
-
-        /* Map Distributor per SMP Core */
-        sprintf(dist_alias_name, "%s%x", dist_prefix, i);
-        memory_region_init_alias(&s->dist_alias[i],
-                                 dist_alias_name,
-                                 sysbus_mmio_get_region(busdev, 0),
-                                 0,
-                                 EXYNOS4210_GIC_DIST_REGION_SIZE);
-        memory_region_add_subregion(&s->dist_container,
-                EXYNOS4210_EXT_GIC_DIST_GET_OFFSET(i), &s->dist_alias[i]);
-    }
-
-    sysbus_init_mmio(dev, &s->cpu_container);
-    sysbus_init_mmio(dev, &s->dist_container);
-
-    return 0;
-}
-
-static Property exynos4210_gic_properties[] = {
-    DEFINE_PROP_UINT32("num-cpu", Exynos4210GicState, num_cpu, 1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void exynos4210_gic_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = exynos4210_gic_init;
-    dc->props = exynos4210_gic_properties;
-}
-
-static const TypeInfo exynos4210_gic_info = {
-    .name          = "exynos4210.gic",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(Exynos4210GicState),
-    .class_init    = exynos4210_gic_class_init,
-};
-
-static void exynos4210_gic_register_types(void)
-{
-    type_register_static(&exynos4210_gic_info);
-}
-
-type_init(exynos4210_gic_register_types)
-
-/* IRQ OR Gate struct.
- *
- * This device models an OR gate. There are n_in input qdev gpio lines and one
- * output sysbus IRQ line. The output IRQ level is formed as OR between all
- * gpio inputs.
- */
-typedef struct {
-    SysBusDevice busdev;
-
-    uint32_t n_in;      /* inputs amount */
-    uint32_t *level;    /* input levels */
-    qemu_irq out;       /* output IRQ */
-} Exynos4210IRQGateState;
-
-static Property exynos4210_irq_gate_properties[] = {
-    DEFINE_PROP_UINT32("n_in", Exynos4210IRQGateState, n_in, 1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription vmstate_exynos4210_irq_gate = {
-    .name = "exynos4210.irq_gate",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields = (VMStateField[]) {
-        VMSTATE_VBUFFER_UINT32(level, Exynos4210IRQGateState, 1, NULL, 0, n_in),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-/* Process a change in IRQ input. */
-static void exynos4210_irq_gate_handler(void *opaque, int irq, int level)
-{
-    Exynos4210IRQGateState *s = (Exynos4210IRQGateState *)opaque;
-    uint32_t i;
-
-    assert(irq < s->n_in);
-
-    s->level[irq] = level;
-
-    for (i = 0; i < s->n_in; i++) {
-        if (s->level[i] >= 1) {
-            qemu_irq_raise(s->out);
-            return;
-        }
-    }
-
-    qemu_irq_lower(s->out);
-}
-
-static void exynos4210_irq_gate_reset(DeviceState *d)
-{
-    Exynos4210IRQGateState *s =
-            DO_UPCAST(Exynos4210IRQGateState, busdev.qdev, d);
-
-    memset(s->level, 0, s->n_in * sizeof(*s->level));
-}
-
-/*
- * IRQ Gate initialization.
- */
-static int exynos4210_irq_gate_init(SysBusDevice *dev)
-{
-    Exynos4210IRQGateState *s = FROM_SYSBUS(Exynos4210IRQGateState, dev);
-
-    /* Allocate general purpose input signals and connect a handler to each of
-     * them */
-    qdev_init_gpio_in(&s->busdev.qdev, exynos4210_irq_gate_handler, s->n_in);
-
-    s->level = g_malloc0(s->n_in * sizeof(*s->level));
-
-    sysbus_init_irq(dev, &s->out);
-
-    return 0;
-}
-
-static void exynos4210_irq_gate_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = exynos4210_irq_gate_init;
-    dc->reset = exynos4210_irq_gate_reset;
-    dc->vmsd = &vmstate_exynos4210_irq_gate;
-    dc->props = exynos4210_irq_gate_properties;
-}
-
-static const TypeInfo exynos4210_irq_gate_info = {
-    .name          = "exynos4210.irq_gate",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(Exynos4210IRQGateState),
-    .class_init    = exynos4210_irq_gate_class_init,
-};
-
-static void exynos4210_irq_gate_register_types(void)
-{
-    type_register_static(&exynos4210_irq_gate_info);
-}
-
-type_init(exynos4210_irq_gate_register_types)
diff --git a/hw/grlib_irqmp.c b/hw/grlib_irqmp.c
deleted file mode 100644 (file)
index 68dfe6a..0000000
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * QEMU GRLIB IRQMP Emulator
- *
- * (Multiprocessor and extended interrupt not supported)
- *
- * Copyright (c) 2010-2011 AdaCore
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/sysbus.h"
-#include "cpu.h"
-
-#include "hw/sparc/grlib.h"
-
-#include "trace.h"
-
-#define IRQMP_MAX_CPU 16
-#define IRQMP_REG_SIZE 256      /* Size of memory mapped registers */
-
-/* Memory mapped register offsets */
-#define LEVEL_OFFSET     0x00
-#define PENDING_OFFSET   0x04
-#define FORCE0_OFFSET    0x08
-#define CLEAR_OFFSET     0x0C
-#define MP_STATUS_OFFSET 0x10
-#define BROADCAST_OFFSET 0x14
-#define MASK_OFFSET      0x40
-#define FORCE_OFFSET     0x80
-#define EXTENDED_OFFSET  0xC0
-
-typedef struct IRQMPState IRQMPState;
-
-typedef struct IRQMP {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-
-    void *set_pil_in;
-    void *set_pil_in_opaque;
-
-    IRQMPState *state;
-} IRQMP;
-
-struct IRQMPState {
-    uint32_t level;
-    uint32_t pending;
-    uint32_t clear;
-    uint32_t broadcast;
-
-    uint32_t mask[IRQMP_MAX_CPU];
-    uint32_t force[IRQMP_MAX_CPU];
-    uint32_t extended[IRQMP_MAX_CPU];
-
-    IRQMP    *parent;
-};
-
-static void grlib_irqmp_check_irqs(IRQMPState *state)
-{
-    uint32_t      pend   = 0;
-    uint32_t      level0 = 0;
-    uint32_t      level1 = 0;
-    set_pil_in_fn set_pil_in;
-
-    assert(state != NULL);
-    assert(state->parent != NULL);
-
-    /* IRQ for CPU 0 (no SMP support) */
-    pend = (state->pending | state->force[0])
-        & state->mask[0];
-
-    level0 = pend & ~state->level;
-    level1 = pend &  state->level;
-
-    trace_grlib_irqmp_check_irqs(state->pending, state->force[0],
-                                 state->mask[0], level1, level0);
-
-    set_pil_in = (set_pil_in_fn)state->parent->set_pil_in;
-
-    /* Trigger level1 interrupt first and level0 if there is no level1 */
-    if (level1 != 0) {
-        set_pil_in(state->parent->set_pil_in_opaque, level1);
-    } else {
-        set_pil_in(state->parent->set_pil_in_opaque, level0);
-    }
-}
-
-void grlib_irqmp_ack(DeviceState *dev, int intno)
-{
-    SysBusDevice *sdev;
-    IRQMP        *irqmp;
-    IRQMPState   *state;
-    uint32_t      mask;
-
-    assert(dev != NULL);
-
-    sdev = SYS_BUS_DEVICE(dev);
-    assert(sdev != NULL);
-
-    irqmp = FROM_SYSBUS(typeof(*irqmp), sdev);
-    assert(irqmp != NULL);
-
-    state = irqmp->state;
-    assert(state != NULL);
-
-    intno &= 15;
-    mask = 1 << intno;
-
-    trace_grlib_irqmp_ack(intno);
-
-    /* Clear registers */
-    state->pending  &= ~mask;
-    state->force[0] &= ~mask; /* Only CPU 0 (No SMP support) */
-
-    grlib_irqmp_check_irqs(state);
-}
-
-void grlib_irqmp_set_irq(void *opaque, int irq, int level)
-{
-    IRQMP      *irqmp;
-    IRQMPState *s;
-    int         i = 0;
-
-    assert(opaque != NULL);
-
-    irqmp = FROM_SYSBUS(typeof(*irqmp), SYS_BUS_DEVICE(opaque));
-    assert(irqmp != NULL);
-
-    s = irqmp->state;
-    assert(s         != NULL);
-    assert(s->parent != NULL);
-
-
-    if (level) {
-        trace_grlib_irqmp_set_irq(irq);
-
-        if (s->broadcast & 1 << irq) {
-            /* Broadcasted IRQ */
-            for (i = 0; i < IRQMP_MAX_CPU; i++) {
-                s->force[i] |= 1 << irq;
-            }
-        } else {
-            s->pending |= 1 << irq;
-        }
-        grlib_irqmp_check_irqs(s);
-
-    }
-}
-
-static uint64_t grlib_irqmp_read(void *opaque, hwaddr addr,
-                                 unsigned size)
-{
-    IRQMP      *irqmp = opaque;
-    IRQMPState *state;
-
-    assert(irqmp != NULL);
-    state = irqmp->state;
-    assert(state != NULL);
-
-    addr &= 0xff;
-
-    /* global registers */
-    switch (addr) {
-    case LEVEL_OFFSET:
-        return state->level;
-
-    case PENDING_OFFSET:
-        return state->pending;
-
-    case FORCE0_OFFSET:
-        /* This register is an "alias" for the force register of CPU 0 */
-        return state->force[0];
-
-    case CLEAR_OFFSET:
-    case MP_STATUS_OFFSET:
-        /* Always read as 0 */
-        return 0;
-
-    case BROADCAST_OFFSET:
-        return state->broadcast;
-
-    default:
-        break;
-    }
-
-    /* mask registers */
-    if (addr >= MASK_OFFSET && addr < FORCE_OFFSET) {
-        int cpu = (addr - MASK_OFFSET) / 4;
-        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
-
-        return state->mask[cpu];
-    }
-
-    /* force registers */
-    if (addr >= FORCE_OFFSET && addr < EXTENDED_OFFSET) {
-        int cpu = (addr - FORCE_OFFSET) / 4;
-        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
-
-        return state->force[cpu];
-    }
-
-    /* extended (not supported) */
-    if (addr >= EXTENDED_OFFSET && addr < IRQMP_REG_SIZE) {
-        int cpu = (addr - EXTENDED_OFFSET) / 4;
-        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
-
-        return state->extended[cpu];
-    }
-
-    trace_grlib_irqmp_readl_unknown(addr);
-    return 0;
-}
-
-static void grlib_irqmp_write(void *opaque, hwaddr addr,
-                              uint64_t value, unsigned size)
-{
-    IRQMP      *irqmp = opaque;
-    IRQMPState *state;
-
-    assert(irqmp != NULL);
-    state = irqmp->state;
-    assert(state != NULL);
-
-    addr &= 0xff;
-
-    /* global registers */
-    switch (addr) {
-    case LEVEL_OFFSET:
-        value &= 0xFFFF << 1; /* clean up the value */
-        state->level = value;
-        return;
-
-    case PENDING_OFFSET:
-        /* Read Only */
-        return;
-
-    case FORCE0_OFFSET:
-        /* This register is an "alias" for the force register of CPU 0 */
-
-        value &= 0xFFFE; /* clean up the value */
-        state->force[0] = value;
-        grlib_irqmp_check_irqs(irqmp->state);
-        return;
-
-    case CLEAR_OFFSET:
-        value &= ~1; /* clean up the value */
-        state->pending &= ~value;
-        return;
-
-    case MP_STATUS_OFFSET:
-        /* Read Only (no SMP support) */
-        return;
-
-    case BROADCAST_OFFSET:
-        value &= 0xFFFE; /* clean up the value */
-        state->broadcast = value;
-        return;
-
-    default:
-        break;
-    }
-
-    /* mask registers */
-    if (addr >= MASK_OFFSET && addr < FORCE_OFFSET) {
-        int cpu = (addr - MASK_OFFSET) / 4;
-        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
-
-        value &= ~1; /* clean up the value */
-        state->mask[cpu] = value;
-        grlib_irqmp_check_irqs(irqmp->state);
-        return;
-    }
-
-    /* force registers */
-    if (addr >= FORCE_OFFSET && addr < EXTENDED_OFFSET) {
-        int cpu = (addr - FORCE_OFFSET) / 4;
-        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
-
-        uint32_t force = value & 0xFFFE;
-        uint32_t clear = (value >> 16) & 0xFFFE;
-        uint32_t old   = state->force[cpu];
-
-        state->force[cpu] = (old | force) & ~clear;
-        grlib_irqmp_check_irqs(irqmp->state);
-        return;
-    }
-
-    /* extended (not supported) */
-    if (addr >= EXTENDED_OFFSET && addr < IRQMP_REG_SIZE) {
-        int cpu = (addr - EXTENDED_OFFSET) / 4;
-        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
-
-        value &= 0xF; /* clean up the value */
-        state->extended[cpu] = value;
-        return;
-    }
-
-    trace_grlib_irqmp_writel_unknown(addr, value);
-}
-
-static const MemoryRegionOps grlib_irqmp_ops = {
-    .read = grlib_irqmp_read,
-    .write = grlib_irqmp_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static void grlib_irqmp_reset(DeviceState *d)
-{
-    IRQMP *irqmp = container_of(d, IRQMP, busdev.qdev);
-    assert(irqmp        != NULL);
-    assert(irqmp->state != NULL);
-
-    memset(irqmp->state, 0, sizeof *irqmp->state);
-    irqmp->state->parent = irqmp;
-}
-
-static int grlib_irqmp_init(SysBusDevice *dev)
-{
-    IRQMP *irqmp = FROM_SYSBUS(typeof(*irqmp), dev);
-
-    assert(irqmp != NULL);
-
-    /* Check parameters */
-    if (irqmp->set_pil_in == NULL) {
-        return -1;
-    }
-
-    memory_region_init_io(&irqmp->iomem, &grlib_irqmp_ops, irqmp,
-                          "irqmp", IRQMP_REG_SIZE);
-
-    irqmp->state = g_malloc0(sizeof *irqmp->state);
-
-    sysbus_init_mmio(dev, &irqmp->iomem);
-
-    return 0;
-}
-
-static Property grlib_irqmp_properties[] = {
-    DEFINE_PROP_PTR("set_pil_in", IRQMP, set_pil_in),
-    DEFINE_PROP_PTR("set_pil_in_opaque", IRQMP, set_pil_in_opaque),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void grlib_irqmp_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = grlib_irqmp_init;
-    dc->reset = grlib_irqmp_reset;
-    dc->props = grlib_irqmp_properties;
-}
-
-static const TypeInfo grlib_irqmp_info = {
-    .name          = "grlib,irqmp",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(IRQMP),
-    .class_init    = grlib_irqmp_class_init,
-};
-
-static void grlib_irqmp_register_types(void)
-{
-    type_register_static(&grlib_irqmp_info);
-}
-
-type_init(grlib_irqmp_register_types)
index a531d3aec68145b91628ce009d50186ff25565da..533d337c17ff15d8dbff5696a35978c58cc1216d 100644 (file)
@@ -1,5 +1,4 @@
-obj-y += apic_common.o apic.o
-obj-y += sga.o ioapic_common.o ioapic.o
+obj-y += sga.o
 obj-y += vmport.o
 obj-y += debugexit.o
 obj-y += kvm/
diff --git a/hw/imx_avic.c b/hw/imx_avic.c
deleted file mode 100644 (file)
index 4e280b6..0000000
+++ /dev/null
@@ -1,408 +0,0 @@
-/*
- * i.MX31 Vectored Interrupt Controller
- *
- * Note this is NOT the PL192 provided by ARM, but
- * a custom implementation by Freescale.
- *
- * Copyright (c) 2008 OKL
- * Copyright (c) 2011 NICTA Pty Ltd
- * Originally written by Hans Jiang
- *
- * This code is licensed under the GPL version 2 or later.  See
- * the COPYING file in the top-level directory.
- *
- * TODO: implement vectors.
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "qemu/host-utils.h"
-
-#define DEBUG_INT 1
-#undef DEBUG_INT /* comment out for debugging */
-
-#ifdef DEBUG_INT
-#define DPRINTF(fmt, args...) \
-do { printf("imx_avic: " fmt , ##args); } while (0)
-#else
-#define DPRINTF(fmt, args...) do {} while (0)
-#endif
-
-/*
- * Define to 1 for messages about attempts to
- * access unimplemented registers or similar.
- */
-#define DEBUG_IMPLEMENTATION 1
-#if DEBUG_IMPLEMENTATION
-#  define IPRINTF(fmt, args...) \
-    do  { fprintf(stderr, "imx_avic: " fmt, ##args); } while (0)
-#else
-#  define IPRINTF(fmt, args...) do {} while (0)
-#endif
-
-#define IMX_AVIC_NUM_IRQS 64
-
-/* Interrupt Control Bits */
-#define ABFLAG (1<<25)
-#define ABFEN (1<<24)
-#define NIDIS (1<<22) /* Normal Interrupt disable */
-#define FIDIS (1<<21) /* Fast interrupt disable */
-#define NIAD  (1<<20) /* Normal Interrupt Arbiter Rise ARM level */
-#define FIAD  (1<<19) /* Fast Interrupt Arbiter Rise ARM level */
-#define NM    (1<<18) /* Normal interrupt mode */
-
-
-#define PRIO_PER_WORD (sizeof(uint32_t) * 8 / 4)
-#define PRIO_WORDS (IMX_AVIC_NUM_IRQS/PRIO_PER_WORD)
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint64_t pending;
-    uint64_t enabled;
-    uint64_t is_fiq;
-    uint32_t intcntl;
-    uint32_t intmask;
-    qemu_irq irq;
-    qemu_irq fiq;
-    uint32_t prio[PRIO_WORDS]; /* Priorities are 4-bits each */
-} IMXAVICState;
-
-static const VMStateDescription vmstate_imx_avic = {
-    .name = "imx-avic",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT64(pending, IMXAVICState),
-        VMSTATE_UINT64(enabled, IMXAVICState),
-        VMSTATE_UINT64(is_fiq, IMXAVICState),
-        VMSTATE_UINT32(intcntl, IMXAVICState),
-        VMSTATE_UINT32(intmask, IMXAVICState),
-        VMSTATE_UINT32_ARRAY(prio, IMXAVICState, PRIO_WORDS),
-        VMSTATE_END_OF_LIST()
-    },
-};
-
-
-
-static inline int imx_avic_prio(IMXAVICState *s, int irq)
-{
-    uint32_t word = irq / PRIO_PER_WORD;
-    uint32_t part = 4 * (irq % PRIO_PER_WORD);
-    return 0xf & (s->prio[word] >> part);
-}
-
-static inline void imx_avic_set_prio(IMXAVICState *s, int irq, int prio)
-{
-    uint32_t word = irq / PRIO_PER_WORD;
-    uint32_t part = 4 * (irq % PRIO_PER_WORD);
-    uint32_t mask = ~(0xf << part);
-    s->prio[word] &= mask;
-    s->prio[word] |= prio << part;
-}
-
-/* Update interrupts.  */
-static void imx_avic_update(IMXAVICState *s)
-{
-    int i;
-    uint64_t new = s->pending & s->enabled;
-    uint64_t flags;
-
-    flags = new & s->is_fiq;
-    qemu_set_irq(s->fiq, !!flags);
-
-    flags = new & ~s->is_fiq;
-    if (!flags || (s->intmask == 0x1f)) {
-        qemu_set_irq(s->irq, !!flags);
-        return;
-    }
-
-    /*
-     * Take interrupt if there's a pending interrupt with
-     * priority higher than the value of intmask
-     */
-    for (i = 0; i < IMX_AVIC_NUM_IRQS; i++) {
-        if (flags & (1UL << i)) {
-            if (imx_avic_prio(s, i) > s->intmask) {
-                qemu_set_irq(s->irq, 1);
-                return;
-            }
-        }
-    }
-    qemu_set_irq(s->irq, 0);
-}
-
-static void imx_avic_set_irq(void *opaque, int irq, int level)
-{
-    IMXAVICState *s = (IMXAVICState *)opaque;
-
-    if (level) {
-        DPRINTF("Raising IRQ %d, prio %d\n",
-                irq, imx_avic_prio(s, irq));
-        s->pending |= (1ULL << irq);
-    } else {
-        DPRINTF("Clearing IRQ %d, prio %d\n",
-                irq, imx_avic_prio(s, irq));
-        s->pending &= ~(1ULL << irq);
-    }
-
-    imx_avic_update(s);
-}
-
-
-static uint64_t imx_avic_read(void *opaque,
-                             hwaddr offset, unsigned size)
-{
-    IMXAVICState *s = (IMXAVICState *)opaque;
-
-
-    DPRINTF("read(offset = 0x%x)\n", offset >> 2);
-    switch (offset >> 2) {
-    case 0: /* INTCNTL */
-        return s->intcntl;
-
-    case 1: /* Normal Interrupt Mask Register, NIMASK */
-        return s->intmask;
-
-    case 2: /* Interrupt Enable Number Register, INTENNUM */
-    case 3: /* Interrupt Disable Number Register, INTDISNUM */
-        return 0;
-
-    case 4: /* Interrupt Enabled Number Register High */
-        return s->enabled >> 32;
-
-    case 5: /* Interrupt Enabled Number Register Low */
-        return s->enabled & 0xffffffffULL;
-
-    case 6: /* Interrupt Type Register High */
-        return s->is_fiq >> 32;
-
-    case 7: /* Interrupt Type Register Low */
-        return s->is_fiq & 0xffffffffULL;
-
-    case 8: /* Normal Interrupt Priority Register 7 */
-    case 9: /* Normal Interrupt Priority Register 6 */
-    case 10:/* Normal Interrupt Priority Register 5 */
-    case 11:/* Normal Interrupt Priority Register 4 */
-    case 12:/* Normal Interrupt Priority Register 3 */
-    case 13:/* Normal Interrupt Priority Register 2 */
-    case 14:/* Normal Interrupt Priority Register 1 */
-    case 15:/* Normal Interrupt Priority Register 0 */
-        return s->prio[15-(offset>>2)];
-
-    case 16: /* Normal interrupt vector and status register */
-    {
-        /*
-         * This returns the highest priority
-         * outstanding interrupt.  Where there is more than
-         * one pending IRQ with the same priority,
-         * take the highest numbered one.
-         */
-        uint64_t flags = s->pending & s->enabled & ~s->is_fiq;
-        int i;
-        int prio = -1;
-        int irq = -1;
-        for (i = 63; i >= 0; --i) {
-            if (flags & (1ULL<<i)) {
-                int irq_prio = imx_avic_prio(s, i);
-                if (irq_prio > prio) {
-                    irq = i;
-                    prio = irq_prio;
-                }
-            }
-        }
-        if (irq >= 0) {
-            imx_avic_set_irq(s, irq, 0);
-            return irq << 16 | prio;
-        }
-        return 0xffffffffULL;
-    }
-    case 17:/* Fast Interrupt vector and status register */
-    {
-        uint64_t flags = s->pending & s->enabled & s->is_fiq;
-        int i = ctz64(flags);
-        if (i < 64) {
-            imx_avic_set_irq(opaque, i, 0);
-            return i;
-        }
-        return 0xffffffffULL;
-    }
-    case 18:/* Interrupt source register high */
-        return s->pending >> 32;
-
-    case 19:/* Interrupt source register low */
-        return s->pending & 0xffffffffULL;
-
-    case 20:/* Interrupt Force Register high */
-    case 21:/* Interrupt Force Register low */
-        return 0;
-
-    case 22:/* Normal Interrupt Pending Register High */
-        return (s->pending & s->enabled & ~s->is_fiq) >> 32;
-
-    case 23:/* Normal Interrupt Pending Register Low */
-        return (s->pending & s->enabled & ~s->is_fiq) & 0xffffffffULL;
-
-    case 24: /* Fast Interrupt Pending Register High  */
-        return (s->pending & s->enabled & s->is_fiq) >> 32;
-
-    case 25: /* Fast Interrupt Pending Register Low  */
-        return (s->pending & s->enabled & s->is_fiq) & 0xffffffffULL;
-
-    case 0x40:            /* AVIC vector 0, use for WFI WAR */
-        return 0x4;
-
-    default:
-        IPRINTF("imx_avic_read: Bad offset 0x%x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void imx_avic_write(void *opaque, hwaddr offset,
-                          uint64_t val, unsigned size)
-{
-    IMXAVICState *s = (IMXAVICState *)opaque;
-
-    /* Vector Registers not yet supported */
-    if (offset >= 0x100 && offset <= 0x2fc) {
-        IPRINTF("imx_avic_write to vector register %d ignored\n",
-                (unsigned int)((offset - 0x100) >> 2));
-        return;
-    }
-
-    DPRINTF("imx_avic_write(0x%x) = %x\n",
-            (unsigned int)offset>>2, (unsigned int)val);
-    switch (offset >> 2) {
-    case 0: /* Interrupt Control Register, INTCNTL */
-        s->intcntl = val & (ABFEN | NIDIS | FIDIS | NIAD | FIAD | NM);
-        if (s->intcntl & ABFEN) {
-            s->intcntl &= ~(val & ABFLAG);
-        }
-        break;
-
-    case 1: /* Normal Interrupt Mask Register, NIMASK */
-        s->intmask = val & 0x1f;
-        break;
-
-    case 2: /* Interrupt Enable Number Register, INTENNUM */
-        DPRINTF("enable(%d)\n", (int)val);
-        val &= 0x3f;
-        s->enabled |= (1ULL << val);
-        break;
-
-    case 3: /* Interrupt Disable Number Register, INTDISNUM */
-        DPRINTF("disable(%d)\n", (int)val);
-        val &= 0x3f;
-        s->enabled &= ~(1ULL << val);
-        break;
-
-    case 4: /* Interrupt Enable Number Register High */
-        s->enabled = (s->enabled & 0xffffffffULL) | (val << 32);
-        break;
-
-    case 5: /* Interrupt Enable Number Register Low */
-        s->enabled = (s->enabled & 0xffffffff00000000ULL) | val;
-        break;
-
-    case 6: /* Interrupt Type Register High */
-        s->is_fiq = (s->is_fiq & 0xffffffffULL) | (val << 32);
-        break;
-
-    case 7: /* Interrupt Type Register Low */
-        s->is_fiq = (s->is_fiq & 0xffffffff00000000ULL) | val;
-        break;
-
-    case 8: /* Normal Interrupt Priority Register 7 */
-    case 9: /* Normal Interrupt Priority Register 6 */
-    case 10:/* Normal Interrupt Priority Register 5 */
-    case 11:/* Normal Interrupt Priority Register 4 */
-    case 12:/* Normal Interrupt Priority Register 3 */
-    case 13:/* Normal Interrupt Priority Register 2 */
-    case 14:/* Normal Interrupt Priority Register 1 */
-    case 15:/* Normal Interrupt Priority Register 0 */
-        s->prio[15-(offset>>2)] = val;
-        break;
-
-        /* Read-only registers, writes ignored */
-    case 16:/* Normal Interrupt Vector and Status register */
-    case 17:/* Fast Interrupt vector and status register */
-    case 18:/* Interrupt source register high */
-    case 19:/* Interrupt source register low */
-        return;
-
-    case 20:/* Interrupt Force Register high */
-        s->pending = (s->pending & 0xffffffffULL) | (val << 32);
-        break;
-
-    case 21:/* Interrupt Force Register low */
-        s->pending = (s->pending & 0xffffffff00000000ULL) | val;
-        break;
-
-    case 22:/* Normal Interrupt Pending Register High */
-    case 23:/* Normal Interrupt Pending Register Low */
-    case 24: /* Fast Interrupt Pending Register High  */
-    case 25: /* Fast Interrupt Pending Register Low  */
-        return;
-
-    default:
-        IPRINTF("imx_avic_write: Bad offset %x\n", (int)offset);
-    }
-    imx_avic_update(s);
-}
-
-static const MemoryRegionOps imx_avic_ops = {
-    .read = imx_avic_read,
-    .write = imx_avic_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void imx_avic_reset(DeviceState *dev)
-{
-    IMXAVICState *s = container_of(dev, IMXAVICState, busdev.qdev);
-    s->pending = 0;
-    s->enabled = 0;
-    s->is_fiq = 0;
-    s->intmask = 0x1f;
-    s->intcntl = 0;
-    memset(s->prio, 0, sizeof s->prio);
-}
-
-static int imx_avic_init(SysBusDevice *dev)
-{
-    IMXAVICState *s = FROM_SYSBUS(IMXAVICState, dev);;
-
-    memory_region_init_io(&s->iomem, &imx_avic_ops, s, "imx_avic", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    qdev_init_gpio_in(&dev->qdev, imx_avic_set_irq, IMX_AVIC_NUM_IRQS);
-    sysbus_init_irq(dev, &s->irq);
-    sysbus_init_irq(dev, &s->fiq);
-
-    return 0;
-}
-
-
-static void imx_avic_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-    k->init = imx_avic_init;
-    dc->vmsd = &vmstate_imx_avic;
-    dc->reset = imx_avic_reset;
-    dc->desc = "i.MX Advanced Vector Interrupt Controller";
-}
-
-static const TypeInfo imx_avic_info = {
-    .name = "imx_avic",
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(IMXAVICState),
-    .class_init = imx_avic_class_init,
-};
-
-static void imx_avic_register_types(void)
-{
-    type_register_static(&imx_avic_info);
-}
-
-type_init(imx_avic_register_types)
index 2813adb3e752ba1d37654e2243cd7251b1ccef58..718d97ae8a3e9ac81c1936e46006f4b174706005 100644 (file)
@@ -3,3 +3,21 @@ common-obj-$(CONFIG_I8259) += i8259_common.o i8259.o
 common-obj-$(CONFIG_PL190) += pl190.o
 common-obj-$(CONFIG_PUV3) += puv3_intc.o
 common-obj-$(CONFIG_XILINX) += xilinx_intc.o
+common-obj-$(CONFIG_ETRAXFS) += etraxfs_pic.o
+common-obj-$(CONFIG_IMX) += imx_avic.o
+common-obj-$(CONFIG_LM32) += lm32_pic.o
+common-obj-$(CONFIG_REALVIEW) += realview_gic.o
+common-obj-$(CONFIG_SLAVIO) += sbi.o slavio_intctl.o sun4c_intctl.o
+common-obj-$(CONFIG_IOAPIC) += ioapic_common.o
+common-obj-$(CONFIG_ARM_GIC) += arm_gic_common.o
+
+obj-$(CONFIG_APIC) += apic.o apic_common.o
+obj-$(CONFIG_ARM_GIC) += arm_gic.o
+obj-$(CONFIG_ARM_GIC_KVM) += arm_gic_kvm.o
+obj-$(CONFIG_STELLARIS) += armv7m_nvic.o
+obj-$(CONFIG_EXYNOS4) += exynos4210_gic.o exynos4210_combiner.o
+obj-$(CONFIG_GRLIB) += grlib_irqmp.o
+obj-$(CONFIG_IOAPIC) += ioapic.o
+obj-$(CONFIG_OMAP) += omap_intc.o
+obj-$(CONFIG_OPENPIC) += openpic.o
+obj-$(CONFIG_SH4) += sh_intc.o
diff --git a/hw/intc/apic.c b/hw/intc/apic.c
new file mode 100644 (file)
index 0000000..2d79a9e
--- /dev/null
@@ -0,0 +1,911 @@
+/*
+ *  APIC support
+ *
+ *  Copyright (c) 2004-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+#include "qemu/thread.h"
+#include "hw/i386/apic_internal.h"
+#include "hw/i386/apic.h"
+#include "hw/i386/ioapic.h"
+#include "hw/pci/msi.h"
+#include "qemu/host-utils.h"
+#include "trace.h"
+#include "hw/i386/pc.h"
+#include "hw/i386/apic-msidef.h"
+
+#define MAX_APIC_WORDS 8
+
+#define SYNC_FROM_VAPIC                 0x1
+#define SYNC_TO_VAPIC                   0x2
+#define SYNC_ISR_IRR_TO_VAPIC           0x4
+
+static APICCommonState *local_apics[MAX_APICS + 1];
+
+static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode);
+static void apic_update_irq(APICCommonState *s);
+static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
+                                      uint8_t dest, uint8_t dest_mode);
+
+/* Find first bit starting from msb */
+static int fls_bit(uint32_t value)
+{
+    return 31 - clz32(value);
+}
+
+/* Find first bit starting from lsb */
+static int ffs_bit(uint32_t value)
+{
+    return ctz32(value);
+}
+
+static inline void set_bit(uint32_t *tab, int index)
+{
+    int i, mask;
+    i = index >> 5;
+    mask = 1 << (index & 0x1f);
+    tab[i] |= mask;
+}
+
+static inline void reset_bit(uint32_t *tab, int index)
+{
+    int i, mask;
+    i = index >> 5;
+    mask = 1 << (index & 0x1f);
+    tab[i] &= ~mask;
+}
+
+static inline int get_bit(uint32_t *tab, int index)
+{
+    int i, mask;
+    i = index >> 5;
+    mask = 1 << (index & 0x1f);
+    return !!(tab[i] & mask);
+}
+
+/* return -1 if no bit is set */
+static int get_highest_priority_int(uint32_t *tab)
+{
+    int i;
+    for (i = 7; i >= 0; i--) {
+        if (tab[i] != 0) {
+            return i * 32 + fls_bit(tab[i]);
+        }
+    }
+    return -1;
+}
+
+static void apic_sync_vapic(APICCommonState *s, int sync_type)
+{
+    VAPICState vapic_state;
+    size_t length;
+    off_t start;
+    int vector;
+
+    if (!s->vapic_paddr) {
+        return;
+    }
+    if (sync_type & SYNC_FROM_VAPIC) {
+        cpu_physical_memory_rw(s->vapic_paddr, (void *)&vapic_state,
+                               sizeof(vapic_state), 0);
+        s->tpr = vapic_state.tpr;
+    }
+    if (sync_type & (SYNC_TO_VAPIC | SYNC_ISR_IRR_TO_VAPIC)) {
+        start = offsetof(VAPICState, isr);
+        length = offsetof(VAPICState, enabled) - offsetof(VAPICState, isr);
+
+        if (sync_type & SYNC_TO_VAPIC) {
+            assert(qemu_cpu_is_self(CPU(s->cpu)));
+
+            vapic_state.tpr = s->tpr;
+            vapic_state.enabled = 1;
+            start = 0;
+            length = sizeof(VAPICState);
+        }
+
+        vector = get_highest_priority_int(s->isr);
+        if (vector < 0) {
+            vector = 0;
+        }
+        vapic_state.isr = vector & 0xf0;
+
+        vapic_state.zero = 0;
+
+        vector = get_highest_priority_int(s->irr);
+        if (vector < 0) {
+            vector = 0;
+        }
+        vapic_state.irr = vector & 0xff;
+
+        cpu_physical_memory_write_rom(s->vapic_paddr + start,
+                                      ((void *)&vapic_state) + start, length);
+    }
+}
+
+static void apic_vapic_base_update(APICCommonState *s)
+{
+    apic_sync_vapic(s, SYNC_TO_VAPIC);
+}
+
+static void apic_local_deliver(APICCommonState *s, int vector)
+{
+    uint32_t lvt = s->lvt[vector];
+    int trigger_mode;
+
+    trace_apic_local_deliver(vector, (lvt >> 8) & 7);
+
+    if (lvt & APIC_LVT_MASKED)
+        return;
+
+    switch ((lvt >> 8) & 7) {
+    case APIC_DM_SMI:
+        cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SMI);
+        break;
+
+    case APIC_DM_NMI:
+        cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_NMI);
+        break;
+
+    case APIC_DM_EXTINT:
+        cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HARD);
+        break;
+
+    case APIC_DM_FIXED:
+        trigger_mode = APIC_TRIGGER_EDGE;
+        if ((vector == APIC_LVT_LINT0 || vector == APIC_LVT_LINT1) &&
+            (lvt & APIC_LVT_LEVEL_TRIGGER))
+            trigger_mode = APIC_TRIGGER_LEVEL;
+        apic_set_irq(s, lvt & 0xff, trigger_mode);
+    }
+}
+
+void apic_deliver_pic_intr(DeviceState *d, int level)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+
+    if (level) {
+        apic_local_deliver(s, APIC_LVT_LINT0);
+    } else {
+        uint32_t lvt = s->lvt[APIC_LVT_LINT0];
+
+        switch ((lvt >> 8) & 7) {
+        case APIC_DM_FIXED:
+            if (!(lvt & APIC_LVT_LEVEL_TRIGGER))
+                break;
+            reset_bit(s->irr, lvt & 0xff);
+            /* fall through */
+        case APIC_DM_EXTINT:
+            cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_HARD);
+            break;
+        }
+    }
+}
+
+static void apic_external_nmi(APICCommonState *s)
+{
+    apic_local_deliver(s, APIC_LVT_LINT1);
+}
+
+#define foreach_apic(apic, deliver_bitmask, code) \
+{\
+    int __i, __j, __mask;\
+    for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\
+        __mask = deliver_bitmask[__i];\
+        if (__mask) {\
+            for(__j = 0; __j < 32; __j++) {\
+                if (__mask & (1 << __j)) {\
+                    apic = local_apics[__i * 32 + __j];\
+                    if (apic) {\
+                        code;\
+                    }\
+                }\
+            }\
+        }\
+    }\
+}
+
+static void apic_bus_deliver(const uint32_t *deliver_bitmask,
+                             uint8_t delivery_mode, uint8_t vector_num,
+                             uint8_t trigger_mode)
+{
+    APICCommonState *apic_iter;
+
+    switch (delivery_mode) {
+        case APIC_DM_LOWPRI:
+            /* XXX: search for focus processor, arbitration */
+            {
+                int i, d;
+                d = -1;
+                for(i = 0; i < MAX_APIC_WORDS; i++) {
+                    if (deliver_bitmask[i]) {
+                        d = i * 32 + ffs_bit(deliver_bitmask[i]);
+                        break;
+                    }
+                }
+                if (d >= 0) {
+                    apic_iter = local_apics[d];
+                    if (apic_iter) {
+                        apic_set_irq(apic_iter, vector_num, trigger_mode);
+                    }
+                }
+            }
+            return;
+
+        case APIC_DM_FIXED:
+            break;
+
+        case APIC_DM_SMI:
+            foreach_apic(apic_iter, deliver_bitmask,
+                cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_SMI)
+            );
+            return;
+
+        case APIC_DM_NMI:
+            foreach_apic(apic_iter, deliver_bitmask,
+                cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_NMI)
+            );
+            return;
+
+        case APIC_DM_INIT:
+            /* normal INIT IPI sent to processors */
+            foreach_apic(apic_iter, deliver_bitmask,
+                         cpu_interrupt(CPU(apic_iter->cpu),
+                                       CPU_INTERRUPT_INIT)
+            );
+            return;
+
+        case APIC_DM_EXTINT:
+            /* handled in I/O APIC code */
+            break;
+
+        default:
+            return;
+    }
+
+    foreach_apic(apic_iter, deliver_bitmask,
+                 apic_set_irq(apic_iter, vector_num, trigger_mode) );
+}
+
+void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode,
+                      uint8_t vector_num, uint8_t trigger_mode)
+{
+    uint32_t deliver_bitmask[MAX_APIC_WORDS];
+
+    trace_apic_deliver_irq(dest, dest_mode, delivery_mode, vector_num,
+                           trigger_mode);
+
+    apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
+    apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
+}
+
+static void apic_set_base(APICCommonState *s, uint64_t val)
+{
+    s->apicbase = (val & 0xfffff000) |
+        (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
+    /* if disabled, cannot be enabled again */
+    if (!(val & MSR_IA32_APICBASE_ENABLE)) {
+        s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
+        cpu_clear_apic_feature(&s->cpu->env);
+        s->spurious_vec &= ~APIC_SV_ENABLE;
+    }
+}
+
+static void apic_set_tpr(APICCommonState *s, uint8_t val)
+{
+    /* Updates from cr8 are ignored while the VAPIC is active */
+    if (!s->vapic_paddr) {
+        s->tpr = val << 4;
+        apic_update_irq(s);
+    }
+}
+
+static uint8_t apic_get_tpr(APICCommonState *s)
+{
+    apic_sync_vapic(s, SYNC_FROM_VAPIC);
+    return s->tpr >> 4;
+}
+
+static int apic_get_ppr(APICCommonState *s)
+{
+    int tpr, isrv, ppr;
+
+    tpr = (s->tpr >> 4);
+    isrv = get_highest_priority_int(s->isr);
+    if (isrv < 0)
+        isrv = 0;
+    isrv >>= 4;
+    if (tpr >= isrv)
+        ppr = s->tpr;
+    else
+        ppr = isrv << 4;
+    return ppr;
+}
+
+static int apic_get_arb_pri(APICCommonState *s)
+{
+    /* XXX: arbitration */
+    return 0;
+}
+
+
+/*
+ * <0 - low prio interrupt,
+ * 0  - no interrupt,
+ * >0 - interrupt number
+ */
+static int apic_irq_pending(APICCommonState *s)
+{
+    int irrv, ppr;
+    irrv = get_highest_priority_int(s->irr);
+    if (irrv < 0) {
+        return 0;
+    }
+    ppr = apic_get_ppr(s);
+    if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) {
+        return -1;
+    }
+
+    return irrv;
+}
+
+/* signal the CPU if an irq is pending */
+static void apic_update_irq(APICCommonState *s)
+{
+    CPUState *cpu;
+
+    if (!(s->spurious_vec & APIC_SV_ENABLE)) {
+        return;
+    }
+    cpu = CPU(s->cpu);
+    if (!qemu_cpu_is_self(cpu)) {
+        cpu_interrupt(cpu, CPU_INTERRUPT_POLL);
+    } else if (apic_irq_pending(s) > 0) {
+        cpu_interrupt(cpu, CPU_INTERRUPT_HARD);
+    }
+}
+
+void apic_poll_irq(DeviceState *d)
+{
+    APICCommonState *s = APIC_COMMON(d);
+
+    apic_sync_vapic(s, SYNC_FROM_VAPIC);
+    apic_update_irq(s);
+}
+
+static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode)
+{
+    apic_report_irq_delivered(!get_bit(s->irr, vector_num));
+
+    set_bit(s->irr, vector_num);
+    if (trigger_mode)
+        set_bit(s->tmr, vector_num);
+    else
+        reset_bit(s->tmr, vector_num);
+    if (s->vapic_paddr) {
+        apic_sync_vapic(s, SYNC_ISR_IRR_TO_VAPIC);
+        /*
+         * The vcpu thread needs to see the new IRR before we pull its current
+         * TPR value. That way, if we miss a lowering of the TRP, the guest
+         * has the chance to notice the new IRR and poll for IRQs on its own.
+         */
+        smp_wmb();
+        apic_sync_vapic(s, SYNC_FROM_VAPIC);
+    }
+    apic_update_irq(s);
+}
+
+static void apic_eoi(APICCommonState *s)
+{
+    int isrv;
+    isrv = get_highest_priority_int(s->isr);
+    if (isrv < 0)
+        return;
+    reset_bit(s->isr, isrv);
+    if (!(s->spurious_vec & APIC_SV_DIRECTED_IO) && get_bit(s->tmr, isrv)) {
+        ioapic_eoi_broadcast(isrv);
+    }
+    apic_sync_vapic(s, SYNC_FROM_VAPIC | SYNC_TO_VAPIC);
+    apic_update_irq(s);
+}
+
+static int apic_find_dest(uint8_t dest)
+{
+    APICCommonState *apic = local_apics[dest];
+    int i;
+
+    if (apic && apic->id == dest)
+        return dest;  /* shortcut in case apic->id == apic->idx */
+
+    for (i = 0; i < MAX_APICS; i++) {
+        apic = local_apics[i];
+       if (apic && apic->id == dest)
+            return i;
+        if (!apic)
+            break;
+    }
+
+    return -1;
+}
+
+static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
+                                      uint8_t dest, uint8_t dest_mode)
+{
+    APICCommonState *apic_iter;
+    int i;
+
+    if (dest_mode == 0) {
+        if (dest == 0xff) {
+            memset(deliver_bitmask, 0xff, MAX_APIC_WORDS * sizeof(uint32_t));
+        } else {
+            int idx = apic_find_dest(dest);
+            memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
+            if (idx >= 0)
+                set_bit(deliver_bitmask, idx);
+        }
+    } else {
+        /* XXX: cluster mode */
+        memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
+        for(i = 0; i < MAX_APICS; i++) {
+            apic_iter = local_apics[i];
+            if (apic_iter) {
+                if (apic_iter->dest_mode == 0xf) {
+                    if (dest & apic_iter->log_dest)
+                        set_bit(deliver_bitmask, i);
+                } else if (apic_iter->dest_mode == 0x0) {
+                    if ((dest & 0xf0) == (apic_iter->log_dest & 0xf0) &&
+                        (dest & apic_iter->log_dest & 0x0f)) {
+                        set_bit(deliver_bitmask, i);
+                    }
+                }
+            } else {
+                break;
+            }
+        }
+    }
+}
+
+static void apic_startup(APICCommonState *s, int vector_num)
+{
+    s->sipi_vector = vector_num;
+    cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI);
+}
+
+void apic_sipi(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+
+    cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI);
+
+    if (!s->wait_for_sipi)
+        return;
+    cpu_x86_load_seg_cache_sipi(s->cpu, s->sipi_vector);
+    s->wait_for_sipi = 0;
+}
+
+static void apic_deliver(DeviceState *d, uint8_t dest, uint8_t dest_mode,
+                         uint8_t delivery_mode, uint8_t vector_num,
+                         uint8_t trigger_mode)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    uint32_t deliver_bitmask[MAX_APIC_WORDS];
+    int dest_shorthand = (s->icr[0] >> 18) & 3;
+    APICCommonState *apic_iter;
+
+    switch (dest_shorthand) {
+    case 0:
+        apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
+        break;
+    case 1:
+        memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask));
+        set_bit(deliver_bitmask, s->idx);
+        break;
+    case 2:
+        memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
+        break;
+    case 3:
+        memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
+        reset_bit(deliver_bitmask, s->idx);
+        break;
+    }
+
+    switch (delivery_mode) {
+        case APIC_DM_INIT:
+            {
+                int trig_mode = (s->icr[0] >> 15) & 1;
+                int level = (s->icr[0] >> 14) & 1;
+                if (level == 0 && trig_mode == 1) {
+                    foreach_apic(apic_iter, deliver_bitmask,
+                                 apic_iter->arb_id = apic_iter->id );
+                    return;
+                }
+            }
+            break;
+
+        case APIC_DM_SIPI:
+            foreach_apic(apic_iter, deliver_bitmask,
+                         apic_startup(apic_iter, vector_num) );
+            return;
+    }
+
+    apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
+}
+
+static bool apic_check_pic(APICCommonState *s)
+{
+    if (!apic_accept_pic_intr(&s->busdev.qdev) || !pic_get_output(isa_pic)) {
+        return false;
+    }
+    apic_deliver_pic_intr(&s->busdev.qdev, 1);
+    return true;
+}
+
+int apic_get_interrupt(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    int intno;
+
+    /* if the APIC is installed or enabled, we let the 8259 handle the
+       IRQs */
+    if (!s)
+        return -1;
+    if (!(s->spurious_vec & APIC_SV_ENABLE))
+        return -1;
+
+    apic_sync_vapic(s, SYNC_FROM_VAPIC);
+    intno = apic_irq_pending(s);
+
+    if (intno == 0) {
+        apic_sync_vapic(s, SYNC_TO_VAPIC);
+        return -1;
+    } else if (intno < 0) {
+        apic_sync_vapic(s, SYNC_TO_VAPIC);
+        return s->spurious_vec & 0xff;
+    }
+    reset_bit(s->irr, intno);
+    set_bit(s->isr, intno);
+    apic_sync_vapic(s, SYNC_TO_VAPIC);
+
+    /* re-inject if there is still a pending PIC interrupt */
+    apic_check_pic(s);
+
+    apic_update_irq(s);
+
+    return intno;
+}
+
+int apic_accept_pic_intr(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    uint32_t lvt0;
+
+    if (!s)
+        return -1;
+
+    lvt0 = s->lvt[APIC_LVT_LINT0];
+
+    if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 ||
+        (lvt0 & APIC_LVT_MASKED) == 0)
+        return 1;
+
+    return 0;
+}
+
+static uint32_t apic_get_current_count(APICCommonState *s)
+{
+    int64_t d;
+    uint32_t val;
+    d = (qemu_get_clock_ns(vm_clock) - s->initial_count_load_time) >>
+        s->count_shift;
+    if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
+        /* periodic */
+        val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
+    } else {
+        if (d >= s->initial_count)
+            val = 0;
+        else
+            val = s->initial_count - d;
+    }
+    return val;
+}
+
+static void apic_timer_update(APICCommonState *s, int64_t current_time)
+{
+    if (apic_next_timer(s, current_time)) {
+        qemu_mod_timer(s->timer, s->next_time);
+    } else {
+        qemu_del_timer(s->timer);
+    }
+}
+
+static void apic_timer(void *opaque)
+{
+    APICCommonState *s = opaque;
+
+    apic_local_deliver(s, APIC_LVT_TIMER);
+    apic_timer_update(s, s->next_time);
+}
+
+static uint32_t apic_mem_readb(void *opaque, hwaddr addr)
+{
+    return 0;
+}
+
+static uint32_t apic_mem_readw(void *opaque, hwaddr addr)
+{
+    return 0;
+}
+
+static void apic_mem_writeb(void *opaque, hwaddr addr, uint32_t val)
+{
+}
+
+static void apic_mem_writew(void *opaque, hwaddr addr, uint32_t val)
+{
+}
+
+static uint32_t apic_mem_readl(void *opaque, hwaddr addr)
+{
+    DeviceState *d;
+    APICCommonState *s;
+    uint32_t val;
+    int index;
+
+    d = cpu_get_current_apic();
+    if (!d) {
+        return 0;
+    }
+    s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+
+    index = (addr >> 4) & 0xff;
+    switch(index) {
+    case 0x02: /* id */
+        val = s->id << 24;
+        break;
+    case 0x03: /* version */
+        val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */
+        break;
+    case 0x08:
+        apic_sync_vapic(s, SYNC_FROM_VAPIC);
+        if (apic_report_tpr_access) {
+            cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_READ);
+        }
+        val = s->tpr;
+        break;
+    case 0x09:
+        val = apic_get_arb_pri(s);
+        break;
+    case 0x0a:
+        /* ppr */
+        val = apic_get_ppr(s);
+        break;
+    case 0x0b:
+        val = 0;
+        break;
+    case 0x0d:
+        val = s->log_dest << 24;
+        break;
+    case 0x0e:
+        val = s->dest_mode << 28;
+        break;
+    case 0x0f:
+        val = s->spurious_vec;
+        break;
+    case 0x10 ... 0x17:
+        val = s->isr[index & 7];
+        break;
+    case 0x18 ... 0x1f:
+        val = s->tmr[index & 7];
+        break;
+    case 0x20 ... 0x27:
+        val = s->irr[index & 7];
+        break;
+    case 0x28:
+        val = s->esr;
+        break;
+    case 0x30:
+    case 0x31:
+        val = s->icr[index & 1];
+        break;
+    case 0x32 ... 0x37:
+        val = s->lvt[index - 0x32];
+        break;
+    case 0x38:
+        val = s->initial_count;
+        break;
+    case 0x39:
+        val = apic_get_current_count(s);
+        break;
+    case 0x3e:
+        val = s->divide_conf;
+        break;
+    default:
+        s->esr |= ESR_ILLEGAL_ADDRESS;
+        val = 0;
+        break;
+    }
+    trace_apic_mem_readl(addr, val);
+    return val;
+}
+
+static void apic_send_msi(hwaddr addr, uint32_t data)
+{
+    uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
+    uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
+    uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
+    uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
+    uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
+    /* XXX: Ignore redirection hint. */
+    apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode);
+}
+
+static void apic_mem_writel(void *opaque, hwaddr addr, uint32_t val)
+{
+    DeviceState *d;
+    APICCommonState *s;
+    int index = (addr >> 4) & 0xff;
+    if (addr > 0xfff || !index) {
+        /* MSI and MMIO APIC are at the same memory location,
+         * but actually not on the global bus: MSI is on PCI bus
+         * APIC is connected directly to the CPU.
+         * Mapping them on the global bus happens to work because
+         * MSI registers are reserved in APIC MMIO and vice versa. */
+        apic_send_msi(addr, val);
+        return;
+    }
+
+    d = cpu_get_current_apic();
+    if (!d) {
+        return;
+    }
+    s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+
+    trace_apic_mem_writel(addr, val);
+
+    switch(index) {
+    case 0x02:
+        s->id = (val >> 24);
+        break;
+    case 0x03:
+        break;
+    case 0x08:
+        if (apic_report_tpr_access) {
+            cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_WRITE);
+        }
+        s->tpr = val;
+        apic_sync_vapic(s, SYNC_TO_VAPIC);
+        apic_update_irq(s);
+        break;
+    case 0x09:
+    case 0x0a:
+        break;
+    case 0x0b: /* EOI */
+        apic_eoi(s);
+        break;
+    case 0x0d:
+        s->log_dest = val >> 24;
+        break;
+    case 0x0e:
+        s->dest_mode = val >> 28;
+        break;
+    case 0x0f:
+        s->spurious_vec = val & 0x1ff;
+        apic_update_irq(s);
+        break;
+    case 0x10 ... 0x17:
+    case 0x18 ... 0x1f:
+    case 0x20 ... 0x27:
+    case 0x28:
+        break;
+    case 0x30:
+        s->icr[0] = val;
+        apic_deliver(d, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
+                     (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
+                     (s->icr[0] >> 15) & 1);
+        break;
+    case 0x31:
+        s->icr[1] = val;
+        break;
+    case 0x32 ... 0x37:
+        {
+            int n = index - 0x32;
+            s->lvt[n] = val;
+            if (n == APIC_LVT_TIMER) {
+                apic_timer_update(s, qemu_get_clock_ns(vm_clock));
+            } else if (n == APIC_LVT_LINT0 && apic_check_pic(s)) {
+                apic_update_irq(s);
+            }
+        }
+        break;
+    case 0x38:
+        s->initial_count = val;
+        s->initial_count_load_time = qemu_get_clock_ns(vm_clock);
+        apic_timer_update(s, s->initial_count_load_time);
+        break;
+    case 0x39:
+        break;
+    case 0x3e:
+        {
+            int v;
+            s->divide_conf = val & 0xb;
+            v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
+            s->count_shift = (v + 1) & 7;
+        }
+        break;
+    default:
+        s->esr |= ESR_ILLEGAL_ADDRESS;
+        break;
+    }
+}
+
+static void apic_pre_save(APICCommonState *s)
+{
+    apic_sync_vapic(s, SYNC_FROM_VAPIC);
+}
+
+static void apic_post_load(APICCommonState *s)
+{
+    if (s->timer_expiry != -1) {
+        qemu_mod_timer(s->timer, s->timer_expiry);
+    } else {
+        qemu_del_timer(s->timer);
+    }
+}
+
+static const MemoryRegionOps apic_io_ops = {
+    .old_mmio = {
+        .read = { apic_mem_readb, apic_mem_readw, apic_mem_readl, },
+        .write = { apic_mem_writeb, apic_mem_writew, apic_mem_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void apic_init(APICCommonState *s)
+{
+    memory_region_init_io(&s->io_memory, &apic_io_ops, s, "apic-msi",
+                          MSI_SPACE_SIZE);
+
+    s->timer = qemu_new_timer_ns(vm_clock, apic_timer, s);
+    local_apics[s->idx] = s;
+
+    msi_supported = true;
+}
+
+static void apic_class_init(ObjectClass *klass, void *data)
+{
+    APICCommonClass *k = APIC_COMMON_CLASS(klass);
+
+    k->init = apic_init;
+    k->set_base = apic_set_base;
+    k->set_tpr = apic_set_tpr;
+    k->get_tpr = apic_get_tpr;
+    k->vapic_base_update = apic_vapic_base_update;
+    k->external_nmi = apic_external_nmi;
+    k->pre_save = apic_pre_save;
+    k->post_load = apic_post_load;
+}
+
+static const TypeInfo apic_info = {
+    .name          = "apic",
+    .instance_size = sizeof(APICCommonState),
+    .parent        = TYPE_APIC_COMMON,
+    .class_init    = apic_class_init,
+};
+
+static void apic_register_types(void)
+{
+    type_register_static(&apic_info);
+}
+
+type_init(apic_register_types)
diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c
new file mode 100644 (file)
index 0000000..e0ae07a
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ *  APIC support - common bits of emulated and KVM kernel model
+ *
+ *  Copyright (c) 2004-2005 Fabrice Bellard
+ *  Copyright (c) 2011      Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+#include "hw/i386/apic.h"
+#include "hw/i386/apic_internal.h"
+#include "trace.h"
+#include "sysemu/kvm.h"
+
+static int apic_irq_delivered;
+bool apic_report_tpr_access;
+
+void cpu_set_apic_base(DeviceState *d, uint64_t val)
+{
+    trace_cpu_set_apic_base(val);
+
+    if (d) {
+        APICCommonState *s = APIC_COMMON(d);
+        APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+        info->set_base(s, val);
+    }
+}
+
+uint64_t cpu_get_apic_base(DeviceState *d)
+{
+    if (d) {
+        APICCommonState *s = APIC_COMMON(d);
+        trace_cpu_get_apic_base((uint64_t)s->apicbase);
+        return s->apicbase;
+    } else {
+        trace_cpu_get_apic_base(MSR_IA32_APICBASE_BSP);
+        return MSR_IA32_APICBASE_BSP;
+    }
+}
+
+void cpu_set_apic_tpr(DeviceState *d, uint8_t val)
+{
+    APICCommonState *s;
+    APICCommonClass *info;
+
+    if (!d) {
+        return;
+    }
+
+    s = APIC_COMMON(d);
+    info = APIC_COMMON_GET_CLASS(s);
+
+    info->set_tpr(s, val);
+}
+
+uint8_t cpu_get_apic_tpr(DeviceState *d)
+{
+    APICCommonState *s;
+    APICCommonClass *info;
+
+    if (!d) {
+        return 0;
+    }
+
+    s = APIC_COMMON(d);
+    info = APIC_COMMON_GET_CLASS(s);
+
+    return info->get_tpr(s);
+}
+
+void apic_enable_tpr_access_reporting(DeviceState *d, bool enable)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+
+    apic_report_tpr_access = enable;
+    if (info->enable_tpr_reporting) {
+        info->enable_tpr_reporting(s, enable);
+    }
+}
+
+void apic_enable_vapic(DeviceState *d, hwaddr paddr)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+
+    s->vapic_paddr = paddr;
+    info->vapic_base_update(s);
+}
+
+void apic_handle_tpr_access_report(DeviceState *d, target_ulong ip,
+                                   TPRAccess access)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+
+    vapic_report_tpr_access(s->vapic, CPU(s->cpu), ip, access);
+}
+
+void apic_report_irq_delivered(int delivered)
+{
+    apic_irq_delivered += delivered;
+
+    trace_apic_report_irq_delivered(apic_irq_delivered);
+}
+
+void apic_reset_irq_delivered(void)
+{
+    trace_apic_reset_irq_delivered(apic_irq_delivered);
+
+    apic_irq_delivered = 0;
+}
+
+int apic_get_irq_delivered(void)
+{
+    trace_apic_get_irq_delivered(apic_irq_delivered);
+
+    return apic_irq_delivered;
+}
+
+void apic_deliver_nmi(DeviceState *d)
+{
+    APICCommonState *s = APIC_COMMON(d);
+    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+
+    info->external_nmi(s);
+}
+
+bool apic_next_timer(APICCommonState *s, int64_t current_time)
+{
+    int64_t d;
+
+    /* We need to store the timer state separately to support APIC
+     * implementations that maintain a non-QEMU timer, e.g. inside the
+     * host kernel. This open-coded state allows us to migrate between
+     * both models. */
+    s->timer_expiry = -1;
+
+    if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED) {
+        return false;
+    }
+
+    d = (current_time - s->initial_count_load_time) >> s->count_shift;
+
+    if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
+        if (!s->initial_count) {
+            return false;
+        }
+        d = ((d / ((uint64_t)s->initial_count + 1)) + 1) *
+            ((uint64_t)s->initial_count + 1);
+    } else {
+        if (d >= s->initial_count) {
+            return false;
+        }
+        d = (uint64_t)s->initial_count + 1;
+    }
+    s->next_time = s->initial_count_load_time + (d << s->count_shift);
+    s->timer_expiry = s->next_time;
+    return true;
+}
+
+void apic_init_reset(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    int i;
+
+    if (!s) {
+        return;
+    }
+    s->tpr = 0;
+    s->spurious_vec = 0xff;
+    s->log_dest = 0;
+    s->dest_mode = 0xf;
+    memset(s->isr, 0, sizeof(s->isr));
+    memset(s->tmr, 0, sizeof(s->tmr));
+    memset(s->irr, 0, sizeof(s->irr));
+    for (i = 0; i < APIC_LVT_NB; i++) {
+        s->lvt[i] = APIC_LVT_MASKED;
+    }
+    s->esr = 0;
+    memset(s->icr, 0, sizeof(s->icr));
+    s->divide_conf = 0;
+    s->count_shift = 0;
+    s->initial_count = 0;
+    s->initial_count_load_time = 0;
+    s->next_time = 0;
+    s->wait_for_sipi = 1;
+
+    if (s->timer) {
+        qemu_del_timer(s->timer);
+    }
+    s->timer_expiry = -1;
+}
+
+void apic_designate_bsp(DeviceState *d)
+{
+    if (d == NULL) {
+        return;
+    }
+
+    APICCommonState *s = APIC_COMMON(d);
+    s->apicbase |= MSR_IA32_APICBASE_BSP;
+}
+
+static void apic_reset_common(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+    bool bsp;
+
+    bsp = cpu_is_bsp(s->cpu);
+    s->apicbase = APIC_DEFAULT_ADDRESS |
+        (bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE;
+
+    s->vapic_paddr = 0;
+    info->vapic_base_update(s);
+
+    apic_init_reset(d);
+
+    if (bsp) {
+        /*
+         * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization
+         * time typically by BIOS, so PIC interrupt can be delivered to the
+         * processor when local APIC is enabled.
+         */
+        s->lvt[APIC_LVT_LINT0] = 0x700;
+    }
+}
+
+/* This function is only used for old state version 1 and 2 */
+static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
+{
+    APICCommonState *s = opaque;
+    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+    int i;
+
+    if (version_id > 2) {
+        return -EINVAL;
+    }
+
+    /* XXX: what if the base changes? (registered memory regions) */
+    qemu_get_be32s(f, &s->apicbase);
+    qemu_get_8s(f, &s->id);
+    qemu_get_8s(f, &s->arb_id);
+    qemu_get_8s(f, &s->tpr);
+    qemu_get_be32s(f, &s->spurious_vec);
+    qemu_get_8s(f, &s->log_dest);
+    qemu_get_8s(f, &s->dest_mode);
+    for (i = 0; i < 8; i++) {
+        qemu_get_be32s(f, &s->isr[i]);
+        qemu_get_be32s(f, &s->tmr[i]);
+        qemu_get_be32s(f, &s->irr[i]);
+    }
+    for (i = 0; i < APIC_LVT_NB; i++) {
+        qemu_get_be32s(f, &s->lvt[i]);
+    }
+    qemu_get_be32s(f, &s->esr);
+    qemu_get_be32s(f, &s->icr[0]);
+    qemu_get_be32s(f, &s->icr[1]);
+    qemu_get_be32s(f, &s->divide_conf);
+    s->count_shift = qemu_get_be32(f);
+    qemu_get_be32s(f, &s->initial_count);
+    s->initial_count_load_time = qemu_get_be64(f);
+    s->next_time = qemu_get_be64(f);
+
+    if (version_id >= 2) {
+        s->timer_expiry = qemu_get_be64(f);
+    }
+
+    if (info->post_load) {
+        info->post_load(s);
+    }
+    return 0;
+}
+
+static int apic_init_common(SysBusDevice *dev)
+{
+    APICCommonState *s = APIC_COMMON(dev);
+    APICCommonClass *info;
+    static DeviceState *vapic;
+    static int apic_no;
+
+    if (apic_no >= MAX_APICS) {
+        return -1;
+    }
+    s->idx = apic_no++;
+
+    info = APIC_COMMON_GET_CLASS(s);
+    info->init(s);
+
+    sysbus_init_mmio(dev, &s->io_memory);
+
+    /* Note: We need at least 1M to map the VAPIC option ROM */
+    if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK &&
+        ram_size >= 1024 * 1024) {
+        vapic = sysbus_create_simple("kvmvapic", -1, NULL);
+    }
+    s->vapic = vapic;
+    if (apic_report_tpr_access && info->enable_tpr_reporting) {
+        info->enable_tpr_reporting(s, true);
+    }
+
+    return 0;
+}
+
+static void apic_dispatch_pre_save(void *opaque)
+{
+    APICCommonState *s = APIC_COMMON(opaque);
+    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+
+    if (info->pre_save) {
+        info->pre_save(s);
+    }
+}
+
+static int apic_dispatch_post_load(void *opaque, int version_id)
+{
+    APICCommonState *s = APIC_COMMON(opaque);
+    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+
+    if (info->post_load) {
+        info->post_load(s);
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_apic_common = {
+    .name = "apic",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 1,
+    .load_state_old = apic_load_old,
+    .pre_save = apic_dispatch_pre_save,
+    .post_load = apic_dispatch_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(apicbase, APICCommonState),
+        VMSTATE_UINT8(id, APICCommonState),
+        VMSTATE_UINT8(arb_id, APICCommonState),
+        VMSTATE_UINT8(tpr, APICCommonState),
+        VMSTATE_UINT32(spurious_vec, APICCommonState),
+        VMSTATE_UINT8(log_dest, APICCommonState),
+        VMSTATE_UINT8(dest_mode, APICCommonState),
+        VMSTATE_UINT32_ARRAY(isr, APICCommonState, 8),
+        VMSTATE_UINT32_ARRAY(tmr, APICCommonState, 8),
+        VMSTATE_UINT32_ARRAY(irr, APICCommonState, 8),
+        VMSTATE_UINT32_ARRAY(lvt, APICCommonState, APIC_LVT_NB),
+        VMSTATE_UINT32(esr, APICCommonState),
+        VMSTATE_UINT32_ARRAY(icr, APICCommonState, 2),
+        VMSTATE_UINT32(divide_conf, APICCommonState),
+        VMSTATE_INT32(count_shift, APICCommonState),
+        VMSTATE_UINT32(initial_count, APICCommonState),
+        VMSTATE_INT64(initial_count_load_time, APICCommonState),
+        VMSTATE_INT64(next_time, APICCommonState),
+        VMSTATE_INT64(timer_expiry,
+                      APICCommonState), /* open-coded timer state */
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property apic_properties_common[] = {
+    DEFINE_PROP_UINT8("id", APICCommonState, id, -1),
+    DEFINE_PROP_BIT("vapic", APICCommonState, vapic_control, VAPIC_ENABLE_BIT,
+                    true),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void apic_common_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->vmsd = &vmstate_apic_common;
+    dc->reset = apic_reset_common;
+    dc->no_user = 1;
+    dc->props = apic_properties_common;
+    sc->init = apic_init_common;
+}
+
+static const TypeInfo apic_common_type = {
+    .name = TYPE_APIC_COMMON,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(APICCommonState),
+    .class_size = sizeof(APICCommonClass),
+    .class_init = apic_common_class_init,
+    .abstract = true,
+};
+
+static void register_types(void)
+{
+    type_register_static(&apic_common_type);
+}
+
+type_init(register_types)
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
new file mode 100644 (file)
index 0000000..bcb072b
--- /dev/null
@@ -0,0 +1,723 @@
+/*
+ * ARM Generic/Distributed Interrupt Controller
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+/* This file contains implementation code for the RealView EB interrupt
+ * controller, MPCore distributed interrupt controller and ARMv7-M
+ * Nested Vectored Interrupt Controller.
+ * It is compiled in two ways:
+ *  (1) as a standalone file to produce a sysbus device which is a GIC
+ *  that can be used on the realview board and as one of the builtin
+ *  private peripherals for the ARM MP CPUs (11MPCore, A9, etc)
+ *  (2) by being directly #included into armv7m_nvic.c to produce the
+ *  armv7m_nvic device.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/arm_gic_internal.h"
+
+//#define DEBUG_GIC
+
+#ifdef DEBUG_GIC
+#define DPRINTF(fmt, ...) \
+do { fprintf(stderr, "arm_gic: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+static const uint8_t gic_id[] = {
+    0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1
+};
+
+#define NUM_CPU(s) ((s)->num_cpu)
+
+static inline int gic_get_current_cpu(GICState *s)
+{
+    if (s->num_cpu > 1) {
+        CPUState *cpu = ENV_GET_CPU(cpu_single_env);
+        return cpu->cpu_index;
+    }
+    return 0;
+}
+
+/* TODO: Many places that call this routine could be optimized.  */
+/* Update interrupt status after enabled or pending bits have been changed.  */
+void gic_update(GICState *s)
+{
+    int best_irq;
+    int best_prio;
+    int irq;
+    int level;
+    int cpu;
+    int cm;
+
+    for (cpu = 0; cpu < NUM_CPU(s); cpu++) {
+        cm = 1 << cpu;
+        s->current_pending[cpu] = 1023;
+        if (!s->enabled || !s->cpu_enabled[cpu]) {
+            qemu_irq_lower(s->parent_irq[cpu]);
+            return;
+        }
+        best_prio = 0x100;
+        best_irq = 1023;
+        for (irq = 0; irq < s->num_irq; irq++) {
+            if (GIC_TEST_ENABLED(irq, cm) && GIC_TEST_PENDING(irq, cm)) {
+                if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
+                    best_prio = GIC_GET_PRIORITY(irq, cpu);
+                    best_irq = irq;
+                }
+            }
+        }
+        level = 0;
+        if (best_prio < s->priority_mask[cpu]) {
+            s->current_pending[cpu] = best_irq;
+            if (best_prio < s->running_priority[cpu]) {
+                DPRINTF("Raised pending IRQ %d (cpu %d)\n", best_irq, cpu);
+                level = 1;
+            }
+        }
+        qemu_set_irq(s->parent_irq[cpu], level);
+    }
+}
+
+void gic_set_pending_private(GICState *s, int cpu, int irq)
+{
+    int cm = 1 << cpu;
+
+    if (GIC_TEST_PENDING(irq, cm))
+        return;
+
+    DPRINTF("Set %d pending cpu %d\n", irq, cpu);
+    GIC_SET_PENDING(irq, cm);
+    gic_update(s);
+}
+
+/* Process a change in an external IRQ input.  */
+static void gic_set_irq(void *opaque, int irq, int level)
+{
+    /* Meaning of the 'irq' parameter:
+     *  [0..N-1] : external interrupts
+     *  [N..N+31] : PPI (internal) interrupts for CPU 0
+     *  [N+32..N+63] : PPI (internal interrupts for CPU 1
+     *  ...
+     */
+    GICState *s = (GICState *)opaque;
+    int cm, target;
+    if (irq < (s->num_irq - GIC_INTERNAL)) {
+        /* The first external input line is internal interrupt 32.  */
+        cm = ALL_CPU_MASK;
+        irq += GIC_INTERNAL;
+        target = GIC_TARGET(irq);
+    } else {
+        int cpu;
+        irq -= (s->num_irq - GIC_INTERNAL);
+        cpu = irq / GIC_INTERNAL;
+        irq %= GIC_INTERNAL;
+        cm = 1 << cpu;
+        target = cm;
+    }
+
+    if (level == GIC_TEST_LEVEL(irq, cm)) {
+        return;
+    }
+
+    if (level) {
+        GIC_SET_LEVEL(irq, cm);
+        if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) {
+            DPRINTF("Set %d pending mask %x\n", irq, target);
+            GIC_SET_PENDING(irq, target);
+        }
+    } else {
+        GIC_CLEAR_LEVEL(irq, cm);
+    }
+    gic_update(s);
+}
+
+static void gic_set_running_irq(GICState *s, int cpu, int irq)
+{
+    s->running_irq[cpu] = irq;
+    if (irq == 1023) {
+        s->running_priority[cpu] = 0x100;
+    } else {
+        s->running_priority[cpu] = GIC_GET_PRIORITY(irq, cpu);
+    }
+    gic_update(s);
+}
+
+uint32_t gic_acknowledge_irq(GICState *s, int cpu)
+{
+    int new_irq;
+    int cm = 1 << cpu;
+    new_irq = s->current_pending[cpu];
+    if (new_irq == 1023
+            || GIC_GET_PRIORITY(new_irq, cpu) >= s->running_priority[cpu]) {
+        DPRINTF("ACK no pending IRQ\n");
+        return 1023;
+    }
+    s->last_active[new_irq][cpu] = s->running_irq[cpu];
+    /* Clear pending flags for both level and edge triggered interrupts.
+       Level triggered IRQs will be reasserted once they become inactive.  */
+    GIC_CLEAR_PENDING(new_irq, GIC_TEST_MODEL(new_irq) ? ALL_CPU_MASK : cm);
+    gic_set_running_irq(s, cpu, new_irq);
+    DPRINTF("ACK %d\n", new_irq);
+    return new_irq;
+}
+
+void gic_complete_irq(GICState *s, int cpu, int irq)
+{
+    int update = 0;
+    int cm = 1 << cpu;
+    DPRINTF("EOI %d\n", irq);
+    if (irq >= s->num_irq) {
+        /* This handles two cases:
+         * 1. If software writes the ID of a spurious interrupt [ie 1023]
+         * to the GICC_EOIR, the GIC ignores that write.
+         * 2. If software writes the number of a non-existent interrupt
+         * this must be a subcase of "value written does not match the last
+         * valid interrupt value read from the Interrupt Acknowledge
+         * register" and so this is UNPREDICTABLE. We choose to ignore it.
+         */
+        return;
+    }
+    if (s->running_irq[cpu] == 1023)
+        return; /* No active IRQ.  */
+    /* Mark level triggered interrupts as pending if they are still
+       raised.  */
+    if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm)
+        && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) {
+        DPRINTF("Set %d pending mask %x\n", irq, cm);
+        GIC_SET_PENDING(irq, cm);
+        update = 1;
+    }
+    if (irq != s->running_irq[cpu]) {
+        /* Complete an IRQ that is not currently running.  */
+        int tmp = s->running_irq[cpu];
+        while (s->last_active[tmp][cpu] != 1023) {
+            if (s->last_active[tmp][cpu] == irq) {
+                s->last_active[tmp][cpu] = s->last_active[irq][cpu];
+                break;
+            }
+            tmp = s->last_active[tmp][cpu];
+        }
+        if (update) {
+            gic_update(s);
+        }
+    } else {
+        /* Complete the current running IRQ.  */
+        gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]);
+    }
+}
+
+static uint32_t gic_dist_readb(void *opaque, hwaddr offset)
+{
+    GICState *s = (GICState *)opaque;
+    uint32_t res;
+    int irq;
+    int i;
+    int cpu;
+    int cm;
+    int mask;
+
+    cpu = gic_get_current_cpu(s);
+    cm = 1 << cpu;
+    if (offset < 0x100) {
+        if (offset == 0)
+            return s->enabled;
+        if (offset == 4)
+            return ((s->num_irq / 32) - 1) | ((NUM_CPU(s) - 1) << 5);
+        if (offset < 0x08)
+            return 0;
+        if (offset >= 0x80) {
+            /* Interrupt Security , RAZ/WI */
+            return 0;
+        }
+        goto bad_reg;
+    } else if (offset < 0x200) {
+        /* Interrupt Set/Clear Enable.  */
+        if (offset < 0x180)
+            irq = (offset - 0x100) * 8;
+        else
+            irq = (offset - 0x180) * 8;
+        irq += GIC_BASE_IRQ;
+        if (irq >= s->num_irq)
+            goto bad_reg;
+        res = 0;
+        for (i = 0; i < 8; i++) {
+            if (GIC_TEST_ENABLED(irq + i, cm)) {
+                res |= (1 << i);
+            }
+        }
+    } else if (offset < 0x300) {
+        /* Interrupt Set/Clear Pending.  */
+        if (offset < 0x280)
+            irq = (offset - 0x200) * 8;
+        else
+            irq = (offset - 0x280) * 8;
+        irq += GIC_BASE_IRQ;
+        if (irq >= s->num_irq)
+            goto bad_reg;
+        res = 0;
+        mask = (irq < GIC_INTERNAL) ?  cm : ALL_CPU_MASK;
+        for (i = 0; i < 8; i++) {
+            if (GIC_TEST_PENDING(irq + i, mask)) {
+                res |= (1 << i);
+            }
+        }
+    } else if (offset < 0x400) {
+        /* Interrupt Active.  */
+        irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;
+        if (irq >= s->num_irq)
+            goto bad_reg;
+        res = 0;
+        mask = (irq < GIC_INTERNAL) ?  cm : ALL_CPU_MASK;
+        for (i = 0; i < 8; i++) {
+            if (GIC_TEST_ACTIVE(irq + i, mask)) {
+                res |= (1 << i);
+            }
+        }
+    } else if (offset < 0x800) {
+        /* Interrupt Priority.  */
+        irq = (offset - 0x400) + GIC_BASE_IRQ;
+        if (irq >= s->num_irq)
+            goto bad_reg;
+        res = GIC_GET_PRIORITY(irq, cpu);
+    } else if (offset < 0xc00) {
+        /* Interrupt CPU Target.  */
+        if (s->num_cpu == 1 && s->revision != REV_11MPCORE) {
+            /* For uniprocessor GICs these RAZ/WI */
+            res = 0;
+        } else {
+            irq = (offset - 0x800) + GIC_BASE_IRQ;
+            if (irq >= s->num_irq) {
+                goto bad_reg;
+            }
+            if (irq >= 29 && irq <= 31) {
+                res = cm;
+            } else {
+                res = GIC_TARGET(irq);
+            }
+        }
+    } else if (offset < 0xf00) {
+        /* Interrupt Configuration.  */
+        irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ;
+        if (irq >= s->num_irq)
+            goto bad_reg;
+        res = 0;
+        for (i = 0; i < 4; i++) {
+            if (GIC_TEST_MODEL(irq + i))
+                res |= (1 << (i * 2));
+            if (GIC_TEST_TRIGGER(irq + i))
+                res |= (2 << (i * 2));
+        }
+    } else if (offset < 0xfe0) {
+        goto bad_reg;
+    } else /* offset >= 0xfe0 */ {
+        if (offset & 3) {
+            res = 0;
+        } else {
+            res = gic_id[(offset - 0xfe0) >> 2];
+        }
+    }
+    return res;
+bad_reg:
+    qemu_log_mask(LOG_GUEST_ERROR,
+                  "gic_dist_readb: Bad offset %x\n", (int)offset);
+    return 0;
+}
+
+static uint32_t gic_dist_readw(void *opaque, hwaddr offset)
+{
+    uint32_t val;
+    val = gic_dist_readb(opaque, offset);
+    val |= gic_dist_readb(opaque, offset + 1) << 8;
+    return val;
+}
+
+static uint32_t gic_dist_readl(void *opaque, hwaddr offset)
+{
+    uint32_t val;
+    val = gic_dist_readw(opaque, offset);
+    val |= gic_dist_readw(opaque, offset + 2) << 16;
+    return val;
+}
+
+static void gic_dist_writeb(void *opaque, hwaddr offset,
+                            uint32_t value)
+{
+    GICState *s = (GICState *)opaque;
+    int irq;
+    int i;
+    int cpu;
+
+    cpu = gic_get_current_cpu(s);
+    if (offset < 0x100) {
+        if (offset == 0) {
+            s->enabled = (value & 1);
+            DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis");
+        } else if (offset < 4) {
+            /* ignored.  */
+        } else if (offset >= 0x80) {
+            /* Interrupt Security Registers, RAZ/WI */
+        } else {
+            goto bad_reg;
+        }
+    } else if (offset < 0x180) {
+        /* Interrupt Set Enable.  */
+        irq = (offset - 0x100) * 8 + GIC_BASE_IRQ;
+        if (irq >= s->num_irq)
+            goto bad_reg;
+        if (irq < 16)
+          value = 0xff;
+        for (i = 0; i < 8; i++) {
+            if (value & (1 << i)) {
+                int mask =
+                    (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq + i);
+                int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
+
+                if (!GIC_TEST_ENABLED(irq + i, cm)) {
+                    DPRINTF("Enabled IRQ %d\n", irq + i);
+                }
+                GIC_SET_ENABLED(irq + i, cm);
+                /* If a raised level triggered IRQ enabled then mark
+                   is as pending.  */
+                if (GIC_TEST_LEVEL(irq + i, mask)
+                        && !GIC_TEST_TRIGGER(irq + i)) {
+                    DPRINTF("Set %d pending mask %x\n", irq + i, mask);
+                    GIC_SET_PENDING(irq + i, mask);
+                }
+            }
+        }
+    } else if (offset < 0x200) {
+        /* Interrupt Clear Enable.  */
+        irq = (offset - 0x180) * 8 + GIC_BASE_IRQ;
+        if (irq >= s->num_irq)
+            goto bad_reg;
+        if (irq < 16)
+          value = 0;
+        for (i = 0; i < 8; i++) {
+            if (value & (1 << i)) {
+                int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
+
+                if (GIC_TEST_ENABLED(irq + i, cm)) {
+                    DPRINTF("Disabled IRQ %d\n", irq + i);
+                }
+                GIC_CLEAR_ENABLED(irq + i, cm);
+            }
+        }
+    } else if (offset < 0x280) {
+        /* Interrupt Set Pending.  */
+        irq = (offset - 0x200) * 8 + GIC_BASE_IRQ;
+        if (irq >= s->num_irq)
+            goto bad_reg;
+        if (irq < 16)
+          irq = 0;
+
+        for (i = 0; i < 8; i++) {
+            if (value & (1 << i)) {
+                GIC_SET_PENDING(irq + i, GIC_TARGET(irq + i));
+            }
+        }
+    } else if (offset < 0x300) {
+        /* Interrupt Clear Pending.  */
+        irq = (offset - 0x280) * 8 + GIC_BASE_IRQ;
+        if (irq >= s->num_irq)
+            goto bad_reg;
+        for (i = 0; i < 8; i++) {
+            /* ??? This currently clears the pending bit for all CPUs, even
+               for per-CPU interrupts.  It's unclear whether this is the
+               corect behavior.  */
+            if (value & (1 << i)) {
+                GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK);
+            }
+        }
+    } else if (offset < 0x400) {
+        /* Interrupt Active.  */
+        goto bad_reg;
+    } else if (offset < 0x800) {
+        /* Interrupt Priority.  */
+        irq = (offset - 0x400) + GIC_BASE_IRQ;
+        if (irq >= s->num_irq)
+            goto bad_reg;
+        if (irq < GIC_INTERNAL) {
+            s->priority1[irq][cpu] = value;
+        } else {
+            s->priority2[irq - GIC_INTERNAL] = value;
+        }
+    } else if (offset < 0xc00) {
+        /* Interrupt CPU Target. RAZ/WI on uniprocessor GICs, with the
+         * annoying exception of the 11MPCore's GIC.
+         */
+        if (s->num_cpu != 1 || s->revision == REV_11MPCORE) {
+            irq = (offset - 0x800) + GIC_BASE_IRQ;
+            if (irq >= s->num_irq) {
+                goto bad_reg;
+            }
+            if (irq < 29) {
+                value = 0;
+            } else if (irq < GIC_INTERNAL) {
+                value = ALL_CPU_MASK;
+            }
+            s->irq_target[irq] = value & ALL_CPU_MASK;
+        }
+    } else if (offset < 0xf00) {
+        /* Interrupt Configuration.  */
+        irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
+        if (irq >= s->num_irq)
+            goto bad_reg;
+        if (irq < GIC_INTERNAL)
+            value |= 0xaa;
+        for (i = 0; i < 4; i++) {
+            if (value & (1 << (i * 2))) {
+                GIC_SET_MODEL(irq + i);
+            } else {
+                GIC_CLEAR_MODEL(irq + i);
+            }
+            if (value & (2 << (i * 2))) {
+                GIC_SET_TRIGGER(irq + i);
+            } else {
+                GIC_CLEAR_TRIGGER(irq + i);
+            }
+        }
+    } else {
+        /* 0xf00 is only handled for 32-bit writes.  */
+        goto bad_reg;
+    }
+    gic_update(s);
+    return;
+bad_reg:
+    qemu_log_mask(LOG_GUEST_ERROR,
+                  "gic_dist_writeb: Bad offset %x\n", (int)offset);
+}
+
+static void gic_dist_writew(void *opaque, hwaddr offset,
+                            uint32_t value)
+{
+    gic_dist_writeb(opaque, offset, value & 0xff);
+    gic_dist_writeb(opaque, offset + 1, value >> 8);
+}
+
+static void gic_dist_writel(void *opaque, hwaddr offset,
+                            uint32_t value)
+{
+    GICState *s = (GICState *)opaque;
+    if (offset == 0xf00) {
+        int cpu;
+        int irq;
+        int mask;
+
+        cpu = gic_get_current_cpu(s);
+        irq = value & 0x3ff;
+        switch ((value >> 24) & 3) {
+        case 0:
+            mask = (value >> 16) & ALL_CPU_MASK;
+            break;
+        case 1:
+            mask = ALL_CPU_MASK ^ (1 << cpu);
+            break;
+        case 2:
+            mask = 1 << cpu;
+            break;
+        default:
+            DPRINTF("Bad Soft Int target filter\n");
+            mask = ALL_CPU_MASK;
+            break;
+        }
+        GIC_SET_PENDING(irq, mask);
+        gic_update(s);
+        return;
+    }
+    gic_dist_writew(opaque, offset, value & 0xffff);
+    gic_dist_writew(opaque, offset + 2, value >> 16);
+}
+
+static const MemoryRegionOps gic_dist_ops = {
+    .old_mmio = {
+        .read = { gic_dist_readb, gic_dist_readw, gic_dist_readl, },
+        .write = { gic_dist_writeb, gic_dist_writew, gic_dist_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static uint32_t gic_cpu_read(GICState *s, int cpu, int offset)
+{
+    switch (offset) {
+    case 0x00: /* Control */
+        return s->cpu_enabled[cpu];
+    case 0x04: /* Priority mask */
+        return s->priority_mask[cpu];
+    case 0x08: /* Binary Point */
+        /* ??? Not implemented.  */
+        return 0;
+    case 0x0c: /* Acknowledge */
+        return gic_acknowledge_irq(s, cpu);
+    case 0x14: /* Running Priority */
+        return s->running_priority[cpu];
+    case 0x18: /* Highest Pending Interrupt */
+        return s->current_pending[cpu];
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "gic_cpu_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void gic_cpu_write(GICState *s, int cpu, int offset, uint32_t value)
+{
+    switch (offset) {
+    case 0x00: /* Control */
+        s->cpu_enabled[cpu] = (value & 1);
+        DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled[cpu] ? "En" : "Dis");
+        break;
+    case 0x04: /* Priority mask */
+        s->priority_mask[cpu] = (value & 0xff);
+        break;
+    case 0x08: /* Binary Point */
+        /* ??? Not implemented.  */
+        break;
+    case 0x10: /* End Of Interrupt */
+        return gic_complete_irq(s, cpu, value & 0x3ff);
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "gic_cpu_write: Bad offset %x\n", (int)offset);
+        return;
+    }
+    gic_update(s);
+}
+
+/* Wrappers to read/write the GIC CPU interface for the current CPU */
+static uint64_t gic_thiscpu_read(void *opaque, hwaddr addr,
+                                 unsigned size)
+{
+    GICState *s = (GICState *)opaque;
+    return gic_cpu_read(s, gic_get_current_cpu(s), addr);
+}
+
+static void gic_thiscpu_write(void *opaque, hwaddr addr,
+                              uint64_t value, unsigned size)
+{
+    GICState *s = (GICState *)opaque;
+    gic_cpu_write(s, gic_get_current_cpu(s), addr, value);
+}
+
+/* Wrappers to read/write the GIC CPU interface for a specific CPU.
+ * These just decode the opaque pointer into GICState* + cpu id.
+ */
+static uint64_t gic_do_cpu_read(void *opaque, hwaddr addr,
+                                unsigned size)
+{
+    GICState **backref = (GICState **)opaque;
+    GICState *s = *backref;
+    int id = (backref - s->backref);
+    return gic_cpu_read(s, id, addr);
+}
+
+static void gic_do_cpu_write(void *opaque, hwaddr addr,
+                             uint64_t value, unsigned size)
+{
+    GICState **backref = (GICState **)opaque;
+    GICState *s = *backref;
+    int id = (backref - s->backref);
+    gic_cpu_write(s, id, addr, value);
+}
+
+static const MemoryRegionOps gic_thiscpu_ops = {
+    .read = gic_thiscpu_read,
+    .write = gic_thiscpu_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const MemoryRegionOps gic_cpu_ops = {
+    .read = gic_do_cpu_read,
+    .write = gic_do_cpu_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+void gic_init_irqs_and_distributor(GICState *s, int num_irq)
+{
+    int i;
+
+    i = s->num_irq - GIC_INTERNAL;
+    /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
+     * GPIO array layout is thus:
+     *  [0..N-1] SPIs
+     *  [N..N+31] PPIs for CPU 0
+     *  [N+32..N+63] PPIs for CPU 1
+     *   ...
+     */
+    if (s->revision != REV_NVIC) {
+        i += (GIC_INTERNAL * s->num_cpu);
+    }
+    qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, i);
+    for (i = 0; i < NUM_CPU(s); i++) {
+        sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
+    }
+    memory_region_init_io(&s->iomem, &gic_dist_ops, s, "gic_dist", 0x1000);
+}
+
+static void arm_gic_realize(DeviceState *dev, Error **errp)
+{
+    /* Device instance realize function for the GIC sysbus device */
+    int i;
+    GICState *s = ARM_GIC(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+    ARMGICClass *agc = ARM_GIC_GET_CLASS(s);
+
+    agc->parent_realize(dev, errp);
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    gic_init_irqs_and_distributor(s, s->num_irq);
+
+    /* Memory regions for the CPU interfaces (NVIC doesn't have these):
+     * a region for "CPU interface for this core", then a region for
+     * "CPU interface for core 0", "for core 1", ...
+     * NB that the memory region size of 0x100 applies for the 11MPCore
+     * and also cores following the GIC v1 spec (ie A9).
+     * GIC v2 defines a larger memory region (0x1000) so this will need
+     * to be extended when we implement A15.
+     */
+    memory_region_init_io(&s->cpuiomem[0], &gic_thiscpu_ops, s,
+                          "gic_cpu", 0x100);
+    for (i = 0; i < NUM_CPU(s); i++) {
+        s->backref[i] = s;
+        memory_region_init_io(&s->cpuiomem[i+1], &gic_cpu_ops, &s->backref[i],
+                              "gic_cpu", 0x100);
+    }
+    /* Distributor */
+    sysbus_init_mmio(sbd, &s->iomem);
+    /* cpu interfaces (one for "current cpu" plus one per cpu) */
+    for (i = 0; i <= NUM_CPU(s); i++) {
+        sysbus_init_mmio(sbd, &s->cpuiomem[i]);
+    }
+}
+
+static void arm_gic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ARMGICClass *agc = ARM_GIC_CLASS(klass);
+
+    dc->no_user = 1;
+    agc->parent_realize = dc->realize;
+    dc->realize = arm_gic_realize;
+}
+
+static const TypeInfo arm_gic_info = {
+    .name = TYPE_ARM_GIC,
+    .parent = TYPE_ARM_GIC_COMMON,
+    .instance_size = sizeof(GICState),
+    .class_init = arm_gic_class_init,
+    .class_size = sizeof(ARMGICClass),
+};
+
+static void arm_gic_register_types(void)
+{
+    type_register_static(&arm_gic_info);
+}
+
+type_init(arm_gic_register_types)
diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c
new file mode 100644 (file)
index 0000000..71594f1
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * ARM GIC support - common bits of emulated and KVM kernel model
+ *
+ * Copyright (c) 2012 Linaro Limited
+ * Written by Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/arm_gic_internal.h"
+
+static void gic_pre_save(void *opaque)
+{
+    GICState *s = (GICState *)opaque;
+    ARMGICCommonClass *c = ARM_GIC_COMMON_GET_CLASS(s);
+
+    if (c->pre_save) {
+        c->pre_save(s);
+    }
+}
+
+static int gic_post_load(void *opaque, int version_id)
+{
+    GICState *s = (GICState *)opaque;
+    ARMGICCommonClass *c = ARM_GIC_COMMON_GET_CLASS(s);
+
+    if (c->post_load) {
+        c->post_load(s);
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_gic_irq_state = {
+    .name = "arm_gic_irq_state",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(enabled, gic_irq_state),
+        VMSTATE_UINT8(pending, gic_irq_state),
+        VMSTATE_UINT8(active, gic_irq_state),
+        VMSTATE_UINT8(level, gic_irq_state),
+        VMSTATE_BOOL(model, gic_irq_state),
+        VMSTATE_BOOL(trigger, gic_irq_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_gic = {
+    .name = "arm_gic",
+    .version_id = 4,
+    .minimum_version_id = 4,
+    .pre_save = gic_pre_save,
+    .post_load = gic_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_BOOL(enabled, GICState),
+        VMSTATE_BOOL_ARRAY(cpu_enabled, GICState, NCPU),
+        VMSTATE_STRUCT_ARRAY(irq_state, GICState, GIC_MAXIRQ, 1,
+                             vmstate_gic_irq_state, gic_irq_state),
+        VMSTATE_UINT8_ARRAY(irq_target, GICState, GIC_MAXIRQ),
+        VMSTATE_UINT8_2DARRAY(priority1, GICState, GIC_INTERNAL, NCPU),
+        VMSTATE_UINT8_ARRAY(priority2, GICState, GIC_MAXIRQ - GIC_INTERNAL),
+        VMSTATE_UINT16_2DARRAY(last_active, GICState, GIC_MAXIRQ, NCPU),
+        VMSTATE_UINT16_ARRAY(priority_mask, GICState, NCPU),
+        VMSTATE_UINT16_ARRAY(running_irq, GICState, NCPU),
+        VMSTATE_UINT16_ARRAY(running_priority, GICState, NCPU),
+        VMSTATE_UINT16_ARRAY(current_pending, GICState, NCPU),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void arm_gic_common_realize(DeviceState *dev, Error **errp)
+{
+    GICState *s = ARM_GIC_COMMON(dev);
+    int num_irq = s->num_irq;
+
+    if (s->num_cpu > NCPU) {
+        error_setg(errp, "requested %u CPUs exceeds GIC maximum %d",
+                   s->num_cpu, NCPU);
+        return;
+    }
+    s->num_irq += GIC_BASE_IRQ;
+    if (s->num_irq > GIC_MAXIRQ) {
+        error_setg(errp,
+                   "requested %u interrupt lines exceeds GIC maximum %d",
+                   num_irq, GIC_MAXIRQ);
+        return;
+    }
+    /* ITLinesNumber is represented as (N / 32) - 1 (see
+     * gic_dist_readb) so this is an implementation imposed
+     * restriction, not an architectural one:
+     */
+    if (s->num_irq < 32 || (s->num_irq % 32)) {
+        error_setg(errp,
+                   "%d interrupt lines unsupported: not divisible by 32",
+                   num_irq);
+        return;
+    }
+}
+
+static void arm_gic_common_reset(DeviceState *dev)
+{
+    GICState *s = FROM_SYSBUS(GICState, SYS_BUS_DEVICE(dev));
+    int i;
+    memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state));
+    for (i = 0 ; i < s->num_cpu; i++) {
+        if (s->revision == REV_11MPCORE) {
+            s->priority_mask[i] = 0xf0;
+        } else {
+            s->priority_mask[i] = 0;
+        }
+        s->current_pending[i] = 1023;
+        s->running_irq[i] = 1023;
+        s->running_priority[i] = 0x100;
+        s->cpu_enabled[i] = false;
+    }
+    for (i = 0; i < 16; i++) {
+        GIC_SET_ENABLED(i, ALL_CPU_MASK);
+        GIC_SET_TRIGGER(i);
+    }
+    if (s->num_cpu == 1) {
+        /* For uniprocessor GICs all interrupts always target the sole CPU */
+        for (i = 0; i < GIC_MAXIRQ; i++) {
+            s->irq_target[i] = 1;
+        }
+    }
+    s->enabled = false;
+}
+
+static Property arm_gic_common_properties[] = {
+    DEFINE_PROP_UINT32("num-cpu", GICState, num_cpu, 1),
+    DEFINE_PROP_UINT32("num-irq", GICState, num_irq, 32),
+    /* Revision can be 1 or 2 for GIC architecture specification
+     * versions 1 or 2, or 0 to indicate the legacy 11MPCore GIC.
+     * (Internally, 0xffffffff also indicates "not a GIC but an NVIC".)
+     */
+    DEFINE_PROP_UINT32("revision", GICState, revision, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void arm_gic_common_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = arm_gic_common_reset;
+    dc->realize = arm_gic_common_realize;
+    dc->props = arm_gic_common_properties;
+    dc->vmsd = &vmstate_gic;
+    dc->no_user = 1;
+}
+
+static const TypeInfo arm_gic_common_type = {
+    .name = TYPE_ARM_GIC_COMMON,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(GICState),
+    .class_size = sizeof(ARMGICCommonClass),
+    .class_init = arm_gic_common_class_init,
+    .abstract = true,
+};
+
+static void register_types(void)
+{
+    type_register_static(&arm_gic_common_type);
+}
+
+type_init(register_types)
diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c
new file mode 100644 (file)
index 0000000..22b40b4
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * ARM Generic Interrupt Controller using KVM in-kernel support
+ *
+ * Copyright (c) 2012 Linaro Limited
+ * Written by Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/sysbus.h"
+#include "sysemu/kvm.h"
+#include "kvm_arm.h"
+#include "hw/arm_gic_internal.h"
+
+#define TYPE_KVM_ARM_GIC "kvm-arm-gic"
+#define KVM_ARM_GIC(obj) \
+     OBJECT_CHECK(GICState, (obj), TYPE_KVM_ARM_GIC)
+#define KVM_ARM_GIC_CLASS(klass) \
+     OBJECT_CLASS_CHECK(KVMARMGICClass, (klass), TYPE_KVM_ARM_GIC)
+#define KVM_ARM_GIC_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(KVMARMGICClass, (obj), TYPE_KVM_ARM_GIC)
+
+typedef struct KVMARMGICClass {
+    ARMGICCommonClass parent_class;
+    DeviceRealize parent_realize;
+    void (*parent_reset)(DeviceState *dev);
+} KVMARMGICClass;
+
+static void kvm_arm_gic_set_irq(void *opaque, int irq, int level)
+{
+    /* Meaning of the 'irq' parameter:
+     *  [0..N-1] : external interrupts
+     *  [N..N+31] : PPI (internal) interrupts for CPU 0
+     *  [N+32..N+63] : PPI (internal interrupts for CPU 1
+     *  ...
+     * Convert this to the kernel's desired encoding, which
+     * has separate fields in the irq number for type,
+     * CPU number and interrupt number.
+     */
+    GICState *s = (GICState *)opaque;
+    int kvm_irq, irqtype, cpu;
+
+    if (irq < (s->num_irq - GIC_INTERNAL)) {
+        /* External interrupt. The kernel numbers these like the GIC
+         * hardware, with external interrupt IDs starting after the
+         * internal ones.
+         */
+        irqtype = KVM_ARM_IRQ_TYPE_SPI;
+        cpu = 0;
+        irq += GIC_INTERNAL;
+    } else {
+        /* Internal interrupt: decode into (cpu, interrupt id) */
+        irqtype = KVM_ARM_IRQ_TYPE_PPI;
+        irq -= (s->num_irq - GIC_INTERNAL);
+        cpu = irq / GIC_INTERNAL;
+        irq %= GIC_INTERNAL;
+    }
+    kvm_irq = (irqtype << KVM_ARM_IRQ_TYPE_SHIFT)
+        | (cpu << KVM_ARM_IRQ_VCPU_SHIFT) | irq;
+
+    kvm_set_irq(kvm_state, kvm_irq, !!level);
+}
+
+static void kvm_arm_gic_put(GICState *s)
+{
+    /* TODO: there isn't currently a kernel interface to set the GIC state */
+}
+
+static void kvm_arm_gic_get(GICState *s)
+{
+    /* TODO: there isn't currently a kernel interface to get the GIC state */
+}
+
+static void kvm_arm_gic_reset(DeviceState *dev)
+{
+    GICState *s = ARM_GIC_COMMON(dev);
+    KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
+
+    kgc->parent_reset(dev);
+    kvm_arm_gic_put(s);
+}
+
+static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
+{
+    int i;
+    GICState *s = KVM_ARM_GIC(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+    KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
+
+    kgc->parent_realize(dev, errp);
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    i = s->num_irq - GIC_INTERNAL;
+    /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
+     * GPIO array layout is thus:
+     *  [0..N-1] SPIs
+     *  [N..N+31] PPIs for CPU 0
+     *  [N+32..N+63] PPIs for CPU 1
+     *   ...
+     */
+    i += (GIC_INTERNAL * s->num_cpu);
+    qdev_init_gpio_in(dev, kvm_arm_gic_set_irq, i);
+    /* We never use our outbound IRQ lines but provide them so that
+     * we maintain the same interface as the non-KVM GIC.
+     */
+    for (i = 0; i < s->num_cpu; i++) {
+        sysbus_init_irq(sbd, &s->parent_irq[i]);
+    }
+    /* Distributor */
+    memory_region_init_reservation(&s->iomem, "kvm-gic_dist", 0x1000);
+    sysbus_init_mmio(sbd, &s->iomem);
+    kvm_arm_register_device(&s->iomem,
+                            (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
+                            | KVM_VGIC_V2_ADDR_TYPE_DIST);
+    /* CPU interface for current core. Unlike arm_gic, we don't
+     * provide the "interface for core #N" memory regions, because
+     * cores with a VGIC don't have those.
+     */
+    memory_region_init_reservation(&s->cpuiomem[0], "kvm-gic_cpu", 0x1000);
+    sysbus_init_mmio(sbd, &s->cpuiomem[0]);
+    kvm_arm_register_device(&s->cpuiomem[0],
+                            (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
+                            | KVM_VGIC_V2_ADDR_TYPE_CPU);
+}
+
+static void kvm_arm_gic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ARMGICCommonClass *agcc = ARM_GIC_COMMON_CLASS(klass);
+    KVMARMGICClass *kgc = KVM_ARM_GIC_CLASS(klass);
+
+    agcc->pre_save = kvm_arm_gic_get;
+    agcc->post_load = kvm_arm_gic_put;
+    kgc->parent_realize = dc->realize;
+    kgc->parent_reset = dc->reset;
+    dc->realize = kvm_arm_gic_realize;
+    dc->reset = kvm_arm_gic_reset;
+    dc->no_user = 1;
+}
+
+static const TypeInfo kvm_arm_gic_info = {
+    .name = TYPE_KVM_ARM_GIC,
+    .parent = TYPE_ARM_GIC_COMMON,
+    .instance_size = sizeof(GICState),
+    .class_init = kvm_arm_gic_class_init,
+    .class_size = sizeof(KVMARMGICClass),
+};
+
+static void kvm_arm_gic_register_types(void)
+{
+    type_register_static(&kvm_arm_gic_info);
+}
+
+type_init(kvm_arm_gic_register_types)
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
new file mode 100644 (file)
index 0000000..7574260
--- /dev/null
@@ -0,0 +1,553 @@
+/*
+ * ARM Nested Vectored Interrupt Controller
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ *
+ * The ARMv7M System controller is fairly tightly tied in with the
+ * NVIC.  Much of that is also implemented here.
+ */
+
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+#include "hw/arm.h"
+#include "exec/address-spaces.h"
+#include "hw/arm_gic_internal.h"
+
+typedef struct {
+    GICState gic;
+    struct {
+        uint32_t control;
+        uint32_t reload;
+        int64_t tick;
+        QEMUTimer *timer;
+    } systick;
+    MemoryRegion sysregmem;
+    MemoryRegion gic_iomem_alias;
+    MemoryRegion container;
+    uint32_t num_irq;
+} nvic_state;
+
+#define TYPE_NVIC "armv7m_nvic"
+/**
+ * NVICClass:
+ * @parent_reset: the parent class' reset handler.
+ *
+ * A model of the v7M NVIC and System Controller
+ */
+typedef struct NVICClass {
+    /*< private >*/
+    ARMGICClass parent_class;
+    /*< public >*/
+    DeviceRealize parent_realize;
+    void (*parent_reset)(DeviceState *dev);
+} NVICClass;
+
+#define NVIC_CLASS(klass) \
+    OBJECT_CLASS_CHECK(NVICClass, (klass), TYPE_NVIC)
+#define NVIC_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(NVICClass, (obj), TYPE_NVIC)
+#define NVIC(obj) \
+    OBJECT_CHECK(nvic_state, (obj), TYPE_NVIC)
+
+static const uint8_t nvic_id[] = {
+    0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1
+};
+
+/* qemu timers run at 1GHz.   We want something closer to 1MHz.  */
+#define SYSTICK_SCALE 1000ULL
+
+#define SYSTICK_ENABLE    (1 << 0)
+#define SYSTICK_TICKINT   (1 << 1)
+#define SYSTICK_CLKSOURCE (1 << 2)
+#define SYSTICK_COUNTFLAG (1 << 16)
+
+int system_clock_scale;
+
+/* Conversion factor from qemu timer to SysTick frequencies.  */
+static inline int64_t systick_scale(nvic_state *s)
+{
+    if (s->systick.control & SYSTICK_CLKSOURCE)
+        return system_clock_scale;
+    else
+        return 1000;
+}
+
+static void systick_reload(nvic_state *s, int reset)
+{
+    if (reset)
+        s->systick.tick = qemu_get_clock_ns(vm_clock);
+    s->systick.tick += (s->systick.reload + 1) * systick_scale(s);
+    qemu_mod_timer(s->systick.timer, s->systick.tick);
+}
+
+static void systick_timer_tick(void * opaque)
+{
+    nvic_state *s = (nvic_state *)opaque;
+    s->systick.control |= SYSTICK_COUNTFLAG;
+    if (s->systick.control & SYSTICK_TICKINT) {
+        /* Trigger the interrupt.  */
+        armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
+    }
+    if (s->systick.reload == 0) {
+        s->systick.control &= ~SYSTICK_ENABLE;
+    } else {
+        systick_reload(s, 0);
+    }
+}
+
+static void systick_reset(nvic_state *s)
+{
+    s->systick.control = 0;
+    s->systick.reload = 0;
+    s->systick.tick = 0;
+    qemu_del_timer(s->systick.timer);
+}
+
+/* The external routines use the hardware vector numbering, ie. the first
+   IRQ is #16.  The internal GIC routines use #32 as the first IRQ.  */
+void armv7m_nvic_set_pending(void *opaque, int irq)
+{
+    nvic_state *s = (nvic_state *)opaque;
+    if (irq >= 16)
+        irq += 16;
+    gic_set_pending_private(&s->gic, 0, irq);
+}
+
+/* Make pending IRQ active.  */
+int armv7m_nvic_acknowledge_irq(void *opaque)
+{
+    nvic_state *s = (nvic_state *)opaque;
+    uint32_t irq;
+
+    irq = gic_acknowledge_irq(&s->gic, 0);
+    if (irq == 1023)
+        hw_error("Interrupt but no vector\n");
+    if (irq >= 32)
+        irq -= 16;
+    return irq;
+}
+
+void armv7m_nvic_complete_irq(void *opaque, int irq)
+{
+    nvic_state *s = (nvic_state *)opaque;
+    if (irq >= 16)
+        irq += 16;
+    gic_complete_irq(&s->gic, 0, irq);
+}
+
+static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
+{
+    uint32_t val;
+    int irq;
+
+    switch (offset) {
+    case 4: /* Interrupt Control Type.  */
+        return (s->num_irq / 32) - 1;
+    case 0x10: /* SysTick Control and Status.  */
+        val = s->systick.control;
+        s->systick.control &= ~SYSTICK_COUNTFLAG;
+        return val;
+    case 0x14: /* SysTick Reload Value.  */
+        return s->systick.reload;
+    case 0x18: /* SysTick Current Value.  */
+        {
+            int64_t t;
+            if ((s->systick.control & SYSTICK_ENABLE) == 0)
+                return 0;
+            t = qemu_get_clock_ns(vm_clock);
+            if (t >= s->systick.tick)
+                return 0;
+            val = ((s->systick.tick - (t + 1)) / systick_scale(s)) + 1;
+            /* The interrupt in triggered when the timer reaches zero.
+               However the counter is not reloaded until the next clock
+               tick.  This is a hack to return zero during the first tick.  */
+            if (val > s->systick.reload)
+                val = 0;
+            return val;
+        }
+    case 0x1c: /* SysTick Calibration Value.  */
+        return 10000;
+    case 0xd00: /* CPUID Base.  */
+        return cpu_single_env->cp15.c0_cpuid;
+    case 0xd04: /* Interrypt Control State.  */
+        /* VECTACTIVE */
+        val = s->gic.running_irq[0];
+        if (val == 1023) {
+            val = 0;
+        } else if (val >= 32) {
+            val -= 16;
+        }
+        /* RETTOBASE */
+        if (s->gic.running_irq[0] == 1023
+                || s->gic.last_active[s->gic.running_irq[0]][0] == 1023) {
+            val |= (1 << 11);
+        }
+        /* VECTPENDING */
+        if (s->gic.current_pending[0] != 1023)
+            val |= (s->gic.current_pending[0] << 12);
+        /* ISRPENDING */
+        for (irq = 32; irq < s->num_irq; irq++) {
+            if (s->gic.irq_state[irq].pending) {
+                val |= (1 << 22);
+                break;
+            }
+        }
+        /* PENDSTSET */
+        if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending)
+            val |= (1 << 26);
+        /* PENDSVSET */
+        if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending)
+            val |= (1 << 28);
+        /* NMIPENDSET */
+        if (s->gic.irq_state[ARMV7M_EXCP_NMI].pending)
+            val |= (1 << 31);
+        return val;
+    case 0xd08: /* Vector Table Offset.  */
+        return cpu_single_env->v7m.vecbase;
+    case 0xd0c: /* Application Interrupt/Reset Control.  */
+        return 0xfa05000;
+    case 0xd10: /* System Control.  */
+        /* TODO: Implement SLEEPONEXIT.  */
+        return 0;
+    case 0xd14: /* Configuration Control.  */
+        /* TODO: Implement Configuration Control bits.  */
+        return 0;
+    case 0xd24: /* System Handler Status.  */
+        val = 0;
+        if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
+        if (s->gic.irq_state[ARMV7M_EXCP_BUS].active) val |= (1 << 1);
+        if (s->gic.irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3);
+        if (s->gic.irq_state[ARMV7M_EXCP_SVC].active) val |= (1 << 7);
+        if (s->gic.irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8);
+        if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10);
+        if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11);
+        if (s->gic.irq_state[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12);
+        if (s->gic.irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13);
+        if (s->gic.irq_state[ARMV7M_EXCP_BUS].pending) val |= (1 << 14);
+        if (s->gic.irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15);
+        if (s->gic.irq_state[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16);
+        if (s->gic.irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17);
+        if (s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18);
+        return val;
+    case 0xd28: /* Configurable Fault Status.  */
+        /* TODO: Implement Fault Status.  */
+        qemu_log_mask(LOG_UNIMP, "Configurable Fault Status unimplemented\n");
+        return 0;
+    case 0xd2c: /* Hard Fault Status.  */
+    case 0xd30: /* Debug Fault Status.  */
+    case 0xd34: /* Mem Manage Address.  */
+    case 0xd38: /* Bus Fault Address.  */
+    case 0xd3c: /* Aux Fault Status.  */
+        /* TODO: Implement fault status registers.  */
+        qemu_log_mask(LOG_UNIMP, "Fault status registers unimplemented\n");
+        return 0;
+    case 0xd40: /* PFR0.  */
+        return 0x00000030;
+    case 0xd44: /* PRF1.  */
+        return 0x00000200;
+    case 0xd48: /* DFR0.  */
+        return 0x00100000;
+    case 0xd4c: /* AFR0.  */
+        return 0x00000000;
+    case 0xd50: /* MMFR0.  */
+        return 0x00000030;
+    case 0xd54: /* MMFR1.  */
+        return 0x00000000;
+    case 0xd58: /* MMFR2.  */
+        return 0x00000000;
+    case 0xd5c: /* MMFR3.  */
+        return 0x00000000;
+    case 0xd60: /* ISAR0.  */
+        return 0x01141110;
+    case 0xd64: /* ISAR1.  */
+        return 0x02111000;
+    case 0xd68: /* ISAR2.  */
+        return 0x21112231;
+    case 0xd6c: /* ISAR3.  */
+        return 0x01111110;
+    case 0xd70: /* ISAR4.  */
+        return 0x01310102;
+    /* TODO: Implement debug registers.  */
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
+        return 0;
+    }
+}
+
+static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value)
+{
+    uint32_t oldval;
+    switch (offset) {
+    case 0x10: /* SysTick Control and Status.  */
+        oldval = s->systick.control;
+        s->systick.control &= 0xfffffff8;
+        s->systick.control |= value & 7;
+        if ((oldval ^ value) & SYSTICK_ENABLE) {
+            int64_t now = qemu_get_clock_ns(vm_clock);
+            if (value & SYSTICK_ENABLE) {
+                if (s->systick.tick) {
+                    s->systick.tick += now;
+                    qemu_mod_timer(s->systick.timer, s->systick.tick);
+                } else {
+                    systick_reload(s, 1);
+                }
+            } else {
+                qemu_del_timer(s->systick.timer);
+                s->systick.tick -= now;
+                if (s->systick.tick < 0)
+                  s->systick.tick = 0;
+            }
+        } else if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
+            /* This is a hack. Force the timer to be reloaded
+               when the reference clock is changed.  */
+            systick_reload(s, 1);
+        }
+        break;
+    case 0x14: /* SysTick Reload Value.  */
+        s->systick.reload = value;
+        break;
+    case 0x18: /* SysTick Current Value.  Writes reload the timer.  */
+        systick_reload(s, 1);
+        s->systick.control &= ~SYSTICK_COUNTFLAG;
+        break;
+    case 0xd04: /* Interrupt Control State.  */
+        if (value & (1 << 31)) {
+            armv7m_nvic_set_pending(s, ARMV7M_EXCP_NMI);
+        }
+        if (value & (1 << 28)) {
+            armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV);
+        } else if (value & (1 << 27)) {
+            s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending = 0;
+            gic_update(&s->gic);
+        }
+        if (value & (1 << 26)) {
+            armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
+        } else if (value & (1 << 25)) {
+            s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending = 0;
+            gic_update(&s->gic);
+        }
+        break;
+    case 0xd08: /* Vector Table Offset.  */
+        cpu_single_env->v7m.vecbase = value & 0xffffff80;
+        break;
+    case 0xd0c: /* Application Interrupt/Reset Control.  */
+        if ((value >> 16) == 0x05fa) {
+            if (value & 2) {
+                qemu_log_mask(LOG_UNIMP, "VECTCLRACTIVE unimplemented\n");
+            }
+            if (value & 5) {
+                qemu_log_mask(LOG_UNIMP, "AIRCR system reset unimplemented\n");
+            }
+        }
+        break;
+    case 0xd10: /* System Control.  */
+    case 0xd14: /* Configuration Control.  */
+        /* TODO: Implement control registers.  */
+        qemu_log_mask(LOG_UNIMP, "NVIC: SCR and CCR unimplemented\n");
+        break;
+    case 0xd24: /* System Handler Control.  */
+        /* TODO: Real hardware allows you to set/clear the active bits
+           under some circumstances.  We don't implement this.  */
+        s->gic.irq_state[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
+        s->gic.irq_state[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
+        s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0;
+        break;
+    case 0xd28: /* Configurable Fault Status.  */
+    case 0xd2c: /* Hard Fault Status.  */
+    case 0xd30: /* Debug Fault Status.  */
+    case 0xd34: /* Mem Manage Address.  */
+    case 0xd38: /* Bus Fault Address.  */
+    case 0xd3c: /* Aux Fault Status.  */
+        qemu_log_mask(LOG_UNIMP,
+                      "NVIC: fault status registers unimplemented\n");
+        break;
+    case 0xf00: /* Software Triggered Interrupt Register */
+        if ((value & 0x1ff) < s->num_irq) {
+            gic_set_pending_private(&s->gic, 0, value & 0x1ff);
+        }
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "NVIC: Bad write offset 0x%x\n", offset);
+    }
+}
+
+static uint64_t nvic_sysreg_read(void *opaque, hwaddr addr,
+                                 unsigned size)
+{
+    nvic_state *s = (nvic_state *)opaque;
+    uint32_t offset = addr;
+    int i;
+    uint32_t val;
+
+    switch (offset) {
+    case 0xd18 ... 0xd23: /* System Handler Priority.  */
+        val = 0;
+        for (i = 0; i < size; i++) {
+            val |= s->gic.priority1[(offset - 0xd14) + i][0] << (i * 8);
+        }
+        return val;
+    case 0xfe0 ... 0xfff: /* ID.  */
+        if (offset & 3) {
+            return 0;
+        }
+        return nvic_id[(offset - 0xfe0) >> 2];
+    }
+    if (size == 4) {
+        return nvic_readl(s, offset);
+    }
+    qemu_log_mask(LOG_GUEST_ERROR,
+                  "NVIC: Bad read of size %d at offset 0x%x\n", size, offset);
+    return 0;
+}
+
+static void nvic_sysreg_write(void *opaque, hwaddr addr,
+                              uint64_t value, unsigned size)
+{
+    nvic_state *s = (nvic_state *)opaque;
+    uint32_t offset = addr;
+    int i;
+
+    switch (offset) {
+    case 0xd18 ... 0xd23: /* System Handler Priority.  */
+        for (i = 0; i < size; i++) {
+            s->gic.priority1[(offset - 0xd14) + i][0] =
+                (value >> (i * 8)) & 0xff;
+        }
+        gic_update(&s->gic);
+        return;
+    }
+    if (size == 4) {
+        nvic_writel(s, offset, value);
+        return;
+    }
+    qemu_log_mask(LOG_GUEST_ERROR,
+                  "NVIC: Bad write of size %d at offset 0x%x\n", size, offset);
+}
+
+static const MemoryRegionOps nvic_sysreg_ops = {
+    .read = nvic_sysreg_read,
+    .write = nvic_sysreg_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_nvic = {
+    .name = "armv7m_nvic",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(systick.control, nvic_state),
+        VMSTATE_UINT32(systick.reload, nvic_state),
+        VMSTATE_INT64(systick.tick, nvic_state),
+        VMSTATE_TIMER(systick.timer, nvic_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void armv7m_nvic_reset(DeviceState *dev)
+{
+    nvic_state *s = NVIC(dev);
+    NVICClass *nc = NVIC_GET_CLASS(s);
+    nc->parent_reset(dev);
+    /* Common GIC reset resets to disabled; the NVIC doesn't have
+     * per-CPU interfaces so mark our non-existent CPU interface
+     * as enabled by default, and with a priority mask which allows
+     * all interrupts through.
+     */
+    s->gic.cpu_enabled[0] = true;
+    s->gic.priority_mask[0] = 0x100;
+    /* The NVIC as a whole is always enabled. */
+    s->gic.enabled = true;
+    systick_reset(s);
+}
+
+static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
+{
+    nvic_state *s = NVIC(dev);
+    NVICClass *nc = NVIC_GET_CLASS(s);
+
+    /* The NVIC always has only one CPU */
+    s->gic.num_cpu = 1;
+    /* Tell the common code we're an NVIC */
+    s->gic.revision = 0xffffffff;
+    s->num_irq = s->gic.num_irq;
+    nc->parent_realize(dev, errp);
+    if (error_is_set(errp)) {
+        return;
+    }
+    gic_init_irqs_and_distributor(&s->gic, s->num_irq);
+    /* The NVIC and system controller register area looks like this:
+     *  0..0xff : system control registers, including systick
+     *  0x100..0xcff : GIC-like registers
+     *  0xd00..0xfff : system control registers
+     * We use overlaying to put the GIC like registers
+     * over the top of the system control register region.
+     */
+    memory_region_init(&s->container, "nvic", 0x1000);
+    /* The system register region goes at the bottom of the priority
+     * stack as it covers the whole page.
+     */
+    memory_region_init_io(&s->sysregmem, &nvic_sysreg_ops, s,
+                          "nvic_sysregs", 0x1000);
+    memory_region_add_subregion(&s->container, 0, &s->sysregmem);
+    /* Alias the GIC region so we can get only the section of it
+     * we need, and layer it on top of the system register region.
+     */
+    memory_region_init_alias(&s->gic_iomem_alias, "nvic-gic", &s->gic.iomem,
+                             0x100, 0xc00);
+    memory_region_add_subregion_overlap(&s->container, 0x100,
+                                        &s->gic_iomem_alias, 1);
+    /* Map the whole thing into system memory at the location required
+     * by the v7M architecture.
+     */
+    memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->container);
+    s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s);
+}
+
+static void armv7m_nvic_instance_init(Object *obj)
+{
+    /* We have a different default value for the num-irq property
+     * than our superclass. This function runs after qdev init
+     * has set the defaults from the Property array and before
+     * any user-specified property setting, so just modify the
+     * value in the GICState struct.
+     */
+    GICState *s = ARM_GIC_COMMON(obj);
+    /* The ARM v7m may have anything from 0 to 496 external interrupt
+     * IRQ lines. We default to 64. Other boards may differ and should
+     * set the num-irq property appropriately.
+     */
+    s->num_irq = 64;
+}
+
+static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
+{
+    NVICClass *nc = NVIC_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    nc->parent_reset = dc->reset;
+    nc->parent_realize = dc->realize;
+    dc->vmsd  = &vmstate_nvic;
+    dc->reset = armv7m_nvic_reset;
+    dc->realize = armv7m_nvic_realize;
+}
+
+static const TypeInfo armv7m_nvic_info = {
+    .name          = TYPE_NVIC,
+    .parent        = TYPE_ARM_GIC_COMMON,
+    .instance_init = armv7m_nvic_instance_init,
+    .instance_size = sizeof(nvic_state),
+    .class_init    = armv7m_nvic_class_init,
+    .class_size    = sizeof(NVICClass),
+};
+
+static void armv7m_nvic_register_types(void)
+{
+    type_register_static(&armv7m_nvic_info);
+}
+
+type_init(armv7m_nvic_register_types)
diff --git a/hw/intc/etraxfs_pic.c b/hw/intc/etraxfs_pic.c
new file mode 100644 (file)
index 0000000..635103c
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * QEMU ETRAX Interrupt Controller.
+ *
+ * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/hw.h"
+//#include "pc.h"
+//#include "etraxfs.h"
+
+#define D(x)
+
+#define R_RW_MASK   0
+#define R_R_VECT    1
+#define R_R_MASKED_VECT 2
+#define R_R_NMI     3
+#define R_R_GURU    4
+#define R_MAX       5
+
+struct etrax_pic
+{
+    SysBusDevice busdev;
+    MemoryRegion mmio;
+    void *interrupt_vector;
+    qemu_irq parent_irq;
+    qemu_irq parent_nmi;
+    uint32_t regs[R_MAX];
+};
+
+static void pic_update(struct etrax_pic *fs)
+{   
+    uint32_t vector = 0;
+    int i;
+
+    fs->regs[R_R_MASKED_VECT] = fs->regs[R_R_VECT] & fs->regs[R_RW_MASK];
+
+    /* The ETRAX interrupt controller signals interrupts to the core
+       through an interrupt request wire and an irq vector bus. If 
+       multiple interrupts are simultaneously active it chooses vector 
+       0x30 and lets the sw choose the priorities.  */
+    if (fs->regs[R_R_MASKED_VECT]) {
+        uint32_t mv = fs->regs[R_R_MASKED_VECT];
+        for (i = 0; i < 31; i++) {
+            if (mv & 1) {
+                vector = 0x31 + i;
+                /* Check for multiple interrupts.  */
+                if (mv > 1)
+                    vector = 0x30;
+                break;
+            }
+            mv >>= 1;
+        }
+    }
+
+    if (fs->interrupt_vector) {
+        /* hack alert: ptr property */
+        *(uint32_t*)(fs->interrupt_vector) = vector;
+    }
+    qemu_set_irq(fs->parent_irq, !!vector);
+}
+
+static uint64_t
+pic_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    struct etrax_pic *fs = opaque;
+    uint32_t rval;
+
+    rval = fs->regs[addr >> 2];
+    D(printf("%s %x=%x\n", __func__, addr, rval));
+    return rval;
+}
+
+static void pic_write(void *opaque, hwaddr addr,
+                      uint64_t value, unsigned int size)
+{
+    struct etrax_pic *fs = opaque;
+    D(printf("%s addr=%x val=%x\n", __func__, addr, value));
+
+    if (addr == R_RW_MASK) {
+        fs->regs[R_RW_MASK] = value;
+        pic_update(fs);
+    }
+}
+
+static const MemoryRegionOps pic_ops = {
+    .read = pic_read,
+    .write = pic_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static void nmi_handler(void *opaque, int irq, int level)
+{   
+    struct etrax_pic *fs = (void *)opaque;
+    uint32_t mask;
+
+    mask = 1 << irq;
+    if (level)
+        fs->regs[R_R_NMI] |= mask;
+    else
+        fs->regs[R_R_NMI] &= ~mask;
+
+    qemu_set_irq(fs->parent_nmi, !!fs->regs[R_R_NMI]);
+}
+
+static void irq_handler(void *opaque, int irq, int level)
+{   
+    struct etrax_pic *fs = (void *)opaque;
+
+    if (irq >= 30)
+        return nmi_handler(opaque, irq, level);
+
+    irq -= 1;
+    fs->regs[R_R_VECT] &= ~(1 << irq);
+    fs->regs[R_R_VECT] |= (!!level << irq);
+    pic_update(fs);
+}
+
+static int etraxfs_pic_init(SysBusDevice *dev)
+{
+    struct etrax_pic *s = FROM_SYSBUS(typeof (*s), dev);
+
+    qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
+    sysbus_init_irq(dev, &s->parent_irq);
+    sysbus_init_irq(dev, &s->parent_nmi);
+
+    memory_region_init_io(&s->mmio, &pic_ops, s, "etraxfs-pic", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->mmio);
+    return 0;
+}
+
+static Property etraxfs_pic_properties[] = {
+    DEFINE_PROP_PTR("interrupt_vector", struct etrax_pic, interrupt_vector),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void etraxfs_pic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = etraxfs_pic_init;
+    dc->props = etraxfs_pic_properties;
+}
+
+static const TypeInfo etraxfs_pic_info = {
+    .name          = "etraxfs,pic",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct etrax_pic),
+    .class_init    = etraxfs_pic_class_init,
+};
+
+static void etraxfs_pic_register_types(void)
+{
+    type_register_static(&etraxfs_pic_info);
+}
+
+type_init(etraxfs_pic_register_types)
diff --git a/hw/intc/exynos4210_combiner.c b/hw/intc/exynos4210_combiner.c
new file mode 100644 (file)
index 0000000..6874287
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * Samsung exynos4210 Interrupt Combiner
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
+ * All rights reserved.
+ *
+ * Evgeny Voevodin <e.voevodin@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Exynos4210 Combiner represents an OR gate for SOC's IRQ lines. It combines
+ * IRQ sources into groups and provides signal output to GIC from each group. It
+ * is driven by common mask and enable/disable logic. Take a note that not all
+ * IRQs are passed to GIC through Combiner.
+ */
+
+#include "hw/sysbus.h"
+
+#include "hw/arm/exynos4210.h"
+
+//#define DEBUG_COMBINER
+
+#ifdef DEBUG_COMBINER
+#define DPRINTF(fmt, ...) \
+        do { fprintf(stdout, "COMBINER: [%s:%d] " fmt, __func__ , __LINE__, \
+                ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#define    IIC_NGRP        64            /* Internal Interrupt Combiner
+                                            Groups number */
+#define    IIC_NIRQ        (IIC_NGRP * 8)/* Internal Interrupt Combiner
+                                            Interrupts number */
+#define IIC_REGION_SIZE    0x108         /* Size of memory mapped region */
+#define IIC_REGSET_SIZE    0x41
+
+/*
+ * State for each output signal of internal combiner
+ */
+typedef struct CombinerGroupState {
+    uint8_t src_mask;            /* 1 - source enabled, 0 - disabled */
+    uint8_t src_pending;        /* Pending source interrupts before masking */
+} CombinerGroupState;
+
+typedef struct Exynos4210CombinerState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    struct CombinerGroupState group[IIC_NGRP];
+    uint32_t reg_set[IIC_REGSET_SIZE];
+    uint32_t icipsr[2];
+    uint32_t external;          /* 1 means that this combiner is external */
+
+    qemu_irq output_irq[IIC_NGRP];
+} Exynos4210CombinerState;
+
+static const VMStateDescription vmstate_exynos4210_combiner_group_state = {
+    .name = "exynos4210.combiner.groupstate",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(src_mask, CombinerGroupState),
+        VMSTATE_UINT8(src_pending, CombinerGroupState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_exynos4210_combiner = {
+    .name = "exynos4210.combiner",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT_ARRAY(group, Exynos4210CombinerState, IIC_NGRP, 0,
+                vmstate_exynos4210_combiner_group_state, CombinerGroupState),
+        VMSTATE_UINT32_ARRAY(reg_set, Exynos4210CombinerState,
+                IIC_REGSET_SIZE),
+        VMSTATE_UINT32_ARRAY(icipsr, Exynos4210CombinerState, 2),
+        VMSTATE_UINT32(external, Exynos4210CombinerState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/*
+ * Get Combiner input GPIO into irqs structure
+ */
+void exynos4210_combiner_get_gpioin(Exynos4210Irq *irqs, DeviceState *dev,
+        int ext)
+{
+    int n;
+    int bit;
+    int max;
+    qemu_irq *irq;
+
+    max = ext ? EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ :
+        EXYNOS4210_MAX_INT_COMBINER_IN_IRQ;
+    irq = ext ? irqs->ext_combiner_irq : irqs->int_combiner_irq;
+
+    /*
+     * Some IRQs of Int/External Combiner are going to two Combiners groups,
+     * so let split them.
+     */
+    for (n = 0; n < max; n++) {
+
+        bit = EXYNOS4210_COMBINER_GET_BIT_NUM(n);
+
+        switch (n) {
+        /* MDNIE_LCD1 INTG1 */
+        case EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 0) ...
+             EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 3):
+            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
+                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(0, bit + 4)]);
+            continue;
+
+        /* TMU INTG3 */
+        case EXYNOS4210_COMBINER_GET_IRQ_NUM(3, 4):
+            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
+                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(2, bit)]);
+            continue;
+
+        /* LCD1 INTG12 */
+        case EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 0) ...
+             EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 3):
+            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
+                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(11, bit + 4)]);
+            continue;
+
+        /* Multi-Core Timer INTG12 */
+        case EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 4) ...
+             EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 8):
+               irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
+                       irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
+            continue;
+
+        /* Multi-Core Timer INTG35 */
+        case EXYNOS4210_COMBINER_GET_IRQ_NUM(35, 4) ...
+             EXYNOS4210_COMBINER_GET_IRQ_NUM(35, 8):
+            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
+                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
+            continue;
+
+        /* Multi-Core Timer INTG51 */
+        case EXYNOS4210_COMBINER_GET_IRQ_NUM(51, 4) ...
+             EXYNOS4210_COMBINER_GET_IRQ_NUM(51, 8):
+            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
+                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
+            continue;
+
+        /* Multi-Core Timer INTG53 */
+        case EXYNOS4210_COMBINER_GET_IRQ_NUM(53, 4) ...
+             EXYNOS4210_COMBINER_GET_IRQ_NUM(53, 8):
+            irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n),
+                    irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]);
+            continue;
+        }
+
+        irq[n] = qdev_get_gpio_in(dev, n);
+    }
+}
+
+static uint64_t
+exynos4210_combiner_read(void *opaque, hwaddr offset, unsigned size)
+{
+    struct Exynos4210CombinerState *s =
+            (struct Exynos4210CombinerState *)opaque;
+    uint32_t req_quad_base_n;    /* Base of registers quad. Multiply it by 4 and
+                                   get a start of corresponding group quad */
+    uint32_t grp_quad_base_n;    /* Base of group quad */
+    uint32_t reg_n;              /* Register number inside the quad */
+    uint32_t val;
+
+    req_quad_base_n = offset >> 4;
+    grp_quad_base_n = req_quad_base_n << 2;
+    reg_n = (offset - (req_quad_base_n << 4)) >> 2;
+
+    if (req_quad_base_n >= IIC_NGRP) {
+        /* Read of ICIPSR register */
+        return s->icipsr[reg_n];
+    }
+
+    val = 0;
+
+    switch (reg_n) {
+    /* IISTR */
+    case 2:
+        val |= s->group[grp_quad_base_n].src_pending;
+        val |= s->group[grp_quad_base_n + 1].src_pending << 8;
+        val |= s->group[grp_quad_base_n + 2].src_pending << 16;
+        val |= s->group[grp_quad_base_n + 3].src_pending << 24;
+        break;
+    /* IIMSR */
+    case 3:
+        val |= s->group[grp_quad_base_n].src_mask &
+        s->group[grp_quad_base_n].src_pending;
+        val |= (s->group[grp_quad_base_n + 1].src_mask &
+                s->group[grp_quad_base_n + 1].src_pending) << 8;
+        val |= (s->group[grp_quad_base_n + 2].src_mask &
+                s->group[grp_quad_base_n + 2].src_pending) << 16;
+        val |= (s->group[grp_quad_base_n + 3].src_mask &
+                s->group[grp_quad_base_n + 3].src_pending) << 24;
+        break;
+    default:
+        if (offset >> 2 >= IIC_REGSET_SIZE) {
+            hw_error("exynos4210.combiner: overflow of reg_set by 0x"
+                    TARGET_FMT_plx "offset\n", offset);
+        }
+        val = s->reg_set[offset >> 2];
+        return 0;
+    }
+    return val;
+}
+
+static void exynos4210_combiner_update(void *opaque, uint8_t group_n)
+{
+    struct Exynos4210CombinerState *s =
+            (struct Exynos4210CombinerState *)opaque;
+
+    /* Send interrupt if needed */
+    if (s->group[group_n].src_mask & s->group[group_n].src_pending) {
+#ifdef DEBUG_COMBINER
+        if (group_n != 26) {
+            /* skip uart */
+            DPRINTF("%s raise IRQ[%d]\n", s->external ? "EXT" : "INT", group_n);
+        }
+#endif
+
+        /* Set Combiner interrupt pending status after masking */
+        if (group_n >= 32) {
+            s->icipsr[1] |= 1 << (group_n - 32);
+        } else {
+            s->icipsr[0] |= 1 << group_n;
+        }
+
+        qemu_irq_raise(s->output_irq[group_n]);
+    } else {
+#ifdef DEBUG_COMBINER
+        if (group_n != 26) {
+            /* skip uart */
+            DPRINTF("%s lower IRQ[%d]\n", s->external ? "EXT" : "INT", group_n);
+        }
+#endif
+
+        /* Set Combiner interrupt pending status after masking */
+        if (group_n >= 32) {
+            s->icipsr[1] &= ~(1 << (group_n - 32));
+        } else {
+            s->icipsr[0] &= ~(1 << group_n);
+        }
+
+        qemu_irq_lower(s->output_irq[group_n]);
+    }
+}
+
+static void exynos4210_combiner_write(void *opaque, hwaddr offset,
+        uint64_t val, unsigned size)
+{
+    struct Exynos4210CombinerState *s =
+            (struct Exynos4210CombinerState *)opaque;
+    uint32_t req_quad_base_n;    /* Base of registers quad. Multiply it by 4 and
+                                   get a start of corresponding group quad */
+    uint32_t grp_quad_base_n;    /* Base of group quad */
+    uint32_t reg_n;              /* Register number inside the quad */
+
+    req_quad_base_n = offset >> 4;
+    grp_quad_base_n = req_quad_base_n << 2;
+    reg_n = (offset - (req_quad_base_n << 4)) >> 2;
+
+    if (req_quad_base_n >= IIC_NGRP) {
+        hw_error("exynos4210.combiner: unallowed write access at offset 0x"
+                TARGET_FMT_plx "\n", offset);
+        return;
+    }
+
+    if (reg_n > 1) {
+        hw_error("exynos4210.combiner: unallowed write access at offset 0x"
+                TARGET_FMT_plx "\n", offset);
+        return;
+    }
+
+    if (offset >> 2 >= IIC_REGSET_SIZE) {
+        hw_error("exynos4210.combiner: overflow of reg_set by 0x"
+                TARGET_FMT_plx "offset\n", offset);
+    }
+    s->reg_set[offset >> 2] = val;
+
+    switch (reg_n) {
+    /* IIESR */
+    case 0:
+        /* FIXME: what if irq is pending, allowed by mask, and we allow it
+         * again. Interrupt will rise again! */
+
+        DPRINTF("%s enable IRQ for groups %d, %d, %d, %d\n",
+                s->external ? "EXT" : "INT",
+                grp_quad_base_n,
+                grp_quad_base_n + 1,
+                grp_quad_base_n + 2,
+                grp_quad_base_n + 3);
+
+        /* Enable interrupt sources */
+        s->group[grp_quad_base_n].src_mask |= val & 0xFF;
+        s->group[grp_quad_base_n + 1].src_mask |= (val & 0xFF00) >> 8;
+        s->group[grp_quad_base_n + 2].src_mask |= (val & 0xFF0000) >> 16;
+        s->group[grp_quad_base_n + 3].src_mask |= (val & 0xFF000000) >> 24;
+
+        exynos4210_combiner_update(s, grp_quad_base_n);
+        exynos4210_combiner_update(s, grp_quad_base_n + 1);
+        exynos4210_combiner_update(s, grp_quad_base_n + 2);
+        exynos4210_combiner_update(s, grp_quad_base_n + 3);
+        break;
+        /* IIECR */
+    case 1:
+        DPRINTF("%s disable IRQ for groups %d, %d, %d, %d\n",
+                s->external ? "EXT" : "INT",
+                grp_quad_base_n,
+                grp_quad_base_n + 1,
+                grp_quad_base_n + 2,
+                grp_quad_base_n + 3);
+
+        /* Disable interrupt sources */
+        s->group[grp_quad_base_n].src_mask &= ~(val & 0xFF);
+        s->group[grp_quad_base_n + 1].src_mask &= ~((val & 0xFF00) >> 8);
+        s->group[grp_quad_base_n + 2].src_mask &= ~((val & 0xFF0000) >> 16);
+        s->group[grp_quad_base_n + 3].src_mask &= ~((val & 0xFF000000) >> 24);
+
+        exynos4210_combiner_update(s, grp_quad_base_n);
+        exynos4210_combiner_update(s, grp_quad_base_n + 1);
+        exynos4210_combiner_update(s, grp_quad_base_n + 2);
+        exynos4210_combiner_update(s, grp_quad_base_n + 3);
+        break;
+    default:
+        hw_error("exynos4210.combiner: unallowed write access at offset 0x"
+                TARGET_FMT_plx "\n", offset);
+        break;
+    }
+}
+
+/* Get combiner group and bit from irq number */
+static uint8_t get_combiner_group_and_bit(int irq, uint8_t *bit)
+{
+    *bit = irq - ((irq >> 3) << 3);
+    return irq >> 3;
+}
+
+/* Process a change in an external IRQ input.  */
+static void exynos4210_combiner_handler(void *opaque, int irq, int level)
+{
+    struct Exynos4210CombinerState *s =
+            (struct Exynos4210CombinerState *)opaque;
+    uint8_t bit_n, group_n;
+
+    group_n = get_combiner_group_and_bit(irq, &bit_n);
+
+    if (s->external && group_n >= EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ) {
+        DPRINTF("%s unallowed IRQ group 0x%x\n", s->external ? "EXT" : "INT"
+                , group_n);
+        return;
+    }
+
+    if (level) {
+        s->group[group_n].src_pending |= 1 << bit_n;
+    } else {
+        s->group[group_n].src_pending &= ~(1 << bit_n);
+    }
+
+    exynos4210_combiner_update(s, group_n);
+}
+
+static void exynos4210_combiner_reset(DeviceState *d)
+{
+    struct Exynos4210CombinerState *s = (struct Exynos4210CombinerState *)d;
+
+    memset(&s->group, 0, sizeof(s->group));
+    memset(&s->reg_set, 0, sizeof(s->reg_set));
+
+    s->reg_set[0xC0 >> 2] = 0x01010101;
+    s->reg_set[0xC4 >> 2] = 0x01010101;
+    s->reg_set[0xD0 >> 2] = 0x01010101;
+    s->reg_set[0xD4 >> 2] = 0x01010101;
+}
+
+static const MemoryRegionOps exynos4210_combiner_ops = {
+    .read = exynos4210_combiner_read,
+    .write = exynos4210_combiner_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+/*
+ * Internal Combiner initialization.
+ */
+static int exynos4210_combiner_init(SysBusDevice *dev)
+{
+    unsigned int i;
+    struct Exynos4210CombinerState *s =
+            FROM_SYSBUS(struct Exynos4210CombinerState, dev);
+
+    /* Allocate general purpose input signals and connect a handler to each of
+     * them */
+    qdev_init_gpio_in(&s->busdev.qdev, exynos4210_combiner_handler, IIC_NIRQ);
+
+    /* Connect SysBusDev irqs to device specific irqs */
+    for (i = 0; i < IIC_NIRQ; i++) {
+        sysbus_init_irq(dev, &s->output_irq[i]);
+    }
+
+    memory_region_init_io(&s->iomem, &exynos4210_combiner_ops, s,
+            "exynos4210-combiner", IIC_REGION_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static Property exynos4210_combiner_properties[] = {
+    DEFINE_PROP_UINT32("external", Exynos4210CombinerState, external, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void exynos4210_combiner_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = exynos4210_combiner_init;
+    dc->reset = exynos4210_combiner_reset;
+    dc->props = exynos4210_combiner_properties;
+    dc->vmsd = &vmstate_exynos4210_combiner;
+}
+
+static const TypeInfo exynos4210_combiner_info = {
+    .name          = "exynos4210.combiner",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Exynos4210CombinerState),
+    .class_init    = exynos4210_combiner_class_init,
+};
+
+static void exynos4210_combiner_register_types(void)
+{
+    type_register_static(&exynos4210_combiner_info);
+}
+
+type_init(exynos4210_combiner_register_types)
diff --git a/hw/intc/exynos4210_gic.c b/hw/intc/exynos4210_gic.c
new file mode 100644 (file)
index 0000000..bad6dde
--- /dev/null
@@ -0,0 +1,462 @@
+/*
+ * Samsung exynos4210 GIC implementation. Based on hw/arm_gic.c
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
+ * All rights reserved.
+ *
+ * Evgeny Voevodin <e.voevodin@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/sysbus.h"
+#include "qemu-common.h"
+#include "hw/irq.h"
+#include "hw/arm/exynos4210.h"
+
+enum ExtGicId {
+    EXT_GIC_ID_MDMA_LCD0 = 66,
+    EXT_GIC_ID_PDMA0,
+    EXT_GIC_ID_PDMA1,
+    EXT_GIC_ID_TIMER0,
+    EXT_GIC_ID_TIMER1,
+    EXT_GIC_ID_TIMER2,
+    EXT_GIC_ID_TIMER3,
+    EXT_GIC_ID_TIMER4,
+    EXT_GIC_ID_MCT_L0,
+    EXT_GIC_ID_WDT,
+    EXT_GIC_ID_RTC_ALARM,
+    EXT_GIC_ID_RTC_TIC,
+    EXT_GIC_ID_GPIO_XB,
+    EXT_GIC_ID_GPIO_XA,
+    EXT_GIC_ID_MCT_L1,
+    EXT_GIC_ID_IEM_APC,
+    EXT_GIC_ID_IEM_IEC,
+    EXT_GIC_ID_NFC,
+    EXT_GIC_ID_UART0,
+    EXT_GIC_ID_UART1,
+    EXT_GIC_ID_UART2,
+    EXT_GIC_ID_UART3,
+    EXT_GIC_ID_UART4,
+    EXT_GIC_ID_MCT_G0,
+    EXT_GIC_ID_I2C0,
+    EXT_GIC_ID_I2C1,
+    EXT_GIC_ID_I2C2,
+    EXT_GIC_ID_I2C3,
+    EXT_GIC_ID_I2C4,
+    EXT_GIC_ID_I2C5,
+    EXT_GIC_ID_I2C6,
+    EXT_GIC_ID_I2C7,
+    EXT_GIC_ID_SPI0,
+    EXT_GIC_ID_SPI1,
+    EXT_GIC_ID_SPI2,
+    EXT_GIC_ID_MCT_G1,
+    EXT_GIC_ID_USB_HOST,
+    EXT_GIC_ID_USB_DEVICE,
+    EXT_GIC_ID_MODEMIF,
+    EXT_GIC_ID_HSMMC0,
+    EXT_GIC_ID_HSMMC1,
+    EXT_GIC_ID_HSMMC2,
+    EXT_GIC_ID_HSMMC3,
+    EXT_GIC_ID_SDMMC,
+    EXT_GIC_ID_MIPI_CSI_4LANE,
+    EXT_GIC_ID_MIPI_DSI_4LANE,
+    EXT_GIC_ID_MIPI_CSI_2LANE,
+    EXT_GIC_ID_MIPI_DSI_2LANE,
+    EXT_GIC_ID_ONENAND_AUDI,
+    EXT_GIC_ID_ROTATOR,
+    EXT_GIC_ID_FIMC0,
+    EXT_GIC_ID_FIMC1,
+    EXT_GIC_ID_FIMC2,
+    EXT_GIC_ID_FIMC3,
+    EXT_GIC_ID_JPEG,
+    EXT_GIC_ID_2D,
+    EXT_GIC_ID_PCIe,
+    EXT_GIC_ID_MIXER,
+    EXT_GIC_ID_HDMI,
+    EXT_GIC_ID_HDMI_I2C,
+    EXT_GIC_ID_MFC,
+    EXT_GIC_ID_TVENC,
+};
+
+enum ExtInt {
+    EXT_GIC_ID_EXTINT0 = 48,
+    EXT_GIC_ID_EXTINT1,
+    EXT_GIC_ID_EXTINT2,
+    EXT_GIC_ID_EXTINT3,
+    EXT_GIC_ID_EXTINT4,
+    EXT_GIC_ID_EXTINT5,
+    EXT_GIC_ID_EXTINT6,
+    EXT_GIC_ID_EXTINT7,
+    EXT_GIC_ID_EXTINT8,
+    EXT_GIC_ID_EXTINT9,
+    EXT_GIC_ID_EXTINT10,
+    EXT_GIC_ID_EXTINT11,
+    EXT_GIC_ID_EXTINT12,
+    EXT_GIC_ID_EXTINT13,
+    EXT_GIC_ID_EXTINT14,
+    EXT_GIC_ID_EXTINT15
+};
+
+/*
+ * External GIC sources which are not from External Interrupt Combiner or
+ * External Interrupts are starting from EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ,
+ * which is INTG16 in Internal Interrupt Combiner.
+ */
+
+static uint32_t
+combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = {
+    /* int combiner groups 16-19 */
+    { }, { }, { }, { },
+    /* int combiner group 20 */
+    { 0, EXT_GIC_ID_MDMA_LCD0 },
+    /* int combiner group 21 */
+    { EXT_GIC_ID_PDMA0, EXT_GIC_ID_PDMA1 },
+    /* int combiner group 22 */
+    { EXT_GIC_ID_TIMER0, EXT_GIC_ID_TIMER1, EXT_GIC_ID_TIMER2,
+            EXT_GIC_ID_TIMER3, EXT_GIC_ID_TIMER4 },
+    /* int combiner group 23 */
+    { EXT_GIC_ID_RTC_ALARM, EXT_GIC_ID_RTC_TIC },
+    /* int combiner group 24 */
+    { EXT_GIC_ID_GPIO_XB, EXT_GIC_ID_GPIO_XA },
+    /* int combiner group 25 */
+    { EXT_GIC_ID_IEM_APC, EXT_GIC_ID_IEM_IEC },
+    /* int combiner group 26 */
+    { EXT_GIC_ID_UART0, EXT_GIC_ID_UART1, EXT_GIC_ID_UART2, EXT_GIC_ID_UART3,
+            EXT_GIC_ID_UART4 },
+    /* int combiner group 27 */
+    { EXT_GIC_ID_I2C0, EXT_GIC_ID_I2C1, EXT_GIC_ID_I2C2, EXT_GIC_ID_I2C3,
+            EXT_GIC_ID_I2C4, EXT_GIC_ID_I2C5, EXT_GIC_ID_I2C6,
+            EXT_GIC_ID_I2C7 },
+    /* int combiner group 28 */
+    { EXT_GIC_ID_SPI0, EXT_GIC_ID_SPI1, EXT_GIC_ID_SPI2 , EXT_GIC_ID_USB_HOST},
+    /* int combiner group 29 */
+    { EXT_GIC_ID_HSMMC0, EXT_GIC_ID_HSMMC1, EXT_GIC_ID_HSMMC2,
+     EXT_GIC_ID_HSMMC3, EXT_GIC_ID_SDMMC },
+    /* int combiner group 30 */
+    { EXT_GIC_ID_MIPI_CSI_4LANE, EXT_GIC_ID_MIPI_CSI_2LANE },
+    /* int combiner group 31 */
+    { EXT_GIC_ID_MIPI_DSI_4LANE, EXT_GIC_ID_MIPI_DSI_2LANE },
+    /* int combiner group 32 */
+    { EXT_GIC_ID_FIMC0, EXT_GIC_ID_FIMC1 },
+    /* int combiner group 33 */
+    { EXT_GIC_ID_FIMC2, EXT_GIC_ID_FIMC3 },
+    /* int combiner group 34 */
+    { EXT_GIC_ID_ONENAND_AUDI, EXT_GIC_ID_NFC },
+    /* int combiner group 35 */
+    { 0, 0, 0, EXT_GIC_ID_MCT_L1, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 },
+    /* int combiner group 36 */
+    { EXT_GIC_ID_MIXER },
+    /* int combiner group 37 */
+    { EXT_GIC_ID_EXTINT4, EXT_GIC_ID_EXTINT5, EXT_GIC_ID_EXTINT6,
+     EXT_GIC_ID_EXTINT7 },
+    /* groups 38-50 */
+    { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { },
+    /* int combiner group 51 */
+    { EXT_GIC_ID_MCT_L0, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 },
+    /* group 52 */
+    { },
+    /* int combiner group 53 */
+    { EXT_GIC_ID_WDT, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 },
+    /* groups 54-63 */
+    { }, { }, { }, { }, { }, { }, { }, { }, { }, { }
+};
+
+#define EXYNOS4210_GIC_NIRQ 160
+
+#define EXYNOS4210_EXT_GIC_CPU_REGION_SIZE     0x10000
+#define EXYNOS4210_EXT_GIC_DIST_REGION_SIZE    0x10000
+
+#define EXYNOS4210_EXT_GIC_PER_CPU_OFFSET      0x8000
+#define EXYNOS4210_EXT_GIC_CPU_GET_OFFSET(n) \
+    ((n) * EXYNOS4210_EXT_GIC_PER_CPU_OFFSET)
+#define EXYNOS4210_EXT_GIC_DIST_GET_OFFSET(n) \
+    ((n) * EXYNOS4210_EXT_GIC_PER_CPU_OFFSET)
+
+#define EXYNOS4210_GIC_CPU_REGION_SIZE  0x100
+#define EXYNOS4210_GIC_DIST_REGION_SIZE 0x1000
+
+static void exynos4210_irq_handler(void *opaque, int irq, int level)
+{
+    Exynos4210Irq *s = (Exynos4210Irq *)opaque;
+
+    /* Bypass */
+    qemu_set_irq(s->board_irqs[irq], level);
+}
+
+/*
+ * Initialize exynos4210 IRQ subsystem stub.
+ */
+qemu_irq *exynos4210_init_irq(Exynos4210Irq *s)
+{
+    return qemu_allocate_irqs(exynos4210_irq_handler, s,
+            EXYNOS4210_MAX_INT_COMBINER_IN_IRQ);
+}
+
+/*
+ * Initialize board IRQs.
+ * These IRQs contain splitted Int/External Combiner and External Gic IRQs.
+ */
+void exynos4210_init_board_irqs(Exynos4210Irq *s)
+{
+    uint32_t grp, bit, irq_id, n;
+
+    for (n = 0; n < EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ; n++) {
+        s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
+                s->ext_combiner_irq[n]);
+
+        irq_id = 0;
+        if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 4) ||
+                n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 4)) {
+            /* MCT_G0 is passed to External GIC */
+            irq_id = EXT_GIC_ID_MCT_G0;
+        }
+        if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 5) ||
+                n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 5)) {
+            /* MCT_G1 is passed to External and GIC */
+            irq_id = EXT_GIC_ID_MCT_G1;
+        }
+        if (irq_id) {
+            s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
+                    s->ext_gic_irq[irq_id-32]);
+        }
+
+    }
+    for (; n < EXYNOS4210_MAX_INT_COMBINER_IN_IRQ; n++) {
+        /* these IDs are passed to Internal Combiner and External GIC */
+        grp = EXYNOS4210_COMBINER_GET_GRP_NUM(n);
+        bit = EXYNOS4210_COMBINER_GET_BIT_NUM(n);
+        irq_id = combiner_grp_to_gic_id[grp -
+                     EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][bit];
+
+        if (irq_id) {
+            s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
+                    s->ext_gic_irq[irq_id-32]);
+        }
+    }
+}
+
+/*
+ * Get IRQ number from exynos4210 IRQ subsystem stub.
+ * To identify IRQ source use internal combiner group and bit number
+ *  grp - group number
+ *  bit - bit number inside group
+ */
+uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit)
+{
+    return EXYNOS4210_COMBINER_GET_IRQ_NUM(grp, bit);
+}
+
+/********* GIC part *********/
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion cpu_container;
+    MemoryRegion dist_container;
+    MemoryRegion cpu_alias[EXYNOS4210_NCPUS];
+    MemoryRegion dist_alias[EXYNOS4210_NCPUS];
+    uint32_t num_cpu;
+    DeviceState *gic;
+} Exynos4210GicState;
+
+static void exynos4210_gic_set_irq(void *opaque, int irq, int level)
+{
+    Exynos4210GicState *s = (Exynos4210GicState *)opaque;
+    qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
+}
+
+static int exynos4210_gic_init(SysBusDevice *dev)
+{
+    Exynos4210GicState *s = FROM_SYSBUS(Exynos4210GicState, dev);
+    uint32_t i;
+    const char cpu_prefix[] = "exynos4210-gic-alias_cpu";
+    const char dist_prefix[] = "exynos4210-gic-alias_dist";
+    char cpu_alias_name[sizeof(cpu_prefix) + 3];
+    char dist_alias_name[sizeof(cpu_prefix) + 3];
+    SysBusDevice *busdev;
+
+    s->gic = qdev_create(NULL, "arm_gic");
+    qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
+    qdev_prop_set_uint32(s->gic, "num-irq", EXYNOS4210_GIC_NIRQ);
+    qdev_init_nofail(s->gic);
+    busdev = SYS_BUS_DEVICE(s->gic);
+
+    /* Pass through outbound IRQ lines from the GIC */
+    sysbus_pass_irq(dev, busdev);
+
+    /* Pass through inbound GPIO lines to the GIC */
+    qdev_init_gpio_in(&s->busdev.qdev, exynos4210_gic_set_irq,
+                      EXYNOS4210_GIC_NIRQ - 32);
+
+    memory_region_init(&s->cpu_container, "exynos4210-cpu-container",
+            EXYNOS4210_EXT_GIC_CPU_REGION_SIZE);
+    memory_region_init(&s->dist_container, "exynos4210-dist-container",
+            EXYNOS4210_EXT_GIC_DIST_REGION_SIZE);
+
+    for (i = 0; i < s->num_cpu; i++) {
+        /* Map CPU interface per SMP Core */
+        sprintf(cpu_alias_name, "%s%x", cpu_prefix, i);
+        memory_region_init_alias(&s->cpu_alias[i],
+                                 cpu_alias_name,
+                                 sysbus_mmio_get_region(busdev, 1),
+                                 0,
+                                 EXYNOS4210_GIC_CPU_REGION_SIZE);
+        memory_region_add_subregion(&s->cpu_container,
+                EXYNOS4210_EXT_GIC_CPU_GET_OFFSET(i), &s->cpu_alias[i]);
+
+        /* Map Distributor per SMP Core */
+        sprintf(dist_alias_name, "%s%x", dist_prefix, i);
+        memory_region_init_alias(&s->dist_alias[i],
+                                 dist_alias_name,
+                                 sysbus_mmio_get_region(busdev, 0),
+                                 0,
+                                 EXYNOS4210_GIC_DIST_REGION_SIZE);
+        memory_region_add_subregion(&s->dist_container,
+                EXYNOS4210_EXT_GIC_DIST_GET_OFFSET(i), &s->dist_alias[i]);
+    }
+
+    sysbus_init_mmio(dev, &s->cpu_container);
+    sysbus_init_mmio(dev, &s->dist_container);
+
+    return 0;
+}
+
+static Property exynos4210_gic_properties[] = {
+    DEFINE_PROP_UINT32("num-cpu", Exynos4210GicState, num_cpu, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void exynos4210_gic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = exynos4210_gic_init;
+    dc->props = exynos4210_gic_properties;
+}
+
+static const TypeInfo exynos4210_gic_info = {
+    .name          = "exynos4210.gic",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Exynos4210GicState),
+    .class_init    = exynos4210_gic_class_init,
+};
+
+static void exynos4210_gic_register_types(void)
+{
+    type_register_static(&exynos4210_gic_info);
+}
+
+type_init(exynos4210_gic_register_types)
+
+/* IRQ OR Gate struct.
+ *
+ * This device models an OR gate. There are n_in input qdev gpio lines and one
+ * output sysbus IRQ line. The output IRQ level is formed as OR between all
+ * gpio inputs.
+ */
+typedef struct {
+    SysBusDevice busdev;
+
+    uint32_t n_in;      /* inputs amount */
+    uint32_t *level;    /* input levels */
+    qemu_irq out;       /* output IRQ */
+} Exynos4210IRQGateState;
+
+static Property exynos4210_irq_gate_properties[] = {
+    DEFINE_PROP_UINT32("n_in", Exynos4210IRQGateState, n_in, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static const VMStateDescription vmstate_exynos4210_irq_gate = {
+    .name = "exynos4210.irq_gate",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields = (VMStateField[]) {
+        VMSTATE_VBUFFER_UINT32(level, Exynos4210IRQGateState, 1, NULL, 0, n_in),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* Process a change in IRQ input. */
+static void exynos4210_irq_gate_handler(void *opaque, int irq, int level)
+{
+    Exynos4210IRQGateState *s = (Exynos4210IRQGateState *)opaque;
+    uint32_t i;
+
+    assert(irq < s->n_in);
+
+    s->level[irq] = level;
+
+    for (i = 0; i < s->n_in; i++) {
+        if (s->level[i] >= 1) {
+            qemu_irq_raise(s->out);
+            return;
+        }
+    }
+
+    qemu_irq_lower(s->out);
+}
+
+static void exynos4210_irq_gate_reset(DeviceState *d)
+{
+    Exynos4210IRQGateState *s =
+            DO_UPCAST(Exynos4210IRQGateState, busdev.qdev, d);
+
+    memset(s->level, 0, s->n_in * sizeof(*s->level));
+}
+
+/*
+ * IRQ Gate initialization.
+ */
+static int exynos4210_irq_gate_init(SysBusDevice *dev)
+{
+    Exynos4210IRQGateState *s = FROM_SYSBUS(Exynos4210IRQGateState, dev);
+
+    /* Allocate general purpose input signals and connect a handler to each of
+     * them */
+    qdev_init_gpio_in(&s->busdev.qdev, exynos4210_irq_gate_handler, s->n_in);
+
+    s->level = g_malloc0(s->n_in * sizeof(*s->level));
+
+    sysbus_init_irq(dev, &s->out);
+
+    return 0;
+}
+
+static void exynos4210_irq_gate_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = exynos4210_irq_gate_init;
+    dc->reset = exynos4210_irq_gate_reset;
+    dc->vmsd = &vmstate_exynos4210_irq_gate;
+    dc->props = exynos4210_irq_gate_properties;
+}
+
+static const TypeInfo exynos4210_irq_gate_info = {
+    .name          = "exynos4210.irq_gate",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Exynos4210IRQGateState),
+    .class_init    = exynos4210_irq_gate_class_init,
+};
+
+static void exynos4210_irq_gate_register_types(void)
+{
+    type_register_static(&exynos4210_irq_gate_info);
+}
+
+type_init(exynos4210_irq_gate_register_types)
diff --git a/hw/intc/grlib_irqmp.c b/hw/intc/grlib_irqmp.c
new file mode 100644 (file)
index 0000000..68dfe6a
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * QEMU GRLIB IRQMP Emulator
+ *
+ * (Multiprocessor and extended interrupt not supported)
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/sysbus.h"
+#include "cpu.h"
+
+#include "hw/sparc/grlib.h"
+
+#include "trace.h"
+
+#define IRQMP_MAX_CPU 16
+#define IRQMP_REG_SIZE 256      /* Size of memory mapped registers */
+
+/* Memory mapped register offsets */
+#define LEVEL_OFFSET     0x00
+#define PENDING_OFFSET   0x04
+#define FORCE0_OFFSET    0x08
+#define CLEAR_OFFSET     0x0C
+#define MP_STATUS_OFFSET 0x10
+#define BROADCAST_OFFSET 0x14
+#define MASK_OFFSET      0x40
+#define FORCE_OFFSET     0x80
+#define EXTENDED_OFFSET  0xC0
+
+typedef struct IRQMPState IRQMPState;
+
+typedef struct IRQMP {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    void *set_pil_in;
+    void *set_pil_in_opaque;
+
+    IRQMPState *state;
+} IRQMP;
+
+struct IRQMPState {
+    uint32_t level;
+    uint32_t pending;
+    uint32_t clear;
+    uint32_t broadcast;
+
+    uint32_t mask[IRQMP_MAX_CPU];
+    uint32_t force[IRQMP_MAX_CPU];
+    uint32_t extended[IRQMP_MAX_CPU];
+
+    IRQMP    *parent;
+};
+
+static void grlib_irqmp_check_irqs(IRQMPState *state)
+{
+    uint32_t      pend   = 0;
+    uint32_t      level0 = 0;
+    uint32_t      level1 = 0;
+    set_pil_in_fn set_pil_in;
+
+    assert(state != NULL);
+    assert(state->parent != NULL);
+
+    /* IRQ for CPU 0 (no SMP support) */
+    pend = (state->pending | state->force[0])
+        & state->mask[0];
+
+    level0 = pend & ~state->level;
+    level1 = pend &  state->level;
+
+    trace_grlib_irqmp_check_irqs(state->pending, state->force[0],
+                                 state->mask[0], level1, level0);
+
+    set_pil_in = (set_pil_in_fn)state->parent->set_pil_in;
+
+    /* Trigger level1 interrupt first and level0 if there is no level1 */
+    if (level1 != 0) {
+        set_pil_in(state->parent->set_pil_in_opaque, level1);
+    } else {
+        set_pil_in(state->parent->set_pil_in_opaque, level0);
+    }
+}
+
+void grlib_irqmp_ack(DeviceState *dev, int intno)
+{
+    SysBusDevice *sdev;
+    IRQMP        *irqmp;
+    IRQMPState   *state;
+    uint32_t      mask;
+
+    assert(dev != NULL);
+
+    sdev = SYS_BUS_DEVICE(dev);
+    assert(sdev != NULL);
+
+    irqmp = FROM_SYSBUS(typeof(*irqmp), sdev);
+    assert(irqmp != NULL);
+
+    state = irqmp->state;
+    assert(state != NULL);
+
+    intno &= 15;
+    mask = 1 << intno;
+
+    trace_grlib_irqmp_ack(intno);
+
+    /* Clear registers */
+    state->pending  &= ~mask;
+    state->force[0] &= ~mask; /* Only CPU 0 (No SMP support) */
+
+    grlib_irqmp_check_irqs(state);
+}
+
+void grlib_irqmp_set_irq(void *opaque, int irq, int level)
+{
+    IRQMP      *irqmp;
+    IRQMPState *s;
+    int         i = 0;
+
+    assert(opaque != NULL);
+
+    irqmp = FROM_SYSBUS(typeof(*irqmp), SYS_BUS_DEVICE(opaque));
+    assert(irqmp != NULL);
+
+    s = irqmp->state;
+    assert(s         != NULL);
+    assert(s->parent != NULL);
+
+
+    if (level) {
+        trace_grlib_irqmp_set_irq(irq);
+
+        if (s->broadcast & 1 << irq) {
+            /* Broadcasted IRQ */
+            for (i = 0; i < IRQMP_MAX_CPU; i++) {
+                s->force[i] |= 1 << irq;
+            }
+        } else {
+            s->pending |= 1 << irq;
+        }
+        grlib_irqmp_check_irqs(s);
+
+    }
+}
+
+static uint64_t grlib_irqmp_read(void *opaque, hwaddr addr,
+                                 unsigned size)
+{
+    IRQMP      *irqmp = opaque;
+    IRQMPState *state;
+
+    assert(irqmp != NULL);
+    state = irqmp->state;
+    assert(state != NULL);
+
+    addr &= 0xff;
+
+    /* global registers */
+    switch (addr) {
+    case LEVEL_OFFSET:
+        return state->level;
+
+    case PENDING_OFFSET:
+        return state->pending;
+
+    case FORCE0_OFFSET:
+        /* This register is an "alias" for the force register of CPU 0 */
+        return state->force[0];
+
+    case CLEAR_OFFSET:
+    case MP_STATUS_OFFSET:
+        /* Always read as 0 */
+        return 0;
+
+    case BROADCAST_OFFSET:
+        return state->broadcast;
+
+    default:
+        break;
+    }
+
+    /* mask registers */
+    if (addr >= MASK_OFFSET && addr < FORCE_OFFSET) {
+        int cpu = (addr - MASK_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        return state->mask[cpu];
+    }
+
+    /* force registers */
+    if (addr >= FORCE_OFFSET && addr < EXTENDED_OFFSET) {
+        int cpu = (addr - FORCE_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        return state->force[cpu];
+    }
+
+    /* extended (not supported) */
+    if (addr >= EXTENDED_OFFSET && addr < IRQMP_REG_SIZE) {
+        int cpu = (addr - EXTENDED_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        return state->extended[cpu];
+    }
+
+    trace_grlib_irqmp_readl_unknown(addr);
+    return 0;
+}
+
+static void grlib_irqmp_write(void *opaque, hwaddr addr,
+                              uint64_t value, unsigned size)
+{
+    IRQMP      *irqmp = opaque;
+    IRQMPState *state;
+
+    assert(irqmp != NULL);
+    state = irqmp->state;
+    assert(state != NULL);
+
+    addr &= 0xff;
+
+    /* global registers */
+    switch (addr) {
+    case LEVEL_OFFSET:
+        value &= 0xFFFF << 1; /* clean up the value */
+        state->level = value;
+        return;
+
+    case PENDING_OFFSET:
+        /* Read Only */
+        return;
+
+    case FORCE0_OFFSET:
+        /* This register is an "alias" for the force register of CPU 0 */
+
+        value &= 0xFFFE; /* clean up the value */
+        state->force[0] = value;
+        grlib_irqmp_check_irqs(irqmp->state);
+        return;
+
+    case CLEAR_OFFSET:
+        value &= ~1; /* clean up the value */
+        state->pending &= ~value;
+        return;
+
+    case MP_STATUS_OFFSET:
+        /* Read Only (no SMP support) */
+        return;
+
+    case BROADCAST_OFFSET:
+        value &= 0xFFFE; /* clean up the value */
+        state->broadcast = value;
+        return;
+
+    default:
+        break;
+    }
+
+    /* mask registers */
+    if (addr >= MASK_OFFSET && addr < FORCE_OFFSET) {
+        int cpu = (addr - MASK_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        value &= ~1; /* clean up the value */
+        state->mask[cpu] = value;
+        grlib_irqmp_check_irqs(irqmp->state);
+        return;
+    }
+
+    /* force registers */
+    if (addr >= FORCE_OFFSET && addr < EXTENDED_OFFSET) {
+        int cpu = (addr - FORCE_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        uint32_t force = value & 0xFFFE;
+        uint32_t clear = (value >> 16) & 0xFFFE;
+        uint32_t old   = state->force[cpu];
+
+        state->force[cpu] = (old | force) & ~clear;
+        grlib_irqmp_check_irqs(irqmp->state);
+        return;
+    }
+
+    /* extended (not supported) */
+    if (addr >= EXTENDED_OFFSET && addr < IRQMP_REG_SIZE) {
+        int cpu = (addr - EXTENDED_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        value &= 0xF; /* clean up the value */
+        state->extended[cpu] = value;
+        return;
+    }
+
+    trace_grlib_irqmp_writel_unknown(addr, value);
+}
+
+static const MemoryRegionOps grlib_irqmp_ops = {
+    .read = grlib_irqmp_read,
+    .write = grlib_irqmp_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void grlib_irqmp_reset(DeviceState *d)
+{
+    IRQMP *irqmp = container_of(d, IRQMP, busdev.qdev);
+    assert(irqmp        != NULL);
+    assert(irqmp->state != NULL);
+
+    memset(irqmp->state, 0, sizeof *irqmp->state);
+    irqmp->state->parent = irqmp;
+}
+
+static int grlib_irqmp_init(SysBusDevice *dev)
+{
+    IRQMP *irqmp = FROM_SYSBUS(typeof(*irqmp), dev);
+
+    assert(irqmp != NULL);
+
+    /* Check parameters */
+    if (irqmp->set_pil_in == NULL) {
+        return -1;
+    }
+
+    memory_region_init_io(&irqmp->iomem, &grlib_irqmp_ops, irqmp,
+                          "irqmp", IRQMP_REG_SIZE);
+
+    irqmp->state = g_malloc0(sizeof *irqmp->state);
+
+    sysbus_init_mmio(dev, &irqmp->iomem);
+
+    return 0;
+}
+
+static Property grlib_irqmp_properties[] = {
+    DEFINE_PROP_PTR("set_pil_in", IRQMP, set_pil_in),
+    DEFINE_PROP_PTR("set_pil_in_opaque", IRQMP, set_pil_in_opaque),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void grlib_irqmp_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = grlib_irqmp_init;
+    dc->reset = grlib_irqmp_reset;
+    dc->props = grlib_irqmp_properties;
+}
+
+static const TypeInfo grlib_irqmp_info = {
+    .name          = "grlib,irqmp",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IRQMP),
+    .class_init    = grlib_irqmp_class_init,
+};
+
+static void grlib_irqmp_register_types(void)
+{
+    type_register_static(&grlib_irqmp_info);
+}
+
+type_init(grlib_irqmp_register_types)
diff --git a/hw/intc/imx_avic.c b/hw/intc/imx_avic.c
new file mode 100644 (file)
index 0000000..4e280b6
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ * i.MX31 Vectored Interrupt Controller
+ *
+ * Note this is NOT the PL192 provided by ARM, but
+ * a custom implementation by Freescale.
+ *
+ * Copyright (c) 2008 OKL
+ * Copyright (c) 2011 NICTA Pty Ltd
+ * Originally written by Hans Jiang
+ *
+ * This code is licensed under the GPL version 2 or later.  See
+ * the COPYING file in the top-level directory.
+ *
+ * TODO: implement vectors.
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "qemu/host-utils.h"
+
+#define DEBUG_INT 1
+#undef DEBUG_INT /* comment out for debugging */
+
+#ifdef DEBUG_INT
+#define DPRINTF(fmt, args...) \
+do { printf("imx_avic: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+/*
+ * Define to 1 for messages about attempts to
+ * access unimplemented registers or similar.
+ */
+#define DEBUG_IMPLEMENTATION 1
+#if DEBUG_IMPLEMENTATION
+#  define IPRINTF(fmt, args...) \
+    do  { fprintf(stderr, "imx_avic: " fmt, ##args); } while (0)
+#else
+#  define IPRINTF(fmt, args...) do {} while (0)
+#endif
+
+#define IMX_AVIC_NUM_IRQS 64
+
+/* Interrupt Control Bits */
+#define ABFLAG (1<<25)
+#define ABFEN (1<<24)
+#define NIDIS (1<<22) /* Normal Interrupt disable */
+#define FIDIS (1<<21) /* Fast interrupt disable */
+#define NIAD  (1<<20) /* Normal Interrupt Arbiter Rise ARM level */
+#define FIAD  (1<<19) /* Fast Interrupt Arbiter Rise ARM level */
+#define NM    (1<<18) /* Normal interrupt mode */
+
+
+#define PRIO_PER_WORD (sizeof(uint32_t) * 8 / 4)
+#define PRIO_WORDS (IMX_AVIC_NUM_IRQS/PRIO_PER_WORD)
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint64_t pending;
+    uint64_t enabled;
+    uint64_t is_fiq;
+    uint32_t intcntl;
+    uint32_t intmask;
+    qemu_irq irq;
+    qemu_irq fiq;
+    uint32_t prio[PRIO_WORDS]; /* Priorities are 4-bits each */
+} IMXAVICState;
+
+static const VMStateDescription vmstate_imx_avic = {
+    .name = "imx-avic",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(pending, IMXAVICState),
+        VMSTATE_UINT64(enabled, IMXAVICState),
+        VMSTATE_UINT64(is_fiq, IMXAVICState),
+        VMSTATE_UINT32(intcntl, IMXAVICState),
+        VMSTATE_UINT32(intmask, IMXAVICState),
+        VMSTATE_UINT32_ARRAY(prio, IMXAVICState, PRIO_WORDS),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+
+
+static inline int imx_avic_prio(IMXAVICState *s, int irq)
+{
+    uint32_t word = irq / PRIO_PER_WORD;
+    uint32_t part = 4 * (irq % PRIO_PER_WORD);
+    return 0xf & (s->prio[word] >> part);
+}
+
+static inline void imx_avic_set_prio(IMXAVICState *s, int irq, int prio)
+{
+    uint32_t word = irq / PRIO_PER_WORD;
+    uint32_t part = 4 * (irq % PRIO_PER_WORD);
+    uint32_t mask = ~(0xf << part);
+    s->prio[word] &= mask;
+    s->prio[word] |= prio << part;
+}
+
+/* Update interrupts.  */
+static void imx_avic_update(IMXAVICState *s)
+{
+    int i;
+    uint64_t new = s->pending & s->enabled;
+    uint64_t flags;
+
+    flags = new & s->is_fiq;
+    qemu_set_irq(s->fiq, !!flags);
+
+    flags = new & ~s->is_fiq;
+    if (!flags || (s->intmask == 0x1f)) {
+        qemu_set_irq(s->irq, !!flags);
+        return;
+    }
+
+    /*
+     * Take interrupt if there's a pending interrupt with
+     * priority higher than the value of intmask
+     */
+    for (i = 0; i < IMX_AVIC_NUM_IRQS; i++) {
+        if (flags & (1UL << i)) {
+            if (imx_avic_prio(s, i) > s->intmask) {
+                qemu_set_irq(s->irq, 1);
+                return;
+            }
+        }
+    }
+    qemu_set_irq(s->irq, 0);
+}
+
+static void imx_avic_set_irq(void *opaque, int irq, int level)
+{
+    IMXAVICState *s = (IMXAVICState *)opaque;
+
+    if (level) {
+        DPRINTF("Raising IRQ %d, prio %d\n",
+                irq, imx_avic_prio(s, irq));
+        s->pending |= (1ULL << irq);
+    } else {
+        DPRINTF("Clearing IRQ %d, prio %d\n",
+                irq, imx_avic_prio(s, irq));
+        s->pending &= ~(1ULL << irq);
+    }
+
+    imx_avic_update(s);
+}
+
+
+static uint64_t imx_avic_read(void *opaque,
+                             hwaddr offset, unsigned size)
+{
+    IMXAVICState *s = (IMXAVICState *)opaque;
+
+
+    DPRINTF("read(offset = 0x%x)\n", offset >> 2);
+    switch (offset >> 2) {
+    case 0: /* INTCNTL */
+        return s->intcntl;
+
+    case 1: /* Normal Interrupt Mask Register, NIMASK */
+        return s->intmask;
+
+    case 2: /* Interrupt Enable Number Register, INTENNUM */
+    case 3: /* Interrupt Disable Number Register, INTDISNUM */
+        return 0;
+
+    case 4: /* Interrupt Enabled Number Register High */
+        return s->enabled >> 32;
+
+    case 5: /* Interrupt Enabled Number Register Low */
+        return s->enabled & 0xffffffffULL;
+
+    case 6: /* Interrupt Type Register High */
+        return s->is_fiq >> 32;
+
+    case 7: /* Interrupt Type Register Low */
+        return s->is_fiq & 0xffffffffULL;
+
+    case 8: /* Normal Interrupt Priority Register 7 */
+    case 9: /* Normal Interrupt Priority Register 6 */
+    case 10:/* Normal Interrupt Priority Register 5 */
+    case 11:/* Normal Interrupt Priority Register 4 */
+    case 12:/* Normal Interrupt Priority Register 3 */
+    case 13:/* Normal Interrupt Priority Register 2 */
+    case 14:/* Normal Interrupt Priority Register 1 */
+    case 15:/* Normal Interrupt Priority Register 0 */
+        return s->prio[15-(offset>>2)];
+
+    case 16: /* Normal interrupt vector and status register */
+    {
+        /*
+         * This returns the highest priority
+         * outstanding interrupt.  Where there is more than
+         * one pending IRQ with the same priority,
+         * take the highest numbered one.
+         */
+        uint64_t flags = s->pending & s->enabled & ~s->is_fiq;
+        int i;
+        int prio = -1;
+        int irq = -1;
+        for (i = 63; i >= 0; --i) {
+            if (flags & (1ULL<<i)) {
+                int irq_prio = imx_avic_prio(s, i);
+                if (irq_prio > prio) {
+                    irq = i;
+                    prio = irq_prio;
+                }
+            }
+        }
+        if (irq >= 0) {
+            imx_avic_set_irq(s, irq, 0);
+            return irq << 16 | prio;
+        }
+        return 0xffffffffULL;
+    }
+    case 17:/* Fast Interrupt vector and status register */
+    {
+        uint64_t flags = s->pending & s->enabled & s->is_fiq;
+        int i = ctz64(flags);
+        if (i < 64) {
+            imx_avic_set_irq(opaque, i, 0);
+            return i;
+        }
+        return 0xffffffffULL;
+    }
+    case 18:/* Interrupt source register high */
+        return s->pending >> 32;
+
+    case 19:/* Interrupt source register low */
+        return s->pending & 0xffffffffULL;
+
+    case 20:/* Interrupt Force Register high */
+    case 21:/* Interrupt Force Register low */
+        return 0;
+
+    case 22:/* Normal Interrupt Pending Register High */
+        return (s->pending & s->enabled & ~s->is_fiq) >> 32;
+
+    case 23:/* Normal Interrupt Pending Register Low */
+        return (s->pending & s->enabled & ~s->is_fiq) & 0xffffffffULL;
+
+    case 24: /* Fast Interrupt Pending Register High  */
+        return (s->pending & s->enabled & s->is_fiq) >> 32;
+
+    case 25: /* Fast Interrupt Pending Register Low  */
+        return (s->pending & s->enabled & s->is_fiq) & 0xffffffffULL;
+
+    case 0x40:            /* AVIC vector 0, use for WFI WAR */
+        return 0x4;
+
+    default:
+        IPRINTF("imx_avic_read: Bad offset 0x%x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void imx_avic_write(void *opaque, hwaddr offset,
+                          uint64_t val, unsigned size)
+{
+    IMXAVICState *s = (IMXAVICState *)opaque;
+
+    /* Vector Registers not yet supported */
+    if (offset >= 0x100 && offset <= 0x2fc) {
+        IPRINTF("imx_avic_write to vector register %d ignored\n",
+                (unsigned int)((offset - 0x100) >> 2));
+        return;
+    }
+
+    DPRINTF("imx_avic_write(0x%x) = %x\n",
+            (unsigned int)offset>>2, (unsigned int)val);
+    switch (offset >> 2) {
+    case 0: /* Interrupt Control Register, INTCNTL */
+        s->intcntl = val & (ABFEN | NIDIS | FIDIS | NIAD | FIAD | NM);
+        if (s->intcntl & ABFEN) {
+            s->intcntl &= ~(val & ABFLAG);
+        }
+        break;
+
+    case 1: /* Normal Interrupt Mask Register, NIMASK */
+        s->intmask = val & 0x1f;
+        break;
+
+    case 2: /* Interrupt Enable Number Register, INTENNUM */
+        DPRINTF("enable(%d)\n", (int)val);
+        val &= 0x3f;
+        s->enabled |= (1ULL << val);
+        break;
+
+    case 3: /* Interrupt Disable Number Register, INTDISNUM */
+        DPRINTF("disable(%d)\n", (int)val);
+        val &= 0x3f;
+        s->enabled &= ~(1ULL << val);
+        break;
+
+    case 4: /* Interrupt Enable Number Register High */
+        s->enabled = (s->enabled & 0xffffffffULL) | (val << 32);
+        break;
+
+    case 5: /* Interrupt Enable Number Register Low */
+        s->enabled = (s->enabled & 0xffffffff00000000ULL) | val;
+        break;
+
+    case 6: /* Interrupt Type Register High */
+        s->is_fiq = (s->is_fiq & 0xffffffffULL) | (val << 32);
+        break;
+
+    case 7: /* Interrupt Type Register Low */
+        s->is_fiq = (s->is_fiq & 0xffffffff00000000ULL) | val;
+        break;
+
+    case 8: /* Normal Interrupt Priority Register 7 */
+    case 9: /* Normal Interrupt Priority Register 6 */
+    case 10:/* Normal Interrupt Priority Register 5 */
+    case 11:/* Normal Interrupt Priority Register 4 */
+    case 12:/* Normal Interrupt Priority Register 3 */
+    case 13:/* Normal Interrupt Priority Register 2 */
+    case 14:/* Normal Interrupt Priority Register 1 */
+    case 15:/* Normal Interrupt Priority Register 0 */
+        s->prio[15-(offset>>2)] = val;
+        break;
+
+        /* Read-only registers, writes ignored */
+    case 16:/* Normal Interrupt Vector and Status register */
+    case 17:/* Fast Interrupt vector and status register */
+    case 18:/* Interrupt source register high */
+    case 19:/* Interrupt source register low */
+        return;
+
+    case 20:/* Interrupt Force Register high */
+        s->pending = (s->pending & 0xffffffffULL) | (val << 32);
+        break;
+
+    case 21:/* Interrupt Force Register low */
+        s->pending = (s->pending & 0xffffffff00000000ULL) | val;
+        break;
+
+    case 22:/* Normal Interrupt Pending Register High */
+    case 23:/* Normal Interrupt Pending Register Low */
+    case 24: /* Fast Interrupt Pending Register High  */
+    case 25: /* Fast Interrupt Pending Register Low  */
+        return;
+
+    default:
+        IPRINTF("imx_avic_write: Bad offset %x\n", (int)offset);
+    }
+    imx_avic_update(s);
+}
+
+static const MemoryRegionOps imx_avic_ops = {
+    .read = imx_avic_read,
+    .write = imx_avic_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void imx_avic_reset(DeviceState *dev)
+{
+    IMXAVICState *s = container_of(dev, IMXAVICState, busdev.qdev);
+    s->pending = 0;
+    s->enabled = 0;
+    s->is_fiq = 0;
+    s->intmask = 0x1f;
+    s->intcntl = 0;
+    memset(s->prio, 0, sizeof s->prio);
+}
+
+static int imx_avic_init(SysBusDevice *dev)
+{
+    IMXAVICState *s = FROM_SYSBUS(IMXAVICState, dev);;
+
+    memory_region_init_io(&s->iomem, &imx_avic_ops, s, "imx_avic", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    qdev_init_gpio_in(&dev->qdev, imx_avic_set_irq, IMX_AVIC_NUM_IRQS);
+    sysbus_init_irq(dev, &s->irq);
+    sysbus_init_irq(dev, &s->fiq);
+
+    return 0;
+}
+
+
+static void imx_avic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    k->init = imx_avic_init;
+    dc->vmsd = &vmstate_imx_avic;
+    dc->reset = imx_avic_reset;
+    dc->desc = "i.MX Advanced Vector Interrupt Controller";
+}
+
+static const TypeInfo imx_avic_info = {
+    .name = "imx_avic",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IMXAVICState),
+    .class_init = imx_avic_class_init,
+};
+
+static void imx_avic_register_types(void)
+{
+    type_register_static(&imx_avic_info);
+}
+
+type_init(imx_avic_register_types)
diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
new file mode 100644 (file)
index 0000000..c6f09f4
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ *  ioapic.c IOAPIC emulation logic
+ *
+ *  Copyright (c) 2004-2005 Fabrice Bellard
+ *
+ *  Split the ioapic logic from apic.c
+ *  Xiantao Zhang <xiantao.zhang@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/i386/ioapic.h"
+#include "hw/i386/ioapic_internal.h"
+
+//#define DEBUG_IOAPIC
+
+#ifdef DEBUG_IOAPIC
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("ioapic: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+static IOAPICCommonState *ioapics[MAX_IOAPICS];
+
+static void ioapic_service(IOAPICCommonState *s)
+{
+    uint8_t i;
+    uint8_t trig_mode;
+    uint8_t vector;
+    uint8_t delivery_mode;
+    uint32_t mask;
+    uint64_t entry;
+    uint8_t dest;
+    uint8_t dest_mode;
+
+    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+        mask = 1 << i;
+        if (s->irr & mask) {
+            entry = s->ioredtbl[i];
+            if (!(entry & IOAPIC_LVT_MASKED)) {
+                trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1);
+                dest = entry >> IOAPIC_LVT_DEST_SHIFT;
+                dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1;
+                delivery_mode =
+                    (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK;
+                if (trig_mode == IOAPIC_TRIGGER_EDGE) {
+                    s->irr &= ~mask;
+                } else {
+                    s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR;
+                }
+                if (delivery_mode == IOAPIC_DM_EXTINT) {
+                    vector = pic_read_irq(isa_pic);
+                } else {
+                    vector = entry & IOAPIC_VECTOR_MASK;
+                }
+                apic_deliver_irq(dest, dest_mode, delivery_mode,
+                                 vector, trig_mode);
+            }
+        }
+    }
+}
+
+static void ioapic_set_irq(void *opaque, int vector, int level)
+{
+    IOAPICCommonState *s = opaque;
+
+    /* ISA IRQs map to GSI 1-1 except for IRQ0 which maps
+     * to GSI 2.  GSI maps to ioapic 1-1.  This is not
+     * the cleanest way of doing it but it should work. */
+
+    DPRINTF("%s: %s vec %x\n", __func__, level ? "raise" : "lower", vector);
+    if (vector == 0) {
+        vector = 2;
+    }
+    if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
+        uint32_t mask = 1 << vector;
+        uint64_t entry = s->ioredtbl[vector];
+
+        if (entry & (1 << IOAPIC_LVT_POLARITY_SHIFT)) {
+            level = !level;
+        }
+        if (((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) ==
+            IOAPIC_TRIGGER_LEVEL) {
+            /* level triggered */
+            if (level) {
+                s->irr |= mask;
+                ioapic_service(s);
+            } else {
+                s->irr &= ~mask;
+            }
+        } else {
+            /* According to the 82093AA manual, we must ignore edge requests
+             * if the input pin is masked. */
+            if (level && !(entry & IOAPIC_LVT_MASKED)) {
+                s->irr |= mask;
+                ioapic_service(s);
+            }
+        }
+    }
+}
+
+void ioapic_eoi_broadcast(int vector)
+{
+    IOAPICCommonState *s;
+    uint64_t entry;
+    int i, n;
+
+    for (i = 0; i < MAX_IOAPICS; i++) {
+        s = ioapics[i];
+        if (!s) {
+            continue;
+        }
+        for (n = 0; n < IOAPIC_NUM_PINS; n++) {
+            entry = s->ioredtbl[n];
+            if ((entry & IOAPIC_LVT_REMOTE_IRR)
+                && (entry & IOAPIC_VECTOR_MASK) == vector) {
+                s->ioredtbl[n] = entry & ~IOAPIC_LVT_REMOTE_IRR;
+                if (!(entry & IOAPIC_LVT_MASKED) && (s->irr & (1 << n))) {
+                    ioapic_service(s);
+                }
+            }
+        }
+    }
+}
+
+static uint64_t
+ioapic_mem_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    IOAPICCommonState *s = opaque;
+    int index;
+    uint32_t val = 0;
+
+    switch (addr & 0xff) {
+    case IOAPIC_IOREGSEL:
+        val = s->ioregsel;
+        break;
+    case IOAPIC_IOWIN:
+        if (size != 4) {
+            break;
+        }
+        switch (s->ioregsel) {
+        case IOAPIC_REG_ID:
+            val = s->id << IOAPIC_ID_SHIFT;
+            break;
+        case IOAPIC_REG_VER:
+            val = IOAPIC_VERSION |
+                ((IOAPIC_NUM_PINS - 1) << IOAPIC_VER_ENTRIES_SHIFT);
+            break;
+        case IOAPIC_REG_ARB:
+            val = 0;
+            break;
+        default:
+            index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1;
+            if (index >= 0 && index < IOAPIC_NUM_PINS) {
+                if (s->ioregsel & 1) {
+                    val = s->ioredtbl[index] >> 32;
+                } else {
+                    val = s->ioredtbl[index] & 0xffffffff;
+                }
+            }
+        }
+        DPRINTF("read: %08x = %08x\n", s->ioregsel, val);
+        break;
+    }
+    return val;
+}
+
+static void
+ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
+                 unsigned int size)
+{
+    IOAPICCommonState *s = opaque;
+    int index;
+
+    switch (addr & 0xff) {
+    case IOAPIC_IOREGSEL:
+        s->ioregsel = val;
+        break;
+    case IOAPIC_IOWIN:
+        if (size != 4) {
+            break;
+        }
+        DPRINTF("write: %08x = %08" PRIx64 "\n", s->ioregsel, val);
+        switch (s->ioregsel) {
+        case IOAPIC_REG_ID:
+            s->id = (val >> IOAPIC_ID_SHIFT) & IOAPIC_ID_MASK;
+            break;
+        case IOAPIC_REG_VER:
+        case IOAPIC_REG_ARB:
+            break;
+        default:
+            index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1;
+            if (index >= 0 && index < IOAPIC_NUM_PINS) {
+                if (s->ioregsel & 1) {
+                    s->ioredtbl[index] &= 0xffffffff;
+                    s->ioredtbl[index] |= (uint64_t)val << 32;
+                } else {
+                    s->ioredtbl[index] &= ~0xffffffffULL;
+                    s->ioredtbl[index] |= val;
+                }
+                ioapic_service(s);
+            }
+        }
+        break;
+    }
+}
+
+static const MemoryRegionOps ioapic_io_ops = {
+    .read = ioapic_mem_read,
+    .write = ioapic_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void ioapic_init(IOAPICCommonState *s, int instance_no)
+{
+    memory_region_init_io(&s->io_memory, &ioapic_io_ops, s, "ioapic", 0x1000);
+
+    qdev_init_gpio_in(&s->busdev.qdev, ioapic_set_irq, IOAPIC_NUM_PINS);
+
+    ioapics[instance_no] = s;
+}
+
+static void ioapic_class_init(ObjectClass *klass, void *data)
+{
+    IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init = ioapic_init;
+    dc->reset = ioapic_reset_common;
+}
+
+static const TypeInfo ioapic_info = {
+    .name          = "ioapic",
+    .parent        = TYPE_IOAPIC_COMMON,
+    .instance_size = sizeof(IOAPICCommonState),
+    .class_init    = ioapic_class_init,
+};
+
+static void ioapic_register_types(void)
+{
+    type_register_static(&ioapic_info);
+}
+
+type_init(ioapic_register_types)
diff --git a/hw/intc/ioapic_common.c b/hw/intc/ioapic_common.c
new file mode 100644 (file)
index 0000000..42c7adc
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ *  IOAPIC emulation logic - common bits of emulated and KVM kernel model
+ *
+ *  Copyright (c) 2004-2005 Fabrice Bellard
+ *  Copyright (c) 2009      Xiantao Zhang, Intel
+ *  Copyright (c) 2011      Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/i386/ioapic.h"
+#include "hw/i386/ioapic_internal.h"
+#include "hw/sysbus.h"
+
+void ioapic_reset_common(DeviceState *dev)
+{
+    IOAPICCommonState *s = IOAPIC_COMMON(dev);
+    int i;
+
+    s->id = 0;
+    s->ioregsel = 0;
+    s->irr = 0;
+    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+        s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT;
+    }
+}
+
+static void ioapic_dispatch_pre_save(void *opaque)
+{
+    IOAPICCommonState *s = IOAPIC_COMMON(opaque);
+    IOAPICCommonClass *info = IOAPIC_COMMON_GET_CLASS(s);
+
+    if (info->pre_save) {
+        info->pre_save(s);
+    }
+}
+
+static int ioapic_dispatch_post_load(void *opaque, int version_id)
+{
+    IOAPICCommonState *s = IOAPIC_COMMON(opaque);
+    IOAPICCommonClass *info = IOAPIC_COMMON_GET_CLASS(s);
+
+    if (info->post_load) {
+        info->post_load(s);
+    }
+    return 0;
+}
+
+static int ioapic_init_common(SysBusDevice *dev)
+{
+    IOAPICCommonState *s = FROM_SYSBUS(IOAPICCommonState, dev);
+    IOAPICCommonClass *info;
+    static int ioapic_no;
+
+    if (ioapic_no >= MAX_IOAPICS) {
+        return -1;
+    }
+
+    info = IOAPIC_COMMON_GET_CLASS(s);
+    info->init(s, ioapic_no);
+
+    sysbus_init_mmio(&s->busdev, &s->io_memory);
+    ioapic_no++;
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_ioapic_common = {
+    .name = "ioapic",
+    .version_id = 3,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = ioapic_dispatch_pre_save,
+    .post_load = ioapic_dispatch_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(id, IOAPICCommonState),
+        VMSTATE_UINT8(ioregsel, IOAPICCommonState),
+        VMSTATE_UNUSED_V(2, 8), /* to account for qemu-kvm's v2 format */
+        VMSTATE_UINT32_V(irr, IOAPICCommonState, 2),
+        VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICCommonState, IOAPIC_NUM_PINS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void ioapic_common_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    sc->init = ioapic_init_common;
+    dc->vmsd = &vmstate_ioapic_common;
+    dc->no_user = 1;
+}
+
+static const TypeInfo ioapic_common_type = {
+    .name = TYPE_IOAPIC_COMMON,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IOAPICCommonState),
+    .class_size = sizeof(IOAPICCommonClass),
+    .class_init = ioapic_common_class_init,
+    .abstract = true,
+};
+
+static void register_types(void)
+{
+    type_register_static(&ioapic_common_type);
+}
+
+type_init(register_types)
diff --git a/hw/intc/lm32_pic.c b/hw/intc/lm32_pic.c
new file mode 100644 (file)
index 0000000..b4e80c8
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ *  LatticeMico32 CPU interrupt controller logic.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "monitor/monitor.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "hw/lm32/lm32_pic.h"
+
+struct LM32PicState {
+    SysBusDevice busdev;
+    qemu_irq parent_irq;
+    uint32_t im;        /* interrupt mask */
+    uint32_t ip;        /* interrupt pending */
+    uint32_t irq_state;
+
+    /* statistics */
+    uint32_t stats_irq_count[32];
+};
+typedef struct LM32PicState LM32PicState;
+
+static LM32PicState *pic;
+void lm32_do_pic_info(Monitor *mon, const QDict *qdict)
+{
+    if (pic == NULL) {
+        return;
+    }
+
+    monitor_printf(mon, "lm32-pic: im=%08x ip=%08x irq_state=%08x\n",
+            pic->im, pic->ip, pic->irq_state);
+}
+
+void lm32_irq_info(Monitor *mon, const QDict *qdict)
+{
+    int i;
+    uint32_t count;
+
+    if (pic == NULL) {
+        return;
+    }
+
+    monitor_printf(mon, "IRQ statistics:\n");
+    for (i = 0; i < 32; i++) {
+        count = pic->stats_irq_count[i];
+        if (count > 0) {
+            monitor_printf(mon, "%2d: %u\n", i, count);
+        }
+    }
+}
+
+static void update_irq(LM32PicState *s)
+{
+    s->ip |= s->irq_state;
+
+    if (s->ip & s->im) {
+        trace_lm32_pic_raise_irq();
+        qemu_irq_raise(s->parent_irq);
+    } else {
+        trace_lm32_pic_lower_irq();
+        qemu_irq_lower(s->parent_irq);
+    }
+}
+
+static void irq_handler(void *opaque, int irq, int level)
+{
+    LM32PicState *s = opaque;
+
+    assert(irq < 32);
+    trace_lm32_pic_interrupt(irq, level);
+
+    if (level) {
+        s->irq_state |= (1 << irq);
+        s->stats_irq_count[irq]++;
+    } else {
+        s->irq_state &= ~(1 << irq);
+    }
+
+    update_irq(s);
+}
+
+void lm32_pic_set_im(DeviceState *d, uint32_t im)
+{
+    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
+
+    trace_lm32_pic_set_im(im);
+    s->im = im;
+
+    update_irq(s);
+}
+
+void lm32_pic_set_ip(DeviceState *d, uint32_t ip)
+{
+    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
+
+    trace_lm32_pic_set_ip(ip);
+
+    /* ack interrupt */
+    s->ip &= ~ip;
+
+    update_irq(s);
+}
+
+uint32_t lm32_pic_get_im(DeviceState *d)
+{
+    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
+
+    trace_lm32_pic_get_im(s->im);
+    return s->im;
+}
+
+uint32_t lm32_pic_get_ip(DeviceState *d)
+{
+    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
+
+    trace_lm32_pic_get_ip(s->ip);
+    return s->ip;
+}
+
+static void pic_reset(DeviceState *d)
+{
+    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
+    int i;
+
+    s->im = 0;
+    s->ip = 0;
+    s->irq_state = 0;
+    for (i = 0; i < 32; i++) {
+        s->stats_irq_count[i] = 0;
+    }
+}
+
+static int lm32_pic_init(SysBusDevice *dev)
+{
+    LM32PicState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
+    sysbus_init_irq(dev, &s->parent_irq);
+
+    pic = s;
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm32_pic = {
+    .name = "lm32-pic",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(im, LM32PicState),
+        VMSTATE_UINT32(ip, LM32PicState),
+        VMSTATE_UINT32(irq_state, LM32PicState),
+        VMSTATE_UINT32_ARRAY(stats_irq_count, LM32PicState, 32),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void lm32_pic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = lm32_pic_init;
+    dc->reset = pic_reset;
+    dc->vmsd = &vmstate_lm32_pic;
+}
+
+static const TypeInfo lm32_pic_info = {
+    .name          = "lm32-pic",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(LM32PicState),
+    .class_init    = lm32_pic_class_init,
+};
+
+static void lm32_pic_register_types(void)
+{
+    type_register_static(&lm32_pic_info);
+}
+
+type_init(lm32_pic_register_types)
diff --git a/hw/intc/omap_intc.c b/hw/intc/omap_intc.c
new file mode 100644 (file)
index 0000000..875eba4
--- /dev/null
@@ -0,0 +1,649 @@
+/*
+ * TI OMAP interrupt controller emulation.
+ *
+ * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog@zabor.org>
+ * Copyright (C) 2007-2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw/hw.h"
+#include "hw/arm/omap.h"
+#include "hw/sysbus.h"
+
+/* Interrupt Handlers */
+struct omap_intr_handler_bank_s {
+    uint32_t irqs;
+    uint32_t inputs;
+    uint32_t mask;
+    uint32_t fiq;
+    uint32_t sens_edge;
+    uint32_t swi;
+    unsigned char priority[32];
+};
+
+struct omap_intr_handler_s {
+    SysBusDevice busdev;
+    qemu_irq *pins;
+    qemu_irq parent_intr[2];
+    MemoryRegion mmio;
+    void *iclk;
+    void *fclk;
+    unsigned char nbanks;
+    int level_only;
+    uint32_t size;
+
+    uint8_t revision;
+
+    /* state */
+    uint32_t new_agr[2];
+    int sir_intr[2];
+    int autoidle;
+    uint32_t mask;
+    struct omap_intr_handler_bank_s bank[3];
+};
+
+static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq)
+{
+    int i, j, sir_intr, p_intr, p, f;
+    uint32_t level;
+    sir_intr = 0;
+    p_intr = 255;
+
+    /* Find the interrupt line with the highest dynamic priority.
+     * Note: 0 denotes the hightest priority.
+     * If all interrupts have the same priority, the default order is IRQ_N,
+     * IRQ_N-1,...,IRQ_0. */
+    for (j = 0; j < s->nbanks; ++j) {
+        level = s->bank[j].irqs & ~s->bank[j].mask &
+                (is_fiq ? s->bank[j].fiq : ~s->bank[j].fiq);
+        for (f = ffs(level), i = f - 1, level >>= f - 1; f; i += f,
+                        level >>= f) {
+            p = s->bank[j].priority[i];
+            if (p <= p_intr) {
+                p_intr = p;
+                sir_intr = 32 * j + i;
+            }
+            f = ffs(level >> 1);
+        }
+    }
+    s->sir_intr[is_fiq] = sir_intr;
+}
+
+static inline void omap_inth_update(struct omap_intr_handler_s *s, int is_fiq)
+{
+    int i;
+    uint32_t has_intr = 0;
+
+    for (i = 0; i < s->nbanks; ++i)
+        has_intr |= s->bank[i].irqs & ~s->bank[i].mask &
+                (is_fiq ? s->bank[i].fiq : ~s->bank[i].fiq);
+
+    if (s->new_agr[is_fiq] & has_intr & s->mask) {
+        s->new_agr[is_fiq] = 0;
+        omap_inth_sir_update(s, is_fiq);
+        qemu_set_irq(s->parent_intr[is_fiq], 1);
+    }
+}
+
+#define INT_FALLING_EDGE       0
+#define INT_LOW_LEVEL          1
+
+static void omap_set_intr(void *opaque, int irq, int req)
+{
+    struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
+    uint32_t rise;
+
+    struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
+    int n = irq & 31;
+
+    if (req) {
+        rise = ~bank->irqs & (1 << n);
+        if (~bank->sens_edge & (1 << n))
+            rise &= ~bank->inputs;
+
+        bank->inputs |= (1 << n);
+        if (rise) {
+            bank->irqs |= rise;
+            omap_inth_update(ih, 0);
+            omap_inth_update(ih, 1);
+        }
+    } else {
+        rise = bank->sens_edge & bank->irqs & (1 << n);
+        bank->irqs &= ~rise;
+        bank->inputs &= ~(1 << n);
+    }
+}
+
+/* Simplified version with no edge detection */
+static void omap_set_intr_noedge(void *opaque, int irq, int req)
+{
+    struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
+    uint32_t rise;
+
+    struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
+    int n = irq & 31;
+
+    if (req) {
+        rise = ~bank->inputs & (1 << n);
+        if (rise) {
+            bank->irqs |= bank->inputs |= rise;
+            omap_inth_update(ih, 0);
+            omap_inth_update(ih, 1);
+        }
+    } else
+        bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi;
+}
+
+static uint64_t omap_inth_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
+    int i, offset = addr;
+    int bank_no = offset >> 8;
+    int line_no;
+    struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
+    offset &= 0xff;
+
+    switch (offset) {
+    case 0x00: /* ITR */
+        return bank->irqs;
+
+    case 0x04: /* MIR */
+        return bank->mask;
+
+    case 0x10: /* SIR_IRQ_CODE */
+    case 0x14:  /* SIR_FIQ_CODE */
+        if (bank_no != 0)
+            break;
+        line_no = s->sir_intr[(offset - 0x10) >> 2];
+        bank = &s->bank[line_no >> 5];
+        i = line_no & 31;
+        if (((bank->sens_edge >> i) & 1) == INT_FALLING_EDGE)
+            bank->irqs &= ~(1 << i);
+        return line_no;
+
+    case 0x18: /* CONTROL_REG */
+        if (bank_no != 0)
+            break;
+        return 0;
+
+    case 0x1c: /* ILR0 */
+    case 0x20: /* ILR1 */
+    case 0x24: /* ILR2 */
+    case 0x28: /* ILR3 */
+    case 0x2c: /* ILR4 */
+    case 0x30: /* ILR5 */
+    case 0x34: /* ILR6 */
+    case 0x38: /* ILR7 */
+    case 0x3c: /* ILR8 */
+    case 0x40: /* ILR9 */
+    case 0x44: /* ILR10 */
+    case 0x48: /* ILR11 */
+    case 0x4c: /* ILR12 */
+    case 0x50: /* ILR13 */
+    case 0x54: /* ILR14 */
+    case 0x58: /* ILR15 */
+    case 0x5c: /* ILR16 */
+    case 0x60: /* ILR17 */
+    case 0x64: /* ILR18 */
+    case 0x68: /* ILR19 */
+    case 0x6c: /* ILR20 */
+    case 0x70: /* ILR21 */
+    case 0x74: /* ILR22 */
+    case 0x78: /* ILR23 */
+    case 0x7c: /* ILR24 */
+    case 0x80: /* ILR25 */
+    case 0x84: /* ILR26 */
+    case 0x88: /* ILR27 */
+    case 0x8c: /* ILR28 */
+    case 0x90: /* ILR29 */
+    case 0x94: /* ILR30 */
+    case 0x98: /* ILR31 */
+        i = (offset - 0x1c) >> 2;
+        return (bank->priority[i] << 2) |
+                (((bank->sens_edge >> i) & 1) << 1) |
+                ((bank->fiq >> i) & 1);
+
+    case 0x9c: /* ISR */
+        return 0x00000000;
+
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_inth_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size)
+{
+    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
+    int i, offset = addr;
+    int bank_no = offset >> 8;
+    struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
+    offset &= 0xff;
+
+    switch (offset) {
+    case 0x00: /* ITR */
+        /* Important: ignore the clearing if the IRQ is level-triggered and
+           the input bit is 1 */
+        bank->irqs &= value | (bank->inputs & bank->sens_edge);
+        return;
+
+    case 0x04: /* MIR */
+        bank->mask = value;
+        omap_inth_update(s, 0);
+        omap_inth_update(s, 1);
+        return;
+
+    case 0x10: /* SIR_IRQ_CODE */
+    case 0x14: /* SIR_FIQ_CODE */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x18: /* CONTROL_REG */
+        if (bank_no != 0)
+            break;
+        if (value & 2) {
+            qemu_set_irq(s->parent_intr[1], 0);
+            s->new_agr[1] = ~0;
+            omap_inth_update(s, 1);
+        }
+        if (value & 1) {
+            qemu_set_irq(s->parent_intr[0], 0);
+            s->new_agr[0] = ~0;
+            omap_inth_update(s, 0);
+        }
+        return;
+
+    case 0x1c: /* ILR0 */
+    case 0x20: /* ILR1 */
+    case 0x24: /* ILR2 */
+    case 0x28: /* ILR3 */
+    case 0x2c: /* ILR4 */
+    case 0x30: /* ILR5 */
+    case 0x34: /* ILR6 */
+    case 0x38: /* ILR7 */
+    case 0x3c: /* ILR8 */
+    case 0x40: /* ILR9 */
+    case 0x44: /* ILR10 */
+    case 0x48: /* ILR11 */
+    case 0x4c: /* ILR12 */
+    case 0x50: /* ILR13 */
+    case 0x54: /* ILR14 */
+    case 0x58: /* ILR15 */
+    case 0x5c: /* ILR16 */
+    case 0x60: /* ILR17 */
+    case 0x64: /* ILR18 */
+    case 0x68: /* ILR19 */
+    case 0x6c: /* ILR20 */
+    case 0x70: /* ILR21 */
+    case 0x74: /* ILR22 */
+    case 0x78: /* ILR23 */
+    case 0x7c: /* ILR24 */
+    case 0x80: /* ILR25 */
+    case 0x84: /* ILR26 */
+    case 0x88: /* ILR27 */
+    case 0x8c: /* ILR28 */
+    case 0x90: /* ILR29 */
+    case 0x94: /* ILR30 */
+    case 0x98: /* ILR31 */
+        i = (offset - 0x1c) >> 2;
+        bank->priority[i] = (value >> 2) & 0x1f;
+        bank->sens_edge &= ~(1 << i);
+        bank->sens_edge |= ((value >> 1) & 1) << i;
+        bank->fiq &= ~(1 << i);
+        bank->fiq |= (value & 1) << i;
+        return;
+
+    case 0x9c: /* ISR */
+        for (i = 0; i < 32; i ++)
+            if (value & (1 << i)) {
+                omap_set_intr(s, 32 * bank_no + i, 1);
+                return;
+            }
+        return;
+    }
+    OMAP_BAD_REG(addr);
+}
+
+static const MemoryRegionOps omap_inth_mem_ops = {
+    .read = omap_inth_read,
+    .write = omap_inth_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void omap_inth_reset(DeviceState *dev)
+{
+    struct omap_intr_handler_s *s = FROM_SYSBUS(struct omap_intr_handler_s,
+                                                SYS_BUS_DEVICE(dev));
+    int i;
+
+    for (i = 0; i < s->nbanks; ++i){
+        s->bank[i].irqs = 0x00000000;
+        s->bank[i].mask = 0xffffffff;
+        s->bank[i].sens_edge = 0x00000000;
+        s->bank[i].fiq = 0x00000000;
+        s->bank[i].inputs = 0x00000000;
+        s->bank[i].swi = 0x00000000;
+        memset(s->bank[i].priority, 0, sizeof(s->bank[i].priority));
+
+        if (s->level_only)
+            s->bank[i].sens_edge = 0xffffffff;
+    }
+
+    s->new_agr[0] = ~0;
+    s->new_agr[1] = ~0;
+    s->sir_intr[0] = 0;
+    s->sir_intr[1] = 0;
+    s->autoidle = 0;
+    s->mask = ~0;
+
+    qemu_set_irq(s->parent_intr[0], 0);
+    qemu_set_irq(s->parent_intr[1], 0);
+}
+
+static int omap_intc_init(SysBusDevice *dev)
+{
+    struct omap_intr_handler_s *s;
+    s = FROM_SYSBUS(struct omap_intr_handler_s, dev);
+    if (!s->iclk) {
+        hw_error("omap-intc: clk not connected\n");
+    }
+    s->nbanks = 1;
+    sysbus_init_irq(dev, &s->parent_intr[0]);
+    sysbus_init_irq(dev, &s->parent_intr[1]);
+    qdev_init_gpio_in(&dev->qdev, omap_set_intr, s->nbanks * 32);
+    memory_region_init_io(&s->mmio, &omap_inth_mem_ops, s,
+                          "omap-intc", s->size);
+    sysbus_init_mmio(dev, &s->mmio);
+    return 0;
+}
+
+static Property omap_intc_properties[] = {
+    DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100),
+    DEFINE_PROP_PTR("clk", struct omap_intr_handler_s, iclk),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void omap_intc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = omap_intc_init;
+    dc->reset = omap_inth_reset;
+    dc->props = omap_intc_properties;
+}
+
+static const TypeInfo omap_intc_info = {
+    .name          = "omap-intc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct omap_intr_handler_s),
+    .class_init    = omap_intc_class_init,
+};
+
+static uint64_t omap2_inth_read(void *opaque, hwaddr addr,
+                                unsigned size)
+{
+    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
+    int offset = addr;
+    int bank_no, line_no;
+    struct omap_intr_handler_bank_s *bank = NULL;
+
+    if ((offset & 0xf80) == 0x80) {
+        bank_no = (offset & 0x60) >> 5;
+        if (bank_no < s->nbanks) {
+            offset &= ~0x60;
+            bank = &s->bank[bank_no];
+        } else {
+            OMAP_BAD_REG(addr);
+            return 0;
+        }
+    }
+
+    switch (offset) {
+    case 0x00: /* INTC_REVISION */
+        return s->revision;
+
+    case 0x10: /* INTC_SYSCONFIG */
+        return (s->autoidle >> 2) & 1;
+
+    case 0x14: /* INTC_SYSSTATUS */
+        return 1;                                              /* RESETDONE */
+
+    case 0x40: /* INTC_SIR_IRQ */
+        return s->sir_intr[0];
+
+    case 0x44: /* INTC_SIR_FIQ */
+        return s->sir_intr[1];
+
+    case 0x48: /* INTC_CONTROL */
+        return (!s->mask) << 2;                                        /* GLOBALMASK */
+
+    case 0x4c: /* INTC_PROTECTION */
+        return 0;
+
+    case 0x50: /* INTC_IDLE */
+        return s->autoidle & 3;
+
+    /* Per-bank registers */
+    case 0x80: /* INTC_ITR */
+        return bank->inputs;
+
+    case 0x84: /* INTC_MIR */
+        return bank->mask;
+
+    case 0x88: /* INTC_MIR_CLEAR */
+    case 0x8c: /* INTC_MIR_SET */
+        return 0;
+
+    case 0x90: /* INTC_ISR_SET */
+        return bank->swi;
+
+    case 0x94: /* INTC_ISR_CLEAR */
+        return 0;
+
+    case 0x98: /* INTC_PENDING_IRQ */
+        return bank->irqs & ~bank->mask & ~bank->fiq;
+
+    case 0x9c: /* INTC_PENDING_FIQ */
+        return bank->irqs & ~bank->mask & bank->fiq;
+
+    /* Per-line registers */
+    case 0x100 ... 0x300:      /* INTC_ILR */
+        bank_no = (offset - 0x100) >> 7;
+        if (bank_no > s->nbanks)
+            break;
+        bank = &s->bank[bank_no];
+        line_no = (offset & 0x7f) >> 2;
+        return (bank->priority[line_no] << 2) |
+                ((bank->fiq >> line_no) & 1);
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap2_inth_write(void *opaque, hwaddr addr,
+                             uint64_t value, unsigned size)
+{
+    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
+    int offset = addr;
+    int bank_no, line_no;
+    struct omap_intr_handler_bank_s *bank = NULL;
+
+    if ((offset & 0xf80) == 0x80) {
+        bank_no = (offset & 0x60) >> 5;
+        if (bank_no < s->nbanks) {
+            offset &= ~0x60;
+            bank = &s->bank[bank_no];
+        } else {
+            OMAP_BAD_REG(addr);
+            return;
+        }
+    }
+
+    switch (offset) {
+    case 0x10: /* INTC_SYSCONFIG */
+        s->autoidle &= 4;
+        s->autoidle |= (value & 1) << 2;
+        if (value & 2)                                         /* SOFTRESET */
+            omap_inth_reset(&s->busdev.qdev);
+        return;
+
+    case 0x48: /* INTC_CONTROL */
+        s->mask = (value & 4) ? 0 : ~0;                                /* GLOBALMASK */
+        if (value & 2) {                                       /* NEWFIQAGR */
+            qemu_set_irq(s->parent_intr[1], 0);
+            s->new_agr[1] = ~0;
+            omap_inth_update(s, 1);
+        }
+        if (value & 1) {                                       /* NEWIRQAGR */
+            qemu_set_irq(s->parent_intr[0], 0);
+            s->new_agr[0] = ~0;
+            omap_inth_update(s, 0);
+        }
+        return;
+
+    case 0x4c: /* INTC_PROTECTION */
+        /* TODO: Make a bitmap (or sizeof(char)map) of access privileges
+         * for every register, see Chapter 3 and 4 for privileged mode.  */
+        if (value & 1)
+            fprintf(stderr, "%s: protection mode enable attempt\n",
+                            __FUNCTION__);
+        return;
+
+    case 0x50: /* INTC_IDLE */
+        s->autoidle &= ~3;
+        s->autoidle |= value & 3;
+        return;
+
+    /* Per-bank registers */
+    case 0x84: /* INTC_MIR */
+        bank->mask = value;
+        omap_inth_update(s, 0);
+        omap_inth_update(s, 1);
+        return;
+
+    case 0x88: /* INTC_MIR_CLEAR */
+        bank->mask &= ~value;
+        omap_inth_update(s, 0);
+        omap_inth_update(s, 1);
+        return;
+
+    case 0x8c: /* INTC_MIR_SET */
+        bank->mask |= value;
+        return;
+
+    case 0x90: /* INTC_ISR_SET */
+        bank->irqs |= bank->swi |= value;
+        omap_inth_update(s, 0);
+        omap_inth_update(s, 1);
+        return;
+
+    case 0x94: /* INTC_ISR_CLEAR */
+        bank->swi &= ~value;
+        bank->irqs = bank->swi & bank->inputs;
+        return;
+
+    /* Per-line registers */
+    case 0x100 ... 0x300:      /* INTC_ILR */
+        bank_no = (offset - 0x100) >> 7;
+        if (bank_no > s->nbanks)
+            break;
+        bank = &s->bank[bank_no];
+        line_no = (offset & 0x7f) >> 2;
+        bank->priority[line_no] = (value >> 2) & 0x3f;
+        bank->fiq &= ~(1 << line_no);
+        bank->fiq |= (value & 1) << line_no;
+        return;
+
+    case 0x00: /* INTC_REVISION */
+    case 0x14: /* INTC_SYSSTATUS */
+    case 0x40: /* INTC_SIR_IRQ */
+    case 0x44: /* INTC_SIR_FIQ */
+    case 0x80: /* INTC_ITR */
+    case 0x98: /* INTC_PENDING_IRQ */
+    case 0x9c: /* INTC_PENDING_FIQ */
+        OMAP_RO_REG(addr);
+        return;
+    }
+    OMAP_BAD_REG(addr);
+}
+
+static const MemoryRegionOps omap2_inth_mem_ops = {
+    .read = omap2_inth_read,
+    .write = omap2_inth_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static int omap2_intc_init(SysBusDevice *dev)
+{
+    struct omap_intr_handler_s *s;
+    s = FROM_SYSBUS(struct omap_intr_handler_s, dev);
+    if (!s->iclk) {
+        hw_error("omap2-intc: iclk not connected\n");
+    }
+    if (!s->fclk) {
+        hw_error("omap2-intc: fclk not connected\n");
+    }
+    s->level_only = 1;
+    s->nbanks = 3;
+    sysbus_init_irq(dev, &s->parent_intr[0]);
+    sysbus_init_irq(dev, &s->parent_intr[1]);
+    qdev_init_gpio_in(&dev->qdev, omap_set_intr_noedge, s->nbanks * 32);
+    memory_region_init_io(&s->mmio, &omap2_inth_mem_ops, s,
+                          "omap2-intc", 0x1000);
+    sysbus_init_mmio(dev, &s->mmio);
+    return 0;
+}
+
+static Property omap2_intc_properties[] = {
+    DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s,
+    revision, 0x21),
+    DEFINE_PROP_PTR("iclk", struct omap_intr_handler_s, iclk),
+    DEFINE_PROP_PTR("fclk", struct omap_intr_handler_s, fclk),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void omap2_intc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = omap2_intc_init;
+    dc->reset = omap_inth_reset;
+    dc->props = omap2_intc_properties;
+}
+
+static const TypeInfo omap2_intc_info = {
+    .name          = "omap2-intc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct omap_intr_handler_s),
+    .class_init    = omap2_intc_class_init,
+};
+
+static void omap_intc_register_types(void)
+{
+    type_register_static(&omap_intc_info);
+    type_register_static(&omap2_intc_info);
+}
+
+type_init(omap_intc_register_types)
diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c
new file mode 100644 (file)
index 0000000..c788714
--- /dev/null
@@ -0,0 +1,1661 @@
+/*
+ * OpenPIC emulation
+ *
+ * Copyright (c) 2004 Jocelyn Mayer
+ *               2011 Alexander Graf
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+/*
+ *
+ * Based on OpenPic implementations:
+ * - Intel GW80314 I/O companion chip developer's manual
+ * - Motorola MPC8245 & MPC8540 user manuals.
+ * - Motorola MCP750 (aka Raven) programmer manual.
+ * - Motorola Harrier programmer manuel
+ *
+ * Serial interrupts, as implemented in Raven chipset are not supported yet.
+ *
+ */
+#include "hw/hw.h"
+#include "hw/ppc/mac.h"
+#include "hw/pci/pci.h"
+#include "hw/ppc/openpic.h"
+#include "hw/sysbus.h"
+#include "hw/pci/msi.h"
+#include "qemu/bitops.h"
+#include "hw/ppc/ppc.h"
+
+//#define DEBUG_OPENPIC
+
+#ifdef DEBUG_OPENPIC
+static const int debug_openpic = 1;
+#else
+static const int debug_openpic = 0;
+#endif
+
+#define DPRINTF(fmt, ...) do { \
+        if (debug_openpic) { \
+            printf(fmt , ## __VA_ARGS__); \
+        } \
+    } while (0)
+
+#define MAX_CPU     32
+#define MAX_SRC     256
+#define MAX_TMR     4
+#define MAX_IPI     4
+#define MAX_MSI     8
+#define MAX_IRQ     (MAX_SRC + MAX_IPI + MAX_TMR)
+#define VID         0x03 /* MPIC version ID */
+
+/* OpenPIC capability flags */
+#define OPENPIC_FLAG_IDR_CRIT     (1 << 0)
+#define OPENPIC_FLAG_ILR          (2 << 0)
+
+/* OpenPIC address map */
+#define OPENPIC_GLB_REG_START        0x0
+#define OPENPIC_GLB_REG_SIZE         0x10F0
+#define OPENPIC_TMR_REG_START        0x10F0
+#define OPENPIC_TMR_REG_SIZE         0x220
+#define OPENPIC_MSI_REG_START        0x1600
+#define OPENPIC_MSI_REG_SIZE         0x200
+#define OPENPIC_SUMMARY_REG_START   0x3800
+#define OPENPIC_SUMMARY_REG_SIZE    0x800
+#define OPENPIC_SRC_REG_START        0x10000
+#define OPENPIC_SRC_REG_SIZE         (MAX_SRC * 0x20)
+#define OPENPIC_CPU_REG_START        0x20000
+#define OPENPIC_CPU_REG_SIZE         0x100 + ((MAX_CPU - 1) * 0x1000)
+
+/* Raven */
+#define RAVEN_MAX_CPU      2
+#define RAVEN_MAX_EXT     48
+#define RAVEN_MAX_IRQ     64
+#define RAVEN_MAX_TMR      MAX_TMR
+#define RAVEN_MAX_IPI      MAX_IPI
+
+/* Interrupt definitions */
+#define RAVEN_FE_IRQ     (RAVEN_MAX_EXT)     /* Internal functional IRQ */
+#define RAVEN_ERR_IRQ    (RAVEN_MAX_EXT + 1) /* Error IRQ */
+#define RAVEN_TMR_IRQ    (RAVEN_MAX_EXT + 2) /* First timer IRQ */
+#define RAVEN_IPI_IRQ    (RAVEN_TMR_IRQ + RAVEN_MAX_TMR) /* First IPI IRQ */
+/* First doorbell IRQ */
+#define RAVEN_DBL_IRQ    (RAVEN_IPI_IRQ + (RAVEN_MAX_CPU * RAVEN_MAX_IPI))
+
+typedef struct FslMpicInfo {
+    int max_ext;
+} FslMpicInfo;
+
+static FslMpicInfo fsl_mpic_20 = {
+    .max_ext = 12,
+};
+
+static FslMpicInfo fsl_mpic_42 = {
+    .max_ext = 12,
+};
+
+#define FRR_NIRQ_SHIFT    16
+#define FRR_NCPU_SHIFT     8
+#define FRR_VID_SHIFT      0
+
+#define VID_REVISION_1_2   2
+#define VID_REVISION_1_3   3
+
+#define VIR_GENERIC      0x00000000 /* Generic Vendor ID */
+
+#define GCR_RESET        0x80000000
+#define GCR_MODE_PASS    0x00000000
+#define GCR_MODE_MIXED   0x20000000
+#define GCR_MODE_PROXY   0x60000000
+
+#define TBCR_CI           0x80000000 /* count inhibit */
+#define TCCR_TOG          0x80000000 /* toggles when decrement to zero */
+
+#define IDR_EP_SHIFT      31
+#define IDR_EP_MASK       (1 << IDR_EP_SHIFT)
+#define IDR_CI0_SHIFT     30
+#define IDR_CI1_SHIFT     29
+#define IDR_P1_SHIFT      1
+#define IDR_P0_SHIFT      0
+
+#define ILR_INTTGT_MASK   0x000000ff
+#define ILR_INTTGT_INT    0x00
+#define ILR_INTTGT_CINT   0x01 /* critical */
+#define ILR_INTTGT_MCP    0x02 /* machine check */
+
+/* The currently supported INTTGT values happen to be the same as QEMU's
+ * openpic output codes, but don't depend on this.  The output codes
+ * could change (unlikely, but...) or support could be added for
+ * more INTTGT values.
+ */
+static const int inttgt_output[][2] = {
+    { ILR_INTTGT_INT, OPENPIC_OUTPUT_INT },
+    { ILR_INTTGT_CINT, OPENPIC_OUTPUT_CINT },
+    { ILR_INTTGT_MCP, OPENPIC_OUTPUT_MCK },
+};
+
+static int inttgt_to_output(int inttgt)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) {
+        if (inttgt_output[i][0] == inttgt) {
+            return inttgt_output[i][1];
+        }
+    }
+
+    fprintf(stderr, "%s: unsupported inttgt %d\n", __func__, inttgt);
+    return OPENPIC_OUTPUT_INT;
+}
+
+static int output_to_inttgt(int output)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) {
+        if (inttgt_output[i][1] == output) {
+            return inttgt_output[i][0];
+        }
+    }
+
+    abort();
+}
+
+#define MSIIR_OFFSET       0x140
+#define MSIIR_SRS_SHIFT    29
+#define MSIIR_SRS_MASK     (0x7 << MSIIR_SRS_SHIFT)
+#define MSIIR_IBS_SHIFT    24
+#define MSIIR_IBS_MASK     (0x1f << MSIIR_IBS_SHIFT)
+
+static int get_current_cpu(void)
+{
+    CPUState *cpu_single_cpu;
+
+    if (!cpu_single_env) {
+        return -1;
+    }
+
+    cpu_single_cpu = ENV_GET_CPU(cpu_single_env);
+    return cpu_single_cpu->cpu_index;
+}
+
+static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
+                                          int idx);
+static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
+                                       uint32_t val, int idx);
+
+typedef enum IRQType {
+    IRQ_TYPE_NORMAL = 0,
+    IRQ_TYPE_FSLINT,        /* FSL internal interrupt -- level only */
+    IRQ_TYPE_FSLSPECIAL,    /* FSL timer/IPI interrupt, edge, no polarity */
+} IRQType;
+
+typedef struct IRQQueue {
+    /* Round up to the nearest 64 IRQs so that the queue length
+     * won't change when moving between 32 and 64 bit hosts.
+     */
+    unsigned long queue[BITS_TO_LONGS((MAX_IRQ + 63) & ~63)];
+    int next;
+    int priority;
+} IRQQueue;
+
+typedef struct IRQSource {
+    uint32_t ivpr;  /* IRQ vector/priority register */
+    uint32_t idr;   /* IRQ destination register */
+    uint32_t destmask; /* bitmap of CPU destinations */
+    int last_cpu;
+    int output;     /* IRQ level, e.g. OPENPIC_OUTPUT_INT */
+    int pending;    /* TRUE if IRQ is pending */
+    IRQType type;
+    bool level:1;   /* level-triggered */
+    bool nomask:1;  /* critical interrupts ignore mask on some FSL MPICs */
+} IRQSource;
+
+#define IVPR_MASK_SHIFT       31
+#define IVPR_MASK_MASK        (1 << IVPR_MASK_SHIFT)
+#define IVPR_ACTIVITY_SHIFT   30
+#define IVPR_ACTIVITY_MASK    (1 << IVPR_ACTIVITY_SHIFT)
+#define IVPR_MODE_SHIFT       29
+#define IVPR_MODE_MASK        (1 << IVPR_MODE_SHIFT)
+#define IVPR_POLARITY_SHIFT   23
+#define IVPR_POLARITY_MASK    (1 << IVPR_POLARITY_SHIFT)
+#define IVPR_SENSE_SHIFT      22
+#define IVPR_SENSE_MASK       (1 << IVPR_SENSE_SHIFT)
+
+#define IVPR_PRIORITY_MASK     (0xF << 16)
+#define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16))
+#define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask)
+
+/* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */
+#define IDR_EP      0x80000000  /* external pin */
+#define IDR_CI      0x40000000  /* critical interrupt */
+
+typedef struct IRQDest {
+    int32_t ctpr; /* CPU current task priority */
+    IRQQueue raised;
+    IRQQueue servicing;
+    qemu_irq *irqs;
+
+    /* Count of IRQ sources asserting on non-INT outputs */
+    uint32_t outputs_active[OPENPIC_OUTPUT_NB];
+} IRQDest;
+
+typedef struct OpenPICState {
+    SysBusDevice busdev;
+    MemoryRegion mem;
+
+    /* Behavior control */
+    FslMpicInfo *fsl;
+    uint32_t model;
+    uint32_t flags;
+    uint32_t nb_irqs;
+    uint32_t vid;
+    uint32_t vir; /* Vendor identification register */
+    uint32_t vector_mask;
+    uint32_t tfrr_reset;
+    uint32_t ivpr_reset;
+    uint32_t idr_reset;
+    uint32_t brr1;
+    uint32_t mpic_mode_mask;
+
+    /* Sub-regions */
+    MemoryRegion sub_io_mem[6];
+
+    /* Global registers */
+    uint32_t frr; /* Feature reporting register */
+    uint32_t gcr; /* Global configuration register  */
+    uint32_t pir; /* Processor initialization register */
+    uint32_t spve; /* Spurious vector register */
+    uint32_t tfrr; /* Timer frequency reporting register */
+    /* Source registers */
+    IRQSource src[MAX_IRQ];
+    /* Local registers per output pin */
+    IRQDest dst[MAX_CPU];
+    uint32_t nb_cpus;
+    /* Timer registers */
+    struct {
+        uint32_t tccr;  /* Global timer current count register */
+        uint32_t tbcr;  /* Global timer base count register */
+    } timers[MAX_TMR];
+    /* Shared MSI registers */
+    struct {
+        uint32_t msir;   /* Shared Message Signaled Interrupt Register */
+    } msi[MAX_MSI];
+    uint32_t max_irq;
+    uint32_t irq_ipi0;
+    uint32_t irq_tim0;
+    uint32_t irq_msi;
+} OpenPICState;
+
+static inline void IRQ_setbit(IRQQueue *q, int n_IRQ)
+{
+    set_bit(n_IRQ, q->queue);
+}
+
+static inline void IRQ_resetbit(IRQQueue *q, int n_IRQ)
+{
+    clear_bit(n_IRQ, q->queue);
+}
+
+static inline int IRQ_testbit(IRQQueue *q, int n_IRQ)
+{
+    return test_bit(n_IRQ, q->queue);
+}
+
+static void IRQ_check(OpenPICState *opp, IRQQueue *q)
+{
+    int irq = -1;
+    int next = -1;
+    int priority = -1;
+
+    for (;;) {
+        irq = find_next_bit(q->queue, opp->max_irq, irq + 1);
+        if (irq == opp->max_irq) {
+            break;
+        }
+
+        DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n",
+                irq, IVPR_PRIORITY(opp->src[irq].ivpr), priority);
+
+        if (IVPR_PRIORITY(opp->src[irq].ivpr) > priority) {
+            next = irq;
+            priority = IVPR_PRIORITY(opp->src[irq].ivpr);
+        }
+    }
+
+    q->next = next;
+    q->priority = priority;
+}
+
+static int IRQ_get_next(OpenPICState *opp, IRQQueue *q)
+{
+    /* XXX: optimize */
+    IRQ_check(opp, q);
+
+    return q->next;
+}
+
+static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,
+                           bool active, bool was_active)
+{
+    IRQDest *dst;
+    IRQSource *src;
+    int priority;
+
+    dst = &opp->dst[n_CPU];
+    src = &opp->src[n_IRQ];
+
+    DPRINTF("%s: IRQ %d active %d was %d\n",
+            __func__, n_IRQ, active, was_active);
+
+    if (src->output != OPENPIC_OUTPUT_INT) {
+        DPRINTF("%s: output %d irq %d active %d was %d count %d\n",
+                __func__, src->output, n_IRQ, active, was_active,
+                dst->outputs_active[src->output]);
+
+        /* On Freescale MPIC, critical interrupts ignore priority,
+         * IACK, EOI, etc.  Before MPIC v4.1 they also ignore
+         * masking.
+         */
+        if (active) {
+            if (!was_active && dst->outputs_active[src->output]++ == 0) {
+                DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d\n",
+                        __func__, src->output, n_CPU, n_IRQ);
+                qemu_irq_raise(dst->irqs[src->output]);
+            }
+        } else {
+            if (was_active && --dst->outputs_active[src->output] == 0) {
+                DPRINTF("%s: Lower OpenPIC output %d cpu %d irq %d\n",
+                        __func__, src->output, n_CPU, n_IRQ);
+                qemu_irq_lower(dst->irqs[src->output]);
+            }
+        }
+
+        return;
+    }
+
+    priority = IVPR_PRIORITY(src->ivpr);
+
+    /* Even if the interrupt doesn't have enough priority,
+     * it is still raised, in case ctpr is lowered later.
+     */
+    if (active) {
+        IRQ_setbit(&dst->raised, n_IRQ);
+    } else {
+        IRQ_resetbit(&dst->raised, n_IRQ);
+    }
+
+    IRQ_check(opp, &dst->raised);
+
+    if (active && priority <= dst->ctpr) {
+        DPRINTF("%s: IRQ %d priority %d too low for ctpr %d on CPU %d\n",
+                __func__, n_IRQ, priority, dst->ctpr, n_CPU);
+        active = 0;
+    }
+
+    if (active) {
+        if (IRQ_get_next(opp, &dst->servicing) >= 0 &&
+                priority <= dst->servicing.priority) {
+            DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
+                    __func__, n_IRQ, dst->servicing.next, n_CPU);
+        } else {
+            DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d/%d\n",
+                    __func__, n_CPU, n_IRQ, dst->raised.next);
+            qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
+        }
+    } else {
+        IRQ_get_next(opp, &dst->servicing);
+        if (dst->raised.priority > dst->ctpr &&
+                dst->raised.priority > dst->servicing.priority) {
+            DPRINTF("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d\n",
+                    __func__, n_IRQ, dst->raised.next, dst->raised.priority,
+                    dst->ctpr, dst->servicing.priority, n_CPU);
+            /* IRQ line stays asserted */
+        } else {
+            DPRINTF("%s: IRQ %d inactive, current prio %d/%d, CPU %d\n",
+                    __func__, n_IRQ, dst->ctpr, dst->servicing.priority, n_CPU);
+            qemu_irq_lower(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
+        }
+    }
+}
+
+/* update pic state because registers for n_IRQ have changed value */
+static void openpic_update_irq(OpenPICState *opp, int n_IRQ)
+{
+    IRQSource *src;
+    bool active, was_active;
+    int i;
+
+    src = &opp->src[n_IRQ];
+    active = src->pending;
+
+    if ((src->ivpr & IVPR_MASK_MASK) && !src->nomask) {
+        /* Interrupt source is disabled */
+        DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
+        active = false;
+    }
+
+    was_active = !!(src->ivpr & IVPR_ACTIVITY_MASK);
+
+    /*
+     * We don't have a similar check for already-active because
+     * ctpr may have changed and we need to withdraw the interrupt.
+     */
+    if (!active && !was_active) {
+        DPRINTF("%s: IRQ %d is already inactive\n", __func__, n_IRQ);
+        return;
+    }
+
+    if (active) {
+        src->ivpr |= IVPR_ACTIVITY_MASK;
+    } else {
+        src->ivpr &= ~IVPR_ACTIVITY_MASK;
+    }
+
+    if (src->destmask == 0) {
+        /* No target */
+        DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
+        return;
+    }
+
+    if (src->destmask == (1 << src->last_cpu)) {
+        /* Only one CPU is allowed to receive this IRQ */
+        IRQ_local_pipe(opp, src->last_cpu, n_IRQ, active, was_active);
+    } else if (!(src->ivpr & IVPR_MODE_MASK)) {
+        /* Directed delivery mode */
+        for (i = 0; i < opp->nb_cpus; i++) {
+            if (src->destmask & (1 << i)) {
+                IRQ_local_pipe(opp, i, n_IRQ, active, was_active);
+            }
+        }
+    } else {
+        /* Distributed delivery mode */
+        for (i = src->last_cpu + 1; i != src->last_cpu; i++) {
+            if (i == opp->nb_cpus) {
+                i = 0;
+            }
+            if (src->destmask & (1 << i)) {
+                IRQ_local_pipe(opp, i, n_IRQ, active, was_active);
+                src->last_cpu = i;
+                break;
+            }
+        }
+    }
+}
+
+static void openpic_set_irq(void *opaque, int n_IRQ, int level)
+{
+    OpenPICState *opp = opaque;
+    IRQSource *src;
+
+    if (n_IRQ >= MAX_IRQ) {
+        fprintf(stderr, "%s: IRQ %d out of range\n", __func__, n_IRQ);
+        abort();
+    }
+
+    src = &opp->src[n_IRQ];
+    DPRINTF("openpic: set irq %d = %d ivpr=0x%08x\n",
+            n_IRQ, level, src->ivpr);
+    if (src->level) {
+        /* level-sensitive irq */
+        src->pending = level;
+        openpic_update_irq(opp, n_IRQ);
+    } else {
+        /* edge-sensitive irq */
+        if (level) {
+            src->pending = 1;
+            openpic_update_irq(opp, n_IRQ);
+        }
+
+        if (src->output != OPENPIC_OUTPUT_INT) {
+            /* Edge-triggered interrupts shouldn't be used
+             * with non-INT delivery, but just in case,
+             * try to make it do something sane rather than
+             * cause an interrupt storm.  This is close to
+             * what you'd probably see happen in real hardware.
+             */
+            src->pending = 0;
+            openpic_update_irq(opp, n_IRQ);
+        }
+    }
+}
+
+static void openpic_reset(DeviceState *d)
+{
+    OpenPICState *opp = FROM_SYSBUS(typeof(*opp), SYS_BUS_DEVICE(d));
+    int i;
+
+    opp->gcr = GCR_RESET;
+    /* Initialise controller registers */
+    opp->frr = ((opp->nb_irqs - 1) << FRR_NIRQ_SHIFT) |
+               ((opp->nb_cpus - 1) << FRR_NCPU_SHIFT) |
+               (opp->vid << FRR_VID_SHIFT);
+
+    opp->pir = 0;
+    opp->spve = -1 & opp->vector_mask;
+    opp->tfrr = opp->tfrr_reset;
+    /* Initialise IRQ sources */
+    for (i = 0; i < opp->max_irq; i++) {
+        opp->src[i].ivpr = opp->ivpr_reset;
+        opp->src[i].idr  = opp->idr_reset;
+
+        switch (opp->src[i].type) {
+        case IRQ_TYPE_NORMAL:
+            opp->src[i].level = !!(opp->ivpr_reset & IVPR_SENSE_MASK);
+            break;
+
+        case IRQ_TYPE_FSLINT:
+            opp->src[i].ivpr |= IVPR_POLARITY_MASK;
+            break;
+
+        case IRQ_TYPE_FSLSPECIAL:
+            break;
+        }
+    }
+    /* Initialise IRQ destinations */
+    for (i = 0; i < MAX_CPU; i++) {
+        opp->dst[i].ctpr      = 15;
+        memset(&opp->dst[i].raised, 0, sizeof(IRQQueue));
+        opp->dst[i].raised.next = -1;
+        memset(&opp->dst[i].servicing, 0, sizeof(IRQQueue));
+        opp->dst[i].servicing.next = -1;
+    }
+    /* Initialise timers */
+    for (i = 0; i < MAX_TMR; i++) {
+        opp->timers[i].tccr = 0;
+        opp->timers[i].tbcr = TBCR_CI;
+    }
+    /* Go out of RESET state */
+    opp->gcr = 0;
+}
+
+static inline uint32_t read_IRQreg_idr(OpenPICState *opp, int n_IRQ)
+{
+    return opp->src[n_IRQ].idr;
+}
+
+static inline uint32_t read_IRQreg_ilr(OpenPICState *opp, int n_IRQ)
+{
+    if (opp->flags & OPENPIC_FLAG_ILR) {
+        return output_to_inttgt(opp->src[n_IRQ].output);
+    }
+
+    return 0xffffffff;
+}
+
+static inline uint32_t read_IRQreg_ivpr(OpenPICState *opp, int n_IRQ)
+{
+    return opp->src[n_IRQ].ivpr;
+}
+
+static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val)
+{
+    IRQSource *src = &opp->src[n_IRQ];
+    uint32_t normal_mask = (1UL << opp->nb_cpus) - 1;
+    uint32_t crit_mask = 0;
+    uint32_t mask = normal_mask;
+    int crit_shift = IDR_EP_SHIFT - opp->nb_cpus;
+    int i;
+
+    if (opp->flags & OPENPIC_FLAG_IDR_CRIT) {
+        crit_mask = mask << crit_shift;
+        mask |= crit_mask | IDR_EP;
+    }
+
+    src->idr = val & mask;
+    DPRINTF("Set IDR %d to 0x%08x\n", n_IRQ, src->idr);
+
+    if (opp->flags & OPENPIC_FLAG_IDR_CRIT) {
+        if (src->idr & crit_mask) {
+            if (src->idr & normal_mask) {
+                DPRINTF("%s: IRQ configured for multiple output types, using "
+                        "critical\n", __func__);
+            }
+
+            src->output = OPENPIC_OUTPUT_CINT;
+            src->nomask = true;
+            src->destmask = 0;
+
+            for (i = 0; i < opp->nb_cpus; i++) {
+                int n_ci = IDR_CI0_SHIFT - i;
+
+                if (src->idr & (1UL << n_ci)) {
+                    src->destmask |= 1UL << i;
+                }
+            }
+        } else {
+            src->output = OPENPIC_OUTPUT_INT;
+            src->nomask = false;
+            src->destmask = src->idr & normal_mask;
+        }
+    } else {
+        src->destmask = src->idr;
+    }
+}
+
+static inline void write_IRQreg_ilr(OpenPICState *opp, int n_IRQ, uint32_t val)
+{
+    if (opp->flags & OPENPIC_FLAG_ILR) {
+        IRQSource *src = &opp->src[n_IRQ];
+
+        src->output = inttgt_to_output(val & ILR_INTTGT_MASK);
+        DPRINTF("Set ILR %d to 0x%08x, output %d\n", n_IRQ, src->idr,
+                src->output);
+
+        /* TODO: on MPIC v4.0 only, set nomask for non-INT */
+    }
+}
+
+static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val)
+{
+    uint32_t mask;
+
+    /* NOTE when implementing newer FSL MPIC models: starting with v4.0,
+     * the polarity bit is read-only on internal interrupts.
+     */
+    mask = IVPR_MASK_MASK | IVPR_PRIORITY_MASK | IVPR_SENSE_MASK |
+           IVPR_POLARITY_MASK | opp->vector_mask;
+
+    /* ACTIVITY bit is read-only */
+    opp->src[n_IRQ].ivpr =
+        (opp->src[n_IRQ].ivpr & IVPR_ACTIVITY_MASK) | (val & mask);
+
+    /* For FSL internal interrupts, The sense bit is reserved and zero,
+     * and the interrupt is always level-triggered.  Timers and IPIs
+     * have no sense or polarity bits, and are edge-triggered.
+     */
+    switch (opp->src[n_IRQ].type) {
+    case IRQ_TYPE_NORMAL:
+        opp->src[n_IRQ].level = !!(opp->src[n_IRQ].ivpr & IVPR_SENSE_MASK);
+        break;
+
+    case IRQ_TYPE_FSLINT:
+        opp->src[n_IRQ].ivpr &= ~IVPR_SENSE_MASK;
+        break;
+
+    case IRQ_TYPE_FSLSPECIAL:
+        opp->src[n_IRQ].ivpr &= ~(IVPR_POLARITY_MASK | IVPR_SENSE_MASK);
+        break;
+    }
+
+    openpic_update_irq(opp, n_IRQ);
+    DPRINTF("Set IVPR %d to 0x%08x -> 0x%08x\n", n_IRQ, val,
+            opp->src[n_IRQ].ivpr);
+}
+
+static void openpic_gcr_write(OpenPICState *opp, uint64_t val)
+{
+    bool mpic_proxy = false;
+
+    if (val & GCR_RESET) {
+        openpic_reset(&opp->busdev.qdev);
+        return;
+    }
+
+    opp->gcr &= ~opp->mpic_mode_mask;
+    opp->gcr |= val & opp->mpic_mode_mask;
+
+    /* Set external proxy mode */
+    if ((val & opp->mpic_mode_mask) == GCR_MODE_PROXY) {
+        mpic_proxy = true;
+    }
+
+    ppce500_set_mpic_proxy(mpic_proxy);
+}
+
+static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val,
+                              unsigned len)
+{
+    OpenPICState *opp = opaque;
+    IRQDest *dst;
+    int idx;
+
+    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
+            __func__, addr, val);
+    if (addr & 0xF) {
+        return;
+    }
+    switch (addr) {
+    case 0x00: /* Block Revision Register1 (BRR1) is Readonly */
+        break;
+    case 0x40:
+    case 0x50:
+    case 0x60:
+    case 0x70:
+    case 0x80:
+    case 0x90:
+    case 0xA0:
+    case 0xB0:
+        openpic_cpu_write_internal(opp, addr, val, get_current_cpu());
+        break;
+    case 0x1000: /* FRR */
+        break;
+    case 0x1020: /* GCR */
+        openpic_gcr_write(opp, val);
+        break;
+    case 0x1080: /* VIR */
+        break;
+    case 0x1090: /* PIR */
+        for (idx = 0; idx < opp->nb_cpus; idx++) {
+            if ((val & (1 << idx)) && !(opp->pir & (1 << idx))) {
+                DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
+                dst = &opp->dst[idx];
+                qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
+            } else if (!(val & (1 << idx)) && (opp->pir & (1 << idx))) {
+                DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
+                dst = &opp->dst[idx];
+                qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
+            }
+        }
+        opp->pir = val;
+        break;
+    case 0x10A0: /* IPI_IVPR */
+    case 0x10B0:
+    case 0x10C0:
+    case 0x10D0:
+        {
+            int idx;
+            idx = (addr - 0x10A0) >> 4;
+            write_IRQreg_ivpr(opp, opp->irq_ipi0 + idx, val);
+        }
+        break;
+    case 0x10E0: /* SPVE */
+        opp->spve = val & opp->vector_mask;
+        break;
+    default:
+        break;
+    }
+}
+
+static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len)
+{
+    OpenPICState *opp = opaque;
+    uint32_t retval;
+
+    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
+    retval = 0xFFFFFFFF;
+    if (addr & 0xF) {
+        return retval;
+    }
+    switch (addr) {
+    case 0x1000: /* FRR */
+        retval = opp->frr;
+        break;
+    case 0x1020: /* GCR */
+        retval = opp->gcr;
+        break;
+    case 0x1080: /* VIR */
+        retval = opp->vir;
+        break;
+    case 0x1090: /* PIR */
+        retval = 0x00000000;
+        break;
+    case 0x00: /* Block Revision Register1 (BRR1) */
+        retval = opp->brr1;
+        break;
+    case 0x40:
+    case 0x50:
+    case 0x60:
+    case 0x70:
+    case 0x80:
+    case 0x90:
+    case 0xA0:
+    case 0xB0:
+        retval = openpic_cpu_read_internal(opp, addr, get_current_cpu());
+        break;
+    case 0x10A0: /* IPI_IVPR */
+    case 0x10B0:
+    case 0x10C0:
+    case 0x10D0:
+        {
+            int idx;
+            idx = (addr - 0x10A0) >> 4;
+            retval = read_IRQreg_ivpr(opp, opp->irq_ipi0 + idx);
+        }
+        break;
+    case 0x10E0: /* SPVE */
+        retval = opp->spve;
+        break;
+    default:
+        break;
+    }
+    DPRINTF("%s: => 0x%08x\n", __func__, retval);
+
+    return retval;
+}
+
+static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val,
+                                unsigned len)
+{
+    OpenPICState *opp = opaque;
+    int idx;
+
+    addr += 0x10f0;
+
+    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
+            __func__, addr, val);
+    if (addr & 0xF) {
+        return;
+    }
+
+    if (addr == 0x10f0) {
+        /* TFRR */
+        opp->tfrr = val;
+        return;
+    }
+
+    idx = (addr >> 6) & 0x3;
+    addr = addr & 0x30;
+
+    switch (addr & 0x30) {
+    case 0x00: /* TCCR */
+        break;
+    case 0x10: /* TBCR */
+        if ((opp->timers[idx].tccr & TCCR_TOG) != 0 &&
+            (val & TBCR_CI) == 0 &&
+            (opp->timers[idx].tbcr & TBCR_CI) != 0) {
+            opp->timers[idx].tccr &= ~TCCR_TOG;
+        }
+        opp->timers[idx].tbcr = val;
+        break;
+    case 0x20: /* TVPR */
+        write_IRQreg_ivpr(opp, opp->irq_tim0 + idx, val);
+        break;
+    case 0x30: /* TDR */
+        write_IRQreg_idr(opp, opp->irq_tim0 + idx, val);
+        break;
+    }
+}
+
+static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len)
+{
+    OpenPICState *opp = opaque;
+    uint32_t retval = -1;
+    int idx;
+
+    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
+    if (addr & 0xF) {
+        goto out;
+    }
+    idx = (addr >> 6) & 0x3;
+    if (addr == 0x0) {
+        /* TFRR */
+        retval = opp->tfrr;
+        goto out;
+    }
+    switch (addr & 0x30) {
+    case 0x00: /* TCCR */
+        retval = opp->timers[idx].tccr;
+        break;
+    case 0x10: /* TBCR */
+        retval = opp->timers[idx].tbcr;
+        break;
+    case 0x20: /* TIPV */
+        retval = read_IRQreg_ivpr(opp, opp->irq_tim0 + idx);
+        break;
+    case 0x30: /* TIDE (TIDR) */
+        retval = read_IRQreg_idr(opp, opp->irq_tim0 + idx);
+        break;
+    }
+
+out:
+    DPRINTF("%s: => 0x%08x\n", __func__, retval);
+
+    return retval;
+}
+
+static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val,
+                              unsigned len)
+{
+    OpenPICState *opp = opaque;
+    int idx;
+
+    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
+            __func__, addr, val);
+
+    addr = addr & 0xffff;
+    idx = addr >> 5;
+
+    switch (addr & 0x1f) {
+    case 0x00:
+        write_IRQreg_ivpr(opp, idx, val);
+        break;
+    case 0x10:
+        write_IRQreg_idr(opp, idx, val);
+        break;
+    case 0x18:
+        write_IRQreg_ilr(opp, idx, val);
+        break;
+    }
+}
+
+static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len)
+{
+    OpenPICState *opp = opaque;
+    uint32_t retval;
+    int idx;
+
+    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
+    retval = 0xFFFFFFFF;
+
+    addr = addr & 0xffff;
+    idx = addr >> 5;
+
+    switch (addr & 0x1f) {
+    case 0x00:
+        retval = read_IRQreg_ivpr(opp, idx);
+        break;
+    case 0x10:
+        retval = read_IRQreg_idr(opp, idx);
+        break;
+    case 0x18:
+        retval = read_IRQreg_ilr(opp, idx);
+        break;
+    }
+
+    DPRINTF("%s: => 0x%08x\n", __func__, retval);
+    return retval;
+}
+
+static void openpic_msi_write(void *opaque, hwaddr addr, uint64_t val,
+                              unsigned size)
+{
+    OpenPICState *opp = opaque;
+    int idx = opp->irq_msi;
+    int srs, ibs;
+
+    DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n",
+            __func__, addr, val);
+    if (addr & 0xF) {
+        return;
+    }
+
+    switch (addr) {
+    case MSIIR_OFFSET:
+        srs = val >> MSIIR_SRS_SHIFT;
+        idx += srs;
+        ibs = (val & MSIIR_IBS_MASK) >> MSIIR_IBS_SHIFT;
+        opp->msi[srs].msir |= 1 << ibs;
+        openpic_set_irq(opp, idx, 1);
+        break;
+    default:
+        /* most registers are read-only, thus ignored */
+        break;
+    }
+}
+
+static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size)
+{
+    OpenPICState *opp = opaque;
+    uint64_t r = 0;
+    int i, srs;
+
+    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
+    if (addr & 0xF) {
+        return -1;
+    }
+
+    srs = addr >> 4;
+
+    switch (addr) {
+    case 0x00:
+    case 0x10:
+    case 0x20:
+    case 0x30:
+    case 0x40:
+    case 0x50:
+    case 0x60:
+    case 0x70: /* MSIRs */
+        r = opp->msi[srs].msir;
+        /* Clear on read */
+        opp->msi[srs].msir = 0;
+        openpic_set_irq(opp, opp->irq_msi + srs, 0);
+        break;
+    case 0x120: /* MSISR */
+        for (i = 0; i < MAX_MSI; i++) {
+            r |= (opp->msi[i].msir ? 1 : 0) << i;
+        }
+        break;
+    }
+
+    return r;
+}
+
+static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size)
+{
+    uint64_t r = 0;
+
+    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
+
+    /* TODO: EISR/EIMR */
+
+    return r;
+}
+
+static void openpic_summary_write(void *opaque, hwaddr addr, uint64_t val,
+                                  unsigned size)
+{
+    DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n",
+            __func__, addr, val);
+
+    /* TODO: EISR/EIMR */
+}
+
+static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
+                                       uint32_t val, int idx)
+{
+    OpenPICState *opp = opaque;
+    IRQSource *src;
+    IRQDest *dst;
+    int s_IRQ, n_IRQ;
+
+    DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx " <= 0x%08x\n", __func__, idx,
+            addr, val);
+
+    if (idx < 0) {
+        return;
+    }
+
+    if (addr & 0xF) {
+        return;
+    }
+    dst = &opp->dst[idx];
+    addr &= 0xFF0;
+    switch (addr) {
+    case 0x40: /* IPIDR */
+    case 0x50:
+    case 0x60:
+    case 0x70:
+        idx = (addr - 0x40) >> 4;
+        /* we use IDE as mask which CPUs to deliver the IPI to still. */
+        opp->src[opp->irq_ipi0 + idx].destmask |= val;
+        openpic_set_irq(opp, opp->irq_ipi0 + idx, 1);
+        openpic_set_irq(opp, opp->irq_ipi0 + idx, 0);
+        break;
+    case 0x80: /* CTPR */
+        dst->ctpr = val & 0x0000000F;
+
+        DPRINTF("%s: set CPU %d ctpr to %d, raised %d servicing %d\n",
+                __func__, idx, dst->ctpr, dst->raised.priority,
+                dst->servicing.priority);
+
+        if (dst->raised.priority <= dst->ctpr) {
+            DPRINTF("%s: Lower OpenPIC INT output cpu %d due to ctpr\n",
+                    __func__, idx);
+            qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
+        } else if (dst->raised.priority > dst->servicing.priority) {
+            DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d\n",
+                    __func__, idx, dst->raised.next);
+            qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
+        }
+
+        break;
+    case 0x90: /* WHOAMI */
+        /* Read-only register */
+        break;
+    case 0xA0: /* IACK */
+        /* Read-only register */
+        break;
+    case 0xB0: /* EOI */
+        DPRINTF("EOI\n");
+        s_IRQ = IRQ_get_next(opp, &dst->servicing);
+
+        if (s_IRQ < 0) {
+            DPRINTF("%s: EOI with no interrupt in service\n", __func__);
+            break;
+        }
+
+        IRQ_resetbit(&dst->servicing, s_IRQ);
+        /* Set up next servicing IRQ */
+        s_IRQ = IRQ_get_next(opp, &dst->servicing);
+        /* Check queued interrupts. */
+        n_IRQ = IRQ_get_next(opp, &dst->raised);
+        src = &opp->src[n_IRQ];
+        if (n_IRQ != -1 &&
+            (s_IRQ == -1 ||
+             IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) {
+            DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
+                    idx, n_IRQ);
+            qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]);
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+static void openpic_cpu_write(void *opaque, hwaddr addr, uint64_t val,
+                              unsigned len)
+{
+    openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12);
+}
+
+
+static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu)
+{
+    IRQSource *src;
+    int retval, irq;
+
+    DPRINTF("Lower OpenPIC INT output\n");
+    qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
+
+    irq = IRQ_get_next(opp, &dst->raised);
+    DPRINTF("IACK: irq=%d\n", irq);
+
+    if (irq == -1) {
+        /* No more interrupt pending */
+        return opp->spve;
+    }
+
+    src = &opp->src[irq];
+    if (!(src->ivpr & IVPR_ACTIVITY_MASK) ||
+            !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) {
+        fprintf(stderr, "%s: bad raised IRQ %d ctpr %d ivpr 0x%08x\n",
+                __func__, irq, dst->ctpr, src->ivpr);
+        openpic_update_irq(opp, irq);
+        retval = opp->spve;
+    } else {
+        /* IRQ enter servicing state */
+        IRQ_setbit(&dst->servicing, irq);
+        retval = IVPR_VECTOR(opp, src->ivpr);
+    }
+
+    if (!src->level) {
+        /* edge-sensitive IRQ */
+        src->ivpr &= ~IVPR_ACTIVITY_MASK;
+        src->pending = 0;
+        IRQ_resetbit(&dst->raised, irq);
+    }
+
+    if ((irq >= opp->irq_ipi0) &&  (irq < (opp->irq_ipi0 + MAX_IPI))) {
+        src->destmask &= ~(1 << cpu);
+        if (src->destmask && !src->level) {
+            /* trigger on CPUs that didn't know about it yet */
+            openpic_set_irq(opp, irq, 1);
+            openpic_set_irq(opp, irq, 0);
+            /* if all CPUs knew about it, set active bit again */
+            src->ivpr |= IVPR_ACTIVITY_MASK;
+        }
+    }
+
+    return retval;
+}
+
+static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
+                                          int idx)
+{
+    OpenPICState *opp = opaque;
+    IRQDest *dst;
+    uint32_t retval;
+
+    DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx "\n", __func__, idx, addr);
+    retval = 0xFFFFFFFF;
+
+    if (idx < 0) {
+        return retval;
+    }
+
+    if (addr & 0xF) {
+        return retval;
+    }
+    dst = &opp->dst[idx];
+    addr &= 0xFF0;
+    switch (addr) {
+    case 0x80: /* CTPR */
+        retval = dst->ctpr;
+        break;
+    case 0x90: /* WHOAMI */
+        retval = idx;
+        break;
+    case 0xA0: /* IACK */
+        retval = openpic_iack(opp, dst, idx);
+        break;
+    case 0xB0: /* EOI */
+        retval = 0;
+        break;
+    default:
+        break;
+    }
+    DPRINTF("%s: => 0x%08x\n", __func__, retval);
+
+    return retval;
+}
+
+static uint64_t openpic_cpu_read(void *opaque, hwaddr addr, unsigned len)
+{
+    return openpic_cpu_read_internal(opaque, addr, (addr & 0x1f000) >> 12);
+}
+
+static const MemoryRegionOps openpic_glb_ops_le = {
+    .write = openpic_gbl_write,
+    .read  = openpic_gbl_read,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps openpic_glb_ops_be = {
+    .write = openpic_gbl_write,
+    .read  = openpic_gbl_read,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps openpic_tmr_ops_le = {
+    .write = openpic_tmr_write,
+    .read  = openpic_tmr_read,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps openpic_tmr_ops_be = {
+    .write = openpic_tmr_write,
+    .read  = openpic_tmr_read,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps openpic_cpu_ops_le = {
+    .write = openpic_cpu_write,
+    .read  = openpic_cpu_read,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps openpic_cpu_ops_be = {
+    .write = openpic_cpu_write,
+    .read  = openpic_cpu_read,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps openpic_src_ops_le = {
+    .write = openpic_src_write,
+    .read  = openpic_src_read,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps openpic_src_ops_be = {
+    .write = openpic_src_write,
+    .read  = openpic_src_read,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps openpic_msi_ops_be = {
+    .read = openpic_msi_read,
+    .write = openpic_msi_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps openpic_summary_ops_be = {
+    .read = openpic_summary_read,
+    .write = openpic_summary_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void openpic_save_IRQ_queue(QEMUFile* f, IRQQueue *q)
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(q->queue); i++) {
+        /* Always put the lower half of a 64-bit long first, in case we
+         * restore on a 32-bit host.  The least significant bits correspond
+         * to lower IRQ numbers in the bitmap.
+         */
+        qemu_put_be32(f, (uint32_t)q->queue[i]);
+#if LONG_MAX > 0x7FFFFFFF
+        qemu_put_be32(f, (uint32_t)(q->queue[i] >> 32));
+#endif
+    }
+
+    qemu_put_sbe32s(f, &q->next);
+    qemu_put_sbe32s(f, &q->priority);
+}
+
+static void openpic_save(QEMUFile* f, void *opaque)
+{
+    OpenPICState *opp = (OpenPICState *)opaque;
+    unsigned int i;
+
+    qemu_put_be32s(f, &opp->gcr);
+    qemu_put_be32s(f, &opp->vir);
+    qemu_put_be32s(f, &opp->pir);
+    qemu_put_be32s(f, &opp->spve);
+    qemu_put_be32s(f, &opp->tfrr);
+
+    qemu_put_be32s(f, &opp->nb_cpus);
+
+    for (i = 0; i < opp->nb_cpus; i++) {
+        qemu_put_sbe32s(f, &opp->dst[i].ctpr);
+        openpic_save_IRQ_queue(f, &opp->dst[i].raised);
+        openpic_save_IRQ_queue(f, &opp->dst[i].servicing);
+        qemu_put_buffer(f, (uint8_t *)&opp->dst[i].outputs_active,
+                        sizeof(opp->dst[i].outputs_active));
+    }
+
+    for (i = 0; i < MAX_TMR; i++) {
+        qemu_put_be32s(f, &opp->timers[i].tccr);
+        qemu_put_be32s(f, &opp->timers[i].tbcr);
+    }
+
+    for (i = 0; i < opp->max_irq; i++) {
+        qemu_put_be32s(f, &opp->src[i].ivpr);
+        qemu_put_be32s(f, &opp->src[i].idr);
+        qemu_get_be32s(f, &opp->src[i].destmask);
+        qemu_put_sbe32s(f, &opp->src[i].last_cpu);
+        qemu_put_sbe32s(f, &opp->src[i].pending);
+    }
+}
+
+static void openpic_load_IRQ_queue(QEMUFile* f, IRQQueue *q)
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(q->queue); i++) {
+        unsigned long val;
+
+        val = qemu_get_be32(f);
+#if LONG_MAX > 0x7FFFFFFF
+        val <<= 32;
+        val |= qemu_get_be32(f);
+#endif
+
+        q->queue[i] = val;
+    }
+
+    qemu_get_sbe32s(f, &q->next);
+    qemu_get_sbe32s(f, &q->priority);
+}
+
+static int openpic_load(QEMUFile* f, void *opaque, int version_id)
+{
+    OpenPICState *opp = (OpenPICState *)opaque;
+    unsigned int i;
+
+    if (version_id != 1) {
+        return -EINVAL;
+    }
+
+    qemu_get_be32s(f, &opp->gcr);
+    qemu_get_be32s(f, &opp->vir);
+    qemu_get_be32s(f, &opp->pir);
+    qemu_get_be32s(f, &opp->spve);
+    qemu_get_be32s(f, &opp->tfrr);
+
+    qemu_get_be32s(f, &opp->nb_cpus);
+
+    for (i = 0; i < opp->nb_cpus; i++) {
+        qemu_get_sbe32s(f, &opp->dst[i].ctpr);
+        openpic_load_IRQ_queue(f, &opp->dst[i].raised);
+        openpic_load_IRQ_queue(f, &opp->dst[i].servicing);
+        qemu_get_buffer(f, (uint8_t *)&opp->dst[i].outputs_active,
+                        sizeof(opp->dst[i].outputs_active));
+    }
+
+    for (i = 0; i < MAX_TMR; i++) {
+        qemu_get_be32s(f, &opp->timers[i].tccr);
+        qemu_get_be32s(f, &opp->timers[i].tbcr);
+    }
+
+    for (i = 0; i < opp->max_irq; i++) {
+        uint32_t val;
+
+        val = qemu_get_be32(f);
+        write_IRQreg_idr(opp, i, val);
+        val = qemu_get_be32(f);
+        write_IRQreg_ivpr(opp, i, val);
+
+        qemu_get_be32s(f, &opp->src[i].ivpr);
+        qemu_get_be32s(f, &opp->src[i].idr);
+        qemu_get_be32s(f, &opp->src[i].destmask);
+        qemu_get_sbe32s(f, &opp->src[i].last_cpu);
+        qemu_get_sbe32s(f, &opp->src[i].pending);
+    }
+
+    return 0;
+}
+
+typedef struct MemReg {
+    const char             *name;
+    MemoryRegionOps const  *ops;
+    hwaddr      start_addr;
+    ram_addr_t              size;
+} MemReg;
+
+static void fsl_common_init(OpenPICState *opp)
+{
+    int i;
+    int virq = MAX_SRC;
+
+    opp->vid = VID_REVISION_1_2;
+    opp->vir = VIR_GENERIC;
+    opp->vector_mask = 0xFFFF;
+    opp->tfrr_reset = 0;
+    opp->ivpr_reset = IVPR_MASK_MASK;
+    opp->idr_reset = 1 << 0;
+    opp->max_irq = MAX_IRQ;
+
+    opp->irq_ipi0 = virq;
+    virq += MAX_IPI;
+    opp->irq_tim0 = virq;
+    virq += MAX_TMR;
+
+    assert(virq <= MAX_IRQ);
+
+    opp->irq_msi = 224;
+
+    msi_supported = true;
+    for (i = 0; i < opp->fsl->max_ext; i++) {
+        opp->src[i].level = false;
+    }
+
+    /* Internal interrupts, including message and MSI */
+    for (i = 16; i < MAX_SRC; i++) {
+        opp->src[i].type = IRQ_TYPE_FSLINT;
+        opp->src[i].level = true;
+    }
+
+    /* timers and IPIs */
+    for (i = MAX_SRC; i < virq; i++) {
+        opp->src[i].type = IRQ_TYPE_FSLSPECIAL;
+        opp->src[i].level = false;
+    }
+}
+
+static void map_list(OpenPICState *opp, const MemReg *list, int *count)
+{
+    while (list->name) {
+        assert(*count < ARRAY_SIZE(opp->sub_io_mem));
+
+        memory_region_init_io(&opp->sub_io_mem[*count], list->ops, opp,
+                              list->name, list->size);
+
+        memory_region_add_subregion(&opp->mem, list->start_addr,
+                                    &opp->sub_io_mem[*count]);
+
+        (*count)++;
+        list++;
+    }
+}
+
+static int openpic_init(SysBusDevice *dev)
+{
+    OpenPICState *opp = FROM_SYSBUS(typeof (*opp), dev);
+    int i, j;
+    int list_count = 0;
+    static const MemReg list_le[] = {
+        {"glb", &openpic_glb_ops_le,
+                OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE},
+        {"tmr", &openpic_tmr_ops_le,
+                OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE},
+        {"src", &openpic_src_ops_le,
+                OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE},
+        {"cpu", &openpic_cpu_ops_le,
+                OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE},
+        {NULL}
+    };
+    static const MemReg list_be[] = {
+        {"glb", &openpic_glb_ops_be,
+                OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE},
+        {"tmr", &openpic_tmr_ops_be,
+                OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE},
+        {"src", &openpic_src_ops_be,
+                OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE},
+        {"cpu", &openpic_cpu_ops_be,
+                OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE},
+        {NULL}
+    };
+    static const MemReg list_fsl[] = {
+        {"msi", &openpic_msi_ops_be,
+                OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE},
+        {"summary", &openpic_summary_ops_be,
+                OPENPIC_SUMMARY_REG_START, OPENPIC_SUMMARY_REG_SIZE},
+        {NULL}
+    };
+
+    memory_region_init(&opp->mem, "openpic", 0x40000);
+
+    switch (opp->model) {
+    case OPENPIC_MODEL_FSL_MPIC_20:
+    default:
+        opp->fsl = &fsl_mpic_20;
+        opp->brr1 = 0x00400200;
+        opp->flags |= OPENPIC_FLAG_IDR_CRIT;
+        opp->nb_irqs = 80;
+        opp->mpic_mode_mask = GCR_MODE_MIXED;
+
+        fsl_common_init(opp);
+        map_list(opp, list_be, &list_count);
+        map_list(opp, list_fsl, &list_count);
+
+        break;
+
+    case OPENPIC_MODEL_FSL_MPIC_42:
+        opp->fsl = &fsl_mpic_42;
+        opp->brr1 = 0x00400402;
+        opp->flags |= OPENPIC_FLAG_ILR;
+        opp->nb_irqs = 196;
+        opp->mpic_mode_mask = GCR_MODE_PROXY;
+
+        fsl_common_init(opp);
+        map_list(opp, list_be, &list_count);
+        map_list(opp, list_fsl, &list_count);
+
+        break;
+
+    case OPENPIC_MODEL_RAVEN:
+        opp->nb_irqs = RAVEN_MAX_EXT;
+        opp->vid = VID_REVISION_1_3;
+        opp->vir = VIR_GENERIC;
+        opp->vector_mask = 0xFF;
+        opp->tfrr_reset = 4160000;
+        opp->ivpr_reset = IVPR_MASK_MASK | IVPR_MODE_MASK;
+        opp->idr_reset = 0;
+        opp->max_irq = RAVEN_MAX_IRQ;
+        opp->irq_ipi0 = RAVEN_IPI_IRQ;
+        opp->irq_tim0 = RAVEN_TMR_IRQ;
+        opp->brr1 = -1;
+        opp->mpic_mode_mask = GCR_MODE_MIXED;
+
+        /* Only UP supported today */
+        if (opp->nb_cpus != 1) {
+            return -EINVAL;
+        }
+
+        map_list(opp, list_le, &list_count);
+        break;
+    }
+
+    for (i = 0; i < opp->nb_cpus; i++) {
+        opp->dst[i].irqs = g_new(qemu_irq, OPENPIC_OUTPUT_NB);
+        for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
+            sysbus_init_irq(dev, &opp->dst[i].irqs[j]);
+        }
+    }
+
+    register_savevm(&opp->busdev.qdev, "openpic", 0, 2,
+                    openpic_save, openpic_load, opp);
+
+    sysbus_init_mmio(dev, &opp->mem);
+    qdev_init_gpio_in(&dev->qdev, openpic_set_irq, opp->max_irq);
+
+    return 0;
+}
+
+static Property openpic_properties[] = {
+    DEFINE_PROP_UINT32("model", OpenPICState, model, OPENPIC_MODEL_FSL_MPIC_20),
+    DEFINE_PROP_UINT32("nb_cpus", OpenPICState, nb_cpus, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void openpic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = openpic_init;
+    dc->props = openpic_properties;
+    dc->reset = openpic_reset;
+}
+
+static const TypeInfo openpic_info = {
+    .name          = "openpic",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(OpenPICState),
+    .class_init    = openpic_class_init,
+};
+
+static void openpic_register_types(void)
+{
+    type_register_static(&openpic_info);
+}
+
+type_init(openpic_register_types)
diff --git a/hw/intc/realview_gic.c b/hw/intc/realview_gic.c
new file mode 100644 (file)
index 0000000..0ec30ca
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * ARM RealView Emulation Baseboard Interrupt Controller
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/sysbus.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    DeviceState *gic;
+    MemoryRegion container;
+} RealViewGICState;
+
+static void realview_gic_set_irq(void *opaque, int irq, int level)
+{
+    RealViewGICState *s = (RealViewGICState *)opaque;
+    qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
+}
+
+static int realview_gic_init(SysBusDevice *dev)
+{
+    RealViewGICState *s = FROM_SYSBUS(RealViewGICState, dev);
+    SysBusDevice *busdev;
+    /* The GICs on the RealView boards have a fixed nonconfigurable
+     * number of interrupt lines, so we don't need to expose this as
+     * a qdev property.
+     */
+    int numirq = 96;
+
+    s->gic = qdev_create(NULL, "arm_gic");
+    qdev_prop_set_uint32(s->gic, "num-cpu", 1);
+    qdev_prop_set_uint32(s->gic, "num-irq", numirq);
+    qdev_init_nofail(s->gic);
+    busdev = SYS_BUS_DEVICE(s->gic);
+
+    /* Pass through outbound IRQ lines from the GIC */
+    sysbus_pass_irq(dev, busdev);
+
+    /* Pass through inbound GPIO lines to the GIC */
+    qdev_init_gpio_in(&s->busdev.qdev, realview_gic_set_irq, numirq - 32);
+
+    memory_region_init(&s->container, "realview-gic-container", 0x2000);
+    memory_region_add_subregion(&s->container, 0,
+                                sysbus_mmio_get_region(busdev, 1));
+    memory_region_add_subregion(&s->container, 0x1000,
+                                sysbus_mmio_get_region(busdev, 0));
+    sysbus_init_mmio(dev, &s->container);
+    return 0;
+}
+
+static void realview_gic_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = realview_gic_init;
+}
+
+static const TypeInfo realview_gic_info = {
+    .name          = "realview_gic",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(RealViewGICState),
+    .class_init    = realview_gic_class_init,
+};
+
+static void realview_gic_register_types(void)
+{
+    type_register_static(&realview_gic_info);
+}
+
+type_init(realview_gic_register_types)
diff --git a/hw/intc/sbi.c b/hw/intc/sbi.c
new file mode 100644 (file)
index 0000000..8795749
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * QEMU Sparc SBI interrupt controller emulation
+ *
+ * Based on slavio_intctl, copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/sysbus.h"
+
+//#define DEBUG_IRQ
+
+#ifdef DEBUG_IRQ
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("IRQ: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+#define MAX_CPUS 16
+
+#define SBI_NREGS 16
+
+typedef struct SBIState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t regs[SBI_NREGS];
+    uint32_t intreg_pending[MAX_CPUS];
+    qemu_irq cpu_irqs[MAX_CPUS];
+    uint32_t pil_out[MAX_CPUS];
+} SBIState;
+
+#define SBI_SIZE (SBI_NREGS * 4)
+
+static void sbi_set_irq(void *opaque, int irq, int level)
+{
+}
+
+static uint64_t sbi_mem_read(void *opaque, hwaddr addr,
+                             unsigned size)
+{
+    SBIState *s = opaque;
+    uint32_t saddr, ret;
+
+    saddr = addr >> 2;
+    switch (saddr) {
+    default:
+        ret = s->regs[saddr];
+        break;
+    }
+    DPRINTF("read system reg 0x" TARGET_FMT_plx " = %x\n", addr, ret);
+
+    return ret;
+}
+
+static void sbi_mem_write(void *opaque, hwaddr addr,
+                          uint64_t val, unsigned dize)
+{
+    SBIState *s = opaque;
+    uint32_t saddr;
+
+    saddr = addr >> 2;
+    DPRINTF("write system reg 0x" TARGET_FMT_plx " = %x\n", addr, (int)val);
+    switch (saddr) {
+    default:
+        s->regs[saddr] = val;
+        break;
+    }
+}
+
+static const MemoryRegionOps sbi_mem_ops = {
+    .read = sbi_mem_read,
+    .write = sbi_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const VMStateDescription vmstate_sbi = {
+    .name ="sbi",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32_ARRAY(intreg_pending, SBIState, MAX_CPUS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void sbi_reset(DeviceState *d)
+{
+    SBIState *s = container_of(d, SBIState, busdev.qdev);
+    unsigned int i;
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        s->intreg_pending[i] = 0;
+    }
+}
+
+static int sbi_init1(SysBusDevice *dev)
+{
+    SBIState *s = FROM_SYSBUS(SBIState, dev);
+    unsigned int i;
+
+    qdev_init_gpio_in(&dev->qdev, sbi_set_irq, 32 + MAX_CPUS);
+    for (i = 0; i < MAX_CPUS; i++) {
+        sysbus_init_irq(dev, &s->cpu_irqs[i]);
+    }
+
+    memory_region_init_io(&s->iomem, &sbi_mem_ops, s, "sbi", SBI_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static void sbi_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = sbi_init1;
+    dc->reset = sbi_reset;
+    dc->vmsd = &vmstate_sbi;
+}
+
+static const TypeInfo sbi_info = {
+    .name          = "sbi",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SBIState),
+    .class_init    = sbi_class_init,
+};
+
+static void sbi_register_types(void)
+{
+    type_register_static(&sbi_info);
+}
+
+type_init(sbi_register_types)
diff --git a/hw/intc/sh_intc.c b/hw/intc/sh_intc.c
new file mode 100644 (file)
index 0000000..050bfb6
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ * SuperH interrupt controller module
+ *
+ * Copyright (c) 2007 Magnus Damm
+ * Based on sh_timer.c and arm_timer.c by Paul Brook
+ * Copyright (c) 2005-2006 CodeSourcery.
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/sh4/sh_intc.h"
+#include "hw/hw.h"
+#include "hw/sh4/sh.h"
+
+//#define DEBUG_INTC
+//#define DEBUG_INTC_SOURCES
+
+#define INTC_A7(x) ((x) & 0x1fffffff)
+
+void sh_intc_toggle_source(struct intc_source *source,
+                          int enable_adj, int assert_adj)
+{
+    int enable_changed = 0;
+    int pending_changed = 0;
+    int old_pending;
+
+    if ((source->enable_count == source->enable_max) && (enable_adj == -1))
+        enable_changed = -1;
+
+    source->enable_count += enable_adj;
+
+    if (source->enable_count == source->enable_max)
+        enable_changed = 1;
+
+    source->asserted += assert_adj;
+
+    old_pending = source->pending;
+    source->pending = source->asserted &&
+      (source->enable_count == source->enable_max);
+
+    if (old_pending != source->pending)
+        pending_changed = 1;
+
+    if (pending_changed) {
+        CPUState *cpu = CPU(sh_env_get_cpu(first_cpu));
+        if (source->pending) {
+            source->parent->pending++;
+            if (source->parent->pending == 1) {
+                cpu_interrupt(cpu, CPU_INTERRUPT_HARD);
+            }
+        } else {
+            source->parent->pending--;
+            if (source->parent->pending == 0) {
+                cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD);
+            }
+       }
+    }
+
+  if (enable_changed || assert_adj || pending_changed) {
+#ifdef DEBUG_INTC_SOURCES
+            printf("sh_intc: (%d/%d/%d/%d) interrupt source 0x%x %s%s%s\n",
+                  source->parent->pending,
+                  source->asserted,
+                  source->enable_count,
+                  source->enable_max,
+                  source->vect,
+                  source->asserted ? "asserted " :
+                  assert_adj ? "deasserted" : "",
+                  enable_changed == 1 ? "enabled " :
+                  enable_changed == -1 ? "disabled " : "",
+                  source->pending ? "pending" : "");
+#endif
+  }
+}
+
+static void sh_intc_set_irq (void *opaque, int n, int level)
+{
+  struct intc_desc *desc = opaque;
+  struct intc_source *source = &(desc->sources[n]);
+
+  if (level && !source->asserted)
+    sh_intc_toggle_source(source, 0, 1);
+  else if (!level && source->asserted)
+    sh_intc_toggle_source(source, 0, -1);
+}
+
+int sh_intc_get_pending_vector(struct intc_desc *desc, int imask)
+{
+    unsigned int i;
+
+    /* slow: use a linked lists of pending sources instead */
+    /* wrong: take interrupt priority into account (one list per priority) */
+
+    if (imask == 0x0f) {
+        return -1; /* FIXME, update code to include priority per source */
+    }
+
+    for (i = 0; i < desc->nr_sources; i++) {
+        struct intc_source *source = desc->sources + i;
+
+       if (source->pending) {
+#ifdef DEBUG_INTC_SOURCES
+            printf("sh_intc: (%d) returning interrupt source 0x%x\n",
+                  desc->pending, source->vect);
+#endif
+            return source->vect;
+       }
+    }
+
+    abort();
+}
+
+#define INTC_MODE_NONE       0
+#define INTC_MODE_DUAL_SET   1
+#define INTC_MODE_DUAL_CLR   2
+#define INTC_MODE_ENABLE_REG 3
+#define INTC_MODE_MASK_REG   4
+#define INTC_MODE_IS_PRIO    8
+
+static unsigned int sh_intc_mode(unsigned long address,
+                                unsigned long set_reg, unsigned long clr_reg)
+{
+    if ((address != INTC_A7(set_reg)) &&
+       (address != INTC_A7(clr_reg)))
+        return INTC_MODE_NONE;
+
+    if (set_reg && clr_reg) {
+        if (address == INTC_A7(set_reg))
+            return INTC_MODE_DUAL_SET;
+       else
+            return INTC_MODE_DUAL_CLR;
+    }
+
+    if (set_reg)
+        return INTC_MODE_ENABLE_REG;
+    else
+        return INTC_MODE_MASK_REG;
+}
+
+static void sh_intc_locate(struct intc_desc *desc,
+                          unsigned long address,
+                          unsigned long **datap,
+                          intc_enum **enums,
+                          unsigned int *first,
+                          unsigned int *width,
+                          unsigned int *modep)
+{
+    unsigned int i, mode;
+
+    /* this is slow but works for now */
+
+    if (desc->mask_regs) {
+        for (i = 0; i < desc->nr_mask_regs; i++) {
+           struct intc_mask_reg *mr = desc->mask_regs + i;
+
+           mode = sh_intc_mode(address, mr->set_reg, mr->clr_reg);
+           if (mode == INTC_MODE_NONE)
+                continue;
+
+           *modep = mode;
+           *datap = &mr->value;
+           *enums = mr->enum_ids;
+           *first = mr->reg_width - 1;
+           *width = 1;
+           return;
+       }
+    }
+
+    if (desc->prio_regs) {
+        for (i = 0; i < desc->nr_prio_regs; i++) {
+           struct intc_prio_reg *pr = desc->prio_regs + i;
+
+           mode = sh_intc_mode(address, pr->set_reg, pr->clr_reg);
+           if (mode == INTC_MODE_NONE)
+                continue;
+
+           *modep = mode | INTC_MODE_IS_PRIO;
+           *datap = &pr->value;
+           *enums = pr->enum_ids;
+           *first = (pr->reg_width / pr->field_width) - 1;
+           *width = pr->field_width;
+           return;
+       }
+    }
+
+    abort();
+}
+
+static void sh_intc_toggle_mask(struct intc_desc *desc, intc_enum id,
+                               int enable, int is_group)
+{
+    struct intc_source *source = desc->sources + id;
+
+    if (!id)
+       return;
+
+    if (!source->next_enum_id && (!source->enable_max || !source->vect)) {
+#ifdef DEBUG_INTC_SOURCES
+        printf("sh_intc: reserved interrupt source %d modified\n", id);
+#endif
+       return;
+    }
+
+    if (source->vect)
+        sh_intc_toggle_source(source, enable ? 1 : -1, 0);
+
+#ifdef DEBUG_INTC
+    else {
+        printf("setting interrupt group %d to %d\n", id, !!enable);
+    }
+#endif
+
+    if ((is_group || !source->vect) && source->next_enum_id) {
+        sh_intc_toggle_mask(desc, source->next_enum_id, enable, 1);
+    }
+
+#ifdef DEBUG_INTC
+    if (!source->vect) {
+        printf("setting interrupt group %d to %d - done\n", id, !!enable);
+    }
+#endif
+}
+
+static uint64_t sh_intc_read(void *opaque, hwaddr offset,
+                             unsigned size)
+{
+    struct intc_desc *desc = opaque;
+    intc_enum *enum_ids = NULL;
+    unsigned int first = 0;
+    unsigned int width = 0;
+    unsigned int mode = 0;
+    unsigned long *valuep;
+
+#ifdef DEBUG_INTC
+    printf("sh_intc_read 0x%lx\n", (unsigned long) offset);
+#endif
+
+    sh_intc_locate(desc, (unsigned long)offset, &valuep, 
+                  &enum_ids, &first, &width, &mode);
+    return *valuep;
+}
+
+static void sh_intc_write(void *opaque, hwaddr offset,
+                          uint64_t value, unsigned size)
+{
+    struct intc_desc *desc = opaque;
+    intc_enum *enum_ids = NULL;
+    unsigned int first = 0;
+    unsigned int width = 0;
+    unsigned int mode = 0;
+    unsigned int k;
+    unsigned long *valuep;
+    unsigned long mask;
+
+#ifdef DEBUG_INTC
+    printf("sh_intc_write 0x%lx 0x%08x\n", (unsigned long) offset, value);
+#endif
+
+    sh_intc_locate(desc, (unsigned long)offset, &valuep, 
+                  &enum_ids, &first, &width, &mode);
+
+    switch (mode) {
+    case INTC_MODE_ENABLE_REG | INTC_MODE_IS_PRIO: break;
+    case INTC_MODE_DUAL_SET: value |= *valuep; break;
+    case INTC_MODE_DUAL_CLR: value = *valuep & ~value; break;
+    default: abort();
+    }
+
+    for (k = 0; k <= first; k++) {
+        mask = ((1 << width) - 1) << ((first - k) * width);
+
+       if ((*valuep & mask) == (value & mask))
+            continue;
+#if 0
+       printf("k = %d, first = %d, enum = %d, mask = 0x%08x\n", 
+              k, first, enum_ids[k], (unsigned int)mask);
+#endif
+        sh_intc_toggle_mask(desc, enum_ids[k], value & mask, 0);
+    }
+
+    *valuep = value;
+
+#ifdef DEBUG_INTC
+    printf("sh_intc_write 0x%lx -> 0x%08x\n", (unsigned long) offset, value);
+#endif
+}
+
+static const MemoryRegionOps sh_intc_ops = {
+    .read = sh_intc_read,
+    .write = sh_intc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+struct intc_source *sh_intc_source(struct intc_desc *desc, intc_enum id)
+{
+    if (id)
+        return desc->sources + id;
+
+    return NULL;
+}
+
+static unsigned int sh_intc_register(MemoryRegion *sysmem,
+                             struct intc_desc *desc,
+                             const unsigned long address,
+                             const char *type,
+                             const char *action,
+                             const unsigned int index)
+{
+    char name[60];
+    MemoryRegion *iomem, *iomem_p4, *iomem_a7;
+
+    if (!address) {
+        return 0;
+    }
+
+    iomem = &desc->iomem;
+    iomem_p4 = desc->iomem_aliases + index;
+    iomem_a7 = iomem_p4 + 1;
+
+#define SH_INTC_IOMEM_FORMAT "interrupt-controller-%s-%s-%s"
+    snprintf(name, sizeof(name), SH_INTC_IOMEM_FORMAT, type, action, "p4");
+    memory_region_init_alias(iomem_p4, name, iomem, INTC_A7(address), 4);
+    memory_region_add_subregion(sysmem, P4ADDR(address), iomem_p4);
+
+    snprintf(name, sizeof(name), SH_INTC_IOMEM_FORMAT, type, action, "a7");
+    memory_region_init_alias(iomem_a7, name, iomem, INTC_A7(address), 4);
+    memory_region_add_subregion(sysmem, A7ADDR(address), iomem_a7);
+#undef SH_INTC_IOMEM_FORMAT
+
+    /* used to increment aliases index */
+    return 2;
+}
+
+static void sh_intc_register_source(struct intc_desc *desc,
+                                   intc_enum source,
+                                   struct intc_group *groups,
+                                   int nr_groups)
+{
+    unsigned int i, k;
+    struct intc_source *s;
+
+    if (desc->mask_regs) {
+        for (i = 0; i < desc->nr_mask_regs; i++) {
+           struct intc_mask_reg *mr = desc->mask_regs + i;
+
+           for (k = 0; k < ARRAY_SIZE(mr->enum_ids); k++) {
+                if (mr->enum_ids[k] != source)
+                    continue;
+
+               s = sh_intc_source(desc, mr->enum_ids[k]);
+               if (s)
+                    s->enable_max++;
+           }
+       }
+    }
+
+    if (desc->prio_regs) {
+        for (i = 0; i < desc->nr_prio_regs; i++) {
+           struct intc_prio_reg *pr = desc->prio_regs + i;
+
+           for (k = 0; k < ARRAY_SIZE(pr->enum_ids); k++) {
+                if (pr->enum_ids[k] != source)
+                    continue;
+
+               s = sh_intc_source(desc, pr->enum_ids[k]);
+               if (s)
+                    s->enable_max++;
+           }
+       }
+    }
+
+    if (groups) {
+        for (i = 0; i < nr_groups; i++) {
+           struct intc_group *gr = groups + i;
+
+           for (k = 0; k < ARRAY_SIZE(gr->enum_ids); k++) {
+                if (gr->enum_ids[k] != source)
+                    continue;
+
+               s = sh_intc_source(desc, gr->enum_ids[k]);
+               if (s)
+                    s->enable_max++;
+           }
+       }
+    }
+
+}
+
+void sh_intc_register_sources(struct intc_desc *desc,
+                             struct intc_vect *vectors,
+                             int nr_vectors,
+                             struct intc_group *groups,
+                             int nr_groups)
+{
+    unsigned int i, k;
+    struct intc_source *s;
+
+    for (i = 0; i < nr_vectors; i++) {
+       struct intc_vect *vect = vectors + i;
+
+       sh_intc_register_source(desc, vect->enum_id, groups, nr_groups);
+       s = sh_intc_source(desc, vect->enum_id);
+        if (s) {
+            s->vect = vect->vect;
+
+#ifdef DEBUG_INTC_SOURCES
+            printf("sh_intc: registered source %d -> 0x%04x (%d/%d)\n",
+                   vect->enum_id, s->vect, s->enable_count, s->enable_max);
+#endif
+        }
+    }
+
+    if (groups) {
+        for (i = 0; i < nr_groups; i++) {
+           struct intc_group *gr = groups + i;
+
+           s = sh_intc_source(desc, gr->enum_id);
+           s->next_enum_id = gr->enum_ids[0];
+
+           for (k = 1; k < ARRAY_SIZE(gr->enum_ids); k++) {
+                if (!gr->enum_ids[k])
+                    continue;
+
+               s = sh_intc_source(desc, gr->enum_ids[k - 1]);
+               s->next_enum_id = gr->enum_ids[k];
+           }
+
+#ifdef DEBUG_INTC_SOURCES
+           printf("sh_intc: registered group %d (%d/%d)\n",
+                  gr->enum_id, s->enable_count, s->enable_max);
+#endif
+       }
+    }
+}
+
+int sh_intc_init(MemoryRegion *sysmem,
+         struct intc_desc *desc,
+                int nr_sources,
+                struct intc_mask_reg *mask_regs,
+                int nr_mask_regs,
+                struct intc_prio_reg *prio_regs,
+                int nr_prio_regs)
+{
+    unsigned int i, j;
+
+    desc->pending = 0;
+    desc->nr_sources = nr_sources;
+    desc->mask_regs = mask_regs;
+    desc->nr_mask_regs = nr_mask_regs;
+    desc->prio_regs = prio_regs;
+    desc->nr_prio_regs = nr_prio_regs;
+    /* Allocate 4 MemoryRegions per register (2 actions * 2 aliases).
+     **/
+    desc->iomem_aliases = g_new0(MemoryRegion,
+                                 (nr_mask_regs + nr_prio_regs) * 4);
+
+    j = 0;
+    i = sizeof(struct intc_source) * nr_sources;
+    desc->sources = g_malloc0(i);
+
+    for (i = 0; i < desc->nr_sources; i++) {
+        struct intc_source *source = desc->sources + i;
+
+        source->parent = desc;
+    }
+
+    desc->irqs = qemu_allocate_irqs(sh_intc_set_irq, desc, nr_sources);
+    memory_region_init_io(&desc->iomem, &sh_intc_ops, desc,
+                          "interrupt-controller", 0x100000000ULL);
+
+#define INT_REG_PARAMS(reg_struct, type, action, j) \
+        reg_struct->action##_reg, #type, #action, j
+    if (desc->mask_regs) {
+        for (i = 0; i < desc->nr_mask_regs; i++) {
+           struct intc_mask_reg *mr = desc->mask_regs + i;
+
+            j += sh_intc_register(sysmem, desc,
+                                  INT_REG_PARAMS(mr, mask, set, j));
+            j += sh_intc_register(sysmem, desc,
+                                  INT_REG_PARAMS(mr, mask, clr, j));
+       }
+    }
+
+    if (desc->prio_regs) {
+        for (i = 0; i < desc->nr_prio_regs; i++) {
+           struct intc_prio_reg *pr = desc->prio_regs + i;
+
+            j += sh_intc_register(sysmem, desc,
+                                  INT_REG_PARAMS(pr, prio, set, j));
+            j += sh_intc_register(sysmem, desc,
+                                  INT_REG_PARAMS(pr, prio, clr, j));
+       }
+    }
+#undef INT_REG_PARAMS
+
+    return 0;
+}
+
+/* Assert level <n> IRL interrupt. 
+   0:deassert. 1:lowest priority,... 15:highest priority. */
+void sh_intc_set_irl(void *opaque, int n, int level)
+{
+    struct intc_source *s = opaque;
+    int i, irl = level ^ 15;
+    for (i = 0; (s = sh_intc_source(s->parent, s->next_enum_id)); i++) {
+       if (i == irl)
+           sh_intc_toggle_source(s, s->enable_count?0:1, s->asserted?0:1);
+       else
+           if (s->asserted)
+               sh_intc_toggle_source(s, 0, -1);
+    }
+}
diff --git a/hw/intc/slavio_intctl.c b/hw/intc/slavio_intctl.c
new file mode 100644 (file)
index 0000000..b367752
--- /dev/null
@@ -0,0 +1,471 @@
+/*
+ * QEMU Sparc SLAVIO interrupt controller emulation
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/sparc/sun4m.h"
+#include "monitor/monitor.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+
+//#define DEBUG_IRQ_COUNT
+
+/*
+ * Registers of interrupt controller in sun4m.
+ *
+ * This is the interrupt controller part of chip STP2001 (Slave I/O), also
+ * produced as NCR89C105. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
+ *
+ * There is a system master controller and one for each cpu.
+ *
+ */
+
+#define MAX_CPUS 16
+#define MAX_PILS 16
+
+struct SLAVIO_INTCTLState;
+
+typedef struct SLAVIO_CPUINTCTLState {
+    MemoryRegion iomem;
+    struct SLAVIO_INTCTLState *master;
+    uint32_t intreg_pending;
+    uint32_t cpu;
+    uint32_t irl_out;
+} SLAVIO_CPUINTCTLState;
+
+typedef struct SLAVIO_INTCTLState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+#ifdef DEBUG_IRQ_COUNT
+    uint64_t irq_count[32];
+#endif
+    qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS];
+    SLAVIO_CPUINTCTLState slaves[MAX_CPUS];
+    uint32_t intregm_pending;
+    uint32_t intregm_disabled;
+    uint32_t target_cpu;
+} SLAVIO_INTCTLState;
+
+#define INTCTL_MAXADDR 0xf
+#define INTCTL_SIZE (INTCTL_MAXADDR + 1)
+#define INTCTLM_SIZE 0x14
+#define MASTER_IRQ_MASK ~0x0fa2007f
+#define MASTER_DISABLE 0x80000000
+#define CPU_SOFTIRQ_MASK 0xfffe0000
+#define CPU_IRQ_INT15_IN (1 << 15)
+#define CPU_IRQ_TIMER_IN (1 << 14)
+
+static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs);
+
+// per-cpu interrupt controller
+static uint64_t slavio_intctl_mem_readl(void *opaque, hwaddr addr,
+                                        unsigned size)
+{
+    SLAVIO_CPUINTCTLState *s = opaque;
+    uint32_t saddr, ret;
+
+    saddr = addr >> 2;
+    switch (saddr) {
+    case 0:
+        ret = s->intreg_pending;
+        break;
+    default:
+        ret = 0;
+        break;
+    }
+    trace_slavio_intctl_mem_readl(s->cpu, addr, ret);
+
+    return ret;
+}
+
+static void slavio_intctl_mem_writel(void *opaque, hwaddr addr,
+                                     uint64_t val, unsigned size)
+{
+    SLAVIO_CPUINTCTLState *s = opaque;
+    uint32_t saddr;
+
+    saddr = addr >> 2;
+    trace_slavio_intctl_mem_writel(s->cpu, addr, val);
+    switch (saddr) {
+    case 1: // clear pending softints
+        val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN;
+        s->intreg_pending &= ~val;
+        slavio_check_interrupts(s->master, 1);
+        trace_slavio_intctl_mem_writel_clear(s->cpu, val, s->intreg_pending);
+        break;
+    case 2: // set softint
+        val &= CPU_SOFTIRQ_MASK;
+        s->intreg_pending |= val;
+        slavio_check_interrupts(s->master, 1);
+        trace_slavio_intctl_mem_writel_set(s->cpu, val, s->intreg_pending);
+        break;
+    default:
+        break;
+    }
+}
+
+static const MemoryRegionOps slavio_intctl_mem_ops = {
+    .read = slavio_intctl_mem_readl,
+    .write = slavio_intctl_mem_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+// master system interrupt controller
+static uint64_t slavio_intctlm_mem_readl(void *opaque, hwaddr addr,
+                                         unsigned size)
+{
+    SLAVIO_INTCTLState *s = opaque;
+    uint32_t saddr, ret;
+
+    saddr = addr >> 2;
+    switch (saddr) {
+    case 0:
+        ret = s->intregm_pending & ~MASTER_DISABLE;
+        break;
+    case 1:
+        ret = s->intregm_disabled & MASTER_IRQ_MASK;
+        break;
+    case 4:
+        ret = s->target_cpu;
+        break;
+    default:
+        ret = 0;
+        break;
+    }
+    trace_slavio_intctlm_mem_readl(addr, ret);
+
+    return ret;
+}
+
+static void slavio_intctlm_mem_writel(void *opaque, hwaddr addr,
+                                      uint64_t val, unsigned size)
+{
+    SLAVIO_INTCTLState *s = opaque;
+    uint32_t saddr;
+
+    saddr = addr >> 2;
+    trace_slavio_intctlm_mem_writel(addr, val);
+    switch (saddr) {
+    case 2: // clear (enable)
+        // Force clear unused bits
+        val &= MASTER_IRQ_MASK;
+        s->intregm_disabled &= ~val;
+        trace_slavio_intctlm_mem_writel_enable(val, s->intregm_disabled);
+        slavio_check_interrupts(s, 1);
+        break;
+    case 3: // set (disable; doesn't affect pending)
+        // Force clear unused bits
+        val &= MASTER_IRQ_MASK;
+        s->intregm_disabled |= val;
+        slavio_check_interrupts(s, 1);
+        trace_slavio_intctlm_mem_writel_disable(val, s->intregm_disabled);
+        break;
+    case 4:
+        s->target_cpu = val & (MAX_CPUS - 1);
+        slavio_check_interrupts(s, 1);
+        trace_slavio_intctlm_mem_writel_target(s->target_cpu);
+        break;
+    default:
+        break;
+    }
+}
+
+static const MemoryRegionOps slavio_intctlm_mem_ops = {
+    .read = slavio_intctlm_mem_readl,
+    .write = slavio_intctlm_mem_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+void slavio_pic_info(Monitor *mon, DeviceState *dev)
+{
+    SysBusDevice *sd;
+    SLAVIO_INTCTLState *s;
+    int i;
+
+    sd = SYS_BUS_DEVICE(dev);
+    s = FROM_SYSBUS(SLAVIO_INTCTLState, sd);
+    for (i = 0; i < MAX_CPUS; i++) {
+        monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
+                       s->slaves[i].intreg_pending);
+    }
+    monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
+                   s->intregm_pending, s->intregm_disabled);
+}
+
+void slavio_irq_info(Monitor *mon, DeviceState *dev)
+{
+#ifndef DEBUG_IRQ_COUNT
+    monitor_printf(mon, "irq statistic code not compiled.\n");
+#else
+    SysBusDevice *sd;
+    SLAVIO_INTCTLState *s;
+    int i;
+    int64_t count;
+
+    sd = SYS_BUS_DEVICE(dev);
+    s = FROM_SYSBUS(SLAVIO_INTCTLState, sd);
+    monitor_printf(mon, "IRQ statistics:\n");
+    for (i = 0; i < 32; i++) {
+        count = s->irq_count[i];
+        if (count > 0)
+            monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
+    }
+#endif
+}
+
+static const uint32_t intbit_to_level[] = {
+    2, 3, 5, 7, 9, 11, 13, 2,   3, 5, 7, 9, 11, 13, 12, 12,
+    6, 13, 4, 10, 8, 9, 11, 0,  0, 0, 0, 15, 15, 15, 15, 0,
+};
+
+static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
+{
+    uint32_t pending = s->intregm_pending, pil_pending;
+    unsigned int i, j;
+
+    pending &= ~s->intregm_disabled;
+
+    trace_slavio_check_interrupts(pending, s->intregm_disabled);
+    for (i = 0; i < MAX_CPUS; i++) {
+        pil_pending = 0;
+
+        /* If we are the current interrupt target, get hard interrupts */
+        if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
+            (i == s->target_cpu)) {
+            for (j = 0; j < 32; j++) {
+                if ((pending & (1 << j)) && intbit_to_level[j]) {
+                    pil_pending |= 1 << intbit_to_level[j];
+                }
+            }
+        }
+
+        /* Calculate current pending hard interrupts for display */
+        s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN |
+            CPU_IRQ_TIMER_IN;
+        if (i == s->target_cpu) {
+            for (j = 0; j < 32; j++) {
+                if ((s->intregm_pending & (1 << j)) && intbit_to_level[j]) {
+                    s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
+                }
+            }
+        }
+
+        /* Level 15 and CPU timer interrupts are only masked when
+           the MASTER_DISABLE bit is set */
+        if (!(s->intregm_disabled & MASTER_DISABLE)) {
+            pil_pending |= s->slaves[i].intreg_pending &
+                (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN);
+        }
+
+        /* Add soft interrupts */
+        pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
+
+        if (set_irqs) {
+            /* Since there is not really an interrupt 0 (and pil_pending
+             * and irl_out bit zero are thus always zero) there is no need
+             * to do anything with cpu_irqs[i][0] and it is OK not to do
+             * the j=0 iteration of this loop.
+             */
+            for (j = MAX_PILS-1; j > 0; j--) {
+                if (pil_pending & (1 << j)) {
+                    if (!(s->slaves[i].irl_out & (1 << j))) {
+                        qemu_irq_raise(s->cpu_irqs[i][j]);
+                    }
+                } else {
+                    if (s->slaves[i].irl_out & (1 << j)) {
+                        qemu_irq_lower(s->cpu_irqs[i][j]);
+                    }
+                }
+            }
+        }
+        s->slaves[i].irl_out = pil_pending;
+    }
+}
+
+/*
+ * "irq" here is the bit number in the system interrupt register to
+ * separate serial and keyboard interrupts sharing a level.
+ */
+static void slavio_set_irq(void *opaque, int irq, int level)
+{
+    SLAVIO_INTCTLState *s = opaque;
+    uint32_t mask = 1 << irq;
+    uint32_t pil = intbit_to_level[irq];
+    unsigned int i;
+
+    trace_slavio_set_irq(s->target_cpu, irq, pil, level);
+    if (pil > 0) {
+        if (level) {
+#ifdef DEBUG_IRQ_COUNT
+            s->irq_count[pil]++;
+#endif
+            s->intregm_pending |= mask;
+            if (pil == 15) {
+                for (i = 0; i < MAX_CPUS; i++) {
+                    s->slaves[i].intreg_pending |= 1 << pil;
+                }
+            }
+        } else {
+            s->intregm_pending &= ~mask;
+            if (pil == 15) {
+                for (i = 0; i < MAX_CPUS; i++) {
+                    s->slaves[i].intreg_pending &= ~(1 << pil);
+                }
+            }
+        }
+        slavio_check_interrupts(s, 1);
+    }
+}
+
+static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
+{
+    SLAVIO_INTCTLState *s = opaque;
+
+    trace_slavio_set_timer_irq_cpu(cpu, level);
+
+    if (level) {
+        s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN;
+    } else {
+        s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN;
+    }
+
+    slavio_check_interrupts(s, 1);
+}
+
+static void slavio_set_irq_all(void *opaque, int irq, int level)
+{
+    if (irq < 32) {
+        slavio_set_irq(opaque, irq, level);
+    } else {
+        slavio_set_timer_irq_cpu(opaque, irq - 32, level);
+    }
+}
+
+static int vmstate_intctl_post_load(void *opaque, int version_id)
+{
+    SLAVIO_INTCTLState *s = opaque;
+
+    slavio_check_interrupts(s, 0);
+    return 0;
+}
+
+static const VMStateDescription vmstate_intctl_cpu = {
+    .name ="slavio_intctl_cpu",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_intctl = {
+    .name ="slavio_intctl",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = vmstate_intctl_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1,
+                             vmstate_intctl_cpu, SLAVIO_CPUINTCTLState),
+        VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState),
+        VMSTATE_UINT32(intregm_disabled, SLAVIO_INTCTLState),
+        VMSTATE_UINT32(target_cpu, SLAVIO_INTCTLState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void slavio_intctl_reset(DeviceState *d)
+{
+    SLAVIO_INTCTLState *s = container_of(d, SLAVIO_INTCTLState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        s->slaves[i].intreg_pending = 0;
+        s->slaves[i].irl_out = 0;
+    }
+    s->intregm_disabled = ~MASTER_IRQ_MASK;
+    s->intregm_pending = 0;
+    s->target_cpu = 0;
+    slavio_check_interrupts(s, 0);
+}
+
+static int slavio_intctl_init1(SysBusDevice *dev)
+{
+    SLAVIO_INTCTLState *s = FROM_SYSBUS(SLAVIO_INTCTLState, dev);
+    unsigned int i, j;
+    char slave_name[45];
+
+    qdev_init_gpio_in(&dev->qdev, slavio_set_irq_all, 32 + MAX_CPUS);
+    memory_region_init_io(&s->iomem, &slavio_intctlm_mem_ops, s,
+                          "master-interrupt-controller", INTCTLM_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        snprintf(slave_name, sizeof(slave_name),
+                 "slave-interrupt-controller-%i", i);
+        for (j = 0; j < MAX_PILS; j++) {
+            sysbus_init_irq(dev, &s->cpu_irqs[i][j]);
+        }
+        memory_region_init_io(&s->slaves[i].iomem, &slavio_intctl_mem_ops,
+                              &s->slaves[i], slave_name, INTCTL_SIZE);
+        sysbus_init_mmio(dev, &s->slaves[i].iomem);
+        s->slaves[i].cpu = i;
+        s->slaves[i].master = s;
+    }
+
+    return 0;
+}
+
+static void slavio_intctl_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = slavio_intctl_init1;
+    dc->reset = slavio_intctl_reset;
+    dc->vmsd = &vmstate_intctl;
+}
+
+static const TypeInfo slavio_intctl_info = {
+    .name          = "slavio_intctl",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SLAVIO_INTCTLState),
+    .class_init    = slavio_intctl_class_init,
+};
+
+static void slavio_intctl_register_types(void)
+{
+    type_register_static(&slavio_intctl_info);
+}
+
+type_init(slavio_intctl_register_types)
diff --git a/hw/intc/sun4c_intctl.c b/hw/intc/sun4c_intctl.c
new file mode 100644 (file)
index 0000000..1096375
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * QEMU Sparc Sun4c interrupt controller emulation
+ *
+ * Based on slavio_intctl, copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/hw.h"
+#include "hw/sparc/sun4m.h"
+#include "monitor/monitor.h"
+#include "hw/sysbus.h"
+
+//#define DEBUG_IRQ_COUNT
+//#define DEBUG_IRQ
+
+#ifdef DEBUG_IRQ
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("IRQ: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+/*
+ * Registers of interrupt controller in sun4c.
+ *
+ */
+
+#define MAX_PILS 16
+
+typedef struct Sun4c_INTCTLState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+#ifdef DEBUG_IRQ_COUNT
+    uint64_t irq_count;
+#endif
+    qemu_irq cpu_irqs[MAX_PILS];
+    const uint32_t *intbit_to_level;
+    uint32_t pil_out;
+    uint8_t reg;
+    uint8_t pending;
+} Sun4c_INTCTLState;
+
+#define INTCTL_SIZE 1
+
+static void sun4c_check_interrupts(void *opaque);
+
+static uint64_t sun4c_intctl_mem_read(void *opaque, hwaddr addr,
+                                      unsigned size)
+{
+    Sun4c_INTCTLState *s = opaque;
+    uint32_t ret;
+
+    ret = s->reg;
+    DPRINTF("read reg 0x" TARGET_FMT_plx " = %x\n", addr, ret);
+
+    return ret;
+}
+
+static void sun4c_intctl_mem_write(void *opaque, hwaddr addr,
+                                   uint64_t val, unsigned size)
+{
+    Sun4c_INTCTLState *s = opaque;
+
+    DPRINTF("write reg 0x" TARGET_FMT_plx " = %x\n", addr, (unsigned)val);
+    val &= 0xbf;
+    s->reg = val;
+    sun4c_check_interrupts(s);
+}
+
+static const MemoryRegionOps sun4c_intctl_mem_ops = {
+    .read = sun4c_intctl_mem_read,
+    .write = sun4c_intctl_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static const uint32_t intbit_to_level[] = { 0, 1, 4, 6, 8, 10, 0, 14, };
+
+static void sun4c_check_interrupts(void *opaque)
+{
+    Sun4c_INTCTLState *s = opaque;
+    uint32_t pil_pending;
+    unsigned int i;
+
+    pil_pending = 0;
+    if (s->pending && !(s->reg & 0x80000000)) {
+        for (i = 0; i < 8; i++) {
+            if (s->pending & (1 << i))
+                pil_pending |= 1 << intbit_to_level[i];
+        }
+    }
+
+    for (i = 0; i < MAX_PILS; i++) {
+        if (pil_pending & (1 << i)) {
+            if (!(s->pil_out & (1 << i)))
+                qemu_irq_raise(s->cpu_irqs[i]);
+        } else {
+            if (s->pil_out & (1 << i))
+                qemu_irq_lower(s->cpu_irqs[i]);
+        }
+    }
+    s->pil_out = pil_pending;
+}
+
+/*
+ * "irq" here is the bit number in the system interrupt register
+ */
+static void sun4c_set_irq(void *opaque, int irq, int level)
+{
+    Sun4c_INTCTLState *s = opaque;
+    uint32_t mask = 1 << irq;
+    uint32_t pil = intbit_to_level[irq];
+
+    DPRINTF("Set irq %d -> pil %d level %d\n", irq, pil,
+            level);
+    if (pil > 0) {
+        if (level) {
+#ifdef DEBUG_IRQ_COUNT
+            s->irq_count++;
+#endif
+            s->pending |= mask;
+        } else {
+            s->pending &= ~mask;
+        }
+        sun4c_check_interrupts(s);
+    }
+}
+
+static const VMStateDescription vmstate_sun4c_intctl = {
+    .name ="sun4c_intctl",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(reg, Sun4c_INTCTLState),
+        VMSTATE_UINT8(pending, Sun4c_INTCTLState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void sun4c_intctl_reset(DeviceState *d)
+{
+    Sun4c_INTCTLState *s = container_of(d, Sun4c_INTCTLState, busdev.qdev);
+
+    s->reg = 1;
+    s->pending = 0;
+}
+
+static int sun4c_intctl_init1(SysBusDevice *dev)
+{
+    Sun4c_INTCTLState *s = FROM_SYSBUS(Sun4c_INTCTLState, dev);
+    unsigned int i;
+
+    memory_region_init_io(&s->iomem, &sun4c_intctl_mem_ops, s,
+                          "intctl", INTCTL_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+    qdev_init_gpio_in(&dev->qdev, sun4c_set_irq, 8);
+
+    for (i = 0; i < MAX_PILS; i++) {
+        sysbus_init_irq(dev, &s->cpu_irqs[i]);
+    }
+
+    return 0;
+}
+
+static void sun4c_intctl_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = sun4c_intctl_init1;
+    dc->reset = sun4c_intctl_reset;
+    dc->vmsd = &vmstate_sun4c_intctl;
+}
+
+static const TypeInfo sun4c_intctl_info = {
+    .name          = "sun4c_intctl",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Sun4c_INTCTLState),
+    .class_init    = sun4c_intctl_class_init,
+};
+
+static void sun4c_intctl_register_types(void)
+{
+    type_register_static(&sun4c_intctl_info);
+}
+
+type_init(sun4c_intctl_register_types)
diff --git a/hw/ioapic.c b/hw/ioapic.c
deleted file mode 100644 (file)
index 7089fa8..0000000
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- *  ioapic.c IOAPIC emulation logic
- *
- *  Copyright (c) 2004-2005 Fabrice Bellard
- *
- *  Split the ioapic logic from apic.c
- *  Xiantao Zhang <xiantao.zhang@intel.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "hw/i386/apic.h"
-#include "hw/i386/ioapic.h"
-#include "hw/i386/ioapic_internal.h"
-
-//#define DEBUG_IOAPIC
-
-#ifdef DEBUG_IOAPIC
-#define DPRINTF(fmt, ...)                                       \
-    do { printf("ioapic: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-static IOAPICCommonState *ioapics[MAX_IOAPICS];
-
-static void ioapic_service(IOAPICCommonState *s)
-{
-    uint8_t i;
-    uint8_t trig_mode;
-    uint8_t vector;
-    uint8_t delivery_mode;
-    uint32_t mask;
-    uint64_t entry;
-    uint8_t dest;
-    uint8_t dest_mode;
-
-    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
-        mask = 1 << i;
-        if (s->irr & mask) {
-            entry = s->ioredtbl[i];
-            if (!(entry & IOAPIC_LVT_MASKED)) {
-                trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1);
-                dest = entry >> IOAPIC_LVT_DEST_SHIFT;
-                dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1;
-                delivery_mode =
-                    (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK;
-                if (trig_mode == IOAPIC_TRIGGER_EDGE) {
-                    s->irr &= ~mask;
-                } else {
-                    s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR;
-                }
-                if (delivery_mode == IOAPIC_DM_EXTINT) {
-                    vector = pic_read_irq(isa_pic);
-                } else {
-                    vector = entry & IOAPIC_VECTOR_MASK;
-                }
-                apic_deliver_irq(dest, dest_mode, delivery_mode,
-                                 vector, trig_mode);
-            }
-        }
-    }
-}
-
-static void ioapic_set_irq(void *opaque, int vector, int level)
-{
-    IOAPICCommonState *s = opaque;
-
-    /* ISA IRQs map to GSI 1-1 except for IRQ0 which maps
-     * to GSI 2.  GSI maps to ioapic 1-1.  This is not
-     * the cleanest way of doing it but it should work. */
-
-    DPRINTF("%s: %s vec %x\n", __func__, level ? "raise" : "lower", vector);
-    if (vector == 0) {
-        vector = 2;
-    }
-    if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
-        uint32_t mask = 1 << vector;
-        uint64_t entry = s->ioredtbl[vector];
-
-        if (entry & (1 << IOAPIC_LVT_POLARITY_SHIFT)) {
-            level = !level;
-        }
-        if (((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) ==
-            IOAPIC_TRIGGER_LEVEL) {
-            /* level triggered */
-            if (level) {
-                s->irr |= mask;
-                ioapic_service(s);
-            } else {
-                s->irr &= ~mask;
-            }
-        } else {
-            /* According to the 82093AA manual, we must ignore edge requests
-             * if the input pin is masked. */
-            if (level && !(entry & IOAPIC_LVT_MASKED)) {
-                s->irr |= mask;
-                ioapic_service(s);
-            }
-        }
-    }
-}
-
-void ioapic_eoi_broadcast(int vector)
-{
-    IOAPICCommonState *s;
-    uint64_t entry;
-    int i, n;
-
-    for (i = 0; i < MAX_IOAPICS; i++) {
-        s = ioapics[i];
-        if (!s) {
-            continue;
-        }
-        for (n = 0; n < IOAPIC_NUM_PINS; n++) {
-            entry = s->ioredtbl[n];
-            if ((entry & IOAPIC_LVT_REMOTE_IRR)
-                && (entry & IOAPIC_VECTOR_MASK) == vector) {
-                s->ioredtbl[n] = entry & ~IOAPIC_LVT_REMOTE_IRR;
-                if (!(entry & IOAPIC_LVT_MASKED) && (s->irr & (1 << n))) {
-                    ioapic_service(s);
-                }
-            }
-        }
-    }
-}
-
-static uint64_t
-ioapic_mem_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    IOAPICCommonState *s = opaque;
-    int index;
-    uint32_t val = 0;
-
-    switch (addr & 0xff) {
-    case IOAPIC_IOREGSEL:
-        val = s->ioregsel;
-        break;
-    case IOAPIC_IOWIN:
-        if (size != 4) {
-            break;
-        }
-        switch (s->ioregsel) {
-        case IOAPIC_REG_ID:
-            val = s->id << IOAPIC_ID_SHIFT;
-            break;
-        case IOAPIC_REG_VER:
-            val = IOAPIC_VERSION |
-                ((IOAPIC_NUM_PINS - 1) << IOAPIC_VER_ENTRIES_SHIFT);
-            break;
-        case IOAPIC_REG_ARB:
-            val = 0;
-            break;
-        default:
-            index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1;
-            if (index >= 0 && index < IOAPIC_NUM_PINS) {
-                if (s->ioregsel & 1) {
-                    val = s->ioredtbl[index] >> 32;
-                } else {
-                    val = s->ioredtbl[index] & 0xffffffff;
-                }
-            }
-        }
-        DPRINTF("read: %08x = %08x\n", s->ioregsel, val);
-        break;
-    }
-    return val;
-}
-
-static void
-ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
-                 unsigned int size)
-{
-    IOAPICCommonState *s = opaque;
-    int index;
-
-    switch (addr & 0xff) {
-    case IOAPIC_IOREGSEL:
-        s->ioregsel = val;
-        break;
-    case IOAPIC_IOWIN:
-        if (size != 4) {
-            break;
-        }
-        DPRINTF("write: %08x = %08" PRIx64 "\n", s->ioregsel, val);
-        switch (s->ioregsel) {
-        case IOAPIC_REG_ID:
-            s->id = (val >> IOAPIC_ID_SHIFT) & IOAPIC_ID_MASK;
-            break;
-        case IOAPIC_REG_VER:
-        case IOAPIC_REG_ARB:
-            break;
-        default:
-            index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1;
-            if (index >= 0 && index < IOAPIC_NUM_PINS) {
-                if (s->ioregsel & 1) {
-                    s->ioredtbl[index] &= 0xffffffff;
-                    s->ioredtbl[index] |= (uint64_t)val << 32;
-                } else {
-                    s->ioredtbl[index] &= ~0xffffffffULL;
-                    s->ioredtbl[index] |= val;
-                }
-                ioapic_service(s);
-            }
-        }
-        break;
-    }
-}
-
-static const MemoryRegionOps ioapic_io_ops = {
-    .read = ioapic_mem_read,
-    .write = ioapic_mem_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void ioapic_init(IOAPICCommonState *s, int instance_no)
-{
-    memory_region_init_io(&s->io_memory, &ioapic_io_ops, s, "ioapic", 0x1000);
-
-    qdev_init_gpio_in(&s->busdev.qdev, ioapic_set_irq, IOAPIC_NUM_PINS);
-
-    ioapics[instance_no] = s;
-}
-
-static void ioapic_class_init(ObjectClass *klass, void *data)
-{
-    IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    k->init = ioapic_init;
-    dc->reset = ioapic_reset_common;
-}
-
-static const TypeInfo ioapic_info = {
-    .name          = "ioapic",
-    .parent        = TYPE_IOAPIC_COMMON,
-    .instance_size = sizeof(IOAPICCommonState),
-    .class_init    = ioapic_class_init,
-};
-
-static void ioapic_register_types(void)
-{
-    type_register_static(&ioapic_info);
-}
-
-type_init(ioapic_register_types)
diff --git a/hw/ioapic_common.c b/hw/ioapic_common.c
deleted file mode 100644 (file)
index 42c7adc..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- *  IOAPIC emulation logic - common bits of emulated and KVM kernel model
- *
- *  Copyright (c) 2004-2005 Fabrice Bellard
- *  Copyright (c) 2009      Xiantao Zhang, Intel
- *  Copyright (c) 2011      Jan Kiszka, Siemens AG
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "hw/i386/ioapic.h"
-#include "hw/i386/ioapic_internal.h"
-#include "hw/sysbus.h"
-
-void ioapic_reset_common(DeviceState *dev)
-{
-    IOAPICCommonState *s = IOAPIC_COMMON(dev);
-    int i;
-
-    s->id = 0;
-    s->ioregsel = 0;
-    s->irr = 0;
-    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
-        s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT;
-    }
-}
-
-static void ioapic_dispatch_pre_save(void *opaque)
-{
-    IOAPICCommonState *s = IOAPIC_COMMON(opaque);
-    IOAPICCommonClass *info = IOAPIC_COMMON_GET_CLASS(s);
-
-    if (info->pre_save) {
-        info->pre_save(s);
-    }
-}
-
-static int ioapic_dispatch_post_load(void *opaque, int version_id)
-{
-    IOAPICCommonState *s = IOAPIC_COMMON(opaque);
-    IOAPICCommonClass *info = IOAPIC_COMMON_GET_CLASS(s);
-
-    if (info->post_load) {
-        info->post_load(s);
-    }
-    return 0;
-}
-
-static int ioapic_init_common(SysBusDevice *dev)
-{
-    IOAPICCommonState *s = FROM_SYSBUS(IOAPICCommonState, dev);
-    IOAPICCommonClass *info;
-    static int ioapic_no;
-
-    if (ioapic_no >= MAX_IOAPICS) {
-        return -1;
-    }
-
-    info = IOAPIC_COMMON_GET_CLASS(s);
-    info->init(s, ioapic_no);
-
-    sysbus_init_mmio(&s->busdev, &s->io_memory);
-    ioapic_no++;
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_ioapic_common = {
-    .name = "ioapic",
-    .version_id = 3,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .pre_save = ioapic_dispatch_pre_save,
-    .post_load = ioapic_dispatch_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT8(id, IOAPICCommonState),
-        VMSTATE_UINT8(ioregsel, IOAPICCommonState),
-        VMSTATE_UNUSED_V(2, 8), /* to account for qemu-kvm's v2 format */
-        VMSTATE_UINT32_V(irr, IOAPICCommonState, 2),
-        VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICCommonState, IOAPIC_NUM_PINS),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void ioapic_common_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    sc->init = ioapic_init_common;
-    dc->vmsd = &vmstate_ioapic_common;
-    dc->no_user = 1;
-}
-
-static const TypeInfo ioapic_common_type = {
-    .name = TYPE_IOAPIC_COMMON,
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(IOAPICCommonState),
-    .class_size = sizeof(IOAPICCommonClass),
-    .class_init = ioapic_common_class_init,
-    .abstract = true,
-};
-
-static void register_types(void)
-{
-    type_register_static(&ioapic_common_type);
-}
-
-type_init(register_types)
diff --git a/hw/kvm/arm_gic.c b/hw/kvm/arm_gic.c
deleted file mode 100644 (file)
index 22b40b4..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * ARM Generic Interrupt Controller using KVM in-kernel support
- *
- * Copyright (c) 2012 Linaro Limited
- * Written by Peter Maydell
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "hw/sysbus.h"
-#include "sysemu/kvm.h"
-#include "kvm_arm.h"
-#include "hw/arm_gic_internal.h"
-
-#define TYPE_KVM_ARM_GIC "kvm-arm-gic"
-#define KVM_ARM_GIC(obj) \
-     OBJECT_CHECK(GICState, (obj), TYPE_KVM_ARM_GIC)
-#define KVM_ARM_GIC_CLASS(klass) \
-     OBJECT_CLASS_CHECK(KVMARMGICClass, (klass), TYPE_KVM_ARM_GIC)
-#define KVM_ARM_GIC_GET_CLASS(obj) \
-     OBJECT_GET_CLASS(KVMARMGICClass, (obj), TYPE_KVM_ARM_GIC)
-
-typedef struct KVMARMGICClass {
-    ARMGICCommonClass parent_class;
-    DeviceRealize parent_realize;
-    void (*parent_reset)(DeviceState *dev);
-} KVMARMGICClass;
-
-static void kvm_arm_gic_set_irq(void *opaque, int irq, int level)
-{
-    /* Meaning of the 'irq' parameter:
-     *  [0..N-1] : external interrupts
-     *  [N..N+31] : PPI (internal) interrupts for CPU 0
-     *  [N+32..N+63] : PPI (internal interrupts for CPU 1
-     *  ...
-     * Convert this to the kernel's desired encoding, which
-     * has separate fields in the irq number for type,
-     * CPU number and interrupt number.
-     */
-    GICState *s = (GICState *)opaque;
-    int kvm_irq, irqtype, cpu;
-
-    if (irq < (s->num_irq - GIC_INTERNAL)) {
-        /* External interrupt. The kernel numbers these like the GIC
-         * hardware, with external interrupt IDs starting after the
-         * internal ones.
-         */
-        irqtype = KVM_ARM_IRQ_TYPE_SPI;
-        cpu = 0;
-        irq += GIC_INTERNAL;
-    } else {
-        /* Internal interrupt: decode into (cpu, interrupt id) */
-        irqtype = KVM_ARM_IRQ_TYPE_PPI;
-        irq -= (s->num_irq - GIC_INTERNAL);
-        cpu = irq / GIC_INTERNAL;
-        irq %= GIC_INTERNAL;
-    }
-    kvm_irq = (irqtype << KVM_ARM_IRQ_TYPE_SHIFT)
-        | (cpu << KVM_ARM_IRQ_VCPU_SHIFT) | irq;
-
-    kvm_set_irq(kvm_state, kvm_irq, !!level);
-}
-
-static void kvm_arm_gic_put(GICState *s)
-{
-    /* TODO: there isn't currently a kernel interface to set the GIC state */
-}
-
-static void kvm_arm_gic_get(GICState *s)
-{
-    /* TODO: there isn't currently a kernel interface to get the GIC state */
-}
-
-static void kvm_arm_gic_reset(DeviceState *dev)
-{
-    GICState *s = ARM_GIC_COMMON(dev);
-    KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
-
-    kgc->parent_reset(dev);
-    kvm_arm_gic_put(s);
-}
-
-static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
-{
-    int i;
-    GICState *s = KVM_ARM_GIC(dev);
-    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-    KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
-
-    kgc->parent_realize(dev, errp);
-    if (error_is_set(errp)) {
-        return;
-    }
-
-    i = s->num_irq - GIC_INTERNAL;
-    /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
-     * GPIO array layout is thus:
-     *  [0..N-1] SPIs
-     *  [N..N+31] PPIs for CPU 0
-     *  [N+32..N+63] PPIs for CPU 1
-     *   ...
-     */
-    i += (GIC_INTERNAL * s->num_cpu);
-    qdev_init_gpio_in(dev, kvm_arm_gic_set_irq, i);
-    /* We never use our outbound IRQ lines but provide them so that
-     * we maintain the same interface as the non-KVM GIC.
-     */
-    for (i = 0; i < s->num_cpu; i++) {
-        sysbus_init_irq(sbd, &s->parent_irq[i]);
-    }
-    /* Distributor */
-    memory_region_init_reservation(&s->iomem, "kvm-gic_dist", 0x1000);
-    sysbus_init_mmio(sbd, &s->iomem);
-    kvm_arm_register_device(&s->iomem,
-                            (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
-                            | KVM_VGIC_V2_ADDR_TYPE_DIST);
-    /* CPU interface for current core. Unlike arm_gic, we don't
-     * provide the "interface for core #N" memory regions, because
-     * cores with a VGIC don't have those.
-     */
-    memory_region_init_reservation(&s->cpuiomem[0], "kvm-gic_cpu", 0x1000);
-    sysbus_init_mmio(sbd, &s->cpuiomem[0]);
-    kvm_arm_register_device(&s->cpuiomem[0],
-                            (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
-                            | KVM_VGIC_V2_ADDR_TYPE_CPU);
-}
-
-static void kvm_arm_gic_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    ARMGICCommonClass *agcc = ARM_GIC_COMMON_CLASS(klass);
-    KVMARMGICClass *kgc = KVM_ARM_GIC_CLASS(klass);
-
-    agcc->pre_save = kvm_arm_gic_get;
-    agcc->post_load = kvm_arm_gic_put;
-    kgc->parent_realize = dc->realize;
-    kgc->parent_reset = dc->reset;
-    dc->realize = kvm_arm_gic_realize;
-    dc->reset = kvm_arm_gic_reset;
-    dc->no_user = 1;
-}
-
-static const TypeInfo kvm_arm_gic_info = {
-    .name = TYPE_KVM_ARM_GIC,
-    .parent = TYPE_ARM_GIC_COMMON,
-    .instance_size = sizeof(GICState),
-    .class_init = kvm_arm_gic_class_init,
-    .class_size = sizeof(KVMARMGICClass),
-};
-
-static void kvm_arm_gic_register_types(void)
-{
-    type_register_static(&kvm_arm_gic_info);
-}
-
-type_init(kvm_arm_gic_register_types)
index bf8d152831af42071957730b0dc7c4ef6a8da352..1e59ac5c62ef6298024add464c6393e13a5db6ec 100644 (file)
@@ -1,5 +1,4 @@
 # LM32 peripherals
-obj-y += lm32_pic.o
 obj-y += lm32_sys.o
 obj-y += milkymist-hpdmc.o
 obj-y += milkymist-pfpu.o
diff --git a/hw/lm32_pic.c b/hw/lm32_pic.c
deleted file mode 100644 (file)
index b4e80c8..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- *  LatticeMico32 CPU interrupt controller logic.
- *
- *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <assert.h>
-
-#include "hw/hw.h"
-#include "hw/i386/pc.h"
-#include "monitor/monitor.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "hw/lm32/lm32_pic.h"
-
-struct LM32PicState {
-    SysBusDevice busdev;
-    qemu_irq parent_irq;
-    uint32_t im;        /* interrupt mask */
-    uint32_t ip;        /* interrupt pending */
-    uint32_t irq_state;
-
-    /* statistics */
-    uint32_t stats_irq_count[32];
-};
-typedef struct LM32PicState LM32PicState;
-
-static LM32PicState *pic;
-void lm32_do_pic_info(Monitor *mon, const QDict *qdict)
-{
-    if (pic == NULL) {
-        return;
-    }
-
-    monitor_printf(mon, "lm32-pic: im=%08x ip=%08x irq_state=%08x\n",
-            pic->im, pic->ip, pic->irq_state);
-}
-
-void lm32_irq_info(Monitor *mon, const QDict *qdict)
-{
-    int i;
-    uint32_t count;
-
-    if (pic == NULL) {
-        return;
-    }
-
-    monitor_printf(mon, "IRQ statistics:\n");
-    for (i = 0; i < 32; i++) {
-        count = pic->stats_irq_count[i];
-        if (count > 0) {
-            monitor_printf(mon, "%2d: %u\n", i, count);
-        }
-    }
-}
-
-static void update_irq(LM32PicState *s)
-{
-    s->ip |= s->irq_state;
-
-    if (s->ip & s->im) {
-        trace_lm32_pic_raise_irq();
-        qemu_irq_raise(s->parent_irq);
-    } else {
-        trace_lm32_pic_lower_irq();
-        qemu_irq_lower(s->parent_irq);
-    }
-}
-
-static void irq_handler(void *opaque, int irq, int level)
-{
-    LM32PicState *s = opaque;
-
-    assert(irq < 32);
-    trace_lm32_pic_interrupt(irq, level);
-
-    if (level) {
-        s->irq_state |= (1 << irq);
-        s->stats_irq_count[irq]++;
-    } else {
-        s->irq_state &= ~(1 << irq);
-    }
-
-    update_irq(s);
-}
-
-void lm32_pic_set_im(DeviceState *d, uint32_t im)
-{
-    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
-
-    trace_lm32_pic_set_im(im);
-    s->im = im;
-
-    update_irq(s);
-}
-
-void lm32_pic_set_ip(DeviceState *d, uint32_t ip)
-{
-    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
-
-    trace_lm32_pic_set_ip(ip);
-
-    /* ack interrupt */
-    s->ip &= ~ip;
-
-    update_irq(s);
-}
-
-uint32_t lm32_pic_get_im(DeviceState *d)
-{
-    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
-
-    trace_lm32_pic_get_im(s->im);
-    return s->im;
-}
-
-uint32_t lm32_pic_get_ip(DeviceState *d)
-{
-    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
-
-    trace_lm32_pic_get_ip(s->ip);
-    return s->ip;
-}
-
-static void pic_reset(DeviceState *d)
-{
-    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
-    int i;
-
-    s->im = 0;
-    s->ip = 0;
-    s->irq_state = 0;
-    for (i = 0; i < 32; i++) {
-        s->stats_irq_count[i] = 0;
-    }
-}
-
-static int lm32_pic_init(SysBusDevice *dev)
-{
-    LM32PicState *s = FROM_SYSBUS(typeof(*s), dev);
-
-    qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
-    sysbus_init_irq(dev, &s->parent_irq);
-
-    pic = s;
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_lm32_pic = {
-    .name = "lm32-pic",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(im, LM32PicState),
-        VMSTATE_UINT32(ip, LM32PicState),
-        VMSTATE_UINT32(irq_state, LM32PicState),
-        VMSTATE_UINT32_ARRAY(stats_irq_count, LM32PicState, 32),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void lm32_pic_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = lm32_pic_init;
-    dc->reset = pic_reset;
-    dc->vmsd = &vmstate_lm32_pic;
-}
-
-static const TypeInfo lm32_pic_info = {
-    .name          = "lm32-pic",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(LM32PicState),
-    .class_init    = lm32_pic_class_init,
-};
-
-static void lm32_pic_register_types(void)
-{
-    type_register_static(&lm32_pic_info);
-}
-
-type_init(lm32_pic_register_types)
diff --git a/hw/omap_intc.c b/hw/omap_intc.c
deleted file mode 100644 (file)
index 875eba4..0000000
+++ /dev/null
@@ -1,649 +0,0 @@
-/*
- * TI OMAP interrupt controller emulation.
- *
- * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog@zabor.org>
- * Copyright (C) 2007-2008 Nokia Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 or
- * (at your option) version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-#include "hw/hw.h"
-#include "hw/arm/omap.h"
-#include "hw/sysbus.h"
-
-/* Interrupt Handlers */
-struct omap_intr_handler_bank_s {
-    uint32_t irqs;
-    uint32_t inputs;
-    uint32_t mask;
-    uint32_t fiq;
-    uint32_t sens_edge;
-    uint32_t swi;
-    unsigned char priority[32];
-};
-
-struct omap_intr_handler_s {
-    SysBusDevice busdev;
-    qemu_irq *pins;
-    qemu_irq parent_intr[2];
-    MemoryRegion mmio;
-    void *iclk;
-    void *fclk;
-    unsigned char nbanks;
-    int level_only;
-    uint32_t size;
-
-    uint8_t revision;
-
-    /* state */
-    uint32_t new_agr[2];
-    int sir_intr[2];
-    int autoidle;
-    uint32_t mask;
-    struct omap_intr_handler_bank_s bank[3];
-};
-
-static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq)
-{
-    int i, j, sir_intr, p_intr, p, f;
-    uint32_t level;
-    sir_intr = 0;
-    p_intr = 255;
-
-    /* Find the interrupt line with the highest dynamic priority.
-     * Note: 0 denotes the hightest priority.
-     * If all interrupts have the same priority, the default order is IRQ_N,
-     * IRQ_N-1,...,IRQ_0. */
-    for (j = 0; j < s->nbanks; ++j) {
-        level = s->bank[j].irqs & ~s->bank[j].mask &
-                (is_fiq ? s->bank[j].fiq : ~s->bank[j].fiq);
-        for (f = ffs(level), i = f - 1, level >>= f - 1; f; i += f,
-                        level >>= f) {
-            p = s->bank[j].priority[i];
-            if (p <= p_intr) {
-                p_intr = p;
-                sir_intr = 32 * j + i;
-            }
-            f = ffs(level >> 1);
-        }
-    }
-    s->sir_intr[is_fiq] = sir_intr;
-}
-
-static inline void omap_inth_update(struct omap_intr_handler_s *s, int is_fiq)
-{
-    int i;
-    uint32_t has_intr = 0;
-
-    for (i = 0; i < s->nbanks; ++i)
-        has_intr |= s->bank[i].irqs & ~s->bank[i].mask &
-                (is_fiq ? s->bank[i].fiq : ~s->bank[i].fiq);
-
-    if (s->new_agr[is_fiq] & has_intr & s->mask) {
-        s->new_agr[is_fiq] = 0;
-        omap_inth_sir_update(s, is_fiq);
-        qemu_set_irq(s->parent_intr[is_fiq], 1);
-    }
-}
-
-#define INT_FALLING_EDGE       0
-#define INT_LOW_LEVEL          1
-
-static void omap_set_intr(void *opaque, int irq, int req)
-{
-    struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
-    uint32_t rise;
-
-    struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
-    int n = irq & 31;
-
-    if (req) {
-        rise = ~bank->irqs & (1 << n);
-        if (~bank->sens_edge & (1 << n))
-            rise &= ~bank->inputs;
-
-        bank->inputs |= (1 << n);
-        if (rise) {
-            bank->irqs |= rise;
-            omap_inth_update(ih, 0);
-            omap_inth_update(ih, 1);
-        }
-    } else {
-        rise = bank->sens_edge & bank->irqs & (1 << n);
-        bank->irqs &= ~rise;
-        bank->inputs &= ~(1 << n);
-    }
-}
-
-/* Simplified version with no edge detection */
-static void omap_set_intr_noedge(void *opaque, int irq, int req)
-{
-    struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
-    uint32_t rise;
-
-    struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
-    int n = irq & 31;
-
-    if (req) {
-        rise = ~bank->inputs & (1 << n);
-        if (rise) {
-            bank->irqs |= bank->inputs |= rise;
-            omap_inth_update(ih, 0);
-            omap_inth_update(ih, 1);
-        }
-    } else
-        bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi;
-}
-
-static uint64_t omap_inth_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
-    int i, offset = addr;
-    int bank_no = offset >> 8;
-    int line_no;
-    struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
-    offset &= 0xff;
-
-    switch (offset) {
-    case 0x00: /* ITR */
-        return bank->irqs;
-
-    case 0x04: /* MIR */
-        return bank->mask;
-
-    case 0x10: /* SIR_IRQ_CODE */
-    case 0x14:  /* SIR_FIQ_CODE */
-        if (bank_no != 0)
-            break;
-        line_no = s->sir_intr[(offset - 0x10) >> 2];
-        bank = &s->bank[line_no >> 5];
-        i = line_no & 31;
-        if (((bank->sens_edge >> i) & 1) == INT_FALLING_EDGE)
-            bank->irqs &= ~(1 << i);
-        return line_no;
-
-    case 0x18: /* CONTROL_REG */
-        if (bank_no != 0)
-            break;
-        return 0;
-
-    case 0x1c: /* ILR0 */
-    case 0x20: /* ILR1 */
-    case 0x24: /* ILR2 */
-    case 0x28: /* ILR3 */
-    case 0x2c: /* ILR4 */
-    case 0x30: /* ILR5 */
-    case 0x34: /* ILR6 */
-    case 0x38: /* ILR7 */
-    case 0x3c: /* ILR8 */
-    case 0x40: /* ILR9 */
-    case 0x44: /* ILR10 */
-    case 0x48: /* ILR11 */
-    case 0x4c: /* ILR12 */
-    case 0x50: /* ILR13 */
-    case 0x54: /* ILR14 */
-    case 0x58: /* ILR15 */
-    case 0x5c: /* ILR16 */
-    case 0x60: /* ILR17 */
-    case 0x64: /* ILR18 */
-    case 0x68: /* ILR19 */
-    case 0x6c: /* ILR20 */
-    case 0x70: /* ILR21 */
-    case 0x74: /* ILR22 */
-    case 0x78: /* ILR23 */
-    case 0x7c: /* ILR24 */
-    case 0x80: /* ILR25 */
-    case 0x84: /* ILR26 */
-    case 0x88: /* ILR27 */
-    case 0x8c: /* ILR28 */
-    case 0x90: /* ILR29 */
-    case 0x94: /* ILR30 */
-    case 0x98: /* ILR31 */
-        i = (offset - 0x1c) >> 2;
-        return (bank->priority[i] << 2) |
-                (((bank->sens_edge >> i) & 1) << 1) |
-                ((bank->fiq >> i) & 1);
-
-    case 0x9c: /* ISR */
-        return 0x00000000;
-
-    }
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_inth_write(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size)
-{
-    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
-    int i, offset = addr;
-    int bank_no = offset >> 8;
-    struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
-    offset &= 0xff;
-
-    switch (offset) {
-    case 0x00: /* ITR */
-        /* Important: ignore the clearing if the IRQ is level-triggered and
-           the input bit is 1 */
-        bank->irqs &= value | (bank->inputs & bank->sens_edge);
-        return;
-
-    case 0x04: /* MIR */
-        bank->mask = value;
-        omap_inth_update(s, 0);
-        omap_inth_update(s, 1);
-        return;
-
-    case 0x10: /* SIR_IRQ_CODE */
-    case 0x14: /* SIR_FIQ_CODE */
-        OMAP_RO_REG(addr);
-        break;
-
-    case 0x18: /* CONTROL_REG */
-        if (bank_no != 0)
-            break;
-        if (value & 2) {
-            qemu_set_irq(s->parent_intr[1], 0);
-            s->new_agr[1] = ~0;
-            omap_inth_update(s, 1);
-        }
-        if (value & 1) {
-            qemu_set_irq(s->parent_intr[0], 0);
-            s->new_agr[0] = ~0;
-            omap_inth_update(s, 0);
-        }
-        return;
-
-    case 0x1c: /* ILR0 */
-    case 0x20: /* ILR1 */
-    case 0x24: /* ILR2 */
-    case 0x28: /* ILR3 */
-    case 0x2c: /* ILR4 */
-    case 0x30: /* ILR5 */
-    case 0x34: /* ILR6 */
-    case 0x38: /* ILR7 */
-    case 0x3c: /* ILR8 */
-    case 0x40: /* ILR9 */
-    case 0x44: /* ILR10 */
-    case 0x48: /* ILR11 */
-    case 0x4c: /* ILR12 */
-    case 0x50: /* ILR13 */
-    case 0x54: /* ILR14 */
-    case 0x58: /* ILR15 */
-    case 0x5c: /* ILR16 */
-    case 0x60: /* ILR17 */
-    case 0x64: /* ILR18 */
-    case 0x68: /* ILR19 */
-    case 0x6c: /* ILR20 */
-    case 0x70: /* ILR21 */
-    case 0x74: /* ILR22 */
-    case 0x78: /* ILR23 */
-    case 0x7c: /* ILR24 */
-    case 0x80: /* ILR25 */
-    case 0x84: /* ILR26 */
-    case 0x88: /* ILR27 */
-    case 0x8c: /* ILR28 */
-    case 0x90: /* ILR29 */
-    case 0x94: /* ILR30 */
-    case 0x98: /* ILR31 */
-        i = (offset - 0x1c) >> 2;
-        bank->priority[i] = (value >> 2) & 0x1f;
-        bank->sens_edge &= ~(1 << i);
-        bank->sens_edge |= ((value >> 1) & 1) << i;
-        bank->fiq &= ~(1 << i);
-        bank->fiq |= (value & 1) << i;
-        return;
-
-    case 0x9c: /* ISR */
-        for (i = 0; i < 32; i ++)
-            if (value & (1 << i)) {
-                omap_set_intr(s, 32 * bank_no + i, 1);
-                return;
-            }
-        return;
-    }
-    OMAP_BAD_REG(addr);
-}
-
-static const MemoryRegionOps omap_inth_mem_ops = {
-    .read = omap_inth_read,
-    .write = omap_inth_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static void omap_inth_reset(DeviceState *dev)
-{
-    struct omap_intr_handler_s *s = FROM_SYSBUS(struct omap_intr_handler_s,
-                                                SYS_BUS_DEVICE(dev));
-    int i;
-
-    for (i = 0; i < s->nbanks; ++i){
-        s->bank[i].irqs = 0x00000000;
-        s->bank[i].mask = 0xffffffff;
-        s->bank[i].sens_edge = 0x00000000;
-        s->bank[i].fiq = 0x00000000;
-        s->bank[i].inputs = 0x00000000;
-        s->bank[i].swi = 0x00000000;
-        memset(s->bank[i].priority, 0, sizeof(s->bank[i].priority));
-
-        if (s->level_only)
-            s->bank[i].sens_edge = 0xffffffff;
-    }
-
-    s->new_agr[0] = ~0;
-    s->new_agr[1] = ~0;
-    s->sir_intr[0] = 0;
-    s->sir_intr[1] = 0;
-    s->autoidle = 0;
-    s->mask = ~0;
-
-    qemu_set_irq(s->parent_intr[0], 0);
-    qemu_set_irq(s->parent_intr[1], 0);
-}
-
-static int omap_intc_init(SysBusDevice *dev)
-{
-    struct omap_intr_handler_s *s;
-    s = FROM_SYSBUS(struct omap_intr_handler_s, dev);
-    if (!s->iclk) {
-        hw_error("omap-intc: clk not connected\n");
-    }
-    s->nbanks = 1;
-    sysbus_init_irq(dev, &s->parent_intr[0]);
-    sysbus_init_irq(dev, &s->parent_intr[1]);
-    qdev_init_gpio_in(&dev->qdev, omap_set_intr, s->nbanks * 32);
-    memory_region_init_io(&s->mmio, &omap_inth_mem_ops, s,
-                          "omap-intc", s->size);
-    sysbus_init_mmio(dev, &s->mmio);
-    return 0;
-}
-
-static Property omap_intc_properties[] = {
-    DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100),
-    DEFINE_PROP_PTR("clk", struct omap_intr_handler_s, iclk),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void omap_intc_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = omap_intc_init;
-    dc->reset = omap_inth_reset;
-    dc->props = omap_intc_properties;
-}
-
-static const TypeInfo omap_intc_info = {
-    .name          = "omap-intc",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(struct omap_intr_handler_s),
-    .class_init    = omap_intc_class_init,
-};
-
-static uint64_t omap2_inth_read(void *opaque, hwaddr addr,
-                                unsigned size)
-{
-    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
-    int offset = addr;
-    int bank_no, line_no;
-    struct omap_intr_handler_bank_s *bank = NULL;
-
-    if ((offset & 0xf80) == 0x80) {
-        bank_no = (offset & 0x60) >> 5;
-        if (bank_no < s->nbanks) {
-            offset &= ~0x60;
-            bank = &s->bank[bank_no];
-        } else {
-            OMAP_BAD_REG(addr);
-            return 0;
-        }
-    }
-
-    switch (offset) {
-    case 0x00: /* INTC_REVISION */
-        return s->revision;
-
-    case 0x10: /* INTC_SYSCONFIG */
-        return (s->autoidle >> 2) & 1;
-
-    case 0x14: /* INTC_SYSSTATUS */
-        return 1;                                              /* RESETDONE */
-
-    case 0x40: /* INTC_SIR_IRQ */
-        return s->sir_intr[0];
-
-    case 0x44: /* INTC_SIR_FIQ */
-        return s->sir_intr[1];
-
-    case 0x48: /* INTC_CONTROL */
-        return (!s->mask) << 2;                                        /* GLOBALMASK */
-
-    case 0x4c: /* INTC_PROTECTION */
-        return 0;
-
-    case 0x50: /* INTC_IDLE */
-        return s->autoidle & 3;
-
-    /* Per-bank registers */
-    case 0x80: /* INTC_ITR */
-        return bank->inputs;
-
-    case 0x84: /* INTC_MIR */
-        return bank->mask;
-
-    case 0x88: /* INTC_MIR_CLEAR */
-    case 0x8c: /* INTC_MIR_SET */
-        return 0;
-
-    case 0x90: /* INTC_ISR_SET */
-        return bank->swi;
-
-    case 0x94: /* INTC_ISR_CLEAR */
-        return 0;
-
-    case 0x98: /* INTC_PENDING_IRQ */
-        return bank->irqs & ~bank->mask & ~bank->fiq;
-
-    case 0x9c: /* INTC_PENDING_FIQ */
-        return bank->irqs & ~bank->mask & bank->fiq;
-
-    /* Per-line registers */
-    case 0x100 ... 0x300:      /* INTC_ILR */
-        bank_no = (offset - 0x100) >> 7;
-        if (bank_no > s->nbanks)
-            break;
-        bank = &s->bank[bank_no];
-        line_no = (offset & 0x7f) >> 2;
-        return (bank->priority[line_no] << 2) |
-                ((bank->fiq >> line_no) & 1);
-    }
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap2_inth_write(void *opaque, hwaddr addr,
-                             uint64_t value, unsigned size)
-{
-    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
-    int offset = addr;
-    int bank_no, line_no;
-    struct omap_intr_handler_bank_s *bank = NULL;
-
-    if ((offset & 0xf80) == 0x80) {
-        bank_no = (offset & 0x60) >> 5;
-        if (bank_no < s->nbanks) {
-            offset &= ~0x60;
-            bank = &s->bank[bank_no];
-        } else {
-            OMAP_BAD_REG(addr);
-            return;
-        }
-    }
-
-    switch (offset) {
-    case 0x10: /* INTC_SYSCONFIG */
-        s->autoidle &= 4;
-        s->autoidle |= (value & 1) << 2;
-        if (value & 2)                                         /* SOFTRESET */
-            omap_inth_reset(&s->busdev.qdev);
-        return;
-
-    case 0x48: /* INTC_CONTROL */
-        s->mask = (value & 4) ? 0 : ~0;                                /* GLOBALMASK */
-        if (value & 2) {                                       /* NEWFIQAGR */
-            qemu_set_irq(s->parent_intr[1], 0);
-            s->new_agr[1] = ~0;
-            omap_inth_update(s, 1);
-        }
-        if (value & 1) {                                       /* NEWIRQAGR */
-            qemu_set_irq(s->parent_intr[0], 0);
-            s->new_agr[0] = ~0;
-            omap_inth_update(s, 0);
-        }
-        return;
-
-    case 0x4c: /* INTC_PROTECTION */
-        /* TODO: Make a bitmap (or sizeof(char)map) of access privileges
-         * for every register, see Chapter 3 and 4 for privileged mode.  */
-        if (value & 1)
-            fprintf(stderr, "%s: protection mode enable attempt\n",
-                            __FUNCTION__);
-        return;
-
-    case 0x50: /* INTC_IDLE */
-        s->autoidle &= ~3;
-        s->autoidle |= value & 3;
-        return;
-
-    /* Per-bank registers */
-    case 0x84: /* INTC_MIR */
-        bank->mask = value;
-        omap_inth_update(s, 0);
-        omap_inth_update(s, 1);
-        return;
-
-    case 0x88: /* INTC_MIR_CLEAR */
-        bank->mask &= ~value;
-        omap_inth_update(s, 0);
-        omap_inth_update(s, 1);
-        return;
-
-    case 0x8c: /* INTC_MIR_SET */
-        bank->mask |= value;
-        return;
-
-    case 0x90: /* INTC_ISR_SET */
-        bank->irqs |= bank->swi |= value;
-        omap_inth_update(s, 0);
-        omap_inth_update(s, 1);
-        return;
-
-    case 0x94: /* INTC_ISR_CLEAR */
-        bank->swi &= ~value;
-        bank->irqs = bank->swi & bank->inputs;
-        return;
-
-    /* Per-line registers */
-    case 0x100 ... 0x300:      /* INTC_ILR */
-        bank_no = (offset - 0x100) >> 7;
-        if (bank_no > s->nbanks)
-            break;
-        bank = &s->bank[bank_no];
-        line_no = (offset & 0x7f) >> 2;
-        bank->priority[line_no] = (value >> 2) & 0x3f;
-        bank->fiq &= ~(1 << line_no);
-        bank->fiq |= (value & 1) << line_no;
-        return;
-
-    case 0x00: /* INTC_REVISION */
-    case 0x14: /* INTC_SYSSTATUS */
-    case 0x40: /* INTC_SIR_IRQ */
-    case 0x44: /* INTC_SIR_FIQ */
-    case 0x80: /* INTC_ITR */
-    case 0x98: /* INTC_PENDING_IRQ */
-    case 0x9c: /* INTC_PENDING_FIQ */
-        OMAP_RO_REG(addr);
-        return;
-    }
-    OMAP_BAD_REG(addr);
-}
-
-static const MemoryRegionOps omap2_inth_mem_ops = {
-    .read = omap2_inth_read,
-    .write = omap2_inth_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static int omap2_intc_init(SysBusDevice *dev)
-{
-    struct omap_intr_handler_s *s;
-    s = FROM_SYSBUS(struct omap_intr_handler_s, dev);
-    if (!s->iclk) {
-        hw_error("omap2-intc: iclk not connected\n");
-    }
-    if (!s->fclk) {
-        hw_error("omap2-intc: fclk not connected\n");
-    }
-    s->level_only = 1;
-    s->nbanks = 3;
-    sysbus_init_irq(dev, &s->parent_intr[0]);
-    sysbus_init_irq(dev, &s->parent_intr[1]);
-    qdev_init_gpio_in(&dev->qdev, omap_set_intr_noedge, s->nbanks * 32);
-    memory_region_init_io(&s->mmio, &omap2_inth_mem_ops, s,
-                          "omap2-intc", 0x1000);
-    sysbus_init_mmio(dev, &s->mmio);
-    return 0;
-}
-
-static Property omap2_intc_properties[] = {
-    DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s,
-    revision, 0x21),
-    DEFINE_PROP_PTR("iclk", struct omap_intr_handler_s, iclk),
-    DEFINE_PROP_PTR("fclk", struct omap_intr_handler_s, fclk),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void omap2_intc_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = omap2_intc_init;
-    dc->reset = omap_inth_reset;
-    dc->props = omap2_intc_properties;
-}
-
-static const TypeInfo omap2_intc_info = {
-    .name          = "omap2-intc",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(struct omap_intr_handler_s),
-    .class_init    = omap2_intc_class_init,
-};
-
-static void omap_intc_register_types(void)
-{
-    type_register_static(&omap_intc_info);
-    type_register_static(&omap2_intc_info);
-}
-
-type_init(omap_intc_register_types)
diff --git a/hw/openpic.c b/hw/openpic.c
deleted file mode 100644 (file)
index c788714..0000000
+++ /dev/null
@@ -1,1661 +0,0 @@
-/*
- * OpenPIC emulation
- *
- * Copyright (c) 2004 Jocelyn Mayer
- *               2011 Alexander Graf
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-/*
- *
- * Based on OpenPic implementations:
- * - Intel GW80314 I/O companion chip developer's manual
- * - Motorola MPC8245 & MPC8540 user manuals.
- * - Motorola MCP750 (aka Raven) programmer manual.
- * - Motorola Harrier programmer manuel
- *
- * Serial interrupts, as implemented in Raven chipset are not supported yet.
- *
- */
-#include "hw/hw.h"
-#include "hw/ppc/mac.h"
-#include "hw/pci/pci.h"
-#include "hw/ppc/openpic.h"
-#include "hw/sysbus.h"
-#include "hw/pci/msi.h"
-#include "qemu/bitops.h"
-#include "hw/ppc/ppc.h"
-
-//#define DEBUG_OPENPIC
-
-#ifdef DEBUG_OPENPIC
-static const int debug_openpic = 1;
-#else
-static const int debug_openpic = 0;
-#endif
-
-#define DPRINTF(fmt, ...) do { \
-        if (debug_openpic) { \
-            printf(fmt , ## __VA_ARGS__); \
-        } \
-    } while (0)
-
-#define MAX_CPU     32
-#define MAX_SRC     256
-#define MAX_TMR     4
-#define MAX_IPI     4
-#define MAX_MSI     8
-#define MAX_IRQ     (MAX_SRC + MAX_IPI + MAX_TMR)
-#define VID         0x03 /* MPIC version ID */
-
-/* OpenPIC capability flags */
-#define OPENPIC_FLAG_IDR_CRIT     (1 << 0)
-#define OPENPIC_FLAG_ILR          (2 << 0)
-
-/* OpenPIC address map */
-#define OPENPIC_GLB_REG_START        0x0
-#define OPENPIC_GLB_REG_SIZE         0x10F0
-#define OPENPIC_TMR_REG_START        0x10F0
-#define OPENPIC_TMR_REG_SIZE         0x220
-#define OPENPIC_MSI_REG_START        0x1600
-#define OPENPIC_MSI_REG_SIZE         0x200
-#define OPENPIC_SUMMARY_REG_START   0x3800
-#define OPENPIC_SUMMARY_REG_SIZE    0x800
-#define OPENPIC_SRC_REG_START        0x10000
-#define OPENPIC_SRC_REG_SIZE         (MAX_SRC * 0x20)
-#define OPENPIC_CPU_REG_START        0x20000
-#define OPENPIC_CPU_REG_SIZE         0x100 + ((MAX_CPU - 1) * 0x1000)
-
-/* Raven */
-#define RAVEN_MAX_CPU      2
-#define RAVEN_MAX_EXT     48
-#define RAVEN_MAX_IRQ     64
-#define RAVEN_MAX_TMR      MAX_TMR
-#define RAVEN_MAX_IPI      MAX_IPI
-
-/* Interrupt definitions */
-#define RAVEN_FE_IRQ     (RAVEN_MAX_EXT)     /* Internal functional IRQ */
-#define RAVEN_ERR_IRQ    (RAVEN_MAX_EXT + 1) /* Error IRQ */
-#define RAVEN_TMR_IRQ    (RAVEN_MAX_EXT + 2) /* First timer IRQ */
-#define RAVEN_IPI_IRQ    (RAVEN_TMR_IRQ + RAVEN_MAX_TMR) /* First IPI IRQ */
-/* First doorbell IRQ */
-#define RAVEN_DBL_IRQ    (RAVEN_IPI_IRQ + (RAVEN_MAX_CPU * RAVEN_MAX_IPI))
-
-typedef struct FslMpicInfo {
-    int max_ext;
-} FslMpicInfo;
-
-static FslMpicInfo fsl_mpic_20 = {
-    .max_ext = 12,
-};
-
-static FslMpicInfo fsl_mpic_42 = {
-    .max_ext = 12,
-};
-
-#define FRR_NIRQ_SHIFT    16
-#define FRR_NCPU_SHIFT     8
-#define FRR_VID_SHIFT      0
-
-#define VID_REVISION_1_2   2
-#define VID_REVISION_1_3   3
-
-#define VIR_GENERIC      0x00000000 /* Generic Vendor ID */
-
-#define GCR_RESET        0x80000000
-#define GCR_MODE_PASS    0x00000000
-#define GCR_MODE_MIXED   0x20000000
-#define GCR_MODE_PROXY   0x60000000
-
-#define TBCR_CI           0x80000000 /* count inhibit */
-#define TCCR_TOG          0x80000000 /* toggles when decrement to zero */
-
-#define IDR_EP_SHIFT      31
-#define IDR_EP_MASK       (1 << IDR_EP_SHIFT)
-#define IDR_CI0_SHIFT     30
-#define IDR_CI1_SHIFT     29
-#define IDR_P1_SHIFT      1
-#define IDR_P0_SHIFT      0
-
-#define ILR_INTTGT_MASK   0x000000ff
-#define ILR_INTTGT_INT    0x00
-#define ILR_INTTGT_CINT   0x01 /* critical */
-#define ILR_INTTGT_MCP    0x02 /* machine check */
-
-/* The currently supported INTTGT values happen to be the same as QEMU's
- * openpic output codes, but don't depend on this.  The output codes
- * could change (unlikely, but...) or support could be added for
- * more INTTGT values.
- */
-static const int inttgt_output[][2] = {
-    { ILR_INTTGT_INT, OPENPIC_OUTPUT_INT },
-    { ILR_INTTGT_CINT, OPENPIC_OUTPUT_CINT },
-    { ILR_INTTGT_MCP, OPENPIC_OUTPUT_MCK },
-};
-
-static int inttgt_to_output(int inttgt)
-{
-    int i;
-
-    for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) {
-        if (inttgt_output[i][0] == inttgt) {
-            return inttgt_output[i][1];
-        }
-    }
-
-    fprintf(stderr, "%s: unsupported inttgt %d\n", __func__, inttgt);
-    return OPENPIC_OUTPUT_INT;
-}
-
-static int output_to_inttgt(int output)
-{
-    int i;
-
-    for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) {
-        if (inttgt_output[i][1] == output) {
-            return inttgt_output[i][0];
-        }
-    }
-
-    abort();
-}
-
-#define MSIIR_OFFSET       0x140
-#define MSIIR_SRS_SHIFT    29
-#define MSIIR_SRS_MASK     (0x7 << MSIIR_SRS_SHIFT)
-#define MSIIR_IBS_SHIFT    24
-#define MSIIR_IBS_MASK     (0x1f << MSIIR_IBS_SHIFT)
-
-static int get_current_cpu(void)
-{
-    CPUState *cpu_single_cpu;
-
-    if (!cpu_single_env) {
-        return -1;
-    }
-
-    cpu_single_cpu = ENV_GET_CPU(cpu_single_env);
-    return cpu_single_cpu->cpu_index;
-}
-
-static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
-                                          int idx);
-static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
-                                       uint32_t val, int idx);
-
-typedef enum IRQType {
-    IRQ_TYPE_NORMAL = 0,
-    IRQ_TYPE_FSLINT,        /* FSL internal interrupt -- level only */
-    IRQ_TYPE_FSLSPECIAL,    /* FSL timer/IPI interrupt, edge, no polarity */
-} IRQType;
-
-typedef struct IRQQueue {
-    /* Round up to the nearest 64 IRQs so that the queue length
-     * won't change when moving between 32 and 64 bit hosts.
-     */
-    unsigned long queue[BITS_TO_LONGS((MAX_IRQ + 63) & ~63)];
-    int next;
-    int priority;
-} IRQQueue;
-
-typedef struct IRQSource {
-    uint32_t ivpr;  /* IRQ vector/priority register */
-    uint32_t idr;   /* IRQ destination register */
-    uint32_t destmask; /* bitmap of CPU destinations */
-    int last_cpu;
-    int output;     /* IRQ level, e.g. OPENPIC_OUTPUT_INT */
-    int pending;    /* TRUE if IRQ is pending */
-    IRQType type;
-    bool level:1;   /* level-triggered */
-    bool nomask:1;  /* critical interrupts ignore mask on some FSL MPICs */
-} IRQSource;
-
-#define IVPR_MASK_SHIFT       31
-#define IVPR_MASK_MASK        (1 << IVPR_MASK_SHIFT)
-#define IVPR_ACTIVITY_SHIFT   30
-#define IVPR_ACTIVITY_MASK    (1 << IVPR_ACTIVITY_SHIFT)
-#define IVPR_MODE_SHIFT       29
-#define IVPR_MODE_MASK        (1 << IVPR_MODE_SHIFT)
-#define IVPR_POLARITY_SHIFT   23
-#define IVPR_POLARITY_MASK    (1 << IVPR_POLARITY_SHIFT)
-#define IVPR_SENSE_SHIFT      22
-#define IVPR_SENSE_MASK       (1 << IVPR_SENSE_SHIFT)
-
-#define IVPR_PRIORITY_MASK     (0xF << 16)
-#define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16))
-#define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask)
-
-/* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */
-#define IDR_EP      0x80000000  /* external pin */
-#define IDR_CI      0x40000000  /* critical interrupt */
-
-typedef struct IRQDest {
-    int32_t ctpr; /* CPU current task priority */
-    IRQQueue raised;
-    IRQQueue servicing;
-    qemu_irq *irqs;
-
-    /* Count of IRQ sources asserting on non-INT outputs */
-    uint32_t outputs_active[OPENPIC_OUTPUT_NB];
-} IRQDest;
-
-typedef struct OpenPICState {
-    SysBusDevice busdev;
-    MemoryRegion mem;
-
-    /* Behavior control */
-    FslMpicInfo *fsl;
-    uint32_t model;
-    uint32_t flags;
-    uint32_t nb_irqs;
-    uint32_t vid;
-    uint32_t vir; /* Vendor identification register */
-    uint32_t vector_mask;
-    uint32_t tfrr_reset;
-    uint32_t ivpr_reset;
-    uint32_t idr_reset;
-    uint32_t brr1;
-    uint32_t mpic_mode_mask;
-
-    /* Sub-regions */
-    MemoryRegion sub_io_mem[6];
-
-    /* Global registers */
-    uint32_t frr; /* Feature reporting register */
-    uint32_t gcr; /* Global configuration register  */
-    uint32_t pir; /* Processor initialization register */
-    uint32_t spve; /* Spurious vector register */
-    uint32_t tfrr; /* Timer frequency reporting register */
-    /* Source registers */
-    IRQSource src[MAX_IRQ];
-    /* Local registers per output pin */
-    IRQDest dst[MAX_CPU];
-    uint32_t nb_cpus;
-    /* Timer registers */
-    struct {
-        uint32_t tccr;  /* Global timer current count register */
-        uint32_t tbcr;  /* Global timer base count register */
-    } timers[MAX_TMR];
-    /* Shared MSI registers */
-    struct {
-        uint32_t msir;   /* Shared Message Signaled Interrupt Register */
-    } msi[MAX_MSI];
-    uint32_t max_irq;
-    uint32_t irq_ipi0;
-    uint32_t irq_tim0;
-    uint32_t irq_msi;
-} OpenPICState;
-
-static inline void IRQ_setbit(IRQQueue *q, int n_IRQ)
-{
-    set_bit(n_IRQ, q->queue);
-}
-
-static inline void IRQ_resetbit(IRQQueue *q, int n_IRQ)
-{
-    clear_bit(n_IRQ, q->queue);
-}
-
-static inline int IRQ_testbit(IRQQueue *q, int n_IRQ)
-{
-    return test_bit(n_IRQ, q->queue);
-}
-
-static void IRQ_check(OpenPICState *opp, IRQQueue *q)
-{
-    int irq = -1;
-    int next = -1;
-    int priority = -1;
-
-    for (;;) {
-        irq = find_next_bit(q->queue, opp->max_irq, irq + 1);
-        if (irq == opp->max_irq) {
-            break;
-        }
-
-        DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n",
-                irq, IVPR_PRIORITY(opp->src[irq].ivpr), priority);
-
-        if (IVPR_PRIORITY(opp->src[irq].ivpr) > priority) {
-            next = irq;
-            priority = IVPR_PRIORITY(opp->src[irq].ivpr);
-        }
-    }
-
-    q->next = next;
-    q->priority = priority;
-}
-
-static int IRQ_get_next(OpenPICState *opp, IRQQueue *q)
-{
-    /* XXX: optimize */
-    IRQ_check(opp, q);
-
-    return q->next;
-}
-
-static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,
-                           bool active, bool was_active)
-{
-    IRQDest *dst;
-    IRQSource *src;
-    int priority;
-
-    dst = &opp->dst[n_CPU];
-    src = &opp->src[n_IRQ];
-
-    DPRINTF("%s: IRQ %d active %d was %d\n",
-            __func__, n_IRQ, active, was_active);
-
-    if (src->output != OPENPIC_OUTPUT_INT) {
-        DPRINTF("%s: output %d irq %d active %d was %d count %d\n",
-                __func__, src->output, n_IRQ, active, was_active,
-                dst->outputs_active[src->output]);
-
-        /* On Freescale MPIC, critical interrupts ignore priority,
-         * IACK, EOI, etc.  Before MPIC v4.1 they also ignore
-         * masking.
-         */
-        if (active) {
-            if (!was_active && dst->outputs_active[src->output]++ == 0) {
-                DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d\n",
-                        __func__, src->output, n_CPU, n_IRQ);
-                qemu_irq_raise(dst->irqs[src->output]);
-            }
-        } else {
-            if (was_active && --dst->outputs_active[src->output] == 0) {
-                DPRINTF("%s: Lower OpenPIC output %d cpu %d irq %d\n",
-                        __func__, src->output, n_CPU, n_IRQ);
-                qemu_irq_lower(dst->irqs[src->output]);
-            }
-        }
-
-        return;
-    }
-
-    priority = IVPR_PRIORITY(src->ivpr);
-
-    /* Even if the interrupt doesn't have enough priority,
-     * it is still raised, in case ctpr is lowered later.
-     */
-    if (active) {
-        IRQ_setbit(&dst->raised, n_IRQ);
-    } else {
-        IRQ_resetbit(&dst->raised, n_IRQ);
-    }
-
-    IRQ_check(opp, &dst->raised);
-
-    if (active && priority <= dst->ctpr) {
-        DPRINTF("%s: IRQ %d priority %d too low for ctpr %d on CPU %d\n",
-                __func__, n_IRQ, priority, dst->ctpr, n_CPU);
-        active = 0;
-    }
-
-    if (active) {
-        if (IRQ_get_next(opp, &dst->servicing) >= 0 &&
-                priority <= dst->servicing.priority) {
-            DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
-                    __func__, n_IRQ, dst->servicing.next, n_CPU);
-        } else {
-            DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d/%d\n",
-                    __func__, n_CPU, n_IRQ, dst->raised.next);
-            qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
-        }
-    } else {
-        IRQ_get_next(opp, &dst->servicing);
-        if (dst->raised.priority > dst->ctpr &&
-                dst->raised.priority > dst->servicing.priority) {
-            DPRINTF("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d\n",
-                    __func__, n_IRQ, dst->raised.next, dst->raised.priority,
-                    dst->ctpr, dst->servicing.priority, n_CPU);
-            /* IRQ line stays asserted */
-        } else {
-            DPRINTF("%s: IRQ %d inactive, current prio %d/%d, CPU %d\n",
-                    __func__, n_IRQ, dst->ctpr, dst->servicing.priority, n_CPU);
-            qemu_irq_lower(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
-        }
-    }
-}
-
-/* update pic state because registers for n_IRQ have changed value */
-static void openpic_update_irq(OpenPICState *opp, int n_IRQ)
-{
-    IRQSource *src;
-    bool active, was_active;
-    int i;
-
-    src = &opp->src[n_IRQ];
-    active = src->pending;
-
-    if ((src->ivpr & IVPR_MASK_MASK) && !src->nomask) {
-        /* Interrupt source is disabled */
-        DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
-        active = false;
-    }
-
-    was_active = !!(src->ivpr & IVPR_ACTIVITY_MASK);
-
-    /*
-     * We don't have a similar check for already-active because
-     * ctpr may have changed and we need to withdraw the interrupt.
-     */
-    if (!active && !was_active) {
-        DPRINTF("%s: IRQ %d is already inactive\n", __func__, n_IRQ);
-        return;
-    }
-
-    if (active) {
-        src->ivpr |= IVPR_ACTIVITY_MASK;
-    } else {
-        src->ivpr &= ~IVPR_ACTIVITY_MASK;
-    }
-
-    if (src->destmask == 0) {
-        /* No target */
-        DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
-        return;
-    }
-
-    if (src->destmask == (1 << src->last_cpu)) {
-        /* Only one CPU is allowed to receive this IRQ */
-        IRQ_local_pipe(opp, src->last_cpu, n_IRQ, active, was_active);
-    } else if (!(src->ivpr & IVPR_MODE_MASK)) {
-        /* Directed delivery mode */
-        for (i = 0; i < opp->nb_cpus; i++) {
-            if (src->destmask & (1 << i)) {
-                IRQ_local_pipe(opp, i, n_IRQ, active, was_active);
-            }
-        }
-    } else {
-        /* Distributed delivery mode */
-        for (i = src->last_cpu + 1; i != src->last_cpu; i++) {
-            if (i == opp->nb_cpus) {
-                i = 0;
-            }
-            if (src->destmask & (1 << i)) {
-                IRQ_local_pipe(opp, i, n_IRQ, active, was_active);
-                src->last_cpu = i;
-                break;
-            }
-        }
-    }
-}
-
-static void openpic_set_irq(void *opaque, int n_IRQ, int level)
-{
-    OpenPICState *opp = opaque;
-    IRQSource *src;
-
-    if (n_IRQ >= MAX_IRQ) {
-        fprintf(stderr, "%s: IRQ %d out of range\n", __func__, n_IRQ);
-        abort();
-    }
-
-    src = &opp->src[n_IRQ];
-    DPRINTF("openpic: set irq %d = %d ivpr=0x%08x\n",
-            n_IRQ, level, src->ivpr);
-    if (src->level) {
-        /* level-sensitive irq */
-        src->pending = level;
-        openpic_update_irq(opp, n_IRQ);
-    } else {
-        /* edge-sensitive irq */
-        if (level) {
-            src->pending = 1;
-            openpic_update_irq(opp, n_IRQ);
-        }
-
-        if (src->output != OPENPIC_OUTPUT_INT) {
-            /* Edge-triggered interrupts shouldn't be used
-             * with non-INT delivery, but just in case,
-             * try to make it do something sane rather than
-             * cause an interrupt storm.  This is close to
-             * what you'd probably see happen in real hardware.
-             */
-            src->pending = 0;
-            openpic_update_irq(opp, n_IRQ);
-        }
-    }
-}
-
-static void openpic_reset(DeviceState *d)
-{
-    OpenPICState *opp = FROM_SYSBUS(typeof(*opp), SYS_BUS_DEVICE(d));
-    int i;
-
-    opp->gcr = GCR_RESET;
-    /* Initialise controller registers */
-    opp->frr = ((opp->nb_irqs - 1) << FRR_NIRQ_SHIFT) |
-               ((opp->nb_cpus - 1) << FRR_NCPU_SHIFT) |
-               (opp->vid << FRR_VID_SHIFT);
-
-    opp->pir = 0;
-    opp->spve = -1 & opp->vector_mask;
-    opp->tfrr = opp->tfrr_reset;
-    /* Initialise IRQ sources */
-    for (i = 0; i < opp->max_irq; i++) {
-        opp->src[i].ivpr = opp->ivpr_reset;
-        opp->src[i].idr  = opp->idr_reset;
-
-        switch (opp->src[i].type) {
-        case IRQ_TYPE_NORMAL:
-            opp->src[i].level = !!(opp->ivpr_reset & IVPR_SENSE_MASK);
-            break;
-
-        case IRQ_TYPE_FSLINT:
-            opp->src[i].ivpr |= IVPR_POLARITY_MASK;
-            break;
-
-        case IRQ_TYPE_FSLSPECIAL:
-            break;
-        }
-    }
-    /* Initialise IRQ destinations */
-    for (i = 0; i < MAX_CPU; i++) {
-        opp->dst[i].ctpr      = 15;
-        memset(&opp->dst[i].raised, 0, sizeof(IRQQueue));
-        opp->dst[i].raised.next = -1;
-        memset(&opp->dst[i].servicing, 0, sizeof(IRQQueue));
-        opp->dst[i].servicing.next = -1;
-    }
-    /* Initialise timers */
-    for (i = 0; i < MAX_TMR; i++) {
-        opp->timers[i].tccr = 0;
-        opp->timers[i].tbcr = TBCR_CI;
-    }
-    /* Go out of RESET state */
-    opp->gcr = 0;
-}
-
-static inline uint32_t read_IRQreg_idr(OpenPICState *opp, int n_IRQ)
-{
-    return opp->src[n_IRQ].idr;
-}
-
-static inline uint32_t read_IRQreg_ilr(OpenPICState *opp, int n_IRQ)
-{
-    if (opp->flags & OPENPIC_FLAG_ILR) {
-        return output_to_inttgt(opp->src[n_IRQ].output);
-    }
-
-    return 0xffffffff;
-}
-
-static inline uint32_t read_IRQreg_ivpr(OpenPICState *opp, int n_IRQ)
-{
-    return opp->src[n_IRQ].ivpr;
-}
-
-static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val)
-{
-    IRQSource *src = &opp->src[n_IRQ];
-    uint32_t normal_mask = (1UL << opp->nb_cpus) - 1;
-    uint32_t crit_mask = 0;
-    uint32_t mask = normal_mask;
-    int crit_shift = IDR_EP_SHIFT - opp->nb_cpus;
-    int i;
-
-    if (opp->flags & OPENPIC_FLAG_IDR_CRIT) {
-        crit_mask = mask << crit_shift;
-        mask |= crit_mask | IDR_EP;
-    }
-
-    src->idr = val & mask;
-    DPRINTF("Set IDR %d to 0x%08x\n", n_IRQ, src->idr);
-
-    if (opp->flags & OPENPIC_FLAG_IDR_CRIT) {
-        if (src->idr & crit_mask) {
-            if (src->idr & normal_mask) {
-                DPRINTF("%s: IRQ configured for multiple output types, using "
-                        "critical\n", __func__);
-            }
-
-            src->output = OPENPIC_OUTPUT_CINT;
-            src->nomask = true;
-            src->destmask = 0;
-
-            for (i = 0; i < opp->nb_cpus; i++) {
-                int n_ci = IDR_CI0_SHIFT - i;
-
-                if (src->idr & (1UL << n_ci)) {
-                    src->destmask |= 1UL << i;
-                }
-            }
-        } else {
-            src->output = OPENPIC_OUTPUT_INT;
-            src->nomask = false;
-            src->destmask = src->idr & normal_mask;
-        }
-    } else {
-        src->destmask = src->idr;
-    }
-}
-
-static inline void write_IRQreg_ilr(OpenPICState *opp, int n_IRQ, uint32_t val)
-{
-    if (opp->flags & OPENPIC_FLAG_ILR) {
-        IRQSource *src = &opp->src[n_IRQ];
-
-        src->output = inttgt_to_output(val & ILR_INTTGT_MASK);
-        DPRINTF("Set ILR %d to 0x%08x, output %d\n", n_IRQ, src->idr,
-                src->output);
-
-        /* TODO: on MPIC v4.0 only, set nomask for non-INT */
-    }
-}
-
-static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val)
-{
-    uint32_t mask;
-
-    /* NOTE when implementing newer FSL MPIC models: starting with v4.0,
-     * the polarity bit is read-only on internal interrupts.
-     */
-    mask = IVPR_MASK_MASK | IVPR_PRIORITY_MASK | IVPR_SENSE_MASK |
-           IVPR_POLARITY_MASK | opp->vector_mask;
-
-    /* ACTIVITY bit is read-only */
-    opp->src[n_IRQ].ivpr =
-        (opp->src[n_IRQ].ivpr & IVPR_ACTIVITY_MASK) | (val & mask);
-
-    /* For FSL internal interrupts, The sense bit is reserved and zero,
-     * and the interrupt is always level-triggered.  Timers and IPIs
-     * have no sense or polarity bits, and are edge-triggered.
-     */
-    switch (opp->src[n_IRQ].type) {
-    case IRQ_TYPE_NORMAL:
-        opp->src[n_IRQ].level = !!(opp->src[n_IRQ].ivpr & IVPR_SENSE_MASK);
-        break;
-
-    case IRQ_TYPE_FSLINT:
-        opp->src[n_IRQ].ivpr &= ~IVPR_SENSE_MASK;
-        break;
-
-    case IRQ_TYPE_FSLSPECIAL:
-        opp->src[n_IRQ].ivpr &= ~(IVPR_POLARITY_MASK | IVPR_SENSE_MASK);
-        break;
-    }
-
-    openpic_update_irq(opp, n_IRQ);
-    DPRINTF("Set IVPR %d to 0x%08x -> 0x%08x\n", n_IRQ, val,
-            opp->src[n_IRQ].ivpr);
-}
-
-static void openpic_gcr_write(OpenPICState *opp, uint64_t val)
-{
-    bool mpic_proxy = false;
-
-    if (val & GCR_RESET) {
-        openpic_reset(&opp->busdev.qdev);
-        return;
-    }
-
-    opp->gcr &= ~opp->mpic_mode_mask;
-    opp->gcr |= val & opp->mpic_mode_mask;
-
-    /* Set external proxy mode */
-    if ((val & opp->mpic_mode_mask) == GCR_MODE_PROXY) {
-        mpic_proxy = true;
-    }
-
-    ppce500_set_mpic_proxy(mpic_proxy);
-}
-
-static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val,
-                              unsigned len)
-{
-    OpenPICState *opp = opaque;
-    IRQDest *dst;
-    int idx;
-
-    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
-            __func__, addr, val);
-    if (addr & 0xF) {
-        return;
-    }
-    switch (addr) {
-    case 0x00: /* Block Revision Register1 (BRR1) is Readonly */
-        break;
-    case 0x40:
-    case 0x50:
-    case 0x60:
-    case 0x70:
-    case 0x80:
-    case 0x90:
-    case 0xA0:
-    case 0xB0:
-        openpic_cpu_write_internal(opp, addr, val, get_current_cpu());
-        break;
-    case 0x1000: /* FRR */
-        break;
-    case 0x1020: /* GCR */
-        openpic_gcr_write(opp, val);
-        break;
-    case 0x1080: /* VIR */
-        break;
-    case 0x1090: /* PIR */
-        for (idx = 0; idx < opp->nb_cpus; idx++) {
-            if ((val & (1 << idx)) && !(opp->pir & (1 << idx))) {
-                DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
-                dst = &opp->dst[idx];
-                qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
-            } else if (!(val & (1 << idx)) && (opp->pir & (1 << idx))) {
-                DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
-                dst = &opp->dst[idx];
-                qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
-            }
-        }
-        opp->pir = val;
-        break;
-    case 0x10A0: /* IPI_IVPR */
-    case 0x10B0:
-    case 0x10C0:
-    case 0x10D0:
-        {
-            int idx;
-            idx = (addr - 0x10A0) >> 4;
-            write_IRQreg_ivpr(opp, opp->irq_ipi0 + idx, val);
-        }
-        break;
-    case 0x10E0: /* SPVE */
-        opp->spve = val & opp->vector_mask;
-        break;
-    default:
-        break;
-    }
-}
-
-static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len)
-{
-    OpenPICState *opp = opaque;
-    uint32_t retval;
-
-    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
-    retval = 0xFFFFFFFF;
-    if (addr & 0xF) {
-        return retval;
-    }
-    switch (addr) {
-    case 0x1000: /* FRR */
-        retval = opp->frr;
-        break;
-    case 0x1020: /* GCR */
-        retval = opp->gcr;
-        break;
-    case 0x1080: /* VIR */
-        retval = opp->vir;
-        break;
-    case 0x1090: /* PIR */
-        retval = 0x00000000;
-        break;
-    case 0x00: /* Block Revision Register1 (BRR1) */
-        retval = opp->brr1;
-        break;
-    case 0x40:
-    case 0x50:
-    case 0x60:
-    case 0x70:
-    case 0x80:
-    case 0x90:
-    case 0xA0:
-    case 0xB0:
-        retval = openpic_cpu_read_internal(opp, addr, get_current_cpu());
-        break;
-    case 0x10A0: /* IPI_IVPR */
-    case 0x10B0:
-    case 0x10C0:
-    case 0x10D0:
-        {
-            int idx;
-            idx = (addr - 0x10A0) >> 4;
-            retval = read_IRQreg_ivpr(opp, opp->irq_ipi0 + idx);
-        }
-        break;
-    case 0x10E0: /* SPVE */
-        retval = opp->spve;
-        break;
-    default:
-        break;
-    }
-    DPRINTF("%s: => 0x%08x\n", __func__, retval);
-
-    return retval;
-}
-
-static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val,
-                                unsigned len)
-{
-    OpenPICState *opp = opaque;
-    int idx;
-
-    addr += 0x10f0;
-
-    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
-            __func__, addr, val);
-    if (addr & 0xF) {
-        return;
-    }
-
-    if (addr == 0x10f0) {
-        /* TFRR */
-        opp->tfrr = val;
-        return;
-    }
-
-    idx = (addr >> 6) & 0x3;
-    addr = addr & 0x30;
-
-    switch (addr & 0x30) {
-    case 0x00: /* TCCR */
-        break;
-    case 0x10: /* TBCR */
-        if ((opp->timers[idx].tccr & TCCR_TOG) != 0 &&
-            (val & TBCR_CI) == 0 &&
-            (opp->timers[idx].tbcr & TBCR_CI) != 0) {
-            opp->timers[idx].tccr &= ~TCCR_TOG;
-        }
-        opp->timers[idx].tbcr = val;
-        break;
-    case 0x20: /* TVPR */
-        write_IRQreg_ivpr(opp, opp->irq_tim0 + idx, val);
-        break;
-    case 0x30: /* TDR */
-        write_IRQreg_idr(opp, opp->irq_tim0 + idx, val);
-        break;
-    }
-}
-
-static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len)
-{
-    OpenPICState *opp = opaque;
-    uint32_t retval = -1;
-    int idx;
-
-    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
-    if (addr & 0xF) {
-        goto out;
-    }
-    idx = (addr >> 6) & 0x3;
-    if (addr == 0x0) {
-        /* TFRR */
-        retval = opp->tfrr;
-        goto out;
-    }
-    switch (addr & 0x30) {
-    case 0x00: /* TCCR */
-        retval = opp->timers[idx].tccr;
-        break;
-    case 0x10: /* TBCR */
-        retval = opp->timers[idx].tbcr;
-        break;
-    case 0x20: /* TIPV */
-        retval = read_IRQreg_ivpr(opp, opp->irq_tim0 + idx);
-        break;
-    case 0x30: /* TIDE (TIDR) */
-        retval = read_IRQreg_idr(opp, opp->irq_tim0 + idx);
-        break;
-    }
-
-out:
-    DPRINTF("%s: => 0x%08x\n", __func__, retval);
-
-    return retval;
-}
-
-static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val,
-                              unsigned len)
-{
-    OpenPICState *opp = opaque;
-    int idx;
-
-    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
-            __func__, addr, val);
-
-    addr = addr & 0xffff;
-    idx = addr >> 5;
-
-    switch (addr & 0x1f) {
-    case 0x00:
-        write_IRQreg_ivpr(opp, idx, val);
-        break;
-    case 0x10:
-        write_IRQreg_idr(opp, idx, val);
-        break;
-    case 0x18:
-        write_IRQreg_ilr(opp, idx, val);
-        break;
-    }
-}
-
-static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len)
-{
-    OpenPICState *opp = opaque;
-    uint32_t retval;
-    int idx;
-
-    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
-    retval = 0xFFFFFFFF;
-
-    addr = addr & 0xffff;
-    idx = addr >> 5;
-
-    switch (addr & 0x1f) {
-    case 0x00:
-        retval = read_IRQreg_ivpr(opp, idx);
-        break;
-    case 0x10:
-        retval = read_IRQreg_idr(opp, idx);
-        break;
-    case 0x18:
-        retval = read_IRQreg_ilr(opp, idx);
-        break;
-    }
-
-    DPRINTF("%s: => 0x%08x\n", __func__, retval);
-    return retval;
-}
-
-static void openpic_msi_write(void *opaque, hwaddr addr, uint64_t val,
-                              unsigned size)
-{
-    OpenPICState *opp = opaque;
-    int idx = opp->irq_msi;
-    int srs, ibs;
-
-    DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n",
-            __func__, addr, val);
-    if (addr & 0xF) {
-        return;
-    }
-
-    switch (addr) {
-    case MSIIR_OFFSET:
-        srs = val >> MSIIR_SRS_SHIFT;
-        idx += srs;
-        ibs = (val & MSIIR_IBS_MASK) >> MSIIR_IBS_SHIFT;
-        opp->msi[srs].msir |= 1 << ibs;
-        openpic_set_irq(opp, idx, 1);
-        break;
-    default:
-        /* most registers are read-only, thus ignored */
-        break;
-    }
-}
-
-static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size)
-{
-    OpenPICState *opp = opaque;
-    uint64_t r = 0;
-    int i, srs;
-
-    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
-    if (addr & 0xF) {
-        return -1;
-    }
-
-    srs = addr >> 4;
-
-    switch (addr) {
-    case 0x00:
-    case 0x10:
-    case 0x20:
-    case 0x30:
-    case 0x40:
-    case 0x50:
-    case 0x60:
-    case 0x70: /* MSIRs */
-        r = opp->msi[srs].msir;
-        /* Clear on read */
-        opp->msi[srs].msir = 0;
-        openpic_set_irq(opp, opp->irq_msi + srs, 0);
-        break;
-    case 0x120: /* MSISR */
-        for (i = 0; i < MAX_MSI; i++) {
-            r |= (opp->msi[i].msir ? 1 : 0) << i;
-        }
-        break;
-    }
-
-    return r;
-}
-
-static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size)
-{
-    uint64_t r = 0;
-
-    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
-
-    /* TODO: EISR/EIMR */
-
-    return r;
-}
-
-static void openpic_summary_write(void *opaque, hwaddr addr, uint64_t val,
-                                  unsigned size)
-{
-    DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n",
-            __func__, addr, val);
-
-    /* TODO: EISR/EIMR */
-}
-
-static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
-                                       uint32_t val, int idx)
-{
-    OpenPICState *opp = opaque;
-    IRQSource *src;
-    IRQDest *dst;
-    int s_IRQ, n_IRQ;
-
-    DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx " <= 0x%08x\n", __func__, idx,
-            addr, val);
-
-    if (idx < 0) {
-        return;
-    }
-
-    if (addr & 0xF) {
-        return;
-    }
-    dst = &opp->dst[idx];
-    addr &= 0xFF0;
-    switch (addr) {
-    case 0x40: /* IPIDR */
-    case 0x50:
-    case 0x60:
-    case 0x70:
-        idx = (addr - 0x40) >> 4;
-        /* we use IDE as mask which CPUs to deliver the IPI to still. */
-        opp->src[opp->irq_ipi0 + idx].destmask |= val;
-        openpic_set_irq(opp, opp->irq_ipi0 + idx, 1);
-        openpic_set_irq(opp, opp->irq_ipi0 + idx, 0);
-        break;
-    case 0x80: /* CTPR */
-        dst->ctpr = val & 0x0000000F;
-
-        DPRINTF("%s: set CPU %d ctpr to %d, raised %d servicing %d\n",
-                __func__, idx, dst->ctpr, dst->raised.priority,
-                dst->servicing.priority);
-
-        if (dst->raised.priority <= dst->ctpr) {
-            DPRINTF("%s: Lower OpenPIC INT output cpu %d due to ctpr\n",
-                    __func__, idx);
-            qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
-        } else if (dst->raised.priority > dst->servicing.priority) {
-            DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d\n",
-                    __func__, idx, dst->raised.next);
-            qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
-        }
-
-        break;
-    case 0x90: /* WHOAMI */
-        /* Read-only register */
-        break;
-    case 0xA0: /* IACK */
-        /* Read-only register */
-        break;
-    case 0xB0: /* EOI */
-        DPRINTF("EOI\n");
-        s_IRQ = IRQ_get_next(opp, &dst->servicing);
-
-        if (s_IRQ < 0) {
-            DPRINTF("%s: EOI with no interrupt in service\n", __func__);
-            break;
-        }
-
-        IRQ_resetbit(&dst->servicing, s_IRQ);
-        /* Set up next servicing IRQ */
-        s_IRQ = IRQ_get_next(opp, &dst->servicing);
-        /* Check queued interrupts. */
-        n_IRQ = IRQ_get_next(opp, &dst->raised);
-        src = &opp->src[n_IRQ];
-        if (n_IRQ != -1 &&
-            (s_IRQ == -1 ||
-             IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) {
-            DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
-                    idx, n_IRQ);
-            qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]);
-        }
-        break;
-    default:
-        break;
-    }
-}
-
-static void openpic_cpu_write(void *opaque, hwaddr addr, uint64_t val,
-                              unsigned len)
-{
-    openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12);
-}
-
-
-static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu)
-{
-    IRQSource *src;
-    int retval, irq;
-
-    DPRINTF("Lower OpenPIC INT output\n");
-    qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
-
-    irq = IRQ_get_next(opp, &dst->raised);
-    DPRINTF("IACK: irq=%d\n", irq);
-
-    if (irq == -1) {
-        /* No more interrupt pending */
-        return opp->spve;
-    }
-
-    src = &opp->src[irq];
-    if (!(src->ivpr & IVPR_ACTIVITY_MASK) ||
-            !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) {
-        fprintf(stderr, "%s: bad raised IRQ %d ctpr %d ivpr 0x%08x\n",
-                __func__, irq, dst->ctpr, src->ivpr);
-        openpic_update_irq(opp, irq);
-        retval = opp->spve;
-    } else {
-        /* IRQ enter servicing state */
-        IRQ_setbit(&dst->servicing, irq);
-        retval = IVPR_VECTOR(opp, src->ivpr);
-    }
-
-    if (!src->level) {
-        /* edge-sensitive IRQ */
-        src->ivpr &= ~IVPR_ACTIVITY_MASK;
-        src->pending = 0;
-        IRQ_resetbit(&dst->raised, irq);
-    }
-
-    if ((irq >= opp->irq_ipi0) &&  (irq < (opp->irq_ipi0 + MAX_IPI))) {
-        src->destmask &= ~(1 << cpu);
-        if (src->destmask && !src->level) {
-            /* trigger on CPUs that didn't know about it yet */
-            openpic_set_irq(opp, irq, 1);
-            openpic_set_irq(opp, irq, 0);
-            /* if all CPUs knew about it, set active bit again */
-            src->ivpr |= IVPR_ACTIVITY_MASK;
-        }
-    }
-
-    return retval;
-}
-
-static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
-                                          int idx)
-{
-    OpenPICState *opp = opaque;
-    IRQDest *dst;
-    uint32_t retval;
-
-    DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx "\n", __func__, idx, addr);
-    retval = 0xFFFFFFFF;
-
-    if (idx < 0) {
-        return retval;
-    }
-
-    if (addr & 0xF) {
-        return retval;
-    }
-    dst = &opp->dst[idx];
-    addr &= 0xFF0;
-    switch (addr) {
-    case 0x80: /* CTPR */
-        retval = dst->ctpr;
-        break;
-    case 0x90: /* WHOAMI */
-        retval = idx;
-        break;
-    case 0xA0: /* IACK */
-        retval = openpic_iack(opp, dst, idx);
-        break;
-    case 0xB0: /* EOI */
-        retval = 0;
-        break;
-    default:
-        break;
-    }
-    DPRINTF("%s: => 0x%08x\n", __func__, retval);
-
-    return retval;
-}
-
-static uint64_t openpic_cpu_read(void *opaque, hwaddr addr, unsigned len)
-{
-    return openpic_cpu_read_internal(opaque, addr, (addr & 0x1f000) >> 12);
-}
-
-static const MemoryRegionOps openpic_glb_ops_le = {
-    .write = openpic_gbl_write,
-    .read  = openpic_gbl_read,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const MemoryRegionOps openpic_glb_ops_be = {
-    .write = openpic_gbl_write,
-    .read  = openpic_gbl_read,
-    .endianness = DEVICE_BIG_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const MemoryRegionOps openpic_tmr_ops_le = {
-    .write = openpic_tmr_write,
-    .read  = openpic_tmr_read,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const MemoryRegionOps openpic_tmr_ops_be = {
-    .write = openpic_tmr_write,
-    .read  = openpic_tmr_read,
-    .endianness = DEVICE_BIG_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const MemoryRegionOps openpic_cpu_ops_le = {
-    .write = openpic_cpu_write,
-    .read  = openpic_cpu_read,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const MemoryRegionOps openpic_cpu_ops_be = {
-    .write = openpic_cpu_write,
-    .read  = openpic_cpu_read,
-    .endianness = DEVICE_BIG_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const MemoryRegionOps openpic_src_ops_le = {
-    .write = openpic_src_write,
-    .read  = openpic_src_read,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const MemoryRegionOps openpic_src_ops_be = {
-    .write = openpic_src_write,
-    .read  = openpic_src_read,
-    .endianness = DEVICE_BIG_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const MemoryRegionOps openpic_msi_ops_be = {
-    .read = openpic_msi_read,
-    .write = openpic_msi_write,
-    .endianness = DEVICE_BIG_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const MemoryRegionOps openpic_summary_ops_be = {
-    .read = openpic_summary_read,
-    .write = openpic_summary_write,
-    .endianness = DEVICE_BIG_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static void openpic_save_IRQ_queue(QEMUFile* f, IRQQueue *q)
-{
-    unsigned int i;
-
-    for (i = 0; i < ARRAY_SIZE(q->queue); i++) {
-        /* Always put the lower half of a 64-bit long first, in case we
-         * restore on a 32-bit host.  The least significant bits correspond
-         * to lower IRQ numbers in the bitmap.
-         */
-        qemu_put_be32(f, (uint32_t)q->queue[i]);
-#if LONG_MAX > 0x7FFFFFFF
-        qemu_put_be32(f, (uint32_t)(q->queue[i] >> 32));
-#endif
-    }
-
-    qemu_put_sbe32s(f, &q->next);
-    qemu_put_sbe32s(f, &q->priority);
-}
-
-static void openpic_save(QEMUFile* f, void *opaque)
-{
-    OpenPICState *opp = (OpenPICState *)opaque;
-    unsigned int i;
-
-    qemu_put_be32s(f, &opp->gcr);
-    qemu_put_be32s(f, &opp->vir);
-    qemu_put_be32s(f, &opp->pir);
-    qemu_put_be32s(f, &opp->spve);
-    qemu_put_be32s(f, &opp->tfrr);
-
-    qemu_put_be32s(f, &opp->nb_cpus);
-
-    for (i = 0; i < opp->nb_cpus; i++) {
-        qemu_put_sbe32s(f, &opp->dst[i].ctpr);
-        openpic_save_IRQ_queue(f, &opp->dst[i].raised);
-        openpic_save_IRQ_queue(f, &opp->dst[i].servicing);
-        qemu_put_buffer(f, (uint8_t *)&opp->dst[i].outputs_active,
-                        sizeof(opp->dst[i].outputs_active));
-    }
-
-    for (i = 0; i < MAX_TMR; i++) {
-        qemu_put_be32s(f, &opp->timers[i].tccr);
-        qemu_put_be32s(f, &opp->timers[i].tbcr);
-    }
-
-    for (i = 0; i < opp->max_irq; i++) {
-        qemu_put_be32s(f, &opp->src[i].ivpr);
-        qemu_put_be32s(f, &opp->src[i].idr);
-        qemu_get_be32s(f, &opp->src[i].destmask);
-        qemu_put_sbe32s(f, &opp->src[i].last_cpu);
-        qemu_put_sbe32s(f, &opp->src[i].pending);
-    }
-}
-
-static void openpic_load_IRQ_queue(QEMUFile* f, IRQQueue *q)
-{
-    unsigned int i;
-
-    for (i = 0; i < ARRAY_SIZE(q->queue); i++) {
-        unsigned long val;
-
-        val = qemu_get_be32(f);
-#if LONG_MAX > 0x7FFFFFFF
-        val <<= 32;
-        val |= qemu_get_be32(f);
-#endif
-
-        q->queue[i] = val;
-    }
-
-    qemu_get_sbe32s(f, &q->next);
-    qemu_get_sbe32s(f, &q->priority);
-}
-
-static int openpic_load(QEMUFile* f, void *opaque, int version_id)
-{
-    OpenPICState *opp = (OpenPICState *)opaque;
-    unsigned int i;
-
-    if (version_id != 1) {
-        return -EINVAL;
-    }
-
-    qemu_get_be32s(f, &opp->gcr);
-    qemu_get_be32s(f, &opp->vir);
-    qemu_get_be32s(f, &opp->pir);
-    qemu_get_be32s(f, &opp->spve);
-    qemu_get_be32s(f, &opp->tfrr);
-
-    qemu_get_be32s(f, &opp->nb_cpus);
-
-    for (i = 0; i < opp->nb_cpus; i++) {
-        qemu_get_sbe32s(f, &opp->dst[i].ctpr);
-        openpic_load_IRQ_queue(f, &opp->dst[i].raised);
-        openpic_load_IRQ_queue(f, &opp->dst[i].servicing);
-        qemu_get_buffer(f, (uint8_t *)&opp->dst[i].outputs_active,
-                        sizeof(opp->dst[i].outputs_active));
-    }
-
-    for (i = 0; i < MAX_TMR; i++) {
-        qemu_get_be32s(f, &opp->timers[i].tccr);
-        qemu_get_be32s(f, &opp->timers[i].tbcr);
-    }
-
-    for (i = 0; i < opp->max_irq; i++) {
-        uint32_t val;
-
-        val = qemu_get_be32(f);
-        write_IRQreg_idr(opp, i, val);
-        val = qemu_get_be32(f);
-        write_IRQreg_ivpr(opp, i, val);
-
-        qemu_get_be32s(f, &opp->src[i].ivpr);
-        qemu_get_be32s(f, &opp->src[i].idr);
-        qemu_get_be32s(f, &opp->src[i].destmask);
-        qemu_get_sbe32s(f, &opp->src[i].last_cpu);
-        qemu_get_sbe32s(f, &opp->src[i].pending);
-    }
-
-    return 0;
-}
-
-typedef struct MemReg {
-    const char             *name;
-    MemoryRegionOps const  *ops;
-    hwaddr      start_addr;
-    ram_addr_t              size;
-} MemReg;
-
-static void fsl_common_init(OpenPICState *opp)
-{
-    int i;
-    int virq = MAX_SRC;
-
-    opp->vid = VID_REVISION_1_2;
-    opp->vir = VIR_GENERIC;
-    opp->vector_mask = 0xFFFF;
-    opp->tfrr_reset = 0;
-    opp->ivpr_reset = IVPR_MASK_MASK;
-    opp->idr_reset = 1 << 0;
-    opp->max_irq = MAX_IRQ;
-
-    opp->irq_ipi0 = virq;
-    virq += MAX_IPI;
-    opp->irq_tim0 = virq;
-    virq += MAX_TMR;
-
-    assert(virq <= MAX_IRQ);
-
-    opp->irq_msi = 224;
-
-    msi_supported = true;
-    for (i = 0; i < opp->fsl->max_ext; i++) {
-        opp->src[i].level = false;
-    }
-
-    /* Internal interrupts, including message and MSI */
-    for (i = 16; i < MAX_SRC; i++) {
-        opp->src[i].type = IRQ_TYPE_FSLINT;
-        opp->src[i].level = true;
-    }
-
-    /* timers and IPIs */
-    for (i = MAX_SRC; i < virq; i++) {
-        opp->src[i].type = IRQ_TYPE_FSLSPECIAL;
-        opp->src[i].level = false;
-    }
-}
-
-static void map_list(OpenPICState *opp, const MemReg *list, int *count)
-{
-    while (list->name) {
-        assert(*count < ARRAY_SIZE(opp->sub_io_mem));
-
-        memory_region_init_io(&opp->sub_io_mem[*count], list->ops, opp,
-                              list->name, list->size);
-
-        memory_region_add_subregion(&opp->mem, list->start_addr,
-                                    &opp->sub_io_mem[*count]);
-
-        (*count)++;
-        list++;
-    }
-}
-
-static int openpic_init(SysBusDevice *dev)
-{
-    OpenPICState *opp = FROM_SYSBUS(typeof (*opp), dev);
-    int i, j;
-    int list_count = 0;
-    static const MemReg list_le[] = {
-        {"glb", &openpic_glb_ops_le,
-                OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE},
-        {"tmr", &openpic_tmr_ops_le,
-                OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE},
-        {"src", &openpic_src_ops_le,
-                OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE},
-        {"cpu", &openpic_cpu_ops_le,
-                OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE},
-        {NULL}
-    };
-    static const MemReg list_be[] = {
-        {"glb", &openpic_glb_ops_be,
-                OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE},
-        {"tmr", &openpic_tmr_ops_be,
-                OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE},
-        {"src", &openpic_src_ops_be,
-                OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE},
-        {"cpu", &openpic_cpu_ops_be,
-                OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE},
-        {NULL}
-    };
-    static const MemReg list_fsl[] = {
-        {"msi", &openpic_msi_ops_be,
-                OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE},
-        {"summary", &openpic_summary_ops_be,
-                OPENPIC_SUMMARY_REG_START, OPENPIC_SUMMARY_REG_SIZE},
-        {NULL}
-    };
-
-    memory_region_init(&opp->mem, "openpic", 0x40000);
-
-    switch (opp->model) {
-    case OPENPIC_MODEL_FSL_MPIC_20:
-    default:
-        opp->fsl = &fsl_mpic_20;
-        opp->brr1 = 0x00400200;
-        opp->flags |= OPENPIC_FLAG_IDR_CRIT;
-        opp->nb_irqs = 80;
-        opp->mpic_mode_mask = GCR_MODE_MIXED;
-
-        fsl_common_init(opp);
-        map_list(opp, list_be, &list_count);
-        map_list(opp, list_fsl, &list_count);
-
-        break;
-
-    case OPENPIC_MODEL_FSL_MPIC_42:
-        opp->fsl = &fsl_mpic_42;
-        opp->brr1 = 0x00400402;
-        opp->flags |= OPENPIC_FLAG_ILR;
-        opp->nb_irqs = 196;
-        opp->mpic_mode_mask = GCR_MODE_PROXY;
-
-        fsl_common_init(opp);
-        map_list(opp, list_be, &list_count);
-        map_list(opp, list_fsl, &list_count);
-
-        break;
-
-    case OPENPIC_MODEL_RAVEN:
-        opp->nb_irqs = RAVEN_MAX_EXT;
-        opp->vid = VID_REVISION_1_3;
-        opp->vir = VIR_GENERIC;
-        opp->vector_mask = 0xFF;
-        opp->tfrr_reset = 4160000;
-        opp->ivpr_reset = IVPR_MASK_MASK | IVPR_MODE_MASK;
-        opp->idr_reset = 0;
-        opp->max_irq = RAVEN_MAX_IRQ;
-        opp->irq_ipi0 = RAVEN_IPI_IRQ;
-        opp->irq_tim0 = RAVEN_TMR_IRQ;
-        opp->brr1 = -1;
-        opp->mpic_mode_mask = GCR_MODE_MIXED;
-
-        /* Only UP supported today */
-        if (opp->nb_cpus != 1) {
-            return -EINVAL;
-        }
-
-        map_list(opp, list_le, &list_count);
-        break;
-    }
-
-    for (i = 0; i < opp->nb_cpus; i++) {
-        opp->dst[i].irqs = g_new(qemu_irq, OPENPIC_OUTPUT_NB);
-        for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
-            sysbus_init_irq(dev, &opp->dst[i].irqs[j]);
-        }
-    }
-
-    register_savevm(&opp->busdev.qdev, "openpic", 0, 2,
-                    openpic_save, openpic_load, opp);
-
-    sysbus_init_mmio(dev, &opp->mem);
-    qdev_init_gpio_in(&dev->qdev, openpic_set_irq, opp->max_irq);
-
-    return 0;
-}
-
-static Property openpic_properties[] = {
-    DEFINE_PROP_UINT32("model", OpenPICState, model, OPENPIC_MODEL_FSL_MPIC_20),
-    DEFINE_PROP_UINT32("nb_cpus", OpenPICState, nb_cpus, 1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void openpic_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = openpic_init;
-    dc->props = openpic_properties;
-    dc->reset = openpic_reset;
-}
-
-static const TypeInfo openpic_info = {
-    .name          = "openpic",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(OpenPICState),
-    .class_init    = openpic_class_init,
-};
-
-static void openpic_register_types(void)
-{
-    type_register_static(&openpic_info);
-}
-
-type_init(openpic_register_types)
index 70342c28ec5929ffde10e3c5ad6c488701fa693f..280ed266e07f91e40c9078b8f1a0486fc6b29d05 100644 (file)
@@ -1,7 +1,5 @@
 # IBM pSeries (sPAPR)
 obj-$(CONFIG_PSERIES) += spapr_nvram.o
-# PowerPC OpenPIC
-obj-y += openpic.o
 
 obj-y := $(addprefix ../,$(obj-y))
 
diff --git a/hw/realview_gic.c b/hw/realview_gic.c
deleted file mode 100644 (file)
index 0ec30ca..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * ARM RealView Emulation Baseboard Interrupt Controller
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/sysbus.h"
-
-typedef struct {
-    SysBusDevice busdev;
-    DeviceState *gic;
-    MemoryRegion container;
-} RealViewGICState;
-
-static void realview_gic_set_irq(void *opaque, int irq, int level)
-{
-    RealViewGICState *s = (RealViewGICState *)opaque;
-    qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
-}
-
-static int realview_gic_init(SysBusDevice *dev)
-{
-    RealViewGICState *s = FROM_SYSBUS(RealViewGICState, dev);
-    SysBusDevice *busdev;
-    /* The GICs on the RealView boards have a fixed nonconfigurable
-     * number of interrupt lines, so we don't need to expose this as
-     * a qdev property.
-     */
-    int numirq = 96;
-
-    s->gic = qdev_create(NULL, "arm_gic");
-    qdev_prop_set_uint32(s->gic, "num-cpu", 1);
-    qdev_prop_set_uint32(s->gic, "num-irq", numirq);
-    qdev_init_nofail(s->gic);
-    busdev = SYS_BUS_DEVICE(s->gic);
-
-    /* Pass through outbound IRQ lines from the GIC */
-    sysbus_pass_irq(dev, busdev);
-
-    /* Pass through inbound GPIO lines to the GIC */
-    qdev_init_gpio_in(&s->busdev.qdev, realview_gic_set_irq, numirq - 32);
-
-    memory_region_init(&s->container, "realview-gic-container", 0x2000);
-    memory_region_add_subregion(&s->container, 0,
-                                sysbus_mmio_get_region(busdev, 1));
-    memory_region_add_subregion(&s->container, 0x1000,
-                                sysbus_mmio_get_region(busdev, 0));
-    sysbus_init_mmio(dev, &s->container);
-    return 0;
-}
-
-static void realview_gic_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = realview_gic_init;
-}
-
-static const TypeInfo realview_gic_info = {
-    .name          = "realview_gic",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(RealViewGICState),
-    .class_init    = realview_gic_class_init,
-};
-
-static void realview_gic_register_types(void)
-{
-    type_register_static(&realview_gic_info);
-}
-
-type_init(realview_gic_register_types)
diff --git a/hw/sbi.c b/hw/sbi.c
deleted file mode 100644 (file)
index 8795749..0000000
--- a/hw/sbi.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * QEMU Sparc SBI interrupt controller emulation
- *
- * Based on slavio_intctl, copyright (c) 2003-2005 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/sysbus.h"
-
-//#define DEBUG_IRQ
-
-#ifdef DEBUG_IRQ
-#define DPRINTF(fmt, ...)                                       \
-    do { printf("IRQ: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-#define MAX_CPUS 16
-
-#define SBI_NREGS 16
-
-typedef struct SBIState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t regs[SBI_NREGS];
-    uint32_t intreg_pending[MAX_CPUS];
-    qemu_irq cpu_irqs[MAX_CPUS];
-    uint32_t pil_out[MAX_CPUS];
-} SBIState;
-
-#define SBI_SIZE (SBI_NREGS * 4)
-
-static void sbi_set_irq(void *opaque, int irq, int level)
-{
-}
-
-static uint64_t sbi_mem_read(void *opaque, hwaddr addr,
-                             unsigned size)
-{
-    SBIState *s = opaque;
-    uint32_t saddr, ret;
-
-    saddr = addr >> 2;
-    switch (saddr) {
-    default:
-        ret = s->regs[saddr];
-        break;
-    }
-    DPRINTF("read system reg 0x" TARGET_FMT_plx " = %x\n", addr, ret);
-
-    return ret;
-}
-
-static void sbi_mem_write(void *opaque, hwaddr addr,
-                          uint64_t val, unsigned dize)
-{
-    SBIState *s = opaque;
-    uint32_t saddr;
-
-    saddr = addr >> 2;
-    DPRINTF("write system reg 0x" TARGET_FMT_plx " = %x\n", addr, (int)val);
-    switch (saddr) {
-    default:
-        s->regs[saddr] = val;
-        break;
-    }
-}
-
-static const MemoryRegionOps sbi_mem_ops = {
-    .read = sbi_mem_read,
-    .write = sbi_mem_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const VMStateDescription vmstate_sbi = {
-    .name ="sbi",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT32_ARRAY(intreg_pending, SBIState, MAX_CPUS),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void sbi_reset(DeviceState *d)
-{
-    SBIState *s = container_of(d, SBIState, busdev.qdev);
-    unsigned int i;
-
-    for (i = 0; i < MAX_CPUS; i++) {
-        s->intreg_pending[i] = 0;
-    }
-}
-
-static int sbi_init1(SysBusDevice *dev)
-{
-    SBIState *s = FROM_SYSBUS(SBIState, dev);
-    unsigned int i;
-
-    qdev_init_gpio_in(&dev->qdev, sbi_set_irq, 32 + MAX_CPUS);
-    for (i = 0; i < MAX_CPUS; i++) {
-        sysbus_init_irq(dev, &s->cpu_irqs[i]);
-    }
-
-    memory_region_init_io(&s->iomem, &sbi_mem_ops, s, "sbi", SBI_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static void sbi_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = sbi_init1;
-    dc->reset = sbi_reset;
-    dc->vmsd = &vmstate_sbi;
-}
-
-static const TypeInfo sbi_info = {
-    .name          = "sbi",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SBIState),
-    .class_init    = sbi_class_init,
-};
-
-static void sbi_register_types(void)
-{
-    type_register_static(&sbi_info);
-}
-
-type_init(sbi_register_types)
index 0387b96b4bef9d1d1781d61477d41a968453ecf1..2393702c5768d628236daf65a5be2cfb5de79d27 100644 (file)
@@ -1,7 +1,3 @@
-obj-y += sh_intc.o
-
-obj-y := $(addprefix ../,$(obj-y))
-
 obj-y += shix.o r2d.o
 
 obj-y += sh7750.o sh7750_regnames.o
diff --git a/hw/sh_intc.c b/hw/sh_intc.c
deleted file mode 100644 (file)
index 050bfb6..0000000
+++ /dev/null
@@ -1,513 +0,0 @@
-/*
- * SuperH interrupt controller module
- *
- * Copyright (c) 2007 Magnus Damm
- * Based on sh_timer.c and arm_timer.c by Paul Brook
- * Copyright (c) 2005-2006 CodeSourcery.
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/sh4/sh_intc.h"
-#include "hw/hw.h"
-#include "hw/sh4/sh.h"
-
-//#define DEBUG_INTC
-//#define DEBUG_INTC_SOURCES
-
-#define INTC_A7(x) ((x) & 0x1fffffff)
-
-void sh_intc_toggle_source(struct intc_source *source,
-                          int enable_adj, int assert_adj)
-{
-    int enable_changed = 0;
-    int pending_changed = 0;
-    int old_pending;
-
-    if ((source->enable_count == source->enable_max) && (enable_adj == -1))
-        enable_changed = -1;
-
-    source->enable_count += enable_adj;
-
-    if (source->enable_count == source->enable_max)
-        enable_changed = 1;
-
-    source->asserted += assert_adj;
-
-    old_pending = source->pending;
-    source->pending = source->asserted &&
-      (source->enable_count == source->enable_max);
-
-    if (old_pending != source->pending)
-        pending_changed = 1;
-
-    if (pending_changed) {
-        CPUState *cpu = CPU(sh_env_get_cpu(first_cpu));
-        if (source->pending) {
-            source->parent->pending++;
-            if (source->parent->pending == 1) {
-                cpu_interrupt(cpu, CPU_INTERRUPT_HARD);
-            }
-        } else {
-            source->parent->pending--;
-            if (source->parent->pending == 0) {
-                cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD);
-            }
-       }
-    }
-
-  if (enable_changed || assert_adj || pending_changed) {
-#ifdef DEBUG_INTC_SOURCES
-            printf("sh_intc: (%d/%d/%d/%d) interrupt source 0x%x %s%s%s\n",
-                  source->parent->pending,
-                  source->asserted,
-                  source->enable_count,
-                  source->enable_max,
-                  source->vect,
-                  source->asserted ? "asserted " :
-                  assert_adj ? "deasserted" : "",
-                  enable_changed == 1 ? "enabled " :
-                  enable_changed == -1 ? "disabled " : "",
-                  source->pending ? "pending" : "");
-#endif
-  }
-}
-
-static void sh_intc_set_irq (void *opaque, int n, int level)
-{
-  struct intc_desc *desc = opaque;
-  struct intc_source *source = &(desc->sources[n]);
-
-  if (level && !source->asserted)
-    sh_intc_toggle_source(source, 0, 1);
-  else if (!level && source->asserted)
-    sh_intc_toggle_source(source, 0, -1);
-}
-
-int sh_intc_get_pending_vector(struct intc_desc *desc, int imask)
-{
-    unsigned int i;
-
-    /* slow: use a linked lists of pending sources instead */
-    /* wrong: take interrupt priority into account (one list per priority) */
-
-    if (imask == 0x0f) {
-        return -1; /* FIXME, update code to include priority per source */
-    }
-
-    for (i = 0; i < desc->nr_sources; i++) {
-        struct intc_source *source = desc->sources + i;
-
-       if (source->pending) {
-#ifdef DEBUG_INTC_SOURCES
-            printf("sh_intc: (%d) returning interrupt source 0x%x\n",
-                  desc->pending, source->vect);
-#endif
-            return source->vect;
-       }
-    }
-
-    abort();
-}
-
-#define INTC_MODE_NONE       0
-#define INTC_MODE_DUAL_SET   1
-#define INTC_MODE_DUAL_CLR   2
-#define INTC_MODE_ENABLE_REG 3
-#define INTC_MODE_MASK_REG   4
-#define INTC_MODE_IS_PRIO    8
-
-static unsigned int sh_intc_mode(unsigned long address,
-                                unsigned long set_reg, unsigned long clr_reg)
-{
-    if ((address != INTC_A7(set_reg)) &&
-       (address != INTC_A7(clr_reg)))
-        return INTC_MODE_NONE;
-
-    if (set_reg && clr_reg) {
-        if (address == INTC_A7(set_reg))
-            return INTC_MODE_DUAL_SET;
-       else
-            return INTC_MODE_DUAL_CLR;
-    }
-
-    if (set_reg)
-        return INTC_MODE_ENABLE_REG;
-    else
-        return INTC_MODE_MASK_REG;
-}
-
-static void sh_intc_locate(struct intc_desc *desc,
-                          unsigned long address,
-                          unsigned long **datap,
-                          intc_enum **enums,
-                          unsigned int *first,
-                          unsigned int *width,
-                          unsigned int *modep)
-{
-    unsigned int i, mode;
-
-    /* this is slow but works for now */
-
-    if (desc->mask_regs) {
-        for (i = 0; i < desc->nr_mask_regs; i++) {
-           struct intc_mask_reg *mr = desc->mask_regs + i;
-
-           mode = sh_intc_mode(address, mr->set_reg, mr->clr_reg);
-           if (mode == INTC_MODE_NONE)
-                continue;
-
-           *modep = mode;
-           *datap = &mr->value;
-           *enums = mr->enum_ids;
-           *first = mr->reg_width - 1;
-           *width = 1;
-           return;
-       }
-    }
-
-    if (desc->prio_regs) {
-        for (i = 0; i < desc->nr_prio_regs; i++) {
-           struct intc_prio_reg *pr = desc->prio_regs + i;
-
-           mode = sh_intc_mode(address, pr->set_reg, pr->clr_reg);
-           if (mode == INTC_MODE_NONE)
-                continue;
-
-           *modep = mode | INTC_MODE_IS_PRIO;
-           *datap = &pr->value;
-           *enums = pr->enum_ids;
-           *first = (pr->reg_width / pr->field_width) - 1;
-           *width = pr->field_width;
-           return;
-       }
-    }
-
-    abort();
-}
-
-static void sh_intc_toggle_mask(struct intc_desc *desc, intc_enum id,
-                               int enable, int is_group)
-{
-    struct intc_source *source = desc->sources + id;
-
-    if (!id)
-       return;
-
-    if (!source->next_enum_id && (!source->enable_max || !source->vect)) {
-#ifdef DEBUG_INTC_SOURCES
-        printf("sh_intc: reserved interrupt source %d modified\n", id);
-#endif
-       return;
-    }
-
-    if (source->vect)
-        sh_intc_toggle_source(source, enable ? 1 : -1, 0);
-
-#ifdef DEBUG_INTC
-    else {
-        printf("setting interrupt group %d to %d\n", id, !!enable);
-    }
-#endif
-
-    if ((is_group || !source->vect) && source->next_enum_id) {
-        sh_intc_toggle_mask(desc, source->next_enum_id, enable, 1);
-    }
-
-#ifdef DEBUG_INTC
-    if (!source->vect) {
-        printf("setting interrupt group %d to %d - done\n", id, !!enable);
-    }
-#endif
-}
-
-static uint64_t sh_intc_read(void *opaque, hwaddr offset,
-                             unsigned size)
-{
-    struct intc_desc *desc = opaque;
-    intc_enum *enum_ids = NULL;
-    unsigned int first = 0;
-    unsigned int width = 0;
-    unsigned int mode = 0;
-    unsigned long *valuep;
-
-#ifdef DEBUG_INTC
-    printf("sh_intc_read 0x%lx\n", (unsigned long) offset);
-#endif
-
-    sh_intc_locate(desc, (unsigned long)offset, &valuep, 
-                  &enum_ids, &first, &width, &mode);
-    return *valuep;
-}
-
-static void sh_intc_write(void *opaque, hwaddr offset,
-                          uint64_t value, unsigned size)
-{
-    struct intc_desc *desc = opaque;
-    intc_enum *enum_ids = NULL;
-    unsigned int first = 0;
-    unsigned int width = 0;
-    unsigned int mode = 0;
-    unsigned int k;
-    unsigned long *valuep;
-    unsigned long mask;
-
-#ifdef DEBUG_INTC
-    printf("sh_intc_write 0x%lx 0x%08x\n", (unsigned long) offset, value);
-#endif
-
-    sh_intc_locate(desc, (unsigned long)offset, &valuep, 
-                  &enum_ids, &first, &width, &mode);
-
-    switch (mode) {
-    case INTC_MODE_ENABLE_REG | INTC_MODE_IS_PRIO: break;
-    case INTC_MODE_DUAL_SET: value |= *valuep; break;
-    case INTC_MODE_DUAL_CLR: value = *valuep & ~value; break;
-    default: abort();
-    }
-
-    for (k = 0; k <= first; k++) {
-        mask = ((1 << width) - 1) << ((first - k) * width);
-
-       if ((*valuep & mask) == (value & mask))
-            continue;
-#if 0
-       printf("k = %d, first = %d, enum = %d, mask = 0x%08x\n", 
-              k, first, enum_ids[k], (unsigned int)mask);
-#endif
-        sh_intc_toggle_mask(desc, enum_ids[k], value & mask, 0);
-    }
-
-    *valuep = value;
-
-#ifdef DEBUG_INTC
-    printf("sh_intc_write 0x%lx -> 0x%08x\n", (unsigned long) offset, value);
-#endif
-}
-
-static const MemoryRegionOps sh_intc_ops = {
-    .read = sh_intc_read,
-    .write = sh_intc_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct intc_source *sh_intc_source(struct intc_desc *desc, intc_enum id)
-{
-    if (id)
-        return desc->sources + id;
-
-    return NULL;
-}
-
-static unsigned int sh_intc_register(MemoryRegion *sysmem,
-                             struct intc_desc *desc,
-                             const unsigned long address,
-                             const char *type,
-                             const char *action,
-                             const unsigned int index)
-{
-    char name[60];
-    MemoryRegion *iomem, *iomem_p4, *iomem_a7;
-
-    if (!address) {
-        return 0;
-    }
-
-    iomem = &desc->iomem;
-    iomem_p4 = desc->iomem_aliases + index;
-    iomem_a7 = iomem_p4 + 1;
-
-#define SH_INTC_IOMEM_FORMAT "interrupt-controller-%s-%s-%s"
-    snprintf(name, sizeof(name), SH_INTC_IOMEM_FORMAT, type, action, "p4");
-    memory_region_init_alias(iomem_p4, name, iomem, INTC_A7(address), 4);
-    memory_region_add_subregion(sysmem, P4ADDR(address), iomem_p4);
-
-    snprintf(name, sizeof(name), SH_INTC_IOMEM_FORMAT, type, action, "a7");
-    memory_region_init_alias(iomem_a7, name, iomem, INTC_A7(address), 4);
-    memory_region_add_subregion(sysmem, A7ADDR(address), iomem_a7);
-#undef SH_INTC_IOMEM_FORMAT
-
-    /* used to increment aliases index */
-    return 2;
-}
-
-static void sh_intc_register_source(struct intc_desc *desc,
-                                   intc_enum source,
-                                   struct intc_group *groups,
-                                   int nr_groups)
-{
-    unsigned int i, k;
-    struct intc_source *s;
-
-    if (desc->mask_regs) {
-        for (i = 0; i < desc->nr_mask_regs; i++) {
-           struct intc_mask_reg *mr = desc->mask_regs + i;
-
-           for (k = 0; k < ARRAY_SIZE(mr->enum_ids); k++) {
-                if (mr->enum_ids[k] != source)
-                    continue;
-
-               s = sh_intc_source(desc, mr->enum_ids[k]);
-               if (s)
-                    s->enable_max++;
-           }
-       }
-    }
-
-    if (desc->prio_regs) {
-        for (i = 0; i < desc->nr_prio_regs; i++) {
-           struct intc_prio_reg *pr = desc->prio_regs + i;
-
-           for (k = 0; k < ARRAY_SIZE(pr->enum_ids); k++) {
-                if (pr->enum_ids[k] != source)
-                    continue;
-
-               s = sh_intc_source(desc, pr->enum_ids[k]);
-               if (s)
-                    s->enable_max++;
-           }
-       }
-    }
-
-    if (groups) {
-        for (i = 0; i < nr_groups; i++) {
-           struct intc_group *gr = groups + i;
-
-           for (k = 0; k < ARRAY_SIZE(gr->enum_ids); k++) {
-                if (gr->enum_ids[k] != source)
-                    continue;
-
-               s = sh_intc_source(desc, gr->enum_ids[k]);
-               if (s)
-                    s->enable_max++;
-           }
-       }
-    }
-
-}
-
-void sh_intc_register_sources(struct intc_desc *desc,
-                             struct intc_vect *vectors,
-                             int nr_vectors,
-                             struct intc_group *groups,
-                             int nr_groups)
-{
-    unsigned int i, k;
-    struct intc_source *s;
-
-    for (i = 0; i < nr_vectors; i++) {
-       struct intc_vect *vect = vectors + i;
-
-       sh_intc_register_source(desc, vect->enum_id, groups, nr_groups);
-       s = sh_intc_source(desc, vect->enum_id);
-        if (s) {
-            s->vect = vect->vect;
-
-#ifdef DEBUG_INTC_SOURCES
-            printf("sh_intc: registered source %d -> 0x%04x (%d/%d)\n",
-                   vect->enum_id, s->vect, s->enable_count, s->enable_max);
-#endif
-        }
-    }
-
-    if (groups) {
-        for (i = 0; i < nr_groups; i++) {
-           struct intc_group *gr = groups + i;
-
-           s = sh_intc_source(desc, gr->enum_id);
-           s->next_enum_id = gr->enum_ids[0];
-
-           for (k = 1; k < ARRAY_SIZE(gr->enum_ids); k++) {
-                if (!gr->enum_ids[k])
-                    continue;
-
-               s = sh_intc_source(desc, gr->enum_ids[k - 1]);
-               s->next_enum_id = gr->enum_ids[k];
-           }
-
-#ifdef DEBUG_INTC_SOURCES
-           printf("sh_intc: registered group %d (%d/%d)\n",
-                  gr->enum_id, s->enable_count, s->enable_max);
-#endif
-       }
-    }
-}
-
-int sh_intc_init(MemoryRegion *sysmem,
-         struct intc_desc *desc,
-                int nr_sources,
-                struct intc_mask_reg *mask_regs,
-                int nr_mask_regs,
-                struct intc_prio_reg *prio_regs,
-                int nr_prio_regs)
-{
-    unsigned int i, j;
-
-    desc->pending = 0;
-    desc->nr_sources = nr_sources;
-    desc->mask_regs = mask_regs;
-    desc->nr_mask_regs = nr_mask_regs;
-    desc->prio_regs = prio_regs;
-    desc->nr_prio_regs = nr_prio_regs;
-    /* Allocate 4 MemoryRegions per register (2 actions * 2 aliases).
-     **/
-    desc->iomem_aliases = g_new0(MemoryRegion,
-                                 (nr_mask_regs + nr_prio_regs) * 4);
-
-    j = 0;
-    i = sizeof(struct intc_source) * nr_sources;
-    desc->sources = g_malloc0(i);
-
-    for (i = 0; i < desc->nr_sources; i++) {
-        struct intc_source *source = desc->sources + i;
-
-        source->parent = desc;
-    }
-
-    desc->irqs = qemu_allocate_irqs(sh_intc_set_irq, desc, nr_sources);
-    memory_region_init_io(&desc->iomem, &sh_intc_ops, desc,
-                          "interrupt-controller", 0x100000000ULL);
-
-#define INT_REG_PARAMS(reg_struct, type, action, j) \
-        reg_struct->action##_reg, #type, #action, j
-    if (desc->mask_regs) {
-        for (i = 0; i < desc->nr_mask_regs; i++) {
-           struct intc_mask_reg *mr = desc->mask_regs + i;
-
-            j += sh_intc_register(sysmem, desc,
-                                  INT_REG_PARAMS(mr, mask, set, j));
-            j += sh_intc_register(sysmem, desc,
-                                  INT_REG_PARAMS(mr, mask, clr, j));
-       }
-    }
-
-    if (desc->prio_regs) {
-        for (i = 0; i < desc->nr_prio_regs; i++) {
-           struct intc_prio_reg *pr = desc->prio_regs + i;
-
-            j += sh_intc_register(sysmem, desc,
-                                  INT_REG_PARAMS(pr, prio, set, j));
-            j += sh_intc_register(sysmem, desc,
-                                  INT_REG_PARAMS(pr, prio, clr, j));
-       }
-    }
-#undef INT_REG_PARAMS
-
-    return 0;
-}
-
-/* Assert level <n> IRL interrupt. 
-   0:deassert. 1:lowest priority,... 15:highest priority. */
-void sh_intc_set_irl(void *opaque, int n, int level)
-{
-    struct intc_source *s = opaque;
-    int i, irl = level ^ 15;
-    for (i = 0; (s = sh_intc_source(s->parent, s->next_enum_id)); i++) {
-       if (i == irl)
-           sh_intc_toggle_source(s, s->enable_count?0:1, s->asserted?0:1);
-       else
-           if (s->asserted)
-               sh_intc_toggle_source(s, 0, -1);
-    }
-}
diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c
deleted file mode 100644 (file)
index b367752..0000000
+++ /dev/null
@@ -1,471 +0,0 @@
-/*
- * QEMU Sparc SLAVIO interrupt controller emulation
- *
- * Copyright (c) 2003-2005 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/sparc/sun4m.h"
-#include "monitor/monitor.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-
-//#define DEBUG_IRQ_COUNT
-
-/*
- * Registers of interrupt controller in sun4m.
- *
- * This is the interrupt controller part of chip STP2001 (Slave I/O), also
- * produced as NCR89C105. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
- *
- * There is a system master controller and one for each cpu.
- *
- */
-
-#define MAX_CPUS 16
-#define MAX_PILS 16
-
-struct SLAVIO_INTCTLState;
-
-typedef struct SLAVIO_CPUINTCTLState {
-    MemoryRegion iomem;
-    struct SLAVIO_INTCTLState *master;
-    uint32_t intreg_pending;
-    uint32_t cpu;
-    uint32_t irl_out;
-} SLAVIO_CPUINTCTLState;
-
-typedef struct SLAVIO_INTCTLState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-#ifdef DEBUG_IRQ_COUNT
-    uint64_t irq_count[32];
-#endif
-    qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS];
-    SLAVIO_CPUINTCTLState slaves[MAX_CPUS];
-    uint32_t intregm_pending;
-    uint32_t intregm_disabled;
-    uint32_t target_cpu;
-} SLAVIO_INTCTLState;
-
-#define INTCTL_MAXADDR 0xf
-#define INTCTL_SIZE (INTCTL_MAXADDR + 1)
-#define INTCTLM_SIZE 0x14
-#define MASTER_IRQ_MASK ~0x0fa2007f
-#define MASTER_DISABLE 0x80000000
-#define CPU_SOFTIRQ_MASK 0xfffe0000
-#define CPU_IRQ_INT15_IN (1 << 15)
-#define CPU_IRQ_TIMER_IN (1 << 14)
-
-static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs);
-
-// per-cpu interrupt controller
-static uint64_t slavio_intctl_mem_readl(void *opaque, hwaddr addr,
-                                        unsigned size)
-{
-    SLAVIO_CPUINTCTLState *s = opaque;
-    uint32_t saddr, ret;
-
-    saddr = addr >> 2;
-    switch (saddr) {
-    case 0:
-        ret = s->intreg_pending;
-        break;
-    default:
-        ret = 0;
-        break;
-    }
-    trace_slavio_intctl_mem_readl(s->cpu, addr, ret);
-
-    return ret;
-}
-
-static void slavio_intctl_mem_writel(void *opaque, hwaddr addr,
-                                     uint64_t val, unsigned size)
-{
-    SLAVIO_CPUINTCTLState *s = opaque;
-    uint32_t saddr;
-
-    saddr = addr >> 2;
-    trace_slavio_intctl_mem_writel(s->cpu, addr, val);
-    switch (saddr) {
-    case 1: // clear pending softints
-        val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN;
-        s->intreg_pending &= ~val;
-        slavio_check_interrupts(s->master, 1);
-        trace_slavio_intctl_mem_writel_clear(s->cpu, val, s->intreg_pending);
-        break;
-    case 2: // set softint
-        val &= CPU_SOFTIRQ_MASK;
-        s->intreg_pending |= val;
-        slavio_check_interrupts(s->master, 1);
-        trace_slavio_intctl_mem_writel_set(s->cpu, val, s->intreg_pending);
-        break;
-    default:
-        break;
-    }
-}
-
-static const MemoryRegionOps slavio_intctl_mem_ops = {
-    .read = slavio_intctl_mem_readl,
-    .write = slavio_intctl_mem_writel,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-// master system interrupt controller
-static uint64_t slavio_intctlm_mem_readl(void *opaque, hwaddr addr,
-                                         unsigned size)
-{
-    SLAVIO_INTCTLState *s = opaque;
-    uint32_t saddr, ret;
-
-    saddr = addr >> 2;
-    switch (saddr) {
-    case 0:
-        ret = s->intregm_pending & ~MASTER_DISABLE;
-        break;
-    case 1:
-        ret = s->intregm_disabled & MASTER_IRQ_MASK;
-        break;
-    case 4:
-        ret = s->target_cpu;
-        break;
-    default:
-        ret = 0;
-        break;
-    }
-    trace_slavio_intctlm_mem_readl(addr, ret);
-
-    return ret;
-}
-
-static void slavio_intctlm_mem_writel(void *opaque, hwaddr addr,
-                                      uint64_t val, unsigned size)
-{
-    SLAVIO_INTCTLState *s = opaque;
-    uint32_t saddr;
-
-    saddr = addr >> 2;
-    trace_slavio_intctlm_mem_writel(addr, val);
-    switch (saddr) {
-    case 2: // clear (enable)
-        // Force clear unused bits
-        val &= MASTER_IRQ_MASK;
-        s->intregm_disabled &= ~val;
-        trace_slavio_intctlm_mem_writel_enable(val, s->intregm_disabled);
-        slavio_check_interrupts(s, 1);
-        break;
-    case 3: // set (disable; doesn't affect pending)
-        // Force clear unused bits
-        val &= MASTER_IRQ_MASK;
-        s->intregm_disabled |= val;
-        slavio_check_interrupts(s, 1);
-        trace_slavio_intctlm_mem_writel_disable(val, s->intregm_disabled);
-        break;
-    case 4:
-        s->target_cpu = val & (MAX_CPUS - 1);
-        slavio_check_interrupts(s, 1);
-        trace_slavio_intctlm_mem_writel_target(s->target_cpu);
-        break;
-    default:
-        break;
-    }
-}
-
-static const MemoryRegionOps slavio_intctlm_mem_ops = {
-    .read = slavio_intctlm_mem_readl,
-    .write = slavio_intctlm_mem_writel,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-void slavio_pic_info(Monitor *mon, DeviceState *dev)
-{
-    SysBusDevice *sd;
-    SLAVIO_INTCTLState *s;
-    int i;
-
-    sd = SYS_BUS_DEVICE(dev);
-    s = FROM_SYSBUS(SLAVIO_INTCTLState, sd);
-    for (i = 0; i < MAX_CPUS; i++) {
-        monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
-                       s->slaves[i].intreg_pending);
-    }
-    monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
-                   s->intregm_pending, s->intregm_disabled);
-}
-
-void slavio_irq_info(Monitor *mon, DeviceState *dev)
-{
-#ifndef DEBUG_IRQ_COUNT
-    monitor_printf(mon, "irq statistic code not compiled.\n");
-#else
-    SysBusDevice *sd;
-    SLAVIO_INTCTLState *s;
-    int i;
-    int64_t count;
-
-    sd = SYS_BUS_DEVICE(dev);
-    s = FROM_SYSBUS(SLAVIO_INTCTLState, sd);
-    monitor_printf(mon, "IRQ statistics:\n");
-    for (i = 0; i < 32; i++) {
-        count = s->irq_count[i];
-        if (count > 0)
-            monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
-    }
-#endif
-}
-
-static const uint32_t intbit_to_level[] = {
-    2, 3, 5, 7, 9, 11, 13, 2,   3, 5, 7, 9, 11, 13, 12, 12,
-    6, 13, 4, 10, 8, 9, 11, 0,  0, 0, 0, 15, 15, 15, 15, 0,
-};
-
-static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
-{
-    uint32_t pending = s->intregm_pending, pil_pending;
-    unsigned int i, j;
-
-    pending &= ~s->intregm_disabled;
-
-    trace_slavio_check_interrupts(pending, s->intregm_disabled);
-    for (i = 0; i < MAX_CPUS; i++) {
-        pil_pending = 0;
-
-        /* If we are the current interrupt target, get hard interrupts */
-        if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
-            (i == s->target_cpu)) {
-            for (j = 0; j < 32; j++) {
-                if ((pending & (1 << j)) && intbit_to_level[j]) {
-                    pil_pending |= 1 << intbit_to_level[j];
-                }
-            }
-        }
-
-        /* Calculate current pending hard interrupts for display */
-        s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN |
-            CPU_IRQ_TIMER_IN;
-        if (i == s->target_cpu) {
-            for (j = 0; j < 32; j++) {
-                if ((s->intregm_pending & (1 << j)) && intbit_to_level[j]) {
-                    s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
-                }
-            }
-        }
-
-        /* Level 15 and CPU timer interrupts are only masked when
-           the MASTER_DISABLE bit is set */
-        if (!(s->intregm_disabled & MASTER_DISABLE)) {
-            pil_pending |= s->slaves[i].intreg_pending &
-                (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN);
-        }
-
-        /* Add soft interrupts */
-        pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
-
-        if (set_irqs) {
-            /* Since there is not really an interrupt 0 (and pil_pending
-             * and irl_out bit zero are thus always zero) there is no need
-             * to do anything with cpu_irqs[i][0] and it is OK not to do
-             * the j=0 iteration of this loop.
-             */
-            for (j = MAX_PILS-1; j > 0; j--) {
-                if (pil_pending & (1 << j)) {
-                    if (!(s->slaves[i].irl_out & (1 << j))) {
-                        qemu_irq_raise(s->cpu_irqs[i][j]);
-                    }
-                } else {
-                    if (s->slaves[i].irl_out & (1 << j)) {
-                        qemu_irq_lower(s->cpu_irqs[i][j]);
-                    }
-                }
-            }
-        }
-        s->slaves[i].irl_out = pil_pending;
-    }
-}
-
-/*
- * "irq" here is the bit number in the system interrupt register to
- * separate serial and keyboard interrupts sharing a level.
- */
-static void slavio_set_irq(void *opaque, int irq, int level)
-{
-    SLAVIO_INTCTLState *s = opaque;
-    uint32_t mask = 1 << irq;
-    uint32_t pil = intbit_to_level[irq];
-    unsigned int i;
-
-    trace_slavio_set_irq(s->target_cpu, irq, pil, level);
-    if (pil > 0) {
-        if (level) {
-#ifdef DEBUG_IRQ_COUNT
-            s->irq_count[pil]++;
-#endif
-            s->intregm_pending |= mask;
-            if (pil == 15) {
-                for (i = 0; i < MAX_CPUS; i++) {
-                    s->slaves[i].intreg_pending |= 1 << pil;
-                }
-            }
-        } else {
-            s->intregm_pending &= ~mask;
-            if (pil == 15) {
-                for (i = 0; i < MAX_CPUS; i++) {
-                    s->slaves[i].intreg_pending &= ~(1 << pil);
-                }
-            }
-        }
-        slavio_check_interrupts(s, 1);
-    }
-}
-
-static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
-{
-    SLAVIO_INTCTLState *s = opaque;
-
-    trace_slavio_set_timer_irq_cpu(cpu, level);
-
-    if (level) {
-        s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN;
-    } else {
-        s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN;
-    }
-
-    slavio_check_interrupts(s, 1);
-}
-
-static void slavio_set_irq_all(void *opaque, int irq, int level)
-{
-    if (irq < 32) {
-        slavio_set_irq(opaque, irq, level);
-    } else {
-        slavio_set_timer_irq_cpu(opaque, irq - 32, level);
-    }
-}
-
-static int vmstate_intctl_post_load(void *opaque, int version_id)
-{
-    SLAVIO_INTCTLState *s = opaque;
-
-    slavio_check_interrupts(s, 0);
-    return 0;
-}
-
-static const VMStateDescription vmstate_intctl_cpu = {
-    .name ="slavio_intctl_cpu",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_intctl = {
-    .name ="slavio_intctl",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .post_load = vmstate_intctl_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1,
-                             vmstate_intctl_cpu, SLAVIO_CPUINTCTLState),
-        VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState),
-        VMSTATE_UINT32(intregm_disabled, SLAVIO_INTCTLState),
-        VMSTATE_UINT32(target_cpu, SLAVIO_INTCTLState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void slavio_intctl_reset(DeviceState *d)
-{
-    SLAVIO_INTCTLState *s = container_of(d, SLAVIO_INTCTLState, busdev.qdev);
-    int i;
-
-    for (i = 0; i < MAX_CPUS; i++) {
-        s->slaves[i].intreg_pending = 0;
-        s->slaves[i].irl_out = 0;
-    }
-    s->intregm_disabled = ~MASTER_IRQ_MASK;
-    s->intregm_pending = 0;
-    s->target_cpu = 0;
-    slavio_check_interrupts(s, 0);
-}
-
-static int slavio_intctl_init1(SysBusDevice *dev)
-{
-    SLAVIO_INTCTLState *s = FROM_SYSBUS(SLAVIO_INTCTLState, dev);
-    unsigned int i, j;
-    char slave_name[45];
-
-    qdev_init_gpio_in(&dev->qdev, slavio_set_irq_all, 32 + MAX_CPUS);
-    memory_region_init_io(&s->iomem, &slavio_intctlm_mem_ops, s,
-                          "master-interrupt-controller", INTCTLM_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    for (i = 0; i < MAX_CPUS; i++) {
-        snprintf(slave_name, sizeof(slave_name),
-                 "slave-interrupt-controller-%i", i);
-        for (j = 0; j < MAX_PILS; j++) {
-            sysbus_init_irq(dev, &s->cpu_irqs[i][j]);
-        }
-        memory_region_init_io(&s->slaves[i].iomem, &slavio_intctl_mem_ops,
-                              &s->slaves[i], slave_name, INTCTL_SIZE);
-        sysbus_init_mmio(dev, &s->slaves[i].iomem);
-        s->slaves[i].cpu = i;
-        s->slaves[i].master = s;
-    }
-
-    return 0;
-}
-
-static void slavio_intctl_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = slavio_intctl_init1;
-    dc->reset = slavio_intctl_reset;
-    dc->vmsd = &vmstate_intctl;
-}
-
-static const TypeInfo slavio_intctl_info = {
-    .name          = "slavio_intctl",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SLAVIO_INTCTLState),
-    .class_init    = slavio_intctl_class_init,
-};
-
-static void slavio_intctl_register_types(void)
-{
-    type_register_static(&slavio_intctl_info);
-}
-
-type_init(slavio_intctl_register_types)
index 3de10ff08c2d11435f59bfb1b70b72674f3aa48f..3246bb15e55186ae6703f6b7cc3393d59797578e 100644 (file)
@@ -1,9 +1,5 @@
-obj-y = slavio_intctl.o
 obj-y += slavio_misc.o
-obj-y += eccmemctl.o sbi.o sun4c_intctl.o
-
-# GRLIB
-obj-y += grlib_irqmp.o
+obj-y += eccmemctl.o
 
 obj-y := $(addprefix ../,$(obj-y))
 
diff --git a/hw/sun4c_intctl.c b/hw/sun4c_intctl.c
deleted file mode 100644 (file)
index 1096375..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * QEMU Sparc Sun4c interrupt controller emulation
- *
- * Based on slavio_intctl, copyright (c) 2003-2005 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw/hw.h"
-#include "hw/sparc/sun4m.h"
-#include "monitor/monitor.h"
-#include "hw/sysbus.h"
-
-//#define DEBUG_IRQ_COUNT
-//#define DEBUG_IRQ
-
-#ifdef DEBUG_IRQ
-#define DPRINTF(fmt, ...)                                       \
-    do { printf("IRQ: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-/*
- * Registers of interrupt controller in sun4c.
- *
- */
-
-#define MAX_PILS 16
-
-typedef struct Sun4c_INTCTLState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-#ifdef DEBUG_IRQ_COUNT
-    uint64_t irq_count;
-#endif
-    qemu_irq cpu_irqs[MAX_PILS];
-    const uint32_t *intbit_to_level;
-    uint32_t pil_out;
-    uint8_t reg;
-    uint8_t pending;
-} Sun4c_INTCTLState;
-
-#define INTCTL_SIZE 1
-
-static void sun4c_check_interrupts(void *opaque);
-
-static uint64_t sun4c_intctl_mem_read(void *opaque, hwaddr addr,
-                                      unsigned size)
-{
-    Sun4c_INTCTLState *s = opaque;
-    uint32_t ret;
-
-    ret = s->reg;
-    DPRINTF("read reg 0x" TARGET_FMT_plx " = %x\n", addr, ret);
-
-    return ret;
-}
-
-static void sun4c_intctl_mem_write(void *opaque, hwaddr addr,
-                                   uint64_t val, unsigned size)
-{
-    Sun4c_INTCTLState *s = opaque;
-
-    DPRINTF("write reg 0x" TARGET_FMT_plx " = %x\n", addr, (unsigned)val);
-    val &= 0xbf;
-    s->reg = val;
-    sun4c_check_interrupts(s);
-}
-
-static const MemoryRegionOps sun4c_intctl_mem_ops = {
-    .read = sun4c_intctl_mem_read,
-    .write = sun4c_intctl_mem_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static const uint32_t intbit_to_level[] = { 0, 1, 4, 6, 8, 10, 0, 14, };
-
-static void sun4c_check_interrupts(void *opaque)
-{
-    Sun4c_INTCTLState *s = opaque;
-    uint32_t pil_pending;
-    unsigned int i;
-
-    pil_pending = 0;
-    if (s->pending && !(s->reg & 0x80000000)) {
-        for (i = 0; i < 8; i++) {
-            if (s->pending & (1 << i))
-                pil_pending |= 1 << intbit_to_level[i];
-        }
-    }
-
-    for (i = 0; i < MAX_PILS; i++) {
-        if (pil_pending & (1 << i)) {
-            if (!(s->pil_out & (1 << i)))
-                qemu_irq_raise(s->cpu_irqs[i]);
-        } else {
-            if (s->pil_out & (1 << i))
-                qemu_irq_lower(s->cpu_irqs[i]);
-        }
-    }
-    s->pil_out = pil_pending;
-}
-
-/*
- * "irq" here is the bit number in the system interrupt register
- */
-static void sun4c_set_irq(void *opaque, int irq, int level)
-{
-    Sun4c_INTCTLState *s = opaque;
-    uint32_t mask = 1 << irq;
-    uint32_t pil = intbit_to_level[irq];
-
-    DPRINTF("Set irq %d -> pil %d level %d\n", irq, pil,
-            level);
-    if (pil > 0) {
-        if (level) {
-#ifdef DEBUG_IRQ_COUNT
-            s->irq_count++;
-#endif
-            s->pending |= mask;
-        } else {
-            s->pending &= ~mask;
-        }
-        sun4c_check_interrupts(s);
-    }
-}
-
-static const VMStateDescription vmstate_sun4c_intctl = {
-    .name ="sun4c_intctl",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT8(reg, Sun4c_INTCTLState),
-        VMSTATE_UINT8(pending, Sun4c_INTCTLState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void sun4c_intctl_reset(DeviceState *d)
-{
-    Sun4c_INTCTLState *s = container_of(d, Sun4c_INTCTLState, busdev.qdev);
-
-    s->reg = 1;
-    s->pending = 0;
-}
-
-static int sun4c_intctl_init1(SysBusDevice *dev)
-{
-    Sun4c_INTCTLState *s = FROM_SYSBUS(Sun4c_INTCTLState, dev);
-    unsigned int i;
-
-    memory_region_init_io(&s->iomem, &sun4c_intctl_mem_ops, s,
-                          "intctl", INTCTL_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-    qdev_init_gpio_in(&dev->qdev, sun4c_set_irq, 8);
-
-    for (i = 0; i < MAX_PILS; i++) {
-        sysbus_init_irq(dev, &s->cpu_irqs[i]);
-    }
-
-    return 0;
-}
-
-static void sun4c_intctl_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = sun4c_intctl_init1;
-    dc->reset = sun4c_intctl_reset;
-    dc->vmsd = &vmstate_sun4c_intctl;
-}
-
-static const TypeInfo sun4c_intctl_info = {
-    .name          = "sun4c_intctl",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(Sun4c_INTCTLState),
-    .class_init    = sun4c_intctl_class_init,
-};
-
-static void sun4c_intctl_register_types(void)
-{
-    type_register_static(&sun4c_intctl_info);
-}
-
-type_init(sun4c_intctl_register_types)