diff options
author | David Hildenbrand <david@redhat.com> | 2019-08-16 10:47:07 +0200 |
---|---|---|
committer | Cornelia Huck <cohuck@redhat.com> | 2019-08-22 14:53:49 +0200 |
commit | 2d3bb388ad93dce9a9454af67f43d3aaaa5b9b1a (patch) | |
tree | 4dc87b5b9421d1791614fb755045197e46b4798f /target/s390x/mmu_helper.c | |
parent | 5b773a1107e7ca6f51e3447cc066f255a7fd8cca (diff) | |
download | qemu-2d3bb388ad93dce9a9454af67f43d3aaaa5b9b1a.zip qemu-2d3bb388ad93dce9a9454af67f43d3aaaa5b9b1a.tar.gz qemu-2d3bb388ad93dce9a9454af67f43d3aaaa5b9b1a.tar.bz2 |
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.c | 24 |
1 files changed, 19 insertions, 5 deletions
diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c index 40b6c1f..61654e0 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); |