dev-arm: Rewrite ICC_BPR0/ICC_BPR1 handling

The patch is fixing BPR reads in AA32, by removing the line

Gicv3::GroupId group =
    misc_reg == MISCREG_ICC_BPR0_EL1 ? Gicv3::G0S : Gicv3::G1S;

Where a read to ICC_BPR0 will return a G1S group.
The patch is also fixing Security banking accesses.

Change-Id: I28f1d1244c44d4b8b202d3141f8380943c7c1c86
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/20620
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
diff --git a/src/dev/arm/gic_v3_cpu_interface.cc b/src/dev/arm/gic_v3_cpu_interface.cc
index b8752dd..cc630b4 100644
--- a/src/dev/arm/gic_v3_cpu_interface.cc
+++ b/src/dev/arm/gic_v3_cpu_interface.cc
@@ -304,102 +304,45 @@
 
       // Binary Point Register 0
       case MISCREG_ICC_BPR0:
-      case MISCREG_ICC_BPR0_EL1:
+      case MISCREG_ICC_BPR0_EL1: {
         if ((currEL() == EL1) && !inSecureState() && hcr_fmo) {
             return readMiscReg(MISCREG_ICV_BPR0_EL1);
         }
 
-        M5_FALLTHROUGH;
+        value = isa->readMiscRegNoEffect(MISCREG_ICC_BPR0_EL1);
+        break;
+      }
 
       // Binary Point Register 1
       case MISCREG_ICC_BPR1:
       case MISCREG_ICC_BPR1_EL1: {
-            if ((currEL() == EL1) && !inSecureState() && hcr_imo) {
-                return readMiscReg(MISCREG_ICV_BPR1_EL1);
-            }
+        value = bpr1(isSecureBelowEL3() ? Gicv3::G1S : Gicv3::G1NS);
+        break;
+      }
 
-            Gicv3::GroupId group =
-                misc_reg == MISCREG_ICC_BPR0_EL1 ? Gicv3::G0S : Gicv3::G1S;
+      // Virtual Binary Point Register 0
+      case MISCREG_ICV_BPR0_EL1: {
+        ICH_VMCR_EL2 ich_vmcr_el2 =
+            isa->readMiscRegNoEffect(MISCREG_ICH_VMCR_EL2);
 
-            if (group == Gicv3::G1S && !inSecureState()) {
-                group = Gicv3::G1NS;
-            }
-
-            ICC_CTLR_EL1 icc_ctlr_el1_s =
-                isa->readMiscRegNoEffect(MISCREG_ICC_CTLR_EL1_S);
-
-            if ((group == Gicv3::G1S) && !isEL3OrMon() &&
-                icc_ctlr_el1_s.CBPR) {
-                group = Gicv3::G0S;
-            }
-
-            bool sat_inc = false;
-
-            ICC_CTLR_EL1 icc_ctlr_el1_ns =
-                isa->readMiscRegNoEffect(MISCREG_ICC_CTLR_EL1_NS);
-
-            if ((group == Gicv3::G1NS) && (currEL() < EL3) &&
-                icc_ctlr_el1_ns.CBPR) {
-                // Reads return BPR0 + 1 saturated to 7, WI
-                group = Gicv3::G0S;
-                sat_inc = true;
-            }
-
-            uint8_t bpr;
-
-            if (group == Gicv3::G0S) {
-                bpr = isa->readMiscRegNoEffect(MISCREG_ICC_BPR0_EL1);
-            } else {
-                bpr = isa->readMiscRegNoEffect(MISCREG_ICC_BPR1_EL1);
-                bpr = std::max(bpr, group == Gicv3::G1S ?
-                    GIC_MIN_BPR : GIC_MIN_BPR_NS);
-            }
-
-            if (sat_inc) {
-                bpr++;
-
-                if (bpr > 7) {
-                    bpr = 7;
-                }
-            }
-
-            value = bpr;
-            break;
+        value = ich_vmcr_el2.VBPR0;
+        break;
       }
 
       // Virtual Binary Point Register 1
-      case MISCREG_ICV_BPR0_EL1:
       case MISCREG_ICV_BPR1_EL1: {
-          Gicv3::GroupId group =
-              misc_reg == MISCREG_ICV_BPR0_EL1 ? Gicv3::G0S : Gicv3::G1NS;
-          ICH_VMCR_EL2 ich_vmcr_el2 =
-              isa->readMiscRegNoEffect(MISCREG_ICH_VMCR_EL2);
-          bool sat_inc = false;
+        ICH_VMCR_EL2 ich_vmcr_el2 =
+            isa->readMiscRegNoEffect(MISCREG_ICH_VMCR_EL2);
 
-          if ((group == Gicv3::G1NS) && ich_vmcr_el2.VCBPR) {
-              // bpr0 + 1 saturated to 7, WI
-              group = Gicv3::G0S;
-              sat_inc = true;
-          }
+        if (ich_vmcr_el2.VCBPR) {
+            // bpr0 + 1 saturated to 7, WI
+            value = ich_vmcr_el2.VBPR0 + 1;
+            value = value < 7 ? value : 7;
+        } else {
+            value = ich_vmcr_el2.VBPR1;
+        }
 
-          uint8_t vbpr;
-
-          if (group == Gicv3::G0S) {
-              vbpr = ich_vmcr_el2.VBPR0;
-          } else {
-              vbpr = ich_vmcr_el2.VBPR1;
-          }
-
-          if (sat_inc) {
-              vbpr++;
-
-              if (vbpr > 7) {
-                  vbpr = 7;
-              }
-          }
-
-          value = vbpr;
-          break;
+        break;
       }
 
       // Interrupt Priority Mask Register
@@ -1093,51 +1036,48 @@
 
       // Binary Point Register 0
       case MISCREG_ICC_BPR0:
-      case MISCREG_ICC_BPR0_EL1:
+      case MISCREG_ICC_BPR0_EL1: {
+        if ((currEL() == EL1) && !inSecureState() && hcr_fmo) {
+            return setMiscReg(MISCREG_ICV_BPR0_EL1, val);
+        }
+        break;
+      }
       // Binary Point Register 1
       case MISCREG_ICC_BPR1:
       case MISCREG_ICC_BPR1_EL1: {
-          if ((currEL() == EL1) && !inSecureState()) {
-              if (misc_reg == MISCREG_ICC_BPR0_EL1 && hcr_fmo) {
-                  return setMiscReg(MISCREG_ICV_BPR0_EL1, val);
-              } else if (misc_reg == MISCREG_ICC_BPR1_EL1 && hcr_imo) {
-                  return setMiscReg(MISCREG_ICV_BPR1_EL1, val);
-              }
-          }
+        if ((currEL() == EL1) && !inSecureState() && hcr_imo) {
+            return setMiscReg(MISCREG_ICV_BPR1_EL1, val);
+        }
 
-          Gicv3::GroupId group =
-              misc_reg == MISCREG_ICC_BPR0_EL1 ? Gicv3::G0S : Gicv3::G1S;
+        val &= 0x7;
 
-          if (group == Gicv3::G1S && !inSecureState()) {
-              group = Gicv3::G1NS;
-          }
+        if (isSecureBelowEL3()) {
+            // group == Gicv3::G1S
+            ICC_CTLR_EL1 icc_ctlr_el1_s =
+                isa->readMiscRegNoEffect(MISCREG_ICC_CTLR_EL1_S);
 
-          ICC_CTLR_EL1 icc_ctlr_el1_s =
-              isa->readMiscRegNoEffect(MISCREG_ICC_CTLR_EL1_S);
+            val = val > GIC_MIN_BPR ? val : GIC_MIN_BPR;
+            if (haveEL(EL3) && !isEL3OrMon() && icc_ctlr_el1_s.CBPR) {
+                isa->setMiscRegNoEffect(MISCREG_ICC_BPR0_EL1, val);
+            } else {
+                isa->setMiscRegNoEffect(MISCREG_ICC_BPR1_EL1_S, val);
+            }
+            return;
+        } else {
+            // group == Gicv3::G1NS
+            ICC_CTLR_EL1 icc_ctlr_el1_ns =
+                isa->readMiscRegNoEffect(MISCREG_ICC_CTLR_EL1_NS);
 
-          if ((group == Gicv3::G1S) && !isEL3OrMon() &&
-              icc_ctlr_el1_s.CBPR) {
-              group = Gicv3::G0S;
-          }
+            val = val > GIC_MIN_BPR_NS ? val : GIC_MIN_BPR_NS;
+            if (haveEL(EL3) && !isEL3OrMon() && icc_ctlr_el1_ns.CBPR) {
+                // Non secure writes from EL1 and EL2 are ignored
+            } else {
+                isa->setMiscRegNoEffect(MISCREG_ICC_BPR1_EL1_NS, val);
+            }
+            return;
+        }
 
-          ICC_CTLR_EL1 icc_ctlr_el1_ns =
-              isa->readMiscRegNoEffect(MISCREG_ICC_CTLR_EL1_NS);
-
-          if ((group == Gicv3::G1NS) && (currEL() < EL3) &&
-              icc_ctlr_el1_ns.CBPR) {
-              // BPR0 + 1 saturated to 7, WI
-              return;
-          }
-
-          uint8_t min_val = (group == Gicv3::G1NS) ?
-              GIC_MIN_BPR_NS : GIC_MIN_BPR;
-          val &= 0x7;
-
-          if (val < min_val) {
-              val = min_val;
-          }
-
-          break;
+        break;
       }
 
       // Virtual Binary Point Register 0
@@ -1961,8 +1901,10 @@
 
     if (group == Gicv3::G0S) {
         bpr = readMiscReg(MISCREG_ICC_BPR0_EL1) & 0x7;
+    } else if (group == Gicv3::G1S) {
+        bpr = bpr1(Gicv3::G1S) & 0x7;
     } else {
-        bpr = readMiscReg(MISCREG_ICC_BPR1_EL1) & 0x7;
+        bpr = bpr1(Gicv3::G1NS) & 0x7;
     }
 
     if (group == Gicv3::G1NS) {
@@ -2556,6 +2498,47 @@
     return ich_misr_el2;
 }
 
+RegVal
+Gicv3CPUInterface::bpr1(Gicv3::GroupId group)
+{
+    bool hcr_imo = getHCREL2IMO();
+    if ((currEL() == EL1) && !inSecureState() && hcr_imo) {
+        return readMiscReg(MISCREG_ICV_BPR1_EL1);
+    }
+
+    RegVal bpr = 0;
+
+    if (group == Gicv3::G1S) {
+        ICC_CTLR_EL1 icc_ctlr_el1_s =
+            isa->readMiscRegNoEffect(MISCREG_ICC_CTLR_EL1_S);
+
+        if (!isEL3OrMon() && icc_ctlr_el1_s.CBPR) {
+            bpr = isa->readMiscRegNoEffect(MISCREG_ICC_BPR0_EL1);
+        } else {
+            bpr = isa->readMiscRegNoEffect(MISCREG_ICC_BPR1_EL1_S);
+            bpr = bpr > GIC_MIN_BPR ? bpr : GIC_MIN_BPR;
+        }
+    } else if (group == Gicv3::G1NS) {
+        ICC_CTLR_EL1 icc_ctlr_el1_ns =
+            isa->readMiscRegNoEffect(MISCREG_ICC_CTLR_EL1_NS);
+
+        // Check if EL3 is implemented and this is a non secure accesses at
+        // EL1 and EL2
+        if (haveEL(EL3) && !isEL3OrMon() && icc_ctlr_el1_ns.CBPR) {
+            // Reads return BPR0 + 1 saturated to 7, WI
+            bpr = isa->readMiscRegNoEffect(MISCREG_ICC_BPR0_EL1) + 1;
+            bpr = bpr < 7 ? bpr : 7;
+        } else {
+            bpr = isa->readMiscRegNoEffect(MISCREG_ICC_BPR1_EL1_NS);
+            bpr = bpr > GIC_MIN_BPR_NS ? bpr : GIC_MIN_BPR_NS;
+        }
+    } else {
+        panic("Should be used with G1S and G1NS only\n");
+    }
+
+    return bpr;
+}
+
 void
 Gicv3CPUInterface::serialize(CheckpointOut & cp) const
 {
diff --git a/src/dev/arm/gic_v3_cpu_interface.hh b/src/dev/arm/gic_v3_cpu_interface.hh
index ed432bc..56a6695 100644
--- a/src/dev/arm/gic_v3_cpu_interface.hh
+++ b/src/dev/arm/gic_v3_cpu_interface.hh
@@ -336,6 +336,7 @@
     void virtualIncrementEOICount();
     bool virtualIsEOISplitMode() const;
     void virtualUpdate();
+    RegVal bpr1(Gicv3::GroupId group);
 
   public: