]> Git Repo - qemu.git/blobdiff - hw/ioapic.c
Rename target_phys_addr_t to hwaddr
[qemu.git] / hw / ioapic.c
index 335da6ef3f856e1a7cdf1549bacf1b842adf42ee..72730951a695f50d03ee039ecb0864ddb9f34845 100644 (file)
@@ -23,8 +23,8 @@
 #include "hw.h"
 #include "pc.h"
 #include "apic.h"
-#include "qemu-timer.h"
-#include "host-utils.h"
+#include "ioapic.h"
+#include "ioapic_internal.h"
 
 //#define DEBUG_IOAPIC
 
 #define DPRINTF(fmt, ...)
 #endif
 
-#define IOAPIC_NUM_PINS                        0x18
-#define IOAPIC_LVT_MASKED              (1<<16)
+static IOAPICCommonState *ioapics[MAX_IOAPICS];
 
-#define IOAPIC_TRIGGER_EDGE            0
-#define IOAPIC_TRIGGER_LEVEL           1
-
-/*io{apic,sapic} delivery mode*/
-#define IOAPIC_DM_FIXED                        0x0
-#define IOAPIC_DM_LOWEST_PRIORITY      0x1
-#define IOAPIC_DM_PMI                  0x2
-#define IOAPIC_DM_NMI                  0x4
-#define IOAPIC_DM_INIT                 0x5
-#define IOAPIC_DM_SIPI                 0x5
-#define IOAPIC_DM_EXTINT               0x7
-
-struct IOAPICState {
-    uint8_t id;
-    uint8_t ioregsel;
-
-    uint32_t irr;
-    uint64_t ioredtbl[IOAPIC_NUM_PINS];
-};
-
-static void ioapic_service(IOAPICState *s)
+static void ioapic_service(IOAPICCommonState *s)
 {
     uint8_t i;
     uint8_t trig_mode;
@@ -68,49 +47,55 @@ static void ioapic_service(IOAPICState *s)
     uint64_t entry;
     uint8_t dest;
     uint8_t dest_mode;
-    uint8_t polarity;
 
     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 >> 15) & 1);
-                dest = entry >> 56;
-                dest_mode = (entry >> 11) & 1;
-                delivery_mode = (entry >> 8) & 7;
-                polarity = (entry >> 13) & 1;
-                if (trig_mode == IOAPIC_TRIGGER_EDGE)
+                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;
-                if (delivery_mode == IOAPIC_DM_EXTINT)
+                } else {
+                    s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR;
+                }
+                if (delivery_mode == IOAPIC_DM_EXTINT) {
                     vector = pic_read_irq(isa_pic);
-                else
-                    vector = entry & 0xff;
-
+                } else {
+                    vector = entry & IOAPIC_VECTOR_MASK;
+                }
                 apic_deliver_irq(dest, dest_mode, delivery_mode,
-                                 vector, polarity, trig_mode);
+                                 vector, trig_mode);
             }
         }
     }
 }
 
-void ioapic_set_irq(void *opaque, int vector, int level)
+static void ioapic_set_irq(void *opaque, int vector, int level)
 {
-    IOAPICState *s = opaque;
+    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)
+    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 >> 15) & 1) {
+        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;
@@ -119,8 +104,9 @@ void ioapic_set_irq(void *opaque, int vector, int level)
                 s->irr &= ~mask;
             }
         } else {
-            /* edge triggered */
-            if (level) {
+            /* 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);
             }
@@ -128,125 +114,146 @@ void ioapic_set_irq(void *opaque, int vector, int level)
     }
 }
 
-static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr)
+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)
 {
-    IOAPICState *s = opaque;
+    IOAPICCommonState *s = opaque;
     int index;
     uint32_t val = 0;
 
-    addr &= 0xff;
-    if (addr == 0x00) {
+    switch (addr & 0xff) {
+    case IOAPIC_IOREGSEL:
         val = s->ioregsel;
-    } else if (addr == 0x10) {
+        break;
+    case IOAPIC_IOWIN:
+        if (size != 4) {
+            break;
+        }
         switch (s->ioregsel) {
-            case 0x00:
-                val = s->id << 24;
-                break;
-            case 0x01:
-                val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */
-                break;
-            case 0x02:
-                val = 0;
-                break;
-            default:
-                index = (s->ioregsel - 0x10) >> 1;
-                if (index >= 0 && index < IOAPIC_NUM_PINS) {
-                    if (s->ioregsel & 1)
-                        val = s->ioredtbl[index] >> 32;
-                    else
-                        val = s->ioredtbl[index] & 0xffffffff;
+        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_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void
+ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
+                 unsigned int size)
 {
-    IOAPICState *s = opaque;
+    IOAPICCommonState *s = opaque;
     int index;
 
-    addr &= 0xff;
-    if (addr == 0x00)  {
+    switch (addr & 0xff) {
+    case IOAPIC_IOREGSEL:
         s->ioregsel = val;
-        return;
-    } else if (addr == 0x10) {
-        DPRINTF("write: %08x = %08x\n", s->ioregsel, val);
+        break;
+    case IOAPIC_IOWIN:
+        if (size != 4) {
+            break;
+        }
+        DPRINTF("write: %08x = %08" PRIx64 "\n", s->ioregsel, val);
         switch (s->ioregsel) {
-            case 0x00:
-                s->id = (val >> 24) & 0xff;
-                return;
-            case 0x01:
-            case 0x02:
-                return;
-            default:
-                index = (s->ioregsel - 0x10) >> 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);
+        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 VMStateDescription vmstate_ioapic = {
-    .name = "ioapic",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT8(id, IOAPICState),
-        VMSTATE_UINT8(ioregsel, IOAPICState),
-        VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICState, IOAPIC_NUM_PINS),
-        VMSTATE_END_OF_LIST()
-    }
+static const MemoryRegionOps ioapic_io_ops = {
+    .read = ioapic_mem_read,
+    .write = ioapic_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static void ioapic_reset(void *opaque)
+static void ioapic_init(IOAPICCommonState *s, int instance_no)
 {
-    IOAPICState *s = opaque;
-    int i;
+    memory_region_init_io(&s->io_memory, &ioapic_io_ops, s, "ioapic", 0x1000);
 
-    memset(s, 0, sizeof(*s));
-    for(i = 0; i < IOAPIC_NUM_PINS; i++)
-        s->ioredtbl[i] = 1 << 16; /* mask LVT */
-}
-
-static CPUReadMemoryFunc * const ioapic_mem_read[3] = {
-    ioapic_mem_readl,
-    ioapic_mem_readl,
-    ioapic_mem_readl,
-};
+    qdev_init_gpio_in(&s->busdev.qdev, ioapic_set_irq, IOAPIC_NUM_PINS);
 
-static CPUWriteMemoryFunc * const ioapic_mem_write[3] = {
-    ioapic_mem_writel,
-    ioapic_mem_writel,
-    ioapic_mem_writel,
-};
+    ioapics[instance_no] = s;
+}
 
-qemu_irq *ioapic_init(void)
+static void ioapic_class_init(ObjectClass *klass, void *data)
 {
-    IOAPICState *s;
-    qemu_irq *irq;
-    int io_memory;
+    IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
 
-    s = qemu_mallocz(sizeof(IOAPICState));
-    ioapic_reset(s);
-
-    io_memory = cpu_register_io_memory(ioapic_mem_read,
-                                       ioapic_mem_write, s);
-    cpu_register_physical_memory(0xfec00000, 0x1000, io_memory);
+    k->init = ioapic_init;
+    dc->reset = ioapic_reset_common;
+}
 
-    vmstate_register(0, &vmstate_ioapic, s);
-    qemu_register_reset(ioapic_reset, s);
-    irq = qemu_allocate_irqs(ioapic_set_irq, s, IOAPIC_NUM_PINS);
+static TypeInfo ioapic_info = {
+    .name          = "ioapic",
+    .parent        = TYPE_IOAPIC_COMMON,
+    .instance_size = sizeof(IOAPICCommonState),
+    .class_init    = ioapic_class_init,
+};
 
-    return irq;
+static void ioapic_register_types(void)
+{
+    type_register_static(&ioapic_info);
 }
+
+type_init(ioapic_register_types)
This page took 0.036868 seconds and 4 git commands to generate.