xref: /openbmc/linux/arch/s390/kvm/priv.c (revision ee1cd5048959de496cd005c50b137212a5b62062)
1d809aa23SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2453423dcSChristian Borntraeger /*
3a53c8fabSHeiko Carstens  * handling privileged instructions
4453423dcSChristian Borntraeger  *
5353cbc6aSJanosch Frank  * Copyright IBM Corp. 2008, 2020
6453423dcSChristian Borntraeger  *
7453423dcSChristian Borntraeger  *    Author(s): Carsten Otte <cotte@de.ibm.com>
8453423dcSChristian Borntraeger  *               Christian Borntraeger <borntraeger@de.ibm.com>
9453423dcSChristian Borntraeger  */
10453423dcSChristian Borntraeger 
11453423dcSChristian Borntraeger #include <linux/kvm.h>
125a0e3ad6STejun Heo #include <linux/gfp.h>
13453423dcSChristian Borntraeger #include <linux/errno.h>
14589ee628SIngo Molnar #include <linux/mm_types.h>
1565fddcfcSMike Rapoport #include <linux/pgtable.h>
16b378a982SHeiko Carstens #include <linux/io.h>
177c959e82SHeiko Carstens #include <asm/asm-offsets.h>
18e769ece3SHeiko Carstens #include <asm/facility.h>
19453423dcSChristian Borntraeger #include <asm/current.h>
20453423dcSChristian Borntraeger #include <asm/debug.h>
21453423dcSChristian Borntraeger #include <asm/ebcdic.h>
22453423dcSChristian Borntraeger #include <asm/sysinfo.h>
23190df4a2SClaudio Imbrenda #include <asm/page-states.h>
241e133ab2SMartin Schwidefsky #include <asm/gmap.h>
2548a3e950SCornelia Huck #include <asm/ptrace.h>
26a7e19ab5SDavid Hildenbrand #include <asm/sclp.h>
27e5282de9SPierre Morel #include <asm/ap.h>
28453423dcSChristian Borntraeger #include "gaccess.h"
29453423dcSChristian Borntraeger #include "kvm-s390.h"
305786fffaSCornelia Huck #include "trace.h"
31453423dcSChristian Borntraeger 
handle_ri(struct kvm_vcpu * vcpu)3280cd8763SFan Zhang static int handle_ri(struct kvm_vcpu *vcpu)
3380cd8763SFan Zhang {
34a37cb07aSChristian Borntraeger 	vcpu->stat.instruction_ri++;
35a37cb07aSChristian Borntraeger 
3680cd8763SFan Zhang 	if (test_kvm_facility(vcpu->kvm, 64)) {
374d5f2c04SChristian Borntraeger 		VCPU_EVENT(vcpu, 3, "%s", "ENABLE: RI (lazy)");
380c9d8683SDavid Hildenbrand 		vcpu->arch.sie_block->ecb3 |= ECB3_RI;
3980cd8763SFan Zhang 		kvm_s390_retry_instr(vcpu);
4080cd8763SFan Zhang 		return 0;
4180cd8763SFan Zhang 	} else
4280cd8763SFan Zhang 		return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
4380cd8763SFan Zhang }
4480cd8763SFan Zhang 
kvm_s390_handle_aa(struct kvm_vcpu * vcpu)4580cd8763SFan Zhang int kvm_s390_handle_aa(struct kvm_vcpu *vcpu)
4680cd8763SFan Zhang {
4780cd8763SFan Zhang 	if ((vcpu->arch.sie_block->ipa & 0xf) <= 4)
4880cd8763SFan Zhang 		return handle_ri(vcpu);
4980cd8763SFan Zhang 	else
5080cd8763SFan Zhang 		return -EOPNOTSUPP;
5180cd8763SFan Zhang }
5280cd8763SFan Zhang 
handle_gs(struct kvm_vcpu * vcpu)534e0b1ab7SFan Zhang static int handle_gs(struct kvm_vcpu *vcpu)
544e0b1ab7SFan Zhang {
55a37cb07aSChristian Borntraeger 	vcpu->stat.instruction_gs++;
56a37cb07aSChristian Borntraeger 
574e0b1ab7SFan Zhang 	if (test_kvm_facility(vcpu->kvm, 133)) {
584e0b1ab7SFan Zhang 		VCPU_EVENT(vcpu, 3, "%s", "ENABLE: GS (lazy)");
594e0b1ab7SFan Zhang 		preempt_disable();
604e0b1ab7SFan Zhang 		__ctl_set_bit(2, 4);
614e0b1ab7SFan Zhang 		current->thread.gs_cb = (struct gs_cb *)&vcpu->run->s.regs.gscb;
624e0b1ab7SFan Zhang 		restore_gs_cb(current->thread.gs_cb);
634e0b1ab7SFan Zhang 		preempt_enable();
644e0b1ab7SFan Zhang 		vcpu->arch.sie_block->ecb |= ECB_GS;
654e0b1ab7SFan Zhang 		vcpu->arch.sie_block->ecd |= ECD_HOSTREGMGMT;
664e0b1ab7SFan Zhang 		vcpu->arch.gs_enabled = 1;
674e0b1ab7SFan Zhang 		kvm_s390_retry_instr(vcpu);
684e0b1ab7SFan Zhang 		return 0;
694e0b1ab7SFan Zhang 	} else
704e0b1ab7SFan Zhang 		return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
714e0b1ab7SFan Zhang }
724e0b1ab7SFan Zhang 
kvm_s390_handle_e3(struct kvm_vcpu * vcpu)734e0b1ab7SFan Zhang int kvm_s390_handle_e3(struct kvm_vcpu *vcpu)
744e0b1ab7SFan Zhang {
754e0b1ab7SFan Zhang 	int code = vcpu->arch.sie_block->ipb & 0xff;
764e0b1ab7SFan Zhang 
774e0b1ab7SFan Zhang 	if (code == 0x49 || code == 0x4d)
784e0b1ab7SFan Zhang 		return handle_gs(vcpu);
794e0b1ab7SFan Zhang 	else
804e0b1ab7SFan Zhang 		return -EOPNOTSUPP;
814e0b1ab7SFan Zhang }
826a3f95a6SThomas Huth /* Handle SCK (SET CLOCK) interception */
handle_set_clock(struct kvm_vcpu * vcpu)836a3f95a6SThomas Huth static int handle_set_clock(struct kvm_vcpu *vcpu)
846a3f95a6SThomas Huth {
850e7def5fSDavid Hildenbrand 	struct kvm_s390_vm_tod_clock gtod = { 0 };
8625ed1675SDavid Hildenbrand 	int rc;
8727f67f87SChristian Borntraeger 	u8 ar;
880e7def5fSDavid Hildenbrand 	u64 op2;
896a3f95a6SThomas Huth 
90a37cb07aSChristian Borntraeger 	vcpu->stat.instruction_sck++;
91a37cb07aSChristian Borntraeger 
926a3f95a6SThomas Huth 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
936a3f95a6SThomas Huth 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
946a3f95a6SThomas Huth 
958ae04b8fSAlexander Yarygin 	op2 = kvm_s390_get_base_disp_s(vcpu, &ar);
966a3f95a6SThomas Huth 	if (op2 & 7)	/* Operand must be on a doubleword boundary */
976a3f95a6SThomas Huth 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
980e7def5fSDavid Hildenbrand 	rc = read_guest(vcpu, op2, ar, &gtod.tod, sizeof(gtod.tod));
990e7a3f94SHeiko Carstens 	if (rc)
1000e7a3f94SHeiko Carstens 		return kvm_s390_inject_prog_cond(vcpu, rc);
1016a3f95a6SThomas Huth 
1020e7def5fSDavid Hildenbrand 	VCPU_EVENT(vcpu, 3, "SCK: setting guest TOD to 0x%llx", gtod.tod);
103c0573ba5SClaudio Imbrenda 	/*
104c0573ba5SClaudio Imbrenda 	 * To set the TOD clock the kvm lock must be taken, but the vcpu lock
105c0573ba5SClaudio Imbrenda 	 * is already held in handle_set_clock. The usual lock order is the
106c0573ba5SClaudio Imbrenda 	 * opposite.  As SCK is deprecated and should not be used in several
107c0573ba5SClaudio Imbrenda 	 * cases, for example when the multiple epoch facility or TOD clock
108c0573ba5SClaudio Imbrenda 	 * steering facility is installed (see Principles of Operation),  a
109c0573ba5SClaudio Imbrenda 	 * slow path can be used.  If the lock can not be taken via try_lock,
110c0573ba5SClaudio Imbrenda 	 * the instruction will be retried via -EAGAIN at a later point in
111c0573ba5SClaudio Imbrenda 	 * time.
112c0573ba5SClaudio Imbrenda 	 */
113c0573ba5SClaudio Imbrenda 	if (!kvm_s390_try_set_tod_clock(vcpu->kvm, &gtod)) {
114c0573ba5SClaudio Imbrenda 		kvm_s390_retry_instr(vcpu);
115c0573ba5SClaudio Imbrenda 		return -EAGAIN;
116c0573ba5SClaudio Imbrenda 	}
1176a3f95a6SThomas Huth 
1186a3f95a6SThomas Huth 	kvm_s390_set_psw_cc(vcpu, 0);
1196a3f95a6SThomas Huth 	return 0;
1206a3f95a6SThomas Huth }
1216a3f95a6SThomas Huth 
handle_set_prefix(struct kvm_vcpu * vcpu)122453423dcSChristian Borntraeger static int handle_set_prefix(struct kvm_vcpu *vcpu)
123453423dcSChristian Borntraeger {
124453423dcSChristian Borntraeger 	u64 operand2;
125665170cbSHeiko Carstens 	u32 address;
126665170cbSHeiko Carstens 	int rc;
12727f67f87SChristian Borntraeger 	u8 ar;
128453423dcSChristian Borntraeger 
129453423dcSChristian Borntraeger 	vcpu->stat.instruction_spx++;
130453423dcSChristian Borntraeger 
1315087dfa6SThomas Huth 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
1325087dfa6SThomas Huth 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
1335087dfa6SThomas Huth 
1348ae04b8fSAlexander Yarygin 	operand2 = kvm_s390_get_base_disp_s(vcpu, &ar);
135453423dcSChristian Borntraeger 
136453423dcSChristian Borntraeger 	/* must be word boundary */
137db4a29cbSHeiko Carstens 	if (operand2 & 3)
138db4a29cbSHeiko Carstens 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
139453423dcSChristian Borntraeger 
140453423dcSChristian Borntraeger 	/* get the value */
1418ae04b8fSAlexander Yarygin 	rc = read_guest(vcpu, operand2, ar, &address, sizeof(address));
142665170cbSHeiko Carstens 	if (rc)
143665170cbSHeiko Carstens 		return kvm_s390_inject_prog_cond(vcpu, rc);
144453423dcSChristian Borntraeger 
145665170cbSHeiko Carstens 	address &= 0x7fffe000u;
146453423dcSChristian Borntraeger 
147665170cbSHeiko Carstens 	/*
148665170cbSHeiko Carstens 	 * Make sure the new value is valid memory. We only need to check the
149665170cbSHeiko Carstens 	 * first page, since address is 8k aligned and memory pieces are always
150665170cbSHeiko Carstens 	 * at least 1MB aligned and have at least a size of 1MB.
151665170cbSHeiko Carstens 	 */
152665170cbSHeiko Carstens 	if (kvm_is_error_gpa(vcpu->kvm, address))
153db4a29cbSHeiko Carstens 		return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
154453423dcSChristian Borntraeger 
1558d26cf7bSChristian Borntraeger 	kvm_s390_set_prefix(vcpu, address);
1565786fffaSCornelia Huck 	trace_kvm_s390_handle_prefix(vcpu, 1, address);
157453423dcSChristian Borntraeger 	return 0;
158453423dcSChristian Borntraeger }
159453423dcSChristian Borntraeger 
handle_store_prefix(struct kvm_vcpu * vcpu)160453423dcSChristian Borntraeger static int handle_store_prefix(struct kvm_vcpu *vcpu)
161453423dcSChristian Borntraeger {
162453423dcSChristian Borntraeger 	u64 operand2;
163453423dcSChristian Borntraeger 	u32 address;
164f748f4a7SHeiko Carstens 	int rc;
16527f67f87SChristian Borntraeger 	u8 ar;
166453423dcSChristian Borntraeger 
167453423dcSChristian Borntraeger 	vcpu->stat.instruction_stpx++;
168b1c571a5SCornelia Huck 
1695087dfa6SThomas Huth 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
1705087dfa6SThomas Huth 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
1715087dfa6SThomas Huth 
1728ae04b8fSAlexander Yarygin 	operand2 = kvm_s390_get_base_disp_s(vcpu, &ar);
173453423dcSChristian Borntraeger 
174453423dcSChristian Borntraeger 	/* must be word boundary */
175db4a29cbSHeiko Carstens 	if (operand2 & 3)
176db4a29cbSHeiko Carstens 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
177453423dcSChristian Borntraeger 
178fda902cbSMichael Mueller 	address = kvm_s390_get_prefix(vcpu);
179453423dcSChristian Borntraeger 
180453423dcSChristian Borntraeger 	/* get the value */
1818ae04b8fSAlexander Yarygin 	rc = write_guest(vcpu, operand2, ar, &address, sizeof(address));
182f748f4a7SHeiko Carstens 	if (rc)
183f748f4a7SHeiko Carstens 		return kvm_s390_inject_prog_cond(vcpu, rc);
184453423dcSChristian Borntraeger 
1857cbde76bSChristian Borntraeger 	VCPU_EVENT(vcpu, 3, "STPX: storing prefix 0x%x into 0x%llx", address, operand2);
1865786fffaSCornelia Huck 	trace_kvm_s390_handle_prefix(vcpu, 0, address);
187453423dcSChristian Borntraeger 	return 0;
188453423dcSChristian Borntraeger }
189453423dcSChristian Borntraeger 
handle_store_cpu_address(struct kvm_vcpu * vcpu)190453423dcSChristian Borntraeger static int handle_store_cpu_address(struct kvm_vcpu *vcpu)
191453423dcSChristian Borntraeger {
1928b96de0eSHeiko Carstens 	u16 vcpu_id = vcpu->vcpu_id;
1938b96de0eSHeiko Carstens 	u64 ga;
1948b96de0eSHeiko Carstens 	int rc;
19527f67f87SChristian Borntraeger 	u8 ar;
196453423dcSChristian Borntraeger 
197453423dcSChristian Borntraeger 	vcpu->stat.instruction_stap++;
198b1c571a5SCornelia Huck 
1995087dfa6SThomas Huth 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
2005087dfa6SThomas Huth 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
2015087dfa6SThomas Huth 
2028ae04b8fSAlexander Yarygin 	ga = kvm_s390_get_base_disp_s(vcpu, &ar);
203453423dcSChristian Borntraeger 
2048b96de0eSHeiko Carstens 	if (ga & 1)
205db4a29cbSHeiko Carstens 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
206453423dcSChristian Borntraeger 
2078ae04b8fSAlexander Yarygin 	rc = write_guest(vcpu, ga, ar, &vcpu_id, sizeof(vcpu_id));
2088b96de0eSHeiko Carstens 	if (rc)
2098b96de0eSHeiko Carstens 		return kvm_s390_inject_prog_cond(vcpu, rc);
210453423dcSChristian Borntraeger 
2117cbde76bSChristian Borntraeger 	VCPU_EVENT(vcpu, 3, "STAP: storing cpu address (%u) to 0x%llx", vcpu_id, ga);
2128b96de0eSHeiko Carstens 	trace_kvm_s390_handle_stap(vcpu, ga);
213453423dcSChristian Borntraeger 	return 0;
214453423dcSChristian Borntraeger }
215453423dcSChristian Borntraeger 
kvm_s390_skey_check_enable(struct kvm_vcpu * vcpu)216730cd632SFarhan Ali int kvm_s390_skey_check_enable(struct kvm_vcpu *vcpu)
217693ffc08SDominik Dingel {
21855531b74SJanosch Frank 	int rc;
21911ddcd41SDavid Hildenbrand 
22011ddcd41SDavid Hildenbrand 	trace_kvm_s390_skey_related_inst(vcpu);
22155531b74SJanosch Frank 	/* Already enabled? */
22257cb198cSJanosch Frank 	if (vcpu->arch.skey_enabled)
22355531b74SJanosch Frank 		return 0;
224693ffc08SDominik Dingel 
2253ac8e380SDominik Dingel 	rc = s390_enable_skey();
22611ddcd41SDavid Hildenbrand 	VCPU_EVENT(vcpu, 3, "enabling storage keys for guest: %d", rc);
22755531b74SJanosch Frank 	if (rc)
22855531b74SJanosch Frank 		return rc;
22955531b74SJanosch Frank 
2308d5fb0dcSDavid Hildenbrand 	if (kvm_s390_test_cpuflags(vcpu, CPUSTAT_KSS))
2319daecfc6SDavid Hildenbrand 		kvm_s390_clear_cpuflags(vcpu, CPUSTAT_KSS);
23255531b74SJanosch Frank 	if (!vcpu->kvm->arch.use_skf)
23357cb198cSJanosch Frank 		vcpu->arch.sie_block->ictl |= ICTL_ISKE | ICTL_SSKE | ICTL_RRBE;
234730cd632SFarhan Ali 	else
23557cb198cSJanosch Frank 		vcpu->arch.sie_block->ictl &= ~(ICTL_ISKE | ICTL_SSKE | ICTL_RRBE);
23657cb198cSJanosch Frank 	vcpu->arch.skey_enabled = true;
23755531b74SJanosch Frank 	return 0;
238693ffc08SDominik Dingel }
239693ffc08SDominik Dingel 
try_handle_skey(struct kvm_vcpu * vcpu)240a7e19ab5SDavid Hildenbrand static int try_handle_skey(struct kvm_vcpu *vcpu)
241453423dcSChristian Borntraeger {
24211ddcd41SDavid Hildenbrand 	int rc;
243693ffc08SDominik Dingel 
244730cd632SFarhan Ali 	rc = kvm_s390_skey_check_enable(vcpu);
2453ac8e380SDominik Dingel 	if (rc)
2463ac8e380SDominik Dingel 		return rc;
24755531b74SJanosch Frank 	if (vcpu->kvm->arch.use_skf) {
248a7e19ab5SDavid Hildenbrand 		/* with storage-key facility, SIE interprets it for us */
2490e8bc06aSDavid Hildenbrand 		kvm_s390_retry_instr(vcpu);
250453423dcSChristian Borntraeger 		VCPU_EVENT(vcpu, 4, "%s", "retrying storage key operation");
251a7e19ab5SDavid Hildenbrand 		return -EAGAIN;
252a7e19ab5SDavid Hildenbrand 	}
253a7e19ab5SDavid Hildenbrand 	return 0;
254a7e19ab5SDavid Hildenbrand }
255a7e19ab5SDavid Hildenbrand 
handle_iske(struct kvm_vcpu * vcpu)256a7e19ab5SDavid Hildenbrand static int handle_iske(struct kvm_vcpu *vcpu)
257a7e19ab5SDavid Hildenbrand {
258bd096f64SJanosch Frank 	unsigned long gaddr, vmaddr;
259a7e19ab5SDavid Hildenbrand 	unsigned char key;
260a7e19ab5SDavid Hildenbrand 	int reg1, reg2;
261bd096f64SJanosch Frank 	bool unlocked;
262a7e19ab5SDavid Hildenbrand 	int rc;
263a7e19ab5SDavid Hildenbrand 
264a37cb07aSChristian Borntraeger 	vcpu->stat.instruction_iske++;
265a37cb07aSChristian Borntraeger 
266ca76ec9cSJanosch Frank 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
267ca76ec9cSJanosch Frank 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
268ca76ec9cSJanosch Frank 
269a7e19ab5SDavid Hildenbrand 	rc = try_handle_skey(vcpu);
270a7e19ab5SDavid Hildenbrand 	if (rc)
271a7e19ab5SDavid Hildenbrand 		return rc != -EAGAIN ? rc : 0;
272a7e19ab5SDavid Hildenbrand 
273a7e19ab5SDavid Hildenbrand 	kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
274a7e19ab5SDavid Hildenbrand 
275bd096f64SJanosch Frank 	gaddr = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK;
276bd096f64SJanosch Frank 	gaddr = kvm_s390_logical_to_effective(vcpu, gaddr);
277bd096f64SJanosch Frank 	gaddr = kvm_s390_real_to_abs(vcpu, gaddr);
278bd096f64SJanosch Frank 	vmaddr = gfn_to_hva(vcpu->kvm, gpa_to_gfn(gaddr));
279bd096f64SJanosch Frank 	if (kvm_is_error_hva(vmaddr))
280a7e19ab5SDavid Hildenbrand 		return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
281bd096f64SJanosch Frank retry:
282bd096f64SJanosch Frank 	unlocked = false;
283d8ed45c5SMichel Lespinasse 	mmap_read_lock(current->mm);
284bd096f64SJanosch Frank 	rc = get_guest_storage_key(current->mm, vmaddr, &key);
285bd096f64SJanosch Frank 
286bd096f64SJanosch Frank 	if (rc) {
28764019a2eSPeter Xu 		rc = fixup_user_fault(current->mm, vmaddr,
288bd096f64SJanosch Frank 				      FAULT_FLAG_WRITE, &unlocked);
289bd096f64SJanosch Frank 		if (!rc) {
290d8ed45c5SMichel Lespinasse 			mmap_read_unlock(current->mm);
291bd096f64SJanosch Frank 			goto retry;
292bd096f64SJanosch Frank 		}
293bd096f64SJanosch Frank 	}
294d8ed45c5SMichel Lespinasse 	mmap_read_unlock(current->mm);
295a11bdb1aSJanosch Frank 	if (rc == -EFAULT)
296a11bdb1aSJanosch Frank 		return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
297a11bdb1aSJanosch Frank 	if (rc < 0)
298a11bdb1aSJanosch Frank 		return rc;
299a7e19ab5SDavid Hildenbrand 	vcpu->run->s.regs.gprs[reg1] &= ~0xff;
300a7e19ab5SDavid Hildenbrand 	vcpu->run->s.regs.gprs[reg1] |= key;
301a7e19ab5SDavid Hildenbrand 	return 0;
302a7e19ab5SDavid Hildenbrand }
303a7e19ab5SDavid Hildenbrand 
handle_rrbe(struct kvm_vcpu * vcpu)304a7e19ab5SDavid Hildenbrand static int handle_rrbe(struct kvm_vcpu *vcpu)
305a7e19ab5SDavid Hildenbrand {
306bd096f64SJanosch Frank 	unsigned long vmaddr, gaddr;
307a7e19ab5SDavid Hildenbrand 	int reg1, reg2;
308bd096f64SJanosch Frank 	bool unlocked;
309a7e19ab5SDavid Hildenbrand 	int rc;
310a7e19ab5SDavid Hildenbrand 
311a37cb07aSChristian Borntraeger 	vcpu->stat.instruction_rrbe++;
312a37cb07aSChristian Borntraeger 
313ca76ec9cSJanosch Frank 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
314ca76ec9cSJanosch Frank 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
315ca76ec9cSJanosch Frank 
316a7e19ab5SDavid Hildenbrand 	rc = try_handle_skey(vcpu);
317a7e19ab5SDavid Hildenbrand 	if (rc)
318a7e19ab5SDavid Hildenbrand 		return rc != -EAGAIN ? rc : 0;
319a7e19ab5SDavid Hildenbrand 
320a7e19ab5SDavid Hildenbrand 	kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
321a7e19ab5SDavid Hildenbrand 
322bd096f64SJanosch Frank 	gaddr = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK;
323bd096f64SJanosch Frank 	gaddr = kvm_s390_logical_to_effective(vcpu, gaddr);
324bd096f64SJanosch Frank 	gaddr = kvm_s390_real_to_abs(vcpu, gaddr);
325bd096f64SJanosch Frank 	vmaddr = gfn_to_hva(vcpu->kvm, gpa_to_gfn(gaddr));
326bd096f64SJanosch Frank 	if (kvm_is_error_hva(vmaddr))
327a7e19ab5SDavid Hildenbrand 		return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
328bd096f64SJanosch Frank retry:
329bd096f64SJanosch Frank 	unlocked = false;
330d8ed45c5SMichel Lespinasse 	mmap_read_lock(current->mm);
331bd096f64SJanosch Frank 	rc = reset_guest_reference_bit(current->mm, vmaddr);
332bd096f64SJanosch Frank 	if (rc < 0) {
33364019a2eSPeter Xu 		rc = fixup_user_fault(current->mm, vmaddr,
334bd096f64SJanosch Frank 				      FAULT_FLAG_WRITE, &unlocked);
335bd096f64SJanosch Frank 		if (!rc) {
336d8ed45c5SMichel Lespinasse 			mmap_read_unlock(current->mm);
337bd096f64SJanosch Frank 			goto retry;
338bd096f64SJanosch Frank 		}
339bd096f64SJanosch Frank 	}
340d8ed45c5SMichel Lespinasse 	mmap_read_unlock(current->mm);
341a11bdb1aSJanosch Frank 	if (rc == -EFAULT)
342a11bdb1aSJanosch Frank 		return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
343a11bdb1aSJanosch Frank 	if (rc < 0)
344a11bdb1aSJanosch Frank 		return rc;
345a7e19ab5SDavid Hildenbrand 	kvm_s390_set_psw_cc(vcpu, rc);
346a7e19ab5SDavid Hildenbrand 	return 0;
347a7e19ab5SDavid Hildenbrand }
348a7e19ab5SDavid Hildenbrand 
349a7e19ab5SDavid Hildenbrand #define SSKE_NQ 0x8
350a7e19ab5SDavid Hildenbrand #define SSKE_MR 0x4
351a7e19ab5SDavid Hildenbrand #define SSKE_MC 0x2
352a7e19ab5SDavid Hildenbrand #define SSKE_MB 0x1
handle_sske(struct kvm_vcpu * vcpu)353a7e19ab5SDavid Hildenbrand static int handle_sske(struct kvm_vcpu *vcpu)
354a7e19ab5SDavid Hildenbrand {
355a7e19ab5SDavid Hildenbrand 	unsigned char m3 = vcpu->arch.sie_block->ipb >> 28;
356a7e19ab5SDavid Hildenbrand 	unsigned long start, end;
357a7e19ab5SDavid Hildenbrand 	unsigned char key, oldkey;
358a7e19ab5SDavid Hildenbrand 	int reg1, reg2;
359bd096f64SJanosch Frank 	bool unlocked;
360a7e19ab5SDavid Hildenbrand 	int rc;
361a7e19ab5SDavid Hildenbrand 
362a37cb07aSChristian Borntraeger 	vcpu->stat.instruction_sske++;
363a37cb07aSChristian Borntraeger 
364ca76ec9cSJanosch Frank 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
365ca76ec9cSJanosch Frank 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
366ca76ec9cSJanosch Frank 
367a7e19ab5SDavid Hildenbrand 	rc = try_handle_skey(vcpu);
368a7e19ab5SDavid Hildenbrand 	if (rc)
369a7e19ab5SDavid Hildenbrand 		return rc != -EAGAIN ? rc : 0;
370a7e19ab5SDavid Hildenbrand 
371a7e19ab5SDavid Hildenbrand 	if (!test_kvm_facility(vcpu->kvm, 8))
372a7e19ab5SDavid Hildenbrand 		m3 &= ~SSKE_MB;
373a7e19ab5SDavid Hildenbrand 	if (!test_kvm_facility(vcpu->kvm, 10))
374a7e19ab5SDavid Hildenbrand 		m3 &= ~(SSKE_MC | SSKE_MR);
375a7e19ab5SDavid Hildenbrand 	if (!test_kvm_facility(vcpu->kvm, 14))
376a7e19ab5SDavid Hildenbrand 		m3 &= ~SSKE_NQ;
377a7e19ab5SDavid Hildenbrand 
378a7e19ab5SDavid Hildenbrand 	kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
379a7e19ab5SDavid Hildenbrand 
380a7e19ab5SDavid Hildenbrand 	key = vcpu->run->s.regs.gprs[reg1] & 0xfe;
381a7e19ab5SDavid Hildenbrand 	start = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK;
382a7e19ab5SDavid Hildenbrand 	start = kvm_s390_logical_to_effective(vcpu, start);
383a7e19ab5SDavid Hildenbrand 	if (m3 & SSKE_MB) {
384a7e19ab5SDavid Hildenbrand 		/* start already designates an absolute address */
38558cdf5ebSHeiko Carstens 		end = (start + _SEGMENT_SIZE) & ~(_SEGMENT_SIZE - 1);
386a7e19ab5SDavid Hildenbrand 	} else {
387a7e19ab5SDavid Hildenbrand 		start = kvm_s390_real_to_abs(vcpu, start);
388a7e19ab5SDavid Hildenbrand 		end = start + PAGE_SIZE;
389a7e19ab5SDavid Hildenbrand 	}
390a7e19ab5SDavid Hildenbrand 
391a7e19ab5SDavid Hildenbrand 	while (start != end) {
392bd096f64SJanosch Frank 		unsigned long vmaddr = gfn_to_hva(vcpu->kvm, gpa_to_gfn(start));
393bd096f64SJanosch Frank 		unlocked = false;
394a7e19ab5SDavid Hildenbrand 
395bd096f64SJanosch Frank 		if (kvm_is_error_hva(vmaddr))
396a7e19ab5SDavid Hildenbrand 			return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
397a7e19ab5SDavid Hildenbrand 
398d8ed45c5SMichel Lespinasse 		mmap_read_lock(current->mm);
399bd096f64SJanosch Frank 		rc = cond_set_guest_storage_key(current->mm, vmaddr, key, &oldkey,
400a7e19ab5SDavid Hildenbrand 						m3 & SSKE_NQ, m3 & SSKE_MR,
401a7e19ab5SDavid Hildenbrand 						m3 & SSKE_MC);
402bd096f64SJanosch Frank 
403bd096f64SJanosch Frank 		if (rc < 0) {
40464019a2eSPeter Xu 			rc = fixup_user_fault(current->mm, vmaddr,
405bd096f64SJanosch Frank 					      FAULT_FLAG_WRITE, &unlocked);
406bd096f64SJanosch Frank 			rc = !rc ? -EAGAIN : rc;
407bd096f64SJanosch Frank 		}
408d8ed45c5SMichel Lespinasse 		mmap_read_unlock(current->mm);
409bd096f64SJanosch Frank 		if (rc == -EFAULT)
410a7e19ab5SDavid Hildenbrand 			return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
41185f517b2SJanis Schoetterl-Glausch 		if (rc == -EAGAIN)
41285f517b2SJanis Schoetterl-Glausch 			continue;
413a11bdb1aSJanosch Frank 		if (rc < 0)
414a11bdb1aSJanosch Frank 			return rc;
415a7e19ab5SDavid Hildenbrand 		start += PAGE_SIZE;
4160b925159SHeiko Carstens 	}
417a7e19ab5SDavid Hildenbrand 
418a7e19ab5SDavid Hildenbrand 	if (m3 & (SSKE_MC | SSKE_MR)) {
419a7e19ab5SDavid Hildenbrand 		if (m3 & SSKE_MB) {
420a7e19ab5SDavid Hildenbrand 			/* skey in reg1 is unpredictable */
421a7e19ab5SDavid Hildenbrand 			kvm_s390_set_psw_cc(vcpu, 3);
422a7e19ab5SDavid Hildenbrand 		} else {
423a7e19ab5SDavid Hildenbrand 			kvm_s390_set_psw_cc(vcpu, rc);
424a7e19ab5SDavid Hildenbrand 			vcpu->run->s.regs.gprs[reg1] &= ~0xff00UL;
425a7e19ab5SDavid Hildenbrand 			vcpu->run->s.regs.gprs[reg1] |= (u64) oldkey << 8;
426a7e19ab5SDavid Hildenbrand 		}
427a7e19ab5SDavid Hildenbrand 	}
428a7e19ab5SDavid Hildenbrand 	if (m3 & SSKE_MB) {
4298bb3fdd6SHeiko Carstens 		if (psw_bits(vcpu->arch.sie_block->gpsw).eaba == PSW_BITS_AMODE_64BIT)
430a7e19ab5SDavid Hildenbrand 			vcpu->run->s.regs.gprs[reg2] &= ~PAGE_MASK;
431a7e19ab5SDavid Hildenbrand 		else
432a7e19ab5SDavid Hildenbrand 			vcpu->run->s.regs.gprs[reg2] &= ~0xfffff000UL;
433a7e19ab5SDavid Hildenbrand 		end = kvm_s390_logical_to_effective(vcpu, end);
434a7e19ab5SDavid Hildenbrand 		vcpu->run->s.regs.gprs[reg2] |= end;
435a7e19ab5SDavid Hildenbrand 	}
436453423dcSChristian Borntraeger 	return 0;
437453423dcSChristian Borntraeger }
438453423dcSChristian Borntraeger 
handle_ipte_interlock(struct kvm_vcpu * vcpu)4398a242234SHeiko Carstens static int handle_ipte_interlock(struct kvm_vcpu *vcpu)
4408a242234SHeiko Carstens {
4418a242234SHeiko Carstens 	vcpu->stat.instruction_ipte_interlock++;
442a7525982SHeiko Carstens 	if (psw_bits(vcpu->arch.sie_block->gpsw).pstate)
4438a242234SHeiko Carstens 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
4440130337eSPierre Morel 	wait_event(vcpu->kvm->arch.ipte_wq, !ipte_lock_held(vcpu->kvm));
4450e8bc06aSDavid Hildenbrand 	kvm_s390_retry_instr(vcpu);
4468a242234SHeiko Carstens 	VCPU_EVENT(vcpu, 4, "%s", "retrying ipte interlock operation");
4478a242234SHeiko Carstens 	return 0;
4488a242234SHeiko Carstens }
4498a242234SHeiko Carstens 
handle_test_block(struct kvm_vcpu * vcpu)450aca84241SThomas Huth static int handle_test_block(struct kvm_vcpu *vcpu)
451aca84241SThomas Huth {
452aca84241SThomas Huth 	gpa_t addr;
453aca84241SThomas Huth 	int reg2;
454aca84241SThomas Huth 
455a37cb07aSChristian Borntraeger 	vcpu->stat.instruction_tb++;
456a37cb07aSChristian Borntraeger 
457aca84241SThomas Huth 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
458aca84241SThomas Huth 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
459aca84241SThomas Huth 
460aca84241SThomas Huth 	kvm_s390_get_regs_rre(vcpu, NULL, &reg2);
461aca84241SThomas Huth 	addr = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK;
462e45efa28SThomas Huth 	addr = kvm_s390_logical_to_effective(vcpu, addr);
463dd9e5b7bSAlexander Yarygin 	if (kvm_s390_check_low_addr_prot_real(vcpu, addr))
464e45efa28SThomas Huth 		return kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm);
465aca84241SThomas Huth 	addr = kvm_s390_real_to_abs(vcpu, addr);
466aca84241SThomas Huth 
467ef23e779SHeiko Carstens 	if (kvm_is_error_gpa(vcpu->kvm, addr))
468aca84241SThomas Huth 		return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
469aca84241SThomas Huth 	/*
470aca84241SThomas Huth 	 * We don't expect errors on modern systems, and do not care
471aca84241SThomas Huth 	 * about storage keys (yet), so let's just clear the page.
472aca84241SThomas Huth 	 */
473ef23e779SHeiko Carstens 	if (kvm_clear_guest(vcpu->kvm, addr, PAGE_SIZE))
474aca84241SThomas Huth 		return -EFAULT;
475aca84241SThomas Huth 	kvm_s390_set_psw_cc(vcpu, 0);
476aca84241SThomas Huth 	vcpu->run->s.regs.gprs[0] = 0;
477aca84241SThomas Huth 	return 0;
478aca84241SThomas Huth }
479aca84241SThomas Huth 
handle_tpi(struct kvm_vcpu * vcpu)480fa6b7fe9SCornelia Huck static int handle_tpi(struct kvm_vcpu *vcpu)
481fa6b7fe9SCornelia Huck {
482fa6b7fe9SCornelia Huck 	struct kvm_s390_interrupt_info *inti;
4834799b557SHeiko Carstens 	unsigned long len;
4844799b557SHeiko Carstens 	u32 tpi_data[3];
485261520dcSDavid Hildenbrand 	int rc;
4867c959e82SHeiko Carstens 	u64 addr;
48727f67f87SChristian Borntraeger 	u8 ar;
488fa6b7fe9SCornelia Huck 
489a37cb07aSChristian Borntraeger 	vcpu->stat.instruction_tpi++;
490a37cb07aSChristian Borntraeger 
4918ae04b8fSAlexander Yarygin 	addr = kvm_s390_get_base_disp_s(vcpu, &ar);
492db4a29cbSHeiko Carstens 	if (addr & 3)
493db4a29cbSHeiko Carstens 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
494261520dcSDavid Hildenbrand 
495f092669eSThomas Huth 	inti = kvm_s390_get_io_int(vcpu->kvm, vcpu->arch.sie_block->gcr[6], 0);
496261520dcSDavid Hildenbrand 	if (!inti) {
497261520dcSDavid Hildenbrand 		kvm_s390_set_psw_cc(vcpu, 0);
498261520dcSDavid Hildenbrand 		return 0;
499261520dcSDavid Hildenbrand 	}
500261520dcSDavid Hildenbrand 
5014799b557SHeiko Carstens 	tpi_data[0] = inti->io.subchannel_id << 16 | inti->io.subchannel_nr;
5024799b557SHeiko Carstens 	tpi_data[1] = inti->io.io_int_parm;
5034799b557SHeiko Carstens 	tpi_data[2] = inti->io.io_int_word;
504fa6b7fe9SCornelia Huck 	if (addr) {
505fa6b7fe9SCornelia Huck 		/*
506fa6b7fe9SCornelia Huck 		 * Store the two-word I/O interruption code into the
507fa6b7fe9SCornelia Huck 		 * provided area.
508fa6b7fe9SCornelia Huck 		 */
5094799b557SHeiko Carstens 		len = sizeof(tpi_data) - 4;
5108ae04b8fSAlexander Yarygin 		rc = write_guest(vcpu, addr, ar, &tpi_data, len);
511261520dcSDavid Hildenbrand 		if (rc) {
512261520dcSDavid Hildenbrand 			rc = kvm_s390_inject_prog_cond(vcpu, rc);
513261520dcSDavid Hildenbrand 			goto reinject_interrupt;
514261520dcSDavid Hildenbrand 		}
515fa6b7fe9SCornelia Huck 	} else {
516fa6b7fe9SCornelia Huck 		/*
517fa6b7fe9SCornelia Huck 		 * Store the three-word I/O interruption code into
518fa6b7fe9SCornelia Huck 		 * the appropriate lowcore area.
519fa6b7fe9SCornelia Huck 		 */
5204799b557SHeiko Carstens 		len = sizeof(tpi_data);
521261520dcSDavid Hildenbrand 		if (write_guest_lc(vcpu, __LC_SUBCHANNEL_ID, &tpi_data, len)) {
522261520dcSDavid Hildenbrand 			/* failed writes to the low core are not recoverable */
5234799b557SHeiko Carstens 			rc = -EFAULT;
524261520dcSDavid Hildenbrand 			goto reinject_interrupt;
525fa6b7fe9SCornelia Huck 		}
526261520dcSDavid Hildenbrand 	}
527261520dcSDavid Hildenbrand 
528261520dcSDavid Hildenbrand 	/* irq was successfully handed to the guest */
529261520dcSDavid Hildenbrand 	kfree(inti);
530261520dcSDavid Hildenbrand 	kvm_s390_set_psw_cc(vcpu, 1);
531261520dcSDavid Hildenbrand 	return 0;
532261520dcSDavid Hildenbrand reinject_interrupt:
5332f32d4eaSCornelia Huck 	/*
5342f32d4eaSCornelia Huck 	 * If we encounter a problem storing the interruption code, the
5352f32d4eaSCornelia Huck 	 * instruction is suppressed from the guest's view: reinject the
5362f32d4eaSCornelia Huck 	 * interrupt.
5372f32d4eaSCornelia Huck 	 */
53815462e37SDavid Hildenbrand 	if (kvm_s390_reinject_io_int(vcpu->kvm, inti)) {
53915462e37SDavid Hildenbrand 		kfree(inti);
54015462e37SDavid Hildenbrand 		rc = -EFAULT;
54115462e37SDavid Hildenbrand 	}
542261520dcSDavid Hildenbrand 	/* don't set the cc, a pgm irq was injected or we drop to user space */
5434799b557SHeiko Carstens 	return rc ? -EFAULT : 0;
544fa6b7fe9SCornelia Huck }
545fa6b7fe9SCornelia Huck 
handle_tsch(struct kvm_vcpu * vcpu)546fa6b7fe9SCornelia Huck static int handle_tsch(struct kvm_vcpu *vcpu)
547fa6b7fe9SCornelia Huck {
5486d3da241SJens Freimann 	struct kvm_s390_interrupt_info *inti = NULL;
5496d3da241SJens Freimann 	const u64 isc_mask = 0xffUL << 24; /* all iscs set */
550fa6b7fe9SCornelia Huck 
551a37cb07aSChristian Borntraeger 	vcpu->stat.instruction_tsch++;
552a37cb07aSChristian Borntraeger 
5536d3da241SJens Freimann 	/* a valid schid has at least one bit set */
5546d3da241SJens Freimann 	if (vcpu->run->s.regs.gprs[1])
5556d3da241SJens Freimann 		inti = kvm_s390_get_io_int(vcpu->kvm, isc_mask,
556fa6b7fe9SCornelia Huck 					   vcpu->run->s.regs.gprs[1]);
557fa6b7fe9SCornelia Huck 
558fa6b7fe9SCornelia Huck 	/*
559fa6b7fe9SCornelia Huck 	 * Prepare exit to userspace.
560fa6b7fe9SCornelia Huck 	 * We indicate whether we dequeued a pending I/O interrupt
561fa6b7fe9SCornelia Huck 	 * so that userspace can re-inject it if the instruction gets
562fa6b7fe9SCornelia Huck 	 * a program check. While this may re-order the pending I/O
563fa6b7fe9SCornelia Huck 	 * interrupts, this is no problem since the priority is kept
564fa6b7fe9SCornelia Huck 	 * intact.
565fa6b7fe9SCornelia Huck 	 */
566fa6b7fe9SCornelia Huck 	vcpu->run->exit_reason = KVM_EXIT_S390_TSCH;
567fa6b7fe9SCornelia Huck 	vcpu->run->s390_tsch.dequeued = !!inti;
568fa6b7fe9SCornelia Huck 	if (inti) {
569fa6b7fe9SCornelia Huck 		vcpu->run->s390_tsch.subchannel_id = inti->io.subchannel_id;
570fa6b7fe9SCornelia Huck 		vcpu->run->s390_tsch.subchannel_nr = inti->io.subchannel_nr;
571fa6b7fe9SCornelia Huck 		vcpu->run->s390_tsch.io_int_parm = inti->io.io_int_parm;
572fa6b7fe9SCornelia Huck 		vcpu->run->s390_tsch.io_int_word = inti->io.io_int_word;
573fa6b7fe9SCornelia Huck 	}
574fa6b7fe9SCornelia Huck 	vcpu->run->s390_tsch.ipb = vcpu->arch.sie_block->ipb;
575fa6b7fe9SCornelia Huck 	kfree(inti);
576fa6b7fe9SCornelia Huck 	return -EREMOTE;
577fa6b7fe9SCornelia Huck }
578fa6b7fe9SCornelia Huck 
handle_io_inst(struct kvm_vcpu * vcpu)579f379aae5SCornelia Huck static int handle_io_inst(struct kvm_vcpu *vcpu)
580453423dcSChristian Borntraeger {
581f379aae5SCornelia Huck 	VCPU_EVENT(vcpu, 4, "%s", "I/O instruction");
582fa6b7fe9SCornelia Huck 
5835087dfa6SThomas Huth 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
5845087dfa6SThomas Huth 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
5855087dfa6SThomas Huth 
586fa6b7fe9SCornelia Huck 	if (vcpu->kvm->arch.css_support) {
587fa6b7fe9SCornelia Huck 		/*
588fa6b7fe9SCornelia Huck 		 * Most I/O instructions will be handled by userspace.
589fa6b7fe9SCornelia Huck 		 * Exceptions are tpi and the interrupt portion of tsch.
590fa6b7fe9SCornelia Huck 		 */
591fa6b7fe9SCornelia Huck 		if (vcpu->arch.sie_block->ipa == 0xb236)
592fa6b7fe9SCornelia Huck 			return handle_tpi(vcpu);
593fa6b7fe9SCornelia Huck 		if (vcpu->arch.sie_block->ipa == 0xb235)
594fa6b7fe9SCornelia Huck 			return handle_tsch(vcpu);
595fa6b7fe9SCornelia Huck 		/* Handle in userspace. */
596a37cb07aSChristian Borntraeger 		vcpu->stat.instruction_io_other++;
597fa6b7fe9SCornelia Huck 		return -EOPNOTSUPP;
598fa6b7fe9SCornelia Huck 	} else {
599fa6b7fe9SCornelia Huck 		/*
600b4a96015SHendrik Brueckner 		 * Set condition code 3 to stop the guest from issuing channel
601fa6b7fe9SCornelia Huck 		 * I/O instructions.
602fa6b7fe9SCornelia Huck 		 */
603ea828ebfSThomas Huth 		kvm_s390_set_psw_cc(vcpu, 3);
604453423dcSChristian Borntraeger 		return 0;
605453423dcSChristian Borntraeger 	}
606fa6b7fe9SCornelia Huck }
607453423dcSChristian Borntraeger 
608e5282de9SPierre Morel /*
609e5282de9SPierre Morel  * handle_pqap: Handling pqap interception
610e5282de9SPierre Morel  * @vcpu: the vcpu having issue the pqap instruction
611e5282de9SPierre Morel  *
612e5282de9SPierre Morel  * We now support PQAP/AQIC instructions and we need to correctly
613e5282de9SPierre Morel  * answer the guest even if no dedicated driver's hook is available.
614e5282de9SPierre Morel  *
615e5282de9SPierre Morel  * The intercepting code calls a dedicated callback for this instruction
616e5282de9SPierre Morel  * if a driver did register one in the CRYPTO satellite of the
617e5282de9SPierre Morel  * SIE block.
618e5282de9SPierre Morel  *
619e5282de9SPierre Morel  * If no callback is available, the queues are not available, return this
620e5282de9SPierre Morel  * response code to the caller and set CC to 3.
621e5282de9SPierre Morel  * Else return the response code returned by the callback.
622e5282de9SPierre Morel  */
handle_pqap(struct kvm_vcpu * vcpu)623e5282de9SPierre Morel static int handle_pqap(struct kvm_vcpu *vcpu)
624e5282de9SPierre Morel {
625e5282de9SPierre Morel 	struct ap_queue_status status = {};
6261e753732STony Krowiak 	crypto_hook pqap_hook;
627e5282de9SPierre Morel 	unsigned long reg0;
628e5282de9SPierre Morel 	int ret;
629e5282de9SPierre Morel 	uint8_t fc;
630e5282de9SPierre Morel 
631e5282de9SPierre Morel 	/* Verify that the AP instruction are available */
632e5282de9SPierre Morel 	if (!ap_instructions_available())
633e5282de9SPierre Morel 		return -EOPNOTSUPP;
634e5282de9SPierre Morel 	/* Verify that the guest is allowed to use AP instructions */
635e5282de9SPierre Morel 	if (!(vcpu->arch.sie_block->eca & ECA_APIE))
636e5282de9SPierre Morel 		return -EOPNOTSUPP;
637e5282de9SPierre Morel 	/*
638e5282de9SPierre Morel 	 * The only possibly intercepted functions when AP instructions are
639e5282de9SPierre Morel 	 * available for the guest are AQIC and TAPQ with the t bit set
640e5282de9SPierre Morel 	 * since we do not set IC.3 (FIII) we currently will only intercept
641e5282de9SPierre Morel 	 * the AQIC function code.
6425615e74fSChristian Borntraeger 	 * Note: running nested under z/VM can result in intercepts for other
6435615e74fSChristian Borntraeger 	 * function codes, e.g. PQAP(QCI). We do not support this and bail out.
644e5282de9SPierre Morel 	 */
645e5282de9SPierre Morel 	reg0 = vcpu->run->s.regs.gprs[0];
646e5282de9SPierre Morel 	fc = (reg0 >> 24) & 0xff;
6475615e74fSChristian Borntraeger 	if (fc != 0x03)
648e5282de9SPierre Morel 		return -EOPNOTSUPP;
649e5282de9SPierre Morel 
650e5282de9SPierre Morel 	/* PQAP instruction is allowed for guest kernel only */
651e5282de9SPierre Morel 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
652e5282de9SPierre Morel 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
653e5282de9SPierre Morel 
654e5282de9SPierre Morel 	/* Common PQAP instruction specification exceptions */
655e5282de9SPierre Morel 	/* bits 41-47 must all be zeros */
656e5282de9SPierre Morel 	if (reg0 & 0x007f0000UL)
657e5282de9SPierre Morel 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
658e5282de9SPierre Morel 	/* APFT not install and T bit set */
659e5282de9SPierre Morel 	if (!test_kvm_facility(vcpu->kvm, 15) && (reg0 & 0x00800000UL))
660e5282de9SPierre Morel 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
661e5282de9SPierre Morel 	/* APXA not installed and APID greater 64 or APQI greater 16 */
662e5282de9SPierre Morel 	if (!(vcpu->kvm->arch.crypto.crycbd & 0x02) && (reg0 & 0x0000c0f0UL))
663e5282de9SPierre Morel 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
664e5282de9SPierre Morel 
665e5282de9SPierre Morel 	/* AQIC function code specific exception */
666e5282de9SPierre Morel 	/* facility 65 not present for AQIC function code */
667e5282de9SPierre Morel 	if (!test_kvm_facility(vcpu->kvm, 65))
668e5282de9SPierre Morel 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
669e5282de9SPierre Morel 
670e5282de9SPierre Morel 	/*
6711e753732STony Krowiak 	 * If the hook callback is registered, there will be a pointer to the
6721e753732STony Krowiak 	 * hook function pointer in the kvm_s390_crypto structure. Lock the
6731e753732STony Krowiak 	 * owner, retrieve the hook function pointer and call the hook.
674e5282de9SPierre Morel 	 */
6751e753732STony Krowiak 	down_read(&vcpu->kvm->arch.crypto.pqap_hook_rwsem);
676e5282de9SPierre Morel 	if (vcpu->kvm->arch.crypto.pqap_hook) {
6771e753732STony Krowiak 		pqap_hook = *vcpu->kvm->arch.crypto.pqap_hook;
6781e753732STony Krowiak 		ret = pqap_hook(vcpu);
679e5282de9SPierre Morel 		if (!ret && vcpu->run->s.regs.gprs[1] & 0x00ff0000)
680e5282de9SPierre Morel 			kvm_s390_set_psw_cc(vcpu, 3);
6811e753732STony Krowiak 		up_read(&vcpu->kvm->arch.crypto.pqap_hook_rwsem);
682e5282de9SPierre Morel 		return ret;
683e5282de9SPierre Morel 	}
6841e753732STony Krowiak 	up_read(&vcpu->kvm->arch.crypto.pqap_hook_rwsem);
685e5282de9SPierre Morel 	/*
686e5282de9SPierre Morel 	 * A vfio_driver must register a hook.
687e5282de9SPierre Morel 	 * No hook means no driver to enable the SIE CRYCB and no queues.
688e5282de9SPierre Morel 	 * We send this response to the guest.
689e5282de9SPierre Morel 	 */
690e5282de9SPierre Morel 	status.response_code = 0x01;
691e5282de9SPierre Morel 	memcpy(&vcpu->run->s.regs.gprs[1], &status, sizeof(status));
692e5282de9SPierre Morel 	kvm_s390_set_psw_cc(vcpu, 3);
693e5282de9SPierre Morel 	return 0;
694e5282de9SPierre Morel }
695e5282de9SPierre Morel 
handle_stfl(struct kvm_vcpu * vcpu)696453423dcSChristian Borntraeger static int handle_stfl(struct kvm_vcpu *vcpu)
697453423dcSChristian Borntraeger {
698453423dcSChristian Borntraeger 	int rc;
6999d8d5786SMichael Mueller 	unsigned int fac;
700453423dcSChristian Borntraeger 
701453423dcSChristian Borntraeger 	vcpu->stat.instruction_stfl++;
7025087dfa6SThomas Huth 
7035087dfa6SThomas Huth 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
7045087dfa6SThomas Huth 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
7055087dfa6SThomas Huth 
7069d8d5786SMichael Mueller 	/*
7079d8d5786SMichael Mueller 	 * We need to shift the lower 32 facility bits (bit 0-31) from a u64
7089d8d5786SMichael Mueller 	 * into a u32 memory representation. They will remain bits 0-31.
7099d8d5786SMichael Mueller 	 */
710c54f0d6aSDavid Hildenbrand 	fac = *vcpu->kvm->arch.model.fac_list >> 32;
711c667aeacSHeiko Carstens 	rc = write_guest_lc(vcpu, offsetof(struct lowcore, stfl_fac_list),
7129d8d5786SMichael Mueller 			    &fac, sizeof(fac));
713dc5008b9SHeiko Carstens 	if (rc)
7140f9701c6SHeiko Carstens 		return rc;
7157cbde76bSChristian Borntraeger 	VCPU_EVENT(vcpu, 3, "STFL: store facility list 0x%x", fac);
7169d8d5786SMichael Mueller 	trace_kvm_s390_handle_stfl(vcpu, fac);
717453423dcSChristian Borntraeger 	return 0;
718453423dcSChristian Borntraeger }
719453423dcSChristian Borntraeger 
72048a3e950SCornelia Huck #define PSW_MASK_ADDR_MODE (PSW_MASK_EA | PSW_MASK_BA)
72148a3e950SCornelia Huck #define PSW_MASK_UNASSIGNED 0xb80800fe7fffffffUL
722d21683eaSHeiko Carstens #define PSW_ADDR_24 0x0000000000ffffffUL
72348a3e950SCornelia Huck #define PSW_ADDR_31 0x000000007fffffffUL
72448a3e950SCornelia Huck 
is_valid_psw(psw_t * psw)725a3fb577eSThomas Huth int is_valid_psw(psw_t *psw)
726a3fb577eSThomas Huth {
7273736b874SHeiko Carstens 	if (psw->mask & PSW_MASK_UNASSIGNED)
7283736b874SHeiko Carstens 		return 0;
7293736b874SHeiko Carstens 	if ((psw->mask & PSW_MASK_ADDR_MODE) == PSW_MASK_BA) {
7303736b874SHeiko Carstens 		if (psw->addr & ~PSW_ADDR_31)
7313736b874SHeiko Carstens 			return 0;
7323736b874SHeiko Carstens 	}
7333736b874SHeiko Carstens 	if (!(psw->mask & PSW_MASK_ADDR_MODE) && (psw->addr & ~PSW_ADDR_24))
7343736b874SHeiko Carstens 		return 0;
7353736b874SHeiko Carstens 	if ((psw->mask & PSW_MASK_ADDR_MODE) ==  PSW_MASK_EA)
7363736b874SHeiko Carstens 		return 0;
737a3fb577eSThomas Huth 	if (psw->addr & 1)
738a3fb577eSThomas Huth 		return 0;
7393736b874SHeiko Carstens 	return 1;
7403736b874SHeiko Carstens }
7413736b874SHeiko Carstens 
kvm_s390_handle_lpsw(struct kvm_vcpu * vcpu)74248a3e950SCornelia Huck int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu)
74348a3e950SCornelia Huck {
7443736b874SHeiko Carstens 	psw_t *gpsw = &vcpu->arch.sie_block->gpsw;
74548a3e950SCornelia Huck 	psw_compat_t new_psw;
7463736b874SHeiko Carstens 	u64 addr;
7472d8bcaedSHeiko Carstens 	int rc;
74827f67f87SChristian Borntraeger 	u8 ar;
74948a3e950SCornelia Huck 
750a37cb07aSChristian Borntraeger 	vcpu->stat.instruction_lpsw++;
751a37cb07aSChristian Borntraeger 
7523736b874SHeiko Carstens 	if (gpsw->mask & PSW_MASK_PSTATE)
753208dd756SThomas Huth 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
754208dd756SThomas Huth 
7558ae04b8fSAlexander Yarygin 	addr = kvm_s390_get_base_disp_s(vcpu, &ar);
7566fd0fcc9SHeiko Carstens 	if (addr & 7)
7576fd0fcc9SHeiko Carstens 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
7582d8bcaedSHeiko Carstens 
7598ae04b8fSAlexander Yarygin 	rc = read_guest(vcpu, addr, ar, &new_psw, sizeof(new_psw));
7602d8bcaedSHeiko Carstens 	if (rc)
7612d8bcaedSHeiko Carstens 		return kvm_s390_inject_prog_cond(vcpu, rc);
7626fd0fcc9SHeiko Carstens 	if (!(new_psw.mask & PSW32_MASK_BASE))
7636fd0fcc9SHeiko Carstens 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
7643736b874SHeiko Carstens 	gpsw->mask = (new_psw.mask & ~PSW32_MASK_BASE) << 32;
7653736b874SHeiko Carstens 	gpsw->mask |= new_psw.addr & PSW32_ADDR_AMODE;
7663736b874SHeiko Carstens 	gpsw->addr = new_psw.addr & ~PSW32_ADDR_AMODE;
7673736b874SHeiko Carstens 	if (!is_valid_psw(gpsw))
7686fd0fcc9SHeiko Carstens 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
76948a3e950SCornelia Huck 	return 0;
77048a3e950SCornelia Huck }
77148a3e950SCornelia Huck 
handle_lpswe(struct kvm_vcpu * vcpu)77248a3e950SCornelia Huck static int handle_lpswe(struct kvm_vcpu *vcpu)
77348a3e950SCornelia Huck {
77448a3e950SCornelia Huck 	psw_t new_psw;
7753736b874SHeiko Carstens 	u64 addr;
7762d8bcaedSHeiko Carstens 	int rc;
77727f67f87SChristian Borntraeger 	u8 ar;
77848a3e950SCornelia Huck 
779a37cb07aSChristian Borntraeger 	vcpu->stat.instruction_lpswe++;
780a37cb07aSChristian Borntraeger 
7815087dfa6SThomas Huth 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
7825087dfa6SThomas Huth 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
7835087dfa6SThomas Huth 
7848ae04b8fSAlexander Yarygin 	addr = kvm_s390_get_base_disp_s(vcpu, &ar);
7856fd0fcc9SHeiko Carstens 	if (addr & 7)
7866fd0fcc9SHeiko Carstens 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
7878ae04b8fSAlexander Yarygin 	rc = read_guest(vcpu, addr, ar, &new_psw, sizeof(new_psw));
7882d8bcaedSHeiko Carstens 	if (rc)
7892d8bcaedSHeiko Carstens 		return kvm_s390_inject_prog_cond(vcpu, rc);
7903736b874SHeiko Carstens 	vcpu->arch.sie_block->gpsw = new_psw;
7913736b874SHeiko Carstens 	if (!is_valid_psw(&vcpu->arch.sie_block->gpsw))
7926fd0fcc9SHeiko Carstens 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
79348a3e950SCornelia Huck 	return 0;
79448a3e950SCornelia Huck }
79548a3e950SCornelia Huck 
handle_lpswey(struct kvm_vcpu * vcpu)796*f4513867SChristian Borntraeger static int handle_lpswey(struct kvm_vcpu *vcpu)
797*f4513867SChristian Borntraeger {
798*f4513867SChristian Borntraeger 	psw_t new_psw;
799*f4513867SChristian Borntraeger 	u64 addr;
800*f4513867SChristian Borntraeger 	int rc;
801*f4513867SChristian Borntraeger 	u8 ar;
802*f4513867SChristian Borntraeger 
803*f4513867SChristian Borntraeger 	vcpu->stat.instruction_lpswey++;
804*f4513867SChristian Borntraeger 
805*f4513867SChristian Borntraeger 	if (!test_kvm_facility(vcpu->kvm, 193))
806*f4513867SChristian Borntraeger 		return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
807*f4513867SChristian Borntraeger 
808*f4513867SChristian Borntraeger 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
809*f4513867SChristian Borntraeger 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
810*f4513867SChristian Borntraeger 
811*f4513867SChristian Borntraeger 	addr = kvm_s390_get_base_disp_siy(vcpu, &ar);
812*f4513867SChristian Borntraeger 	if (addr & 7)
813*f4513867SChristian Borntraeger 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
814*f4513867SChristian Borntraeger 
815*f4513867SChristian Borntraeger 	rc = read_guest(vcpu, addr, ar, &new_psw, sizeof(new_psw));
816*f4513867SChristian Borntraeger 	if (rc)
817*f4513867SChristian Borntraeger 		return kvm_s390_inject_prog_cond(vcpu, rc);
818*f4513867SChristian Borntraeger 
819*f4513867SChristian Borntraeger 	vcpu->arch.sie_block->gpsw = new_psw;
820*f4513867SChristian Borntraeger 	if (!is_valid_psw(&vcpu->arch.sie_block->gpsw))
821*f4513867SChristian Borntraeger 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
822*f4513867SChristian Borntraeger 
823*f4513867SChristian Borntraeger 	return 0;
824*f4513867SChristian Borntraeger }
825*f4513867SChristian Borntraeger 
handle_stidp(struct kvm_vcpu * vcpu)826453423dcSChristian Borntraeger static int handle_stidp(struct kvm_vcpu *vcpu)
827453423dcSChristian Borntraeger {
8289bb0ec09SDavid Hildenbrand 	u64 stidp_data = vcpu->kvm->arch.model.cpuid;
829453423dcSChristian Borntraeger 	u64 operand2;
8307d777d78SHeiko Carstens 	int rc;
83127f67f87SChristian Borntraeger 	u8 ar;
832453423dcSChristian Borntraeger 
833453423dcSChristian Borntraeger 	vcpu->stat.instruction_stidp++;
834b1c571a5SCornelia Huck 
8355087dfa6SThomas Huth 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
8365087dfa6SThomas Huth 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
8375087dfa6SThomas Huth 
8388ae04b8fSAlexander Yarygin 	operand2 = kvm_s390_get_base_disp_s(vcpu, &ar);
839453423dcSChristian Borntraeger 
840db4a29cbSHeiko Carstens 	if (operand2 & 7)
841db4a29cbSHeiko Carstens 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
842453423dcSChristian Borntraeger 
8438ae04b8fSAlexander Yarygin 	rc = write_guest(vcpu, operand2, ar, &stidp_data, sizeof(stidp_data));
8447d777d78SHeiko Carstens 	if (rc)
8457d777d78SHeiko Carstens 		return kvm_s390_inject_prog_cond(vcpu, rc);
846453423dcSChristian Borntraeger 
8477cbde76bSChristian Borntraeger 	VCPU_EVENT(vcpu, 3, "STIDP: store cpu id 0x%llx", stidp_data);
848453423dcSChristian Borntraeger 	return 0;
849453423dcSChristian Borntraeger }
850453423dcSChristian Borntraeger 
handle_stsi_3_2_2(struct kvm_vcpu * vcpu,struct sysinfo_3_2_2 * mem)851453423dcSChristian Borntraeger static void handle_stsi_3_2_2(struct kvm_vcpu *vcpu, struct sysinfo_3_2_2 *mem)
852453423dcSChristian Borntraeger {
853453423dcSChristian Borntraeger 	int cpus = 0;
854453423dcSChristian Borntraeger 	int n;
855453423dcSChristian Borntraeger 
856ff520a63SJens Freimann 	cpus = atomic_read(&vcpu->kvm->online_vcpus);
857453423dcSChristian Borntraeger 
858453423dcSChristian Borntraeger 	/* deal with other level 3 hypervisors */
859caf757c6SHeiko Carstens 	if (stsi(mem, 3, 2, 2))
860453423dcSChristian Borntraeger 		mem->count = 0;
861453423dcSChristian Borntraeger 	if (mem->count < 8)
862453423dcSChristian Borntraeger 		mem->count++;
863453423dcSChristian Borntraeger 	for (n = mem->count - 1; n > 0 ; n--)
864453423dcSChristian Borntraeger 		memcpy(&mem->vm[n], &mem->vm[n - 1], sizeof(mem->vm[0]));
865453423dcSChristian Borntraeger 
866b75f4c9aSEkaterina Tumanova 	memset(&mem->vm[0], 0, sizeof(mem->vm[0]));
867453423dcSChristian Borntraeger 	mem->vm[0].cpus_total = cpus;
868453423dcSChristian Borntraeger 	mem->vm[0].cpus_configured = cpus;
869453423dcSChristian Borntraeger 	mem->vm[0].cpus_standby = 0;
870453423dcSChristian Borntraeger 	mem->vm[0].cpus_reserved = 0;
871453423dcSChristian Borntraeger 	mem->vm[0].caf = 1000;
872453423dcSChristian Borntraeger 	memcpy(mem->vm[0].name, "KVMguest", 8);
873453423dcSChristian Borntraeger 	ASCEBC(mem->vm[0].name, 8);
874453423dcSChristian Borntraeger 	memcpy(mem->vm[0].cpi, "KVM/Linux       ", 16);
875453423dcSChristian Borntraeger 	ASCEBC(mem->vm[0].cpi, 16);
876453423dcSChristian Borntraeger }
877453423dcSChristian Borntraeger 
insert_stsi_usr_data(struct kvm_vcpu * vcpu,u64 addr,u8 ar,u8 fc,u8 sel1,u16 sel2)87827f67f87SChristian Borntraeger static void insert_stsi_usr_data(struct kvm_vcpu *vcpu, u64 addr, u8 ar,
879e44fc8c9SEkaterina Tumanova 				 u8 fc, u8 sel1, u16 sel2)
880e44fc8c9SEkaterina Tumanova {
881e44fc8c9SEkaterina Tumanova 	vcpu->run->exit_reason = KVM_EXIT_S390_STSI;
882e44fc8c9SEkaterina Tumanova 	vcpu->run->s390_stsi.addr = addr;
883e44fc8c9SEkaterina Tumanova 	vcpu->run->s390_stsi.ar = ar;
884e44fc8c9SEkaterina Tumanova 	vcpu->run->s390_stsi.fc = fc;
885e44fc8c9SEkaterina Tumanova 	vcpu->run->s390_stsi.sel1 = sel1;
886e44fc8c9SEkaterina Tumanova 	vcpu->run->s390_stsi.sel2 = sel2;
887e44fc8c9SEkaterina Tumanova }
888e44fc8c9SEkaterina Tumanova 
handle_stsi(struct kvm_vcpu * vcpu)889453423dcSChristian Borntraeger static int handle_stsi(struct kvm_vcpu *vcpu)
890453423dcSChristian Borntraeger {
8915a32c1afSChristian Borntraeger 	int fc = (vcpu->run->s.regs.gprs[0] & 0xf0000000) >> 28;
8925a32c1afSChristian Borntraeger 	int sel1 = vcpu->run->s.regs.gprs[0] & 0xff;
8935a32c1afSChristian Borntraeger 	int sel2 = vcpu->run->s.regs.gprs[1] & 0xffff;
894c51f068cSHeiko Carstens 	unsigned long mem = 0;
895453423dcSChristian Borntraeger 	u64 operand2;
896db4a29cbSHeiko Carstens 	int rc = 0;
89727f67f87SChristian Borntraeger 	u8 ar;
898453423dcSChristian Borntraeger 
899453423dcSChristian Borntraeger 	vcpu->stat.instruction_stsi++;
9007cbde76bSChristian Borntraeger 	VCPU_EVENT(vcpu, 3, "STSI: fc: %u sel1: %u sel2: %u", fc, sel1, sel2);
901453423dcSChristian Borntraeger 
9025087dfa6SThomas Huth 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
9035087dfa6SThomas Huth 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
9045087dfa6SThomas Huth 
90524fe0195SPierre Morel 	/* Bailout forbidden function codes */
90624fe0195SPierre Morel 	if (fc > 3 && fc != 15)
90724fe0195SPierre Morel 		goto out_no_data;
90824fe0195SPierre Morel 
90924fe0195SPierre Morel 	/*
91024fe0195SPierre Morel 	 * fc 15 is provided only with
91124fe0195SPierre Morel 	 *   - PTF/CPU topology support through facility 15
91224fe0195SPierre Morel 	 *   - KVM_CAP_S390_USER_STSI
91324fe0195SPierre Morel 	 */
91424fe0195SPierre Morel 	if (fc == 15 && (!test_kvm_facility(vcpu->kvm, 11) ||
91524fe0195SPierre Morel 			 !vcpu->kvm->arch.user_stsi))
91624fe0195SPierre Morel 		goto out_no_data;
91787d41fb4SThomas Huth 
91887d41fb4SThomas Huth 	if (vcpu->run->s.regs.gprs[0] & 0x0fffff00
91987d41fb4SThomas Huth 	    || vcpu->run->s.regs.gprs[1] & 0xffff0000)
92087d41fb4SThomas Huth 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
92187d41fb4SThomas Huth 
92287d41fb4SThomas Huth 	if (fc == 0) {
92387d41fb4SThomas Huth 		vcpu->run->s.regs.gprs[0] = 3 << 28;
924ea828ebfSThomas Huth 		kvm_s390_set_psw_cc(vcpu, 0);
92587d41fb4SThomas Huth 		return 0;
92687d41fb4SThomas Huth 	}
92787d41fb4SThomas Huth 
9288ae04b8fSAlexander Yarygin 	operand2 = kvm_s390_get_base_disp_s(vcpu, &ar);
929453423dcSChristian Borntraeger 
930353cbc6aSJanosch Frank 	if (!kvm_s390_pv_cpu_is_protected(vcpu) && (operand2 & 0xfff))
931453423dcSChristian Borntraeger 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
932453423dcSChristian Borntraeger 
933453423dcSChristian Borntraeger 	switch (fc) {
934453423dcSChristian Borntraeger 	case 1: /* same handling for 1 and 2 */
935453423dcSChristian Borntraeger 	case 2:
936c4196218SChristian Borntraeger 		mem = get_zeroed_page(GFP_KERNEL_ACCOUNT);
937453423dcSChristian Borntraeger 		if (!mem)
938c51f068cSHeiko Carstens 			goto out_no_data;
939caf757c6SHeiko Carstens 		if (stsi((void *) mem, fc, sel1, sel2))
940c51f068cSHeiko Carstens 			goto out_no_data;
941453423dcSChristian Borntraeger 		break;
942453423dcSChristian Borntraeger 	case 3:
943453423dcSChristian Borntraeger 		if (sel1 != 2 || sel2 != 2)
944c51f068cSHeiko Carstens 			goto out_no_data;
945c4196218SChristian Borntraeger 		mem = get_zeroed_page(GFP_KERNEL_ACCOUNT);
946453423dcSChristian Borntraeger 		if (!mem)
947c51f068cSHeiko Carstens 			goto out_no_data;
948453423dcSChristian Borntraeger 		handle_stsi_3_2_2(vcpu, (void *) mem);
949453423dcSChristian Borntraeger 		break;
95024fe0195SPierre Morel 	case 15: /* fc 15 is fully handled in userspace */
95124fe0195SPierre Morel 		insert_stsi_usr_data(vcpu, operand2, ar, fc, sel1, sel2);
95224fe0195SPierre Morel 		trace_kvm_s390_handle_stsi(vcpu, fc, sel1, sel2, operand2);
95324fe0195SPierre Morel 		return -EREMOTE;
954453423dcSChristian Borntraeger 	}
955353cbc6aSJanosch Frank 	if (kvm_s390_pv_cpu_is_protected(vcpu)) {
956b99f4512SNico Boehr 		memcpy(sida_addr(vcpu->arch.sie_block), (void *)mem, PAGE_SIZE);
957353cbc6aSJanosch Frank 		rc = 0;
958353cbc6aSJanosch Frank 	} else {
9598ae04b8fSAlexander Yarygin 		rc = write_guest(vcpu, operand2, ar, (void *)mem, PAGE_SIZE);
960353cbc6aSJanosch Frank 	}
961645c5bc1SHeiko Carstens 	if (rc) {
962645c5bc1SHeiko Carstens 		rc = kvm_s390_inject_prog_cond(vcpu, rc);
963645c5bc1SHeiko Carstens 		goto out;
964453423dcSChristian Borntraeger 	}
965e44fc8c9SEkaterina Tumanova 	if (vcpu->kvm->arch.user_stsi) {
966e44fc8c9SEkaterina Tumanova 		insert_stsi_usr_data(vcpu, operand2, ar, fc, sel1, sel2);
967e44fc8c9SEkaterina Tumanova 		rc = -EREMOTE;
968e44fc8c9SEkaterina Tumanova 	}
9695786fffaSCornelia Huck 	trace_kvm_s390_handle_stsi(vcpu, fc, sel1, sel2, operand2);
970453423dcSChristian Borntraeger 	free_page(mem);
971ea828ebfSThomas Huth 	kvm_s390_set_psw_cc(vcpu, 0);
9725a32c1afSChristian Borntraeger 	vcpu->run->s.regs.gprs[0] = 0;
973e44fc8c9SEkaterina Tumanova 	return rc;
974c51f068cSHeiko Carstens out_no_data:
975ea828ebfSThomas Huth 	kvm_s390_set_psw_cc(vcpu, 3);
976645c5bc1SHeiko Carstens out:
977c51f068cSHeiko Carstens 	free_page(mem);
978db4a29cbSHeiko Carstens 	return rc;
979453423dcSChristian Borntraeger }
980453423dcSChristian Borntraeger 
kvm_s390_handle_b2(struct kvm_vcpu * vcpu)98170455a36SChristian Borntraeger int kvm_s390_handle_b2(struct kvm_vcpu *vcpu)
982453423dcSChristian Borntraeger {
9836db4263fSChristian Borntraeger 	switch (vcpu->arch.sie_block->ipa & 0x00ff) {
9846db4263fSChristian Borntraeger 	case 0x02:
9856db4263fSChristian Borntraeger 		return handle_stidp(vcpu);
9866db4263fSChristian Borntraeger 	case 0x04:
9876db4263fSChristian Borntraeger 		return handle_set_clock(vcpu);
9886db4263fSChristian Borntraeger 	case 0x10:
9896db4263fSChristian Borntraeger 		return handle_set_prefix(vcpu);
9906db4263fSChristian Borntraeger 	case 0x11:
9916db4263fSChristian Borntraeger 		return handle_store_prefix(vcpu);
9926db4263fSChristian Borntraeger 	case 0x12:
9936db4263fSChristian Borntraeger 		return handle_store_cpu_address(vcpu);
9946db4263fSChristian Borntraeger 	case 0x14:
9956db4263fSChristian Borntraeger 		return kvm_s390_handle_vsie(vcpu);
9966db4263fSChristian Borntraeger 	case 0x21:
9976db4263fSChristian Borntraeger 	case 0x50:
9986db4263fSChristian Borntraeger 		return handle_ipte_interlock(vcpu);
9996db4263fSChristian Borntraeger 	case 0x29:
10006db4263fSChristian Borntraeger 		return handle_iske(vcpu);
10016db4263fSChristian Borntraeger 	case 0x2a:
10026db4263fSChristian Borntraeger 		return handle_rrbe(vcpu);
10036db4263fSChristian Borntraeger 	case 0x2b:
10046db4263fSChristian Borntraeger 		return handle_sske(vcpu);
10056db4263fSChristian Borntraeger 	case 0x2c:
10066db4263fSChristian Borntraeger 		return handle_test_block(vcpu);
10076db4263fSChristian Borntraeger 	case 0x30:
10086db4263fSChristian Borntraeger 	case 0x31:
10096db4263fSChristian Borntraeger 	case 0x32:
10106db4263fSChristian Borntraeger 	case 0x33:
10116db4263fSChristian Borntraeger 	case 0x34:
10126db4263fSChristian Borntraeger 	case 0x35:
10136db4263fSChristian Borntraeger 	case 0x36:
10146db4263fSChristian Borntraeger 	case 0x37:
10156db4263fSChristian Borntraeger 	case 0x38:
10166db4263fSChristian Borntraeger 	case 0x39:
10176db4263fSChristian Borntraeger 	case 0x3a:
10186db4263fSChristian Borntraeger 	case 0x3b:
10196db4263fSChristian Borntraeger 	case 0x3c:
10206db4263fSChristian Borntraeger 	case 0x5f:
10216db4263fSChristian Borntraeger 	case 0x74:
10226db4263fSChristian Borntraeger 	case 0x76:
10236db4263fSChristian Borntraeger 		return handle_io_inst(vcpu);
10246db4263fSChristian Borntraeger 	case 0x56:
10256db4263fSChristian Borntraeger 		return handle_sthyi(vcpu);
10266db4263fSChristian Borntraeger 	case 0x7d:
10276db4263fSChristian Borntraeger 		return handle_stsi(vcpu);
1028e5282de9SPierre Morel 	case 0xaf:
1029e5282de9SPierre Morel 		return handle_pqap(vcpu);
10306db4263fSChristian Borntraeger 	case 0xb1:
10316db4263fSChristian Borntraeger 		return handle_stfl(vcpu);
10326db4263fSChristian Borntraeger 	case 0xb2:
10336db4263fSChristian Borntraeger 		return handle_lpswe(vcpu);
10346db4263fSChristian Borntraeger 	default:
1035b8e660b8SHeiko Carstens 		return -EOPNOTSUPP;
1036453423dcSChristian Borntraeger 	}
10376db4263fSChristian Borntraeger }
1038bb25b9baSChristian Borntraeger 
handle_epsw(struct kvm_vcpu * vcpu)103948a3e950SCornelia Huck static int handle_epsw(struct kvm_vcpu *vcpu)
104048a3e950SCornelia Huck {
104148a3e950SCornelia Huck 	int reg1, reg2;
104248a3e950SCornelia Huck 
1043a37cb07aSChristian Borntraeger 	vcpu->stat.instruction_epsw++;
1044a37cb07aSChristian Borntraeger 
1045aeb87c3cSThomas Huth 	kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
104648a3e950SCornelia Huck 
104748a3e950SCornelia Huck 	/* This basically extracts the mask half of the psw. */
1048843200e7SThomas Huth 	vcpu->run->s.regs.gprs[reg1] &= 0xffffffff00000000UL;
104948a3e950SCornelia Huck 	vcpu->run->s.regs.gprs[reg1] |= vcpu->arch.sie_block->gpsw.mask >> 32;
105048a3e950SCornelia Huck 	if (reg2) {
1051843200e7SThomas Huth 		vcpu->run->s.regs.gprs[reg2] &= 0xffffffff00000000UL;
105248a3e950SCornelia Huck 		vcpu->run->s.regs.gprs[reg2] |=
1053843200e7SThomas Huth 			vcpu->arch.sie_block->gpsw.mask & 0x00000000ffffffffUL;
105448a3e950SCornelia Huck 	}
105548a3e950SCornelia Huck 	return 0;
105648a3e950SCornelia Huck }
105748a3e950SCornelia Huck 
105869d0d3a3SChristian Borntraeger #define PFMF_RESERVED   0xfffc0101UL
105969d0d3a3SChristian Borntraeger #define PFMF_SK         0x00020000UL
106069d0d3a3SChristian Borntraeger #define PFMF_CF         0x00010000UL
106169d0d3a3SChristian Borntraeger #define PFMF_UI         0x00008000UL
106269d0d3a3SChristian Borntraeger #define PFMF_FSC        0x00007000UL
106369d0d3a3SChristian Borntraeger #define PFMF_NQ         0x00000800UL
106469d0d3a3SChristian Borntraeger #define PFMF_MR         0x00000400UL
106569d0d3a3SChristian Borntraeger #define PFMF_MC         0x00000200UL
106669d0d3a3SChristian Borntraeger #define PFMF_KEY        0x000000feUL
106769d0d3a3SChristian Borntraeger 
handle_pfmf(struct kvm_vcpu * vcpu)106869d0d3a3SChristian Borntraeger static int handle_pfmf(struct kvm_vcpu *vcpu)
106969d0d3a3SChristian Borntraeger {
10701824c723SDavid Hildenbrand 	bool mr = false, mc = false, nq;
107169d0d3a3SChristian Borntraeger 	int reg1, reg2;
107269d0d3a3SChristian Borntraeger 	unsigned long start, end;
10731824c723SDavid Hildenbrand 	unsigned char key;
107469d0d3a3SChristian Borntraeger 
107569d0d3a3SChristian Borntraeger 	vcpu->stat.instruction_pfmf++;
107669d0d3a3SChristian Borntraeger 
107769d0d3a3SChristian Borntraeger 	kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
107869d0d3a3SChristian Borntraeger 
107903c02807SHeiko Carstens 	if (!test_kvm_facility(vcpu->kvm, 8))
108069d0d3a3SChristian Borntraeger 		return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
108169d0d3a3SChristian Borntraeger 
108269d0d3a3SChristian Borntraeger 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
1083208dd756SThomas Huth 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
108469d0d3a3SChristian Borntraeger 
108569d0d3a3SChristian Borntraeger 	if (vcpu->run->s.regs.gprs[reg1] & PFMF_RESERVED)
108669d0d3a3SChristian Borntraeger 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
108769d0d3a3SChristian Borntraeger 
1088edc5b055SDavid Hildenbrand 	/* Only provide non-quiescing support if enabled for the guest */
1089edc5b055SDavid Hildenbrand 	if (vcpu->run->s.regs.gprs[reg1] & PFMF_NQ &&
1090edc5b055SDavid Hildenbrand 	    !test_kvm_facility(vcpu->kvm, 14))
109169d0d3a3SChristian Borntraeger 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
109269d0d3a3SChristian Borntraeger 
10931824c723SDavid Hildenbrand 	/* Only provide conditional-SSKE support if enabled for the guest */
10941824c723SDavid Hildenbrand 	if (vcpu->run->s.regs.gprs[reg1] & PFMF_SK &&
10951824c723SDavid Hildenbrand 	    test_kvm_facility(vcpu->kvm, 10)) {
10961824c723SDavid Hildenbrand 		mr = vcpu->run->s.regs.gprs[reg1] & PFMF_MR;
10971824c723SDavid Hildenbrand 		mc = vcpu->run->s.regs.gprs[reg1] & PFMF_MC;
10981824c723SDavid Hildenbrand 	}
10991824c723SDavid Hildenbrand 
11001824c723SDavid Hildenbrand 	nq = vcpu->run->s.regs.gprs[reg1] & PFMF_NQ;
11011824c723SDavid Hildenbrand 	key = vcpu->run->s.regs.gprs[reg1] & PFMF_KEY;
110269d0d3a3SChristian Borntraeger 	start = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK;
1103a02689feSThomas Huth 	start = kvm_s390_logical_to_effective(vcpu, start);
1104fb34c603SThomas Huth 
11056164a2e9SDavid Hildenbrand 	if (vcpu->run->s.regs.gprs[reg1] & PFMF_CF) {
11066164a2e9SDavid Hildenbrand 		if (kvm_s390_check_low_addr_prot_real(vcpu, start))
11076164a2e9SDavid Hildenbrand 			return kvm_s390_inject_prog_irq(vcpu, &vcpu->arch.pgm);
11086164a2e9SDavid Hildenbrand 	}
11096164a2e9SDavid Hildenbrand 
111069d0d3a3SChristian Borntraeger 	switch (vcpu->run->s.regs.gprs[reg1] & PFMF_FSC) {
111169d0d3a3SChristian Borntraeger 	case 0x00000000:
11126164a2e9SDavid Hildenbrand 		/* only 4k frames specify a real address */
11136164a2e9SDavid Hildenbrand 		start = kvm_s390_real_to_abs(vcpu, start);
111458cdf5ebSHeiko Carstens 		end = (start + PAGE_SIZE) & ~(PAGE_SIZE - 1);
111569d0d3a3SChristian Borntraeger 		break;
111669d0d3a3SChristian Borntraeger 	case 0x00001000:
111758cdf5ebSHeiko Carstens 		end = (start + _SEGMENT_SIZE) & ~(_SEGMENT_SIZE - 1);
111869d0d3a3SChristian Borntraeger 		break;
111969d0d3a3SChristian Borntraeger 	case 0x00002000:
112053df84f8SGuenther Hutzl 		/* only support 2G frame size if EDAT2 is available and we are
112153df84f8SGuenther Hutzl 		   not in 24-bit addressing mode */
112253df84f8SGuenther Hutzl 		if (!test_kvm_facility(vcpu->kvm, 78) ||
11238bb3fdd6SHeiko Carstens 		    psw_bits(vcpu->arch.sie_block->gpsw).eaba == PSW_BITS_AMODE_24BIT)
112453df84f8SGuenther Hutzl 			return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
112558cdf5ebSHeiko Carstens 		end = (start + _REGION3_SIZE) & ~(_REGION3_SIZE - 1);
112653df84f8SGuenther Hutzl 		break;
112769d0d3a3SChristian Borntraeger 	default:
112869d0d3a3SChristian Borntraeger 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
112969d0d3a3SChristian Borntraeger 	}
1130a02689feSThomas Huth 
1131695be0e7SDavid Hildenbrand 	while (start != end) {
1132bd096f64SJanosch Frank 		unsigned long vmaddr;
1133bd096f64SJanosch Frank 		bool unlocked = false;
113469d0d3a3SChristian Borntraeger 
1135fb34c603SThomas Huth 		/* Translate guest address to host address */
1136bd096f64SJanosch Frank 		vmaddr = gfn_to_hva(vcpu->kvm, gpa_to_gfn(start));
1137bd096f64SJanosch Frank 		if (kvm_is_error_hva(vmaddr))
113869d0d3a3SChristian Borntraeger 			return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
113969d0d3a3SChristian Borntraeger 
114069d0d3a3SChristian Borntraeger 		if (vcpu->run->s.regs.gprs[reg1] & PFMF_CF) {
11410230cae7SJanosch Frank 			if (kvm_clear_guest(vcpu->kvm, start, PAGE_SIZE))
114269d0d3a3SChristian Borntraeger 				return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
114369d0d3a3SChristian Borntraeger 		}
114469d0d3a3SChristian Borntraeger 
114569d0d3a3SChristian Borntraeger 		if (vcpu->run->s.regs.gprs[reg1] & PFMF_SK) {
1146730cd632SFarhan Ali 			int rc = kvm_s390_skey_check_enable(vcpu);
11473ac8e380SDominik Dingel 
11483ac8e380SDominik Dingel 			if (rc)
11493ac8e380SDominik Dingel 				return rc;
1150d8ed45c5SMichel Lespinasse 			mmap_read_lock(current->mm);
1151bd096f64SJanosch Frank 			rc = cond_set_guest_storage_key(current->mm, vmaddr,
11521824c723SDavid Hildenbrand 							key, NULL, nq, mr, mc);
1153bd096f64SJanosch Frank 			if (rc < 0) {
115464019a2eSPeter Xu 				rc = fixup_user_fault(current->mm, vmaddr,
1155bd096f64SJanosch Frank 						      FAULT_FLAG_WRITE, &unlocked);
1156bd096f64SJanosch Frank 				rc = !rc ? -EAGAIN : rc;
115769d0d3a3SChristian Borntraeger 			}
1158d8ed45c5SMichel Lespinasse 			mmap_read_unlock(current->mm);
1159bd096f64SJanosch Frank 			if (rc == -EFAULT)
1160bd096f64SJanosch Frank 				return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
1161a11bdb1aSJanosch Frank 			if (rc == -EAGAIN)
1162a11bdb1aSJanosch Frank 				continue;
1163a11bdb1aSJanosch Frank 			if (rc < 0)
1164a11bdb1aSJanosch Frank 				return rc;
116569d0d3a3SChristian Borntraeger 		}
1166a11bdb1aSJanosch Frank 		start += PAGE_SIZE;
1167bd096f64SJanosch Frank 	}
11682c26d1d2SDavid Hildenbrand 	if (vcpu->run->s.regs.gprs[reg1] & PFMF_FSC) {
11698bb3fdd6SHeiko Carstens 		if (psw_bits(vcpu->arch.sie_block->gpsw).eaba == PSW_BITS_AMODE_64BIT) {
117069d0d3a3SChristian Borntraeger 			vcpu->run->s.regs.gprs[reg2] = end;
11712c26d1d2SDavid Hildenbrand 		} else {
11722c26d1d2SDavid Hildenbrand 			vcpu->run->s.regs.gprs[reg2] &= ~0xffffffffUL;
11732c26d1d2SDavid Hildenbrand 			end = kvm_s390_logical_to_effective(vcpu, end);
11742c26d1d2SDavid Hildenbrand 			vcpu->run->s.regs.gprs[reg2] |= end;
11752c26d1d2SDavid Hildenbrand 		}
11762c26d1d2SDavid Hildenbrand 	}
117769d0d3a3SChristian Borntraeger 	return 0;
117869d0d3a3SChristian Borntraeger }
117969d0d3a3SChristian Borntraeger 
1180afdad616SClaudio Imbrenda /*
1181c1e8d7c6SMichel Lespinasse  * Must be called with relevant read locks held (kvm->mm->mmap_lock, kvm->srcu)
1182afdad616SClaudio Imbrenda  */
__do_essa(struct kvm_vcpu * vcpu,const int orc)1183afdad616SClaudio Imbrenda static inline int __do_essa(struct kvm_vcpu *vcpu, const int orc)
1184190df4a2SClaudio Imbrenda {
1185190df4a2SClaudio Imbrenda 	int r1, r2, nappended, entries;
1186190df4a2SClaudio Imbrenda 	unsigned long gfn, hva, res, pgstev, ptev;
1187190df4a2SClaudio Imbrenda 	unsigned long *cbrlo;
1188190df4a2SClaudio Imbrenda 
1189190df4a2SClaudio Imbrenda 	/*
1190190df4a2SClaudio Imbrenda 	 * We don't need to set SD.FPF.SK to 1 here, because if we have a
1191190df4a2SClaudio Imbrenda 	 * machine check here we either handle it or crash
1192190df4a2SClaudio Imbrenda 	 */
1193190df4a2SClaudio Imbrenda 
1194190df4a2SClaudio Imbrenda 	kvm_s390_get_regs_rre(vcpu, &r1, &r2);
1195190df4a2SClaudio Imbrenda 	gfn = vcpu->run->s.regs.gprs[r2] >> PAGE_SHIFT;
1196190df4a2SClaudio Imbrenda 	hva = gfn_to_hva(vcpu->kvm, gfn);
1197190df4a2SClaudio Imbrenda 	entries = (vcpu->arch.sie_block->cbrlo & ~PAGE_MASK) >> 3;
1198190df4a2SClaudio Imbrenda 
1199190df4a2SClaudio Imbrenda 	if (kvm_is_error_hva(hva))
1200190df4a2SClaudio Imbrenda 		return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
1201190df4a2SClaudio Imbrenda 
1202190df4a2SClaudio Imbrenda 	nappended = pgste_perform_essa(vcpu->kvm->mm, hva, orc, &ptev, &pgstev);
1203190df4a2SClaudio Imbrenda 	if (nappended < 0) {
1204190df4a2SClaudio Imbrenda 		res = orc ? 0x10 : 0;
1205190df4a2SClaudio Imbrenda 		vcpu->run->s.regs.gprs[r1] = res; /* Exception Indication */
1206190df4a2SClaudio Imbrenda 		return 0;
1207190df4a2SClaudio Imbrenda 	}
1208190df4a2SClaudio Imbrenda 	res = (pgstev & _PGSTE_GPS_USAGE_MASK) >> 22;
1209190df4a2SClaudio Imbrenda 	/*
1210190df4a2SClaudio Imbrenda 	 * Set the block-content state part of the result. 0 means resident, so
1211190df4a2SClaudio Imbrenda 	 * nothing to do if the page is valid. 2 is for preserved pages
1212190df4a2SClaudio Imbrenda 	 * (non-present and non-zero), and 3 for zero pages (non-present and
1213190df4a2SClaudio Imbrenda 	 * zero).
1214190df4a2SClaudio Imbrenda 	 */
1215190df4a2SClaudio Imbrenda 	if (ptev & _PAGE_INVALID) {
1216190df4a2SClaudio Imbrenda 		res |= 2;
1217190df4a2SClaudio Imbrenda 		if (pgstev & _PGSTE_GPS_ZERO)
1218190df4a2SClaudio Imbrenda 			res |= 1;
1219190df4a2SClaudio Imbrenda 	}
12201bab1c02SClaudio Imbrenda 	if (pgstev & _PGSTE_GPS_NODAT)
12211bab1c02SClaudio Imbrenda 		res |= 0x20;
1222190df4a2SClaudio Imbrenda 	vcpu->run->s.regs.gprs[r1] = res;
1223190df4a2SClaudio Imbrenda 	/*
1224190df4a2SClaudio Imbrenda 	 * It is possible that all the normal 511 slots were full, in which case
1225190df4a2SClaudio Imbrenda 	 * we will now write in the 512th slot, which is reserved for host use.
1226190df4a2SClaudio Imbrenda 	 * In both cases we let the normal essa handling code process all the
1227190df4a2SClaudio Imbrenda 	 * slots, including the reserved one, if needed.
1228190df4a2SClaudio Imbrenda 	 */
1229190df4a2SClaudio Imbrenda 	if (nappended > 0) {
1230190df4a2SClaudio Imbrenda 		cbrlo = phys_to_virt(vcpu->arch.sie_block->cbrlo & PAGE_MASK);
1231190df4a2SClaudio Imbrenda 		cbrlo[entries] = gfn << PAGE_SHIFT;
1232190df4a2SClaudio Imbrenda 	}
1233190df4a2SClaudio Imbrenda 
1234afdad616SClaudio Imbrenda 	if (orc) {
1235afdad616SClaudio Imbrenda 		struct kvm_memory_slot *ms = gfn_to_memslot(vcpu->kvm, gfn);
1236afdad616SClaudio Imbrenda 
1237afdad616SClaudio Imbrenda 		/* Increment only if we are really flipping the bit */
1238afdad616SClaudio Imbrenda 		if (ms && !test_and_set_bit(gfn - ms->base_gfn, kvm_second_dirty_bitmap(ms)))
1239afdad616SClaudio Imbrenda 			atomic64_inc(&vcpu->kvm->arch.cmma_dirty_pages);
1240190df4a2SClaudio Imbrenda 	}
1241190df4a2SClaudio Imbrenda 
1242190df4a2SClaudio Imbrenda 	return nappended;
1243190df4a2SClaudio Imbrenda }
1244190df4a2SClaudio Imbrenda 
handle_essa(struct kvm_vcpu * vcpu)1245b31288faSKonstantin Weitz static int handle_essa(struct kvm_vcpu *vcpu)
1246b31288faSKonstantin Weitz {
1247b31288faSKonstantin Weitz 	/* entries expected to be 1FF */
1248b31288faSKonstantin Weitz 	int entries = (vcpu->arch.sie_block->cbrlo & ~PAGE_MASK) >> 3;
12494a5e7e38SDavid Hildenbrand 	unsigned long *cbrlo;
1250b31288faSKonstantin Weitz 	struct gmap *gmap;
1251190df4a2SClaudio Imbrenda 	int i, orc;
1252b31288faSKonstantin Weitz 
12537cbde76bSChristian Borntraeger 	VCPU_EVENT(vcpu, 4, "ESSA: release %d pages", entries);
1254b31288faSKonstantin Weitz 	gmap = vcpu->arch.gmap;
1255b31288faSKonstantin Weitz 	vcpu->stat.instruction_essa++;
1256e6db1d61SDominik Dingel 	if (!vcpu->kvm->arch.use_cmma)
1257b31288faSKonstantin Weitz 		return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
1258b31288faSKonstantin Weitz 
1259b31288faSKonstantin Weitz 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
1260b31288faSKonstantin Weitz 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
1261190df4a2SClaudio Imbrenda 	/* Check for invalid operation request code */
1262190df4a2SClaudio Imbrenda 	orc = (vcpu->arch.sie_block->ipb & 0xf0000000) >> 28;
12631bab1c02SClaudio Imbrenda 	/* ORCs 0-6 are always valid */
12641bab1c02SClaudio Imbrenda 	if (orc > (test_kvm_facility(vcpu->kvm, 147) ? ESSA_SET_STABLE_NODAT
12651bab1c02SClaudio Imbrenda 						: ESSA_SET_STABLE_IF_RESIDENT))
1266b31288faSKonstantin Weitz 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
1267b31288faSKonstantin Weitz 
1268afdad616SClaudio Imbrenda 	if (!vcpu->kvm->arch.migration_mode) {
1269190df4a2SClaudio Imbrenda 		/*
1270190df4a2SClaudio Imbrenda 		 * CMMA is enabled in the KVM settings, but is disabled in
1271190df4a2SClaudio Imbrenda 		 * the SIE block and in the mm_context, and we are not doing
1272190df4a2SClaudio Imbrenda 		 * a migration. Enable CMMA in the mm_context.
1273190df4a2SClaudio Imbrenda 		 * Since we need to take a write lock to write to the context
1274190df4a2SClaudio Imbrenda 		 * to avoid races with storage keys handling, we check if the
1275190df4a2SClaudio Imbrenda 		 * value really needs to be written to; if the value is
1276190df4a2SClaudio Imbrenda 		 * already correct, we do nothing and avoid the lock.
1277190df4a2SClaudio Imbrenda 		 */
1278c9f0a2b8SJanosch Frank 		if (vcpu->kvm->mm->context.uses_cmm == 0) {
1279d8ed45c5SMichel Lespinasse 			mmap_write_lock(vcpu->kvm->mm);
1280c9f0a2b8SJanosch Frank 			vcpu->kvm->mm->context.uses_cmm = 1;
1281d8ed45c5SMichel Lespinasse 			mmap_write_unlock(vcpu->kvm->mm);
1282190df4a2SClaudio Imbrenda 		}
1283190df4a2SClaudio Imbrenda 		/*
1284190df4a2SClaudio Imbrenda 		 * If we are here, we are supposed to have CMMA enabled in
1285190df4a2SClaudio Imbrenda 		 * the SIE block. Enabling CMMA works on a per-CPU basis,
1286190df4a2SClaudio Imbrenda 		 * while the context use_cmma flag is per process.
1287190df4a2SClaudio Imbrenda 		 * It's possible that the context flag is enabled and the
1288190df4a2SClaudio Imbrenda 		 * SIE flag is not, so we set the flag always; if it was
1289190df4a2SClaudio Imbrenda 		 * already set, nothing changes, otherwise we enable it
1290190df4a2SClaudio Imbrenda 		 * on this CPU too.
1291190df4a2SClaudio Imbrenda 		 */
1292190df4a2SClaudio Imbrenda 		vcpu->arch.sie_block->ecb2 |= ECB2_CMMA;
12930e8bc06aSDavid Hildenbrand 		/* Retry the ESSA instruction */
12940e8bc06aSDavid Hildenbrand 		kvm_s390_retry_instr(vcpu);
1295190df4a2SClaudio Imbrenda 	} else {
1296afdad616SClaudio Imbrenda 		int srcu_idx;
1297afdad616SClaudio Imbrenda 
1298d8ed45c5SMichel Lespinasse 		mmap_read_lock(vcpu->kvm->mm);
1299afdad616SClaudio Imbrenda 		srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
1300afdad616SClaudio Imbrenda 		i = __do_essa(vcpu, orc);
1301afdad616SClaudio Imbrenda 		srcu_read_unlock(&vcpu->kvm->srcu, srcu_idx);
1302d8ed45c5SMichel Lespinasse 		mmap_read_unlock(vcpu->kvm->mm);
1303190df4a2SClaudio Imbrenda 		if (i < 0)
1304190df4a2SClaudio Imbrenda 			return i;
1305afdad616SClaudio Imbrenda 		/* Account for the possible extra cbrl entry */
1306190df4a2SClaudio Imbrenda 		entries += i;
1307190df4a2SClaudio Imbrenda 	}
1308b31288faSKonstantin Weitz 	vcpu->arch.sie_block->cbrlo &= PAGE_MASK;	/* reset nceo */
1309b31288faSKonstantin Weitz 	cbrlo = phys_to_virt(vcpu->arch.sie_block->cbrlo);
1310d8ed45c5SMichel Lespinasse 	mmap_read_lock(gmap->mm);
13114a5e7e38SDavid Hildenbrand 	for (i = 0; i < entries; ++i)
13124a5e7e38SDavid Hildenbrand 		__gmap_zap(gmap, cbrlo[i]);
1313d8ed45c5SMichel Lespinasse 	mmap_read_unlock(gmap->mm);
1314b31288faSKonstantin Weitz 	return 0;
1315b31288faSKonstantin Weitz }
1316b31288faSKonstantin Weitz 
kvm_s390_handle_b9(struct kvm_vcpu * vcpu)131748a3e950SCornelia Huck int kvm_s390_handle_b9(struct kvm_vcpu *vcpu)
131848a3e950SCornelia Huck {
13196db4263fSChristian Borntraeger 	switch (vcpu->arch.sie_block->ipa & 0x00ff) {
13206db4263fSChristian Borntraeger 	case 0x8a:
13216db4263fSChristian Borntraeger 	case 0x8e:
13226db4263fSChristian Borntraeger 	case 0x8f:
13236db4263fSChristian Borntraeger 		return handle_ipte_interlock(vcpu);
13246db4263fSChristian Borntraeger 	case 0x8d:
13256db4263fSChristian Borntraeger 		return handle_epsw(vcpu);
13266db4263fSChristian Borntraeger 	case 0xab:
13276db4263fSChristian Borntraeger 		return handle_essa(vcpu);
13286db4263fSChristian Borntraeger 	case 0xaf:
13296db4263fSChristian Borntraeger 		return handle_pfmf(vcpu);
13306db4263fSChristian Borntraeger 	default:
133148a3e950SCornelia Huck 		return -EOPNOTSUPP;
133248a3e950SCornelia Huck 	}
13336db4263fSChristian Borntraeger }
133448a3e950SCornelia Huck 
kvm_s390_handle_lctl(struct kvm_vcpu * vcpu)1335953ed88dSThomas Huth int kvm_s390_handle_lctl(struct kvm_vcpu *vcpu)
1336953ed88dSThomas Huth {
1337953ed88dSThomas Huth 	int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
1338953ed88dSThomas Huth 	int reg3 = vcpu->arch.sie_block->ipa & 0x000f;
1339fc56eb66SHeiko Carstens 	int reg, rc, nr_regs;
1340fc56eb66SHeiko Carstens 	u32 ctl_array[16];
1341f987a3eeSHeiko Carstens 	u64 ga;
134227f67f87SChristian Borntraeger 	u8 ar;
1343953ed88dSThomas Huth 
1344953ed88dSThomas Huth 	vcpu->stat.instruction_lctl++;
1345953ed88dSThomas Huth 
1346953ed88dSThomas Huth 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
1347953ed88dSThomas Huth 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
1348953ed88dSThomas Huth 
13498ae04b8fSAlexander Yarygin 	ga = kvm_s390_get_base_disp_rs(vcpu, &ar);
1350953ed88dSThomas Huth 
1351f987a3eeSHeiko Carstens 	if (ga & 3)
1352953ed88dSThomas Huth 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
1353953ed88dSThomas Huth 
13547cbde76bSChristian Borntraeger 	VCPU_EVENT(vcpu, 4, "LCTL: r1:%d, r3:%d, addr: 0x%llx", reg1, reg3, ga);
1355f987a3eeSHeiko Carstens 	trace_kvm_s390_handle_lctl(vcpu, 0, reg1, reg3, ga);
1356953ed88dSThomas Huth 
1357fc56eb66SHeiko Carstens 	nr_regs = ((reg3 - reg1) & 0xf) + 1;
13588ae04b8fSAlexander Yarygin 	rc = read_guest(vcpu, ga, ar, ctl_array, nr_regs * sizeof(u32));
1359953ed88dSThomas Huth 	if (rc)
1360f987a3eeSHeiko Carstens 		return kvm_s390_inject_prog_cond(vcpu, rc);
1361fc56eb66SHeiko Carstens 	reg = reg1;
1362fc56eb66SHeiko Carstens 	nr_regs = 0;
1363fc56eb66SHeiko Carstens 	do {
1364953ed88dSThomas Huth 		vcpu->arch.sie_block->gcr[reg] &= 0xffffffff00000000ul;
1365fc56eb66SHeiko Carstens 		vcpu->arch.sie_block->gcr[reg] |= ctl_array[nr_regs++];
1366953ed88dSThomas Huth 		if (reg == reg3)
1367953ed88dSThomas Huth 			break;
1368953ed88dSThomas Huth 		reg = (reg + 1) % 16;
1369953ed88dSThomas Huth 	} while (1);
13702dca485fSChristian Borntraeger 	kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
1371953ed88dSThomas Huth 	return 0;
1372953ed88dSThomas Huth }
1373953ed88dSThomas Huth 
kvm_s390_handle_stctl(struct kvm_vcpu * vcpu)1374aba07508SDavid Hildenbrand int kvm_s390_handle_stctl(struct kvm_vcpu *vcpu)
1375aba07508SDavid Hildenbrand {
1376aba07508SDavid Hildenbrand 	int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
1377aba07508SDavid Hildenbrand 	int reg3 = vcpu->arch.sie_block->ipa & 0x000f;
1378fc56eb66SHeiko Carstens 	int reg, rc, nr_regs;
1379fc56eb66SHeiko Carstens 	u32 ctl_array[16];
1380aba07508SDavid Hildenbrand 	u64 ga;
138127f67f87SChristian Borntraeger 	u8 ar;
1382aba07508SDavid Hildenbrand 
1383aba07508SDavid Hildenbrand 	vcpu->stat.instruction_stctl++;
1384aba07508SDavid Hildenbrand 
1385aba07508SDavid Hildenbrand 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
1386aba07508SDavid Hildenbrand 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
1387aba07508SDavid Hildenbrand 
13888ae04b8fSAlexander Yarygin 	ga = kvm_s390_get_base_disp_rs(vcpu, &ar);
1389aba07508SDavid Hildenbrand 
1390aba07508SDavid Hildenbrand 	if (ga & 3)
1391aba07508SDavid Hildenbrand 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
1392aba07508SDavid Hildenbrand 
13937cbde76bSChristian Borntraeger 	VCPU_EVENT(vcpu, 4, "STCTL r1:%d, r3:%d, addr: 0x%llx", reg1, reg3, ga);
1394aba07508SDavid Hildenbrand 	trace_kvm_s390_handle_stctl(vcpu, 0, reg1, reg3, ga);
1395aba07508SDavid Hildenbrand 
1396aba07508SDavid Hildenbrand 	reg = reg1;
1397fc56eb66SHeiko Carstens 	nr_regs = 0;
1398aba07508SDavid Hildenbrand 	do {
1399fc56eb66SHeiko Carstens 		ctl_array[nr_regs++] = vcpu->arch.sie_block->gcr[reg];
1400aba07508SDavid Hildenbrand 		if (reg == reg3)
1401aba07508SDavid Hildenbrand 			break;
1402aba07508SDavid Hildenbrand 		reg = (reg + 1) % 16;
1403aba07508SDavid Hildenbrand 	} while (1);
14048ae04b8fSAlexander Yarygin 	rc = write_guest(vcpu, ga, ar, ctl_array, nr_regs * sizeof(u32));
1405fc56eb66SHeiko Carstens 	return rc ? kvm_s390_inject_prog_cond(vcpu, rc) : 0;
1406aba07508SDavid Hildenbrand }
1407aba07508SDavid Hildenbrand 
handle_lctlg(struct kvm_vcpu * vcpu)1408953ed88dSThomas Huth static int handle_lctlg(struct kvm_vcpu *vcpu)
1409953ed88dSThomas Huth {
1410953ed88dSThomas Huth 	int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
1411953ed88dSThomas Huth 	int reg3 = vcpu->arch.sie_block->ipa & 0x000f;
1412fc56eb66SHeiko Carstens 	int reg, rc, nr_regs;
1413fc56eb66SHeiko Carstens 	u64 ctl_array[16];
1414fc56eb66SHeiko Carstens 	u64 ga;
141527f67f87SChristian Borntraeger 	u8 ar;
1416953ed88dSThomas Huth 
1417953ed88dSThomas Huth 	vcpu->stat.instruction_lctlg++;
1418953ed88dSThomas Huth 
1419953ed88dSThomas Huth 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
1420953ed88dSThomas Huth 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
1421953ed88dSThomas Huth 
14228ae04b8fSAlexander Yarygin 	ga = kvm_s390_get_base_disp_rsy(vcpu, &ar);
1423953ed88dSThomas Huth 
1424f987a3eeSHeiko Carstens 	if (ga & 7)
1425953ed88dSThomas Huth 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
1426953ed88dSThomas Huth 
14277cbde76bSChristian Borntraeger 	VCPU_EVENT(vcpu, 4, "LCTLG: r1:%d, r3:%d, addr: 0x%llx", reg1, reg3, ga);
1428f987a3eeSHeiko Carstens 	trace_kvm_s390_handle_lctl(vcpu, 1, reg1, reg3, ga);
1429953ed88dSThomas Huth 
1430fc56eb66SHeiko Carstens 	nr_regs = ((reg3 - reg1) & 0xf) + 1;
14318ae04b8fSAlexander Yarygin 	rc = read_guest(vcpu, ga, ar, ctl_array, nr_regs * sizeof(u64));
1432953ed88dSThomas Huth 	if (rc)
1433f987a3eeSHeiko Carstens 		return kvm_s390_inject_prog_cond(vcpu, rc);
1434fc56eb66SHeiko Carstens 	reg = reg1;
1435fc56eb66SHeiko Carstens 	nr_regs = 0;
1436fc56eb66SHeiko Carstens 	do {
1437fc56eb66SHeiko Carstens 		vcpu->arch.sie_block->gcr[reg] = ctl_array[nr_regs++];
1438953ed88dSThomas Huth 		if (reg == reg3)
1439953ed88dSThomas Huth 			break;
1440953ed88dSThomas Huth 		reg = (reg + 1) % 16;
1441953ed88dSThomas Huth 	} while (1);
14422dca485fSChristian Borntraeger 	kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
1443953ed88dSThomas Huth 	return 0;
1444953ed88dSThomas Huth }
1445953ed88dSThomas Huth 
handle_stctg(struct kvm_vcpu * vcpu)1446aba07508SDavid Hildenbrand static int handle_stctg(struct kvm_vcpu *vcpu)
1447aba07508SDavid Hildenbrand {
1448aba07508SDavid Hildenbrand 	int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
1449aba07508SDavid Hildenbrand 	int reg3 = vcpu->arch.sie_block->ipa & 0x000f;
1450fc56eb66SHeiko Carstens 	int reg, rc, nr_regs;
1451fc56eb66SHeiko Carstens 	u64 ctl_array[16];
1452fc56eb66SHeiko Carstens 	u64 ga;
145327f67f87SChristian Borntraeger 	u8 ar;
1454aba07508SDavid Hildenbrand 
1455aba07508SDavid Hildenbrand 	vcpu->stat.instruction_stctg++;
1456aba07508SDavid Hildenbrand 
1457aba07508SDavid Hildenbrand 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
1458aba07508SDavid Hildenbrand 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
1459aba07508SDavid Hildenbrand 
14608ae04b8fSAlexander Yarygin 	ga = kvm_s390_get_base_disp_rsy(vcpu, &ar);
1461aba07508SDavid Hildenbrand 
1462aba07508SDavid Hildenbrand 	if (ga & 7)
1463aba07508SDavid Hildenbrand 		return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
1464aba07508SDavid Hildenbrand 
14657cbde76bSChristian Borntraeger 	VCPU_EVENT(vcpu, 4, "STCTG r1:%d, r3:%d, addr: 0x%llx", reg1, reg3, ga);
1466aba07508SDavid Hildenbrand 	trace_kvm_s390_handle_stctl(vcpu, 1, reg1, reg3, ga);
1467aba07508SDavid Hildenbrand 
1468fc56eb66SHeiko Carstens 	reg = reg1;
1469fc56eb66SHeiko Carstens 	nr_regs = 0;
1470aba07508SDavid Hildenbrand 	do {
1471fc56eb66SHeiko Carstens 		ctl_array[nr_regs++] = vcpu->arch.sie_block->gcr[reg];
1472aba07508SDavid Hildenbrand 		if (reg == reg3)
1473aba07508SDavid Hildenbrand 			break;
1474aba07508SDavid Hildenbrand 		reg = (reg + 1) % 16;
1475aba07508SDavid Hildenbrand 	} while (1);
14768ae04b8fSAlexander Yarygin 	rc = write_guest(vcpu, ga, ar, ctl_array, nr_regs * sizeof(u64));
1477fc56eb66SHeiko Carstens 	return rc ? kvm_s390_inject_prog_cond(vcpu, rc) : 0;
1478aba07508SDavid Hildenbrand }
1479aba07508SDavid Hildenbrand 
kvm_s390_handle_eb(struct kvm_vcpu * vcpu)1480953ed88dSThomas Huth int kvm_s390_handle_eb(struct kvm_vcpu *vcpu)
1481f379aae5SCornelia Huck {
14826db4263fSChristian Borntraeger 	switch (vcpu->arch.sie_block->ipb & 0x000000ff) {
14836db4263fSChristian Borntraeger 	case 0x25:
14846db4263fSChristian Borntraeger 		return handle_stctg(vcpu);
14856db4263fSChristian Borntraeger 	case 0x2f:
14866db4263fSChristian Borntraeger 		return handle_lctlg(vcpu);
14876db4263fSChristian Borntraeger 	case 0x60:
14886db4263fSChristian Borntraeger 	case 0x61:
14896db4263fSChristian Borntraeger 	case 0x62:
14906db4263fSChristian Borntraeger 		return handle_ri(vcpu);
1491*f4513867SChristian Borntraeger 	case 0x71:
1492*f4513867SChristian Borntraeger 		return handle_lpswey(vcpu);
14936db4263fSChristian Borntraeger 	default:
1494f379aae5SCornelia Huck 		return -EOPNOTSUPP;
1495f379aae5SCornelia Huck 	}
14966db4263fSChristian Borntraeger }
1497f379aae5SCornelia Huck 
handle_tprot(struct kvm_vcpu * vcpu)1498bb25b9baSChristian Borntraeger static int handle_tprot(struct kvm_vcpu *vcpu)
1499bb25b9baSChristian Borntraeger {
150061380a7aSJanis Schoetterl-Glausch 	u64 address, operand2;
150161380a7aSJanis Schoetterl-Glausch 	unsigned long gpa;
150261380a7aSJanis Schoetterl-Glausch 	u8 access_key;
1503a0465f9aSThomas Huth 	bool writable;
150461380a7aSJanis Schoetterl-Glausch 	int ret, cc;
150527f67f87SChristian Borntraeger 	u8 ar;
1506bb25b9baSChristian Borntraeger 
1507bb25b9baSChristian Borntraeger 	vcpu->stat.instruction_tprot++;
1508bb25b9baSChristian Borntraeger 
1509f9f6bbc6SThomas Huth 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
1510f9f6bbc6SThomas Huth 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
1511f9f6bbc6SThomas Huth 
151261380a7aSJanis Schoetterl-Glausch 	kvm_s390_get_base_disp_sse(vcpu, &address, &operand2, &ar, NULL);
151361380a7aSJanis Schoetterl-Glausch 	access_key = (operand2 & 0xf0) >> 4;
1514b1c571a5SCornelia Huck 
1515bb25b9baSChristian Borntraeger 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_DAT)
15160130337eSPierre Morel 		ipte_lock(vcpu->kvm);
151761380a7aSJanis Schoetterl-Glausch 
151861380a7aSJanis Schoetterl-Glausch 	ret = guest_translate_address_with_key(vcpu, address, ar, &gpa,
151961380a7aSJanis Schoetterl-Glausch 					       GACC_STORE, access_key);
152061380a7aSJanis Schoetterl-Glausch 	if (ret == 0) {
152161380a7aSJanis Schoetterl-Glausch 		gfn_to_hva_prot(vcpu->kvm, gpa_to_gfn(gpa), &writable);
152261380a7aSJanis Schoetterl-Glausch 	} else if (ret == PGM_PROTECTION) {
152361380a7aSJanis Schoetterl-Glausch 		writable = false;
1524a0465f9aSThomas Huth 		/* Write protected? Try again with read-only... */
152561380a7aSJanis Schoetterl-Glausch 		ret = guest_translate_address_with_key(vcpu, address, ar, &gpa,
152661380a7aSJanis Schoetterl-Glausch 						       GACC_FETCH, access_key);
152761380a7aSJanis Schoetterl-Glausch 	}
152861380a7aSJanis Schoetterl-Glausch 	if (ret >= 0) {
152961380a7aSJanis Schoetterl-Glausch 		cc = -1;
153061380a7aSJanis Schoetterl-Glausch 
153161380a7aSJanis Schoetterl-Glausch 		/* Fetching permitted; storing permitted */
153261380a7aSJanis Schoetterl-Glausch 		if (ret == 0 && writable)
153361380a7aSJanis Schoetterl-Glausch 			cc = 0;
153461380a7aSJanis Schoetterl-Glausch 		/* Fetching permitted; storing not permitted */
153561380a7aSJanis Schoetterl-Glausch 		else if (ret == 0 && !writable)
1536a0465f9aSThomas Huth 			cc = 1;
153761380a7aSJanis Schoetterl-Glausch 		/* Fetching not permitted; storing not permitted */
153861380a7aSJanis Schoetterl-Glausch 		else if (ret == PGM_PROTECTION)
153961380a7aSJanis Schoetterl-Glausch 			cc = 2;
1540a0465f9aSThomas Huth 		/* Translation not available */
154161380a7aSJanis Schoetterl-Glausch 		else if (ret != PGM_ADDRESSING && ret != PGM_TRANSLATION_SPEC)
154261380a7aSJanis Schoetterl-Glausch 			cc = 3;
154361380a7aSJanis Schoetterl-Glausch 
154461380a7aSJanis Schoetterl-Glausch 		if (cc != -1) {
154561380a7aSJanis Schoetterl-Glausch 			kvm_s390_set_psw_cc(vcpu, cc);
1546a0465f9aSThomas Huth 			ret = 0;
154761380a7aSJanis Schoetterl-Glausch 		} else {
154861380a7aSJanis Schoetterl-Glausch 			ret = kvm_s390_inject_program_int(vcpu, ret);
1549a0465f9aSThomas Huth 		}
1550a0465f9aSThomas Huth 	}
1551bb25b9baSChristian Borntraeger 
1552a0465f9aSThomas Huth 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_DAT)
15530130337eSPierre Morel 		ipte_unlock(vcpu->kvm);
1554a0465f9aSThomas Huth 	return ret;
1555bb25b9baSChristian Borntraeger }
1556bb25b9baSChristian Borntraeger 
kvm_s390_handle_e5(struct kvm_vcpu * vcpu)1557bb25b9baSChristian Borntraeger int kvm_s390_handle_e5(struct kvm_vcpu *vcpu)
1558bb25b9baSChristian Borntraeger {
15596db4263fSChristian Borntraeger 	switch (vcpu->arch.sie_block->ipa & 0x00ff) {
15606db4263fSChristian Borntraeger 	case 0x01:
1561bb25b9baSChristian Borntraeger 		return handle_tprot(vcpu);
15626db4263fSChristian Borntraeger 	default:
1563bb25b9baSChristian Borntraeger 		return -EOPNOTSUPP;
1564bb25b9baSChristian Borntraeger 	}
15656db4263fSChristian Borntraeger }
1566bb25b9baSChristian Borntraeger 
handle_sckpf(struct kvm_vcpu * vcpu)15678c3f61e2SCornelia Huck static int handle_sckpf(struct kvm_vcpu *vcpu)
15688c3f61e2SCornelia Huck {
15698c3f61e2SCornelia Huck 	u32 value;
15708c3f61e2SCornelia Huck 
1571a37cb07aSChristian Borntraeger 	vcpu->stat.instruction_sckpf++;
1572a37cb07aSChristian Borntraeger 
15738c3f61e2SCornelia Huck 	if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
1574208dd756SThomas Huth 		return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
15758c3f61e2SCornelia Huck 
15768c3f61e2SCornelia Huck 	if (vcpu->run->s.regs.gprs[0] & 0x00000000ffff0000)
15778c3f61e2SCornelia Huck 		return kvm_s390_inject_program_int(vcpu,
15788c3f61e2SCornelia Huck 						   PGM_SPECIFICATION);
15798c3f61e2SCornelia Huck 
15808c3f61e2SCornelia Huck 	value = vcpu->run->s.regs.gprs[0] & 0x000000000000ffff;
15818c3f61e2SCornelia Huck 	vcpu->arch.sie_block->todpr = value;
15828c3f61e2SCornelia Huck 
15838c3f61e2SCornelia Huck 	return 0;
15848c3f61e2SCornelia Huck }
15858c3f61e2SCornelia Huck 
handle_ptff(struct kvm_vcpu * vcpu)15869acc317bSDavid Hildenbrand static int handle_ptff(struct kvm_vcpu *vcpu)
15879acc317bSDavid Hildenbrand {
1588a37cb07aSChristian Borntraeger 	vcpu->stat.instruction_ptff++;
1589a37cb07aSChristian Borntraeger 
15909acc317bSDavid Hildenbrand 	/* we don't emulate any control instructions yet */
15919acc317bSDavid Hildenbrand 	kvm_s390_set_psw_cc(vcpu, 3);
15929acc317bSDavid Hildenbrand 	return 0;
15939acc317bSDavid Hildenbrand }
15949acc317bSDavid Hildenbrand 
kvm_s390_handle_01(struct kvm_vcpu * vcpu)15958c3f61e2SCornelia Huck int kvm_s390_handle_01(struct kvm_vcpu *vcpu)
15968c3f61e2SCornelia Huck {
15976db4263fSChristian Borntraeger 	switch (vcpu->arch.sie_block->ipa & 0x00ff) {
15986db4263fSChristian Borntraeger 	case 0x04:
15996db4263fSChristian Borntraeger 		return handle_ptff(vcpu);
16006db4263fSChristian Borntraeger 	case 0x07:
16016db4263fSChristian Borntraeger 		return handle_sckpf(vcpu);
16026db4263fSChristian Borntraeger 	default:
16038c3f61e2SCornelia Huck 		return -EOPNOTSUPP;
16048c3f61e2SCornelia Huck 	}
16056db4263fSChristian Borntraeger }
1606