summaryrefslogtreecommitdiff
path: root/hw/intc
diff options
context:
space:
mode:
Diffstat (limited to 'hw/intc')
-rw-r--r--hw/intc/arm_gic.c25
1 files changed, 21 insertions, 4 deletions
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
index d701e49ff9..724bc9fa61 100644
--- a/hw/intc/arm_gic.c
+++ b/hw/intc/arm_gic.c
@@ -93,6 +93,7 @@ void gic_update(GICState *s)
best_irq = 1023;
for (irq = 0; irq < s->num_irq; irq++) {
if (GIC_TEST_ENABLED(irq, cm) && gic_test_pending(s, irq, cm) &&
+ (!GIC_TEST_ACTIVE(irq, cm)) &&
(irq < GIC_INTERNAL || GIC_TARGET(irq) & cm)) {
if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
best_prio = GIC_GET_PRIORITY(irq, cpu);
@@ -255,7 +256,8 @@ static int gic_get_group_priority(GICState *s, int cpu, int irq)
if (gic_has_groups(s) &&
!(s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) &&
GIC_TEST_GROUP(irq, (1 << cpu))) {
- bpr = s->abpr[cpu];
+ bpr = s->abpr[cpu] - 1;
+ assert(bpr >= 0);
} else {
bpr = s->bpr[cpu];
}
@@ -503,6 +505,11 @@ static void gic_set_cpu_control(GICState *s, int cpu, uint32_t value,
static uint8_t gic_get_running_priority(GICState *s, int cpu, MemTxAttrs attrs)
{
+ if ((s->revision != REV_11MPCORE) && (s->running_priority[cpu] > 0xff)) {
+ /* Idle priority */
+ return 0xff;
+ }
+
if (s->security_extn && !attrs.secure) {
if (s->running_priority[cpu] & 0x80) {
/* Running priority in upper half of range: return the Non-secure
@@ -1205,8 +1212,13 @@ static MemTxResult gic_cpu_read(GICState *s, int cpu, int offset,
break;
case 0x08: /* Binary Point */
if (s->security_extn && !attrs.secure) {
- /* BPR is banked. Non-secure copy stored in ABPR. */
- *data = s->abpr[cpu];
+ if (s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) {
+ /* NS view of BPR when CBPR is 1 */
+ *data = MIN(s->bpr[cpu] + 1, 7);
+ } else {
+ /* BPR is banked. Non-secure copy stored in ABPR. */
+ *data = s->abpr[cpu];
+ }
} else {
*data = s->bpr[cpu];
}
@@ -1279,7 +1291,12 @@ static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset,
break;
case 0x08: /* Binary Point */
if (s->security_extn && !attrs.secure) {
- s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR);
+ if (s->cpu_ctlr[cpu] & GICC_CTLR_CBPR) {
+ /* WI when CBPR is 1 */
+ return MEMTX_OK;
+ } else {
+ s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR);
+ }
} else {
s->bpr[cpu] = MAX(value & 0x7, GIC_MIN_BPR);
}