Commit 4352300804 for qemu.org
commit 43523008040e39044a8fa91d020460f65705a6bb
Author: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Date: Mon Nov 9 13:52:08 2026 +0000
hw/intc/arm_gic: do not hardcode GICv2 minimum binary point
The number of priority bits is implementation defined, and indeed
machines such as a9mpcore and arm11mpcore define it in the
num-priority-bits property. However we still hardcoded GIC_MIN_BPR.
This commit replaces the GIC_MIN_BPR and GIC_MIN_ABPR defs with macros
that read the property.
The calculation is based on "Table 4-47 Active Priorities register
implementation" in the GICv2 spec (page 4-150 of ARM IHI 0048B.b
ID072613):
+---------------+---------------+---------------+
| | | Maximum |
| Minimum value | Minimum value | number of |
| of Secure | of Non-secure | group |
| GICC_BPR | GICC_BPR | priority bits |
+===============+===============+===============+
| 3 | 4 | 4 |
| 2 | 3 | 5 |
| 1 | 2 | 6 |
| 0 | 1 | 7 |
+---------------+---------------+---------------+
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4375
Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Message-id: 20261106-gic_read_bpr_from_property-v2-1-9f096cce4814@linaro.org
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
index b60f1f630b..0236f45c3d 100644
--- a/hw/intc/arm_gic.c
+++ b/hw/intc/arm_gic.c
@@ -479,7 +479,7 @@ static void gic_activate_irq(GICState *s, int cpu, int irq)
* and update the running priority.
*/
int prio = gic_get_group_priority(s, cpu, irq);
- int min_bpr = gic_is_vcpu(cpu) ? GIC_VIRT_MIN_BPR : GIC_MIN_BPR;
+ int min_bpr = gic_is_vcpu(cpu) ? GIC_VIRT_MIN_BPR : gic_min_bpr(s);
int preemption_level = prio >> (min_bpr + 1);
int regno = preemption_level / 32;
int bitno = preemption_level % 32;
@@ -521,7 +521,7 @@ static int gic_get_prio_from_apr_bits(GICState *s, int cpu)
if (!apr) {
continue;
}
- return (i * 32 + ctz32(apr)) << (GIC_MIN_BPR + 1);
+ return (i * 32 + ctz32(apr)) << (gic_min_bpr(s) + 1);
}
return 0x100;
}
@@ -1561,7 +1561,7 @@ static inline uint32_t gic_apr_ns_view(GICState *s, int cpu, int regno)
/* Return the Nonsecure view of GICC_APR<regno>. This is the
* second half of GICC_NSAPR.
*/
- switch (GIC_MIN_BPR) {
+ switch (gic_min_bpr(s)) {
case 0:
if (regno < 2) {
return s->nsapr[regno + 2][cpu];
@@ -1592,7 +1592,7 @@ static inline void gic_apr_write_ns_view(GICState *s, int cpu, int regno,
uint32_t value)
{
/* Write the Nonsecure view of GICC_APR<regno>. */
- switch (GIC_MIN_BPR) {
+ switch (gic_min_bpr(s)) {
case 0:
if (regno < 2) {
s->nsapr[regno + 2][cpu] = value;
@@ -1731,10 +1731,10 @@ static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset,
/* WI when CBPR is 1 */
return MEMTX_OK;
} else {
- s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR);
+ s->abpr[cpu] = MAX(value & 0x7, gic_min_abpr(s));
}
} else {
- int min_bpr = gic_is_vcpu(cpu) ? GIC_VIRT_MIN_BPR : GIC_MIN_BPR;
+ int min_bpr = gic_is_vcpu(cpu) ? GIC_VIRT_MIN_BPR : gic_min_bpr(s);
s->bpr[cpu] = MAX(value & 0x7, min_bpr);
}
break;
@@ -1746,7 +1746,7 @@ static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset,
/* unimplemented, or NS access: RAZ/WI */
return MEMTX_OK;
} else {
- s->abpr[cpu] = MAX(value & 0x7, GIC_MIN_ABPR);
+ s->abpr[cpu] = MAX(value & 0x7, gic_min_abpr(s));
}
break;
case 0xd0: case 0xd4: case 0xd8: case 0xdc:
diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c
index a7c0763ab6..fec5662d69 100644
--- a/hw/intc/arm_gic_common.c
+++ b/hw/intc/arm_gic_common.c
@@ -259,8 +259,8 @@ static inline void arm_gic_common_reset_irq_state(GICState *s, int cidx,
s->current_pending[i] = 1023;
s->running_priority[i] = 0x100;
s->cpu_ctlr[i] = 0;
- s->bpr[i] = gic_is_vcpu(i) ? GIC_VIRT_MIN_BPR : GIC_MIN_BPR;
- s->abpr[i] = gic_is_vcpu(i) ? GIC_VIRT_MIN_ABPR : GIC_MIN_ABPR;
+ s->bpr[i] = gic_is_vcpu(i) ? GIC_VIRT_MIN_BPR : gic_min_bpr(s);
+ s->abpr[i] = gic_is_vcpu(i) ? GIC_VIRT_MIN_ABPR : gic_min_abpr(s);
if (!gic_is_vcpu(i)) {
for (j = 0; j < GIC_INTERNAL; j++) {
diff --git a/include/hw/intc/arm_gic.h b/include/hw/intc/arm_gic.h
index be923f7ed8..a1f4a2eeba 100644
--- a/include/hw/intc/arm_gic.h
+++ b/include/hw/intc/arm_gic.h
@@ -72,8 +72,6 @@
/* Number of SGI target-list bits */
#define GIC_TARGETLIST_BITS 8
-#define GIC_MAX_PRIORITY_BITS 8
-#define GIC_MIN_PRIORITY_BITS 4
#define TYPE_ARM_GIC "arm_gic"
typedef struct ARMGICClass ARMGICClass;
diff --git a/include/hw/intc/arm_gic_common.h b/include/hw/intc/arm_gic_common.h
index b169394e6c..db7370a80a 100644
--- a/include/hw/intc/arm_gic_common.h
+++ b/include/hw/intc/arm_gic_common.h
@@ -37,8 +37,8 @@
#define MAX_NR_GROUP_PRIO 128
#define GIC_NR_APRS (MAX_NR_GROUP_PRIO / 32)
-#define GIC_MIN_BPR 0
-#define GIC_MIN_ABPR (GIC_MIN_BPR + 1)
+#define GIC_MAX_PRIORITY_BITS 8
+#define GIC_MIN_PRIORITY_BITS 4
/* Architectural maximum number of list registers in the virtual interface */
#define GIC_MAX_LR 64
@@ -151,6 +151,20 @@ struct GICState {
};
typedef struct GICState GICState;
+
+static inline uint32_t gic_min_bpr(GICState *s)
+{
+ uint32_t num_preemption_bits = s->n_prio_bits == 8 ? 7 : s->n_prio_bits;
+ assert(!(s->n_prio_bits > GIC_MAX_PRIORITY_BITS
+ || s->n_prio_bits < GIC_MIN_PRIORITY_BITS));
+ return 7 - num_preemption_bits;
+}
+
+static inline uint32_t gic_min_abpr(GICState *s)
+{
+ return gic_min_bpr(s) + 1;
+}
+
#define TYPE_ARM_GIC_COMMON "arm_gic_common"
typedef struct ARMGICCommonClass ARMGICCommonClass;
DECLARE_OBJ_CHECKERS(GICState, ARMGICCommonClass,