__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


Reply via email to