[PATCH 03/16] target/arm: opt-in align-down for a misaligned PMSAv7 MPU RBAR

Kyle Fox <[email protected]>
Newsgroups org.nongnu.qemu-arm,org.nongnu.qemu-devel
Message-ID <[email protected]>
A PMSAv7 MPU region base that is not aligned to its region size is
UNPREDICTABLE per the architecture, and QEMU disables such a region.
Some PMSAv7 implementations instead ignore the sub-size low bits of
RBAR.ADDR and match against the aligned-down base. The NXP i.MX 95 RT
core (Cortex-M7) SDK firmware relies on this for a peripheral region
(DRBAR 0x4c800000 programmed with a 512MB size, intended as 0x40000000).

Add an opt-in "pmsav7-rbar-align-down" property that aligns such a base
down instead of dropping the region. It defaults to false, so existing
behaviour is unchanged, and is only registered on PMSAv7 CPUs (v7-M and
v7-R, i.e. v7 without v8), where get_phys_addr_pmsav7() runs.

Signed-off-by: Kyle Fox <[email protected]>
---
 target/arm/cpu.c | 19 +++++++++++++++++++
 target/arm/cpu.h |  6 ++++++
 target/arm/ptw.c | 28 +++++++++++++++++++++++-----
 3 files changed, 48 insertions(+), 5 deletions(-)

diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 77aa78f00e2..22e84c1ced2 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -1349,6 +1349,16 @@ static const Property arm_cpu_pmsav7_dregion_property =
             DEFINE_PROP_UNSIGNED_NODEFAULT("pmsav7-dregion", ARMCPU,
                                            pmsav7_dregion,
                                            qdev_prop_uint32, uint32_t);
+
+/*
+ * Opt-in: treat a PMSAv7 MPU region base that is not aligned to its region
+ * size as aligned-down instead of UNPREDICTABLE (see get_phys_addr_pmsav7()).
+ * Only registered on PMSAv7 (v7-M / v7-R) CPUs, and only enabled by an
+ * integrator whose firmware relies on it (e.g. the i.MX 95 Cortex-M7).
+ */
+static const Property arm_cpu_pmsav7_rbar_align_down_property =
+            DEFINE_PROP_BOOL("pmsav7-rbar-align-down", ARMCPU,
+                             pmsav7_rbar_align_down, false);
 #endif
 
 static bool arm_get_pmu(Object *obj, Error **errp)
@@ -1659,6 +1669,15 @@ static void arm_cpu_post_init(Object *obj)
         if (arm_feature(&cpu->env, ARM_FEATURE_V7)) {
             qdev_property_add_static(DEVICE(obj),
                                      &arm_cpu_pmsav7_dregion_property);
+            /*
+             * get_phys_addr_pmsav7() only runs on PMSAv7 CPUs, i.e. v7
+             * without v8 (a v8 M/R core uses the PMSAv8 MPU, which has no
+             * such alignment rule), so only offer the property there.
+             */
+            if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
+                qdev_property_add_static(DEVICE(obj),
+                        &arm_cpu_pmsav7_rbar_align_down_property);
+            }
         }
     }
 
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index c0492c8dfbc..03ead3cda15 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1145,6 +1145,12 @@ struct ArchCPU {
      * architecture version.
      */
     bool cfgend;
+    /*
+     * If set, a PMSAv7 MPU region base that is not aligned to its region
+     * size is treated as aligned-down (matching Cortex-M silicon such as the
+     * i.MX 95 M-cores) instead of the architectural UNPREDICTABLE drop.
+     */
+    bool pmsav7_rbar_align_down;
 
     QLIST_HEAD(, ARMELChangeHook) pre_el_change_hooks;
     QLIST_HEAD(, ARMELChangeHook) el_change_hooks;
diff --git a/target/arm/ptw.c b/target/arm/ptw.c
index a29de0385f4..51805c05226 100644
--- a/target/arm/ptw.c
+++ b/target/arm/ptw.c
@@ -2757,11 +2757,29 @@ static bool get_phys_addr_pmsav7(CPUARMState *env,
             rmask = (1ull << rsize) - 1;
 
             if (base & rmask) {
-                qemu_log_mask(LOG_GUEST_ERROR,
-                              "DRBAR[%d]: 0x%" PRIx32 " misaligned "
-                              "to DRSR region size, mask = 0x%" PRIx32 "\n",
-                              n, base, rmask);
-                continue;
+                if (cpu->pmsav7_rbar_align_down) {
+                    /*
+                     * Opt-in behaviour for Cortex-M silicon such as the
+                     * i.MX 95 M-cores: a region base not aligned to its size
+                     * is treated as aligned-down (RBAR.ADDR is only
+                     * [31:log2(size)]), matching that hardware, whose SM/RT
+                     * firmware programs e.g. DRBAR 0x4c800000 with a 512MB
+                     * size intended as 0x40000000. Off by default because the
+                     * architecture calls a misaligned base UNPREDICTABLE.
+                     */
+                    qemu_log_mask(LOG_GUEST_ERROR,
+                                  "DRBAR[%d]: 0x%" PRIx32 " not aligned to "
+                                  "DRSR region size (mask 0x%" PRIx32 "); "
+                                  "aligning down to 0x%" PRIx32 "\n",
+                                  n, base, rmask, base & ~rmask);
+                    base &= ~rmask;
+                } else {
+                    qemu_log_mask(LOG_GUEST_ERROR,
+                                  "DRBAR[%d]: 0x%" PRIx32 " misaligned "
+                                  "to DRSR region size, mask = 0x%" PRIx32 "\n",
+                                  n, base, rmask);
+                    continue;
+                }
             }
 
             if (address < base || address > base + rmask) {
-- 
2.34.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.