From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49267) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XKm70-0001zp-3Z for qemu-devel@nongnu.org; Fri, 22 Aug 2014 06:30:32 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1XKm6q-00049Y-KT for qemu-devel@nongnu.org; Fri, 22 Aug 2014 06:30:26 -0400 Received: from edge20.ethz.ch ([82.130.99.26]:57019) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XKm6q-00047W-7B for qemu-devel@nongnu.org; Fri, 22 Aug 2014 06:30:16 -0400 From: Fabian Aggeler Date: Fri, 22 Aug 2014 12:29:50 +0200 Message-ID: <1408703392-23893-14-git-send-email-aggelerf@ethz.ch> In-Reply-To: <1408703392-23893-1-git-send-email-aggelerf@ethz.ch> References: <1408703392-23893-1-git-send-email-aggelerf@ethz.ch> MIME-Version: 1.0 Content-Type: text/plain Subject: [Qemu-devel] [PATCH 13/15] hw/intc/arm_gic: Restrict priority view List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: peter.maydell@linaro.org, greg.bellows@linaro.org, christoffer.dall@linaro.org, edgar.iglesias@gmail.com GICs with Security Extensions restrict the non-secure view of the interrupt priority and priority mask registers. Signed-off-by: Fabian Aggeler --- hw/intc/arm_gic.c | 66 +++++++++++++++++++++++++++++++++++++++++++++----- hw/intc/gic_internal.h | 3 +++ 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index cddad45..3fe5f09 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -256,11 +256,66 @@ uint32_t gic_acknowledge_irq(GICState *s, int cpu) void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val) { + uint8_t prio = val; + + if (s->security_extn && ns_access()) { + if (GIC_TEST_GROUP0(irq, (1 << cpu))) { + return; /* Ignore Non-secure access of Group0 IRQ */ + } + prio = 0x80 | (prio >> 1); /* Non-secure view */ + } + if (irq < GIC_INTERNAL) { - s->priority1[irq][cpu] = val; + s->priority1[irq][cpu] = prio; } else { - s->priority2[(irq) - GIC_INTERNAL] = val; + s->priority2[(irq) - GIC_INTERNAL] = prio; + } +} + +uint32_t gic_get_priority(GICState *s, int cpu, int irq) +{ + uint32_t prio = GIC_GET_PRIORITY(irq, cpu); + + if (s->security_extn && ns_access()) { + if (GIC_TEST_GROUP0(irq, (1 << cpu))) { + return 0; /* Non-secure access cannot read priority of Group0 IRQ */ + } + prio = (prio << 1); /* Non-secure view */ } + return prio; +} + +void gic_set_priority_mask(GICState *s, int cpu, uint8_t val) +{ + uint8_t pmask = (val & 0xff); + + if (s->security_extn && ns_access()) { + 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; +} + +uint32_t gic_get_priority_mask(GICState *s, int cpu) +{ + uint32_t pmask = s->priority_mask[cpu]; + + if (s->security_extn && ns_access()) { + if (pmask & 0x80) { + /* Priority Mask in upper half, return Non-secure view */ + pmask = (pmask << 1); + } else { + /* Priority Mask in lower half, RAZ */ + pmask = 0; + } + } + return pmask; + } uint32_t gic_get_cpu_control(GICState *s, int cpu) @@ -518,7 +573,7 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset) 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); } else if (offset < 0xc00) { /* Interrupt CPU Target. */ if (s->num_cpu == 1 && s->revision != REV_11MPCORE) { @@ -871,7 +926,7 @@ static uint32_t gic_cpu_read(GICState *s, int cpu, int offset) case 0x00: /* Control */ return gic_get_cpu_control(s, cpu); case 0x04: /* Priority mask */ - return s->priority_mask[cpu]; + return gic_get_priority_mask(s, cpu); case 0x08: /* Binary Point */ if (s->security_extn && ns_access()) { /* BPR is banked. Non-secure copy stored in ABPR. */ @@ -909,8 +964,7 @@ static void gic_cpu_write(GICState *s, int cpu, int offset, uint32_t value) case 0x00: /* Control */ return gic_set_cpu_control(s, cpu, value); case 0x04: /* Priority mask */ - s->priority_mask[cpu] = (value & 0xff); - break; + return gic_set_priority_mask(s, cpu, value); case 0x08: /* Binary Point */ if (s->security_extn && ns_access()) { /* BPR is banked. Non-secure copy stored in ABPR. */ diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h index 17632c1..8d951cc 100644 --- a/hw/intc/gic_internal.h +++ b/hw/intc/gic_internal.h @@ -76,6 +76,9 @@ void gic_complete_irq(GICState *s, int cpu, int irq); void gic_update(GICState *s); void gic_init_irqs_and_distributor(GICState *s, int num_irq); void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val); +uint32_t gic_get_priority(GICState *s, int cpu, int irq); +void gic_set_priority_mask(GICState *s, int cpu, uint8_t val); +uint32_t gic_get_priority_mask(GICState *s, int cpu); uint32_t gic_get_cpu_control(GICState *s, int cpu); void gic_set_cpu_control(GICState *s, int cpu, uint32_t value); uint8_t gic_get_running_priority(GICState *s, int cpu); -- 1.8.3.2