__do_essa() treated any negative return from dat_perform_essa() as the
normal "no CBRL entry appended" case and returned 0, so a page-table
walk failure silently dropped the addressing exception.
DAT_WALK_ANY is required in the dat_entry_walk() call so that a GFN
backed by a large page (segment or region entry) does not return an
error: the walk stops early but succeeds, leaving ptep as NULL, which is
already handled by the existing "set exception state, return -1" path.
Without DAT_WALK_ANY such addresses would fall through to the new error
path and incorrectly inject PGM_ADDRESSING.
Return -PGM_ADDRESSING on a walk failure and inject the program
interrupt in __do_essa() for the -PGM_ADDRESSING return value.
Fixes: e38c884df921 ("KVM: s390: Switch to new gmap")
Reported-by: Christian Borntraeger <[email protected]>
Suggested-by: Claudio Imbrenda <[email protected]>
Signed-off-by: Gautam Gala <[email protected]>
Acked-by: Christian Borntraeger <[email protected]>
---
arch/s390/kvm/gmap/dat.c | 5 ++++-
arch/s390/kvm/s390/priv.c | 4 +++-
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/arch/s390/kvm/gmap/dat.c b/arch/s390/kvm/gmap/dat.c
index ff80d02c9f56..1bc6d2ec5b08 100644
--- a/arch/s390/kvm/gmap/dat.c
+++ b/arch/s390/kvm/gmap/dat.c
@@ -1084,6 +1084,7 @@ int dat_set_prefix_notif_bit(union asce asce, gfn_t gfn)
* * %1 if the page state has been altered and the page is to be added to the
CBRL
* * %0 if the page state has been altered, but the page is not to be added to
the CBRL
* * %-1 if the page state has not been altered and the page is not to be
added to the CBRL
+ * * %-PGM_ADDRESSING if the guest page-table walk failed
*/
int dat_perform_essa(union asce asce, gfn_t gfn, int orc, union essa_state
*state, bool *dirty)
{
@@ -1092,7 +1093,9 @@ int dat_perform_essa(union asce asce, gfn_t gfn, int orc,
union essa_state *stat
union pte *ptep;
int res = 0;
- if (dat_entry_walk(NULL, gfn, asce, 0, TABLE_TYPE_PAGE_TABLE, &crstep,
&ptep)) {
+ if (dat_entry_walk(NULL, gfn, asce, DAT_WALK_ANY,
TABLE_TYPE_PAGE_TABLE, &crstep, &ptep))
+ return -PGM_ADDRESSING;
+ if (!ptep) {
*state = (union essa_state) { .exception = 1 };
return -1;
}
diff --git a/arch/s390/kvm/s390/priv.c b/arch/s390/kvm/s390/priv.c
index b3cb2c2c3aa7..2abd1bdfdf32 100644
--- a/arch/s390/kvm/s390/priv.c
+++ b/arch/s390/kvm/s390/priv.c
@@ -1168,8 +1168,10 @@ static inline int __do_essa(struct kvm_vcpu *vcpu, const
int orc)
entries = (vcpu->arch.sie_block->cbrlo & ~PAGE_MASK) >> 3;
nappended = dat_perform_essa(vcpu->arch.gmap->asce, gfn, orc, &state,
&dirtied);
+ if (nappended == -PGM_ADDRESSING)
+ return kvm_s390_inject_program_int(vcpu, -PGM_ADDRESSING);
vcpu->run->s.regs.gprs[r1] = state.val;
- if (nappended < 0)
+ if (nappended == -1)
return 0;
/*
* It is possible that all the normal 511 slots were full, in which case
--
2.55.0