From 44f552964714a41ccd41b5e8ac4cbd2478249db1 Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Tue, 12 May 2015 11:57:16 +0100 Subject: hw/intc/arm_gic: Create outbound FIQ lines Create the outbound FIQ lines from the GIC to the CPUs; these are used if the GIC has security extensions or grouping support. Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Edgar E. Iglesias Signed-off-by: Peter Maydell Message-id: 1430502643-25909-2-git-send-email-peter.maydell@linaro.org Message-id: 1429113742-8371-2-git-send-email-greg.bellows@linaro.org [PMM: added FIQ lines to kvm-arm-gic so its interface is the same; tweaked commit message] Signed-off-by: Peter Maydell --- include/hw/intc/arm_gic_common.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h index f6887ed92b..01c6f248ab 100644 --- a/include/hw/intc/arm_gic_common.h +++ b/include/hw/intc/arm_gic_common.h @@ -50,6 +50,7 @@ typedef struct GICState { /*< public >*/ qemu_irq parent_irq[GIC_NCPU]; + qemu_irq parent_fiq[GIC_NCPU]; bool enabled; bool cpu_enabled[GIC_NCPU]; -- cgit v1.2.3-55-g7522 From 5543d1abb6e218a9d3b8887b777fd3947c86c4cf Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Tue, 12 May 2015 11:57:16 +0100 Subject: hw/intc/arm_gic: Add Security Extensions property Add a QOM property which allows the GIC Security Extensions to be enabled. These are an optional part of the GICv1 and GICv2 architecture. This commit just adds the property and some sanity checks that it is only enabled on GIC revisions that support it. Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Edgar E. Iglesias Signed-off-by: Peter Maydell Message-id: 1430502643-25909-3-git-send-email-peter.maydell@linaro.org Message-id: 1429113742-8371-5-git-send-email-greg.bellows@linaro.org [PMM: changed property name, added checks that it isn't set for older GIC revisions or if using the KVM VGIC; reworded commit message] Signed-off-by: Peter Maydell --- hw/intc/arm_gic.c | 5 ++++- hw/intc/arm_gic_common.c | 9 +++++++++ hw/intc/arm_gic_kvm.c | 6 ++++++ include/hw/intc/arm_gic_common.h | 1 + 4 files changed, 20 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index e9fb8b9400..cdf7408774 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -298,7 +298,10 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset) if (offset == 0) return s->enabled; if (offset == 4) - return ((s->num_irq / 32) - 1) | ((NUM_CPU(s) - 1) << 5); + /* Interrupt Controller Type Register */ + return ((s->num_irq / 32) - 1) + | ((NUM_CPU(s) - 1) << 5) + | (s->security_extn << 10); if (offset < 0x08) return 0; if (offset >= 0x80) { diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c index 18b01ba0c7..5ed21f1b46 100644 --- a/hw/intc/arm_gic_common.c +++ b/hw/intc/arm_gic_common.c @@ -110,6 +110,13 @@ static void arm_gic_common_realize(DeviceState *dev, Error **errp) num_irq); return; } + + if (s->security_extn && + (s->revision == REV_11MPCORE || s->revision == REV_NVIC)) { + error_setg(errp, "this GIC revision does not implement " + "the security extensions"); + return; + } } static void arm_gic_common_reset(DeviceState *dev) @@ -149,6 +156,8 @@ static Property arm_gic_common_properties[] = { * (Internally, 0xffffffff also indicates "not a GIC but an NVIC".) */ DEFINE_PROP_UINT32("revision", GICState, revision, 1), + /* True if the GIC should implement the security extensions */ + DEFINE_PROP_BOOL("has-security-extensions", GICState, security_extn, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index 5aedae1660..cb47b12f0e 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -544,6 +544,12 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) return; } + if (s->security_extn) { + error_setg(errp, "the in-kernel VGIC does not implement the " + "security extensions"); + 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: diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h index 01c6f248ab..78251345f7 100644 --- a/include/hw/intc/arm_gic_common.h +++ b/include/hw/intc/arm_gic_common.h @@ -105,6 +105,7 @@ typedef struct GICState { MemoryRegion cpuiomem[GIC_NCPU + 1]; /* CPU interfaces */ uint32_t num_irq; uint32_t revision; + bool security_extn; int dev_fd; /* kvm device fd if backed by kvm vgic support */ } GICState; -- cgit v1.2.3-55-g7522 From c27a5ba94874cb3a29e21b3ad4bd5e504aea93b2 Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Tue, 12 May 2015 11:57:17 +0100 Subject: hw/intc/arm_gic: Add Interrupt Group Registers The Interrupt Group Registers allow the guest to configure interrupts into one of two groups, where Group0 are higher priority and may be routed to IRQ or FIQ, and Group1 are lower priority and always routed to IRQ. (In a GIC with the security extensions Group0 is Secure interrupts and Group 1 is NonSecure.) The GICv2 always supports interrupt grouping; the GICv1 does only if it implements the security extensions. This patch implements the ability to read and write the registers; the actual functionality the bits control will be added in a subsequent patch. Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Edgar E. Iglesias Signed-off-by: Peter Maydell Message-id: 1430502643-25909-5-git-send-email-peter.maydell@linaro.org Message-id: 1429113742-8371-7-git-send-email-greg.bellows@linaro.org [PMM: bring GIC_*_GROUP macros into line with the others, ie a simple SET/CLEAR/TEST rather than GROUP0/GROUP1; utility gic_has_groups() function; minor style fixes; bump vmstate version] Signed-off-by: Peter Maydell --- hw/intc/arm_gic.c | 50 +++++++++++++++++++++++++++++++++++++--- hw/intc/arm_gic_common.c | 5 ++-- hw/intc/gic_internal.h | 4 ++++ include/hw/intc/arm_gic_common.h | 1 + 4 files changed, 55 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 29015c2e6d..1aa45209ce 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -45,6 +45,14 @@ static inline int gic_get_current_cpu(GICState *s) 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) @@ -305,8 +313,24 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) if (offset < 0x08) return 0; if (offset >= 0x80) { - /* Interrupt Security , RAZ/WI */ - return 0; + /* Interrupt Group Registers: these RAZ/WI if this is an NS + * access to a GIC with the security extensions, or if the GIC + * doesn't have groups at all. + */ + res = 0; + if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) { + /* Every byte offset holds 8 group status bits */ + irq = (offset - 0x080) * 8 + GIC_BASE_IRQ; + if (irq >= s->num_irq) { + goto bad_reg; + } + for (i = 0; i < 8; i++) { + if (GIC_TEST_GROUP(irq + i, cm)) { + res |= (1 << i); + } + } + } + return res; } goto bad_reg; } else if (offset < 0x200) { @@ -456,7 +480,27 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, } else if (offset < 4) { /* ignored. */ } else if (offset >= 0x80) { - /* Interrupt Security Registers, RAZ/WI */ + /* Interrupt Group Registers: RAZ/WI for NS access to secure + * GIC, or for GICs without groups. + */ + if (!(s->security_extn && !attrs.secure) && gic_has_groups(s)) { + /* Every byte offset holds 8 group status bits */ + irq = (offset - 0x80) * 8 + GIC_BASE_IRQ; + if (irq >= s->num_irq) { + goto bad_reg; + } + for (i = 0; i < 8; i++) { + /* Group bits are banked for private interrupts */ + int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; + if (value & (1 << i)) { + /* Group1 (Non-secure) */ + GIC_SET_GROUP(irq + i, cm); + } else { + /* Group0 (Secure) */ + GIC_CLEAR_GROUP(irq + i, cm); + } + } + } } else { goto bad_reg; } diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c index 5ed21f1b46..b5a85e5673 100644 --- a/hw/intc/arm_gic_common.c +++ b/hw/intc/arm_gic_common.c @@ -52,14 +52,15 @@ static const VMStateDescription vmstate_gic_irq_state = { VMSTATE_UINT8(level, gic_irq_state), VMSTATE_BOOL(model, gic_irq_state), VMSTATE_BOOL(edge_trigger, gic_irq_state), + VMSTATE_UINT8(group, gic_irq_state), VMSTATE_END_OF_LIST() } }; static const VMStateDescription vmstate_gic = { .name = "arm_gic", - .version_id = 7, - .minimum_version_id = 7, + .version_id = 8, + .minimum_version_id = 8, .pre_save = gic_pre_save, .post_load = gic_post_load, .fields = (VMStateField[]) { diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h index e87ef36d0c..e8cf773e73 100644 --- a/hw/intc/gic_internal.h +++ b/hw/intc/gic_internal.h @@ -50,6 +50,10 @@ s->priority1[irq][cpu] : \ s->priority2[(irq) - GIC_INTERNAL]) #define GIC_TARGET(irq) s->irq_target[irq] +#define GIC_CLEAR_GROUP(irq, cm) (s->irq_state[irq].group &= ~(cm)) +#define GIC_SET_GROUP(irq, cm) (s->irq_state[irq].group |= (cm)) +#define GIC_TEST_GROUP(irq, cm) ((s->irq_state[irq].group & (cm)) != 0) + /* The special cases for the revision property: */ #define REV_11MPCORE 0 diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h index 78251345f7..b78981ed58 100644 --- a/include/hw/intc/arm_gic_common.h +++ b/include/hw/intc/arm_gic_common.h @@ -42,6 +42,7 @@ typedef struct gic_irq_state { uint8_t level; bool model; /* 0 = N:N, 1 = 1:N */ bool edge_trigger; /* true: edge-triggered, false: level-triggered */ + uint8_t group; } gic_irq_state; typedef struct GICState { -- cgit v1.2.3-55-g7522 From 679aa175e84f5f80b32b307fce5a6b92729e0e61 Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Tue, 12 May 2015 11:57:17 +0100 Subject: hw/intc/arm_gic: Make ICDDCR/GICD_CTLR banked ICDDCR/GICD_CTLR is banked if the GIC has the security extensions, and the S (or only) copy has separate enable bits for Group0 and Group1 enable if the GIC implements interrupt groups. EnableGroup0 (Bit [1]) in GICv1 is architecturally IMPDEF. Since this bit (Enable Non-secure) is present in the integrated GIC of the Cortex-A9 MPCore, we support this bit in our GICv1 implementation too. Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Edgar E. Iglesias Signed-off-by: Peter Maydell Message-id: 1430502643-25909-7-git-send-email-peter.maydell@linaro.org Message-id: 1429113742-8371-8-git-send-email-greg.bellows@linaro.org [PMM: rewritten to store the state in a single s->ctlr uint32, with the NS register handled as an alias of bit 1 in that value; added vmstate version bump] Signed-off-by: Peter Maydell --- hw/intc/arm_gic.c | 28 +++++++++++++++++++++++----- hw/intc/arm_gic_common.c | 8 ++++---- hw/intc/arm_gic_kvm.c | 8 ++++---- hw/intc/armv7m_nvic.c | 2 +- hw/intc/gic_internal.h | 2 ++ include/hw/intc/arm_gic_common.h | 5 ++++- 6 files changed, 38 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 1aa45209ce..4f13ff2c90 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -67,7 +67,8 @@ void gic_update(GICState *s) for (cpu = 0; cpu < NUM_CPU(s); cpu++) { cm = 1 << cpu; s->current_pending[cpu] = 1023; - if (!s->enabled || !s->cpu_enabled[cpu]) { + if (!(s->ctlr & (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1)) + || !s->cpu_enabled[cpu]) { qemu_irq_lower(s->parent_irq[cpu]); return; } @@ -303,8 +304,16 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) cpu = gic_get_current_cpu(s); cm = 1 << cpu; if (offset < 0x100) { - if (offset == 0) - return s->enabled; + if (offset == 0) { /* GICD_CTLR */ + if (s->security_extn && !attrs.secure) { + /* The NS bank of this register is just an alias of the + * EnableGrp1 bit in the S bank version. + */ + return extract32(s->ctlr, 1, 1); + } else { + return s->ctlr; + } + } if (offset == 4) /* Interrupt Controller Type Register */ return ((s->num_irq / 32) - 1) @@ -475,8 +484,17 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, cpu = gic_get_current_cpu(s); if (offset < 0x100) { if (offset == 0) { - s->enabled = (value & 1); - DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis"); + if (s->security_extn && !attrs.secure) { + /* NS version is just an alias of the S version's bit 1 */ + s->ctlr = deposit32(s->ctlr, 1, 1, value); + } else if (gic_has_groups(s)) { + s->ctlr = value & (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1); + } else { + s->ctlr = value & GICD_CTLR_EN_GRP0; + } + DPRINTF("Distributor: Group0 %sabled; Group 1 %sabled\n", + s->ctlr & GICD_CTLR_EN_GRP0 ? "En" : "Dis", + s->ctlr & GICD_CTLR_EN_GRP1 ? "En" : "Dis"); } else if (offset < 4) { /* ignored. */ } else if (offset >= 0x80) { diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c index b5a85e5673..bef76fc474 100644 --- a/hw/intc/arm_gic_common.c +++ b/hw/intc/arm_gic_common.c @@ -59,12 +59,12 @@ static const VMStateDescription vmstate_gic_irq_state = { static const VMStateDescription vmstate_gic = { .name = "arm_gic", - .version_id = 8, - .minimum_version_id = 8, + .version_id = 9, + .minimum_version_id = 9, .pre_save = gic_pre_save, .post_load = gic_post_load, .fields = (VMStateField[]) { - VMSTATE_BOOL(enabled, GICState), + VMSTATE_UINT32(ctlr, GICState), VMSTATE_BOOL_ARRAY(cpu_enabled, GICState, GIC_NCPU), VMSTATE_STRUCT_ARRAY(irq_state, GICState, GIC_MAXIRQ, 1, vmstate_gic_irq_state, gic_irq_state), @@ -146,7 +146,7 @@ static void arm_gic_common_reset(DeviceState *dev) s->irq_target[i] = 1; } } - s->enabled = false; + s->ctlr = 0; } static Property arm_gic_common_properties[] = { diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index 3591ca7d5d..4260fd8f04 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -353,8 +353,8 @@ static void kvm_arm_gic_put(GICState *s) * Distributor State */ - /* s->enabled -> GICD_CTLR */ - reg = s->enabled; + /* s->ctlr -> GICD_CTLR */ + reg = s->ctlr; kvm_gicd_access(s, 0x0, 0, ®, true); /* Sanity checking on GICD_TYPER and s->num_irq, s->num_cpu */ @@ -453,9 +453,9 @@ static void kvm_arm_gic_get(GICState *s) * Distributor State */ - /* GICD_CTLR -> s->enabled */ + /* GICD_CTLR -> s->ctlr */ kvm_gicd_access(s, 0x0, 0, ®, false); - s->enabled = reg & 1; + s->ctlr = reg; /* Sanity checking on GICD_TYPER -> s->num_irq, s->num_cpu */ kvm_gicd_access(s, 0x4, 0, ®, false); diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index ca19157c1e..16f0dca2d4 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -477,7 +477,7 @@ static void armv7m_nvic_reset(DeviceState *dev) s->gic.cpu_enabled[0] = true; s->gic.priority_mask[0] = 0x100; /* The NVIC as a whole is always enabled. */ - s->gic.enabled = true; + s->gic.ctlr = 1; systick_reset(s); } diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h index e8cf773e73..3b4b3fbc0e 100644 --- a/hw/intc/gic_internal.h +++ b/hw/intc/gic_internal.h @@ -54,6 +54,8 @@ #define GIC_SET_GROUP(irq, cm) (s->irq_state[irq].group |= (cm)) #define GIC_TEST_GROUP(irq, cm) ((s->irq_state[irq].group & (cm)) != 0) +#define GICD_CTLR_EN_GRP0 (1U << 0) +#define GICD_CTLR_EN_GRP1 (1U << 1) /* The special cases for the revision property: */ #define REV_11MPCORE 0 diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h index b78981ed58..d5d38772c2 100644 --- a/include/hw/intc/arm_gic_common.h +++ b/include/hw/intc/arm_gic_common.h @@ -52,7 +52,10 @@ typedef struct GICState { qemu_irq parent_irq[GIC_NCPU]; qemu_irq parent_fiq[GIC_NCPU]; - bool enabled; + /* GICD_CTLR; for a GIC with the security extensions the NS banked version + * of this register is just an alias of bit 1 of the S banked version. + */ + uint32_t ctlr; bool cpu_enabled[GIC_NCPU]; gic_irq_state irq_state[GIC_MAXIRQ]; -- cgit v1.2.3-55-g7522 From 822e9cc310484f77e0b1c16fbef763a5d0eec80a Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Tue, 12 May 2015 11:57:17 +0100 Subject: hw/intc/arm_gic: Make ICCBPR/GICC_BPR banked This register is banked in GICs with Security Extensions. Storing the non-secure copy of BPR in the abpr, which is an alias to the non-secure copy for secure access. ABPR itself is only accessible from secure state if the GIC implements Security Extensions. Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Edgar E. Iglesias Signed-off-by: Peter Maydell Message-id: 1430502643-25909-8-git-send-email-peter.maydell@linaro.org Message-id: 1429113742-8371-10-git-send-email-greg.bellows@linaro.org [PMM: rewrote to fix style issues and correct handling of GICv2 without security extensions] Signed-off-by: Peter Maydell --- hw/intc/arm_gic.c | 31 ++++++++++++++++++++++++++----- include/hw/intc/arm_gic_common.h | 11 ++++++++--- 2 files changed, 34 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 4f13ff2c90..e6ad8dea72 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -762,7 +762,12 @@ static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset, *data = s->priority_mask[cpu]; break; case 0x08: /* Binary Point */ - *data = s->bpr[cpu]; + if (s->security_extn && !attrs.secure) { + /* BPR is banked. Non-secure copy stored in ABPR. */ + *data = s->abpr[cpu]; + } else { + *data = s->bpr[cpu]; + } break; case 0x0c: /* Acknowledge */ *data = gic_acknowledge_irq(s, cpu); @@ -774,7 +779,16 @@ static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset, *data = s->current_pending[cpu]; break; case 0x1c: /* Aliased Binary Point */ - *data = s->abpr[cpu]; + /* GIC v2, no security: ABPR + * GIC v1, no security: not implemented (RAZ/WI) + * With security extensions, secure access: ABPR (alias of NS BPR) + * With security extensions, nonsecure access: RAZ/WI + */ + if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) { + *data = 0; + } else { + *data = s->abpr[cpu]; + } break; case 0xd0: case 0xd4: case 0xd8: case 0xdc: *data = s->apr[(offset - 0xd0) / 4][cpu]; @@ -799,14 +813,21 @@ static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset, s->priority_mask[cpu] = (value & 0xff); break; case 0x08: /* Binary Point */ - s->bpr[cpu] = (value & 0x7); + if (s->security_extn && !attrs.secure) { + s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR); + } else { + s->bpr[cpu] = MAX(value & 0x7, GIC_MIN_BPR); + } break; case 0x10: /* End Of Interrupt */ gic_complete_irq(s, cpu, value & 0x3ff); return MEMTX_OK; case 0x1c: /* Aliased Binary Point */ - if (s->revision >= 2) { - s->abpr[cpu] = (value & 0x7); + if (!gic_has_groups(s) || (s->security_extn && !attrs.secure)) { + /* unimplemented, or NS access: RAZ/WI */ + return MEMTX_OK; + } else { + s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR); } break; case 0xd0: case 0xd4: case 0xd8: case 0xdc: diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h index d5d38772c2..261402f86a 100644 --- a/include/hw/intc/arm_gic_common.h +++ b/include/hw/intc/arm_gic_common.h @@ -34,6 +34,9 @@ #define MAX_NR_GROUP_PRIO 128 #define GIC_NR_APRS (MAX_NR_GROUP_PRIO / 32) +#define GIC_MIN_BPR 0 +#define GIC_MIN_ABPR (GIC_MIN_BPR + 1) + typedef struct gic_irq_state { /* The enable bits are only banked for per-cpu interrupts. */ uint8_t enabled; @@ -76,9 +79,11 @@ typedef struct GICState { uint16_t running_priority[GIC_NCPU]; uint16_t current_pending[GIC_NCPU]; - /* We present the GICv2 without security extensions to a guest and - * therefore the guest can configure the GICC_CTLR to configure group 1 - * binary point in the abpr. + /* If we present the GICv2 without security extensions to a guest, + * the guest can configure the GICC_CTLR to configure group 1 binary point + * in the abpr. + * For a GIC with Security Extensions we use use bpr for the + * secure copy and abpr as storage for the non-secure copy of the register. */ uint8_t bpr[GIC_NCPU]; uint8_t abpr[GIC_NCPU]; -- cgit v1.2.3-55-g7522 From 32951860834f09d1c1a0b81d8d7d5529e2d0e074 Mon Sep 17 00:00:00 2001 From: Fabian Aggeler Date: Tue, 12 May 2015 11:57:17 +0100 Subject: hw/intc/arm_gic: Make ICCICR/GICC_CTLR banked ICCICR/GICC_CTLR is banked in GICv1 implementations with Security Extensions or in GICv2 in independent from Security Extensions. This makes it possible to enable forwarding of interrupts from the CPU interfaces to the connected processors for Group0 and Group1. We also allow to set additional bits like AckCtl and FIQEn by changing the type from bool to uint32. Since the field does not only store the enable bit anymore and since we are touching the vmstate, we use the opportunity to rename the field to cpu_ctlr. Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows Reviewed-by: Edgar E. Iglesias Signed-off-by: Peter Maydell Message-id: 1430502643-25909-9-git-send-email-peter.maydell@linaro.org Message-id: 1429113742-8371-9-git-send-email-greg.bellows@linaro.org [PMM: rewrote to store state in a single uint32_t rather than keeping the NS and S banked variants separate; this considerably simplifies the get/set functions] Signed-off-by: Peter Maydell --- hw/intc/arm_gic.c | 51 ++++++++++++++++++++++++++++++++++++---- hw/intc/arm_gic_common.c | 8 +++---- hw/intc/arm_gic_kvm.c | 8 +++---- hw/intc/armv7m_nvic.c | 2 +- hw/intc/gic_internal.h | 16 +++++++++++++ include/hw/intc/arm_gic_common.h | 5 +++- 6 files changed, 76 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index e6ad8dea72..4aaaac2de3 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -68,7 +68,7 @@ void gic_update(GICState *s) cm = 1 << cpu; s->current_pending[cpu] = 1023; if (!(s->ctlr & (GICD_CTLR_EN_GRP0 | GICD_CTLR_EN_GRP1)) - || !s->cpu_enabled[cpu]) { + || !(s->cpu_ctlr[cpu] & (GICC_CTLR_EN_GRP0 | GICC_CTLR_EN_GRP1))) { qemu_irq_lower(s->parent_irq[cpu]); return; } @@ -242,6 +242,50 @@ void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val) } } +static uint32_t gic_get_cpu_control(GICState *s, int cpu, MemTxAttrs attrs) +{ + uint32_t ret = s->cpu_ctlr[cpu]; + + if (s->security_extn && !attrs.secure) { + /* Construct the NS banked view of GICC_CTLR from the correct + * bits of the S banked view. We don't need to move the bypass + * control bits because we don't implement that (IMPDEF) part + * of the GIC architecture. + */ + ret = (ret & (GICC_CTLR_EN_GRP1 | GICC_CTLR_EOIMODE_NS)) >> 1; + } + return ret; +} + +static void gic_set_cpu_control(GICState *s, int cpu, uint32_t value, + MemTxAttrs attrs) +{ + uint32_t mask; + + if (s->security_extn && !attrs.secure) { + /* The NS view can only write certain bits in the register; + * the rest are unchanged + */ + mask = GICC_CTLR_EN_GRP1; + if (s->revision == 2) { + mask |= GICC_CTLR_EOIMODE_NS; + } + s->cpu_ctlr[cpu] &= ~mask; + s->cpu_ctlr[cpu] |= (value << 1) & mask; + } else { + if (s->revision == 2) { + mask = s->security_extn ? GICC_CTLR_V2_S_MASK : GICC_CTLR_V2_MASK; + } else { + mask = s->security_extn ? GICC_CTLR_V1_S_MASK : GICC_CTLR_V1_MASK; + } + s->cpu_ctlr[cpu] = value & mask; + } + DPRINTF("CPU Interface %d: Group0 Interrupts %sabled, " + "Group1 Interrupts %sabled\n", cpu, + (s->cpu_ctlr[cpu] & GICC_CTLR_EN_GRP0) ? "En" : "Dis", + (s->cpu_ctlr[cpu] & GICC_CTLR_EN_GRP1) ? "En" : "Dis"); +} + void gic_complete_irq(GICState *s, int cpu, int irq) { int update = 0; @@ -756,7 +800,7 @@ static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset, { switch (offset) { case 0x00: /* Control */ - *data = s->cpu_enabled[cpu]; + *data = gic_get_cpu_control(s, cpu, attrs); break; case 0x04: /* Priority mask */ *data = s->priority_mask[cpu]; @@ -806,8 +850,7 @@ static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset, { switch (offset) { case 0x00: /* Control */ - s->cpu_enabled[cpu] = (value & 1); - DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled[cpu] ? "En" : "Dis"); + gic_set_cpu_control(s, cpu, value, attrs); break; case 0x04: /* Priority mask */ s->priority_mask[cpu] = (value & 0xff); diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c index bef76fc474..044ad66730 100644 --- a/hw/intc/arm_gic_common.c +++ b/hw/intc/arm_gic_common.c @@ -59,13 +59,13 @@ static const VMStateDescription vmstate_gic_irq_state = { static const VMStateDescription vmstate_gic = { .name = "arm_gic", - .version_id = 9, - .minimum_version_id = 9, + .version_id = 10, + .minimum_version_id = 10, .pre_save = gic_pre_save, .post_load = gic_post_load, .fields = (VMStateField[]) { VMSTATE_UINT32(ctlr, GICState), - VMSTATE_BOOL_ARRAY(cpu_enabled, GICState, GIC_NCPU), + VMSTATE_UINT32_ARRAY(cpu_ctlr, GICState, GIC_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), @@ -134,7 +134,7 @@ static void arm_gic_common_reset(DeviceState *dev) s->current_pending[i] = 1023; s->running_irq[i] = 1023; s->running_priority[i] = 0x100; - s->cpu_enabled[i] = false; + s->cpu_ctlr[i] = 0; } for (i = 0; i < GIC_NR_SGIS; i++) { GIC_SET_ENABLED(i, ALL_CPU_MASK); diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index 4260fd8f04..33e6a87b3c 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -414,8 +414,8 @@ static void kvm_arm_gic_put(GICState *s) */ for (cpu = 0; cpu < s->num_cpu; cpu++) { - /* s->cpu_enabled[cpu] -> GICC_CTLR */ - reg = s->cpu_enabled[cpu]; + /* s->cpu_ctlr[cpu] -> GICC_CTLR */ + reg = s->cpu_ctlr[cpu]; kvm_gicc_access(s, 0x00, cpu, ®, true); /* s->priority_mask[cpu] -> GICC_PMR */ @@ -506,9 +506,9 @@ static void kvm_arm_gic_get(GICState *s) */ for (cpu = 0; cpu < s->num_cpu; cpu++) { - /* GICC_CTLR -> s->cpu_enabled[cpu] */ + /* GICC_CTLR -> s->cpu_ctlr[cpu] */ kvm_gicc_access(s, 0x00, cpu, ®, false); - s->cpu_enabled[cpu] = (reg & 1); + s->cpu_ctlr[cpu] = reg; /* GICC_PMR -> s->priority_mask[cpu] */ kvm_gicc_access(s, 0x04, cpu, ®, false); diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 16f0dca2d4..a6567a378d 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -474,7 +474,7 @@ static void armv7m_nvic_reset(DeviceState *dev) * as enabled by default, and with a priority mask which allows * all interrupts through. */ - s->gic.cpu_enabled[0] = true; + 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; diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h index 3b4b3fbc0e..81c764c100 100644 --- a/hw/intc/gic_internal.h +++ b/hw/intc/gic_internal.h @@ -57,6 +57,22 @@ #define GICD_CTLR_EN_GRP0 (1U << 0) #define GICD_CTLR_EN_GRP1 (1U << 1) +#define GICC_CTLR_EN_GRP0 (1U << 0) +#define GICC_CTLR_EN_GRP1 (1U << 1) +#define GICC_CTLR_ACK_CTL (1U << 2) +#define GICC_CTLR_FIQ_EN (1U << 3) +#define GICC_CTLR_CBPR (1U << 4) /* GICv1: SBPR */ +#define GICC_CTLR_EOIMODE (1U << 9) +#define GICC_CTLR_EOIMODE_NS (1U << 10) + +/* Valid bits for GICC_CTLR for GICv1, v1 with security extensions, + * GICv2 and GICv2 with security extensions: + */ +#define GICC_CTLR_V1_MASK 0x1 +#define GICC_CTLR_V1_S_MASK 0x1f +#define GICC_CTLR_V2_MASK 0x21f +#define GICC_CTLR_V2_S_MASK 0x61f + /* The special cases for the revision property: */ #define REV_11MPCORE 0 #define REV_NVIC 0xffffffff diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h index 261402f86a..899db3d7a0 100644 --- a/include/hw/intc/arm_gic_common.h +++ b/include/hw/intc/arm_gic_common.h @@ -59,7 +59,10 @@ typedef struct GICState { * of this register is just an alias of bit 1 of the S banked version. */ uint32_t ctlr; - bool cpu_enabled[GIC_NCPU]; + /* GICC_CTLR; again, the NS banked version is just aliases of bits of + * the S banked register, so our state only needs to store the S version. + */ + uint32_t cpu_ctlr[GIC_NCPU]; gic_irq_state irq_state[GIC_MAXIRQ]; uint8_t irq_target[GIC_MAXIRQ]; -- cgit v1.2.3-55-g7522