aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2018-03-31 09:42:33 +0100
committerPeter Maydell <peter.maydell@linaro.org>2018-03-31 09:42:33 +0100
commitf184de7553272223d6af731d7d623a7cebf710b5 (patch)
treef35234259272e7006085cd5160cfd0518e7e56b8
parentb60d667d3d0a9733a42552345b8c37587354f3cd (diff)
parentb02403363f1056421d120c8e974fdf9c76a84f95 (diff)
downloadqemu-f184de7553272223d6af731d7d623a7cebf710b5.zip
qemu-f184de7553272223d6af731d7d623a7cebf710b5.tar.gz
qemu-f184de7553272223d6af731d7d623a7cebf710b5.tar.bz2
Merge remote-tracking branch 'remotes/riscv/tags/riscv-qemu-2.12-critical-fixes' into staging
RISC-V: Critical fixes for QEMU 2.12 This series includes changes that are considered release critical, such as floating point register file corruption under SMP Linux due to incorrect handling of mstatus.FS. This workaround will be replaced with a more comprehensive fix for mstatus.FS handling in QEMU 2.13. # gpg: Signature made Thu 29 Mar 2018 18:22:42 BST # gpg: using DSA key 6BF1D7B357EF3E4F # gpg: Good signature from "Michael Clark <michaeljclark@mac.com>" # gpg: aka "Michael Clark <mjc@sifive.com>" # gpg: aka "Michael Clark <michael@metaparadigm.com>" # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 7C99 930E B17C D8BA 073D 5EFA 6BF1 D7B3 57EF 3E4F * remotes/riscv/tags/riscv-qemu-2.12-critical-fixes: RISC-V: Workaround for critical mstatus.FS bug Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--target/riscv/op_helper.c17
1 files changed, 15 insertions, 2 deletions
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index e34715d..7c6068b 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -144,8 +144,21 @@ void csr_write_helper(CPURISCVState *env, target_ulong val_to_write,
}
mstatus = (mstatus & ~mask) | (val_to_write & mask);
- int dirty = (mstatus & MSTATUS_FS) == MSTATUS_FS;
- dirty |= (mstatus & MSTATUS_XS) == MSTATUS_XS;
+
+ /* Note: this is a workaround for an issue where mstatus.FS
+ does not report dirty after floating point operations
+ that modify floating point state. This workaround is
+ technically compliant with the RISC-V Privileged
+ specification as it is legal to return only off, or dirty.
+ at the expense of extra floating point save/restore. */
+
+ /* FP is always dirty or off */
+ if (mstatus & MSTATUS_FS) {
+ mstatus |= MSTATUS_FS;
+ }
+
+ int dirty = ((mstatus & MSTATUS_FS) == MSTATUS_FS) |
+ ((mstatus & MSTATUS_XS) == MSTATUS_XS);
mstatus = set_field(mstatus, MSTATUS_SD, dirty);
env->mstatus = mstatus;
break;