xref: /linux/arch/s390/kvm/gaccess.c (revision b24413180f5600bcb3bb70fbed5cf186b60864bd)
1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
222938978SHeiko Carstens /*
322938978SHeiko Carstens  * guest access functions
422938978SHeiko Carstens  *
522938978SHeiko Carstens  * Copyright IBM Corp. 2014
622938978SHeiko Carstens  *
722938978SHeiko Carstens  */
822938978SHeiko Carstens 
922938978SHeiko Carstens #include <linux/vmalloc.h>
10589ee628SIngo Molnar #include <linux/mm_types.h>
1122938978SHeiko Carstens #include <linux/err.h>
12589ee628SIngo Molnar 
1322938978SHeiko Carstens #include <asm/pgtable.h>
14aa17aa57SMartin Schwidefsky #include <asm/gmap.h>
1522938978SHeiko Carstens #include "kvm-s390.h"
1622938978SHeiko Carstens #include "gaccess.h"
17664b4973SAlexander Yarygin #include <asm/switch_to.h>
1822938978SHeiko Carstens 
1922938978SHeiko Carstens union asce {
2022938978SHeiko Carstens 	unsigned long val;
2122938978SHeiko Carstens 	struct {
2222938978SHeiko Carstens 		unsigned long origin : 52; /* Region- or Segment-Table Origin */
2322938978SHeiko Carstens 		unsigned long	 : 2;
2422938978SHeiko Carstens 		unsigned long g  : 1; /* Subspace Group Control */
2522938978SHeiko Carstens 		unsigned long p  : 1; /* Private Space Control */
2622938978SHeiko Carstens 		unsigned long s  : 1; /* Storage-Alteration-Event Control */
2722938978SHeiko Carstens 		unsigned long x  : 1; /* Space-Switch-Event Control */
2822938978SHeiko Carstens 		unsigned long r  : 1; /* Real-Space Control */
2922938978SHeiko Carstens 		unsigned long	 : 1;
3022938978SHeiko Carstens 		unsigned long dt : 2; /* Designation-Type Control */
3122938978SHeiko Carstens 		unsigned long tl : 2; /* Region- or Segment-Table Length */
3222938978SHeiko Carstens 	};
3322938978SHeiko Carstens };
3422938978SHeiko Carstens 
3522938978SHeiko Carstens enum {
3622938978SHeiko Carstens 	ASCE_TYPE_SEGMENT = 0,
3722938978SHeiko Carstens 	ASCE_TYPE_REGION3 = 1,
3822938978SHeiko Carstens 	ASCE_TYPE_REGION2 = 2,
3922938978SHeiko Carstens 	ASCE_TYPE_REGION1 = 3
4022938978SHeiko Carstens };
4122938978SHeiko Carstens 
4222938978SHeiko Carstens union region1_table_entry {
4322938978SHeiko Carstens 	unsigned long val;
4422938978SHeiko Carstens 	struct {
4522938978SHeiko Carstens 		unsigned long rto: 52;/* Region-Table Origin */
4622938978SHeiko Carstens 		unsigned long	 : 2;
4722938978SHeiko Carstens 		unsigned long p  : 1; /* DAT-Protection Bit */
4822938978SHeiko Carstens 		unsigned long	 : 1;
4922938978SHeiko Carstens 		unsigned long tf : 2; /* Region-Second-Table Offset */
5022938978SHeiko Carstens 		unsigned long i  : 1; /* Region-Invalid Bit */
5122938978SHeiko Carstens 		unsigned long	 : 1;
5222938978SHeiko Carstens 		unsigned long tt : 2; /* Table-Type Bits */
5322938978SHeiko Carstens 		unsigned long tl : 2; /* Region-Second-Table Length */
5422938978SHeiko Carstens 	};
5522938978SHeiko Carstens };
5622938978SHeiko Carstens 
5722938978SHeiko Carstens union region2_table_entry {
5822938978SHeiko Carstens 	unsigned long val;
5922938978SHeiko Carstens 	struct {
6022938978SHeiko Carstens 		unsigned long rto: 52;/* Region-Table Origin */
6122938978SHeiko Carstens 		unsigned long	 : 2;
6222938978SHeiko Carstens 		unsigned long p  : 1; /* DAT-Protection Bit */
6322938978SHeiko Carstens 		unsigned long	 : 1;
6422938978SHeiko Carstens 		unsigned long tf : 2; /* Region-Third-Table Offset */
6522938978SHeiko Carstens 		unsigned long i  : 1; /* Region-Invalid Bit */
6622938978SHeiko Carstens 		unsigned long	 : 1;
6722938978SHeiko Carstens 		unsigned long tt : 2; /* Table-Type Bits */
6822938978SHeiko Carstens 		unsigned long tl : 2; /* Region-Third-Table Length */
6922938978SHeiko Carstens 	};
7022938978SHeiko Carstens };
7122938978SHeiko Carstens 
7222938978SHeiko Carstens struct region3_table_entry_fc0 {
7322938978SHeiko Carstens 	unsigned long sto: 52;/* Segment-Table Origin */
7422938978SHeiko Carstens 	unsigned long	 : 1;
7522938978SHeiko Carstens 	unsigned long fc : 1; /* Format-Control */
7622938978SHeiko Carstens 	unsigned long p  : 1; /* DAT-Protection Bit */
7722938978SHeiko Carstens 	unsigned long	 : 1;
7822938978SHeiko Carstens 	unsigned long tf : 2; /* Segment-Table Offset */
7922938978SHeiko Carstens 	unsigned long i  : 1; /* Region-Invalid Bit */
8022938978SHeiko Carstens 	unsigned long cr : 1; /* Common-Region Bit */
8122938978SHeiko Carstens 	unsigned long tt : 2; /* Table-Type Bits */
8222938978SHeiko Carstens 	unsigned long tl : 2; /* Segment-Table Length */
8322938978SHeiko Carstens };
8422938978SHeiko Carstens 
8522938978SHeiko Carstens struct region3_table_entry_fc1 {
8622938978SHeiko Carstens 	unsigned long rfaa : 33; /* Region-Frame Absolute Address */
8722938978SHeiko Carstens 	unsigned long	 : 14;
8822938978SHeiko Carstens 	unsigned long av : 1; /* ACCF-Validity Control */
8922938978SHeiko Carstens 	unsigned long acc: 4; /* Access-Control Bits */
9022938978SHeiko Carstens 	unsigned long f  : 1; /* Fetch-Protection Bit */
9122938978SHeiko Carstens 	unsigned long fc : 1; /* Format-Control */
9222938978SHeiko Carstens 	unsigned long p  : 1; /* DAT-Protection Bit */
936ae1574cSChristian Borntraeger 	unsigned long iep: 1; /* Instruction-Execution-Protection */
9422938978SHeiko Carstens 	unsigned long	 : 2;
9522938978SHeiko Carstens 	unsigned long i  : 1; /* Region-Invalid Bit */
9622938978SHeiko Carstens 	unsigned long cr : 1; /* Common-Region Bit */
9722938978SHeiko Carstens 	unsigned long tt : 2; /* Table-Type Bits */
9822938978SHeiko Carstens 	unsigned long	 : 2;
9922938978SHeiko Carstens };
10022938978SHeiko Carstens 
10122938978SHeiko Carstens union region3_table_entry {
10222938978SHeiko Carstens 	unsigned long val;
10322938978SHeiko Carstens 	struct region3_table_entry_fc0 fc0;
10422938978SHeiko Carstens 	struct region3_table_entry_fc1 fc1;
10522938978SHeiko Carstens 	struct {
10622938978SHeiko Carstens 		unsigned long	 : 53;
10722938978SHeiko Carstens 		unsigned long fc : 1; /* Format-Control */
10822938978SHeiko Carstens 		unsigned long	 : 4;
10922938978SHeiko Carstens 		unsigned long i  : 1; /* Region-Invalid Bit */
11022938978SHeiko Carstens 		unsigned long cr : 1; /* Common-Region Bit */
11122938978SHeiko Carstens 		unsigned long tt : 2; /* Table-Type Bits */
11222938978SHeiko Carstens 		unsigned long	 : 2;
11322938978SHeiko Carstens 	};
11422938978SHeiko Carstens };
11522938978SHeiko Carstens 
11622938978SHeiko Carstens struct segment_entry_fc0 {
11722938978SHeiko Carstens 	unsigned long pto: 53;/* Page-Table Origin */
11822938978SHeiko Carstens 	unsigned long fc : 1; /* Format-Control */
11922938978SHeiko Carstens 	unsigned long p  : 1; /* DAT-Protection Bit */
12022938978SHeiko Carstens 	unsigned long	 : 3;
12122938978SHeiko Carstens 	unsigned long i  : 1; /* Segment-Invalid Bit */
12222938978SHeiko Carstens 	unsigned long cs : 1; /* Common-Segment Bit */
12322938978SHeiko Carstens 	unsigned long tt : 2; /* Table-Type Bits */
12422938978SHeiko Carstens 	unsigned long	 : 2;
12522938978SHeiko Carstens };
12622938978SHeiko Carstens 
12722938978SHeiko Carstens struct segment_entry_fc1 {
12822938978SHeiko Carstens 	unsigned long sfaa : 44; /* Segment-Frame Absolute Address */
12922938978SHeiko Carstens 	unsigned long	 : 3;
13022938978SHeiko Carstens 	unsigned long av : 1; /* ACCF-Validity Control */
13122938978SHeiko Carstens 	unsigned long acc: 4; /* Access-Control Bits */
13222938978SHeiko Carstens 	unsigned long f  : 1; /* Fetch-Protection Bit */
13322938978SHeiko Carstens 	unsigned long fc : 1; /* Format-Control */
13422938978SHeiko Carstens 	unsigned long p  : 1; /* DAT-Protection Bit */
1356ae1574cSChristian Borntraeger 	unsigned long iep: 1; /* Instruction-Execution-Protection */
13622938978SHeiko Carstens 	unsigned long	 : 2;
13722938978SHeiko Carstens 	unsigned long i  : 1; /* Segment-Invalid Bit */
13822938978SHeiko Carstens 	unsigned long cs : 1; /* Common-Segment Bit */
13922938978SHeiko Carstens 	unsigned long tt : 2; /* Table-Type Bits */
14022938978SHeiko Carstens 	unsigned long	 : 2;
14122938978SHeiko Carstens };
14222938978SHeiko Carstens 
14322938978SHeiko Carstens union segment_table_entry {
14422938978SHeiko Carstens 	unsigned long val;
14522938978SHeiko Carstens 	struct segment_entry_fc0 fc0;
14622938978SHeiko Carstens 	struct segment_entry_fc1 fc1;
14722938978SHeiko Carstens 	struct {
14822938978SHeiko Carstens 		unsigned long	 : 53;
14922938978SHeiko Carstens 		unsigned long fc : 1; /* Format-Control */
15022938978SHeiko Carstens 		unsigned long	 : 4;
15122938978SHeiko Carstens 		unsigned long i  : 1; /* Segment-Invalid Bit */
15222938978SHeiko Carstens 		unsigned long cs : 1; /* Common-Segment Bit */
15322938978SHeiko Carstens 		unsigned long tt : 2; /* Table-Type Bits */
15422938978SHeiko Carstens 		unsigned long	 : 2;
15522938978SHeiko Carstens 	};
15622938978SHeiko Carstens };
15722938978SHeiko Carstens 
15822938978SHeiko Carstens enum {
15922938978SHeiko Carstens 	TABLE_TYPE_SEGMENT = 0,
16022938978SHeiko Carstens 	TABLE_TYPE_REGION3 = 1,
16122938978SHeiko Carstens 	TABLE_TYPE_REGION2 = 2,
16222938978SHeiko Carstens 	TABLE_TYPE_REGION1 = 3
16322938978SHeiko Carstens };
16422938978SHeiko Carstens 
16522938978SHeiko Carstens union page_table_entry {
16622938978SHeiko Carstens 	unsigned long val;
16722938978SHeiko Carstens 	struct {
16822938978SHeiko Carstens 		unsigned long pfra : 52; /* Page-Frame Real Address */
16922938978SHeiko Carstens 		unsigned long z  : 1; /* Zero Bit */
17022938978SHeiko Carstens 		unsigned long i  : 1; /* Page-Invalid Bit */
17122938978SHeiko Carstens 		unsigned long p  : 1; /* DAT-Protection Bit */
1726ae1574cSChristian Borntraeger 		unsigned long iep: 1; /* Instruction-Execution-Protection */
1736ae1574cSChristian Borntraeger 		unsigned long	 : 8;
17422938978SHeiko Carstens 	};
17522938978SHeiko Carstens };
17622938978SHeiko Carstens 
17722938978SHeiko Carstens /*
17822938978SHeiko Carstens  * vaddress union in order to easily decode a virtual address into its
17922938978SHeiko Carstens  * region first index, region second index etc. parts.
18022938978SHeiko Carstens  */
18122938978SHeiko Carstens union vaddress {
18222938978SHeiko Carstens 	unsigned long addr;
18322938978SHeiko Carstens 	struct {
18422938978SHeiko Carstens 		unsigned long rfx : 11;
18522938978SHeiko Carstens 		unsigned long rsx : 11;
18622938978SHeiko Carstens 		unsigned long rtx : 11;
18722938978SHeiko Carstens 		unsigned long sx  : 11;
18822938978SHeiko Carstens 		unsigned long px  : 8;
18922938978SHeiko Carstens 		unsigned long bx  : 12;
19022938978SHeiko Carstens 	};
19122938978SHeiko Carstens 	struct {
19222938978SHeiko Carstens 		unsigned long rfx01 : 2;
19322938978SHeiko Carstens 		unsigned long	    : 9;
19422938978SHeiko Carstens 		unsigned long rsx01 : 2;
19522938978SHeiko Carstens 		unsigned long	    : 9;
19622938978SHeiko Carstens 		unsigned long rtx01 : 2;
19722938978SHeiko Carstens 		unsigned long	    : 9;
19822938978SHeiko Carstens 		unsigned long sx01  : 2;
19922938978SHeiko Carstens 		unsigned long	    : 29;
20022938978SHeiko Carstens 	};
20122938978SHeiko Carstens };
20222938978SHeiko Carstens 
20322938978SHeiko Carstens /*
20422938978SHeiko Carstens  * raddress union which will contain the result (real or absolute address)
20522938978SHeiko Carstens  * after a page table walk. The rfaa, sfaa and pfra members are used to
20622938978SHeiko Carstens  * simply assign them the value of a region, segment or page table entry.
20722938978SHeiko Carstens  */
20822938978SHeiko Carstens union raddress {
20922938978SHeiko Carstens 	unsigned long addr;
21022938978SHeiko Carstens 	unsigned long rfaa : 33; /* Region-Frame Absolute Address */
21122938978SHeiko Carstens 	unsigned long sfaa : 44; /* Segment-Frame Absolute Address */
21222938978SHeiko Carstens 	unsigned long pfra : 52; /* Page-Frame Real Address */
21322938978SHeiko Carstens };
21422938978SHeiko Carstens 
215664b4973SAlexander Yarygin union alet {
216664b4973SAlexander Yarygin 	u32 val;
217664b4973SAlexander Yarygin 	struct {
218664b4973SAlexander Yarygin 		u32 reserved : 7;
219664b4973SAlexander Yarygin 		u32 p        : 1;
220664b4973SAlexander Yarygin 		u32 alesn    : 8;
221664b4973SAlexander Yarygin 		u32 alen     : 16;
222664b4973SAlexander Yarygin 	};
223664b4973SAlexander Yarygin };
224664b4973SAlexander Yarygin 
225664b4973SAlexander Yarygin union ald {
226664b4973SAlexander Yarygin 	u32 val;
227664b4973SAlexander Yarygin 	struct {
228664b4973SAlexander Yarygin 		u32     : 1;
229664b4973SAlexander Yarygin 		u32 alo : 24;
230664b4973SAlexander Yarygin 		u32 all : 7;
231664b4973SAlexander Yarygin 	};
232664b4973SAlexander Yarygin };
233664b4973SAlexander Yarygin 
234664b4973SAlexander Yarygin struct ale {
235664b4973SAlexander Yarygin 	unsigned long i      : 1; /* ALEN-Invalid Bit */
236664b4973SAlexander Yarygin 	unsigned long        : 5;
237664b4973SAlexander Yarygin 	unsigned long fo     : 1; /* Fetch-Only Bit */
238664b4973SAlexander Yarygin 	unsigned long p      : 1; /* Private Bit */
239664b4973SAlexander Yarygin 	unsigned long alesn  : 8; /* Access-List-Entry Sequence Number */
240664b4973SAlexander Yarygin 	unsigned long aleax  : 16; /* Access-List-Entry Authorization Index */
241664b4973SAlexander Yarygin 	unsigned long        : 32;
242664b4973SAlexander Yarygin 	unsigned long        : 1;
243664b4973SAlexander Yarygin 	unsigned long asteo  : 25; /* ASN-Second-Table-Entry Origin */
244664b4973SAlexander Yarygin 	unsigned long        : 6;
245664b4973SAlexander Yarygin 	unsigned long astesn : 32; /* ASTE Sequence Number */
2461cae0255SMartin Schwidefsky };
247664b4973SAlexander Yarygin 
248664b4973SAlexander Yarygin struct aste {
249664b4973SAlexander Yarygin 	unsigned long i      : 1; /* ASX-Invalid Bit */
250664b4973SAlexander Yarygin 	unsigned long ato    : 29; /* Authority-Table Origin */
251664b4973SAlexander Yarygin 	unsigned long        : 1;
252664b4973SAlexander Yarygin 	unsigned long b      : 1; /* Base-Space Bit */
253664b4973SAlexander Yarygin 	unsigned long ax     : 16; /* Authorization Index */
254664b4973SAlexander Yarygin 	unsigned long atl    : 12; /* Authority-Table Length */
255664b4973SAlexander Yarygin 	unsigned long        : 2;
256664b4973SAlexander Yarygin 	unsigned long ca     : 1; /* Controlled-ASN Bit */
257664b4973SAlexander Yarygin 	unsigned long ra     : 1; /* Reusable-ASN Bit */
258664b4973SAlexander Yarygin 	unsigned long asce   : 64; /* Address-Space-Control Element */
259664b4973SAlexander Yarygin 	unsigned long ald    : 32;
260664b4973SAlexander Yarygin 	unsigned long astesn : 32;
261664b4973SAlexander Yarygin 	/* .. more fields there */
2621cae0255SMartin Schwidefsky };
2638a242234SHeiko Carstens 
2648a242234SHeiko Carstens int ipte_lock_held(struct kvm_vcpu *vcpu)
2658a242234SHeiko Carstens {
2660c9d8683SDavid Hildenbrand 	if (vcpu->arch.sie_block->eca & ECA_SII) {
2675e044315SEugene (jno) Dvurechenski 		int rc;
2688a242234SHeiko Carstens 
2695e044315SEugene (jno) Dvurechenski 		read_lock(&vcpu->kvm->arch.sca_lock);
2705e044315SEugene (jno) Dvurechenski 		rc = kvm_s390_get_ipte_control(vcpu->kvm)->kh != 0;
2715e044315SEugene (jno) Dvurechenski 		read_unlock(&vcpu->kvm->arch.sca_lock);
2725e044315SEugene (jno) Dvurechenski 		return rc;
2735e044315SEugene (jno) Dvurechenski 	}
274a6b7e459SThomas Huth 	return vcpu->kvm->arch.ipte_lock_count != 0;
2758a242234SHeiko Carstens }
2768a242234SHeiko Carstens 
2778a242234SHeiko Carstens static void ipte_lock_simple(struct kvm_vcpu *vcpu)
2788a242234SHeiko Carstens {
2798a242234SHeiko Carstens 	union ipte_control old, new, *ic;
2808a242234SHeiko Carstens 
281a6b7e459SThomas Huth 	mutex_lock(&vcpu->kvm->arch.ipte_mutex);
282a6b7e459SThomas Huth 	vcpu->kvm->arch.ipte_lock_count++;
283a6b7e459SThomas Huth 	if (vcpu->kvm->arch.ipte_lock_count > 1)
2848a242234SHeiko Carstens 		goto out;
2855e044315SEugene (jno) Dvurechenski retry:
2865e044315SEugene (jno) Dvurechenski 	read_lock(&vcpu->kvm->arch.sca_lock);
28760514510SEugene (jno) Dvurechenski 	ic = kvm_s390_get_ipte_control(vcpu->kvm);
2888a242234SHeiko Carstens 	do {
2895de72a22SChristian Borntraeger 		old = READ_ONCE(*ic);
2905e044315SEugene (jno) Dvurechenski 		if (old.k) {
2915e044315SEugene (jno) Dvurechenski 			read_unlock(&vcpu->kvm->arch.sca_lock);
2928a242234SHeiko Carstens 			cond_resched();
2935e044315SEugene (jno) Dvurechenski 			goto retry;
2948a242234SHeiko Carstens 		}
2958a242234SHeiko Carstens 		new = old;
2968a242234SHeiko Carstens 		new.k = 1;
2978a242234SHeiko Carstens 	} while (cmpxchg(&ic->val, old.val, new.val) != old.val);
2985e044315SEugene (jno) Dvurechenski 	read_unlock(&vcpu->kvm->arch.sca_lock);
2998a242234SHeiko Carstens out:
300a6b7e459SThomas Huth 	mutex_unlock(&vcpu->kvm->arch.ipte_mutex);
3018a242234SHeiko Carstens }
3028a242234SHeiko Carstens 
3038a242234SHeiko Carstens static void ipte_unlock_simple(struct kvm_vcpu *vcpu)
3048a242234SHeiko Carstens {
3058a242234SHeiko Carstens 	union ipte_control old, new, *ic;
3068a242234SHeiko Carstens 
307a6b7e459SThomas Huth 	mutex_lock(&vcpu->kvm->arch.ipte_mutex);
308a6b7e459SThomas Huth 	vcpu->kvm->arch.ipte_lock_count--;
309a6b7e459SThomas Huth 	if (vcpu->kvm->arch.ipte_lock_count)
3108a242234SHeiko Carstens 		goto out;
3115e044315SEugene (jno) Dvurechenski 	read_lock(&vcpu->kvm->arch.sca_lock);
31260514510SEugene (jno) Dvurechenski 	ic = kvm_s390_get_ipte_control(vcpu->kvm);
3138a242234SHeiko Carstens 	do {
3145de72a22SChristian Borntraeger 		old = READ_ONCE(*ic);
3151365039dSChristian Borntraeger 		new = old;
3168a242234SHeiko Carstens 		new.k = 0;
3178a242234SHeiko Carstens 	} while (cmpxchg(&ic->val, old.val, new.val) != old.val);
3185e044315SEugene (jno) Dvurechenski 	read_unlock(&vcpu->kvm->arch.sca_lock);
3198a242234SHeiko Carstens 	wake_up(&vcpu->kvm->arch.ipte_wq);
3208a242234SHeiko Carstens out:
321a6b7e459SThomas Huth 	mutex_unlock(&vcpu->kvm->arch.ipte_mutex);
3228a242234SHeiko Carstens }
3238a242234SHeiko Carstens 
3248a242234SHeiko Carstens static void ipte_lock_siif(struct kvm_vcpu *vcpu)
3258a242234SHeiko Carstens {
3268a242234SHeiko Carstens 	union ipte_control old, new, *ic;
3278a242234SHeiko Carstens 
3285e044315SEugene (jno) Dvurechenski retry:
3295e044315SEugene (jno) Dvurechenski 	read_lock(&vcpu->kvm->arch.sca_lock);
33060514510SEugene (jno) Dvurechenski 	ic = kvm_s390_get_ipte_control(vcpu->kvm);
3318a242234SHeiko Carstens 	do {
3325de72a22SChristian Borntraeger 		old = READ_ONCE(*ic);
3335e044315SEugene (jno) Dvurechenski 		if (old.kg) {
3345e044315SEugene (jno) Dvurechenski 			read_unlock(&vcpu->kvm->arch.sca_lock);
3358a242234SHeiko Carstens 			cond_resched();
3365e044315SEugene (jno) Dvurechenski 			goto retry;
3378a242234SHeiko Carstens 		}
3388a242234SHeiko Carstens 		new = old;
3398a242234SHeiko Carstens 		new.k = 1;
3408a242234SHeiko Carstens 		new.kh++;
3418a242234SHeiko Carstens 	} while (cmpxchg(&ic->val, old.val, new.val) != old.val);
3425e044315SEugene (jno) Dvurechenski 	read_unlock(&vcpu->kvm->arch.sca_lock);
3438a242234SHeiko Carstens }
3448a242234SHeiko Carstens 
3458a242234SHeiko Carstens static void ipte_unlock_siif(struct kvm_vcpu *vcpu)
3468a242234SHeiko Carstens {
3478a242234SHeiko Carstens 	union ipte_control old, new, *ic;
3488a242234SHeiko Carstens 
3495e044315SEugene (jno) Dvurechenski 	read_lock(&vcpu->kvm->arch.sca_lock);
35060514510SEugene (jno) Dvurechenski 	ic = kvm_s390_get_ipte_control(vcpu->kvm);
3518a242234SHeiko Carstens 	do {
3525de72a22SChristian Borntraeger 		old = READ_ONCE(*ic);
3531365039dSChristian Borntraeger 		new = old;
3548a242234SHeiko Carstens 		new.kh--;
3558a242234SHeiko Carstens 		if (!new.kh)
3568a242234SHeiko Carstens 			new.k = 0;
3578a242234SHeiko Carstens 	} while (cmpxchg(&ic->val, old.val, new.val) != old.val);
3585e044315SEugene (jno) Dvurechenski 	read_unlock(&vcpu->kvm->arch.sca_lock);
3598a242234SHeiko Carstens 	if (!new.kh)
3608a242234SHeiko Carstens 		wake_up(&vcpu->kvm->arch.ipte_wq);
3618a242234SHeiko Carstens }
3628a242234SHeiko Carstens 
363a0465f9aSThomas Huth void ipte_lock(struct kvm_vcpu *vcpu)
3648a242234SHeiko Carstens {
3650c9d8683SDavid Hildenbrand 	if (vcpu->arch.sie_block->eca & ECA_SII)
3668a242234SHeiko Carstens 		ipte_lock_siif(vcpu);
3678a242234SHeiko Carstens 	else
3688a242234SHeiko Carstens 		ipte_lock_simple(vcpu);
3698a242234SHeiko Carstens }
3708a242234SHeiko Carstens 
371a0465f9aSThomas Huth void ipte_unlock(struct kvm_vcpu *vcpu)
3728a242234SHeiko Carstens {
3730c9d8683SDavid Hildenbrand 	if (vcpu->arch.sie_block->eca & ECA_SII)
3748a242234SHeiko Carstens 		ipte_unlock_siif(vcpu);
3758a242234SHeiko Carstens 	else
3768a242234SHeiko Carstens 		ipte_unlock_simple(vcpu);
3778a242234SHeiko Carstens }
3788a242234SHeiko Carstens 
37927f67f87SChristian Borntraeger static int ar_translation(struct kvm_vcpu *vcpu, union asce *asce, u8 ar,
38092c96321SDavid Hildenbrand 			  enum gacc_mode mode)
38122938978SHeiko Carstens {
382664b4973SAlexander Yarygin 	union alet alet;
383664b4973SAlexander Yarygin 	struct ale ale;
384664b4973SAlexander Yarygin 	struct aste aste;
385664b4973SAlexander Yarygin 	unsigned long ald_addr, authority_table_addr;
386664b4973SAlexander Yarygin 	union ald ald;
387664b4973SAlexander Yarygin 	int eax, rc;
388664b4973SAlexander Yarygin 	u8 authority_table;
389664b4973SAlexander Yarygin 
390664b4973SAlexander Yarygin 	if (ar >= NUM_ACRS)
391664b4973SAlexander Yarygin 		return -EINVAL;
392664b4973SAlexander Yarygin 
393664b4973SAlexander Yarygin 	save_access_regs(vcpu->run->s.regs.acrs);
394664b4973SAlexander Yarygin 	alet.val = vcpu->run->s.regs.acrs[ar];
395664b4973SAlexander Yarygin 
396664b4973SAlexander Yarygin 	if (ar == 0 || alet.val == 0) {
397664b4973SAlexander Yarygin 		asce->val = vcpu->arch.sie_block->gcr[1];
398664b4973SAlexander Yarygin 		return 0;
399664b4973SAlexander Yarygin 	} else if (alet.val == 1) {
400664b4973SAlexander Yarygin 		asce->val = vcpu->arch.sie_block->gcr[7];
401664b4973SAlexander Yarygin 		return 0;
402664b4973SAlexander Yarygin 	}
403664b4973SAlexander Yarygin 
404664b4973SAlexander Yarygin 	if (alet.reserved)
405664b4973SAlexander Yarygin 		return PGM_ALET_SPECIFICATION;
406664b4973SAlexander Yarygin 
407664b4973SAlexander Yarygin 	if (alet.p)
408664b4973SAlexander Yarygin 		ald_addr = vcpu->arch.sie_block->gcr[5];
409664b4973SAlexander Yarygin 	else
410664b4973SAlexander Yarygin 		ald_addr = vcpu->arch.sie_block->gcr[2];
411664b4973SAlexander Yarygin 	ald_addr &= 0x7fffffc0;
412664b4973SAlexander Yarygin 
413664b4973SAlexander Yarygin 	rc = read_guest_real(vcpu, ald_addr + 16, &ald.val, sizeof(union ald));
414664b4973SAlexander Yarygin 	if (rc)
415664b4973SAlexander Yarygin 		return rc;
416664b4973SAlexander Yarygin 
417664b4973SAlexander Yarygin 	if (alet.alen / 8 > ald.all)
418664b4973SAlexander Yarygin 		return PGM_ALEN_TRANSLATION;
419664b4973SAlexander Yarygin 
420664b4973SAlexander Yarygin 	if (0x7fffffff - ald.alo * 128 < alet.alen * 16)
421664b4973SAlexander Yarygin 		return PGM_ADDRESSING;
422664b4973SAlexander Yarygin 
423664b4973SAlexander Yarygin 	rc = read_guest_real(vcpu, ald.alo * 128 + alet.alen * 16, &ale,
424664b4973SAlexander Yarygin 			     sizeof(struct ale));
425664b4973SAlexander Yarygin 	if (rc)
426664b4973SAlexander Yarygin 		return rc;
427664b4973SAlexander Yarygin 
428664b4973SAlexander Yarygin 	if (ale.i == 1)
429664b4973SAlexander Yarygin 		return PGM_ALEN_TRANSLATION;
430664b4973SAlexander Yarygin 	if (ale.alesn != alet.alesn)
431664b4973SAlexander Yarygin 		return PGM_ALE_SEQUENCE;
432664b4973SAlexander Yarygin 
433664b4973SAlexander Yarygin 	rc = read_guest_real(vcpu, ale.asteo * 64, &aste, sizeof(struct aste));
434664b4973SAlexander Yarygin 	if (rc)
435664b4973SAlexander Yarygin 		return rc;
436664b4973SAlexander Yarygin 
437664b4973SAlexander Yarygin 	if (aste.i)
438664b4973SAlexander Yarygin 		return PGM_ASTE_VALIDITY;
439664b4973SAlexander Yarygin 	if (aste.astesn != ale.astesn)
440664b4973SAlexander Yarygin 		return PGM_ASTE_SEQUENCE;
441664b4973SAlexander Yarygin 
442664b4973SAlexander Yarygin 	if (ale.p == 1) {
443664b4973SAlexander Yarygin 		eax = (vcpu->arch.sie_block->gcr[8] >> 16) & 0xffff;
444664b4973SAlexander Yarygin 		if (ale.aleax != eax) {
445664b4973SAlexander Yarygin 			if (eax / 16 > aste.atl)
446664b4973SAlexander Yarygin 				return PGM_EXTENDED_AUTHORITY;
447664b4973SAlexander Yarygin 
448664b4973SAlexander Yarygin 			authority_table_addr = aste.ato * 4 + eax / 4;
449664b4973SAlexander Yarygin 
450664b4973SAlexander Yarygin 			rc = read_guest_real(vcpu, authority_table_addr,
451664b4973SAlexander Yarygin 					     &authority_table,
452664b4973SAlexander Yarygin 					     sizeof(u8));
453664b4973SAlexander Yarygin 			if (rc)
454664b4973SAlexander Yarygin 				return rc;
455664b4973SAlexander Yarygin 
456664b4973SAlexander Yarygin 			if ((authority_table & (0x40 >> ((eax & 3) * 2))) == 0)
457664b4973SAlexander Yarygin 				return PGM_EXTENDED_AUTHORITY;
458664b4973SAlexander Yarygin 		}
459664b4973SAlexander Yarygin 	}
460664b4973SAlexander Yarygin 
46192c96321SDavid Hildenbrand 	if (ale.fo == 1 && mode == GACC_STORE)
462664b4973SAlexander Yarygin 		return PGM_PROTECTION;
463664b4973SAlexander Yarygin 
464664b4973SAlexander Yarygin 	asce->val = aste.asce;
465664b4973SAlexander Yarygin 	return 0;
466664b4973SAlexander Yarygin }
467664b4973SAlexander Yarygin 
468664b4973SAlexander Yarygin struct trans_exc_code_bits {
469664b4973SAlexander Yarygin 	unsigned long addr : 52; /* Translation-exception Address */
470664b4973SAlexander Yarygin 	unsigned long fsi  : 2;  /* Access Exception Fetch/Store Indication */
471a679c547SChristian Borntraeger 	unsigned long	   : 2;
472a679c547SChristian Borntraeger 	unsigned long b56  : 1;
473a679c547SChristian Borntraeger 	unsigned long	   : 3;
474664b4973SAlexander Yarygin 	unsigned long b60  : 1;
475664b4973SAlexander Yarygin 	unsigned long b61  : 1;
476664b4973SAlexander Yarygin 	unsigned long as   : 2;  /* ASCE Identifier */
477664b4973SAlexander Yarygin };
478664b4973SAlexander Yarygin 
479664b4973SAlexander Yarygin enum {
480664b4973SAlexander Yarygin 	FSI_UNKNOWN = 0, /* Unknown wether fetch or store */
481664b4973SAlexander Yarygin 	FSI_STORE   = 1, /* Exception was due to store operation */
482664b4973SAlexander Yarygin 	FSI_FETCH   = 2  /* Exception was due to fetch operation */
483664b4973SAlexander Yarygin };
484664b4973SAlexander Yarygin 
485d03193deSDavid Hildenbrand enum prot_type {
486d03193deSDavid Hildenbrand 	PROT_TYPE_LA   = 0,
487d03193deSDavid Hildenbrand 	PROT_TYPE_KEYC = 1,
488d03193deSDavid Hildenbrand 	PROT_TYPE_ALC  = 2,
489d03193deSDavid Hildenbrand 	PROT_TYPE_DAT  = 3,
4906ae1574cSChristian Borntraeger 	PROT_TYPE_IEP  = 4,
491d03193deSDavid Hildenbrand };
492d03193deSDavid Hildenbrand 
493d03193deSDavid Hildenbrand static int trans_exc(struct kvm_vcpu *vcpu, int code, unsigned long gva,
49427f67f87SChristian Borntraeger 		     u8 ar, enum gacc_mode mode, enum prot_type prot)
495d03193deSDavid Hildenbrand {
496d03193deSDavid Hildenbrand 	struct kvm_s390_pgm_info *pgm = &vcpu->arch.pgm;
497d03193deSDavid Hildenbrand 	struct trans_exc_code_bits *tec;
498d03193deSDavid Hildenbrand 
499d03193deSDavid Hildenbrand 	memset(pgm, 0, sizeof(*pgm));
500d03193deSDavid Hildenbrand 	pgm->code = code;
501d03193deSDavid Hildenbrand 	tec = (struct trans_exc_code_bits *)&pgm->trans_exc_code;
502d03193deSDavid Hildenbrand 
503d03193deSDavid Hildenbrand 	switch (code) {
504c14b88d7SJanosch Frank 	case PGM_PROTECTION:
505c14b88d7SJanosch Frank 		switch (prot) {
5066ae1574cSChristian Borntraeger 		case PROT_TYPE_IEP:
5076ae1574cSChristian Borntraeger 			tec->b61 = 1;
5086ae1574cSChristian Borntraeger 			/* FALL THROUGH */
509a679c547SChristian Borntraeger 		case PROT_TYPE_LA:
510a679c547SChristian Borntraeger 			tec->b56 = 1;
511a679c547SChristian Borntraeger 			break;
512a679c547SChristian Borntraeger 		case PROT_TYPE_KEYC:
513a679c547SChristian Borntraeger 			tec->b60 = 1;
514a679c547SChristian Borntraeger 			break;
515c14b88d7SJanosch Frank 		case PROT_TYPE_ALC:
516c14b88d7SJanosch Frank 			tec->b60 = 1;
517c14b88d7SJanosch Frank 			/* FALL THROUGH */
518c14b88d7SJanosch Frank 		case PROT_TYPE_DAT:
519c14b88d7SJanosch Frank 			tec->b61 = 1;
520c14b88d7SJanosch Frank 			break;
521c14b88d7SJanosch Frank 		}
522c14b88d7SJanosch Frank 		/* FALL THROUGH */
523d03193deSDavid Hildenbrand 	case PGM_ASCE_TYPE:
524d03193deSDavid Hildenbrand 	case PGM_PAGE_TRANSLATION:
525d03193deSDavid Hildenbrand 	case PGM_REGION_FIRST_TRANS:
526d03193deSDavid Hildenbrand 	case PGM_REGION_SECOND_TRANS:
527d03193deSDavid Hildenbrand 	case PGM_REGION_THIRD_TRANS:
528d03193deSDavid Hildenbrand 	case PGM_SEGMENT_TRANSLATION:
529d03193deSDavid Hildenbrand 		/*
530d03193deSDavid Hildenbrand 		 * op_access_id only applies to MOVE_PAGE -> set bit 61
531d03193deSDavid Hildenbrand 		 * exc_access_id has to be set to 0 for some instructions. Both
532c14b88d7SJanosch Frank 		 * cases have to be handled by the caller.
533d03193deSDavid Hildenbrand 		 */
534d03193deSDavid Hildenbrand 		tec->addr = gva >> PAGE_SHIFT;
535d03193deSDavid Hildenbrand 		tec->fsi = mode == GACC_STORE ? FSI_STORE : FSI_FETCH;
536d03193deSDavid Hildenbrand 		tec->as = psw_bits(vcpu->arch.sie_block->gpsw).as;
537d03193deSDavid Hildenbrand 		/* FALL THROUGH */
538d03193deSDavid Hildenbrand 	case PGM_ALEN_TRANSLATION:
539d03193deSDavid Hildenbrand 	case PGM_ALE_SEQUENCE:
540d03193deSDavid Hildenbrand 	case PGM_ASTE_VALIDITY:
541d03193deSDavid Hildenbrand 	case PGM_ASTE_SEQUENCE:
542d03193deSDavid Hildenbrand 	case PGM_EXTENDED_AUTHORITY:
543c14b88d7SJanosch Frank 		/*
544c14b88d7SJanosch Frank 		 * We can always store exc_access_id, as it is
545c14b88d7SJanosch Frank 		 * undefined for non-ar cases. It is undefined for
546c14b88d7SJanosch Frank 		 * most DAT protection exceptions.
547c14b88d7SJanosch Frank 		 */
548d03193deSDavid Hildenbrand 		pgm->exc_access_id = ar;
549d03193deSDavid Hildenbrand 		break;
550d03193deSDavid Hildenbrand 	}
551d03193deSDavid Hildenbrand 	return code;
552d03193deSDavid Hildenbrand }
553d03193deSDavid Hildenbrand 
554664b4973SAlexander Yarygin static int get_vcpu_asce(struct kvm_vcpu *vcpu, union asce *asce,
55527f67f87SChristian Borntraeger 			 unsigned long ga, u8 ar, enum gacc_mode mode)
556664b4973SAlexander Yarygin {
557664b4973SAlexander Yarygin 	int rc;
55834346b9aSDavid Hildenbrand 	struct psw_bits psw = psw_bits(vcpu->arch.sie_block->gpsw);
559664b4973SAlexander Yarygin 
560a7525982SHeiko Carstens 	if (!psw.dat) {
561664b4973SAlexander Yarygin 		asce->val = 0;
562664b4973SAlexander Yarygin 		asce->r = 1;
563664b4973SAlexander Yarygin 		return 0;
564664b4973SAlexander Yarygin 	}
565664b4973SAlexander Yarygin 
5668bb3fdd6SHeiko Carstens 	if ((mode == GACC_IFETCH) && (psw.as != PSW_BITS_AS_HOME))
5678bb3fdd6SHeiko Carstens 		psw.as = PSW_BITS_AS_PRIMARY;
56834346b9aSDavid Hildenbrand 
56934346b9aSDavid Hildenbrand 	switch (psw.as) {
5708bb3fdd6SHeiko Carstens 	case PSW_BITS_AS_PRIMARY:
571664b4973SAlexander Yarygin 		asce->val = vcpu->arch.sie_block->gcr[1];
572664b4973SAlexander Yarygin 		return 0;
5738bb3fdd6SHeiko Carstens 	case PSW_BITS_AS_SECONDARY:
574664b4973SAlexander Yarygin 		asce->val = vcpu->arch.sie_block->gcr[7];
575664b4973SAlexander Yarygin 		return 0;
5768bb3fdd6SHeiko Carstens 	case PSW_BITS_AS_HOME:
577664b4973SAlexander Yarygin 		asce->val = vcpu->arch.sie_block->gcr[13];
578664b4973SAlexander Yarygin 		return 0;
5798bb3fdd6SHeiko Carstens 	case PSW_BITS_AS_ACCREG:
58092c96321SDavid Hildenbrand 		rc = ar_translation(vcpu, asce, ar, mode);
581664b4973SAlexander Yarygin 		if (rc > 0)
582bcfa01d7SDavid Hildenbrand 			return trans_exc(vcpu, rc, ga, ar, mode, PROT_TYPE_ALC);
583664b4973SAlexander Yarygin 		return rc;
58422938978SHeiko Carstens 	}
58522938978SHeiko Carstens 	return 0;
58622938978SHeiko Carstens }
58722938978SHeiko Carstens 
58822938978SHeiko Carstens static int deref_table(struct kvm *kvm, unsigned long gpa, unsigned long *val)
58922938978SHeiko Carstens {
59022938978SHeiko Carstens 	return kvm_read_guest(kvm, gpa, val, sizeof(*val));
59122938978SHeiko Carstens }
59222938978SHeiko Carstens 
59322938978SHeiko Carstens /**
59422938978SHeiko Carstens  * guest_translate - translate a guest virtual into a guest absolute address
59522938978SHeiko Carstens  * @vcpu: virtual cpu
59622938978SHeiko Carstens  * @gva: guest virtual address
59722938978SHeiko Carstens  * @gpa: points to where guest physical (absolute) address should be stored
59875a18122SAlexander Yarygin  * @asce: effective asce
59992c96321SDavid Hildenbrand  * @mode: indicates the access mode to be used
6006ae1574cSChristian Borntraeger  * @prot: returns the type for protection exceptions
60122938978SHeiko Carstens  *
60222938978SHeiko Carstens  * Translate a guest virtual address into a guest absolute address by means
60316b0fc13SYannick Guerrini  * of dynamic address translation as specified by the architecture.
60422938978SHeiko Carstens  * If the resulting absolute address is not available in the configuration
60522938978SHeiko Carstens  * an addressing exception is indicated and @gpa will not be changed.
60622938978SHeiko Carstens  *
60722938978SHeiko Carstens  * Returns: - zero on success; @gpa contains the resulting absolute address
60822938978SHeiko Carstens  *	    - a negative value if guest access failed due to e.g. broken
60922938978SHeiko Carstens  *	      guest mapping
61022938978SHeiko Carstens  *	    - a positve value if an access exception happened. In this case
61122938978SHeiko Carstens  *	      the returned value is the program interruption code as defined
61222938978SHeiko Carstens  *	      by the architecture
61322938978SHeiko Carstens  */
61422938978SHeiko Carstens static unsigned long guest_translate(struct kvm_vcpu *vcpu, unsigned long gva,
61575a18122SAlexander Yarygin 				     unsigned long *gpa, const union asce asce,
6166ae1574cSChristian Borntraeger 				     enum gacc_mode mode, enum prot_type *prot)
61722938978SHeiko Carstens {
61822938978SHeiko Carstens 	union vaddress vaddr = {.addr = gva};
61922938978SHeiko Carstens 	union raddress raddr = {.addr = gva};
62022938978SHeiko Carstens 	union page_table_entry pte;
62122938978SHeiko Carstens 	int dat_protection = 0;
6226ae1574cSChristian Borntraeger 	int iep_protection = 0;
62322938978SHeiko Carstens 	union ctlreg0 ctlreg0;
62422938978SHeiko Carstens 	unsigned long ptr;
6256ae1574cSChristian Borntraeger 	int edat1, edat2, iep;
62622938978SHeiko Carstens 
62722938978SHeiko Carstens 	ctlreg0.val = vcpu->arch.sie_block->gcr[0];
6289d8d5786SMichael Mueller 	edat1 = ctlreg0.edat && test_kvm_facility(vcpu->kvm, 8);
6299d8d5786SMichael Mueller 	edat2 = edat1 && test_kvm_facility(vcpu->kvm, 78);
6306ae1574cSChristian Borntraeger 	iep = ctlreg0.iep && test_kvm_facility(vcpu->kvm, 130);
63122938978SHeiko Carstens 	if (asce.r)
63222938978SHeiko Carstens 		goto real_address;
63358cdf5ebSHeiko Carstens 	ptr = asce.origin * PAGE_SIZE;
63422938978SHeiko Carstens 	switch (asce.dt) {
63522938978SHeiko Carstens 	case ASCE_TYPE_REGION1:
63622938978SHeiko Carstens 		if (vaddr.rfx01 > asce.tl)
63722938978SHeiko Carstens 			return PGM_REGION_FIRST_TRANS;
63822938978SHeiko Carstens 		ptr += vaddr.rfx * 8;
63922938978SHeiko Carstens 		break;
64022938978SHeiko Carstens 	case ASCE_TYPE_REGION2:
64122938978SHeiko Carstens 		if (vaddr.rfx)
64222938978SHeiko Carstens 			return PGM_ASCE_TYPE;
64322938978SHeiko Carstens 		if (vaddr.rsx01 > asce.tl)
64422938978SHeiko Carstens 			return PGM_REGION_SECOND_TRANS;
64522938978SHeiko Carstens 		ptr += vaddr.rsx * 8;
64622938978SHeiko Carstens 		break;
64722938978SHeiko Carstens 	case ASCE_TYPE_REGION3:
64822938978SHeiko Carstens 		if (vaddr.rfx || vaddr.rsx)
64922938978SHeiko Carstens 			return PGM_ASCE_TYPE;
65022938978SHeiko Carstens 		if (vaddr.rtx01 > asce.tl)
65122938978SHeiko Carstens 			return PGM_REGION_THIRD_TRANS;
65222938978SHeiko Carstens 		ptr += vaddr.rtx * 8;
65322938978SHeiko Carstens 		break;
65422938978SHeiko Carstens 	case ASCE_TYPE_SEGMENT:
65522938978SHeiko Carstens 		if (vaddr.rfx || vaddr.rsx || vaddr.rtx)
65622938978SHeiko Carstens 			return PGM_ASCE_TYPE;
65722938978SHeiko Carstens 		if (vaddr.sx01 > asce.tl)
65822938978SHeiko Carstens 			return PGM_SEGMENT_TRANSLATION;
65922938978SHeiko Carstens 		ptr += vaddr.sx * 8;
66022938978SHeiko Carstens 		break;
66122938978SHeiko Carstens 	}
66222938978SHeiko Carstens 	switch (asce.dt) {
66322938978SHeiko Carstens 	case ASCE_TYPE_REGION1:	{
66422938978SHeiko Carstens 		union region1_table_entry rfte;
66522938978SHeiko Carstens 
66622938978SHeiko Carstens 		if (kvm_is_error_gpa(vcpu->kvm, ptr))
66722938978SHeiko Carstens 			return PGM_ADDRESSING;
66822938978SHeiko Carstens 		if (deref_table(vcpu->kvm, ptr, &rfte.val))
66922938978SHeiko Carstens 			return -EFAULT;
67022938978SHeiko Carstens 		if (rfte.i)
67122938978SHeiko Carstens 			return PGM_REGION_FIRST_TRANS;
67222938978SHeiko Carstens 		if (rfte.tt != TABLE_TYPE_REGION1)
67322938978SHeiko Carstens 			return PGM_TRANSLATION_SPEC;
67422938978SHeiko Carstens 		if (vaddr.rsx01 < rfte.tf || vaddr.rsx01 > rfte.tl)
67522938978SHeiko Carstens 			return PGM_REGION_SECOND_TRANS;
67622938978SHeiko Carstens 		if (edat1)
67722938978SHeiko Carstens 			dat_protection |= rfte.p;
67858cdf5ebSHeiko Carstens 		ptr = rfte.rto * PAGE_SIZE + vaddr.rsx * 8;
67922938978SHeiko Carstens 	}
68022938978SHeiko Carstens 		/* fallthrough */
68122938978SHeiko Carstens 	case ASCE_TYPE_REGION2: {
68222938978SHeiko Carstens 		union region2_table_entry rste;
68322938978SHeiko Carstens 
68422938978SHeiko Carstens 		if (kvm_is_error_gpa(vcpu->kvm, ptr))
68522938978SHeiko Carstens 			return PGM_ADDRESSING;
68622938978SHeiko Carstens 		if (deref_table(vcpu->kvm, ptr, &rste.val))
68722938978SHeiko Carstens 			return -EFAULT;
68822938978SHeiko Carstens 		if (rste.i)
68922938978SHeiko Carstens 			return PGM_REGION_SECOND_TRANS;
69022938978SHeiko Carstens 		if (rste.tt != TABLE_TYPE_REGION2)
69122938978SHeiko Carstens 			return PGM_TRANSLATION_SPEC;
69222938978SHeiko Carstens 		if (vaddr.rtx01 < rste.tf || vaddr.rtx01 > rste.tl)
69322938978SHeiko Carstens 			return PGM_REGION_THIRD_TRANS;
69422938978SHeiko Carstens 		if (edat1)
69522938978SHeiko Carstens 			dat_protection |= rste.p;
69658cdf5ebSHeiko Carstens 		ptr = rste.rto * PAGE_SIZE + vaddr.rtx * 8;
69722938978SHeiko Carstens 	}
69822938978SHeiko Carstens 		/* fallthrough */
69922938978SHeiko Carstens 	case ASCE_TYPE_REGION3: {
70022938978SHeiko Carstens 		union region3_table_entry rtte;
70122938978SHeiko Carstens 
70222938978SHeiko Carstens 		if (kvm_is_error_gpa(vcpu->kvm, ptr))
70322938978SHeiko Carstens 			return PGM_ADDRESSING;
70422938978SHeiko Carstens 		if (deref_table(vcpu->kvm, ptr, &rtte.val))
70522938978SHeiko Carstens 			return -EFAULT;
70622938978SHeiko Carstens 		if (rtte.i)
70722938978SHeiko Carstens 			return PGM_REGION_THIRD_TRANS;
70822938978SHeiko Carstens 		if (rtte.tt != TABLE_TYPE_REGION3)
70922938978SHeiko Carstens 			return PGM_TRANSLATION_SPEC;
71022938978SHeiko Carstens 		if (rtte.cr && asce.p && edat2)
71122938978SHeiko Carstens 			return PGM_TRANSLATION_SPEC;
71222938978SHeiko Carstens 		if (rtte.fc && edat2) {
71322938978SHeiko Carstens 			dat_protection |= rtte.fc1.p;
7146ae1574cSChristian Borntraeger 			iep_protection = rtte.fc1.iep;
71522938978SHeiko Carstens 			raddr.rfaa = rtte.fc1.rfaa;
71622938978SHeiko Carstens 			goto absolute_address;
71722938978SHeiko Carstens 		}
71822938978SHeiko Carstens 		if (vaddr.sx01 < rtte.fc0.tf)
71922938978SHeiko Carstens 			return PGM_SEGMENT_TRANSLATION;
72022938978SHeiko Carstens 		if (vaddr.sx01 > rtte.fc0.tl)
72122938978SHeiko Carstens 			return PGM_SEGMENT_TRANSLATION;
72222938978SHeiko Carstens 		if (edat1)
72322938978SHeiko Carstens 			dat_protection |= rtte.fc0.p;
72458cdf5ebSHeiko Carstens 		ptr = rtte.fc0.sto * PAGE_SIZE + vaddr.sx * 8;
72522938978SHeiko Carstens 	}
72622938978SHeiko Carstens 		/* fallthrough */
72722938978SHeiko Carstens 	case ASCE_TYPE_SEGMENT: {
72822938978SHeiko Carstens 		union segment_table_entry ste;
72922938978SHeiko Carstens 
73022938978SHeiko Carstens 		if (kvm_is_error_gpa(vcpu->kvm, ptr))
73122938978SHeiko Carstens 			return PGM_ADDRESSING;
73222938978SHeiko Carstens 		if (deref_table(vcpu->kvm, ptr, &ste.val))
73322938978SHeiko Carstens 			return -EFAULT;
73422938978SHeiko Carstens 		if (ste.i)
73522938978SHeiko Carstens 			return PGM_SEGMENT_TRANSLATION;
73622938978SHeiko Carstens 		if (ste.tt != TABLE_TYPE_SEGMENT)
73722938978SHeiko Carstens 			return PGM_TRANSLATION_SPEC;
73822938978SHeiko Carstens 		if (ste.cs && asce.p)
73922938978SHeiko Carstens 			return PGM_TRANSLATION_SPEC;
74022938978SHeiko Carstens 		if (ste.fc && edat1) {
74122938978SHeiko Carstens 			dat_protection |= ste.fc1.p;
7426ae1574cSChristian Borntraeger 			iep_protection = ste.fc1.iep;
74322938978SHeiko Carstens 			raddr.sfaa = ste.fc1.sfaa;
74422938978SHeiko Carstens 			goto absolute_address;
74522938978SHeiko Carstens 		}
74622938978SHeiko Carstens 		dat_protection |= ste.fc0.p;
74758cdf5ebSHeiko Carstens 		ptr = ste.fc0.pto * (PAGE_SIZE / 2) + vaddr.px * 8;
74822938978SHeiko Carstens 	}
74922938978SHeiko Carstens 	}
75022938978SHeiko Carstens 	if (kvm_is_error_gpa(vcpu->kvm, ptr))
75122938978SHeiko Carstens 		return PGM_ADDRESSING;
75222938978SHeiko Carstens 	if (deref_table(vcpu->kvm, ptr, &pte.val))
75322938978SHeiko Carstens 		return -EFAULT;
75422938978SHeiko Carstens 	if (pte.i)
75522938978SHeiko Carstens 		return PGM_PAGE_TRANSLATION;
75622938978SHeiko Carstens 	if (pte.z)
75722938978SHeiko Carstens 		return PGM_TRANSLATION_SPEC;
75822938978SHeiko Carstens 	dat_protection |= pte.p;
7596ae1574cSChristian Borntraeger 	iep_protection = pte.iep;
76022938978SHeiko Carstens 	raddr.pfra = pte.pfra;
76122938978SHeiko Carstens real_address:
76222938978SHeiko Carstens 	raddr.addr = kvm_s390_real_to_abs(vcpu, raddr.addr);
76322938978SHeiko Carstens absolute_address:
7646ae1574cSChristian Borntraeger 	if (mode == GACC_STORE && dat_protection) {
7656ae1574cSChristian Borntraeger 		*prot = PROT_TYPE_DAT;
76622938978SHeiko Carstens 		return PGM_PROTECTION;
7676ae1574cSChristian Borntraeger 	}
7686ae1574cSChristian Borntraeger 	if (mode == GACC_IFETCH && iep_protection && iep) {
7696ae1574cSChristian Borntraeger 		*prot = PROT_TYPE_IEP;
7706ae1574cSChristian Borntraeger 		return PGM_PROTECTION;
7716ae1574cSChristian Borntraeger 	}
77222938978SHeiko Carstens 	if (kvm_is_error_gpa(vcpu->kvm, raddr.addr))
77322938978SHeiko Carstens 		return PGM_ADDRESSING;
77422938978SHeiko Carstens 	*gpa = raddr.addr;
77522938978SHeiko Carstens 	return 0;
77622938978SHeiko Carstens }
77722938978SHeiko Carstens 
77822938978SHeiko Carstens static inline int is_low_address(unsigned long ga)
77922938978SHeiko Carstens {
78022938978SHeiko Carstens 	/* Check for address ranges 0..511 and 4096..4607 */
78122938978SHeiko Carstens 	return (ga & ~0x11fful) == 0;
78222938978SHeiko Carstens }
78322938978SHeiko Carstens 
78475a18122SAlexander Yarygin static int low_address_protection_enabled(struct kvm_vcpu *vcpu,
78575a18122SAlexander Yarygin 					  const union asce asce)
78622938978SHeiko Carstens {
78722938978SHeiko Carstens 	union ctlreg0 ctlreg0 = {.val = vcpu->arch.sie_block->gcr[0]};
78822938978SHeiko Carstens 	psw_t *psw = &vcpu->arch.sie_block->gpsw;
78922938978SHeiko Carstens 
79022938978SHeiko Carstens 	if (!ctlreg0.lap)
79122938978SHeiko Carstens 		return 0;
792a7525982SHeiko Carstens 	if (psw_bits(*psw).dat && asce.p)
79322938978SHeiko Carstens 		return 0;
79422938978SHeiko Carstens 	return 1;
79522938978SHeiko Carstens }
79622938978SHeiko Carstens 
79727f67f87SChristian Borntraeger static int guest_page_range(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar,
79822938978SHeiko Carstens 			    unsigned long *pages, unsigned long nr_pages,
79992c96321SDavid Hildenbrand 			    const union asce asce, enum gacc_mode mode)
80022938978SHeiko Carstens {
80122938978SHeiko Carstens 	psw_t *psw = &vcpu->arch.sie_block->gpsw;
802cde0dcfbSDavid Hildenbrand 	int lap_enabled, rc = 0;
8036ae1574cSChristian Borntraeger 	enum prot_type prot;
80422938978SHeiko Carstens 
80575a18122SAlexander Yarygin 	lap_enabled = low_address_protection_enabled(vcpu, asce);
80622938978SHeiko Carstens 	while (nr_pages) {
80722938978SHeiko Carstens 		ga = kvm_s390_logical_to_effective(vcpu, ga);
808cde0dcfbSDavid Hildenbrand 		if (mode == GACC_STORE && lap_enabled && is_low_address(ga))
809cde0dcfbSDavid Hildenbrand 			return trans_exc(vcpu, PGM_PROTECTION, ga, ar, mode,
810cde0dcfbSDavid Hildenbrand 					 PROT_TYPE_LA);
81122938978SHeiko Carstens 		ga &= PAGE_MASK;
812a7525982SHeiko Carstens 		if (psw_bits(*psw).dat) {
8136ae1574cSChristian Borntraeger 			rc = guest_translate(vcpu, ga, pages, asce, mode, &prot);
81422938978SHeiko Carstens 			if (rc < 0)
81522938978SHeiko Carstens 				return rc;
81622938978SHeiko Carstens 		} else {
81722938978SHeiko Carstens 			*pages = kvm_s390_real_to_abs(vcpu, ga);
81822938978SHeiko Carstens 			if (kvm_is_error_gpa(vcpu->kvm, *pages))
819cde0dcfbSDavid Hildenbrand 				rc = PGM_ADDRESSING;
82022938978SHeiko Carstens 		}
821cde0dcfbSDavid Hildenbrand 		if (rc)
8226ae1574cSChristian Borntraeger 			return trans_exc(vcpu, rc, ga, ar, mode, prot);
82322938978SHeiko Carstens 		ga += PAGE_SIZE;
82422938978SHeiko Carstens 		pages++;
82522938978SHeiko Carstens 		nr_pages--;
82622938978SHeiko Carstens 	}
82722938978SHeiko Carstens 	return 0;
82822938978SHeiko Carstens }
82922938978SHeiko Carstens 
83027f67f87SChristian Borntraeger int access_guest(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar, void *data,
83192c96321SDavid Hildenbrand 		 unsigned long len, enum gacc_mode mode)
83222938978SHeiko Carstens {
83322938978SHeiko Carstens 	psw_t *psw = &vcpu->arch.sie_block->gpsw;
83422938978SHeiko Carstens 	unsigned long _len, nr_pages, gpa, idx;
83522938978SHeiko Carstens 	unsigned long pages_array[2];
83622938978SHeiko Carstens 	unsigned long *pages;
8378a242234SHeiko Carstens 	int need_ipte_lock;
8388a242234SHeiko Carstens 	union asce asce;
83922938978SHeiko Carstens 	int rc;
84022938978SHeiko Carstens 
84122938978SHeiko Carstens 	if (!len)
84222938978SHeiko Carstens 		return 0;
8436167375bSDavid Hildenbrand 	ga = kvm_s390_logical_to_effective(vcpu, ga);
8446167375bSDavid Hildenbrand 	rc = get_vcpu_asce(vcpu, &asce, ga, ar, mode);
845664b4973SAlexander Yarygin 	if (rc)
846664b4973SAlexander Yarygin 		return rc;
84722938978SHeiko Carstens 	nr_pages = (((ga & ~PAGE_MASK) + len - 1) >> PAGE_SHIFT) + 1;
84822938978SHeiko Carstens 	pages = pages_array;
84922938978SHeiko Carstens 	if (nr_pages > ARRAY_SIZE(pages_array))
85022938978SHeiko Carstens 		pages = vmalloc(nr_pages * sizeof(unsigned long));
85122938978SHeiko Carstens 	if (!pages)
85222938978SHeiko Carstens 		return -ENOMEM;
853a7525982SHeiko Carstens 	need_ipte_lock = psw_bits(*psw).dat && !asce.r;
8548a242234SHeiko Carstens 	if (need_ipte_lock)
8558a242234SHeiko Carstens 		ipte_lock(vcpu);
856cde0dcfbSDavid Hildenbrand 	rc = guest_page_range(vcpu, ga, ar, pages, nr_pages, asce, mode);
85722938978SHeiko Carstens 	for (idx = 0; idx < nr_pages && !rc; idx++) {
85822938978SHeiko Carstens 		gpa = *(pages + idx) + (ga & ~PAGE_MASK);
85922938978SHeiko Carstens 		_len = min(PAGE_SIZE - (gpa & ~PAGE_MASK), len);
86092c96321SDavid Hildenbrand 		if (mode == GACC_STORE)
86122938978SHeiko Carstens 			rc = kvm_write_guest(vcpu->kvm, gpa, data, _len);
86222938978SHeiko Carstens 		else
86322938978SHeiko Carstens 			rc = kvm_read_guest(vcpu->kvm, gpa, data, _len);
86422938978SHeiko Carstens 		len -= _len;
86522938978SHeiko Carstens 		ga += _len;
86622938978SHeiko Carstens 		data += _len;
86722938978SHeiko Carstens 	}
8688a242234SHeiko Carstens 	if (need_ipte_lock)
8698a242234SHeiko Carstens 		ipte_unlock(vcpu);
87022938978SHeiko Carstens 	if (nr_pages > ARRAY_SIZE(pages_array))
87122938978SHeiko Carstens 		vfree(pages);
87222938978SHeiko Carstens 	return rc;
87322938978SHeiko Carstens }
87422938978SHeiko Carstens 
87522938978SHeiko Carstens int access_guest_real(struct kvm_vcpu *vcpu, unsigned long gra,
87692c96321SDavid Hildenbrand 		      void *data, unsigned long len, enum gacc_mode mode)
87722938978SHeiko Carstens {
87822938978SHeiko Carstens 	unsigned long _len, gpa;
87922938978SHeiko Carstens 	int rc = 0;
88022938978SHeiko Carstens 
88122938978SHeiko Carstens 	while (len && !rc) {
88222938978SHeiko Carstens 		gpa = kvm_s390_real_to_abs(vcpu, gra);
88322938978SHeiko Carstens 		_len = min(PAGE_SIZE - (gpa & ~PAGE_MASK), len);
88492c96321SDavid Hildenbrand 		if (mode)
88522938978SHeiko Carstens 			rc = write_guest_abs(vcpu, gpa, data, _len);
88622938978SHeiko Carstens 		else
88722938978SHeiko Carstens 			rc = read_guest_abs(vcpu, gpa, data, _len);
88822938978SHeiko Carstens 		len -= _len;
88922938978SHeiko Carstens 		gra += _len;
89022938978SHeiko Carstens 		data += _len;
89122938978SHeiko Carstens 	}
89222938978SHeiko Carstens 	return rc;
89322938978SHeiko Carstens }
894f8232c8cSThomas Huth 
895f8232c8cSThomas Huth /**
8969fbc0276SThomas Huth  * guest_translate_address - translate guest logical into guest absolute address
8979fbc0276SThomas Huth  *
8989fbc0276SThomas Huth  * Parameter semantics are the same as the ones from guest_translate.
8999fbc0276SThomas Huth  * The memory contents at the guest address are not changed.
9009fbc0276SThomas Huth  *
9019fbc0276SThomas Huth  * Note: The IPTE lock is not taken during this function, so the caller
9029fbc0276SThomas Huth  * has to take care of this.
9039fbc0276SThomas Huth  */
90427f67f87SChristian Borntraeger int guest_translate_address(struct kvm_vcpu *vcpu, unsigned long gva, u8 ar,
90592c96321SDavid Hildenbrand 			    unsigned long *gpa, enum gacc_mode mode)
9069fbc0276SThomas Huth {
9079fbc0276SThomas Huth 	psw_t *psw = &vcpu->arch.sie_block->gpsw;
9086ae1574cSChristian Borntraeger 	enum prot_type prot;
9099fbc0276SThomas Huth 	union asce asce;
9109fbc0276SThomas Huth 	int rc;
9119fbc0276SThomas Huth 
9129fbc0276SThomas Huth 	gva = kvm_s390_logical_to_effective(vcpu, gva);
9136167375bSDavid Hildenbrand 	rc = get_vcpu_asce(vcpu, &asce, gva, ar, mode);
914664b4973SAlexander Yarygin 	if (rc)
915664b4973SAlexander Yarygin 		return rc;
91675a18122SAlexander Yarygin 	if (is_low_address(gva) && low_address_protection_enabled(vcpu, asce)) {
917fbcb7d51SDavid Hildenbrand 		if (mode == GACC_STORE)
918fbcb7d51SDavid Hildenbrand 			return trans_exc(vcpu, PGM_PROTECTION, gva, 0,
919fbcb7d51SDavid Hildenbrand 					 mode, PROT_TYPE_LA);
9209fbc0276SThomas Huth 	}
9219fbc0276SThomas Huth 
922a7525982SHeiko Carstens 	if (psw_bits(*psw).dat && !asce.r) {	/* Use DAT? */
9236ae1574cSChristian Borntraeger 		rc = guest_translate(vcpu, gva, gpa, asce, mode, &prot);
924fbcb7d51SDavid Hildenbrand 		if (rc > 0)
9256ae1574cSChristian Borntraeger 			return trans_exc(vcpu, rc, gva, 0, mode, prot);
9269fbc0276SThomas Huth 	} else {
9279fbc0276SThomas Huth 		*gpa = kvm_s390_real_to_abs(vcpu, gva);
9289fbc0276SThomas Huth 		if (kvm_is_error_gpa(vcpu->kvm, *gpa))
929fbcb7d51SDavid Hildenbrand 			return trans_exc(vcpu, rc, gva, PGM_ADDRESSING, mode, 0);
9309fbc0276SThomas Huth 	}
9319fbc0276SThomas Huth 
9329fbc0276SThomas Huth 	return rc;
9339fbc0276SThomas Huth }
9349fbc0276SThomas Huth 
9359fbc0276SThomas Huth /**
93641408c28SThomas Huth  * check_gva_range - test a range of guest virtual addresses for accessibility
93741408c28SThomas Huth  */
93827f67f87SChristian Borntraeger int check_gva_range(struct kvm_vcpu *vcpu, unsigned long gva, u8 ar,
93992c96321SDavid Hildenbrand 		    unsigned long length, enum gacc_mode mode)
94041408c28SThomas Huth {
94141408c28SThomas Huth 	unsigned long gpa;
94241408c28SThomas Huth 	unsigned long currlen;
94341408c28SThomas Huth 	int rc = 0;
94441408c28SThomas Huth 
94541408c28SThomas Huth 	ipte_lock(vcpu);
94641408c28SThomas Huth 	while (length > 0 && !rc) {
94741408c28SThomas Huth 		currlen = min(length, PAGE_SIZE - (gva % PAGE_SIZE));
94892c96321SDavid Hildenbrand 		rc = guest_translate_address(vcpu, gva, ar, &gpa, mode);
94941408c28SThomas Huth 		gva += currlen;
95041408c28SThomas Huth 		length -= currlen;
95141408c28SThomas Huth 	}
95241408c28SThomas Huth 	ipte_unlock(vcpu);
95341408c28SThomas Huth 
95441408c28SThomas Huth 	return rc;
95541408c28SThomas Huth }
95641408c28SThomas Huth 
95741408c28SThomas Huth /**
958dd9e5b7bSAlexander Yarygin  * kvm_s390_check_low_addr_prot_real - check for low-address protection
959dd9e5b7bSAlexander Yarygin  * @gra: Guest real address
960f8232c8cSThomas Huth  *
961f8232c8cSThomas Huth  * Checks whether an address is subject to low-address protection and set
962f8232c8cSThomas Huth  * up vcpu->arch.pgm accordingly if necessary.
963f8232c8cSThomas Huth  *
964f8232c8cSThomas Huth  * Return: 0 if no protection exception, or PGM_PROTECTION if protected.
965f8232c8cSThomas Huth  */
966dd9e5b7bSAlexander Yarygin int kvm_s390_check_low_addr_prot_real(struct kvm_vcpu *vcpu, unsigned long gra)
967f8232c8cSThomas Huth {
968dd9e5b7bSAlexander Yarygin 	union ctlreg0 ctlreg0 = {.val = vcpu->arch.sie_block->gcr[0]};
969f8232c8cSThomas Huth 
970dd9e5b7bSAlexander Yarygin 	if (!ctlreg0.lap || !is_low_address(gra))
971f8232c8cSThomas Huth 		return 0;
9723e3c67f6SDavid Hildenbrand 	return trans_exc(vcpu, PGM_PROTECTION, gra, 0, GACC_STORE, PROT_TYPE_LA);
973f8232c8cSThomas Huth }
974aa17aa57SMartin Schwidefsky 
975aa17aa57SMartin Schwidefsky /**
976aa17aa57SMartin Schwidefsky  * kvm_s390_shadow_tables - walk the guest page table and create shadow tables
977aa17aa57SMartin Schwidefsky  * @sg: pointer to the shadow guest address space structure
978aa17aa57SMartin Schwidefsky  * @saddr: faulting address in the shadow gmap
979aa17aa57SMartin Schwidefsky  * @pgt: pointer to the page table address result
980fd8d4e3aSDavid Hildenbrand  * @fake: pgt references contiguous guest memory block, not a pgtable
981aa17aa57SMartin Schwidefsky  */
982aa17aa57SMartin Schwidefsky static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr,
983fd8d4e3aSDavid Hildenbrand 				  unsigned long *pgt, int *dat_protection,
984fd8d4e3aSDavid Hildenbrand 				  int *fake)
985aa17aa57SMartin Schwidefsky {
986aa17aa57SMartin Schwidefsky 	struct gmap *parent;
987aa17aa57SMartin Schwidefsky 	union asce asce;
988aa17aa57SMartin Schwidefsky 	union vaddress vaddr;
989aa17aa57SMartin Schwidefsky 	unsigned long ptr;
990aa17aa57SMartin Schwidefsky 	int rc;
991aa17aa57SMartin Schwidefsky 
992fd8d4e3aSDavid Hildenbrand 	*fake = 0;
9931c65781bSDavid Hildenbrand 	*dat_protection = 0;
994aa17aa57SMartin Schwidefsky 	parent = sg->parent;
995aa17aa57SMartin Schwidefsky 	vaddr.addr = saddr;
996aa17aa57SMartin Schwidefsky 	asce.val = sg->orig_asce;
99758cdf5ebSHeiko Carstens 	ptr = asce.origin * PAGE_SIZE;
9983218f709SDavid Hildenbrand 	if (asce.r) {
9993218f709SDavid Hildenbrand 		*fake = 1;
1000addb63c1SHeiko Carstens 		ptr = 0;
10013218f709SDavid Hildenbrand 		asce.dt = ASCE_TYPE_REGION1;
10023218f709SDavid Hildenbrand 	}
1003aa17aa57SMartin Schwidefsky 	switch (asce.dt) {
1004aa17aa57SMartin Schwidefsky 	case ASCE_TYPE_REGION1:
1005addb63c1SHeiko Carstens 		if (vaddr.rfx01 > asce.tl && !*fake)
1006aa17aa57SMartin Schwidefsky 			return PGM_REGION_FIRST_TRANS;
1007aa17aa57SMartin Schwidefsky 		break;
1008aa17aa57SMartin Schwidefsky 	case ASCE_TYPE_REGION2:
1009aa17aa57SMartin Schwidefsky 		if (vaddr.rfx)
1010aa17aa57SMartin Schwidefsky 			return PGM_ASCE_TYPE;
1011aa17aa57SMartin Schwidefsky 		if (vaddr.rsx01 > asce.tl)
1012aa17aa57SMartin Schwidefsky 			return PGM_REGION_SECOND_TRANS;
1013aa17aa57SMartin Schwidefsky 		break;
1014aa17aa57SMartin Schwidefsky 	case ASCE_TYPE_REGION3:
1015aa17aa57SMartin Schwidefsky 		if (vaddr.rfx || vaddr.rsx)
1016aa17aa57SMartin Schwidefsky 			return PGM_ASCE_TYPE;
1017aa17aa57SMartin Schwidefsky 		if (vaddr.rtx01 > asce.tl)
1018aa17aa57SMartin Schwidefsky 			return PGM_REGION_THIRD_TRANS;
1019aa17aa57SMartin Schwidefsky 		break;
1020aa17aa57SMartin Schwidefsky 	case ASCE_TYPE_SEGMENT:
1021aa17aa57SMartin Schwidefsky 		if (vaddr.rfx || vaddr.rsx || vaddr.rtx)
1022aa17aa57SMartin Schwidefsky 			return PGM_ASCE_TYPE;
1023aa17aa57SMartin Schwidefsky 		if (vaddr.sx01 > asce.tl)
1024aa17aa57SMartin Schwidefsky 			return PGM_SEGMENT_TRANSLATION;
1025aa17aa57SMartin Schwidefsky 		break;
1026aa17aa57SMartin Schwidefsky 	}
1027aa17aa57SMartin Schwidefsky 
1028aa17aa57SMartin Schwidefsky 	switch (asce.dt) {
1029aa17aa57SMartin Schwidefsky 	case ASCE_TYPE_REGION1: {
1030aa17aa57SMartin Schwidefsky 		union region1_table_entry rfte;
1031aa17aa57SMartin Schwidefsky 
10323218f709SDavid Hildenbrand 		if (*fake) {
103358cdf5ebSHeiko Carstens 			ptr += vaddr.rfx * _REGION1_SIZE;
10343218f709SDavid Hildenbrand 			rfte.val = ptr;
10353218f709SDavid Hildenbrand 			goto shadow_r2t;
10363218f709SDavid Hildenbrand 		}
1037aa17aa57SMartin Schwidefsky 		rc = gmap_read_table(parent, ptr + vaddr.rfx * 8, &rfte.val);
1038aa17aa57SMartin Schwidefsky 		if (rc)
1039aa17aa57SMartin Schwidefsky 			return rc;
1040aa17aa57SMartin Schwidefsky 		if (rfte.i)
1041aa17aa57SMartin Schwidefsky 			return PGM_REGION_FIRST_TRANS;
1042aa17aa57SMartin Schwidefsky 		if (rfte.tt != TABLE_TYPE_REGION1)
1043aa17aa57SMartin Schwidefsky 			return PGM_TRANSLATION_SPEC;
1044aa17aa57SMartin Schwidefsky 		if (vaddr.rsx01 < rfte.tf || vaddr.rsx01 > rfte.tl)
1045aa17aa57SMartin Schwidefsky 			return PGM_REGION_SECOND_TRANS;
10461c65781bSDavid Hildenbrand 		if (sg->edat_level >= 1)
10471c65781bSDavid Hildenbrand 			*dat_protection |= rfte.p;
104858cdf5ebSHeiko Carstens 		ptr = rfte.rto * PAGE_SIZE;
10493218f709SDavid Hildenbrand shadow_r2t:
10503218f709SDavid Hildenbrand 		rc = gmap_shadow_r2t(sg, saddr, rfte.val, *fake);
1051aa17aa57SMartin Schwidefsky 		if (rc)
1052aa17aa57SMartin Schwidefsky 			return rc;
1053aa17aa57SMartin Schwidefsky 		/* fallthrough */
1054aa17aa57SMartin Schwidefsky 	}
1055aa17aa57SMartin Schwidefsky 	case ASCE_TYPE_REGION2: {
1056aa17aa57SMartin Schwidefsky 		union region2_table_entry rste;
1057aa17aa57SMartin Schwidefsky 
10583218f709SDavid Hildenbrand 		if (*fake) {
105958cdf5ebSHeiko Carstens 			ptr += vaddr.rsx * _REGION2_SIZE;
10603218f709SDavid Hildenbrand 			rste.val = ptr;
10613218f709SDavid Hildenbrand 			goto shadow_r3t;
10623218f709SDavid Hildenbrand 		}
1063aa17aa57SMartin Schwidefsky 		rc = gmap_read_table(parent, ptr + vaddr.rsx * 8, &rste.val);
1064aa17aa57SMartin Schwidefsky 		if (rc)
1065aa17aa57SMartin Schwidefsky 			return rc;
1066aa17aa57SMartin Schwidefsky 		if (rste.i)
1067aa17aa57SMartin Schwidefsky 			return PGM_REGION_SECOND_TRANS;
1068aa17aa57SMartin Schwidefsky 		if (rste.tt != TABLE_TYPE_REGION2)
1069aa17aa57SMartin Schwidefsky 			return PGM_TRANSLATION_SPEC;
1070aa17aa57SMartin Schwidefsky 		if (vaddr.rtx01 < rste.tf || vaddr.rtx01 > rste.tl)
1071aa17aa57SMartin Schwidefsky 			return PGM_REGION_THIRD_TRANS;
10721c65781bSDavid Hildenbrand 		if (sg->edat_level >= 1)
10731c65781bSDavid Hildenbrand 			*dat_protection |= rste.p;
107458cdf5ebSHeiko Carstens 		ptr = rste.rto * PAGE_SIZE;
10753218f709SDavid Hildenbrand shadow_r3t:
10761c65781bSDavid Hildenbrand 		rste.p |= *dat_protection;
10773218f709SDavid Hildenbrand 		rc = gmap_shadow_r3t(sg, saddr, rste.val, *fake);
1078aa17aa57SMartin Schwidefsky 		if (rc)
1079aa17aa57SMartin Schwidefsky 			return rc;
1080aa17aa57SMartin Schwidefsky 		/* fallthrough */
1081aa17aa57SMartin Schwidefsky 	}
1082aa17aa57SMartin Schwidefsky 	case ASCE_TYPE_REGION3: {
1083aa17aa57SMartin Schwidefsky 		union region3_table_entry rtte;
1084aa17aa57SMartin Schwidefsky 
10853218f709SDavid Hildenbrand 		if (*fake) {
108658cdf5ebSHeiko Carstens 			ptr += vaddr.rtx * _REGION3_SIZE;
10873218f709SDavid Hildenbrand 			rtte.val = ptr;
10883218f709SDavid Hildenbrand 			goto shadow_sgt;
10893218f709SDavid Hildenbrand 		}
1090aa17aa57SMartin Schwidefsky 		rc = gmap_read_table(parent, ptr + vaddr.rtx * 8, &rtte.val);
1091aa17aa57SMartin Schwidefsky 		if (rc)
1092aa17aa57SMartin Schwidefsky 			return rc;
1093aa17aa57SMartin Schwidefsky 		if (rtte.i)
1094aa17aa57SMartin Schwidefsky 			return PGM_REGION_THIRD_TRANS;
1095aa17aa57SMartin Schwidefsky 		if (rtte.tt != TABLE_TYPE_REGION3)
1096aa17aa57SMartin Schwidefsky 			return PGM_TRANSLATION_SPEC;
109718b89809SDavid Hildenbrand 		if (rtte.cr && asce.p && sg->edat_level >= 2)
109818b89809SDavid Hildenbrand 			return PGM_TRANSLATION_SPEC;
109918b89809SDavid Hildenbrand 		if (rtte.fc && sg->edat_level >= 2) {
11001c65781bSDavid Hildenbrand 			*dat_protection |= rtte.fc0.p;
110118b89809SDavid Hildenbrand 			*fake = 1;
110258cdf5ebSHeiko Carstens 			ptr = rtte.fc1.rfaa * _REGION3_SIZE;
110318b89809SDavid Hildenbrand 			rtte.val = ptr;
110418b89809SDavid Hildenbrand 			goto shadow_sgt;
110518b89809SDavid Hildenbrand 		}
1106aa17aa57SMartin Schwidefsky 		if (vaddr.sx01 < rtte.fc0.tf || vaddr.sx01 > rtte.fc0.tl)
1107aa17aa57SMartin Schwidefsky 			return PGM_SEGMENT_TRANSLATION;
11081c65781bSDavid Hildenbrand 		if (sg->edat_level >= 1)
11091c65781bSDavid Hildenbrand 			*dat_protection |= rtte.fc0.p;
111058cdf5ebSHeiko Carstens 		ptr = rtte.fc0.sto * PAGE_SIZE;
111118b89809SDavid Hildenbrand shadow_sgt:
11121c65781bSDavid Hildenbrand 		rtte.fc0.p |= *dat_protection;
111318b89809SDavid Hildenbrand 		rc = gmap_shadow_sgt(sg, saddr, rtte.val, *fake);
1114aa17aa57SMartin Schwidefsky 		if (rc)
1115aa17aa57SMartin Schwidefsky 			return rc;
1116aa17aa57SMartin Schwidefsky 		/* fallthrough */
1117aa17aa57SMartin Schwidefsky 	}
1118aa17aa57SMartin Schwidefsky 	case ASCE_TYPE_SEGMENT: {
1119aa17aa57SMartin Schwidefsky 		union segment_table_entry ste;
1120aa17aa57SMartin Schwidefsky 
112118b89809SDavid Hildenbrand 		if (*fake) {
112258cdf5ebSHeiko Carstens 			ptr += vaddr.sx * _SEGMENT_SIZE;
112318b89809SDavid Hildenbrand 			ste.val = ptr;
112418b89809SDavid Hildenbrand 			goto shadow_pgt;
112518b89809SDavid Hildenbrand 		}
1126aa17aa57SMartin Schwidefsky 		rc = gmap_read_table(parent, ptr + vaddr.sx * 8, &ste.val);
1127aa17aa57SMartin Schwidefsky 		if (rc)
1128aa17aa57SMartin Schwidefsky 			return rc;
1129aa17aa57SMartin Schwidefsky 		if (ste.i)
1130aa17aa57SMartin Schwidefsky 			return PGM_SEGMENT_TRANSLATION;
1131aa17aa57SMartin Schwidefsky 		if (ste.tt != TABLE_TYPE_SEGMENT)
1132aa17aa57SMartin Schwidefsky 			return PGM_TRANSLATION_SPEC;
1133aa17aa57SMartin Schwidefsky 		if (ste.cs && asce.p)
1134aa17aa57SMartin Schwidefsky 			return PGM_TRANSLATION_SPEC;
11351c65781bSDavid Hildenbrand 		*dat_protection |= ste.fc0.p;
1136fd8d4e3aSDavid Hildenbrand 		if (ste.fc && sg->edat_level >= 1) {
1137fd8d4e3aSDavid Hildenbrand 			*fake = 1;
113858cdf5ebSHeiko Carstens 			ptr = ste.fc1.sfaa * _SEGMENT_SIZE;
1139fd8d4e3aSDavid Hildenbrand 			ste.val = ptr;
1140fd8d4e3aSDavid Hildenbrand 			goto shadow_pgt;
1141fd8d4e3aSDavid Hildenbrand 		}
114258cdf5ebSHeiko Carstens 		ptr = ste.fc0.pto * (PAGE_SIZE / 2);
1143fd8d4e3aSDavid Hildenbrand shadow_pgt:
11441c65781bSDavid Hildenbrand 		ste.fc0.p |= *dat_protection;
1145fd8d4e3aSDavid Hildenbrand 		rc = gmap_shadow_pgt(sg, saddr, ste.val, *fake);
1146aa17aa57SMartin Schwidefsky 		if (rc)
1147aa17aa57SMartin Schwidefsky 			return rc;
1148aa17aa57SMartin Schwidefsky 	}
1149aa17aa57SMartin Schwidefsky 	}
1150aa17aa57SMartin Schwidefsky 	/* Return the parent address of the page table */
1151aa17aa57SMartin Schwidefsky 	*pgt = ptr;
1152aa17aa57SMartin Schwidefsky 	return 0;
1153aa17aa57SMartin Schwidefsky }
1154aa17aa57SMartin Schwidefsky 
1155aa17aa57SMartin Schwidefsky /**
1156aa17aa57SMartin Schwidefsky  * kvm_s390_shadow_fault - handle fault on a shadow page table
1157f4debb40SDavid Hildenbrand  * @vcpu: virtual cpu
1158aa17aa57SMartin Schwidefsky  * @sg: pointer to the shadow guest address space structure
1159aa17aa57SMartin Schwidefsky  * @saddr: faulting address in the shadow gmap
1160aa17aa57SMartin Schwidefsky  *
1161aa17aa57SMartin Schwidefsky  * Returns: - 0 if the shadow fault was successfully resolved
1162aa17aa57SMartin Schwidefsky  *	    - > 0 (pgm exception code) on exceptions while faulting
1163aa17aa57SMartin Schwidefsky  *	    - -EAGAIN if the caller can retry immediately
1164aa17aa57SMartin Schwidefsky  *	    - -EFAULT when accessing invalid guest addresses
1165aa17aa57SMartin Schwidefsky  *	    - -ENOMEM if out of memory
1166aa17aa57SMartin Schwidefsky  */
1167f4debb40SDavid Hildenbrand int kvm_s390_shadow_fault(struct kvm_vcpu *vcpu, struct gmap *sg,
1168f4debb40SDavid Hildenbrand 			  unsigned long saddr)
1169aa17aa57SMartin Schwidefsky {
1170aa17aa57SMartin Schwidefsky 	union vaddress vaddr;
1171aa17aa57SMartin Schwidefsky 	union page_table_entry pte;
1172aa17aa57SMartin Schwidefsky 	unsigned long pgt;
1173fd8d4e3aSDavid Hildenbrand 	int dat_protection, fake;
1174aa17aa57SMartin Schwidefsky 	int rc;
1175aa17aa57SMartin Schwidefsky 
1176e52f8b61SDavid Hildenbrand 	down_read(&sg->mm->mmap_sem);
1177f4debb40SDavid Hildenbrand 	/*
1178f4debb40SDavid Hildenbrand 	 * We don't want any guest-2 tables to change - so the parent
1179f4debb40SDavid Hildenbrand 	 * tables/pointers we read stay valid - unshadowing is however
1180f4debb40SDavid Hildenbrand 	 * always possible - only guest_table_lock protects us.
1181f4debb40SDavid Hildenbrand 	 */
1182f4debb40SDavid Hildenbrand 	ipte_lock(vcpu);
1183e52f8b61SDavid Hildenbrand 
1184fd8d4e3aSDavid Hildenbrand 	rc = gmap_shadow_pgt_lookup(sg, saddr, &pgt, &dat_protection, &fake);
1185aa17aa57SMartin Schwidefsky 	if (rc)
1186fd8d4e3aSDavid Hildenbrand 		rc = kvm_s390_shadow_tables(sg, saddr, &pgt, &dat_protection,
1187fd8d4e3aSDavid Hildenbrand 					    &fake);
1188aa17aa57SMartin Schwidefsky 
1189aa17aa57SMartin Schwidefsky 	vaddr.addr = saddr;
1190fd8d4e3aSDavid Hildenbrand 	if (fake) {
119158cdf5ebSHeiko Carstens 		pte.val = pgt + vaddr.px * PAGE_SIZE;
1192fd8d4e3aSDavid Hildenbrand 		goto shadow_page;
1193fd8d4e3aSDavid Hildenbrand 	}
1194e52f8b61SDavid Hildenbrand 	if (!rc)
1195aa17aa57SMartin Schwidefsky 		rc = gmap_read_table(sg->parent, pgt + vaddr.px * 8, &pte.val);
1196e52f8b61SDavid Hildenbrand 	if (!rc && pte.i)
1197e52f8b61SDavid Hildenbrand 		rc = PGM_PAGE_TRANSLATION;
1198232b8e3bSHeiko Carstens 	if (!rc && pte.z)
1199e52f8b61SDavid Hildenbrand 		rc = PGM_TRANSLATION_SPEC;
1200fd8d4e3aSDavid Hildenbrand shadow_page:
120100fc062dSDavid Hildenbrand 	pte.p |= dat_protection;
1202e52f8b61SDavid Hildenbrand 	if (!rc)
1203a9d23e71SDavid Hildenbrand 		rc = gmap_shadow_page(sg, saddr, __pte(pte.val));
1204f4debb40SDavid Hildenbrand 	ipte_unlock(vcpu);
1205e52f8b61SDavid Hildenbrand 	up_read(&sg->mm->mmap_sem);
1206aa17aa57SMartin Schwidefsky 	return rc;
1207aa17aa57SMartin Schwidefsky }
1208