Prechádzať zdrojové kódy

Merge tag 'pull-target-arm-20241105' of https://git.linaro.org/people/pmaydell/qemu-arm into staging

target-arm queue:
 * Fix MMU indexes for AArch32 Secure PL1&0 in a less complex and buggy way
 * Fix SVE SDOT/UDOT/USDOT (4-way, indexed)
 * softfloat: set 2-operand NaN propagation rule at runtime
 * disas: Fix build against Capstone v6 (again)
 * hw/rtc/ds1338: Trace send and receive operations
 * hw/timer/imx_gpt: Convert DPRINTF to trace events
 * hw/watchdog/wdt_imx2: Remove redundant assignment
 * hw/sensor/tmp105: Convert printf() to trace event, add tracing for read/write access
 * hw/net/npcm_gmac: Change error log to trace event
 * target/arm: Enable FEAT_CMOW for -cpu max

# -----BEGIN PGP SIGNATURE-----
#
# iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmcp/yoZHHBldGVyLm1h
# eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3ucMD/9pWk2ETLjdviPxlacs5IoM
# HvGn8Ll2BSMbeb4YdJc7oZ4YJchGpgHhocEwZuaU9HheWjSg+ZEbyhZgN4DdkT8J
# pYr+Rl0MgDNN219kYnO/yqnqlgHbtUpE7y57Li3ApoGNbWAVxsH0xoT45Lpi7DOd
# uvJfIy/xdaT3zu/4uBjj7c2VrD8wntEayLM8hpqlgeQZKRG3Wtlk/xrQFKOHPDPO
# MDbsGoc2FyogRQoo6WH+J6gkkR9PhqXe6Hbf6WIr1/uffZUZU4M8leSw2DgxrYHo
# Zf36AzttwO4GHyML/5SR7uvzfXl7OkGyjedLGCUa7INc3br2+GvLMltdLGGPM9cc
# ckMHOWd9ZQuSxcpbtPkSYRG0McRE1GLT+KV3BNOLnN9AJl3qv5Qa55iPrtpB08vX
# 3jN6H964w99+NoSB2tTHszpep+M7SRuw5QLsuk3tC/qnBMpzKRwZjGVUegNUtfi/
# Lg5ExF8B62K+xb5j5FmODbbXZmb5AD0rV2MGRIVHjiHdnf7J2FmWUJCe2sYFRnRm
# nzszhdOKw4PBhC2fb6Vb/DwCqdQy9vcITWpWBtcjkV5mAPhcBo/VNKNeKoc/tPNS
# H8FIFIJbtv5aIixqtKcUBUmrBCYy4EoiRMLkqfC09VW60wtWswAP4KBQxi1ogehV
# jJw8AgSLCl2MsVmyzgleZQ==
# =Woag
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 05 Nov 2024 11:19:06 GMT
# gpg:                using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg:                issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate]
# gpg:                 aka "Peter Maydell <peter@archaic.org.uk>" [ultimate]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* tag 'pull-target-arm-20241105' of https://git.linaro.org/people/pmaydell/qemu-arm: (31 commits)
  target/arm: Enable FEAT_CMOW for -cpu max
  hw/net/npcm_gmac: Change error log to trace event
  hw/sensor/tmp105: Convert printf() to trace event, add tracing for read/write access
  hw/watchdog/wdt_imx2: Remove redundant assignment
  hw/timer/imx_gpt: Convert DPRINTF to trace events
  hw/rtc/ds1338: Trace send and receive operations
  disas: Fix build against Capstone v6 (again)
  target/arm: Fix SVE SDOT/UDOT/USDOT (4-way, indexed)
  target/arm: Add new MMU indexes for AArch32 Secure PL1&0
  Revert "target/arm: Fix usage of MMU indexes when EL3 is AArch32"
  softfloat: Remove fallback rule from pickNaN()
  target/rx: Explicitly set 2-NaN propagation rule
  target/openrisc: Explicitly set 2-NaN propagation rule
  target/microblaze: Explicitly set 2-NaN propagation rule
  target/microblaze: Move setting of float rounding mode to reset
  target/alpha: Explicitly set 2-NaN propagation rule
  target/i386: Set 2-NaN propagation rule explicitly
  target/xtensa: Explicitly set 2-NaN propagation rule
  target/xtensa: Factor out calls to set_use_first_nan()
  target/sparc: Explicitly set 2-NaN propagation rule
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Peter Maydell 9 mesiacov pred
rodič
commit
f15f7273ea
55 zmenil súbory, kde vykonal 516 pridanie a 239 odobranie
  1. 1 0
      docs/system/arm/emulation.rst
  2. 59 97
      fpu/softfloat-specialize.c.inc
  3. 2 3
      hw/net/npcm_gmac.c
  4. 1 0
      hw/net/trace-events
  5. 6 0
      hw/rtc/ds1338.c
  6. 4 0
      hw/rtc/trace-events
  7. 6 1
      hw/sensor/tmp105.c
  8. 6 0
      hw/sensor/trace-events
  9. 1 0
      hw/sensor/trace.h
  10. 5 13
      hw/timer/imx_gpt.c
  11. 6 0
      hw/timer/trace-events
  12. 0 1
      hw/watchdog/wdt_imx2.c
  13. 1 0
      include/disas/capstone.h
  14. 11 0
      include/fpu/softfloat-helpers.h
  15. 38 0
      include/fpu/softfloat-types.h
  16. 18 0
      linux-user/arm/nwfpe/fpa11.c
  17. 1 0
      meson.build
  18. 11 0
      target/alpha/cpu.c
  19. 5 0
      target/arm/cpu-features.h
  20. 17 8
      target/arm/cpu.c
  21. 25 24
      target/arm/cpu.h
  22. 48 25
      target/arm/helper.c
  23. 17 24
      target/arm/internals.h
  24. 5 5
      target/arm/ptw.c
  25. 1 0
      target/arm/tcg/cpu64.c
  26. 0 4
      target/arm/tcg/hflags.c
  27. 13 1
      target/arm/tcg/op_helper.c
  28. 1 1
      target/arm/tcg/translate-a64.c
  29. 7 5
      target/arm/tcg/translate.c
  30. 0 2
      target/arm/tcg/translate.h
  31. 8 1
      target/arm/tcg/vec_helper.c
  32. 6 0
      target/hppa/fpu_helper.c
  33. 4 0
      target/i386/cpu.c
  34. 3 0
      target/i386/cpu.h
  35. 40 0
      target/i386/tcg/fpu_helper.c
  36. 1 0
      target/loongarch/tcg/fpu_helper.c
  37. 16 0
      target/m68k/cpu.c
  38. 1 0
      target/m68k/fpu_helper.c
  39. 2 2
      target/m68k/helper.c
  40. 7 3
      target/microblaze/cpu.c
  41. 1 1
      target/mips/cpu.c
  42. 22 0
      target/mips/fpu_helper.h
  43. 17 0
      target/mips/msa.c
  44. 6 0
      target/openrisc/cpu.c
  45. 8 0
      target/ppc/cpu_init.c
  46. 7 0
      target/rx/cpu.c
  47. 1 0
      target/s390x/cpu.c
  48. 9 1
      target/sparc/cpu.c
  49. 8 2
      target/sparc/fop_helper.c
  50. 1 1
      target/xtensa/cpu.c
  51. 6 0
      target/xtensa/cpu.h
  52. 21 14
      target/xtensa/fpu_helper.c
  53. 2 0
      tests/fp/fp-bench.c
  54. 1 0
      tests/fp/fp-test-log2.c
  55. 2 0
      tests/fp/fp-test.c

+ 1 - 0
docs/system/arm/emulation.rst

@@ -26,6 +26,7 @@ the following architecture extensions:
 - FEAT_BF16 (AArch64 BFloat16 instructions)
 - FEAT_BF16 (AArch64 BFloat16 instructions)
 - FEAT_BTI (Branch Target Identification)
 - FEAT_BTI (Branch Target Identification)
 - FEAT_CCIDX (Extended cache index)
 - FEAT_CCIDX (Extended cache index)
+- FEAT_CMOW (Control for cache maintenance permission)
 - FEAT_CRC32 (CRC32 instructions)
 - FEAT_CRC32 (CRC32 instructions)
 - FEAT_Crypto (Cryptographic Extension)
 - FEAT_Crypto (Cryptographic Extension)
 - FEAT_CSV2 (Cache speculation variant 2)
 - FEAT_CSV2 (Cache speculation variant 2)

+ 59 - 97
fpu/softfloat-specialize.c.inc

@@ -390,118 +390,80 @@ bool float32_is_signaling_nan(float32 a_, float_status *status)
 static int pickNaN(FloatClass a_cls, FloatClass b_cls,
 static int pickNaN(FloatClass a_cls, FloatClass b_cls,
                    bool aIsLargerSignificand, float_status *status)
                    bool aIsLargerSignificand, float_status *status)
 {
 {
-#if defined(TARGET_ARM) || defined(TARGET_MIPS) || defined(TARGET_HPPA) || \
-    defined(TARGET_LOONGARCH64) || defined(TARGET_S390X)
-    /* ARM mandated NaN propagation rules (see FPProcessNaNs()), take
-     * the first of:
-     *  1. A if it is signaling
-     *  2. B if it is signaling
-     *  3. A (quiet)
-     *  4. B (quiet)
-     * A signaling NaN is always quietened before returning it.
-     */
-    /* According to MIPS specifications, if one of the two operands is
-     * a sNaN, a new qNaN has to be generated. This is done in
-     * floatXX_silence_nan(). For qNaN inputs the specifications
-     * says: "When possible, this QNaN result is one of the operand QNaN
-     * values." In practice it seems that most implementations choose
-     * the first operand if both operands are qNaN. In short this gives
-     * the following rules:
-     *  1. A if it is signaling
-     *  2. B if it is signaling
-     *  3. A (quiet)
-     *  4. B (quiet)
-     * A signaling NaN is always silenced before returning it.
-     */
-    if (is_snan(a_cls)) {
-        return 0;
-    } else if (is_snan(b_cls)) {
-        return 1;
-    } else if (is_qnan(a_cls)) {
-        return 0;
-    } else {
-        return 1;
-    }
-#elif defined(TARGET_PPC) || defined(TARGET_M68K)
-    /* PowerPC propagation rules:
-     *  1. A if it sNaN or qNaN
-     *  2. B if it sNaN or qNaN
-     * A signaling NaN is always silenced before returning it.
-     */
-    /* M68000 FAMILY PROGRAMMER'S REFERENCE MANUAL
-     * 3.4 FLOATING-POINT INSTRUCTION DETAILS
-     * If either operand, but not both operands, of an operation is a
-     * nonsignaling NaN, then that NaN is returned as the result. If both
-     * operands are nonsignaling NaNs, then the destination operand
-     * nonsignaling NaN is returned as the result.
-     * If either operand to an operation is a signaling NaN (SNaN), then the
-     * SNaN bit is set in the FPSR EXC byte. If the SNaN exception enable bit
-     * is set in the FPCR ENABLE byte, then the exception is taken and the
-     * destination is not modified. If the SNaN exception enable bit is not
-     * set, setting the SNaN bit in the operand to a one converts the SNaN to
-     * a nonsignaling NaN. The operation then continues as described in the
-     * preceding paragraph for nonsignaling NaNs.
-     */
-    if (is_nan(a_cls)) {
-        return 0;
-    } else {
-        return 1;
-    }
-#elif defined(TARGET_SPARC)
-    /* Prefer SNaN over QNaN, order B then A. */
-    if (is_snan(b_cls)) {
-        return 1;
-    } else if (is_snan(a_cls)) {
-        return 0;
-    } else if (is_qnan(b_cls)) {
-        return 1;
-    } else {
-        return 0;
-    }
-#elif defined(TARGET_XTENSA)
     /*
     /*
-     * Xtensa has two NaN propagation modes.
-     * Which one is active is controlled by float_status::use_first_nan.
+     * We guarantee not to require the target to tell us how to
+     * pick a NaN if we're always returning the default NaN.
+     * But if we're not in default-NaN mode then the target must
+     * specify via set_float_2nan_prop_rule().
      */
      */
-    if (status->use_first_nan) {
-        if (is_nan(a_cls)) {
+    assert(!status->default_nan_mode);
+
+    switch (status->float_2nan_prop_rule) {
+    case float_2nan_prop_s_ab:
+        if (is_snan(a_cls)) {
+            return 0;
+        } else if (is_snan(b_cls)) {
+            return 1;
+        } else if (is_qnan(a_cls)) {
             return 0;
             return 0;
         } else {
         } else {
             return 1;
             return 1;
         }
         }
-    } else {
-        if (is_nan(b_cls)) {
+        break;
+    case float_2nan_prop_s_ba:
+        if (is_snan(b_cls)) {
+            return 1;
+        } else if (is_snan(a_cls)) {
+            return 0;
+        } else if (is_qnan(b_cls)) {
             return 1;
             return 1;
         } else {
         } else {
             return 0;
             return 0;
         }
         }
-    }
-#else
-    /* This implements x87 NaN propagation rules:
-     * SNaN + QNaN => return the QNaN
-     * two SNaNs => return the one with the larger significand, silenced
-     * two QNaNs => return the one with the larger significand
-     * SNaN and a non-NaN => return the SNaN, silenced
-     * QNaN and a non-NaN => return the QNaN
-     *
-     * If we get down to comparing significands and they are the same,
-     * return the NaN with the positive sign bit (if any).
-     */
-    if (is_snan(a_cls)) {
-        if (is_snan(b_cls)) {
-            return aIsLargerSignificand ? 0 : 1;
+        break;
+    case float_2nan_prop_ab:
+        if (is_nan(a_cls)) {
+            return 0;
+        } else {
+            return 1;
         }
         }
-        return is_qnan(b_cls) ? 1 : 0;
-    } else if (is_qnan(a_cls)) {
-        if (is_snan(b_cls) || !is_qnan(b_cls)) {
+        break;
+    case float_2nan_prop_ba:
+        if (is_nan(b_cls)) {
+            return 1;
+        } else {
             return 0;
             return 0;
+        }
+        break;
+    case float_2nan_prop_x87:
+        /*
+         * This implements x87 NaN propagation rules:
+         * SNaN + QNaN => return the QNaN
+         * two SNaNs => return the one with the larger significand, silenced
+         * two QNaNs => return the one with the larger significand
+         * SNaN and a non-NaN => return the SNaN, silenced
+         * QNaN and a non-NaN => return the QNaN
+         *
+         * If we get down to comparing significands and they are the same,
+         * return the NaN with the positive sign bit (if any).
+         */
+        if (is_snan(a_cls)) {
+            if (is_snan(b_cls)) {
+                return aIsLargerSignificand ? 0 : 1;
+            }
+            return is_qnan(b_cls) ? 1 : 0;
+        } else if (is_qnan(a_cls)) {
+            if (is_snan(b_cls) || !is_qnan(b_cls)) {
+                return 0;
+            } else {
+                return aIsLargerSignificand ? 0 : 1;
+            }
         } else {
         } else {
-            return aIsLargerSignificand ? 0 : 1;
+            return 1;
         }
         }
-    } else {
-        return 1;
+    default:
+        g_assert_not_reached();
     }
     }
-#endif
 }
 }
 
 
 /*----------------------------------------------------------------------------
 /*----------------------------------------------------------------------------

+ 2 - 3
hw/net/npcm_gmac.c

@@ -546,9 +546,8 @@ static void gmac_try_send_next_packet(NPCMGMACState *gmac)
 
 
         /* 1 = DMA Owned, 0 = Software Owned */
         /* 1 = DMA Owned, 0 = Software Owned */
         if (!(tx_desc.tdes0 & TX_DESC_TDES0_OWN)) {
         if (!(tx_desc.tdes0 & TX_DESC_TDES0_OWN)) {
-            qemu_log_mask(LOG_GUEST_ERROR,
-                          "TX Descriptor @ 0x%x is owned by software\n",
-                          desc_addr);
+            trace_npcm_gmac_tx_desc_owner(DEVICE(gmac)->canonical_path,
+                                          desc_addr);
             gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_TU;
             gmac->regs[R_NPCM_DMA_STATUS] |= NPCM_DMA_STATUS_TU;
             gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT,
             gmac_dma_set_state(gmac, NPCM_DMA_STATUS_TX_PROCESS_STATE_SHIFT,
                 NPCM_DMA_STATUS_TX_SUSPENDED_STATE);
                 NPCM_DMA_STATUS_TX_SUSPENDED_STATE);

+ 1 - 0
hw/net/trace-events

@@ -478,6 +478,7 @@ npcm_gmac_packet_received(const char* name, uint32_t len) "%s: Reception finishe
 npcm_gmac_packet_sent(const char* name, uint16_t len) "%s: TX packet sent!, length: 0x%04" PRIX16
 npcm_gmac_packet_sent(const char* name, uint16_t len) "%s: TX packet sent!, length: 0x%04" PRIX16
 npcm_gmac_debug_desc_data(const char* name, void* addr, uint32_t des0, uint32_t des1, uint32_t des2, uint32_t des3)"%s: Address: %p Descriptor 0: 0x%04" PRIX32 " Descriptor 1: 0x%04" PRIX32 "Descriptor 2: 0x%04" PRIX32 " Descriptor 3: 0x%04" PRIX32
 npcm_gmac_debug_desc_data(const char* name, void* addr, uint32_t des0, uint32_t des1, uint32_t des2, uint32_t des3)"%s: Address: %p Descriptor 0: 0x%04" PRIX32 " Descriptor 1: 0x%04" PRIX32 "Descriptor 2: 0x%04" PRIX32 " Descriptor 3: 0x%04" PRIX32
 npcm_gmac_packet_tx_desc_data(const char* name, uint32_t tdes0, uint32_t tdes1) "%s: Tdes0: 0x%04" PRIX32 " Tdes1: 0x%04" PRIX32
 npcm_gmac_packet_tx_desc_data(const char* name, uint32_t tdes0, uint32_t tdes1) "%s: Tdes0: 0x%04" PRIX32 " Tdes1: 0x%04" PRIX32
+npcm_gmac_tx_desc_owner(const char* name, uint32_t desc_addr) "%s: TX Descriptor @0x%04" PRIX32 " is owned by software"
 
 
 # npcm_pcs.c
 # npcm_pcs.c
 npcm_pcs_reg_read(const char *name, uint16_t indirect_access_baes, uint64_t offset, uint16_t value) "%s: IND: 0x%02" PRIx16 " offset: 0x%04" PRIx64 " value: 0x%04" PRIx16
 npcm_pcs_reg_read(const char *name, uint16_t indirect_access_baes, uint64_t offset, uint16_t value) "%s: IND: 0x%02" PRIx16 " offset: 0x%04" PRIx64 " value: 0x%04" PRIx16

+ 6 - 0
hw/rtc/ds1338.c

@@ -17,6 +17,7 @@
 #include "qemu/module.h"
 #include "qemu/module.h"
 #include "qom/object.h"
 #include "qom/object.h"
 #include "sysemu/rtc.h"
 #include "sysemu/rtc.h"
+#include "trace.h"
 
 
 /* Size of NVRAM including both the user-accessible area and the
 /* Size of NVRAM including both the user-accessible area and the
  * secondary register area.
  * secondary register area.
@@ -126,6 +127,9 @@ static uint8_t ds1338_recv(I2CSlave *i2c)
     uint8_t res;
     uint8_t res;
 
 
     res  = s->nvram[s->ptr];
     res  = s->nvram[s->ptr];
+
+    trace_ds1338_recv(s->ptr, res);
+
     inc_regptr(s);
     inc_regptr(s);
     return res;
     return res;
 }
 }
@@ -134,6 +138,8 @@ static int ds1338_send(I2CSlave *i2c, uint8_t data)
 {
 {
     DS1338State *s = DS1338(i2c);
     DS1338State *s = DS1338(i2c);
 
 
+    trace_ds1338_send(s->ptr, data);
+
     if (s->addr_byte) {
     if (s->addr_byte) {
         s->ptr = data & (NVRAM_SIZE - 1);
         s->ptr = data & (NVRAM_SIZE - 1);
         s->addr_byte = false;
         s->addr_byte = false;

+ 4 - 0
hw/rtc/trace-events

@@ -22,6 +22,10 @@ pl031_set_alarm(uint32_t ticks) "alarm set for %u ticks"
 aspeed_rtc_read(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
 aspeed_rtc_read(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
 aspeed_rtc_write(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
 aspeed_rtc_write(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
 
 
+# ds1338.c
+ds1338_recv(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] -> 0x%02" PRIx8
+ds1338_send(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] <- 0x%02" PRIx8
+
 # m48t59.c
 # m48t59.c
 m48txx_nvram_io_read(uint64_t addr, uint64_t value) "io read addr:0x%04" PRIx64 " value:0x%02" PRIx64
 m48txx_nvram_io_read(uint64_t addr, uint64_t value) "io read addr:0x%04" PRIx64 " value:0x%02" PRIx64
 m48txx_nvram_io_write(uint64_t addr, uint64_t value) "io write addr:0x%04" PRIx64 " value:0x%02" PRIx64
 m48txx_nvram_io_write(uint64_t addr, uint64_t value) "io write addr:0x%04" PRIx64 " value:0x%02" PRIx64

+ 6 - 1
hw/sensor/tmp105.c

@@ -27,6 +27,7 @@
 #include "qapi/visitor.h"
 #include "qapi/visitor.h"
 #include "qemu/module.h"
 #include "qemu/module.h"
 #include "hw/registerfields.h"
 #include "hw/registerfields.h"
+#include "trace.h"
 
 
 FIELD(CONFIG, SHUTDOWN_MODE,        0, 1)
 FIELD(CONFIG, SHUTDOWN_MODE,        0, 1)
 FIELD(CONFIG, THERMOSTAT_MODE,      1, 1)
 FIELD(CONFIG, THERMOSTAT_MODE,      1, 1)
@@ -150,17 +151,21 @@ static void tmp105_read(TMP105State *s)
         s->buf[s->len++] = ((uint16_t) s->limit[1]) >> 0;
         s->buf[s->len++] = ((uint16_t) s->limit[1]) >> 0;
         break;
         break;
     }
     }
+
+    trace_tmp105_read(s->i2c.address, s->pointer);
 }
 }
 
 
 static void tmp105_write(TMP105State *s)
 static void tmp105_write(TMP105State *s)
 {
 {
+    trace_tmp105_write(s->i2c.address, s->pointer);
+
     switch (s->pointer & 3) {
     switch (s->pointer & 3) {
     case TMP105_REG_TEMPERATURE:
     case TMP105_REG_TEMPERATURE:
         break;
         break;
 
 
     case TMP105_REG_CONFIG:
     case TMP105_REG_CONFIG:
         if (FIELD_EX8(s->buf[0] & ~s->config, CONFIG, SHUTDOWN_MODE)) {
         if (FIELD_EX8(s->buf[0] & ~s->config, CONFIG, SHUTDOWN_MODE)) {
-            printf("%s: TMP105 shutdown\n", __func__);
+            trace_tmp105_write_shutdown(s->i2c.address);
         }
         }
         s->config = FIELD_DP8(s->buf[0], CONFIG, ONE_SHOT, 0);
         s->config = FIELD_DP8(s->buf[0], CONFIG, ONE_SHOT, 0);
         s->faults = tmp105_faultq[FIELD_EX8(s->config, CONFIG, FAULT_QUEUE)];
         s->faults = tmp105_faultq[FIELD_EX8(s->config, CONFIG, FAULT_QUEUE)];

+ 6 - 0
hw/sensor/trace-events

@@ -0,0 +1,6 @@
+# See docs/devel/tracing.rst for syntax documentation.
+
+# tmp105.c
+tmp105_read(uint8_t dev, uint8_t addr) "device: 0x%02x, addr: 0x%02x"
+tmp105_write(uint8_t dev, uint8_t addr) "device: 0x%02x, addr 0x%02x"
+tmp105_write_shutdown(uint8_t dev) "device: 0x%02x"

+ 1 - 0
hw/sensor/trace.h

@@ -0,0 +1 @@
+#include "trace/trace-hw_sensor.h"

+ 5 - 13
hw/timer/imx_gpt.c

@@ -18,19 +18,12 @@
 #include "migration/vmstate.h"
 #include "migration/vmstate.h"
 #include "qemu/module.h"
 #include "qemu/module.h"
 #include "qemu/log.h"
 #include "qemu/log.h"
+#include "trace.h"
 
 
 #ifndef DEBUG_IMX_GPT
 #ifndef DEBUG_IMX_GPT
 #define DEBUG_IMX_GPT 0
 #define DEBUG_IMX_GPT 0
 #endif
 #endif
 
 
-#define DPRINTF(fmt, args...) \
-    do { \
-        if (DEBUG_IMX_GPT) { \
-            fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_GPT, \
-                                             __func__, ##args); \
-        } \
-    } while (0)
-
 static const char *imx_gpt_reg_name(uint32_t reg)
 static const char *imx_gpt_reg_name(uint32_t reg)
 {
 {
     switch (reg) {
     switch (reg) {
@@ -145,7 +138,7 @@ static void imx_gpt_set_freq(IMXGPTState *s)
     s->freq = imx_ccm_get_clock_frequency(s->ccm,
     s->freq = imx_ccm_get_clock_frequency(s->ccm,
                                           s->clocks[clksrc]) / (1 + s->pr);
                                           s->clocks[clksrc]) / (1 + s->pr);
 
 
-    DPRINTF("Setting clksrc %d to frequency %d\n", clksrc, s->freq);
+    trace_imx_gpt_set_freq(clksrc, s->freq);
 
 
     if (s->freq) {
     if (s->freq) {
         ptimer_set_freq(s->timer, s->freq);
         ptimer_set_freq(s->timer, s->freq);
@@ -317,7 +310,7 @@ static uint64_t imx_gpt_read(void *opaque, hwaddr offset, unsigned size)
         break;
         break;
     }
     }
 
 
-    DPRINTF("(%s) = 0x%08x\n", imx_gpt_reg_name(offset >> 2), reg_value);
+    trace_imx_gpt_read(imx_gpt_reg_name(offset >> 2), reg_value);
 
 
     return reg_value;
     return reg_value;
 }
 }
@@ -384,8 +377,7 @@ static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value,
     IMXGPTState *s = IMX_GPT(opaque);
     IMXGPTState *s = IMX_GPT(opaque);
     uint32_t oldreg;
     uint32_t oldreg;
 
 
-    DPRINTF("(%s, value = 0x%08x)\n", imx_gpt_reg_name(offset >> 2),
-            (uint32_t)value);
+    trace_imx_gpt_write(imx_gpt_reg_name(offset >> 2), (uint32_t)value);
 
 
     switch (offset >> 2) {
     switch (offset >> 2) {
     case 0:
     case 0:
@@ -485,7 +477,7 @@ static void imx_gpt_timeout(void *opaque)
 {
 {
     IMXGPTState *s = IMX_GPT(opaque);
     IMXGPTState *s = IMX_GPT(opaque);
 
 
-    DPRINTF("\n");
+    trace_imx_gpt_timeout();
 
 
     s->sr |= s->next_int;
     s->sr |= s->next_int;
     s->next_int = 0;
     s->next_int = 0;

+ 6 - 0
hw/timer/trace-events

@@ -49,6 +49,12 @@ cmsdk_apb_dualtimer_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK A
 cmsdk_apb_dualtimer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB dualtimer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
 cmsdk_apb_dualtimer_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB dualtimer write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
 cmsdk_apb_dualtimer_reset(void) "CMSDK APB dualtimer: reset"
 cmsdk_apb_dualtimer_reset(void) "CMSDK APB dualtimer: reset"
 
 
+# imx_gpt.c
+imx_gpt_set_freq(uint32_t clksrc, uint32_t freq) "Setting clksrc %u to %u Hz"
+imx_gpt_read(const char *name, uint64_t value) "%s -> 0x%08" PRIx64
+imx_gpt_write(const char *name, uint64_t value) "%s <- 0x%08" PRIx64
+imx_gpt_timeout(void) ""
+
 # npcm7xx_timer.c
 # npcm7xx_timer.c
 npcm7xx_timer_read(const char *id, uint64_t offset, uint64_t value) " %s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
 npcm7xx_timer_read(const char *id, uint64_t offset, uint64_t value) " %s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
 npcm7xx_timer_write(const char *id, uint64_t offset, uint64_t value) "%s offset: 0x%04" PRIx64 " value 0x%08" PRIx64
 npcm7xx_timer_write(const char *id, uint64_t offset, uint64_t value) "%s offset: 0x%04" PRIx64 " value 0x%08" PRIx64

+ 0 - 1
hw/watchdog/wdt_imx2.c

@@ -39,7 +39,6 @@ static void imx2_wdt_expired(void *opaque)
 
 
     /* Perform watchdog action if watchdog is enabled */
     /* Perform watchdog action if watchdog is enabled */
     if (s->wcr & IMX2_WDT_WCR_WDE) {
     if (s->wcr & IMX2_WDT_WCR_WDE) {
-        s->wrsr = IMX2_WDT_WRSR_TOUT;
         watchdog_perform_action();
         watchdog_perform_action();
     }
     }
 }
 }

+ 1 - 0
include/disas/capstone.h

@@ -4,6 +4,7 @@
 #ifdef CONFIG_CAPSTONE
 #ifdef CONFIG_CAPSTONE
 
 
 #define CAPSTONE_AARCH64_COMPAT_HEADER
 #define CAPSTONE_AARCH64_COMPAT_HEADER
+#define CAPSTONE_SYSTEMZ_COMPAT_HEADER
 #include <capstone.h>
 #include <capstone.h>
 
 
 #else
 #else

+ 11 - 0
include/fpu/softfloat-helpers.h

@@ -75,6 +75,12 @@ static inline void set_floatx80_rounding_precision(FloatX80RoundPrec val,
     status->floatx80_rounding_precision = val;
     status->floatx80_rounding_precision = val;
 }
 }
 
 
+static inline void set_float_2nan_prop_rule(Float2NaNPropRule rule,
+                                            float_status *status)
+{
+    status->float_2nan_prop_rule = rule;
+}
+
 static inline void set_flush_to_zero(bool val, float_status *status)
 static inline void set_flush_to_zero(bool val, float_status *status)
 {
 {
     status->flush_to_zero = val;
     status->flush_to_zero = val;
@@ -126,6 +132,11 @@ get_floatx80_rounding_precision(float_status *status)
     return status->floatx80_rounding_precision;
     return status->floatx80_rounding_precision;
 }
 }
 
 
+static inline Float2NaNPropRule get_float_2nan_prop_rule(float_status *status)
+{
+    return status->float_2nan_prop_rule;
+}
+
 static inline bool get_flush_to_zero(float_status *status)
 static inline bool get_flush_to_zero(float_status *status)
 {
 {
     return status->flush_to_zero;
     return status->flush_to_zero;

+ 38 - 0
include/fpu/softfloat-types.h

@@ -170,6 +170,43 @@ typedef enum __attribute__((__packed__)) {
     floatx80_precision_s,
     floatx80_precision_s,
 } FloatX80RoundPrec;
 } FloatX80RoundPrec;
 
 
+/*
+ * 2-input NaN propagation rule. Individual architectures have
+ * different rules for which input NaN is propagated to the output
+ * when there is more than one NaN on the input.
+ *
+ * If default_nan_mode is enabled then it is valid not to set a
+ * NaN propagation rule, because the softfloat code guarantees
+ * not to try to pick a NaN to propagate in default NaN mode.
+ * When not in default-NaN mode, it is an error for the target
+ * not to set the rule in float_status, and we will assert if
+ * we need to handle an input NaN and no rule was selected.
+ */
+typedef enum __attribute__((__packed__)) {
+    /* No propagation rule specified */
+    float_2nan_prop_none = 0,
+    /* Prefer SNaN over QNaN, then operand A over B */
+    float_2nan_prop_s_ab,
+    /* Prefer SNaN over QNaN, then operand B over A */
+    float_2nan_prop_s_ba,
+    /* Prefer A over B regardless of SNaN vs QNaN */
+    float_2nan_prop_ab,
+    /* Prefer B over A regardless of SNaN vs QNaN */
+    float_2nan_prop_ba,
+    /*
+     * This implements x87 NaN propagation rules:
+     * SNaN + QNaN => return the QNaN
+     * two SNaNs => return the one with the larger significand, silenced
+     * two QNaNs => return the one with the larger significand
+     * SNaN and a non-NaN => return the SNaN, silenced
+     * QNaN and a non-NaN => return the QNaN
+     *
+     * If we get down to comparing significands and they are the same,
+     * return the NaN with the positive sign bit (if any).
+     */
+    float_2nan_prop_x87,
+} Float2NaNPropRule;
+
 /*
 /*
  * Floating Point Status. Individual architectures may maintain
  * Floating Point Status. Individual architectures may maintain
  * several versions of float_status for different functions. The
  * several versions of float_status for different functions. The
@@ -181,6 +218,7 @@ typedef struct float_status {
     uint16_t float_exception_flags;
     uint16_t float_exception_flags;
     FloatRoundMode float_rounding_mode;
     FloatRoundMode float_rounding_mode;
     FloatX80RoundPrec floatx80_rounding_precision;
     FloatX80RoundPrec floatx80_rounding_precision;
+    Float2NaNPropRule float_2nan_prop_rule;
     bool tininess_before_rounding;
     bool tininess_before_rounding;
     /* should denormalised results go to zero and set the inexact flag? */
     /* should denormalised results go to zero and set the inexact flag? */
     bool flush_to_zero;
     bool flush_to_zero;

+ 18 - 0
linux-user/arm/nwfpe/fpa11.c

@@ -51,6 +51,24 @@ void resetFPA11(void)
 #ifdef MAINTAIN_FPCR
 #ifdef MAINTAIN_FPCR
   fpa11->fpcr = MASK_RESET;
   fpa11->fpcr = MASK_RESET;
 #endif
 #endif
+
+  /*
+   * Real FPA11 hardware does not handle NaNs, but always takes an
+   * exception for them to be software-emulated (ARM7500FE datasheet
+   * section 10.4). There is no documented architectural requirement
+   * for NaN propagation rules and it will depend on how the OS
+   * level software emulation opted to do it. We here use prop_s_ab
+   * which matches the later VFP hardware choice and how QEMU's
+   * fpa11 emulation has worked in the past. The real Linux kernel
+   * does something slightly different: arch/arm/nwfpe/softfloat-specialize
+   * propagateFloat64NaN() has the curious behaviour that it prefers
+   * the QNaN over the SNaN, but if both are QNaN it picks A and
+   * if both are SNaN it picks B. In theory we could add this as
+   * a NaN propagation rule, but in practice FPA11 emulation is so
+   * close to totally dead that it's not worth trying to match it at
+   * this late date.
+   */
+  set_float_2nan_prop_rule(float_2nan_prop_s_ab, &fpa11->fp_status);
 }
 }
 
 
 void SetRoundingMode(const unsigned int opcode)
 void SetRoundingMode(const unsigned int opcode)

+ 1 - 0
meson.build

@@ -3484,6 +3484,7 @@ if have_system
     'hw/s390x',
     'hw/s390x',
     'hw/scsi',
     'hw/scsi',
     'hw/sd',
     'hw/sd',
+    'hw/sensor',
     'hw/sh4',
     'hw/sh4',
     'hw/sparc',
     'hw/sparc',
     'hw/sparc64',
     'hw/sparc64',

+ 11 - 0
target/alpha/cpu.c

@@ -24,6 +24,7 @@
 #include "qemu/qemu-print.h"
 #include "qemu/qemu-print.h"
 #include "cpu.h"
 #include "cpu.h"
 #include "exec/exec-all.h"
 #include "exec/exec-all.h"
+#include "fpu/softfloat.h"
 
 
 
 
 static void alpha_cpu_set_pc(CPUState *cs, vaddr value)
 static void alpha_cpu_set_pc(CPUState *cs, vaddr value)
@@ -187,7 +188,17 @@ static void alpha_cpu_initfn(Object *obj)
 {
 {
     CPUAlphaState *env = cpu_env(CPU(obj));
     CPUAlphaState *env = cpu_env(CPU(obj));
 
 
+    /* TODO all this should be done in reset, not init */
+
     env->lock_addr = -1;
     env->lock_addr = -1;
+
+    /*
+     * TODO: this is incorrect. The Alpha Architecture Handbook version 4
+     * describes NaN propagation in section 4.7.10.4. We should prefer
+     * the operand in Fb (whether it is a QNaN or an SNaN), then the
+     * operand in Fa. That is float_2nan_prop_ba.
+     */
+    set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status);
 #if defined(CONFIG_USER_ONLY)
 #if defined(CONFIG_USER_ONLY)
     env->flags = ENV_FLAG_PS_USER | ENV_FLAG_FEN;
     env->flags = ENV_FLAG_PS_USER | ENV_FLAG_FEN;
     cpu_alpha_store_fpcr(env, (uint64_t)(FPCR_INVD | FPCR_DZED | FPCR_OVFD
     cpu_alpha_store_fpcr(env, (uint64_t)(FPCR_INVD | FPCR_DZED | FPCR_OVFD

+ 5 - 0
target/arm/cpu-features.h

@@ -802,6 +802,11 @@ static inline bool isar_feature_aa64_tidcp1(const ARMISARegisters *id)
     return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, TIDCP1) != 0;
     return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, TIDCP1) != 0;
 }
 }
 
 
+static inline bool isar_feature_aa64_cmow(const ARMISARegisters *id)
+{
+    return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, CMOW) != 0;
+}
+
 static inline bool isar_feature_aa64_hafs(const ARMISARegisters *id)
 static inline bool isar_feature_aa64_hafs(const ARMISARegisters *id)
 {
 {
     return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, HAFDBS) != 0;
     return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, HAFDBS) != 0;

+ 17 - 8
target/arm/cpu.c

@@ -168,6 +168,18 @@ void arm_register_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook,
     QLIST_INSERT_HEAD(&cpu->el_change_hooks, entry, node);
     QLIST_INSERT_HEAD(&cpu->el_change_hooks, entry, node);
 }
 }
 
 
+/*
+ * Set the float_status behaviour to match the Arm defaults:
+ *  * tininess-before-rounding
+ *  * 2-input NaN propagation prefers SNaN over QNaN, and then
+ *    operand A over operand B (see FPProcessNaNs() pseudocode)
+ */
+static void arm_set_default_fp_behaviours(float_status *s)
+{
+    set_float_detect_tininess(float_tininess_before_rounding, s);
+    set_float_2nan_prop_rule(float_2nan_prop_s_ab, s);
+}
+
 static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
 static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
 {
 {
     /* Reset a single ARMCPRegInfo register */
     /* Reset a single ARMCPRegInfo register */
@@ -549,14 +561,11 @@ static void arm_cpu_reset_hold(Object *obj, ResetType type)
     set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status);
     set_flush_inputs_to_zero(1, &env->vfp.standard_fp_status);
     set_default_nan_mode(1, &env->vfp.standard_fp_status);
     set_default_nan_mode(1, &env->vfp.standard_fp_status);
     set_default_nan_mode(1, &env->vfp.standard_fp_status_f16);
     set_default_nan_mode(1, &env->vfp.standard_fp_status_f16);
-    set_float_detect_tininess(float_tininess_before_rounding,
-                              &env->vfp.fp_status);
-    set_float_detect_tininess(float_tininess_before_rounding,
-                              &env->vfp.standard_fp_status);
-    set_float_detect_tininess(float_tininess_before_rounding,
-                              &env->vfp.fp_status_f16);
-    set_float_detect_tininess(float_tininess_before_rounding,
-                              &env->vfp.standard_fp_status_f16);
+    arm_set_default_fp_behaviours(&env->vfp.fp_status);
+    arm_set_default_fp_behaviours(&env->vfp.standard_fp_status);
+    arm_set_default_fp_behaviours(&env->vfp.fp_status_f16);
+    arm_set_default_fp_behaviours(&env->vfp.standard_fp_status_f16);
+
 #ifndef CONFIG_USER_ONLY
 #ifndef CONFIG_USER_ONLY
     if (kvm_enabled()) {
     if (kvm_enabled()) {
         kvm_arm_reset_vcpu(cpu);
         kvm_arm_reset_vcpu(cpu);

+ 25 - 24
target/arm/cpu.h

@@ -1367,6 +1367,7 @@ void pmu_init(ARMCPU *cpu);
 #define SCTLR_EnIB    (1U << 30) /* v8.3, AArch64 only */
 #define SCTLR_EnIB    (1U << 30) /* v8.3, AArch64 only */
 #define SCTLR_EnIA    (1U << 31) /* v8.3, AArch64 only */
 #define SCTLR_EnIA    (1U << 31) /* v8.3, AArch64 only */
 #define SCTLR_DSSBS_32 (1U << 31) /* v8.5, AArch32 only */
 #define SCTLR_DSSBS_32 (1U << 31) /* v8.5, AArch32 only */
+#define SCTLR_CMOW    (1ULL << 32) /* FEAT_CMOW */
 #define SCTLR_MSCEN   (1ULL << 33) /* FEAT_MOPS */
 #define SCTLR_MSCEN   (1ULL << 33) /* FEAT_MOPS */
 #define SCTLR_BT0     (1ULL << 35) /* v8.5-BTI */
 #define SCTLR_BT0     (1ULL << 35) /* v8.5-BTI */
 #define SCTLR_BT1     (1ULL << 36) /* v8.5-BTI */
 #define SCTLR_BT1     (1ULL << 36) /* v8.5-BTI */
@@ -2805,38 +2806,38 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync);
  *     The only use of stage 2 translations is either as part of an s1+2
  *     The only use of stage 2 translations is either as part of an s1+2
  *     lookup or when loading the descriptors during a stage 1 page table walk,
  *     lookup or when loading the descriptors during a stage 1 page table walk,
  *     and in both those cases we don't use the TLB.
  *     and in both those cases we don't use the TLB.
- *  4. we want to be able to use the TLB for accesses done as part of a
+ *  4. we can also safely fold together the "32 bit EL3" and "64 bit EL3"
+ *     translation regimes, because they map reasonably well to each other
+ *     and they can't both be active at the same time.
+ *  5. we want to be able to use the TLB for accesses done as part of a
  *     stage1 page table walk, rather than having to walk the stage2 page
  *     stage1 page table walk, rather than having to walk the stage2 page
  *     table over and over.
  *     table over and over.
- *  5. we need separate EL1/EL2 mmu_idx for handling the Privileged Access
+ *  6. we need separate EL1/EL2 mmu_idx for handling the Privileged Access
  *     Never (PAN) bit within PSTATE.
  *     Never (PAN) bit within PSTATE.
- *  6. we fold together most secure and non-secure regimes for A-profile,
+ *  7. we fold together most secure and non-secure regimes for A-profile,
  *     because there are no banked system registers for aarch64, so the
  *     because there are no banked system registers for aarch64, so the
  *     process of switching between secure and non-secure is
  *     process of switching between secure and non-secure is
  *     already heavyweight.
  *     already heavyweight.
- *  7. we cannot fold together Stage 2 Secure and Stage 2 NonSecure,
+ *  8. we cannot fold together Stage 2 Secure and Stage 2 NonSecure,
  *     because both are in use simultaneously for Secure EL2.
  *     because both are in use simultaneously for Secure EL2.
  *
  *
  * This gives us the following list of cases:
  * This gives us the following list of cases:
  *
  *
- * EL0 EL1&0 stage 1+2 (or AArch32 PL0 PL1&0 stage 1+2)
- * EL1 EL1&0 stage 1+2 (or AArch32 PL1 PL1&0 stage 1+2)
- * EL1 EL1&0 stage 1+2 +PAN (or AArch32 PL1 PL1&0 stage 1+2 +PAN)
+ * EL0 EL1&0 stage 1+2 (aka NS PL0 PL1&0 stage 1+2)
+ * EL1 EL1&0 stage 1+2 (aka NS PL1 PL1&0 stage 1+2)
+ * EL1 EL1&0 stage 1+2 +PAN (aka NS PL1 P1&0 stage 1+2 +PAN)
  * EL0 EL2&0
  * EL0 EL2&0
  * EL2 EL2&0
  * EL2 EL2&0
  * EL2 EL2&0 +PAN
  * EL2 EL2&0 +PAN
  * EL2 (aka NS PL2)
  * EL2 (aka NS PL2)
- * EL3 (not used when EL3 is AArch32)
+ * EL3 (aka AArch32 S PL1 PL1&0)
+ * AArch32 S PL0 PL1&0 (we call this EL30_0)
+ * AArch32 S PL1 PL1&0 +PAN (we call this EL30_3_PAN)
  * Stage2 Secure
  * Stage2 Secure
  * Stage2 NonSecure
  * Stage2 NonSecure
  * plus one TLB per Physical address space: S, NS, Realm, Root
  * plus one TLB per Physical address space: S, NS, Realm, Root
  *
  *
- * for a total of 14 different mmu_idx.
- *
- * Note that when EL3 is AArch32, the usage is potentially confusing
- * because the MMU indexes are named for their AArch64 use, so code
- * using the ARMMMUIdx_E10_1 might be at EL3, not EL1. This is because
- * Secure PL1 is always at EL3.
+ * for a total of 16 different mmu_idx.
  *
  *
  * R profile CPUs have an MPU, but can use the same set of MMU indexes
  * R profile CPUs have an MPU, but can use the same set of MMU indexes
  * as A profile. They only need to distinguish EL0 and EL1 (and
  * as A profile. They only need to distinguish EL0 and EL1 (and
@@ -2900,6 +2901,8 @@ typedef enum ARMMMUIdx {
     ARMMMUIdx_E20_2_PAN = 5 | ARM_MMU_IDX_A,
     ARMMMUIdx_E20_2_PAN = 5 | ARM_MMU_IDX_A,
     ARMMMUIdx_E2        = 6 | ARM_MMU_IDX_A,
     ARMMMUIdx_E2        = 6 | ARM_MMU_IDX_A,
     ARMMMUIdx_E3        = 7 | ARM_MMU_IDX_A,
     ARMMMUIdx_E3        = 7 | ARM_MMU_IDX_A,
+    ARMMMUIdx_E30_0     = 8 | ARM_MMU_IDX_A,
+    ARMMMUIdx_E30_3_PAN = 9 | ARM_MMU_IDX_A,
 
 
     /*
     /*
      * Used for second stage of an S12 page table walk, or for descriptor
      * Used for second stage of an S12 page table walk, or for descriptor
@@ -2907,14 +2910,14 @@ typedef enum ARMMMUIdx {
      * are in use simultaneously for SecureEL2: the security state for
      * are in use simultaneously for SecureEL2: the security state for
      * the S2 ptw is selected by the NS bit from the S1 ptw.
      * the S2 ptw is selected by the NS bit from the S1 ptw.
      */
      */
-    ARMMMUIdx_Stage2_S  = 8 | ARM_MMU_IDX_A,
-    ARMMMUIdx_Stage2    = 9 | ARM_MMU_IDX_A,
+    ARMMMUIdx_Stage2_S  = 10 | ARM_MMU_IDX_A,
+    ARMMMUIdx_Stage2    = 11 | ARM_MMU_IDX_A,
 
 
     /* TLBs with 1-1 mapping to the physical address spaces. */
     /* TLBs with 1-1 mapping to the physical address spaces. */
-    ARMMMUIdx_Phys_S     = 10 | ARM_MMU_IDX_A,
-    ARMMMUIdx_Phys_NS    = 11 | ARM_MMU_IDX_A,
-    ARMMMUIdx_Phys_Root  = 12 | ARM_MMU_IDX_A,
-    ARMMMUIdx_Phys_Realm = 13 | ARM_MMU_IDX_A,
+    ARMMMUIdx_Phys_S     = 12 | ARM_MMU_IDX_A,
+    ARMMMUIdx_Phys_NS    = 13 | ARM_MMU_IDX_A,
+    ARMMMUIdx_Phys_Root  = 14 | ARM_MMU_IDX_A,
+    ARMMMUIdx_Phys_Realm = 15 | ARM_MMU_IDX_A,
 
 
     /*
     /*
      * These are not allocated TLBs and are used only for AT system
      * These are not allocated TLBs and are used only for AT system
@@ -2953,6 +2956,8 @@ typedef enum ARMMMUIdxBit {
     TO_CORE_BIT(E20_2),
     TO_CORE_BIT(E20_2),
     TO_CORE_BIT(E20_2_PAN),
     TO_CORE_BIT(E20_2_PAN),
     TO_CORE_BIT(E3),
     TO_CORE_BIT(E3),
+    TO_CORE_BIT(E30_0),
+    TO_CORE_BIT(E30_3_PAN),
     TO_CORE_BIT(Stage2),
     TO_CORE_BIT(Stage2),
     TO_CORE_BIT(Stage2_S),
     TO_CORE_BIT(Stage2_S),
 
 
@@ -3130,10 +3135,6 @@ FIELD(TBFLAG_A32, NS, 10, 1)
  * This requires an SME trap from AArch32 mode when using NEON.
  * This requires an SME trap from AArch32 mode when using NEON.
  */
  */
 FIELD(TBFLAG_A32, SME_TRAP_NONSTREAMING, 11, 1)
 FIELD(TBFLAG_A32, SME_TRAP_NONSTREAMING, 11, 1)
-/*
- * Indicates whether we are in the Secure PL1&0 translation regime
- */
-FIELD(TBFLAG_A32, S_PL1_0, 12, 1)
 
 
 /*
 /*
  * Bit usage when in AArch32 state, for M-profile only.
  * Bit usage when in AArch32 state, for M-profile only.

+ 48 - 25
target/arm/helper.c

@@ -444,6 +444,9 @@ static int alle1_tlbmask(CPUARMState *env)
      * Note that the 'ALL' scope must invalidate both stage 1 and
      * Note that the 'ALL' scope must invalidate both stage 1 and
      * stage 2 translations, whereas most other scopes only invalidate
      * stage 2 translations, whereas most other scopes only invalidate
      * stage 1 translations.
      * stage 1 translations.
+     *
+     * For AArch32 this is only used for TLBIALLNSNH and VTTBR
+     * writes, so only needs to apply to NS PL1&0, not S PL1&0.
      */
      */
     return (ARMMMUIdxBit_E10_1 |
     return (ARMMMUIdxBit_E10_1 |
             ARMMMUIdxBit_E10_1_PAN |
             ARMMMUIdxBit_E10_1_PAN |
@@ -3701,7 +3704,7 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value,
          */
          */
         format64 = arm_s1_regime_using_lpae_format(env, mmu_idx);
         format64 = arm_s1_regime_using_lpae_format(env, mmu_idx);
 
 
-        if (arm_feature(env, ARM_FEATURE_EL2) && !arm_aa32_secure_pl1_0(env)) {
+        if (arm_feature(env, ARM_FEATURE_EL2)) {
             if (mmu_idx == ARMMMUIdx_E10_0 ||
             if (mmu_idx == ARMMMUIdx_E10_0 ||
                 mmu_idx == ARMMMUIdx_E10_1 ||
                 mmu_idx == ARMMMUIdx_E10_1 ||
                 mmu_idx == ARMMMUIdx_E10_1_PAN) {
                 mmu_idx == ARMMMUIdx_E10_1_PAN) {
@@ -3775,11 +3778,17 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
     case 0:
     case 0:
         /* stage 1 current state PL1: ATS1CPR, ATS1CPW, ATS1CPRP, ATS1CPWP */
         /* stage 1 current state PL1: ATS1CPR, ATS1CPW, ATS1CPRP, ATS1CPWP */
         switch (el) {
         switch (el) {
+        case 3:
+            if (ri->crm == 9 && arm_pan_enabled(env)) {
+                mmu_idx = ARMMMUIdx_E30_3_PAN;
+            } else {
+                mmu_idx = ARMMMUIdx_E3;
+            }
+            break;
         case 2:
         case 2:
             g_assert(ss != ARMSS_Secure);  /* ARMv8.4-SecEL2 is 64-bit only */
             g_assert(ss != ARMSS_Secure);  /* ARMv8.4-SecEL2 is 64-bit only */
             /* fall through */
             /* fall through */
         case 1:
         case 1:
-        case 3:
             if (ri->crm == 9 && arm_pan_enabled(env)) {
             if (ri->crm == 9 && arm_pan_enabled(env)) {
                 mmu_idx = ARMMMUIdx_Stage1_E1_PAN;
                 mmu_idx = ARMMMUIdx_Stage1_E1_PAN;
             } else {
             } else {
@@ -3794,7 +3803,7 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
         /* stage 1 current state PL0: ATS1CUR, ATS1CUW */
         /* stage 1 current state PL0: ATS1CUR, ATS1CUW */
         switch (el) {
         switch (el) {
         case 3:
         case 3:
-            mmu_idx = ARMMMUIdx_E10_0;
+            mmu_idx = ARMMMUIdx_E30_0;
             break;
             break;
         case 2:
         case 2:
             g_assert(ss != ARMSS_Secure);  /* ARMv8.4-SecEL2 is 64-bit only */
             g_assert(ss != ARMSS_Secure);  /* ARMv8.4-SecEL2 is 64-bit only */
@@ -4904,11 +4913,14 @@ static int vae1_tlbmask(CPUARMState *env)
     uint64_t hcr = arm_hcr_el2_eff(env);
     uint64_t hcr = arm_hcr_el2_eff(env);
     uint16_t mask;
     uint16_t mask;
 
 
+    assert(arm_feature(env, ARM_FEATURE_AARCH64));
+
     if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
     if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
         mask = ARMMMUIdxBit_E20_2 |
         mask = ARMMMUIdxBit_E20_2 |
                ARMMMUIdxBit_E20_2_PAN |
                ARMMMUIdxBit_E20_2_PAN |
                ARMMMUIdxBit_E20_0;
                ARMMMUIdxBit_E20_0;
     } else {
     } else {
+        /* This is AArch64 only, so we don't need to touch the EL30_x TLBs */
         mask = ARMMMUIdxBit_E10_1 |
         mask = ARMMMUIdxBit_E10_1 |
                ARMMMUIdxBit_E10_1_PAN |
                ARMMMUIdxBit_E10_1_PAN |
                ARMMMUIdxBit_E10_0;
                ARMMMUIdxBit_E10_0;
@@ -4947,6 +4959,8 @@ static int vae1_tlbbits(CPUARMState *env, uint64_t addr)
     uint64_t hcr = arm_hcr_el2_eff(env);
     uint64_t hcr = arm_hcr_el2_eff(env);
     ARMMMUIdx mmu_idx;
     ARMMMUIdx mmu_idx;
 
 
+    assert(arm_feature(env, ARM_FEATURE_AARCH64));
+
     /* Only the regime of the mmu_idx below is significant. */
     /* Only the regime of the mmu_idx below is significant. */
     if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
     if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
         mmu_idx = ARMMMUIdx_E20_0;
         mmu_idx = ARMMMUIdx_E20_0;
@@ -6215,6 +6229,11 @@ static void hcrx_write(CPUARMState *env, const ARMCPRegInfo *ri,
     if (cpu_isar_feature(aa64_nmi, cpu)) {
     if (cpu_isar_feature(aa64_nmi, cpu)) {
         valid_mask |= HCRX_TALLINT | HCRX_VINMI | HCRX_VFNMI;
         valid_mask |= HCRX_TALLINT | HCRX_VINMI | HCRX_VFNMI;
     }
     }
+    /* FEAT_CMOW adds CMOW */
+
+    if (cpu_isar_feature(aa64_cmow, cpu)) {
+        valid_mask |= HCRX_CMOW;
+    }
 
 
     /* Clear RES0 bits.  */
     /* Clear RES0 bits.  */
     env->cp15.hcrx_el2 = value & valid_mask;
     env->cp15.hcrx_el2 = value & valid_mask;
@@ -11860,13 +11879,20 @@ void arm_cpu_do_interrupt(CPUState *cs)
 
 
 uint64_t arm_sctlr(CPUARMState *env, int el)
 uint64_t arm_sctlr(CPUARMState *env, int el)
 {
 {
-    if (arm_aa32_secure_pl1_0(env)) {
-        /* In Secure PL1&0 SCTLR_S is always controlling */
-        el = 3;
-    } else if (el == 0) {
-        /* Only EL0 needs to be adjusted for EL1&0 or EL2&0. */
+    /* Only EL0 needs to be adjusted for EL1&0 or EL2&0 or EL3&0 */
+    if (el == 0) {
         ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, 0);
         ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, 0);
-        el = mmu_idx == ARMMMUIdx_E20_0 ? 2 : 1;
+        switch (mmu_idx) {
+        case ARMMMUIdx_E20_0:
+            el = 2;
+            break;
+        case ARMMMUIdx_E30_0:
+            el = 3;
+            break;
+        default:
+            el = 1;
+            break;
+        }
     }
     }
     return env->cp15.sctlr_el[el];
     return env->cp15.sctlr_el[el];
 }
 }
@@ -12524,12 +12550,8 @@ int fp_exception_el(CPUARMState *env, int cur_el)
     return 0;
     return 0;
 }
 }
 
 
-/*
- * Return the exception level we're running at if this is our mmu_idx.
- * s_pl1_0 should be true if this is the AArch32 Secure PL1&0 translation
- * regime.
- */
-int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx, bool s_pl1_0)
+/* Return the exception level we're running at if this is our mmu_idx */
+int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx)
 {
 {
     if (mmu_idx & ARM_MMU_IDX_M) {
     if (mmu_idx & ARM_MMU_IDX_M) {
         return mmu_idx & ARM_MMU_IDX_M_PRIV;
         return mmu_idx & ARM_MMU_IDX_M_PRIV;
@@ -12538,15 +12560,17 @@ int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx, bool s_pl1_0)
     switch (mmu_idx) {
     switch (mmu_idx) {
     case ARMMMUIdx_E10_0:
     case ARMMMUIdx_E10_0:
     case ARMMMUIdx_E20_0:
     case ARMMMUIdx_E20_0:
+    case ARMMMUIdx_E30_0:
         return 0;
         return 0;
     case ARMMMUIdx_E10_1:
     case ARMMMUIdx_E10_1:
     case ARMMMUIdx_E10_1_PAN:
     case ARMMMUIdx_E10_1_PAN:
-        return s_pl1_0 ? 3 : 1;
+        return 1;
     case ARMMMUIdx_E2:
     case ARMMMUIdx_E2:
     case ARMMMUIdx_E20_2:
     case ARMMMUIdx_E20_2:
     case ARMMMUIdx_E20_2_PAN:
     case ARMMMUIdx_E20_2_PAN:
         return 2;
         return 2;
     case ARMMMUIdx_E3:
     case ARMMMUIdx_E3:
+    case ARMMMUIdx_E30_3_PAN:
         return 3;
         return 3;
     default:
     default:
         g_assert_not_reached();
         g_assert_not_reached();
@@ -12575,19 +12599,13 @@ ARMMMUIdx arm_mmu_idx_el(CPUARMState *env, int el)
         hcr = arm_hcr_el2_eff(env);
         hcr = arm_hcr_el2_eff(env);
         if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
         if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
             idx = ARMMMUIdx_E20_0;
             idx = ARMMMUIdx_E20_0;
+        } else if (arm_is_secure_below_el3(env) &&
+                   !arm_el_is_aa64(env, 3)) {
+            idx = ARMMMUIdx_E30_0;
         } else {
         } else {
             idx = ARMMMUIdx_E10_0;
             idx = ARMMMUIdx_E10_0;
         }
         }
         break;
         break;
-    case 3:
-        /*
-         * AArch64 EL3 has its own translation regime; AArch32 EL3
-         * uses the Secure PL1&0 translation regime.
-         */
-        if (arm_el_is_aa64(env, 3)) {
-            return ARMMMUIdx_E3;
-        }
-        /* fall through */
     case 1:
     case 1:
         if (arm_pan_enabled(env)) {
         if (arm_pan_enabled(env)) {
             idx = ARMMMUIdx_E10_1_PAN;
             idx = ARMMMUIdx_E10_1_PAN;
@@ -12607,6 +12625,11 @@ ARMMMUIdx arm_mmu_idx_el(CPUARMState *env, int el)
             idx = ARMMMUIdx_E2;
             idx = ARMMMUIdx_E2;
         }
         }
         break;
         break;
+    case 3:
+        if (!arm_el_is_aa64(env, 3) && arm_pan_enabled(env)) {
+            return ARMMMUIdx_E30_3_PAN;
+        }
+        return ARMMMUIdx_E3;
     default:
     default:
         g_assert_not_reached();
         g_assert_not_reached();
     }
     }

+ 17 - 24
target/arm/internals.h

@@ -275,20 +275,6 @@ FIELD(CNTHCTL, CNTPMASK, 19, 1)
 #define M_FAKE_FSR_NSC_EXEC 0xf /* NS executing in S&NSC memory */
 #define M_FAKE_FSR_NSC_EXEC 0xf /* NS executing in S&NSC memory */
 #define M_FAKE_FSR_SFAULT 0xe /* SecureFault INVTRAN, INVEP or AUVIOL */
 #define M_FAKE_FSR_SFAULT 0xe /* SecureFault INVTRAN, INVEP or AUVIOL */
 
 
-/**
- * arm_aa32_secure_pl1_0(): Return true if in Secure PL1&0 regime
- *
- * Return true if the CPU is in the Secure PL1&0 translation regime.
- * This requires that EL3 exists and is AArch32 and we are currently
- * Secure. If this is the case then the ARMMMUIdx_E10* apply and
- * mean we are in EL3, not EL1.
- */
-static inline bool arm_aa32_secure_pl1_0(CPUARMState *env)
-{
-    return arm_feature(env, ARM_FEATURE_EL3) &&
-        !arm_el_is_aa64(env, 3) && arm_is_secure(env);
-}
-
 /**
 /**
  * raise_exception: Raise the specified exception.
  * raise_exception: Raise the specified exception.
  * Raise a guest exception with the specified value, syndrome register
  * Raise a guest exception with the specified value, syndrome register
@@ -841,12 +827,7 @@ static inline ARMMMUIdx core_to_aa64_mmu_idx(int mmu_idx)
     return mmu_idx | ARM_MMU_IDX_A;
     return mmu_idx | ARM_MMU_IDX_A;
 }
 }
 
 
-/**
- * Return the exception level we're running at if our current MMU index
- * is @mmu_idx. @s_pl1_0 should be true if this is the AArch32
- * Secure PL1&0 translation regime.
- */
-int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx, bool s_pl1_0);
+int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx);
 
 
 /* Return the MMU index for a v7M CPU in the specified security state */
 /* Return the MMU index for a v7M CPU in the specified security state */
 ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate);
 ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate);
@@ -890,7 +871,16 @@ static inline void arm_call_el_change_hook(ARMCPU *cpu)
     }
     }
 }
 }
 
 
-/* Return true if this address translation regime has two ranges.  */
+/*
+ * Return true if this address translation regime has two ranges.
+ * Note that this will not return the correct answer for AArch32
+ * Secure PL1&0 (i.e. mmu indexes E3, E30_0, E30_3_PAN), but it is
+ * never called from a context where EL3 can be AArch32. (The
+ * correct return value for ARMMMUIdx_E3 would be different for
+ * that case, so we can't just make the function return the
+ * correct value anyway; we would need an extra "bool e3_is_aarch32"
+ * argument which all the current callsites would pass as 'false'.)
+ */
 static inline bool regime_has_2_ranges(ARMMMUIdx mmu_idx)
 static inline bool regime_has_2_ranges(ARMMMUIdx mmu_idx)
 {
 {
     switch (mmu_idx) {
     switch (mmu_idx) {
@@ -915,6 +905,7 @@ static inline bool regime_is_pan(CPUARMState *env, ARMMMUIdx mmu_idx)
     case ARMMMUIdx_Stage1_E1_PAN:
     case ARMMMUIdx_Stage1_E1_PAN:
     case ARMMMUIdx_E10_1_PAN:
     case ARMMMUIdx_E10_1_PAN:
     case ARMMMUIdx_E20_2_PAN:
     case ARMMMUIdx_E20_2_PAN:
+    case ARMMMUIdx_E30_3_PAN:
         return true;
         return true;
     default:
     default:
         return false;
         return false;
@@ -938,14 +929,15 @@ static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx)
     case ARMMMUIdx_E2:
     case ARMMMUIdx_E2:
         return 2;
         return 2;
     case ARMMMUIdx_E3:
     case ARMMMUIdx_E3:
+    case ARMMMUIdx_E30_0:
+    case ARMMMUIdx_E30_3_PAN:
         return 3;
         return 3;
     case ARMMMUIdx_E10_0:
     case ARMMMUIdx_E10_0:
     case ARMMMUIdx_Stage1_E0:
     case ARMMMUIdx_Stage1_E0:
-    case ARMMMUIdx_E10_1:
-    case ARMMMUIdx_E10_1_PAN:
     case ARMMMUIdx_Stage1_E1:
     case ARMMMUIdx_Stage1_E1:
     case ARMMMUIdx_Stage1_E1_PAN:
     case ARMMMUIdx_Stage1_E1_PAN:
-        return arm_el_is_aa64(env, 3) || !arm_is_secure_below_el3(env) ? 1 : 3;
+    case ARMMMUIdx_E10_1:
+    case ARMMMUIdx_E10_1_PAN:
     case ARMMMUIdx_MPrivNegPri:
     case ARMMMUIdx_MPrivNegPri:
     case ARMMMUIdx_MUserNegPri:
     case ARMMMUIdx_MUserNegPri:
     case ARMMMUIdx_MPriv:
     case ARMMMUIdx_MPriv:
@@ -965,6 +957,7 @@ static inline bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx)
     switch (mmu_idx) {
     switch (mmu_idx) {
     case ARMMMUIdx_E10_0:
     case ARMMMUIdx_E10_0:
     case ARMMMUIdx_E20_0:
     case ARMMMUIdx_E20_0:
+    case ARMMMUIdx_E30_0:
     case ARMMMUIdx_Stage1_E0:
     case ARMMMUIdx_Stage1_E0:
     case ARMMMUIdx_MUser:
     case ARMMMUIdx_MUser:
     case ARMMMUIdx_MSUser:
     case ARMMMUIdx_MSUser:

+ 5 - 5
target/arm/ptw.c

@@ -280,6 +280,8 @@ static bool regime_translation_disabled(CPUARMState *env, ARMMMUIdx mmu_idx,
     case ARMMMUIdx_E20_2_PAN:
     case ARMMMUIdx_E20_2_PAN:
     case ARMMMUIdx_E2:
     case ARMMMUIdx_E2:
     case ARMMMUIdx_E3:
     case ARMMMUIdx_E3:
+    case ARMMMUIdx_E30_0:
+    case ARMMMUIdx_E30_3_PAN:
         break;
         break;
 
 
     case ARMMMUIdx_Phys_S:
     case ARMMMUIdx_Phys_S:
@@ -3607,11 +3609,7 @@ bool get_phys_addr(CPUARMState *env, vaddr address,
     case ARMMMUIdx_Stage1_E1:
     case ARMMMUIdx_Stage1_E1:
     case ARMMMUIdx_Stage1_E1_PAN:
     case ARMMMUIdx_Stage1_E1_PAN:
     case ARMMMUIdx_E2:
     case ARMMMUIdx_E2:
-        if (arm_aa32_secure_pl1_0(env)) {
-            ss = ARMSS_Secure;
-        } else {
-            ss = arm_security_space_below_el3(env);
-        }
+        ss = arm_security_space_below_el3(env);
         break;
         break;
     case ARMMMUIdx_Stage2:
     case ARMMMUIdx_Stage2:
         /*
         /*
@@ -3639,6 +3637,8 @@ bool get_phys_addr(CPUARMState *env, vaddr address,
         ss = ARMSS_Secure;
         ss = ARMSS_Secure;
         break;
         break;
     case ARMMMUIdx_E3:
     case ARMMMUIdx_E3:
+    case ARMMMUIdx_E30_0:
+    case ARMMMUIdx_E30_3_PAN:
         if (arm_feature(env, ARM_FEATURE_AARCH64) &&
         if (arm_feature(env, ARM_FEATURE_AARCH64) &&
             cpu_isar_feature(aa64_rme, env_archcpu(env))) {
             cpu_isar_feature(aa64_rme, env_archcpu(env))) {
             ss = ARMSS_Root;
             ss = ARMSS_Root;

+ 1 - 0
target/arm/tcg/cpu64.c

@@ -1218,6 +1218,7 @@ void aarch64_max_tcg_initfn(Object *obj)
     t = FIELD_DP64(t, ID_AA64MMFR1, ETS, 2);      /* FEAT_ETS2 */
     t = FIELD_DP64(t, ID_AA64MMFR1, ETS, 2);      /* FEAT_ETS2 */
     t = FIELD_DP64(t, ID_AA64MMFR1, HCX, 1);      /* FEAT_HCX */
     t = FIELD_DP64(t, ID_AA64MMFR1, HCX, 1);      /* FEAT_HCX */
     t = FIELD_DP64(t, ID_AA64MMFR1, TIDCP1, 1);   /* FEAT_TIDCP1 */
     t = FIELD_DP64(t, ID_AA64MMFR1, TIDCP1, 1);   /* FEAT_TIDCP1 */
+    t = FIELD_DP64(t, ID_AA64MMFR1, CMOW, 1);     /* FEAT_CMOW */
     cpu->isar.id_aa64mmfr1 = t;
     cpu->isar.id_aa64mmfr1 = t;
 
 
     t = cpu->isar.id_aa64mmfr2;
     t = cpu->isar.id_aa64mmfr2;

+ 0 - 4
target/arm/tcg/hflags.c

@@ -198,10 +198,6 @@ static CPUARMTBFlags rebuild_hflags_a32(CPUARMState *env, int fp_el,
         DP_TBFLAG_A32(flags, SME_TRAP_NONSTREAMING, 1);
         DP_TBFLAG_A32(flags, SME_TRAP_NONSTREAMING, 1);
     }
     }
 
 
-    if (arm_aa32_secure_pl1_0(env)) {
-        DP_TBFLAG_A32(flags, S_PL1_0, 1);
-    }
-
     return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags);
     return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags);
 }
 }
 
 

+ 13 - 1
target/arm/tcg/op_helper.c

@@ -912,7 +912,19 @@ void HELPER(tidcp_el0)(CPUARMState *env, uint32_t syndrome)
 {
 {
     /* See arm_sctlr(), but we also need the sctlr el. */
     /* See arm_sctlr(), but we also need the sctlr el. */
     ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, 0);
     ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, 0);
-    int target_el = mmu_idx == ARMMMUIdx_E20_0 ? 2 : 1;
+    int target_el;
+
+    switch (mmu_idx) {
+    case ARMMMUIdx_E20_0:
+        target_el = 2;
+        break;
+    case ARMMMUIdx_E30_0:
+        target_el = 3;
+        break;
+    default:
+        target_el = 1;
+        break;
+    }
 
 
     /*
     /*
      * The bit is not valid unless the target el is aa64, but since the
      * The bit is not valid unless the target el is aa64, but since the

+ 1 - 1
target/arm/tcg/translate-a64.c

@@ -11690,7 +11690,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase,
     dc->tbii = EX_TBFLAG_A64(tb_flags, TBII);
     dc->tbii = EX_TBFLAG_A64(tb_flags, TBII);
     dc->tbid = EX_TBFLAG_A64(tb_flags, TBID);
     dc->tbid = EX_TBFLAG_A64(tb_flags, TBID);
     dc->tcma = EX_TBFLAG_A64(tb_flags, TCMA);
     dc->tcma = EX_TBFLAG_A64(tb_flags, TCMA);
-    dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx, false);
+    dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
 #if !defined(CONFIG_USER_ONLY)
 #if !defined(CONFIG_USER_ONLY)
     dc->user = (dc->current_el == 0);
     dc->user = (dc->current_el == 0);
 #endif
 #endif

+ 7 - 5
target/arm/tcg/translate.c

@@ -228,6 +228,9 @@ static inline int get_a32_user_mem_index(DisasContext *s)
      */
      */
     switch (s->mmu_idx) {
     switch (s->mmu_idx) {
     case ARMMMUIdx_E3:
     case ARMMMUIdx_E3:
+    case ARMMMUIdx_E30_0:
+    case ARMMMUIdx_E30_3_PAN:
+        return arm_to_core_mmu_idx(ARMMMUIdx_E30_0);
     case ARMMMUIdx_E2:        /* this one is UNPREDICTABLE */
     case ARMMMUIdx_E2:        /* this one is UNPREDICTABLE */
     case ARMMMUIdx_E10_0:
     case ARMMMUIdx_E10_0:
     case ARMMMUIdx_E10_1:
     case ARMMMUIdx_E10_1:
@@ -7546,6 +7549,10 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
 
 
     core_mmu_idx = EX_TBFLAG_ANY(tb_flags, MMUIDX);
     core_mmu_idx = EX_TBFLAG_ANY(tb_flags, MMUIDX);
     dc->mmu_idx = core_to_arm_mmu_idx(env, core_mmu_idx);
     dc->mmu_idx = core_to_arm_mmu_idx(env, core_mmu_idx);
+    dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
+#if !defined(CONFIG_USER_ONLY)
+    dc->user = (dc->current_el == 0);
+#endif
     dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL);
     dc->fp_excp_el = EX_TBFLAG_ANY(tb_flags, FPEXC_EL);
     dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM);
     dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM);
     dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL);
     dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL);
@@ -7576,12 +7583,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
         }
         }
         dc->sme_trap_nonstreaming =
         dc->sme_trap_nonstreaming =
             EX_TBFLAG_A32(tb_flags, SME_TRAP_NONSTREAMING);
             EX_TBFLAG_A32(tb_flags, SME_TRAP_NONSTREAMING);
-        dc->s_pl1_0 = EX_TBFLAG_A32(tb_flags, S_PL1_0);
     }
     }
-    dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx, dc->s_pl1_0);
-#if !defined(CONFIG_USER_ONLY)
-    dc->user = (dc->current_el == 0);
-#endif
     dc->lse2 = false; /* applies only to aarch64 */
     dc->lse2 = false; /* applies only to aarch64 */
     dc->cp_regs = cpu->cp_regs;
     dc->cp_regs = cpu->cp_regs;
     dc->features = env->features;
     dc->features = env->features;

+ 0 - 2
target/arm/tcg/translate.h

@@ -165,8 +165,6 @@ typedef struct DisasContext {
     uint8_t gm_blocksize;
     uint8_t gm_blocksize;
     /* True if the current insn_start has been updated. */
     /* True if the current insn_start has been updated. */
     bool insn_start_updated;
     bool insn_start_updated;
-    /* True if this is the AArch32 Secure PL1&0 translation regime */
-    bool s_pl1_0;
     /* Bottom two bits of XScale c15_cpar coprocessor access control reg */
     /* Bottom two bits of XScale c15_cpar coprocessor access control reg */
     int c15_cpar;
     int c15_cpar;
     /* Offset from VNCR_EL2 when FEAT_NV2 redirects this reg to memory */
     /* Offset from VNCR_EL2 when FEAT_NV2 redirects this reg to memory */

+ 8 - 1
target/arm/tcg/vec_helper.c

@@ -836,6 +836,13 @@ void HELPER(NAME)(void *vd, void *vn, void *vm, void *va, uint32_t desc)  \
 {                                                                         \
 {                                                                         \
     intptr_t i = 0, opr_sz = simd_oprsz(desc);                            \
     intptr_t i = 0, opr_sz = simd_oprsz(desc);                            \
     intptr_t opr_sz_n = opr_sz / sizeof(TYPED);                           \
     intptr_t opr_sz_n = opr_sz / sizeof(TYPED);                           \
+    /*                                                                    \
+     * Special case: opr_sz == 8 from AA64/AA32 advsimd means the         \
+     * first iteration might not be a full 16 byte segment. But           \
+     * for vector lengths beyond that this must be SVE and we know        \
+     * opr_sz is a multiple of 16, so we need not clamp segend            \
+     * to opr_sz_n when we advance it at the end of the loop.             \
+     */                                                                   \
     intptr_t segend = MIN(16 / sizeof(TYPED), opr_sz_n);                  \
     intptr_t segend = MIN(16 / sizeof(TYPED), opr_sz_n);                  \
     intptr_t index = simd_data(desc);                                     \
     intptr_t index = simd_data(desc);                                     \
     TYPED *d = vd, *a = va;                                               \
     TYPED *d = vd, *a = va;                                               \
@@ -853,7 +860,7 @@ void HELPER(NAME)(void *vd, void *vn, void *vm, void *va, uint32_t desc)  \
                     n[i * 4 + 2] * m2 +                                   \
                     n[i * 4 + 2] * m2 +                                   \
                     n[i * 4 + 3] * m3);                                   \
                     n[i * 4 + 3] * m3);                                   \
         } while (++i < segend);                                           \
         } while (++i < segend);                                           \
-        segend = i + 4;                                                   \
+        segend = i + (16 / sizeof(TYPED));                                \
     } while (i < opr_sz_n);                                               \
     } while (i < opr_sz_n);                                               \
     clear_tail(d, opr_sz, simd_maxsz(desc));                              \
     clear_tail(d, opr_sz, simd_maxsz(desc));                              \
 }
 }

+ 6 - 0
target/hppa/fpu_helper.c

@@ -49,6 +49,12 @@ void HELPER(loaded_fr0)(CPUHPPAState *env)
     d = FIELD_EX32(shadow, FPSR, D);
     d = FIELD_EX32(shadow, FPSR, D);
     set_flush_to_zero(d, &env->fp_status);
     set_flush_to_zero(d, &env->fp_status);
     set_flush_inputs_to_zero(d, &env->fp_status);
     set_flush_inputs_to_zero(d, &env->fp_status);
+
+    /*
+     * TODO: we only need to do this at CPU reset, but currently
+     * HPPA does note implement a CPU reset method at all...
+     */
+    set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fp_status);
 }
 }
 
 
 void cpu_hppa_loaded_fr0(CPUHPPAState *env)
 void cpu_hppa_loaded_fr0(CPUHPPAState *env)

+ 4 - 0
target/i386/cpu.c

@@ -7200,6 +7200,10 @@ static void x86_cpu_reset_hold(Object *obj, ResetType type)
 
 
     memset(env, 0, offsetof(CPUX86State, end_reset_fields));
     memset(env, 0, offsetof(CPUX86State, end_reset_fields));
 
 
+    if (tcg_enabled()) {
+        cpu_init_fp_statuses(env);
+    }
+
     env->old_exception = -1;
     env->old_exception = -1;
 
 
     /* init to reset state */
     /* init to reset state */

+ 3 - 0
target/i386/cpu.h

@@ -2614,6 +2614,9 @@ static inline bool cpu_vmx_maybe_enabled(CPUX86State *env)
 int get_pg_mode(CPUX86State *env);
 int get_pg_mode(CPUX86State *env);
 
 
 /* fpu_helper.c */
 /* fpu_helper.c */
+
+/* Set all non-runtime-variable float_status fields to x86 handling */
+void cpu_init_fp_statuses(CPUX86State *env);
 void update_fp_status(CPUX86State *env);
 void update_fp_status(CPUX86State *env);
 void update_mxcsr_status(CPUX86State *env);
 void update_mxcsr_status(CPUX86State *env);
 void update_mxcsr_from_sse_status(CPUX86State *env);
 void update_mxcsr_from_sse_status(CPUX86State *env);

+ 40 - 0
target/i386/tcg/fpu_helper.c

@@ -135,6 +135,46 @@ static void fpu_set_exception(CPUX86State *env, int mask)
     }
     }
 }
 }
 
 
+void cpu_init_fp_statuses(CPUX86State *env)
+{
+    /*
+     * Initialise the non-runtime-varying fields of the various
+     * float_status words to x86 behaviour. This must be called at
+     * CPU reset because the float_status words are in the
+     * "zeroed on reset" portion of the CPU state struct.
+     * Fields in float_status that vary under guest control are set
+     * via the codepath for setting that register, eg cpu_set_fpuc().
+     */
+    /*
+     * Use x87 NaN propagation rules:
+     * SNaN + QNaN => return the QNaN
+     * two SNaNs => return the one with the larger significand, silenced
+     * two QNaNs => return the one with the larger significand
+     * SNaN and a non-NaN => return the SNaN, silenced
+     * QNaN and a non-NaN => return the QNaN
+     *
+     * If we get down to comparing significands and they are the same,
+     * return the NaN with the positive sign bit (if any).
+     */
+    set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status);
+    /*
+     * TODO: These are incorrect: the x86 Software Developer's Manual vol 1
+     * section 4.8.3.5 "Operating on SNaNs and QNaNs" says that the
+     * "larger significand" behaviour is only used for x87 FPU operations.
+     * For SSE the required behaviour is to always return the first NaN,
+     * which is float_2nan_prop_ab.
+     *
+     * mmx_status is used only for the AMD 3DNow! instructions, which
+     * are documented in the "3DNow! Technology Manual" as not supporting
+     * NaNs or infinities as inputs. The result of passing two NaNs is
+     * documented as "undefined", so we can do what we choose.
+     * (Strictly there is some behaviour we don't implement correctly
+     * for these "unsupported" NaN and Inf values, like "NaN * 0 == 0".)
+     */
+    set_float_2nan_prop_rule(float_2nan_prop_x87, &env->mmx_status);
+    set_float_2nan_prop_rule(float_2nan_prop_x87, &env->sse_status);
+}
+
 static inline uint8_t save_exception_flags(CPUX86State *env)
 static inline uint8_t save_exception_flags(CPUX86State *env)
 {
 {
     uint8_t old_flags = get_float_exception_flags(&env->fp_status);
     uint8_t old_flags = get_float_exception_flags(&env->fp_status);

+ 1 - 0
target/loongarch/tcg/fpu_helper.c

@@ -31,6 +31,7 @@ void restore_fp_status(CPULoongArchState *env)
     set_float_rounding_mode(ieee_rm[(env->fcsr0 >> FCSR0_RM) & 0x3],
     set_float_rounding_mode(ieee_rm[(env->fcsr0 >> FCSR0_RM) & 0x3],
                             &env->fp_status);
                             &env->fp_status);
     set_flush_to_zero(0, &env->fp_status);
     set_flush_to_zero(0, &env->fp_status);
+    set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fp_status);
 }
 }
 
 
 int ieee_ex_to_loongarch(int xcpt)
 int ieee_ex_to_loongarch(int xcpt)

+ 16 - 0
target/m68k/cpu.c

@@ -93,6 +93,22 @@ static void m68k_cpu_reset_hold(Object *obj, ResetType type)
         env->fregs[i].d = nan;
         env->fregs[i].d = nan;
     }
     }
     cpu_m68k_set_fpcr(env, 0);
     cpu_m68k_set_fpcr(env, 0);
+    /*
+     * M68000 FAMILY PROGRAMMER'S REFERENCE MANUAL
+     * 3.4 FLOATING-POINT INSTRUCTION DETAILS
+     * If either operand, but not both operands, of an operation is a
+     * nonsignaling NaN, then that NaN is returned as the result. If both
+     * operands are nonsignaling NaNs, then the destination operand
+     * nonsignaling NaN is returned as the result.
+     * If either operand to an operation is a signaling NaN (SNaN), then the
+     * SNaN bit is set in the FPSR EXC byte. If the SNaN exception enable bit
+     * is set in the FPCR ENABLE byte, then the exception is taken and the
+     * destination is not modified. If the SNaN exception enable bit is not
+     * set, setting the SNaN bit in the operand to a one converts the SNaN to
+     * a nonsignaling NaN. The operation then continues as described in the
+     * preceding paragraph for nonsignaling NaNs.
+     */
+    set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status);
     env->fpsr = 0;
     env->fpsr = 0;
 
 
     /* TODO: We should set PC from the interrupt vector.  */
     /* TODO: We should set PC from the interrupt vector.  */

+ 1 - 0
target/m68k/fpu_helper.c

@@ -620,6 +620,7 @@ void HELPER(frem)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1)
         int sign;
         int sign;
 
 
         /* Calculate quotient directly using round to nearest mode */
         /* Calculate quotient directly using round to nearest mode */
+        set_float_2nan_prop_rule(float_2nan_prop_ab, &fp_status);
         set_float_rounding_mode(float_round_nearest_even, &fp_status);
         set_float_rounding_mode(float_round_nearest_even, &fp_status);
         set_floatx80_rounding_precision(
         set_floatx80_rounding_precision(
             get_floatx80_rounding_precision(&env->fp_status), &fp_status);
             get_floatx80_rounding_precision(&env->fp_status), &fp_status);

+ 2 - 2
target/m68k/helper.c

@@ -36,7 +36,7 @@ static int cf_fpu_gdb_get_reg(CPUState *cs, GByteArray *mem_buf, int n)
     CPUM68KState *env = &cpu->env;
     CPUM68KState *env = &cpu->env;
 
 
     if (n < 8) {
     if (n < 8) {
-        float_status s;
+        float_status s = {};
         return gdb_get_reg64(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
         return gdb_get_reg64(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
     }
     }
     switch (n) {
     switch (n) {
@@ -56,7 +56,7 @@ static int cf_fpu_gdb_set_reg(CPUState *cs, uint8_t *mem_buf, int n)
     CPUM68KState *env = &cpu->env;
     CPUM68KState *env = &cpu->env;
 
 
     if (n < 8) {
     if (n < 8) {
-        float_status s;
+        float_status s = {};
         env->fregs[n].d = float64_to_floatx80(ldq_be_p(mem_buf), &s);
         env->fregs[n].d = float64_to_floatx80(ldq_be_p(mem_buf), &s);
         return 8;
         return 8;
     }
     }

+ 7 - 3
target/microblaze/cpu.c

@@ -201,6 +201,13 @@ static void mb_cpu_reset_hold(Object *obj, ResetType type)
 
 
     env->pc = cpu->cfg.base_vectors;
     env->pc = cpu->cfg.base_vectors;
 
 
+    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
+    /*
+     * TODO: this is probably not the correct NaN propagation rule for
+     * this architecture.
+     */
+    set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status);
+
 #if defined(CONFIG_USER_ONLY)
 #if defined(CONFIG_USER_ONLY)
     /* start in user mode with interrupts enabled.  */
     /* start in user mode with interrupts enabled.  */
     mb_cpu_write_msr(env, MSR_EE | MSR_IE | MSR_VM | MSR_UM);
     mb_cpu_write_msr(env, MSR_EE | MSR_IE | MSR_VM | MSR_UM);
@@ -311,15 +318,12 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp)
 static void mb_cpu_initfn(Object *obj)
 static void mb_cpu_initfn(Object *obj)
 {
 {
     MicroBlazeCPU *cpu = MICROBLAZE_CPU(obj);
     MicroBlazeCPU *cpu = MICROBLAZE_CPU(obj);
-    CPUMBState *env = &cpu->env;
 
 
     gdb_register_coprocessor(CPU(cpu), mb_cpu_gdb_read_stack_protect,
     gdb_register_coprocessor(CPU(cpu), mb_cpu_gdb_read_stack_protect,
                              mb_cpu_gdb_write_stack_protect,
                              mb_cpu_gdb_write_stack_protect,
                              gdb_find_static_feature("microblaze-stack-protect.xml"),
                              gdb_find_static_feature("microblaze-stack-protect.xml"),
                              0);
                              0);
 
 
-    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
-
 #ifndef CONFIG_USER_ONLY
 #ifndef CONFIG_USER_ONLY
     /* Inbound IRQ and FIR lines */
     /* Inbound IRQ and FIR lines */
     qdev_init_gpio_in(DEVICE(cpu), microblaze_cpu_set_irq, 2);
     qdev_init_gpio_in(DEVICE(cpu), microblaze_cpu_set_irq, 2);

+ 1 - 1
target/mips/cpu.c

@@ -407,9 +407,9 @@ static void mips_cpu_reset_hold(Object *obj, ResetType type)
     }
     }
 
 
     msa_reset(env);
     msa_reset(env);
+    fp_reset(env);
 
 
     compute_hflags(env);
     compute_hflags(env);
-    restore_fp_status(env);
     restore_pamask(env);
     restore_pamask(env);
     cs->exception_index = EXCP_NONE;
     cs->exception_index = EXCP_NONE;
 
 

+ 22 - 0
target/mips/fpu_helper.h

@@ -44,6 +44,28 @@ static inline void restore_fp_status(CPUMIPSState *env)
     restore_snan_bit_mode(env);
     restore_snan_bit_mode(env);
 }
 }
 
 
+static inline void fp_reset(CPUMIPSState *env)
+{
+    restore_fp_status(env);
+
+    /*
+     * According to MIPS specifications, if one of the two operands is
+     * a sNaN, a new qNaN has to be generated. This is done in
+     * floatXX_silence_nan(). For qNaN inputs the specifications
+     * says: "When possible, this QNaN result is one of the operand QNaN
+     * values." In practice it seems that most implementations choose
+     * the first operand if both operands are qNaN. In short this gives
+     * the following rules:
+     *  1. A if it is signaling
+     *  2. B if it is signaling
+     *  3. A (quiet)
+     *  4. B (quiet)
+     * A signaling NaN is always silenced before returning it.
+     */
+    set_float_2nan_prop_rule(float_2nan_prop_s_ab,
+                             &env->active_fpu.fp_status);
+}
+
 /* MSA */
 /* MSA */
 
 
 enum CPUMIPSMSADataFormat {
 enum CPUMIPSMSADataFormat {

+ 17 - 0
target/mips/msa.c

@@ -49,6 +49,23 @@ void msa_reset(CPUMIPSState *env)
     set_float_detect_tininess(float_tininess_after_rounding,
     set_float_detect_tininess(float_tininess_after_rounding,
                               &env->active_tc.msa_fp_status);
                               &env->active_tc.msa_fp_status);
 
 
+    /*
+     * According to MIPS specifications, if one of the two operands is
+     * a sNaN, a new qNaN has to be generated. This is done in
+     * floatXX_silence_nan(). For qNaN inputs the specifications
+     * says: "When possible, this QNaN result is one of the operand QNaN
+     * values." In practice it seems that most implementations choose
+     * the first operand if both operands are qNaN. In short this gives
+     * the following rules:
+     *  1. A if it is signaling
+     *  2. B if it is signaling
+     *  3. A (quiet)
+     *  4. B (quiet)
+     * A signaling NaN is always silenced before returning it.
+     */
+    set_float_2nan_prop_rule(float_2nan_prop_s_ab,
+                             &env->active_tc.msa_fp_status);
+
     /* clear float_status exception flags */
     /* clear float_status exception flags */
     set_float_exception_flags(0, &env->active_tc.msa_fp_status);
     set_float_exception_flags(0, &env->active_tc.msa_fp_status);
 
 

+ 6 - 0
target/openrisc/cpu.c

@@ -105,6 +105,12 @@ static void openrisc_cpu_reset_hold(Object *obj, ResetType type)
 
 
     set_float_detect_tininess(float_tininess_before_rounding,
     set_float_detect_tininess(float_tininess_before_rounding,
                               &cpu->env.fp_status);
                               &cpu->env.fp_status);
+    /*
+     * TODO: this is probably not the correct NaN propagation rule for
+     * this architecture.
+     */
+    set_float_2nan_prop_rule(float_2nan_prop_x87, &cpu->env.fp_status);
+
 
 
 #ifndef CONFIG_USER_ONLY
 #ifndef CONFIG_USER_ONLY
     cpu->env.picmr = 0x00000000;
     cpu->env.picmr = 0x00000000;

+ 8 - 0
target/ppc/cpu_init.c

@@ -7262,6 +7262,14 @@ static void ppc_cpu_reset_hold(Object *obj, ResetType type)
     /* tininess for underflow is detected before rounding */
     /* tininess for underflow is detected before rounding */
     set_float_detect_tininess(float_tininess_before_rounding,
     set_float_detect_tininess(float_tininess_before_rounding,
                               &env->fp_status);
                               &env->fp_status);
+    /*
+     * PowerPC propagation rules:
+     *  1. A if it sNaN or qNaN
+     *  2. B if it sNaN or qNaN
+     * A signaling NaN is always silenced before returning it.
+     */
+    set_float_2nan_prop_rule(float_2nan_prop_ab, &env->fp_status);
+    set_float_2nan_prop_rule(float_2nan_prop_ab, &env->vec_status);
 
 
     for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) {
     for (i = 0; i < ARRAY_SIZE(env->spr_cb); i++) {
         ppc_spr_t *spr = &env->spr_cb[i];
         ppc_spr_t *spr = &env->spr_cb[i];

+ 7 - 0
target/rx/cpu.c

@@ -93,6 +93,13 @@ static void rx_cpu_reset_hold(Object *obj, ResetType type)
     env->fpsw = 0;
     env->fpsw = 0;
     set_flush_to_zero(1, &env->fp_status);
     set_flush_to_zero(1, &env->fp_status);
     set_flush_inputs_to_zero(1, &env->fp_status);
     set_flush_inputs_to_zero(1, &env->fp_status);
+    /*
+     * TODO: this is not the correct NaN propagation rule for this
+     * architecture. The "RX Family User's Manual: Software" table 1.6
+     * defines the propagation rules as "prefer SNaN over QNaN;
+     * then prefer dest over source", which is float_2nan_prop_s_ab.
+     */
+    set_float_2nan_prop_rule(float_2nan_prop_x87, &env->fp_status);
 }
 }
 
 
 static ObjectClass *rx_cpu_class_by_name(const char *cpu_model)
 static ObjectClass *rx_cpu_class_by_name(const char *cpu_model)

+ 1 - 0
target/s390x/cpu.c

@@ -205,6 +205,7 @@ static void s390_cpu_reset_hold(Object *obj, ResetType type)
         /* tininess for underflow is detected before rounding */
         /* tininess for underflow is detected before rounding */
         set_float_detect_tininess(float_tininess_before_rounding,
         set_float_detect_tininess(float_tininess_before_rounding,
                                   &env->fpu_status);
                                   &env->fpu_status);
+        set_float_2nan_prop_rule(float_2nan_prop_s_ab, &env->fpu_status);
        /* fall through */
        /* fall through */
     case RESET_TYPE_S390_CPU_NORMAL:
     case RESET_TYPE_S390_CPU_NORMAL:
         env->psw.mask &= ~PSW_MASK_RI;
         env->psw.mask &= ~PSW_MASK_RI;

+ 9 - 1
target/sparc/cpu.c

@@ -26,6 +26,7 @@
 #include "hw/qdev-properties.h"
 #include "hw/qdev-properties.h"
 #include "qapi/visitor.h"
 #include "qapi/visitor.h"
 #include "tcg/tcg.h"
 #include "tcg/tcg.h"
+#include "fpu/softfloat.h"
 
 
 //#define DEBUG_FEATURES
 //#define DEBUG_FEATURES
 
 
@@ -76,6 +77,7 @@ static void sparc_cpu_reset_hold(Object *obj, ResetType type)
     env->npc = env->pc + 4;
     env->npc = env->pc + 4;
 #endif
 #endif
     env->cache_control = 0;
     env->cache_control = 0;
+    cpu_put_fsr(env, 0);
 }
 }
 
 
 #ifndef CONFIG_USER_ONLY
 #ifndef CONFIG_USER_ONLY
@@ -805,7 +807,13 @@ static void sparc_cpu_realizefn(DeviceState *dev, Error **errp)
     env->version |= env->def.maxtl << 8;
     env->version |= env->def.maxtl << 8;
     env->version |= env->def.nwindows - 1;
     env->version |= env->def.nwindows - 1;
 #endif
 #endif
-    cpu_put_fsr(env, 0);
+
+    /*
+     * Prefer SNaN over QNaN, order B then A. It's OK to do this in realize
+     * rather than reset, because fp_status is after 'end_reset_fields' in
+     * the CPU state struct so it won't get zeroed on reset.
+     */
+    set_float_2nan_prop_rule(float_2nan_prop_s_ba, &env->fp_status);
 
 
     cpu_exec_realizefn(cs, &local_err);
     cpu_exec_realizefn(cs, &local_err);
     if (local_err != NULL) {
     if (local_err != NULL) {

+ 8 - 2
target/sparc/fop_helper.c

@@ -497,7 +497,10 @@ uint32_t helper_flcmps(float32 src1, float32 src2)
      * Perform the comparison with a dummy fp environment.
      * Perform the comparison with a dummy fp environment.
      */
      */
     float_status discard = { };
     float_status discard = { };
-    FloatRelation r = float32_compare_quiet(src1, src2, &discard);
+    FloatRelation r;
+
+    set_float_2nan_prop_rule(float_2nan_prop_s_ba, &discard);
+    r = float32_compare_quiet(src1, src2, &discard);
 
 
     switch (r) {
     switch (r) {
     case float_relation_equal:
     case float_relation_equal:
@@ -518,7 +521,10 @@ uint32_t helper_flcmps(float32 src1, float32 src2)
 uint32_t helper_flcmpd(float64 src1, float64 src2)
 uint32_t helper_flcmpd(float64 src1, float64 src2)
 {
 {
     float_status discard = { };
     float_status discard = { };
-    FloatRelation r = float64_compare_quiet(src1, src2, &discard);
+    FloatRelation r;
+
+    set_float_2nan_prop_rule(float_2nan_prop_s_ba, &discard);
+    r = float64_compare_quiet(src1, src2, &discard);
 
 
     switch (r) {
     switch (r) {
     case float_relation_equal:
     case float_relation_equal:

+ 1 - 1
target/xtensa/cpu.c

@@ -134,7 +134,7 @@ static void xtensa_cpu_reset_hold(Object *obj, ResetType type)
     cs->halted = env->runstall;
     cs->halted = env->runstall;
 #endif
 #endif
     set_no_signaling_nans(!dfpu, &env->fp_status);
     set_no_signaling_nans(!dfpu, &env->fp_status);
-    set_use_first_nan(!dfpu, &env->fp_status);
+    xtensa_use_first_nan(env, !dfpu);
 }
 }
 
 
 static ObjectClass *xtensa_cpu_class_by_name(const char *cpu_model)
 static ObjectClass *xtensa_cpu_class_by_name(const char *cpu_model)

+ 6 - 0
target/xtensa/cpu.h

@@ -802,4 +802,10 @@ static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, vaddr *pc,
 XtensaCPU *xtensa_cpu_create_with_clock(const char *cpu_type,
 XtensaCPU *xtensa_cpu_create_with_clock(const char *cpu_type,
                                         Clock *cpu_refclk);
                                         Clock *cpu_refclk);
 
 
+/*
+ * Set the NaN propagation rule for future FPU operations:
+ * use_first is true to pick the first NaN as the result if both
+ * inputs are NaNs, false to pick the second.
+ */
+void xtensa_use_first_nan(CPUXtensaState *env, bool use_first);
 #endif
 #endif

+ 21 - 14
target/xtensa/fpu_helper.c

@@ -57,6 +57,13 @@ static const struct {
     { XTENSA_FP_V, float_flag_invalid, },
     { XTENSA_FP_V, float_flag_invalid, },
 };
 };
 
 
+void xtensa_use_first_nan(CPUXtensaState *env, bool use_first)
+{
+    set_use_first_nan(use_first, &env->fp_status);
+    set_float_2nan_prop_rule(use_first ? float_2nan_prop_ab : float_2nan_prop_ba,
+                             &env->fp_status);
+}
+
 void HELPER(wur_fpu2k_fcr)(CPUXtensaState *env, uint32_t v)
 void HELPER(wur_fpu2k_fcr)(CPUXtensaState *env, uint32_t v)
 {
 {
     static const int rounding_mode[] = {
     static const int rounding_mode[] = {
@@ -171,87 +178,87 @@ float32 HELPER(fpu2k_msub_s)(CPUXtensaState *env,
 
 
 float64 HELPER(add_d)(CPUXtensaState *env, float64 a, float64 b)
 float64 HELPER(add_d)(CPUXtensaState *env, float64 a, float64 b)
 {
 {
-    set_use_first_nan(true, &env->fp_status);
+    xtensa_use_first_nan(env, true);
     return float64_add(a, b, &env->fp_status);
     return float64_add(a, b, &env->fp_status);
 }
 }
 
 
 float32 HELPER(add_s)(CPUXtensaState *env, float32 a, float32 b)
 float32 HELPER(add_s)(CPUXtensaState *env, float32 a, float32 b)
 {
 {
-    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
+    xtensa_use_first_nan(env, env->config->use_first_nan);
     return float32_add(a, b, &env->fp_status);
     return float32_add(a, b, &env->fp_status);
 }
 }
 
 
 float64 HELPER(sub_d)(CPUXtensaState *env, float64 a, float64 b)
 float64 HELPER(sub_d)(CPUXtensaState *env, float64 a, float64 b)
 {
 {
-    set_use_first_nan(true, &env->fp_status);
+    xtensa_use_first_nan(env, true);
     return float64_sub(a, b, &env->fp_status);
     return float64_sub(a, b, &env->fp_status);
 }
 }
 
 
 float32 HELPER(sub_s)(CPUXtensaState *env, float32 a, float32 b)
 float32 HELPER(sub_s)(CPUXtensaState *env, float32 a, float32 b)
 {
 {
-    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
+    xtensa_use_first_nan(env, env->config->use_first_nan);
     return float32_sub(a, b, &env->fp_status);
     return float32_sub(a, b, &env->fp_status);
 }
 }
 
 
 float64 HELPER(mul_d)(CPUXtensaState *env, float64 a, float64 b)
 float64 HELPER(mul_d)(CPUXtensaState *env, float64 a, float64 b)
 {
 {
-    set_use_first_nan(true, &env->fp_status);
+    xtensa_use_first_nan(env, true);
     return float64_mul(a, b, &env->fp_status);
     return float64_mul(a, b, &env->fp_status);
 }
 }
 
 
 float32 HELPER(mul_s)(CPUXtensaState *env, float32 a, float32 b)
 float32 HELPER(mul_s)(CPUXtensaState *env, float32 a, float32 b)
 {
 {
-    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
+    xtensa_use_first_nan(env, env->config->use_first_nan);
     return float32_mul(a, b, &env->fp_status);
     return float32_mul(a, b, &env->fp_status);
 }
 }
 
 
 float64 HELPER(madd_d)(CPUXtensaState *env, float64 a, float64 b, float64 c)
 float64 HELPER(madd_d)(CPUXtensaState *env, float64 a, float64 b, float64 c)
 {
 {
-    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
+    xtensa_use_first_nan(env, env->config->use_first_nan);
     return float64_muladd(b, c, a, 0, &env->fp_status);
     return float64_muladd(b, c, a, 0, &env->fp_status);
 }
 }
 
 
 float32 HELPER(madd_s)(CPUXtensaState *env, float32 a, float32 b, float32 c)
 float32 HELPER(madd_s)(CPUXtensaState *env, float32 a, float32 b, float32 c)
 {
 {
-    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
+    xtensa_use_first_nan(env, env->config->use_first_nan);
     return float32_muladd(b, c, a, 0, &env->fp_status);
     return float32_muladd(b, c, a, 0, &env->fp_status);
 }
 }
 
 
 float64 HELPER(msub_d)(CPUXtensaState *env, float64 a, float64 b, float64 c)
 float64 HELPER(msub_d)(CPUXtensaState *env, float64 a, float64 b, float64 c)
 {
 {
-    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
+    xtensa_use_first_nan(env, env->config->use_first_nan);
     return float64_muladd(b, c, a, float_muladd_negate_product,
     return float64_muladd(b, c, a, float_muladd_negate_product,
                           &env->fp_status);
                           &env->fp_status);
 }
 }
 
 
 float32 HELPER(msub_s)(CPUXtensaState *env, float32 a, float32 b, float32 c)
 float32 HELPER(msub_s)(CPUXtensaState *env, float32 a, float32 b, float32 c)
 {
 {
-    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
+    xtensa_use_first_nan(env, env->config->use_first_nan);
     return float32_muladd(b, c, a, float_muladd_negate_product,
     return float32_muladd(b, c, a, float_muladd_negate_product,
                           &env->fp_status);
                           &env->fp_status);
 }
 }
 
 
 float64 HELPER(mkdadj_d)(CPUXtensaState *env, float64 a, float64 b)
 float64 HELPER(mkdadj_d)(CPUXtensaState *env, float64 a, float64 b)
 {
 {
-    set_use_first_nan(true, &env->fp_status);
+    xtensa_use_first_nan(env, true);
     return float64_div(b, a, &env->fp_status);
     return float64_div(b, a, &env->fp_status);
 }
 }
 
 
 float32 HELPER(mkdadj_s)(CPUXtensaState *env, float32 a, float32 b)
 float32 HELPER(mkdadj_s)(CPUXtensaState *env, float32 a, float32 b)
 {
 {
-    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
+    xtensa_use_first_nan(env, env->config->use_first_nan);
     return float32_div(b, a, &env->fp_status);
     return float32_div(b, a, &env->fp_status);
 }
 }
 
 
 float64 HELPER(mksadj_d)(CPUXtensaState *env, float64 v)
 float64 HELPER(mksadj_d)(CPUXtensaState *env, float64 v)
 {
 {
-    set_use_first_nan(true, &env->fp_status);
+    xtensa_use_first_nan(env, true);
     return float64_sqrt(v, &env->fp_status);
     return float64_sqrt(v, &env->fp_status);
 }
 }
 
 
 float32 HELPER(mksadj_s)(CPUXtensaState *env, float32 v)
 float32 HELPER(mksadj_s)(CPUXtensaState *env, float32 v)
 {
 {
-    set_use_first_nan(env->config->use_first_nan, &env->fp_status);
+    xtensa_use_first_nan(env, env->config->use_first_nan);
     return float32_sqrt(v, &env->fp_status);
     return float32_sqrt(v, &env->fp_status);
 }
 }
 
 

+ 2 - 0
tests/fp/fp-bench.c

@@ -488,6 +488,8 @@ static void run_bench(void)
 {
 {
     bench_func_t f;
     bench_func_t f;
 
 
+    set_float_2nan_prop_rule(float_2nan_prop_s_ab, &soft_status);
+
     f = bench_funcs[operation][precision];
     f = bench_funcs[operation][precision];
     g_assert(f);
     g_assert(f);
     f();
     f();

+ 1 - 0
tests/fp/fp-test-log2.c

@@ -70,6 +70,7 @@ int main(int ac, char **av)
     float_status qsf = {0};
     float_status qsf = {0};
     int i;
     int i;
 
 
+    set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf);
     set_float_rounding_mode(float_round_nearest_even, &qsf);
     set_float_rounding_mode(float_round_nearest_even, &qsf);
 
 
     test.d = 0.0;
     test.d = 0.0;

+ 2 - 0
tests/fp/fp-test.c

@@ -935,6 +935,8 @@ void run_test(void)
 {
 {
     unsigned int i;
     unsigned int i;
 
 
+    set_float_2nan_prop_rule(float_2nan_prop_s_ab, &qsf);
+
     genCases_setLevel(test_level);
     genCases_setLevel(test_level);
     verCases_maxErrorCount = n_max_errors;
     verCases_maxErrorCount = n_max_errors;