diff options
author | Fabian Aggeler <aggelerf@ethz.ch> | 2015-05-12 11:57:17 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2015-05-12 11:57:17 +0100 |
commit | 8150847061f8d2606101bfff77cc6ec86b081ab0 (patch) | |
tree | 8447b726a34d0a104d2282145e3eb3f004f6b3d2 | |
parent | 08efa9f2d1bb27d64fbedcc2879ca45ae6832c20 (diff) |
hw/intc/arm_gic: Restrict priority view
GICs with Security Extensions restrict the non-secure view of the
interrupt priority and priority mask registers.
Signed-off-by: Fabian Aggeler <aggelerf@ethz.ch>
Signed-off-by: Greg Bellows <greg.bellows@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1430502643-25909-11-git-send-email-peter.maydell@linaro.org
Message-id: 1429113742-8371-15-git-send-email-greg.bellows@linaro.org
[PMM: minor code tweaks; fixed missing masking in gic_set_priority_mask
and gic_set_priority]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | hw/intc/arm_gic.c | 63 | ||||
-rw-r--r-- | hw/intc/arm_gic_kvm.c | 2 | ||||
-rw-r--r-- | hw/intc/gic_internal.h | 3 |
3 files changed, 61 insertions, 7 deletions
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index e3bbe9e9e0..7c0ddc85cf 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -233,8 +233,16 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu) return ret; } -void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val) +void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val, + MemTxAttrs attrs) { + if (s->security_extn && !attrs.secure) { + if (!GIC_TEST_GROUP(irq, (1 << cpu))) { + return; /* Ignore Non-secure access of Group0 IRQ */ + } + val = 0x80 | (val >> 1); /* Non-secure view */ + } + if (irq < GIC_INTERNAL) { s->priority1[irq][cpu] = val; } else { @@ -242,6 +250,51 @@ void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val) } } +static uint32_t gic_get_priority(GICState *s, int cpu, int irq, + MemTxAttrs attrs) +{ + uint32_t prio = GIC_GET_PRIORITY(irq, cpu); + + if (s->security_extn && !attrs.secure) { + if (!GIC_TEST_GROUP(irq, (1 << cpu))) { + return 0; /* Non-secure access cannot read priority of Group0 IRQ */ + } + prio = (prio << 1) & 0xff; /* Non-secure view */ + } + return prio; +} + +static void gic_set_priority_mask(GICState *s, int cpu, uint8_t pmask, + MemTxAttrs attrs) +{ + if (s->security_extn && !attrs.secure) { + if (s->priority_mask[cpu] & 0x80) { + /* Priority Mask in upper half */ + pmask = 0x80 | (pmask >> 1); + } else { + /* Non-secure write ignored if priority mask is in lower half */ + return; + } + } + s->priority_mask[cpu] = pmask; +} + +static uint32_t gic_get_priority_mask(GICState *s, int cpu, MemTxAttrs attrs) +{ + uint32_t pmask = s->priority_mask[cpu]; + + if (s->security_extn && !attrs.secure) { + if (pmask & 0x80) { + /* Priority Mask in upper half, return Non-secure view */ + pmask = (pmask << 1) & 0xff; + } else { + /* Priority Mask in lower half, RAZ */ + pmask = 0; + } + } + return pmask; +} + static uint32_t gic_get_cpu_control(GICState *s, int cpu, MemTxAttrs attrs) { uint32_t ret = s->cpu_ctlr[cpu]; @@ -451,7 +504,7 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs) irq = (offset - 0x400) + GIC_BASE_IRQ; if (irq >= s->num_irq) goto bad_reg; - res = GIC_GET_PRIORITY(irq, cpu); + res = gic_get_priority(s, cpu, irq, attrs); } else if (offset < 0xc00) { /* Interrupt CPU Target. */ if (s->num_cpu == 1 && s->revision != REV_11MPCORE) { @@ -669,7 +722,7 @@ static void gic_dist_writeb(void *opaque, hwaddr offset, irq = (offset - 0x400) + GIC_BASE_IRQ; if (irq >= s->num_irq) goto bad_reg; - gic_set_priority(s, cpu, irq, value); + gic_set_priority(s, cpu, irq, value, attrs); } else if (offset < 0xc00) { /* Interrupt CPU Target. RAZ/WI on uniprocessor GICs, with the * annoying exception of the 11MPCore's GIC. @@ -820,7 +873,7 @@ static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset, *data = gic_get_cpu_control(s, cpu, attrs); break; case 0x04: /* Priority mask */ - *data = s->priority_mask[cpu]; + *data = gic_get_priority_mask(s, cpu, attrs); break; case 0x08: /* Binary Point */ if (s->security_extn && !attrs.secure) { @@ -870,7 +923,7 @@ static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset, gic_set_cpu_control(s, cpu, value, attrs); break; case 0x04: /* Priority mask */ - s->priority_mask[cpu] = (value & 0xff); + gic_set_priority_mask(s, cpu, value, attrs); break; case 0x08: /* Binary Point */ if (s->security_extn && !attrs.secure) { diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index 33e6a87b3c..2cb7d255d2 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -251,7 +251,7 @@ static void translate_priority(GICState *s, int irq, int cpu, if (to_kernel) { *field = GIC_GET_PRIORITY(irq, cpu) & 0xff; } else { - gic_set_priority(s, cpu, irq, *field & 0xff); + gic_set_priority(s, cpu, irq, *field & 0xff, MEMTXATTRS_UNSPECIFIED); } } diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h index 81c764c100..119fb8147e 100644 --- a/hw/intc/gic_internal.h +++ b/hw/intc/gic_internal.h @@ -82,7 +82,8 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu); void gic_complete_irq(GICState *s, int cpu, int irq); void gic_update(GICState *s); void gic_init_irqs_and_distributor(GICState *s); -void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val); +void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val, + MemTxAttrs attrs); static inline bool gic_test_pending(GICState *s, int irq, int cm) { |