Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com> --- hw/intc/armv7m_nvic.c | 107 ++++++++++++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 56 deletions(-)
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index c860b36..8eaf677 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -827,7 +827,7 @@ int nvic_post_load(void *opaque, int version_id) set_prio(s, i, s->vectors[i].raw_prio); } - nvic_irq_update(s, highest_runnable_prio(s->cpu)); + nvic_irq_update(s, 0); return 0; } @@ -883,66 +883,66 @@ static const VMStateDescription vmstate_nvic = { } }; +static Property props_nvic[] = { + DEFINE_PROP_UINT32("num-irq", nvic_state, num_irq, 64), + DEFINE_PROP_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_ctlr[0] = GICC_CTLR_EN_GRP0; - s->gic.priority_mask[0] = 0x100; - /* The NVIC as a whole is always enabled. */ - s->gic.ctlr = 1; + + s->vectors[ARMV7M_EXCP_RESET].enabled = 1; + s->vectors[ARMV7M_EXCP_NMI].enabled = 1; + s->vectors[ARMV7M_EXCP_HARD].enabled = 1; + s->vectors[ARMV7M_EXCP_SVC].enabled = 1; + s->vectors[ARMV7M_EXCP_DEBUG].enabled = 1; + s->vectors[ARMV7M_EXCP_PENDSV].enabled = 1; + + s->vectors[ARMV7M_EXCP_RESET].prio_group = -3; + s->vectors[ARMV7M_EXCP_NMI].prio_group = -2; + s->vectors[ARMV7M_EXCP_HARD].prio_group = -1; + systick_reset(s); } static void armv7m_nvic_realize(DeviceState *dev, Error **errp) { nvic_state *s = NVIC(dev); - NVICClass *nc = NVIC_GET_CLASS(s); - Error *local_err = NULL; - - /* 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, &local_err); - if (local_err) { - error_propagate(errp, local_err); + + /* evil hack to get ARMCPU* ahead of time */ + assert(cpus.tqh_first); + assert(!CPU_NEXT(cpus.tqh_first)); + s->cpu = ARM_CPU(cpus.tqh_first); + assert(s->cpu); + + if (s->num_irq > NVIC_MAX_IRQ) { + error_setg(errp, TYPE_NVIC " num_irq too large"); return; } - gic_init_irqs_and_distributor(&s->gic); - /* 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, OBJECT(s), "nvic", 0x1000); - /* The system register region goes at the bottom of the priority - * stack as it covers the whole page. + + qdev_init_gpio_in(dev, set_irq_level, s->num_irq); + + s->num_irq += 16; /* include space for internal exception vectors */ + + /* The NVIC and system controller register area starts at 0xe000e000 + * and looks like this: + * 0x004 - ICTR + * 0x010 - 0x1c - systick + * 0x100..0x7ec - NVIC + * 0x7f0..0xcff - Reserved + * 0xd00..0xd3c - SCS registers + * 0xd40..0xeff - Reserved or Not implemented + * 0xf00 - STIR */ - memory_region_init_io(&s->sysregmem, OBJECT(s), &nvic_sysreg_ops, s, + + memory_region_init_io(&s->iomem, OBJECT(s), &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, OBJECT(s), - "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); + memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->iomem); s->systick.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, systick_timer_tick, s); } @@ -954,36 +954,31 @@ static void armv7m_nvic_instance_init(Object *obj) * any user-specified property setting, so just modify the * value in the GICState struct. */ - GICState *s = ARM_GIC_COMMON(obj); DeviceState *dev = DEVICE(obj); nvic_state *nvic = NVIC(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; + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + sysbus_init_irq(sbd, &nvic->excpout); qdev_init_gpio_out_named(dev, &nvic->sysresetreq, "SYSRESETREQ", 1); } 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->props = props_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, + .parent = TYPE_SYS_BUS_DEVICE, .instance_init = armv7m_nvic_instance_init, .instance_size = sizeof(nvic_state), .class_init = armv7m_nvic_class_init, - .class_size = sizeof(NVICClass), + .class_size = sizeof(SysBusDeviceClass), }; static void armv7m_nvic_register_types(void) -- 2.1.4