]> Git Repo - qemu.git/blobdiff - hw/armv7m_nvic.c
hw: move PCI bridges to hw/pci-* or hw/ARCH
[qemu.git] / hw / armv7m_nvic.c
index 35c1aa67e20aaad5d04e5b29f23662a73b60c0dd..75742601cb08eb26bb8c197b90c5edd97b859a97 100644 (file)
  * NVIC.  Much of that is also implemented here.
  */
 
-#include "sysbus.h"
-#include "qemu-timer.h"
-#include "arm-misc.h"
-#include "exec-memory.h"
-#include "arm_gic_internal.h"
+#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;
@@ -41,7 +41,7 @@ typedef struct NVICClass {
     /*< private >*/
     ARMGICClass parent_class;
     /*< public >*/
-    int (*parent_init)(SysBusDevice *dev);
+    DeviceRealize parent_realize;
     void (*parent_reset)(DeviceState *dev);
 } NVICClass;
 
@@ -138,9 +138,8 @@ void armv7m_nvic_complete_irq(void *opaque, int irq)
     gic_complete_irq(&s->gic, 0, irq);
 }
 
-static uint32_t nvic_readl(void *opaque, uint32_t offset)
+static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
 {
-    nvic_state *s = (nvic_state *)opaque;
     uint32_t val;
     int irq;
 
@@ -216,14 +215,6 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
     case 0xd14: /* Configuration Control.  */
         /* TODO: Implement Configuration Control bits.  */
         return 0;
-    case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority.  */
-        irq = offset - 0xd14;
-        val = 0;
-        val |= s->gic.priority1[irq++][0];
-        val |= s->gic.priority1[irq++][0] << 8;
-        val |= s->gic.priority1[irq++][0] << 16;
-        val |= s->gic.priority1[irq][0] << 24;
-        return val;
     case 0xd24: /* System Handler Status.  */
         val = 0;
         if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
@@ -243,7 +234,7 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
         return val;
     case 0xd28: /* Configurable Fault Status.  */
         /* TODO: Implement Fault Status.  */
-        hw_error("Not implemented: Configurable Fault Status.");
+        qemu_log_mask(LOG_UNIMP, "Configurable Fault Status unimplemented\n");
         return 0;
     case 0xd2c: /* Hard Fault Status.  */
     case 0xd30: /* Debug Fault Status.  */
@@ -251,7 +242,8 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
     case 0xd38: /* Bus Fault Address.  */
     case 0xd3c: /* Aux Fault Status.  */
         /* TODO: Implement fault status registers.  */
-        goto bad_reg;
+        qemu_log_mask(LOG_UNIMP, "Fault status registers unimplemented\n");
+        return 0;
     case 0xd40: /* PFR0.  */
         return 0x00000030;
     case 0xd44: /* PRF1.  */
@@ -280,14 +272,13 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
         return 0x01310102;
     /* TODO: Implement debug registers.  */
     default:
-    bad_reg:
-        hw_error("NVIC: Bad read offset 0x%x\n", offset);
+        qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
+        return 0;
     }
 }
 
-static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
+static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value)
 {
-    nvic_state *s = (nvic_state *)opaque;
     uint32_t oldval;
     switch (offset) {
     case 0x10: /* SysTick Control and Status.  */
@@ -345,27 +336,17 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
     case 0xd0c: /* Application Interrupt/Reset Control.  */
         if ((value >> 16) == 0x05fa) {
             if (value & 2) {
-                hw_error("VECTCLRACTIVE not implemented");
+                qemu_log_mask(LOG_UNIMP, "VECTCLRACTIVE unimplemented\n");
             }
             if (value & 5) {
-                hw_error("System reset");
+                qemu_log_mask(LOG_UNIMP, "AIRCR system reset unimplemented\n");
             }
         }
         break;
     case 0xd10: /* System Control.  */
     case 0xd14: /* Configuration Control.  */
         /* TODO: Implement control registers.  */
-        goto bad_reg;
-    case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority.  */
-        {
-            int irq;
-            irq = offset - 0xd14;
-            s->gic.priority1[irq++][0] = value & 0xff;
-            s->gic.priority1[irq++][0] = (value >> 8) & 0xff;
-            s->gic.priority1[irq++][0] = (value >> 16) & 0xff;
-            s->gic.priority1[irq][0] = (value >> 24) & 0xff;
-            gic_update(&s->gic);
-        }
+        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
@@ -380,47 +361,71 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
     case 0xd34: /* Mem Manage Address.  */
     case 0xd38: /* Bus Fault Address.  */
     case 0xd3c: /* Aux Fault Status.  */
-        goto bad_reg;
+        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:
-    bad_reg:
-        hw_error("NVIC: Bad write offset 0x%x\n", offset);
+        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)
 {
-    /* At the moment we only support the ID registers for byte/word access.
-     * This is not strictly correct as a few of the other registers also
-     * allow byte access.
-     */
+    nvic_state *s = (nvic_state *)opaque;
     uint32_t offset = addr;
-    if (offset >= 0xfe0) {
+    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(opaque, offset);
+        return nvic_readl(s, offset);
     }
-    hw_error("NVIC: Bad read of size %d at offset 0x%x\n", size, 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(opaque, offset, value);
+        nvic_writel(s, offset, value);
         return;
     }
-    hw_error("NVIC: Bad write of size %d at offset 0x%x\n", size, offset);
+    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 = {
@@ -450,15 +455,17 @@ static void armv7m_nvic_reset(DeviceState *dev)
     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.
+     * as enabled by default, and with a priority mask which allows
+     * all interrupts through.
      */
-    s->gic.cpu_enabled[0] = 1;
+    s->gic.cpu_enabled[0] = true;
+    s->gic.priority_mask[0] = 0x100;
     /* The NVIC as a whole is always enabled. */
-    s->gic.enabled = 1;
+    s->gic.enabled = true;
     systick_reset(s);
 }
 
-static int armv7m_nvic_init(SysBusDevice *dev)
+static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
 {
     nvic_state *s = NVIC(dev);
     NVICClass *nc = NVIC_GET_CLASS(s);
@@ -468,7 +475,10 @@ static int armv7m_nvic_init(SysBusDevice *dev)
     /* Tell the common code we're an NVIC */
     s->gic.revision = 0xffffffff;
     s->num_irq = s->gic.num_irq;
-    nc->parent_init(dev);
+    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
@@ -496,7 +506,6 @@ static int armv7m_nvic_init(SysBusDevice *dev)
      */
     memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->container);
     s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s);
-    return 0;
 }
 
 static void armv7m_nvic_instance_init(Object *obj)
@@ -519,16 +528,15 @@ static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
 {
     NVICClass *nc = NVIC_CLASS(klass);
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
 
     nc->parent_reset = dc->reset;
-    nc->parent_init = sdc->init;
-    sdc->init = armv7m_nvic_init;
+    nc->parent_realize = dc->realize;
     dc->vmsd  = &vmstate_nvic;
     dc->reset = armv7m_nvic_reset;
+    dc->realize = armv7m_nvic_realize;
 }
 
-static TypeInfo armv7m_nvic_info = {
+static const TypeInfo armv7m_nvic_info = {
     .name          = TYPE_NVIC,
     .parent        = TYPE_ARM_GIC_COMMON,
     .instance_init = armv7m_nvic_instance_init,
This page took 0.03011 seconds and 4 git commands to generate.