From patchwork Fri May 1 17:50:36 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 467058 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id A83851402B0 for ; Sat, 2 May 2015 03:53:32 +1000 (AEST) Received: from localhost ([::1]:55004 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YoF7y-00026i-Ta for incoming@patchwork.ozlabs.org; Fri, 01 May 2015 13:53:30 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:58033) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YoF5S-00056X-Io for qemu-devel@nongnu.org; Fri, 01 May 2015 13:50:55 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YoF5R-0002aX-FA for qemu-devel@nongnu.org; Fri, 01 May 2015 13:50:54 -0400 Received: from mnementh.archaic.org.uk ([2001:8b0:1d0::1]:34037) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YoF5R-0002Wq-7F for qemu-devel@nongnu.org; Fri, 01 May 2015 13:50:53 -0400 Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.80) (envelope-from ) id 1YoF5I-0006kz-1z; Fri, 01 May 2015 18:50:44 +0100 From: Peter Maydell To: qemu-devel@nongnu.org Date: Fri, 1 May 2015 18:50:36 +0100 Message-Id: <1430502643-25909-11-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1430502643-25909-1-git-send-email-peter.maydell@linaro.org> References: <1430502643-25909-1-git-send-email-peter.maydell@linaro.org> X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2001:8b0:1d0::1 Cc: "Edgar E. Iglesias" , Greg Bellows , patches@linaro.org Subject: [Qemu-devel] [PATCH v4 10/17] hw/intc/arm_gic: Restrict priority view X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Fabian Aggeler GICs with Security Extensions restrict the non-secure view of the interrupt priority and priority mask registers. Signed-off-by: Fabian Aggeler Signed-off-by: Greg Bellows 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 Reviewed-by: Edgar E. Iglesias --- hw/intc/arm_gic.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++---- hw/intc/arm_gic_kvm.c | 2 +- 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 e3bbe9e..7c0ddc8 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 c5a2f81..54f18df 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 81c764c..119fb81 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) {