On 22 August 2014 05:29, Fabian Aggeler wrote: > 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 */ > This should probably be masked to avoid a return containing reserved bits or only return a uint8_t. > } > + 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; > Again this should probably be masked to prevent returning a value with reserved bits set. > + } > + } > + 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 > >