diff options
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 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); |