summaryrefslogtreecommitdiffstats
path: root/target/s390x/mmu_helper.c
diff options
context:
space:
mode:
authorDavid Hildenbrand2019-08-16 10:47:07 +0200
committerCornelia Huck2019-08-22 14:53:49 +0200
commit2d3bb388ad93dce9a9454af67f43d3aaaa5b9b1a (patch)
tree4dc87b5b9421d1791614fb755045197e46b4798f /target/s390x/mmu_helper.c
parents390x/tcg: Flush the TLB of all CPUs on SSKE and RRBE (diff)
downloadqemu-2d3bb388ad93dce9a9454af67f43d3aaaa5b9b1a.tar.gz
qemu-2d3bb388ad93dce9a9454af67f43d3aaaa5b9b1a.tar.xz
qemu-2d3bb388ad93dce9a9454af67f43d3aaaa5b9b1a.zip
s390x/mmu: Better storage key reference and change bit handling
Any access sets the reference bit. In case we have a read-fault, we should not allow writes to the TLB entry if the change bit was not already set. This is a preparation for proper storage-key reference/change bit handling in TCG and a fix for KVM whereby read accesses would set the change bit (old KVM versions without the ioctl to carry out the translation). Reviewed-by: Cornelia Huck <cohuck@redhat.com> Signed-off-by: David Hildenbrand <david@redhat.com> Message-Id: <20190816084708.602-6-david@redhat.com> Signed-off-by: Cornelia Huck <cohuck@redhat.com>
Diffstat (limited to 'target/s390x/mmu_helper.c')
-rw-r--r--target/s390x/mmu_helper.c24
1 files changed, 19 insertions, 5 deletions
diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c
index 40b6c1fc36..61654e07de 100644
--- a/target/s390x/mmu_helper.c
+++ b/target/s390x/mmu_helper.c
@@ -421,14 +421,28 @@ nodat:
return 0;
}
- if (*flags & PAGE_READ) {
- key |= SK_R;
- }
-
- if (*flags & PAGE_WRITE) {
+ switch (rw) {
+ case MMU_DATA_LOAD:
+ case MMU_INST_FETCH:
+ /*
+ * The TLB entry has to remain write-protected on read-faults if
+ * the storage key does not indicate a change already. Otherwise
+ * we might miss setting the change bit on write accesses.
+ */
+ if (!(key & SK_C)) {
+ *flags &= ~PAGE_WRITE;
+ }
+ break;
+ case MMU_DATA_STORE:
key |= SK_C;
+ break;
+ default:
+ g_assert_not_reached();
}
+ /* Any store/fetch sets the reference bit */
+ key |= SK_R;
+
r = skeyclass->set_skeys(ss, *raddr / TARGET_PAGE_SIZE, 1, &key);
if (r) {
trace_set_skeys_nonzero(r);