/* * 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 "qemu/osdep.h" #include "hw/sysbus.h" #include "gic_internal.h" #include "qapi/error.h" #include "qom/cpu.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_11mpcore[] = { 0x00, 0x00, 0x00, 0x00, 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; static const uint8_t gic_id_gicv1[] = { 0x04, 0x00, 0x00, 0x00, 0x90, 0xb3, 0x1b, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; static const uint8_t gic_id_gicv2[] = { 0x04, 0x00, 0x00, 0x00, 0x90, 0xb4, 0x2b, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; static inline int gic_get_current_cpu(GICState *s) { if (s->num_cpu > 1) { return current_cpu->cpu_index; } return 0; } /* Return true if this GIC config has interrupt groups, which is * true if we're a GICv2, or a GICv1 with the security extensions. */ static inline bool gic_has_groups(GICState *s) { return s->revision == 2 || s->security_extn; } /* 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 irq_level, fiq_level; int cpu; int cm; for (cpu = 0; cpu < s->num_cpu; cpu++) { cm = 1 << cpu; s->current_pending[cpu] = 1023; if (!(s->ctlr & (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1)) || !(s->cpu_ctlr[cpu] & (GICC_CTLR_EN_GRP0 | GICC_CTLR_EN_GRP1))) { qemu_irq_lower(s->parent_irq[cpu]); qemu_irq_lower(s->parent_fiq[cpu]); continue; } best_prio = 0x100; best_irq = 1023; for (irq = 0; irq < s->num_irq; irq++) { if (GIC_TEST_ENABLED(irq, cm) && gic_test_pending(s, irq, cm) && (irq < GIC_INTERNAL || GIC_TARGET(irq) & cm)) { if (GIC_GET_PRIORITY(irq, cpu) < best_prio) { best_prio = GIC_GET_PRIORITY(irq, cpu); best_irq = irq; } } } irq_level = fiq_level = 0; if (best_prio < s->priority_mask[cpu]) { s->current_pending[cpu] = best_irq; if (best_prio < s->running_priority[cpu]) { int group = GIC_TEST_GROUP(best_irq, cm); if (extract32(s->ctlr, group, 1) && extract32(s->cpu_ctlr[cpu], group, 1)) { if (group == 0 && s->cpu_ctlr[cpu] & GICC_CTLR_FIQ_EN) { DPRINTF("Raised pending FIQ %d (cpu %d)\n", best_irq, cpu); fiq_level = 1; } else { DPRINTF("Raised pending IRQ %d (cpu %d)\n", best_irq, cpu); irq_level = 1; } } } } qemu_set_irq(s->parent_irq[cpu], irq_level); qemu_set_irq(s->parent_fiq[cpu], fiq_level); } } void gic_set_pending_private(GICState *s, int cpu, int irq) { int cm = 1 << cpu; if (gic_test_pending(s, irq, cm)) { return; } DPRINTF("Set %d pending cpu %d\n", irq, cpu); GIC_SET_PENDING(irq, cm); gic_update(s); } static void gic_set_irq_11mpcore(GICState *s, int irq, int level, int cm, int target) { if (level) { GIC_SET_LEVEL(irq, cm); if (GIC_TEST_EDGE_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); } } static void gic_set_irq_generic(GICState *s, int irq, int level, int cm, int target) { if (level) { GIC_SET_LEVEL(irq, cm); DPRINTF("Set %d pending mask %x\n", irq, target); if (GIC_TEST_EDGE_TRIGGER(irq)) { GIC_SET_PENDING(irq, target); } } else { GIC_CLEAR_LEVEL(irq, cm); } } /* 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;
# Use this environment when deploying an SSL-enabled overcloud where the public
# endpoint is an IP address.
parameter_defaults:
  EndpointMap:
    AodhAdmin: {protocol: 'http', port: '8042', host: 'IP_ADDRESS'}
    AodhInternal: {protocol: 'http', port: '8042', host: 'IP_ADDRESS'}
    AodhPublic: {protocol: 'https', port: '13042', host: 'IP_ADDRESS'}
    CeilometerAdmin: {protocol: 'http', port: '8777', host: 'IP_ADDRESS'}
    CeilometerInternal: {protocol: 'http', port: '8777', host: 'IP_ADDRESS'}
    CeilometerPublic: {protocol: 'https', port: '13777', host: 'IP_ADDRESS'}
    CinderAdmin: {protocol: 'http', port: '8776', host: 'IP_ADDRESS'}
    CinderInternal: {protocol: 'http', port: '8776', host: 'IP_ADDRESS'}
    CinderPublic: {protocol: 'https', port: '13776', host: 'IP_ADDRESS'}
    GlanceAdmin: {protocol: 'http', port: '9292', host: 'IP_ADDRESS'}
    GlanceInternal: {protocol: 'http', port: '9292', host: 'IP_ADDRESS'}
    GlancePublic: {protocol: 'https', port: '13292', host: 'IP_ADDRESS'}
    GlanceRegistryInternal: {protocol: 'http', port: '9191', host: 'IP_ADDRESS'}
    GnocchiAdmin: {protocol: 'http', port: '8041', host: 'IP_ADDRESS'}
    GnocchiInternal: {protocol: 'http', port: '8041', host: 'IP_ADDRESS'}
    GnocchiPublic: {protocol: 'https', port: '13041', host: 'IP_ADDRESS'}
    HeatAdmin: {protocol: 'http', port: '8004', host: 'IP_ADDRESS'}
    HeatInternal: {protocol: 'http', port: '8004', host: 'IP_ADDRESS'}
    HeatPublic: {protocol: 'https', port: '13004', host: 'IP_ADDRESS'}
    HeatCfnAdmin: {protocol: 'http', port: '8000', host: 'IP_ADDRESS'}
    HeatCfnInternal: {protocol: 'http', port: '8000', host: 'IP_ADDRESS'}
    HeatCfnPublic: {protocol: 'https', port: '13005', host: 'IP_ADDRESS'}
    HorizonPublic: {protocol: 'https', port: '443', host: 'IP_ADDRESS'}
    IronicAdmin: {protocol: 'http', port: '6385', host: 'IP_ADDRESS'}
    IronicInternal: {protocol: 'http', port: '6385', host: 'IP_ADDRESS'}
    IronicPublic: {protocol: 'https', port: '13385', host: 'IP_ADDRESS'}
    KeystoneAdmin: {protocol: 'http', port: '35357', host: 'IP_ADDRESS'}
    KeystoneInternal: {protocol: 'http', port: '5000', host: 'IP_ADDRESS'}
    KeystonePublic: {protocol: 'https', port: '13000', host: 'IP_ADDRESS'}
    ManilaAdmin: {protocol: 'http', port: '8786', host: 'IP_ADDRESS'}
    ManilaInternal: {protocol: 'http', port: '8786', host: 'IP_ADDRESS'}
    ManilaPublic: {protocol: 'https', port: '13786', host: 'IP_ADDRESS'}
    MysqlInternal: {protocol: 'mysql+pymysql', port: '3306', host: 'IP_ADDRESS'}
    NeutronAdmin: {protocol: 'http', port: '9696', host: 'IP_ADDRESS'}
    NeutronInternal: {protocol: 'http', port: '9696', host: 'IP_ADDRESS'}
    NeutronPublic: {protocol: 'https', port: '13696', host: 'IP_ADDRESS'}
    NovaAdmin: {protocol: 'http', port: '8774', host: 'IP_ADDRESS'}
    NovaInternal: {protocol: 'http', port: '8774', host: 'IP_ADDRESS'}
    NovaPublic: {protocol: 'https', port: '13774', host: 'IP_ADDRESS'}
    NovaVNCProxyAdmin: {protocol: 'http', port: '6080', host: 'IP_ADDRESS'}
    NovaVNCProxyInternal: {protocol: 'http', port: '6080', host: 'IP_ADDRESS'}
    NovaVNCProxyPublic: {protocol: 'https', port: '13080', host: 'IP_ADDRESS'}
    SaharaAdmin: {protocol: 'http', port: '8386', host: 'IP_ADDRESS'}
    SaharaInternal: {protocol: 'http', port: '8386', host: 'IP_ADDRESS'}
    SaharaPublic: {protocol: 'https', port: '13386', host: 'IP_ADDRESS'}
    SwiftAdmin: {protocol: 'http', port: '8080', host: 'IP_ADDRESS'}
    SwiftInternal: {protocol: 'http', port: '8080', host: 'IP_ADDRESS'}
    SwiftPublic: {protocol: 'https', port: '13808', host: 'IP_ADDRESS'}

resource_registry:
  OS::TripleO::NodeTLSData: ../puppet/extraconfig/tls/tls-cert-inject.yaml
int)offset); return MEMTX_ERROR; } gic_update(s); return MEMTX_OK; } /* Wrappers to read/write the GIC CPU interface for the current CPU */ static MemTxResult gic_thiscpu_read(void *opaque, hwaddr addr, uint64_t *data, unsigned size, MemTxAttrs attrs) { GICState *s = (GICState *)opaque; return gic_cpu_read(s, gic_get_current_cpu(s), addr, data, attrs); } static MemTxResult gic_thiscpu_write(void *opaque, hwaddr addr, uint64_t value, unsigned size, MemTxAttrs attrs) { GICState *s = (GICState *)opaque; return gic_cpu_write(s, gic_get_current_cpu(s), addr, value, attrs); } /* Wrappers to read/write the GIC CPU interface for a specific CPU. * These just decode the opaque pointer into GICState* + cpu id. */ static MemTxResult gic_do_cpu_read(void *opaque, hwaddr addr, uint64_t *data, unsigned size, MemTxAttrs attrs) { GICState **backref = (GICState **)opaque; GICState *s = *backref; int id = (backref - s->backref); return gic_cpu_read(s, id, addr, data, attrs); } static MemTxResult gic_do_cpu_write(void *opaque, hwaddr addr, uint64_t value, unsigned size, MemTxAttrs attrs) { GICState **backref = (GICState **)opaque; GICState *s = *backref; int id = (backref - s->backref); return gic_cpu_write(s, id, addr, value, attrs); } static const MemoryRegionOps gic_ops[2] = { { .read_with_attrs = gic_dist_read, .write_with_attrs = gic_dist_write, .endianness = DEVICE_NATIVE_ENDIAN, }, { .read_with_attrs = gic_thiscpu_read, .write_with_attrs = gic_thiscpu_write, .endianness = DEVICE_NATIVE_ENDIAN, } }; static const MemoryRegionOps gic_cpu_ops = { .read_with_attrs = gic_do_cpu_read, .write_with_attrs = gic_do_cpu_write, .endianness = DEVICE_NATIVE_ENDIAN, }; /* This function is used by nvic model */ void gic_init_irqs_and_distributor(GICState *s) { gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops); } 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); Error *local_err = NULL; agc->parent_realize(dev, &local_err); if (local_err) { error_propagate(errp, local_err); return; } /* This creates distributor and main CPU interface (s->cpuiomem[0]) */ gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops); /* Extra core-specific regions for the CPU interfaces. This is * necessary for "franken-GIC" implementations, for example on * Exynos 4. * 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. */ for (i = 0; i < s->num_cpu; i++) { s->backref[i] = s; memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops, &s->backref[i], "gic_cpu", 0x100); sysbus_init_mmio(sbd, &s->cpuiomem[i+1]); } } static void arm_gic_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ARMGICClass *agc = ARM_GIC_CLASS(klass); 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)