xref: /openbmc/linux/arch/s390/kvm/kvm-s390.c (revision f7819512996361280b86259222456fcf15aad926)
1b0c632dbSHeiko Carstens /*
2a53c8fabSHeiko Carstens  * hosting zSeries kernel virtual machines
3b0c632dbSHeiko Carstens  *
4628eb9b8SChristian Ehrhardt  * Copyright IBM Corp. 2008, 2009
5b0c632dbSHeiko Carstens  *
6b0c632dbSHeiko Carstens  * This program is free software; you can redistribute it and/or modify
7b0c632dbSHeiko Carstens  * it under the terms of the GNU General Public License (version 2 only)
8b0c632dbSHeiko Carstens  * as published by the Free Software Foundation.
9b0c632dbSHeiko Carstens  *
10b0c632dbSHeiko Carstens  *    Author(s): Carsten Otte <cotte@de.ibm.com>
11b0c632dbSHeiko Carstens  *               Christian Borntraeger <borntraeger@de.ibm.com>
12b0c632dbSHeiko Carstens  *               Heiko Carstens <heiko.carstens@de.ibm.com>
13628eb9b8SChristian Ehrhardt  *               Christian Ehrhardt <ehrhardt@de.ibm.com>
1415f36ebdSJason J. Herne  *               Jason J. Herne <jjherne@us.ibm.com>
15b0c632dbSHeiko Carstens  */
16b0c632dbSHeiko Carstens 
17b0c632dbSHeiko Carstens #include <linux/compiler.h>
18b0c632dbSHeiko Carstens #include <linux/err.h>
19b0c632dbSHeiko Carstens #include <linux/fs.h>
20ca872302SChristian Borntraeger #include <linux/hrtimer.h>
21b0c632dbSHeiko Carstens #include <linux/init.h>
22b0c632dbSHeiko Carstens #include <linux/kvm.h>
23b0c632dbSHeiko Carstens #include <linux/kvm_host.h>
24b0c632dbSHeiko Carstens #include <linux/module.h>
25a374e892STony Krowiak #include <linux/random.h>
26b0c632dbSHeiko Carstens #include <linux/slab.h>
27ba5c1e9bSCarsten Otte #include <linux/timer.h>
28cbb870c8SHeiko Carstens #include <asm/asm-offsets.h>
29b0c632dbSHeiko Carstens #include <asm/lowcore.h>
30b0c632dbSHeiko Carstens #include <asm/pgtable.h>
31f5daba1dSHeiko Carstens #include <asm/nmi.h>
32a0616cdeSDavid Howells #include <asm/switch_to.h>
3378c4b59fSMichael Mueller #include <asm/facility.h>
341526bf9cSChristian Borntraeger #include <asm/sclp.h>
358f2abe6aSChristian Borntraeger #include "kvm-s390.h"
36b0c632dbSHeiko Carstens #include "gaccess.h"
37b0c632dbSHeiko Carstens 
385786fffaSCornelia Huck #define CREATE_TRACE_POINTS
395786fffaSCornelia Huck #include "trace.h"
40ade38c31SCornelia Huck #include "trace-s390.h"
415786fffaSCornelia Huck 
42b0c632dbSHeiko Carstens #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
43b0c632dbSHeiko Carstens 
44b0c632dbSHeiko Carstens struct kvm_stats_debugfs_item debugfs_entries[] = {
45b0c632dbSHeiko Carstens 	{ "userspace_handled", VCPU_STAT(exit_userspace) },
460eaeafa1SChristian Borntraeger 	{ "exit_null", VCPU_STAT(exit_null) },
478f2abe6aSChristian Borntraeger 	{ "exit_validity", VCPU_STAT(exit_validity) },
488f2abe6aSChristian Borntraeger 	{ "exit_stop_request", VCPU_STAT(exit_stop_request) },
498f2abe6aSChristian Borntraeger 	{ "exit_external_request", VCPU_STAT(exit_external_request) },
508f2abe6aSChristian Borntraeger 	{ "exit_external_interrupt", VCPU_STAT(exit_external_interrupt) },
51ba5c1e9bSCarsten Otte 	{ "exit_instruction", VCPU_STAT(exit_instruction) },
52ba5c1e9bSCarsten Otte 	{ "exit_program_interruption", VCPU_STAT(exit_program_interruption) },
53ba5c1e9bSCarsten Otte 	{ "exit_instr_and_program_int", VCPU_STAT(exit_instr_and_program) },
54*f7819512SPaolo Bonzini 	{ "halt_successful_poll", VCPU_STAT(halt_successful_poll) },
55ce2e4f0bSDavid Hildenbrand 	{ "halt_wakeup", VCPU_STAT(halt_wakeup) },
56f5e10b09SChristian Borntraeger 	{ "instruction_lctlg", VCPU_STAT(instruction_lctlg) },
57ba5c1e9bSCarsten Otte 	{ "instruction_lctl", VCPU_STAT(instruction_lctl) },
58aba07508SDavid Hildenbrand 	{ "instruction_stctl", VCPU_STAT(instruction_stctl) },
59aba07508SDavid Hildenbrand 	{ "instruction_stctg", VCPU_STAT(instruction_stctg) },
60ba5c1e9bSCarsten Otte 	{ "deliver_emergency_signal", VCPU_STAT(deliver_emergency_signal) },
617697e71fSChristian Ehrhardt 	{ "deliver_external_call", VCPU_STAT(deliver_external_call) },
62ba5c1e9bSCarsten Otte 	{ "deliver_service_signal", VCPU_STAT(deliver_service_signal) },
63ba5c1e9bSCarsten Otte 	{ "deliver_virtio_interrupt", VCPU_STAT(deliver_virtio_interrupt) },
64ba5c1e9bSCarsten Otte 	{ "deliver_stop_signal", VCPU_STAT(deliver_stop_signal) },
65ba5c1e9bSCarsten Otte 	{ "deliver_prefix_signal", VCPU_STAT(deliver_prefix_signal) },
66ba5c1e9bSCarsten Otte 	{ "deliver_restart_signal", VCPU_STAT(deliver_restart_signal) },
67ba5c1e9bSCarsten Otte 	{ "deliver_program_interruption", VCPU_STAT(deliver_program_int) },
68ba5c1e9bSCarsten Otte 	{ "exit_wait_state", VCPU_STAT(exit_wait_state) },
6969d0d3a3SChristian Borntraeger 	{ "instruction_pfmf", VCPU_STAT(instruction_pfmf) },
70453423dcSChristian Borntraeger 	{ "instruction_stidp", VCPU_STAT(instruction_stidp) },
71453423dcSChristian Borntraeger 	{ "instruction_spx", VCPU_STAT(instruction_spx) },
72453423dcSChristian Borntraeger 	{ "instruction_stpx", VCPU_STAT(instruction_stpx) },
73453423dcSChristian Borntraeger 	{ "instruction_stap", VCPU_STAT(instruction_stap) },
74453423dcSChristian Borntraeger 	{ "instruction_storage_key", VCPU_STAT(instruction_storage_key) },
758a242234SHeiko Carstens 	{ "instruction_ipte_interlock", VCPU_STAT(instruction_ipte_interlock) },
76453423dcSChristian Borntraeger 	{ "instruction_stsch", VCPU_STAT(instruction_stsch) },
77453423dcSChristian Borntraeger 	{ "instruction_chsc", VCPU_STAT(instruction_chsc) },
78b31288faSKonstantin Weitz 	{ "instruction_essa", VCPU_STAT(instruction_essa) },
79453423dcSChristian Borntraeger 	{ "instruction_stsi", VCPU_STAT(instruction_stsi) },
80453423dcSChristian Borntraeger 	{ "instruction_stfl", VCPU_STAT(instruction_stfl) },
81bb25b9baSChristian Borntraeger 	{ "instruction_tprot", VCPU_STAT(instruction_tprot) },
825288fbf0SChristian Borntraeger 	{ "instruction_sigp_sense", VCPU_STAT(instruction_sigp_sense) },
83bd59d3a4SCornelia Huck 	{ "instruction_sigp_sense_running", VCPU_STAT(instruction_sigp_sense_running) },
847697e71fSChristian Ehrhardt 	{ "instruction_sigp_external_call", VCPU_STAT(instruction_sigp_external_call) },
855288fbf0SChristian Borntraeger 	{ "instruction_sigp_emergency", VCPU_STAT(instruction_sigp_emergency) },
8642cb0c9fSDavid Hildenbrand 	{ "instruction_sigp_cond_emergency", VCPU_STAT(instruction_sigp_cond_emergency) },
8742cb0c9fSDavid Hildenbrand 	{ "instruction_sigp_start", VCPU_STAT(instruction_sigp_start) },
885288fbf0SChristian Borntraeger 	{ "instruction_sigp_stop", VCPU_STAT(instruction_sigp_stop) },
8942cb0c9fSDavid Hildenbrand 	{ "instruction_sigp_stop_store_status", VCPU_STAT(instruction_sigp_stop_store_status) },
9042cb0c9fSDavid Hildenbrand 	{ "instruction_sigp_store_status", VCPU_STAT(instruction_sigp_store_status) },
915288fbf0SChristian Borntraeger 	{ "instruction_sigp_set_arch", VCPU_STAT(instruction_sigp_arch) },
925288fbf0SChristian Borntraeger 	{ "instruction_sigp_set_prefix", VCPU_STAT(instruction_sigp_prefix) },
935288fbf0SChristian Borntraeger 	{ "instruction_sigp_restart", VCPU_STAT(instruction_sigp_restart) },
9442cb0c9fSDavid Hildenbrand 	{ "instruction_sigp_cpu_reset", VCPU_STAT(instruction_sigp_cpu_reset) },
9542cb0c9fSDavid Hildenbrand 	{ "instruction_sigp_init_cpu_reset", VCPU_STAT(instruction_sigp_init_cpu_reset) },
9642cb0c9fSDavid Hildenbrand 	{ "instruction_sigp_unknown", VCPU_STAT(instruction_sigp_unknown) },
97388186bcSChristian Borntraeger 	{ "diagnose_10", VCPU_STAT(diagnose_10) },
98e28acfeaSChristian Borntraeger 	{ "diagnose_44", VCPU_STAT(diagnose_44) },
9941628d33SKonstantin Weitz 	{ "diagnose_9c", VCPU_STAT(diagnose_9c) },
100b0c632dbSHeiko Carstens 	{ NULL }
101b0c632dbSHeiko Carstens };
102b0c632dbSHeiko Carstens 
10378c4b59fSMichael Mueller unsigned long *vfacilities;
1042c70fe44SChristian Borntraeger static struct gmap_notifier gmap_notifier;
105b0c632dbSHeiko Carstens 
10678c4b59fSMichael Mueller /* test availability of vfacility */
107280ef0f1SHeiko Carstens int test_vfacility(unsigned long nr)
10878c4b59fSMichael Mueller {
10978c4b59fSMichael Mueller 	return __test_facility(nr, (void *) vfacilities);
11078c4b59fSMichael Mueller }
11178c4b59fSMichael Mueller 
112b0c632dbSHeiko Carstens /* Section: not file related */
11313a34e06SRadim Krčmář int kvm_arch_hardware_enable(void)
114b0c632dbSHeiko Carstens {
115b0c632dbSHeiko Carstens 	/* every s390 is virtualization enabled ;-) */
11610474ae8SAlexander Graf 	return 0;
117b0c632dbSHeiko Carstens }
118b0c632dbSHeiko Carstens 
1192c70fe44SChristian Borntraeger static void kvm_gmap_notifier(struct gmap *gmap, unsigned long address);
1202c70fe44SChristian Borntraeger 
121b0c632dbSHeiko Carstens int kvm_arch_hardware_setup(void)
122b0c632dbSHeiko Carstens {
1232c70fe44SChristian Borntraeger 	gmap_notifier.notifier_call = kvm_gmap_notifier;
1242c70fe44SChristian Borntraeger 	gmap_register_ipte_notifier(&gmap_notifier);
125b0c632dbSHeiko Carstens 	return 0;
126b0c632dbSHeiko Carstens }
127b0c632dbSHeiko Carstens 
128b0c632dbSHeiko Carstens void kvm_arch_hardware_unsetup(void)
129b0c632dbSHeiko Carstens {
1302c70fe44SChristian Borntraeger 	gmap_unregister_ipte_notifier(&gmap_notifier);
131b0c632dbSHeiko Carstens }
132b0c632dbSHeiko Carstens 
133b0c632dbSHeiko Carstens int kvm_arch_init(void *opaque)
134b0c632dbSHeiko Carstens {
13584877d93SCornelia Huck 	/* Register floating interrupt controller interface. */
13684877d93SCornelia Huck 	return kvm_register_device_ops(&kvm_flic_ops, KVM_DEV_TYPE_FLIC);
137b0c632dbSHeiko Carstens }
138b0c632dbSHeiko Carstens 
139b0c632dbSHeiko Carstens /* Section: device related */
140b0c632dbSHeiko Carstens long kvm_arch_dev_ioctl(struct file *filp,
141b0c632dbSHeiko Carstens 			unsigned int ioctl, unsigned long arg)
142b0c632dbSHeiko Carstens {
143b0c632dbSHeiko Carstens 	if (ioctl == KVM_S390_ENABLE_SIE)
144b0c632dbSHeiko Carstens 		return s390_enable_sie();
145b0c632dbSHeiko Carstens 	return -EINVAL;
146b0c632dbSHeiko Carstens }
147b0c632dbSHeiko Carstens 
148784aa3d7SAlexander Graf int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
149b0c632dbSHeiko Carstens {
150d7b0b5ebSCarsten Otte 	int r;
151d7b0b5ebSCarsten Otte 
1522bd0ac4eSCarsten Otte 	switch (ext) {
153d7b0b5ebSCarsten Otte 	case KVM_CAP_S390_PSW:
154b6cf8788SChristian Borntraeger 	case KVM_CAP_S390_GMAP:
15552e16b18SChristian Borntraeger 	case KVM_CAP_SYNC_MMU:
1561efd0f59SCarsten Otte #ifdef CONFIG_KVM_S390_UCONTROL
1571efd0f59SCarsten Otte 	case KVM_CAP_S390_UCONTROL:
1581efd0f59SCarsten Otte #endif
1593c038e6bSDominik Dingel 	case KVM_CAP_ASYNC_PF:
16060b413c9SChristian Borntraeger 	case KVM_CAP_SYNC_REGS:
16114eebd91SCarsten Otte 	case KVM_CAP_ONE_REG:
162d6712df9SCornelia Huck 	case KVM_CAP_ENABLE_CAP:
163fa6b7fe9SCornelia Huck 	case KVM_CAP_S390_CSS_SUPPORT:
164ebc32262SCornelia Huck 	case KVM_CAP_IRQFD:
16510ccaa1eSCornelia Huck 	case KVM_CAP_IOEVENTFD:
166c05c4186SJens Freimann 	case KVM_CAP_DEVICE_CTRL:
167d938dc55SCornelia Huck 	case KVM_CAP_ENABLE_CAP_VM:
16878599d90SCornelia Huck 	case KVM_CAP_S390_IRQCHIP:
169f2061656SDominik Dingel 	case KVM_CAP_VM_ATTRIBUTES:
1706352e4d2SDavid Hildenbrand 	case KVM_CAP_MP_STATE:
1712444b352SDavid Hildenbrand 	case KVM_CAP_S390_USER_SIGP:
172d7b0b5ebSCarsten Otte 		r = 1;
173d7b0b5ebSCarsten Otte 		break;
174e726b1bdSChristian Borntraeger 	case KVM_CAP_NR_VCPUS:
175e726b1bdSChristian Borntraeger 	case KVM_CAP_MAX_VCPUS:
176e726b1bdSChristian Borntraeger 		r = KVM_MAX_VCPUS;
177e726b1bdSChristian Borntraeger 		break;
178e1e2e605SNick Wang 	case KVM_CAP_NR_MEMSLOTS:
179e1e2e605SNick Wang 		r = KVM_USER_MEM_SLOTS;
180e1e2e605SNick Wang 		break;
1811526bf9cSChristian Borntraeger 	case KVM_CAP_S390_COW:
182abf09bedSMartin Schwidefsky 		r = MACHINE_HAS_ESOP;
1831526bf9cSChristian Borntraeger 		break;
1842bd0ac4eSCarsten Otte 	default:
185d7b0b5ebSCarsten Otte 		r = 0;
186b0c632dbSHeiko Carstens 	}
187d7b0b5ebSCarsten Otte 	return r;
1882bd0ac4eSCarsten Otte }
189b0c632dbSHeiko Carstens 
19015f36ebdSJason J. Herne static void kvm_s390_sync_dirty_log(struct kvm *kvm,
19115f36ebdSJason J. Herne 					struct kvm_memory_slot *memslot)
19215f36ebdSJason J. Herne {
19315f36ebdSJason J. Herne 	gfn_t cur_gfn, last_gfn;
19415f36ebdSJason J. Herne 	unsigned long address;
19515f36ebdSJason J. Herne 	struct gmap *gmap = kvm->arch.gmap;
19615f36ebdSJason J. Herne 
19715f36ebdSJason J. Herne 	down_read(&gmap->mm->mmap_sem);
19815f36ebdSJason J. Herne 	/* Loop over all guest pages */
19915f36ebdSJason J. Herne 	last_gfn = memslot->base_gfn + memslot->npages;
20015f36ebdSJason J. Herne 	for (cur_gfn = memslot->base_gfn; cur_gfn <= last_gfn; cur_gfn++) {
20115f36ebdSJason J. Herne 		address = gfn_to_hva_memslot(memslot, cur_gfn);
20215f36ebdSJason J. Herne 
20315f36ebdSJason J. Herne 		if (gmap_test_and_clear_dirty(address, gmap))
20415f36ebdSJason J. Herne 			mark_page_dirty(kvm, cur_gfn);
20515f36ebdSJason J. Herne 	}
20615f36ebdSJason J. Herne 	up_read(&gmap->mm->mmap_sem);
20715f36ebdSJason J. Herne }
20815f36ebdSJason J. Herne 
209b0c632dbSHeiko Carstens /* Section: vm related */
210b0c632dbSHeiko Carstens /*
211b0c632dbSHeiko Carstens  * Get (and clear) the dirty memory log for a memory slot.
212b0c632dbSHeiko Carstens  */
213b0c632dbSHeiko Carstens int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
214b0c632dbSHeiko Carstens 			       struct kvm_dirty_log *log)
215b0c632dbSHeiko Carstens {
21615f36ebdSJason J. Herne 	int r;
21715f36ebdSJason J. Herne 	unsigned long n;
21815f36ebdSJason J. Herne 	struct kvm_memory_slot *memslot;
21915f36ebdSJason J. Herne 	int is_dirty = 0;
22015f36ebdSJason J. Herne 
22115f36ebdSJason J. Herne 	mutex_lock(&kvm->slots_lock);
22215f36ebdSJason J. Herne 
22315f36ebdSJason J. Herne 	r = -EINVAL;
22415f36ebdSJason J. Herne 	if (log->slot >= KVM_USER_MEM_SLOTS)
22515f36ebdSJason J. Herne 		goto out;
22615f36ebdSJason J. Herne 
22715f36ebdSJason J. Herne 	memslot = id_to_memslot(kvm->memslots, log->slot);
22815f36ebdSJason J. Herne 	r = -ENOENT;
22915f36ebdSJason J. Herne 	if (!memslot->dirty_bitmap)
23015f36ebdSJason J. Herne 		goto out;
23115f36ebdSJason J. Herne 
23215f36ebdSJason J. Herne 	kvm_s390_sync_dirty_log(kvm, memslot);
23315f36ebdSJason J. Herne 	r = kvm_get_dirty_log(kvm, log, &is_dirty);
23415f36ebdSJason J. Herne 	if (r)
23515f36ebdSJason J. Herne 		goto out;
23615f36ebdSJason J. Herne 
23715f36ebdSJason J. Herne 	/* Clear the dirty log */
23815f36ebdSJason J. Herne 	if (is_dirty) {
23915f36ebdSJason J. Herne 		n = kvm_dirty_bitmap_bytes(memslot);
24015f36ebdSJason J. Herne 		memset(memslot->dirty_bitmap, 0, n);
24115f36ebdSJason J. Herne 	}
24215f36ebdSJason J. Herne 	r = 0;
24315f36ebdSJason J. Herne out:
24415f36ebdSJason J. Herne 	mutex_unlock(&kvm->slots_lock);
24515f36ebdSJason J. Herne 	return r;
246b0c632dbSHeiko Carstens }
247b0c632dbSHeiko Carstens 
248d938dc55SCornelia Huck static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
249d938dc55SCornelia Huck {
250d938dc55SCornelia Huck 	int r;
251d938dc55SCornelia Huck 
252d938dc55SCornelia Huck 	if (cap->flags)
253d938dc55SCornelia Huck 		return -EINVAL;
254d938dc55SCornelia Huck 
255d938dc55SCornelia Huck 	switch (cap->cap) {
25684223598SCornelia Huck 	case KVM_CAP_S390_IRQCHIP:
25784223598SCornelia Huck 		kvm->arch.use_irqchip = 1;
25884223598SCornelia Huck 		r = 0;
25984223598SCornelia Huck 		break;
2602444b352SDavid Hildenbrand 	case KVM_CAP_S390_USER_SIGP:
2612444b352SDavid Hildenbrand 		kvm->arch.user_sigp = 1;
2622444b352SDavid Hildenbrand 		r = 0;
2632444b352SDavid Hildenbrand 		break;
264d938dc55SCornelia Huck 	default:
265d938dc55SCornelia Huck 		r = -EINVAL;
266d938dc55SCornelia Huck 		break;
267d938dc55SCornelia Huck 	}
268d938dc55SCornelia Huck 	return r;
269d938dc55SCornelia Huck }
270d938dc55SCornelia Huck 
2718c0a7ce6SDominik Dingel static int kvm_s390_get_mem_control(struct kvm *kvm, struct kvm_device_attr *attr)
2728c0a7ce6SDominik Dingel {
2738c0a7ce6SDominik Dingel 	int ret;
2748c0a7ce6SDominik Dingel 
2758c0a7ce6SDominik Dingel 	switch (attr->attr) {
2768c0a7ce6SDominik Dingel 	case KVM_S390_VM_MEM_LIMIT_SIZE:
2778c0a7ce6SDominik Dingel 		ret = 0;
2788c0a7ce6SDominik Dingel 		if (put_user(kvm->arch.gmap->asce_end, (u64 __user *)attr->addr))
2798c0a7ce6SDominik Dingel 			ret = -EFAULT;
2808c0a7ce6SDominik Dingel 		break;
2818c0a7ce6SDominik Dingel 	default:
2828c0a7ce6SDominik Dingel 		ret = -ENXIO;
2838c0a7ce6SDominik Dingel 		break;
2848c0a7ce6SDominik Dingel 	}
2858c0a7ce6SDominik Dingel 	return ret;
2868c0a7ce6SDominik Dingel }
2878c0a7ce6SDominik Dingel 
2888c0a7ce6SDominik Dingel static int kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *attr)
2894f718eabSDominik Dingel {
2904f718eabSDominik Dingel 	int ret;
2914f718eabSDominik Dingel 	unsigned int idx;
2924f718eabSDominik Dingel 	switch (attr->attr) {
2934f718eabSDominik Dingel 	case KVM_S390_VM_MEM_ENABLE_CMMA:
2944f718eabSDominik Dingel 		ret = -EBUSY;
2954f718eabSDominik Dingel 		mutex_lock(&kvm->lock);
2964f718eabSDominik Dingel 		if (atomic_read(&kvm->online_vcpus) == 0) {
2974f718eabSDominik Dingel 			kvm->arch.use_cmma = 1;
2984f718eabSDominik Dingel 			ret = 0;
2994f718eabSDominik Dingel 		}
3004f718eabSDominik Dingel 		mutex_unlock(&kvm->lock);
3014f718eabSDominik Dingel 		break;
3024f718eabSDominik Dingel 	case KVM_S390_VM_MEM_CLR_CMMA:
3034f718eabSDominik Dingel 		mutex_lock(&kvm->lock);
3044f718eabSDominik Dingel 		idx = srcu_read_lock(&kvm->srcu);
305a13cff31SDominik Dingel 		s390_reset_cmma(kvm->arch.gmap->mm);
3064f718eabSDominik Dingel 		srcu_read_unlock(&kvm->srcu, idx);
3074f718eabSDominik Dingel 		mutex_unlock(&kvm->lock);
3084f718eabSDominik Dingel 		ret = 0;
3094f718eabSDominik Dingel 		break;
3108c0a7ce6SDominik Dingel 	case KVM_S390_VM_MEM_LIMIT_SIZE: {
3118c0a7ce6SDominik Dingel 		unsigned long new_limit;
3128c0a7ce6SDominik Dingel 
3138c0a7ce6SDominik Dingel 		if (kvm_is_ucontrol(kvm))
3148c0a7ce6SDominik Dingel 			return -EINVAL;
3158c0a7ce6SDominik Dingel 
3168c0a7ce6SDominik Dingel 		if (get_user(new_limit, (u64 __user *)attr->addr))
3178c0a7ce6SDominik Dingel 			return -EFAULT;
3188c0a7ce6SDominik Dingel 
3198c0a7ce6SDominik Dingel 		if (new_limit > kvm->arch.gmap->asce_end)
3208c0a7ce6SDominik Dingel 			return -E2BIG;
3218c0a7ce6SDominik Dingel 
3228c0a7ce6SDominik Dingel 		ret = -EBUSY;
3238c0a7ce6SDominik Dingel 		mutex_lock(&kvm->lock);
3248c0a7ce6SDominik Dingel 		if (atomic_read(&kvm->online_vcpus) == 0) {
3258c0a7ce6SDominik Dingel 			/* gmap_alloc will round the limit up */
3268c0a7ce6SDominik Dingel 			struct gmap *new = gmap_alloc(current->mm, new_limit);
3278c0a7ce6SDominik Dingel 
3288c0a7ce6SDominik Dingel 			if (!new) {
3298c0a7ce6SDominik Dingel 				ret = -ENOMEM;
3308c0a7ce6SDominik Dingel 			} else {
3318c0a7ce6SDominik Dingel 				gmap_free(kvm->arch.gmap);
3328c0a7ce6SDominik Dingel 				new->private = kvm;
3338c0a7ce6SDominik Dingel 				kvm->arch.gmap = new;
3348c0a7ce6SDominik Dingel 				ret = 0;
3358c0a7ce6SDominik Dingel 			}
3368c0a7ce6SDominik Dingel 		}
3378c0a7ce6SDominik Dingel 		mutex_unlock(&kvm->lock);
3388c0a7ce6SDominik Dingel 		break;
3398c0a7ce6SDominik Dingel 	}
3404f718eabSDominik Dingel 	default:
3414f718eabSDominik Dingel 		ret = -ENXIO;
3424f718eabSDominik Dingel 		break;
3434f718eabSDominik Dingel 	}
3444f718eabSDominik Dingel 	return ret;
3454f718eabSDominik Dingel }
3464f718eabSDominik Dingel 
347a374e892STony Krowiak static void kvm_s390_vcpu_crypto_setup(struct kvm_vcpu *vcpu);
348a374e892STony Krowiak 
349a374e892STony Krowiak static int kvm_s390_vm_set_crypto(struct kvm *kvm, struct kvm_device_attr *attr)
350a374e892STony Krowiak {
351a374e892STony Krowiak 	struct kvm_vcpu *vcpu;
352a374e892STony Krowiak 	int i;
353a374e892STony Krowiak 
354a374e892STony Krowiak 	if (!test_vfacility(76))
355a374e892STony Krowiak 		return -EINVAL;
356a374e892STony Krowiak 
357a374e892STony Krowiak 	mutex_lock(&kvm->lock);
358a374e892STony Krowiak 	switch (attr->attr) {
359a374e892STony Krowiak 	case KVM_S390_VM_CRYPTO_ENABLE_AES_KW:
360a374e892STony Krowiak 		get_random_bytes(
361a374e892STony Krowiak 			kvm->arch.crypto.crycb->aes_wrapping_key_mask,
362a374e892STony Krowiak 			sizeof(kvm->arch.crypto.crycb->aes_wrapping_key_mask));
363a374e892STony Krowiak 		kvm->arch.crypto.aes_kw = 1;
364a374e892STony Krowiak 		break;
365a374e892STony Krowiak 	case KVM_S390_VM_CRYPTO_ENABLE_DEA_KW:
366a374e892STony Krowiak 		get_random_bytes(
367a374e892STony Krowiak 			kvm->arch.crypto.crycb->dea_wrapping_key_mask,
368a374e892STony Krowiak 			sizeof(kvm->arch.crypto.crycb->dea_wrapping_key_mask));
369a374e892STony Krowiak 		kvm->arch.crypto.dea_kw = 1;
370a374e892STony Krowiak 		break;
371a374e892STony Krowiak 	case KVM_S390_VM_CRYPTO_DISABLE_AES_KW:
372a374e892STony Krowiak 		kvm->arch.crypto.aes_kw = 0;
373a374e892STony Krowiak 		memset(kvm->arch.crypto.crycb->aes_wrapping_key_mask, 0,
374a374e892STony Krowiak 			sizeof(kvm->arch.crypto.crycb->aes_wrapping_key_mask));
375a374e892STony Krowiak 		break;
376a374e892STony Krowiak 	case KVM_S390_VM_CRYPTO_DISABLE_DEA_KW:
377a374e892STony Krowiak 		kvm->arch.crypto.dea_kw = 0;
378a374e892STony Krowiak 		memset(kvm->arch.crypto.crycb->dea_wrapping_key_mask, 0,
379a374e892STony Krowiak 			sizeof(kvm->arch.crypto.crycb->dea_wrapping_key_mask));
380a374e892STony Krowiak 		break;
381a374e892STony Krowiak 	default:
382a374e892STony Krowiak 		mutex_unlock(&kvm->lock);
383a374e892STony Krowiak 		return -ENXIO;
384a374e892STony Krowiak 	}
385a374e892STony Krowiak 
386a374e892STony Krowiak 	kvm_for_each_vcpu(i, vcpu, kvm) {
387a374e892STony Krowiak 		kvm_s390_vcpu_crypto_setup(vcpu);
388a374e892STony Krowiak 		exit_sie(vcpu);
389a374e892STony Krowiak 	}
390a374e892STony Krowiak 	mutex_unlock(&kvm->lock);
391a374e892STony Krowiak 	return 0;
392a374e892STony Krowiak }
393a374e892STony Krowiak 
39472f25020SJason J. Herne static int kvm_s390_set_tod_high(struct kvm *kvm, struct kvm_device_attr *attr)
39572f25020SJason J. Herne {
39672f25020SJason J. Herne 	u8 gtod_high;
39772f25020SJason J. Herne 
39872f25020SJason J. Herne 	if (copy_from_user(&gtod_high, (void __user *)attr->addr,
39972f25020SJason J. Herne 					   sizeof(gtod_high)))
40072f25020SJason J. Herne 		return -EFAULT;
40172f25020SJason J. Herne 
40272f25020SJason J. Herne 	if (gtod_high != 0)
40372f25020SJason J. Herne 		return -EINVAL;
40472f25020SJason J. Herne 
40572f25020SJason J. Herne 	return 0;
40672f25020SJason J. Herne }
40772f25020SJason J. Herne 
40872f25020SJason J. Herne static int kvm_s390_set_tod_low(struct kvm *kvm, struct kvm_device_attr *attr)
40972f25020SJason J. Herne {
41072f25020SJason J. Herne 	struct kvm_vcpu *cur_vcpu;
41172f25020SJason J. Herne 	unsigned int vcpu_idx;
41272f25020SJason J. Herne 	u64 host_tod, gtod;
41372f25020SJason J. Herne 	int r;
41472f25020SJason J. Herne 
41572f25020SJason J. Herne 	if (copy_from_user(&gtod, (void __user *)attr->addr, sizeof(gtod)))
41672f25020SJason J. Herne 		return -EFAULT;
41772f25020SJason J. Herne 
41872f25020SJason J. Herne 	r = store_tod_clock(&host_tod);
41972f25020SJason J. Herne 	if (r)
42072f25020SJason J. Herne 		return r;
42172f25020SJason J. Herne 
42272f25020SJason J. Herne 	mutex_lock(&kvm->lock);
42372f25020SJason J. Herne 	kvm->arch.epoch = gtod - host_tod;
42472f25020SJason J. Herne 	kvm_for_each_vcpu(vcpu_idx, cur_vcpu, kvm) {
42572f25020SJason J. Herne 		cur_vcpu->arch.sie_block->epoch = kvm->arch.epoch;
42672f25020SJason J. Herne 		exit_sie(cur_vcpu);
42772f25020SJason J. Herne 	}
42872f25020SJason J. Herne 	mutex_unlock(&kvm->lock);
42972f25020SJason J. Herne 	return 0;
43072f25020SJason J. Herne }
43172f25020SJason J. Herne 
43272f25020SJason J. Herne static int kvm_s390_set_tod(struct kvm *kvm, struct kvm_device_attr *attr)
43372f25020SJason J. Herne {
43472f25020SJason J. Herne 	int ret;
43572f25020SJason J. Herne 
43672f25020SJason J. Herne 	if (attr->flags)
43772f25020SJason J. Herne 		return -EINVAL;
43872f25020SJason J. Herne 
43972f25020SJason J. Herne 	switch (attr->attr) {
44072f25020SJason J. Herne 	case KVM_S390_VM_TOD_HIGH:
44172f25020SJason J. Herne 		ret = kvm_s390_set_tod_high(kvm, attr);
44272f25020SJason J. Herne 		break;
44372f25020SJason J. Herne 	case KVM_S390_VM_TOD_LOW:
44472f25020SJason J. Herne 		ret = kvm_s390_set_tod_low(kvm, attr);
44572f25020SJason J. Herne 		break;
44672f25020SJason J. Herne 	default:
44772f25020SJason J. Herne 		ret = -ENXIO;
44872f25020SJason J. Herne 		break;
44972f25020SJason J. Herne 	}
45072f25020SJason J. Herne 	return ret;
45172f25020SJason J. Herne }
45272f25020SJason J. Herne 
45372f25020SJason J. Herne static int kvm_s390_get_tod_high(struct kvm *kvm, struct kvm_device_attr *attr)
45472f25020SJason J. Herne {
45572f25020SJason J. Herne 	u8 gtod_high = 0;
45672f25020SJason J. Herne 
45772f25020SJason J. Herne 	if (copy_to_user((void __user *)attr->addr, &gtod_high,
45872f25020SJason J. Herne 					 sizeof(gtod_high)))
45972f25020SJason J. Herne 		return -EFAULT;
46072f25020SJason J. Herne 
46172f25020SJason J. Herne 	return 0;
46272f25020SJason J. Herne }
46372f25020SJason J. Herne 
46472f25020SJason J. Herne static int kvm_s390_get_tod_low(struct kvm *kvm, struct kvm_device_attr *attr)
46572f25020SJason J. Herne {
46672f25020SJason J. Herne 	u64 host_tod, gtod;
46772f25020SJason J. Herne 	int r;
46872f25020SJason J. Herne 
46972f25020SJason J. Herne 	r = store_tod_clock(&host_tod);
47072f25020SJason J. Herne 	if (r)
47172f25020SJason J. Herne 		return r;
47272f25020SJason J. Herne 
47372f25020SJason J. Herne 	gtod = host_tod + kvm->arch.epoch;
47472f25020SJason J. Herne 	if (copy_to_user((void __user *)attr->addr, &gtod, sizeof(gtod)))
47572f25020SJason J. Herne 		return -EFAULT;
47672f25020SJason J. Herne 
47772f25020SJason J. Herne 	return 0;
47872f25020SJason J. Herne }
47972f25020SJason J. Herne 
48072f25020SJason J. Herne static int kvm_s390_get_tod(struct kvm *kvm, struct kvm_device_attr *attr)
48172f25020SJason J. Herne {
48272f25020SJason J. Herne 	int ret;
48372f25020SJason J. Herne 
48472f25020SJason J. Herne 	if (attr->flags)
48572f25020SJason J. Herne 		return -EINVAL;
48672f25020SJason J. Herne 
48772f25020SJason J. Herne 	switch (attr->attr) {
48872f25020SJason J. Herne 	case KVM_S390_VM_TOD_HIGH:
48972f25020SJason J. Herne 		ret = kvm_s390_get_tod_high(kvm, attr);
49072f25020SJason J. Herne 		break;
49172f25020SJason J. Herne 	case KVM_S390_VM_TOD_LOW:
49272f25020SJason J. Herne 		ret = kvm_s390_get_tod_low(kvm, attr);
49372f25020SJason J. Herne 		break;
49472f25020SJason J. Herne 	default:
49572f25020SJason J. Herne 		ret = -ENXIO;
49672f25020SJason J. Herne 		break;
49772f25020SJason J. Herne 	}
49872f25020SJason J. Herne 	return ret;
49972f25020SJason J. Herne }
50072f25020SJason J. Herne 
501f2061656SDominik Dingel static int kvm_s390_vm_set_attr(struct kvm *kvm, struct kvm_device_attr *attr)
502f2061656SDominik Dingel {
503f2061656SDominik Dingel 	int ret;
504f2061656SDominik Dingel 
505f2061656SDominik Dingel 	switch (attr->group) {
5064f718eabSDominik Dingel 	case KVM_S390_VM_MEM_CTRL:
5078c0a7ce6SDominik Dingel 		ret = kvm_s390_set_mem_control(kvm, attr);
5084f718eabSDominik Dingel 		break;
50972f25020SJason J. Herne 	case KVM_S390_VM_TOD:
51072f25020SJason J. Herne 		ret = kvm_s390_set_tod(kvm, attr);
51172f25020SJason J. Herne 		break;
512a374e892STony Krowiak 	case KVM_S390_VM_CRYPTO:
513a374e892STony Krowiak 		ret = kvm_s390_vm_set_crypto(kvm, attr);
514a374e892STony Krowiak 		break;
515f2061656SDominik Dingel 	default:
516f2061656SDominik Dingel 		ret = -ENXIO;
517f2061656SDominik Dingel 		break;
518f2061656SDominik Dingel 	}
519f2061656SDominik Dingel 
520f2061656SDominik Dingel 	return ret;
521f2061656SDominik Dingel }
522f2061656SDominik Dingel 
523f2061656SDominik Dingel static int kvm_s390_vm_get_attr(struct kvm *kvm, struct kvm_device_attr *attr)
524f2061656SDominik Dingel {
5258c0a7ce6SDominik Dingel 	int ret;
5268c0a7ce6SDominik Dingel 
5278c0a7ce6SDominik Dingel 	switch (attr->group) {
5288c0a7ce6SDominik Dingel 	case KVM_S390_VM_MEM_CTRL:
5298c0a7ce6SDominik Dingel 		ret = kvm_s390_get_mem_control(kvm, attr);
5308c0a7ce6SDominik Dingel 		break;
53172f25020SJason J. Herne 	case KVM_S390_VM_TOD:
53272f25020SJason J. Herne 		ret = kvm_s390_get_tod(kvm, attr);
53372f25020SJason J. Herne 		break;
5348c0a7ce6SDominik Dingel 	default:
5358c0a7ce6SDominik Dingel 		ret = -ENXIO;
5368c0a7ce6SDominik Dingel 		break;
5378c0a7ce6SDominik Dingel 	}
5388c0a7ce6SDominik Dingel 
5398c0a7ce6SDominik Dingel 	return ret;
540f2061656SDominik Dingel }
541f2061656SDominik Dingel 
542f2061656SDominik Dingel static int kvm_s390_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr)
543f2061656SDominik Dingel {
544f2061656SDominik Dingel 	int ret;
545f2061656SDominik Dingel 
546f2061656SDominik Dingel 	switch (attr->group) {
5474f718eabSDominik Dingel 	case KVM_S390_VM_MEM_CTRL:
5484f718eabSDominik Dingel 		switch (attr->attr) {
5494f718eabSDominik Dingel 		case KVM_S390_VM_MEM_ENABLE_CMMA:
5504f718eabSDominik Dingel 		case KVM_S390_VM_MEM_CLR_CMMA:
5518c0a7ce6SDominik Dingel 		case KVM_S390_VM_MEM_LIMIT_SIZE:
5524f718eabSDominik Dingel 			ret = 0;
5534f718eabSDominik Dingel 			break;
5544f718eabSDominik Dingel 		default:
5554f718eabSDominik Dingel 			ret = -ENXIO;
5564f718eabSDominik Dingel 			break;
5574f718eabSDominik Dingel 		}
5584f718eabSDominik Dingel 		break;
55972f25020SJason J. Herne 	case KVM_S390_VM_TOD:
56072f25020SJason J. Herne 		switch (attr->attr) {
56172f25020SJason J. Herne 		case KVM_S390_VM_TOD_LOW:
56272f25020SJason J. Herne 		case KVM_S390_VM_TOD_HIGH:
56372f25020SJason J. Herne 			ret = 0;
56472f25020SJason J. Herne 			break;
56572f25020SJason J. Herne 		default:
56672f25020SJason J. Herne 			ret = -ENXIO;
56772f25020SJason J. Herne 			break;
56872f25020SJason J. Herne 		}
56972f25020SJason J. Herne 		break;
570a374e892STony Krowiak 	case KVM_S390_VM_CRYPTO:
571a374e892STony Krowiak 		switch (attr->attr) {
572a374e892STony Krowiak 		case KVM_S390_VM_CRYPTO_ENABLE_AES_KW:
573a374e892STony Krowiak 		case KVM_S390_VM_CRYPTO_ENABLE_DEA_KW:
574a374e892STony Krowiak 		case KVM_S390_VM_CRYPTO_DISABLE_AES_KW:
575a374e892STony Krowiak 		case KVM_S390_VM_CRYPTO_DISABLE_DEA_KW:
576a374e892STony Krowiak 			ret = 0;
577a374e892STony Krowiak 			break;
578a374e892STony Krowiak 		default:
579a374e892STony Krowiak 			ret = -ENXIO;
580a374e892STony Krowiak 			break;
581a374e892STony Krowiak 		}
582a374e892STony Krowiak 		break;
583f2061656SDominik Dingel 	default:
584f2061656SDominik Dingel 		ret = -ENXIO;
585f2061656SDominik Dingel 		break;
586f2061656SDominik Dingel 	}
587f2061656SDominik Dingel 
588f2061656SDominik Dingel 	return ret;
589f2061656SDominik Dingel }
590f2061656SDominik Dingel 
591b0c632dbSHeiko Carstens long kvm_arch_vm_ioctl(struct file *filp,
592b0c632dbSHeiko Carstens 		       unsigned int ioctl, unsigned long arg)
593b0c632dbSHeiko Carstens {
594b0c632dbSHeiko Carstens 	struct kvm *kvm = filp->private_data;
595b0c632dbSHeiko Carstens 	void __user *argp = (void __user *)arg;
596f2061656SDominik Dingel 	struct kvm_device_attr attr;
597b0c632dbSHeiko Carstens 	int r;
598b0c632dbSHeiko Carstens 
599b0c632dbSHeiko Carstens 	switch (ioctl) {
600ba5c1e9bSCarsten Otte 	case KVM_S390_INTERRUPT: {
601ba5c1e9bSCarsten Otte 		struct kvm_s390_interrupt s390int;
602ba5c1e9bSCarsten Otte 
603ba5c1e9bSCarsten Otte 		r = -EFAULT;
604ba5c1e9bSCarsten Otte 		if (copy_from_user(&s390int, argp, sizeof(s390int)))
605ba5c1e9bSCarsten Otte 			break;
606ba5c1e9bSCarsten Otte 		r = kvm_s390_inject_vm(kvm, &s390int);
607ba5c1e9bSCarsten Otte 		break;
608ba5c1e9bSCarsten Otte 	}
609d938dc55SCornelia Huck 	case KVM_ENABLE_CAP: {
610d938dc55SCornelia Huck 		struct kvm_enable_cap cap;
611d938dc55SCornelia Huck 		r = -EFAULT;
612d938dc55SCornelia Huck 		if (copy_from_user(&cap, argp, sizeof(cap)))
613d938dc55SCornelia Huck 			break;
614d938dc55SCornelia Huck 		r = kvm_vm_ioctl_enable_cap(kvm, &cap);
615d938dc55SCornelia Huck 		break;
616d938dc55SCornelia Huck 	}
61784223598SCornelia Huck 	case KVM_CREATE_IRQCHIP: {
61884223598SCornelia Huck 		struct kvm_irq_routing_entry routing;
61984223598SCornelia Huck 
62084223598SCornelia Huck 		r = -EINVAL;
62184223598SCornelia Huck 		if (kvm->arch.use_irqchip) {
62284223598SCornelia Huck 			/* Set up dummy routing. */
62384223598SCornelia Huck 			memset(&routing, 0, sizeof(routing));
62484223598SCornelia Huck 			kvm_set_irq_routing(kvm, &routing, 0, 0);
62584223598SCornelia Huck 			r = 0;
62684223598SCornelia Huck 		}
62784223598SCornelia Huck 		break;
62884223598SCornelia Huck 	}
629f2061656SDominik Dingel 	case KVM_SET_DEVICE_ATTR: {
630f2061656SDominik Dingel 		r = -EFAULT;
631f2061656SDominik Dingel 		if (copy_from_user(&attr, (void __user *)arg, sizeof(attr)))
632f2061656SDominik Dingel 			break;
633f2061656SDominik Dingel 		r = kvm_s390_vm_set_attr(kvm, &attr);
634f2061656SDominik Dingel 		break;
635f2061656SDominik Dingel 	}
636f2061656SDominik Dingel 	case KVM_GET_DEVICE_ATTR: {
637f2061656SDominik Dingel 		r = -EFAULT;
638f2061656SDominik Dingel 		if (copy_from_user(&attr, (void __user *)arg, sizeof(attr)))
639f2061656SDominik Dingel 			break;
640f2061656SDominik Dingel 		r = kvm_s390_vm_get_attr(kvm, &attr);
641f2061656SDominik Dingel 		break;
642f2061656SDominik Dingel 	}
643f2061656SDominik Dingel 	case KVM_HAS_DEVICE_ATTR: {
644f2061656SDominik Dingel 		r = -EFAULT;
645f2061656SDominik Dingel 		if (copy_from_user(&attr, (void __user *)arg, sizeof(attr)))
646f2061656SDominik Dingel 			break;
647f2061656SDominik Dingel 		r = kvm_s390_vm_has_attr(kvm, &attr);
648f2061656SDominik Dingel 		break;
649f2061656SDominik Dingel 	}
650b0c632dbSHeiko Carstens 	default:
651367e1319SAvi Kivity 		r = -ENOTTY;
652b0c632dbSHeiko Carstens 	}
653b0c632dbSHeiko Carstens 
654b0c632dbSHeiko Carstens 	return r;
655b0c632dbSHeiko Carstens }
656b0c632dbSHeiko Carstens 
6575102ee87STony Krowiak static int kvm_s390_crypto_init(struct kvm *kvm)
6585102ee87STony Krowiak {
6595102ee87STony Krowiak 	if (!test_vfacility(76))
6605102ee87STony Krowiak 		return 0;
6615102ee87STony Krowiak 
6625102ee87STony Krowiak 	kvm->arch.crypto.crycb = kzalloc(sizeof(*kvm->arch.crypto.crycb),
6635102ee87STony Krowiak 					 GFP_KERNEL | GFP_DMA);
6645102ee87STony Krowiak 	if (!kvm->arch.crypto.crycb)
6655102ee87STony Krowiak 		return -ENOMEM;
6665102ee87STony Krowiak 
6675102ee87STony Krowiak 	kvm->arch.crypto.crycbd = (__u32) (unsigned long) kvm->arch.crypto.crycb |
6685102ee87STony Krowiak 				  CRYCB_FORMAT1;
6695102ee87STony Krowiak 
670a374e892STony Krowiak 	/* Disable AES/DEA protected key functions by default */
671a374e892STony Krowiak 	kvm->arch.crypto.aes_kw = 0;
672a374e892STony Krowiak 	kvm->arch.crypto.dea_kw = 0;
673a374e892STony Krowiak 
6745102ee87STony Krowiak 	return 0;
6755102ee87STony Krowiak }
6765102ee87STony Krowiak 
677e08b9637SCarsten Otte int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
678b0c632dbSHeiko Carstens {
679b0c632dbSHeiko Carstens 	int rc;
680b0c632dbSHeiko Carstens 	char debug_name[16];
681f6c137ffSChristian Borntraeger 	static unsigned long sca_offset;
682b0c632dbSHeiko Carstens 
683e08b9637SCarsten Otte 	rc = -EINVAL;
684e08b9637SCarsten Otte #ifdef CONFIG_KVM_S390_UCONTROL
685e08b9637SCarsten Otte 	if (type & ~KVM_VM_S390_UCONTROL)
686e08b9637SCarsten Otte 		goto out_err;
687e08b9637SCarsten Otte 	if ((type & KVM_VM_S390_UCONTROL) && (!capable(CAP_SYS_ADMIN)))
688e08b9637SCarsten Otte 		goto out_err;
689e08b9637SCarsten Otte #else
690e08b9637SCarsten Otte 	if (type)
691e08b9637SCarsten Otte 		goto out_err;
692e08b9637SCarsten Otte #endif
693e08b9637SCarsten Otte 
694b0c632dbSHeiko Carstens 	rc = s390_enable_sie();
695b0c632dbSHeiko Carstens 	if (rc)
696d89f5effSJan Kiszka 		goto out_err;
697b0c632dbSHeiko Carstens 
698b290411aSCarsten Otte 	rc = -ENOMEM;
699b290411aSCarsten Otte 
700b0c632dbSHeiko Carstens 	kvm->arch.sca = (struct sca_block *) get_zeroed_page(GFP_KERNEL);
701b0c632dbSHeiko Carstens 	if (!kvm->arch.sca)
702d89f5effSJan Kiszka 		goto out_err;
703f6c137ffSChristian Borntraeger 	spin_lock(&kvm_lock);
704f6c137ffSChristian Borntraeger 	sca_offset = (sca_offset + 16) & 0x7f0;
705f6c137ffSChristian Borntraeger 	kvm->arch.sca = (struct sca_block *) ((char *) kvm->arch.sca + sca_offset);
706f6c137ffSChristian Borntraeger 	spin_unlock(&kvm_lock);
707b0c632dbSHeiko Carstens 
708b0c632dbSHeiko Carstens 	sprintf(debug_name, "kvm-%u", current->pid);
709b0c632dbSHeiko Carstens 
710b0c632dbSHeiko Carstens 	kvm->arch.dbf = debug_register(debug_name, 8, 2, 8 * sizeof(long));
711b0c632dbSHeiko Carstens 	if (!kvm->arch.dbf)
712b0c632dbSHeiko Carstens 		goto out_nodbf;
713b0c632dbSHeiko Carstens 
7145102ee87STony Krowiak 	if (kvm_s390_crypto_init(kvm) < 0)
7155102ee87STony Krowiak 		goto out_crypto;
7165102ee87STony Krowiak 
717ba5c1e9bSCarsten Otte 	spin_lock_init(&kvm->arch.float_int.lock);
718ba5c1e9bSCarsten Otte 	INIT_LIST_HEAD(&kvm->arch.float_int.list);
7198a242234SHeiko Carstens 	init_waitqueue_head(&kvm->arch.ipte_wq);
720a6b7e459SThomas Huth 	mutex_init(&kvm->arch.ipte_mutex);
721ba5c1e9bSCarsten Otte 
722b0c632dbSHeiko Carstens 	debug_register_view(kvm->arch.dbf, &debug_sprintf_view);
723b0c632dbSHeiko Carstens 	VM_EVENT(kvm, 3, "%s", "vm created");
724b0c632dbSHeiko Carstens 
725e08b9637SCarsten Otte 	if (type & KVM_VM_S390_UCONTROL) {
726e08b9637SCarsten Otte 		kvm->arch.gmap = NULL;
727e08b9637SCarsten Otte 	} else {
7280349985aSChristian Borntraeger 		kvm->arch.gmap = gmap_alloc(current->mm, (1UL << 44) - 1);
729598841caSCarsten Otte 		if (!kvm->arch.gmap)
730598841caSCarsten Otte 			goto out_nogmap;
7312c70fe44SChristian Borntraeger 		kvm->arch.gmap->private = kvm;
73224eb3a82SDominik Dingel 		kvm->arch.gmap->pfault_enabled = 0;
733e08b9637SCarsten Otte 	}
734fa6b7fe9SCornelia Huck 
735fa6b7fe9SCornelia Huck 	kvm->arch.css_support = 0;
73684223598SCornelia Huck 	kvm->arch.use_irqchip = 0;
73772f25020SJason J. Herne 	kvm->arch.epoch = 0;
738fa6b7fe9SCornelia Huck 
7398ad35755SDavid Hildenbrand 	spin_lock_init(&kvm->arch.start_stop_lock);
7408ad35755SDavid Hildenbrand 
741d89f5effSJan Kiszka 	return 0;
742598841caSCarsten Otte out_nogmap:
7435102ee87STony Krowiak 	kfree(kvm->arch.crypto.crycb);
7445102ee87STony Krowiak out_crypto:
745598841caSCarsten Otte 	debug_unregister(kvm->arch.dbf);
746b0c632dbSHeiko Carstens out_nodbf:
747b0c632dbSHeiko Carstens 	free_page((unsigned long)(kvm->arch.sca));
748d89f5effSJan Kiszka out_err:
749d89f5effSJan Kiszka 	return rc;
750b0c632dbSHeiko Carstens }
751b0c632dbSHeiko Carstens 
752d329c035SChristian Borntraeger void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
753d329c035SChristian Borntraeger {
754d329c035SChristian Borntraeger 	VCPU_EVENT(vcpu, 3, "%s", "free cpu");
755ade38c31SCornelia Huck 	trace_kvm_s390_destroy_vcpu(vcpu->vcpu_id);
75667335e63SChristian Borntraeger 	kvm_s390_clear_local_irqs(vcpu);
7573c038e6bSDominik Dingel 	kvm_clear_async_pf_completion_queue(vcpu);
75858f9460bSCarsten Otte 	if (!kvm_is_ucontrol(vcpu->kvm)) {
75958f9460bSCarsten Otte 		clear_bit(63 - vcpu->vcpu_id,
76058f9460bSCarsten Otte 			  (unsigned long *) &vcpu->kvm->arch.sca->mcn);
761abf4a71eSCarsten Otte 		if (vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda ==
762abf4a71eSCarsten Otte 		    (__u64) vcpu->arch.sie_block)
763abf4a71eSCarsten Otte 			vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda = 0;
76458f9460bSCarsten Otte 	}
765abf4a71eSCarsten Otte 	smp_mb();
76627e0393fSCarsten Otte 
76727e0393fSCarsten Otte 	if (kvm_is_ucontrol(vcpu->kvm))
76827e0393fSCarsten Otte 		gmap_free(vcpu->arch.gmap);
76927e0393fSCarsten Otte 
770b31605c1SDominik Dingel 	if (kvm_s390_cmma_enabled(vcpu->kvm))
771b31605c1SDominik Dingel 		kvm_s390_vcpu_unsetup_cmma(vcpu);
772d329c035SChristian Borntraeger 	free_page((unsigned long)(vcpu->arch.sie_block));
773b31288faSKonstantin Weitz 
7746692cef3SChristian Borntraeger 	kvm_vcpu_uninit(vcpu);
775b110feafSMichael Mueller 	kmem_cache_free(kvm_vcpu_cache, vcpu);
776d329c035SChristian Borntraeger }
777d329c035SChristian Borntraeger 
778d329c035SChristian Borntraeger static void kvm_free_vcpus(struct kvm *kvm)
779d329c035SChristian Borntraeger {
780d329c035SChristian Borntraeger 	unsigned int i;
781988a2caeSGleb Natapov 	struct kvm_vcpu *vcpu;
782d329c035SChristian Borntraeger 
783988a2caeSGleb Natapov 	kvm_for_each_vcpu(i, vcpu, kvm)
784988a2caeSGleb Natapov 		kvm_arch_vcpu_destroy(vcpu);
785988a2caeSGleb Natapov 
786988a2caeSGleb Natapov 	mutex_lock(&kvm->lock);
787988a2caeSGleb Natapov 	for (i = 0; i < atomic_read(&kvm->online_vcpus); i++)
788d329c035SChristian Borntraeger 		kvm->vcpus[i] = NULL;
789988a2caeSGleb Natapov 
790988a2caeSGleb Natapov 	atomic_set(&kvm->online_vcpus, 0);
791988a2caeSGleb Natapov 	mutex_unlock(&kvm->lock);
792d329c035SChristian Borntraeger }
793d329c035SChristian Borntraeger 
794b0c632dbSHeiko Carstens void kvm_arch_destroy_vm(struct kvm *kvm)
795b0c632dbSHeiko Carstens {
796d329c035SChristian Borntraeger 	kvm_free_vcpus(kvm);
797b0c632dbSHeiko Carstens 	free_page((unsigned long)(kvm->arch.sca));
798d329c035SChristian Borntraeger 	debug_unregister(kvm->arch.dbf);
7995102ee87STony Krowiak 	kfree(kvm->arch.crypto.crycb);
80027e0393fSCarsten Otte 	if (!kvm_is_ucontrol(kvm))
801598841caSCarsten Otte 		gmap_free(kvm->arch.gmap);
802841b91c5SCornelia Huck 	kvm_s390_destroy_adapters(kvm);
80367335e63SChristian Borntraeger 	kvm_s390_clear_float_irqs(kvm);
804b0c632dbSHeiko Carstens }
805b0c632dbSHeiko Carstens 
806b0c632dbSHeiko Carstens /* Section: vcpu related */
807dafd032aSDominik Dingel static int __kvm_ucontrol_vcpu_init(struct kvm_vcpu *vcpu)
808b0c632dbSHeiko Carstens {
809c6c956b8SMartin Schwidefsky 	vcpu->arch.gmap = gmap_alloc(current->mm, -1UL);
81027e0393fSCarsten Otte 	if (!vcpu->arch.gmap)
81127e0393fSCarsten Otte 		return -ENOMEM;
8122c70fe44SChristian Borntraeger 	vcpu->arch.gmap->private = vcpu->kvm;
813dafd032aSDominik Dingel 
81427e0393fSCarsten Otte 	return 0;
81527e0393fSCarsten Otte }
81627e0393fSCarsten Otte 
817dafd032aSDominik Dingel int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
818dafd032aSDominik Dingel {
819dafd032aSDominik Dingel 	vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
820dafd032aSDominik Dingel 	kvm_clear_async_pf_completion_queue(vcpu);
82159674c1aSChristian Borntraeger 	vcpu->run->kvm_valid_regs = KVM_SYNC_PREFIX |
82259674c1aSChristian Borntraeger 				    KVM_SYNC_GPRS |
8239eed0735SChristian Borntraeger 				    KVM_SYNC_ACRS |
824b028ee3eSDavid Hildenbrand 				    KVM_SYNC_CRS |
825b028ee3eSDavid Hildenbrand 				    KVM_SYNC_ARCH0 |
826b028ee3eSDavid Hildenbrand 				    KVM_SYNC_PFAULT;
827dafd032aSDominik Dingel 
828dafd032aSDominik Dingel 	if (kvm_is_ucontrol(vcpu->kvm))
829dafd032aSDominik Dingel 		return __kvm_ucontrol_vcpu_init(vcpu);
830dafd032aSDominik Dingel 
831b0c632dbSHeiko Carstens 	return 0;
832b0c632dbSHeiko Carstens }
833b0c632dbSHeiko Carstens 
834b0c632dbSHeiko Carstens void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
835b0c632dbSHeiko Carstens {
8364725c860SMartin Schwidefsky 	save_fp_ctl(&vcpu->arch.host_fpregs.fpc);
8374725c860SMartin Schwidefsky 	save_fp_regs(vcpu->arch.host_fpregs.fprs);
838b0c632dbSHeiko Carstens 	save_access_regs(vcpu->arch.host_acrs);
8394725c860SMartin Schwidefsky 	restore_fp_ctl(&vcpu->arch.guest_fpregs.fpc);
8404725c860SMartin Schwidefsky 	restore_fp_regs(vcpu->arch.guest_fpregs.fprs);
84159674c1aSChristian Borntraeger 	restore_access_regs(vcpu->run->s.regs.acrs);
842480e5926SChristian Borntraeger 	gmap_enable(vcpu->arch.gmap);
8439e6dabefSCornelia Huck 	atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
844b0c632dbSHeiko Carstens }
845b0c632dbSHeiko Carstens 
846b0c632dbSHeiko Carstens void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
847b0c632dbSHeiko Carstens {
8489e6dabefSCornelia Huck 	atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
849480e5926SChristian Borntraeger 	gmap_disable(vcpu->arch.gmap);
8504725c860SMartin Schwidefsky 	save_fp_ctl(&vcpu->arch.guest_fpregs.fpc);
8514725c860SMartin Schwidefsky 	save_fp_regs(vcpu->arch.guest_fpregs.fprs);
85259674c1aSChristian Borntraeger 	save_access_regs(vcpu->run->s.regs.acrs);
8534725c860SMartin Schwidefsky 	restore_fp_ctl(&vcpu->arch.host_fpregs.fpc);
8544725c860SMartin Schwidefsky 	restore_fp_regs(vcpu->arch.host_fpregs.fprs);
855b0c632dbSHeiko Carstens 	restore_access_regs(vcpu->arch.host_acrs);
856b0c632dbSHeiko Carstens }
857b0c632dbSHeiko Carstens 
858b0c632dbSHeiko Carstens static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu)
859b0c632dbSHeiko Carstens {
860b0c632dbSHeiko Carstens 	/* this equals initial cpu reset in pop, but we don't switch to ESA */
861b0c632dbSHeiko Carstens 	vcpu->arch.sie_block->gpsw.mask = 0UL;
862b0c632dbSHeiko Carstens 	vcpu->arch.sie_block->gpsw.addr = 0UL;
8638d26cf7bSChristian Borntraeger 	kvm_s390_set_prefix(vcpu, 0);
864b0c632dbSHeiko Carstens 	vcpu->arch.sie_block->cputm     = 0UL;
865b0c632dbSHeiko Carstens 	vcpu->arch.sie_block->ckc       = 0UL;
866b0c632dbSHeiko Carstens 	vcpu->arch.sie_block->todpr     = 0;
867b0c632dbSHeiko Carstens 	memset(vcpu->arch.sie_block->gcr, 0, 16 * sizeof(__u64));
868b0c632dbSHeiko Carstens 	vcpu->arch.sie_block->gcr[0]  = 0xE0UL;
869b0c632dbSHeiko Carstens 	vcpu->arch.sie_block->gcr[14] = 0xC2000000UL;
870b0c632dbSHeiko Carstens 	vcpu->arch.guest_fpregs.fpc = 0;
871b0c632dbSHeiko Carstens 	asm volatile("lfpc %0" : : "Q" (vcpu->arch.guest_fpregs.fpc));
872b0c632dbSHeiko Carstens 	vcpu->arch.sie_block->gbea = 1;
873672550fbSChristian Borntraeger 	vcpu->arch.sie_block->pp = 0;
8743c038e6bSDominik Dingel 	vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
8753c038e6bSDominik Dingel 	kvm_clear_async_pf_completion_queue(vcpu);
8766352e4d2SDavid Hildenbrand 	if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm))
8776852d7b6SDavid Hildenbrand 		kvm_s390_vcpu_stop(vcpu);
8782ed10cc1SJens Freimann 	kvm_s390_clear_local_irqs(vcpu);
879b0c632dbSHeiko Carstens }
880b0c632dbSHeiko Carstens 
88131928aa5SDominik Dingel void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
88242897d86SMarcelo Tosatti {
88372f25020SJason J. Herne 	mutex_lock(&vcpu->kvm->lock);
88472f25020SJason J. Herne 	vcpu->arch.sie_block->epoch = vcpu->kvm->arch.epoch;
88572f25020SJason J. Herne 	mutex_unlock(&vcpu->kvm->lock);
886dafd032aSDominik Dingel 	if (!kvm_is_ucontrol(vcpu->kvm))
887dafd032aSDominik Dingel 		vcpu->arch.gmap = vcpu->kvm->arch.gmap;
88842897d86SMarcelo Tosatti }
88942897d86SMarcelo Tosatti 
8905102ee87STony Krowiak static void kvm_s390_vcpu_crypto_setup(struct kvm_vcpu *vcpu)
8915102ee87STony Krowiak {
8925102ee87STony Krowiak 	if (!test_vfacility(76))
8935102ee87STony Krowiak 		return;
8945102ee87STony Krowiak 
895a374e892STony Krowiak 	vcpu->arch.sie_block->ecb3 &= ~(ECB3_AES | ECB3_DEA);
896a374e892STony Krowiak 
897a374e892STony Krowiak 	if (vcpu->kvm->arch.crypto.aes_kw)
898a374e892STony Krowiak 		vcpu->arch.sie_block->ecb3 |= ECB3_AES;
899a374e892STony Krowiak 	if (vcpu->kvm->arch.crypto.dea_kw)
900a374e892STony Krowiak 		vcpu->arch.sie_block->ecb3 |= ECB3_DEA;
901a374e892STony Krowiak 
9025102ee87STony Krowiak 	vcpu->arch.sie_block->crycbd = vcpu->kvm->arch.crypto.crycbd;
9035102ee87STony Krowiak }
9045102ee87STony Krowiak 
905b31605c1SDominik Dingel void kvm_s390_vcpu_unsetup_cmma(struct kvm_vcpu *vcpu)
906b31605c1SDominik Dingel {
907b31605c1SDominik Dingel 	free_page(vcpu->arch.sie_block->cbrlo);
908b31605c1SDominik Dingel 	vcpu->arch.sie_block->cbrlo = 0;
909b31605c1SDominik Dingel }
910b31605c1SDominik Dingel 
911b31605c1SDominik Dingel int kvm_s390_vcpu_setup_cmma(struct kvm_vcpu *vcpu)
912b31605c1SDominik Dingel {
913b31605c1SDominik Dingel 	vcpu->arch.sie_block->cbrlo = get_zeroed_page(GFP_KERNEL);
914b31605c1SDominik Dingel 	if (!vcpu->arch.sie_block->cbrlo)
915b31605c1SDominik Dingel 		return -ENOMEM;
916b31605c1SDominik Dingel 
917b31605c1SDominik Dingel 	vcpu->arch.sie_block->ecb2 |= 0x80;
918b31605c1SDominik Dingel 	vcpu->arch.sie_block->ecb2 &= ~0x08;
919b31605c1SDominik Dingel 	return 0;
920b31605c1SDominik Dingel }
921b31605c1SDominik Dingel 
922b0c632dbSHeiko Carstens int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
923b0c632dbSHeiko Carstens {
924b31605c1SDominik Dingel 	int rc = 0;
925b31288faSKonstantin Weitz 
9269e6dabefSCornelia Huck 	atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH |
9279e6dabefSCornelia Huck 						    CPUSTAT_SM |
92869d0d3a3SChristian Borntraeger 						    CPUSTAT_STOPPED |
92969d0d3a3SChristian Borntraeger 						    CPUSTAT_GED);
930fc34531dSChristian Borntraeger 	vcpu->arch.sie_block->ecb   = 6;
9317feb6bb8SMichael Mueller 	if (test_vfacility(50) && test_vfacility(73))
9327feb6bb8SMichael Mueller 		vcpu->arch.sie_block->ecb |= 0x10;
9337feb6bb8SMichael Mueller 
93469d0d3a3SChristian Borntraeger 	vcpu->arch.sie_block->ecb2  = 8;
935ea5f4969SDavid Hildenbrand 	vcpu->arch.sie_block->eca   = 0xC1002000U;
936217a4406SHeiko Carstens 	if (sclp_has_siif())
937217a4406SHeiko Carstens 		vcpu->arch.sie_block->eca |= 1;
938ea5f4969SDavid Hildenbrand 	if (sclp_has_sigpif())
939ea5f4969SDavid Hildenbrand 		vcpu->arch.sie_block->eca |= 0x10000000U;
94078c4b59fSMichael Mueller 	vcpu->arch.sie_block->fac   = (int) (long) vfacilities;
9415a5e6536SMatthew Rosato 	vcpu->arch.sie_block->ictl |= ICTL_ISKE | ICTL_SSKE | ICTL_RRBE |
9425a5e6536SMatthew Rosato 				      ICTL_TPROT;
9435a5e6536SMatthew Rosato 
944b31605c1SDominik Dingel 	if (kvm_s390_cmma_enabled(vcpu->kvm)) {
945b31605c1SDominik Dingel 		rc = kvm_s390_vcpu_setup_cmma(vcpu);
946b31605c1SDominik Dingel 		if (rc)
947b31605c1SDominik Dingel 			return rc;
948b31288faSKonstantin Weitz 	}
9490ac96cafSDavid Hildenbrand 	hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
950ca872302SChristian Borntraeger 	vcpu->arch.ckc_timer.function = kvm_s390_idle_wakeup;
951453423dcSChristian Borntraeger 	get_cpu_id(&vcpu->arch.cpu_id);
95292e6ecf3SChristian Borntraeger 	vcpu->arch.cpu_id.version = 0xff;
9535102ee87STony Krowiak 
9545102ee87STony Krowiak 	kvm_s390_vcpu_crypto_setup(vcpu);
9555102ee87STony Krowiak 
956b31605c1SDominik Dingel 	return rc;
957b0c632dbSHeiko Carstens }
958b0c632dbSHeiko Carstens 
959b0c632dbSHeiko Carstens struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
960b0c632dbSHeiko Carstens 				      unsigned int id)
961b0c632dbSHeiko Carstens {
9624d47555aSCarsten Otte 	struct kvm_vcpu *vcpu;
9637feb6bb8SMichael Mueller 	struct sie_page *sie_page;
9644d47555aSCarsten Otte 	int rc = -EINVAL;
965b0c632dbSHeiko Carstens 
9664d47555aSCarsten Otte 	if (id >= KVM_MAX_VCPUS)
9674d47555aSCarsten Otte 		goto out;
9684d47555aSCarsten Otte 
9694d47555aSCarsten Otte 	rc = -ENOMEM;
9704d47555aSCarsten Otte 
971b110feafSMichael Mueller 	vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
972b0c632dbSHeiko Carstens 	if (!vcpu)
9734d47555aSCarsten Otte 		goto out;
974b0c632dbSHeiko Carstens 
9757feb6bb8SMichael Mueller 	sie_page = (struct sie_page *) get_zeroed_page(GFP_KERNEL);
9767feb6bb8SMichael Mueller 	if (!sie_page)
977b0c632dbSHeiko Carstens 		goto out_free_cpu;
978b0c632dbSHeiko Carstens 
9797feb6bb8SMichael Mueller 	vcpu->arch.sie_block = &sie_page->sie_block;
9807feb6bb8SMichael Mueller 	vcpu->arch.sie_block->itdba = (unsigned long) &sie_page->itdb;
9817feb6bb8SMichael Mueller 
982b0c632dbSHeiko Carstens 	vcpu->arch.sie_block->icpua = id;
98358f9460bSCarsten Otte 	if (!kvm_is_ucontrol(kvm)) {
98458f9460bSCarsten Otte 		if (!kvm->arch.sca) {
98558f9460bSCarsten Otte 			WARN_ON_ONCE(1);
98658f9460bSCarsten Otte 			goto out_free_cpu;
98758f9460bSCarsten Otte 		}
988abf4a71eSCarsten Otte 		if (!kvm->arch.sca->cpu[id].sda)
98958f9460bSCarsten Otte 			kvm->arch.sca->cpu[id].sda =
99058f9460bSCarsten Otte 				(__u64) vcpu->arch.sie_block;
99158f9460bSCarsten Otte 		vcpu->arch.sie_block->scaoh =
99258f9460bSCarsten Otte 			(__u32)(((__u64)kvm->arch.sca) >> 32);
993b0c632dbSHeiko Carstens 		vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca;
994fc34531dSChristian Borntraeger 		set_bit(63 - id, (unsigned long *) &kvm->arch.sca->mcn);
99558f9460bSCarsten Otte 	}
996b0c632dbSHeiko Carstens 
997ba5c1e9bSCarsten Otte 	spin_lock_init(&vcpu->arch.local_int.lock);
998ba5c1e9bSCarsten Otte 	vcpu->arch.local_int.float_int = &kvm->arch.float_int;
999d0321a24SChristian Borntraeger 	vcpu->arch.local_int.wq = &vcpu->wq;
10005288fbf0SChristian Borntraeger 	vcpu->arch.local_int.cpuflags = &vcpu->arch.sie_block->cpuflags;
1001ba5c1e9bSCarsten Otte 
1002b0c632dbSHeiko Carstens 	rc = kvm_vcpu_init(vcpu, kvm, id);
1003b0c632dbSHeiko Carstens 	if (rc)
10047b06bf2fSWei Yongjun 		goto out_free_sie_block;
1005b0c632dbSHeiko Carstens 	VM_EVENT(kvm, 3, "create cpu %d at %p, sie block at %p", id, vcpu,
1006b0c632dbSHeiko Carstens 		 vcpu->arch.sie_block);
1007ade38c31SCornelia Huck 	trace_kvm_s390_create_vcpu(id, vcpu, vcpu->arch.sie_block);
1008b0c632dbSHeiko Carstens 
1009b0c632dbSHeiko Carstens 	return vcpu;
10107b06bf2fSWei Yongjun out_free_sie_block:
10117b06bf2fSWei Yongjun 	free_page((unsigned long)(vcpu->arch.sie_block));
1012b0c632dbSHeiko Carstens out_free_cpu:
1013b110feafSMichael Mueller 	kmem_cache_free(kvm_vcpu_cache, vcpu);
10144d47555aSCarsten Otte out:
1015b0c632dbSHeiko Carstens 	return ERR_PTR(rc);
1016b0c632dbSHeiko Carstens }
1017b0c632dbSHeiko Carstens 
1018b0c632dbSHeiko Carstens int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
1019b0c632dbSHeiko Carstens {
10209a022067SDavid Hildenbrand 	return kvm_s390_vcpu_has_irq(vcpu, 0);
1021b0c632dbSHeiko Carstens }
1022b0c632dbSHeiko Carstens 
102349b99e1eSChristian Borntraeger void s390_vcpu_block(struct kvm_vcpu *vcpu)
102449b99e1eSChristian Borntraeger {
102549b99e1eSChristian Borntraeger 	atomic_set_mask(PROG_BLOCK_SIE, &vcpu->arch.sie_block->prog20);
102649b99e1eSChristian Borntraeger }
102749b99e1eSChristian Borntraeger 
102849b99e1eSChristian Borntraeger void s390_vcpu_unblock(struct kvm_vcpu *vcpu)
102949b99e1eSChristian Borntraeger {
103049b99e1eSChristian Borntraeger 	atomic_clear_mask(PROG_BLOCK_SIE, &vcpu->arch.sie_block->prog20);
103149b99e1eSChristian Borntraeger }
103249b99e1eSChristian Borntraeger 
103349b99e1eSChristian Borntraeger /*
103449b99e1eSChristian Borntraeger  * Kick a guest cpu out of SIE and wait until SIE is not running.
103549b99e1eSChristian Borntraeger  * If the CPU is not running (e.g. waiting as idle) the function will
103649b99e1eSChristian Borntraeger  * return immediately. */
103749b99e1eSChristian Borntraeger void exit_sie(struct kvm_vcpu *vcpu)
103849b99e1eSChristian Borntraeger {
103949b99e1eSChristian Borntraeger 	atomic_set_mask(CPUSTAT_STOP_INT, &vcpu->arch.sie_block->cpuflags);
104049b99e1eSChristian Borntraeger 	while (vcpu->arch.sie_block->prog0c & PROG_IN_SIE)
104149b99e1eSChristian Borntraeger 		cpu_relax();
104249b99e1eSChristian Borntraeger }
104349b99e1eSChristian Borntraeger 
104449b99e1eSChristian Borntraeger /* Kick a guest cpu out of SIE and prevent SIE-reentry */
104549b99e1eSChristian Borntraeger void exit_sie_sync(struct kvm_vcpu *vcpu)
104649b99e1eSChristian Borntraeger {
104749b99e1eSChristian Borntraeger 	s390_vcpu_block(vcpu);
104849b99e1eSChristian Borntraeger 	exit_sie(vcpu);
104949b99e1eSChristian Borntraeger }
105049b99e1eSChristian Borntraeger 
10512c70fe44SChristian Borntraeger static void kvm_gmap_notifier(struct gmap *gmap, unsigned long address)
10522c70fe44SChristian Borntraeger {
10532c70fe44SChristian Borntraeger 	int i;
10542c70fe44SChristian Borntraeger 	struct kvm *kvm = gmap->private;
10552c70fe44SChristian Borntraeger 	struct kvm_vcpu *vcpu;
10562c70fe44SChristian Borntraeger 
10572c70fe44SChristian Borntraeger 	kvm_for_each_vcpu(i, vcpu, kvm) {
10582c70fe44SChristian Borntraeger 		/* match against both prefix pages */
1059fda902cbSMichael Mueller 		if (kvm_s390_get_prefix(vcpu) == (address & ~0x1000UL)) {
10602c70fe44SChristian Borntraeger 			VCPU_EVENT(vcpu, 2, "gmap notifier for %lx", address);
10612c70fe44SChristian Borntraeger 			kvm_make_request(KVM_REQ_MMU_RELOAD, vcpu);
10622c70fe44SChristian Borntraeger 			exit_sie_sync(vcpu);
10632c70fe44SChristian Borntraeger 		}
10642c70fe44SChristian Borntraeger 	}
10652c70fe44SChristian Borntraeger }
10662c70fe44SChristian Borntraeger 
1067b6d33834SChristoffer Dall int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
1068b6d33834SChristoffer Dall {
1069b6d33834SChristoffer Dall 	/* kvm common code refers to this, but never calls it */
1070b6d33834SChristoffer Dall 	BUG();
1071b6d33834SChristoffer Dall 	return 0;
1072b6d33834SChristoffer Dall }
1073b6d33834SChristoffer Dall 
107414eebd91SCarsten Otte static int kvm_arch_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu,
107514eebd91SCarsten Otte 					   struct kvm_one_reg *reg)
107614eebd91SCarsten Otte {
107714eebd91SCarsten Otte 	int r = -EINVAL;
107814eebd91SCarsten Otte 
107914eebd91SCarsten Otte 	switch (reg->id) {
108029b7c71bSCarsten Otte 	case KVM_REG_S390_TODPR:
108129b7c71bSCarsten Otte 		r = put_user(vcpu->arch.sie_block->todpr,
108229b7c71bSCarsten Otte 			     (u32 __user *)reg->addr);
108329b7c71bSCarsten Otte 		break;
108429b7c71bSCarsten Otte 	case KVM_REG_S390_EPOCHDIFF:
108529b7c71bSCarsten Otte 		r = put_user(vcpu->arch.sie_block->epoch,
108629b7c71bSCarsten Otte 			     (u64 __user *)reg->addr);
108729b7c71bSCarsten Otte 		break;
108846a6dd1cSJason J. herne 	case KVM_REG_S390_CPU_TIMER:
108946a6dd1cSJason J. herne 		r = put_user(vcpu->arch.sie_block->cputm,
109046a6dd1cSJason J. herne 			     (u64 __user *)reg->addr);
109146a6dd1cSJason J. herne 		break;
109246a6dd1cSJason J. herne 	case KVM_REG_S390_CLOCK_COMP:
109346a6dd1cSJason J. herne 		r = put_user(vcpu->arch.sie_block->ckc,
109446a6dd1cSJason J. herne 			     (u64 __user *)reg->addr);
109546a6dd1cSJason J. herne 		break;
1096536336c2SDominik Dingel 	case KVM_REG_S390_PFTOKEN:
1097536336c2SDominik Dingel 		r = put_user(vcpu->arch.pfault_token,
1098536336c2SDominik Dingel 			     (u64 __user *)reg->addr);
1099536336c2SDominik Dingel 		break;
1100536336c2SDominik Dingel 	case KVM_REG_S390_PFCOMPARE:
1101536336c2SDominik Dingel 		r = put_user(vcpu->arch.pfault_compare,
1102536336c2SDominik Dingel 			     (u64 __user *)reg->addr);
1103536336c2SDominik Dingel 		break;
1104536336c2SDominik Dingel 	case KVM_REG_S390_PFSELECT:
1105536336c2SDominik Dingel 		r = put_user(vcpu->arch.pfault_select,
1106536336c2SDominik Dingel 			     (u64 __user *)reg->addr);
1107536336c2SDominik Dingel 		break;
1108672550fbSChristian Borntraeger 	case KVM_REG_S390_PP:
1109672550fbSChristian Borntraeger 		r = put_user(vcpu->arch.sie_block->pp,
1110672550fbSChristian Borntraeger 			     (u64 __user *)reg->addr);
1111672550fbSChristian Borntraeger 		break;
1112afa45ff5SChristian Borntraeger 	case KVM_REG_S390_GBEA:
1113afa45ff5SChristian Borntraeger 		r = put_user(vcpu->arch.sie_block->gbea,
1114afa45ff5SChristian Borntraeger 			     (u64 __user *)reg->addr);
1115afa45ff5SChristian Borntraeger 		break;
111614eebd91SCarsten Otte 	default:
111714eebd91SCarsten Otte 		break;
111814eebd91SCarsten Otte 	}
111914eebd91SCarsten Otte 
112014eebd91SCarsten Otte 	return r;
112114eebd91SCarsten Otte }
112214eebd91SCarsten Otte 
112314eebd91SCarsten Otte static int kvm_arch_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu,
112414eebd91SCarsten Otte 					   struct kvm_one_reg *reg)
112514eebd91SCarsten Otte {
112614eebd91SCarsten Otte 	int r = -EINVAL;
112714eebd91SCarsten Otte 
112814eebd91SCarsten Otte 	switch (reg->id) {
112929b7c71bSCarsten Otte 	case KVM_REG_S390_TODPR:
113029b7c71bSCarsten Otte 		r = get_user(vcpu->arch.sie_block->todpr,
113129b7c71bSCarsten Otte 			     (u32 __user *)reg->addr);
113229b7c71bSCarsten Otte 		break;
113329b7c71bSCarsten Otte 	case KVM_REG_S390_EPOCHDIFF:
113429b7c71bSCarsten Otte 		r = get_user(vcpu->arch.sie_block->epoch,
113529b7c71bSCarsten Otte 			     (u64 __user *)reg->addr);
113629b7c71bSCarsten Otte 		break;
113746a6dd1cSJason J. herne 	case KVM_REG_S390_CPU_TIMER:
113846a6dd1cSJason J. herne 		r = get_user(vcpu->arch.sie_block->cputm,
113946a6dd1cSJason J. herne 			     (u64 __user *)reg->addr);
114046a6dd1cSJason J. herne 		break;
114146a6dd1cSJason J. herne 	case KVM_REG_S390_CLOCK_COMP:
114246a6dd1cSJason J. herne 		r = get_user(vcpu->arch.sie_block->ckc,
114346a6dd1cSJason J. herne 			     (u64 __user *)reg->addr);
114446a6dd1cSJason J. herne 		break;
1145536336c2SDominik Dingel 	case KVM_REG_S390_PFTOKEN:
1146536336c2SDominik Dingel 		r = get_user(vcpu->arch.pfault_token,
1147536336c2SDominik Dingel 			     (u64 __user *)reg->addr);
11489fbd8082SDavid Hildenbrand 		if (vcpu->arch.pfault_token == KVM_S390_PFAULT_TOKEN_INVALID)
11499fbd8082SDavid Hildenbrand 			kvm_clear_async_pf_completion_queue(vcpu);
1150536336c2SDominik Dingel 		break;
1151536336c2SDominik Dingel 	case KVM_REG_S390_PFCOMPARE:
1152536336c2SDominik Dingel 		r = get_user(vcpu->arch.pfault_compare,
1153536336c2SDominik Dingel 			     (u64 __user *)reg->addr);
1154536336c2SDominik Dingel 		break;
1155536336c2SDominik Dingel 	case KVM_REG_S390_PFSELECT:
1156536336c2SDominik Dingel 		r = get_user(vcpu->arch.pfault_select,
1157536336c2SDominik Dingel 			     (u64 __user *)reg->addr);
1158536336c2SDominik Dingel 		break;
1159672550fbSChristian Borntraeger 	case KVM_REG_S390_PP:
1160672550fbSChristian Borntraeger 		r = get_user(vcpu->arch.sie_block->pp,
1161672550fbSChristian Borntraeger 			     (u64 __user *)reg->addr);
1162672550fbSChristian Borntraeger 		break;
1163afa45ff5SChristian Borntraeger 	case KVM_REG_S390_GBEA:
1164afa45ff5SChristian Borntraeger 		r = get_user(vcpu->arch.sie_block->gbea,
1165afa45ff5SChristian Borntraeger 			     (u64 __user *)reg->addr);
1166afa45ff5SChristian Borntraeger 		break;
116714eebd91SCarsten Otte 	default:
116814eebd91SCarsten Otte 		break;
116914eebd91SCarsten Otte 	}
117014eebd91SCarsten Otte 
117114eebd91SCarsten Otte 	return r;
117214eebd91SCarsten Otte }
1173b6d33834SChristoffer Dall 
1174b0c632dbSHeiko Carstens static int kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu)
1175b0c632dbSHeiko Carstens {
1176b0c632dbSHeiko Carstens 	kvm_s390_vcpu_initial_reset(vcpu);
1177b0c632dbSHeiko Carstens 	return 0;
1178b0c632dbSHeiko Carstens }
1179b0c632dbSHeiko Carstens 
1180b0c632dbSHeiko Carstens int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
1181b0c632dbSHeiko Carstens {
11825a32c1afSChristian Borntraeger 	memcpy(&vcpu->run->s.regs.gprs, &regs->gprs, sizeof(regs->gprs));
1183b0c632dbSHeiko Carstens 	return 0;
1184b0c632dbSHeiko Carstens }
1185b0c632dbSHeiko Carstens 
1186b0c632dbSHeiko Carstens int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
1187b0c632dbSHeiko Carstens {
11885a32c1afSChristian Borntraeger 	memcpy(&regs->gprs, &vcpu->run->s.regs.gprs, sizeof(regs->gprs));
1189b0c632dbSHeiko Carstens 	return 0;
1190b0c632dbSHeiko Carstens }
1191b0c632dbSHeiko Carstens 
1192b0c632dbSHeiko Carstens int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
1193b0c632dbSHeiko Carstens 				  struct kvm_sregs *sregs)
1194b0c632dbSHeiko Carstens {
119559674c1aSChristian Borntraeger 	memcpy(&vcpu->run->s.regs.acrs, &sregs->acrs, sizeof(sregs->acrs));
1196b0c632dbSHeiko Carstens 	memcpy(&vcpu->arch.sie_block->gcr, &sregs->crs, sizeof(sregs->crs));
119759674c1aSChristian Borntraeger 	restore_access_regs(vcpu->run->s.regs.acrs);
1198b0c632dbSHeiko Carstens 	return 0;
1199b0c632dbSHeiko Carstens }
1200b0c632dbSHeiko Carstens 
1201b0c632dbSHeiko Carstens int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
1202b0c632dbSHeiko Carstens 				  struct kvm_sregs *sregs)
1203b0c632dbSHeiko Carstens {
120459674c1aSChristian Borntraeger 	memcpy(&sregs->acrs, &vcpu->run->s.regs.acrs, sizeof(sregs->acrs));
1205b0c632dbSHeiko Carstens 	memcpy(&sregs->crs, &vcpu->arch.sie_block->gcr, sizeof(sregs->crs));
1206b0c632dbSHeiko Carstens 	return 0;
1207b0c632dbSHeiko Carstens }
1208b0c632dbSHeiko Carstens 
1209b0c632dbSHeiko Carstens int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
1210b0c632dbSHeiko Carstens {
12114725c860SMartin Schwidefsky 	if (test_fp_ctl(fpu->fpc))
12124725c860SMartin Schwidefsky 		return -EINVAL;
1213b0c632dbSHeiko Carstens 	memcpy(&vcpu->arch.guest_fpregs.fprs, &fpu->fprs, sizeof(fpu->fprs));
12144725c860SMartin Schwidefsky 	vcpu->arch.guest_fpregs.fpc = fpu->fpc;
12154725c860SMartin Schwidefsky 	restore_fp_ctl(&vcpu->arch.guest_fpregs.fpc);
12164725c860SMartin Schwidefsky 	restore_fp_regs(vcpu->arch.guest_fpregs.fprs);
1217b0c632dbSHeiko Carstens 	return 0;
1218b0c632dbSHeiko Carstens }
1219b0c632dbSHeiko Carstens 
1220b0c632dbSHeiko Carstens int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
1221b0c632dbSHeiko Carstens {
1222b0c632dbSHeiko Carstens 	memcpy(&fpu->fprs, &vcpu->arch.guest_fpregs.fprs, sizeof(fpu->fprs));
1223b0c632dbSHeiko Carstens 	fpu->fpc = vcpu->arch.guest_fpregs.fpc;
1224b0c632dbSHeiko Carstens 	return 0;
1225b0c632dbSHeiko Carstens }
1226b0c632dbSHeiko Carstens 
1227b0c632dbSHeiko Carstens static int kvm_arch_vcpu_ioctl_set_initial_psw(struct kvm_vcpu *vcpu, psw_t psw)
1228b0c632dbSHeiko Carstens {
1229b0c632dbSHeiko Carstens 	int rc = 0;
1230b0c632dbSHeiko Carstens 
12317a42fdc2SDavid Hildenbrand 	if (!is_vcpu_stopped(vcpu))
1232b0c632dbSHeiko Carstens 		rc = -EBUSY;
1233d7b0b5ebSCarsten Otte 	else {
1234d7b0b5ebSCarsten Otte 		vcpu->run->psw_mask = psw.mask;
1235d7b0b5ebSCarsten Otte 		vcpu->run->psw_addr = psw.addr;
1236d7b0b5ebSCarsten Otte 	}
1237b0c632dbSHeiko Carstens 	return rc;
1238b0c632dbSHeiko Carstens }
1239b0c632dbSHeiko Carstens 
1240b0c632dbSHeiko Carstens int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
1241b0c632dbSHeiko Carstens 				  struct kvm_translation *tr)
1242b0c632dbSHeiko Carstens {
1243b0c632dbSHeiko Carstens 	return -EINVAL; /* not implemented yet */
1244b0c632dbSHeiko Carstens }
1245b0c632dbSHeiko Carstens 
124627291e21SDavid Hildenbrand #define VALID_GUESTDBG_FLAGS (KVM_GUESTDBG_SINGLESTEP | \
124727291e21SDavid Hildenbrand 			      KVM_GUESTDBG_USE_HW_BP | \
124827291e21SDavid Hildenbrand 			      KVM_GUESTDBG_ENABLE)
124927291e21SDavid Hildenbrand 
1250d0bfb940SJan Kiszka int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
1251d0bfb940SJan Kiszka 					struct kvm_guest_debug *dbg)
1252b0c632dbSHeiko Carstens {
125327291e21SDavid Hildenbrand 	int rc = 0;
125427291e21SDavid Hildenbrand 
125527291e21SDavid Hildenbrand 	vcpu->guest_debug = 0;
125627291e21SDavid Hildenbrand 	kvm_s390_clear_bp_data(vcpu);
125727291e21SDavid Hildenbrand 
12582de3bfc2SDavid Hildenbrand 	if (dbg->control & ~VALID_GUESTDBG_FLAGS)
125927291e21SDavid Hildenbrand 		return -EINVAL;
126027291e21SDavid Hildenbrand 
126127291e21SDavid Hildenbrand 	if (dbg->control & KVM_GUESTDBG_ENABLE) {
126227291e21SDavid Hildenbrand 		vcpu->guest_debug = dbg->control;
126327291e21SDavid Hildenbrand 		/* enforce guest PER */
126427291e21SDavid Hildenbrand 		atomic_set_mask(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags);
126527291e21SDavid Hildenbrand 
126627291e21SDavid Hildenbrand 		if (dbg->control & KVM_GUESTDBG_USE_HW_BP)
126727291e21SDavid Hildenbrand 			rc = kvm_s390_import_bp_data(vcpu, dbg);
126827291e21SDavid Hildenbrand 	} else {
126927291e21SDavid Hildenbrand 		atomic_clear_mask(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags);
127027291e21SDavid Hildenbrand 		vcpu->arch.guestdbg.last_bp = 0;
127127291e21SDavid Hildenbrand 	}
127227291e21SDavid Hildenbrand 
127327291e21SDavid Hildenbrand 	if (rc) {
127427291e21SDavid Hildenbrand 		vcpu->guest_debug = 0;
127527291e21SDavid Hildenbrand 		kvm_s390_clear_bp_data(vcpu);
127627291e21SDavid Hildenbrand 		atomic_clear_mask(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags);
127727291e21SDavid Hildenbrand 	}
127827291e21SDavid Hildenbrand 
127927291e21SDavid Hildenbrand 	return rc;
1280b0c632dbSHeiko Carstens }
1281b0c632dbSHeiko Carstens 
128262d9f0dbSMarcelo Tosatti int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
128362d9f0dbSMarcelo Tosatti 				    struct kvm_mp_state *mp_state)
128462d9f0dbSMarcelo Tosatti {
12856352e4d2SDavid Hildenbrand 	/* CHECK_STOP and LOAD are not supported yet */
12866352e4d2SDavid Hildenbrand 	return is_vcpu_stopped(vcpu) ? KVM_MP_STATE_STOPPED :
12876352e4d2SDavid Hildenbrand 				       KVM_MP_STATE_OPERATING;
128862d9f0dbSMarcelo Tosatti }
128962d9f0dbSMarcelo Tosatti 
129062d9f0dbSMarcelo Tosatti int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
129162d9f0dbSMarcelo Tosatti 				    struct kvm_mp_state *mp_state)
129262d9f0dbSMarcelo Tosatti {
12936352e4d2SDavid Hildenbrand 	int rc = 0;
12946352e4d2SDavid Hildenbrand 
12956352e4d2SDavid Hildenbrand 	/* user space knows about this interface - let it control the state */
12966352e4d2SDavid Hildenbrand 	vcpu->kvm->arch.user_cpu_state_ctrl = 1;
12976352e4d2SDavid Hildenbrand 
12986352e4d2SDavid Hildenbrand 	switch (mp_state->mp_state) {
12996352e4d2SDavid Hildenbrand 	case KVM_MP_STATE_STOPPED:
13006352e4d2SDavid Hildenbrand 		kvm_s390_vcpu_stop(vcpu);
13016352e4d2SDavid Hildenbrand 		break;
13026352e4d2SDavid Hildenbrand 	case KVM_MP_STATE_OPERATING:
13036352e4d2SDavid Hildenbrand 		kvm_s390_vcpu_start(vcpu);
13046352e4d2SDavid Hildenbrand 		break;
13056352e4d2SDavid Hildenbrand 	case KVM_MP_STATE_LOAD:
13066352e4d2SDavid Hildenbrand 	case KVM_MP_STATE_CHECK_STOP:
13076352e4d2SDavid Hildenbrand 		/* fall through - CHECK_STOP and LOAD are not supported yet */
13086352e4d2SDavid Hildenbrand 	default:
13096352e4d2SDavid Hildenbrand 		rc = -ENXIO;
13106352e4d2SDavid Hildenbrand 	}
13116352e4d2SDavid Hildenbrand 
13126352e4d2SDavid Hildenbrand 	return rc;
131362d9f0dbSMarcelo Tosatti }
131462d9f0dbSMarcelo Tosatti 
1315b31605c1SDominik Dingel bool kvm_s390_cmma_enabled(struct kvm *kvm)
1316b31605c1SDominik Dingel {
1317b31605c1SDominik Dingel 	if (!MACHINE_IS_LPAR)
1318b31605c1SDominik Dingel 		return false;
1319b31605c1SDominik Dingel 	/* only enable for z10 and later */
1320b31605c1SDominik Dingel 	if (!MACHINE_HAS_EDAT1)
1321b31605c1SDominik Dingel 		return false;
1322b31605c1SDominik Dingel 	if (!kvm->arch.use_cmma)
1323b31605c1SDominik Dingel 		return false;
1324b31605c1SDominik Dingel 	return true;
1325b31605c1SDominik Dingel }
1326b31605c1SDominik Dingel 
13278ad35755SDavid Hildenbrand static bool ibs_enabled(struct kvm_vcpu *vcpu)
13288ad35755SDavid Hildenbrand {
13298ad35755SDavid Hildenbrand 	return atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_IBS;
13308ad35755SDavid Hildenbrand }
13318ad35755SDavid Hildenbrand 
13322c70fe44SChristian Borntraeger static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu)
13332c70fe44SChristian Borntraeger {
13348ad35755SDavid Hildenbrand retry:
13358ad35755SDavid Hildenbrand 	s390_vcpu_unblock(vcpu);
13362c70fe44SChristian Borntraeger 	/*
13372c70fe44SChristian Borntraeger 	 * We use MMU_RELOAD just to re-arm the ipte notifier for the
13382c70fe44SChristian Borntraeger 	 * guest prefix page. gmap_ipte_notify will wait on the ptl lock.
13392c70fe44SChristian Borntraeger 	 * This ensures that the ipte instruction for this request has
13402c70fe44SChristian Borntraeger 	 * already finished. We might race against a second unmapper that
13412c70fe44SChristian Borntraeger 	 * wants to set the blocking bit. Lets just retry the request loop.
13422c70fe44SChristian Borntraeger 	 */
13438ad35755SDavid Hildenbrand 	if (kvm_check_request(KVM_REQ_MMU_RELOAD, vcpu)) {
13442c70fe44SChristian Borntraeger 		int rc;
13452c70fe44SChristian Borntraeger 		rc = gmap_ipte_notify(vcpu->arch.gmap,
1346fda902cbSMichael Mueller 				      kvm_s390_get_prefix(vcpu),
13472c70fe44SChristian Borntraeger 				      PAGE_SIZE * 2);
13482c70fe44SChristian Borntraeger 		if (rc)
13492c70fe44SChristian Borntraeger 			return rc;
13508ad35755SDavid Hildenbrand 		goto retry;
13512c70fe44SChristian Borntraeger 	}
13528ad35755SDavid Hildenbrand 
1353d3d692c8SDavid Hildenbrand 	if (kvm_check_request(KVM_REQ_TLB_FLUSH, vcpu)) {
1354d3d692c8SDavid Hildenbrand 		vcpu->arch.sie_block->ihcpu = 0xffff;
1355d3d692c8SDavid Hildenbrand 		goto retry;
1356d3d692c8SDavid Hildenbrand 	}
1357d3d692c8SDavid Hildenbrand 
13588ad35755SDavid Hildenbrand 	if (kvm_check_request(KVM_REQ_ENABLE_IBS, vcpu)) {
13598ad35755SDavid Hildenbrand 		if (!ibs_enabled(vcpu)) {
13608ad35755SDavid Hildenbrand 			trace_kvm_s390_enable_disable_ibs(vcpu->vcpu_id, 1);
13618ad35755SDavid Hildenbrand 			atomic_set_mask(CPUSTAT_IBS,
13628ad35755SDavid Hildenbrand 					&vcpu->arch.sie_block->cpuflags);
13638ad35755SDavid Hildenbrand 		}
13648ad35755SDavid Hildenbrand 		goto retry;
13658ad35755SDavid Hildenbrand 	}
13668ad35755SDavid Hildenbrand 
13678ad35755SDavid Hildenbrand 	if (kvm_check_request(KVM_REQ_DISABLE_IBS, vcpu)) {
13688ad35755SDavid Hildenbrand 		if (ibs_enabled(vcpu)) {
13698ad35755SDavid Hildenbrand 			trace_kvm_s390_enable_disable_ibs(vcpu->vcpu_id, 0);
13708ad35755SDavid Hildenbrand 			atomic_clear_mask(CPUSTAT_IBS,
13718ad35755SDavid Hildenbrand 					  &vcpu->arch.sie_block->cpuflags);
13728ad35755SDavid Hildenbrand 		}
13738ad35755SDavid Hildenbrand 		goto retry;
13748ad35755SDavid Hildenbrand 	}
13758ad35755SDavid Hildenbrand 
13760759d068SDavid Hildenbrand 	/* nothing to do, just clear the request */
13770759d068SDavid Hildenbrand 	clear_bit(KVM_REQ_UNHALT, &vcpu->requests);
13780759d068SDavid Hildenbrand 
13792c70fe44SChristian Borntraeger 	return 0;
13802c70fe44SChristian Borntraeger }
13812c70fe44SChristian Borntraeger 
1382fa576c58SThomas Huth /**
1383fa576c58SThomas Huth  * kvm_arch_fault_in_page - fault-in guest page if necessary
1384fa576c58SThomas Huth  * @vcpu: The corresponding virtual cpu
1385fa576c58SThomas Huth  * @gpa: Guest physical address
1386fa576c58SThomas Huth  * @writable: Whether the page should be writable or not
1387fa576c58SThomas Huth  *
1388fa576c58SThomas Huth  * Make sure that a guest page has been faulted-in on the host.
1389fa576c58SThomas Huth  *
1390fa576c58SThomas Huth  * Return: Zero on success, negative error code otherwise.
1391fa576c58SThomas Huth  */
1392fa576c58SThomas Huth long kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int writable)
139324eb3a82SDominik Dingel {
1394527e30b4SMartin Schwidefsky 	return gmap_fault(vcpu->arch.gmap, gpa,
1395527e30b4SMartin Schwidefsky 			  writable ? FAULT_FLAG_WRITE : 0);
139624eb3a82SDominik Dingel }
139724eb3a82SDominik Dingel 
13983c038e6bSDominik Dingel static void __kvm_inject_pfault_token(struct kvm_vcpu *vcpu, bool start_token,
13993c038e6bSDominik Dingel 				      unsigned long token)
14003c038e6bSDominik Dingel {
14013c038e6bSDominik Dingel 	struct kvm_s390_interrupt inti;
1402383d0b05SJens Freimann 	struct kvm_s390_irq irq;
14033c038e6bSDominik Dingel 
14043c038e6bSDominik Dingel 	if (start_token) {
1405383d0b05SJens Freimann 		irq.u.ext.ext_params2 = token;
1406383d0b05SJens Freimann 		irq.type = KVM_S390_INT_PFAULT_INIT;
1407383d0b05SJens Freimann 		WARN_ON_ONCE(kvm_s390_inject_vcpu(vcpu, &irq));
14083c038e6bSDominik Dingel 	} else {
14093c038e6bSDominik Dingel 		inti.type = KVM_S390_INT_PFAULT_DONE;
1410383d0b05SJens Freimann 		inti.parm64 = token;
14113c038e6bSDominik Dingel 		WARN_ON_ONCE(kvm_s390_inject_vm(vcpu->kvm, &inti));
14123c038e6bSDominik Dingel 	}
14133c038e6bSDominik Dingel }
14143c038e6bSDominik Dingel 
14153c038e6bSDominik Dingel void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
14163c038e6bSDominik Dingel 				     struct kvm_async_pf *work)
14173c038e6bSDominik Dingel {
14183c038e6bSDominik Dingel 	trace_kvm_s390_pfault_init(vcpu, work->arch.pfault_token);
14193c038e6bSDominik Dingel 	__kvm_inject_pfault_token(vcpu, true, work->arch.pfault_token);
14203c038e6bSDominik Dingel }
14213c038e6bSDominik Dingel 
14223c038e6bSDominik Dingel void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,
14233c038e6bSDominik Dingel 				 struct kvm_async_pf *work)
14243c038e6bSDominik Dingel {
14253c038e6bSDominik Dingel 	trace_kvm_s390_pfault_done(vcpu, work->arch.pfault_token);
14263c038e6bSDominik Dingel 	__kvm_inject_pfault_token(vcpu, false, work->arch.pfault_token);
14273c038e6bSDominik Dingel }
14283c038e6bSDominik Dingel 
14293c038e6bSDominik Dingel void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu,
14303c038e6bSDominik Dingel 			       struct kvm_async_pf *work)
14313c038e6bSDominik Dingel {
14323c038e6bSDominik Dingel 	/* s390 will always inject the page directly */
14333c038e6bSDominik Dingel }
14343c038e6bSDominik Dingel 
14353c038e6bSDominik Dingel bool kvm_arch_can_inject_async_page_present(struct kvm_vcpu *vcpu)
14363c038e6bSDominik Dingel {
14373c038e6bSDominik Dingel 	/*
14383c038e6bSDominik Dingel 	 * s390 will always inject the page directly,
14393c038e6bSDominik Dingel 	 * but we still want check_async_completion to cleanup
14403c038e6bSDominik Dingel 	 */
14413c038e6bSDominik Dingel 	return true;
14423c038e6bSDominik Dingel }
14433c038e6bSDominik Dingel 
14443c038e6bSDominik Dingel static int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu)
14453c038e6bSDominik Dingel {
14463c038e6bSDominik Dingel 	hva_t hva;
14473c038e6bSDominik Dingel 	struct kvm_arch_async_pf arch;
14483c038e6bSDominik Dingel 	int rc;
14493c038e6bSDominik Dingel 
14503c038e6bSDominik Dingel 	if (vcpu->arch.pfault_token == KVM_S390_PFAULT_TOKEN_INVALID)
14513c038e6bSDominik Dingel 		return 0;
14523c038e6bSDominik Dingel 	if ((vcpu->arch.sie_block->gpsw.mask & vcpu->arch.pfault_select) !=
14533c038e6bSDominik Dingel 	    vcpu->arch.pfault_compare)
14543c038e6bSDominik Dingel 		return 0;
14553c038e6bSDominik Dingel 	if (psw_extint_disabled(vcpu))
14563c038e6bSDominik Dingel 		return 0;
14579a022067SDavid Hildenbrand 	if (kvm_s390_vcpu_has_irq(vcpu, 0))
14583c038e6bSDominik Dingel 		return 0;
14593c038e6bSDominik Dingel 	if (!(vcpu->arch.sie_block->gcr[0] & 0x200ul))
14603c038e6bSDominik Dingel 		return 0;
14613c038e6bSDominik Dingel 	if (!vcpu->arch.gmap->pfault_enabled)
14623c038e6bSDominik Dingel 		return 0;
14633c038e6bSDominik Dingel 
146481480cc1SHeiko Carstens 	hva = gfn_to_hva(vcpu->kvm, gpa_to_gfn(current->thread.gmap_addr));
146581480cc1SHeiko Carstens 	hva += current->thread.gmap_addr & ~PAGE_MASK;
146681480cc1SHeiko Carstens 	if (read_guest_real(vcpu, vcpu->arch.pfault_token, &arch.pfault_token, 8))
14673c038e6bSDominik Dingel 		return 0;
14683c038e6bSDominik Dingel 
14693c038e6bSDominik Dingel 	rc = kvm_setup_async_pf(vcpu, current->thread.gmap_addr, hva, &arch);
14703c038e6bSDominik Dingel 	return rc;
14713c038e6bSDominik Dingel }
14723c038e6bSDominik Dingel 
14733fb4c40fSThomas Huth static int vcpu_pre_run(struct kvm_vcpu *vcpu)
1474b0c632dbSHeiko Carstens {
14753fb4c40fSThomas Huth 	int rc, cpuflags;
1476e168bf8dSCarsten Otte 
14773c038e6bSDominik Dingel 	/*
14783c038e6bSDominik Dingel 	 * On s390 notifications for arriving pages will be delivered directly
14793c038e6bSDominik Dingel 	 * to the guest but the house keeping for completed pfaults is
14803c038e6bSDominik Dingel 	 * handled outside the worker.
14813c038e6bSDominik Dingel 	 */
14823c038e6bSDominik Dingel 	kvm_check_async_pf_completion(vcpu);
14833c038e6bSDominik Dingel 
14845a32c1afSChristian Borntraeger 	memcpy(&vcpu->arch.sie_block->gg14, &vcpu->run->s.regs.gprs[14], 16);
1485b0c632dbSHeiko Carstens 
1486b0c632dbSHeiko Carstens 	if (need_resched())
1487b0c632dbSHeiko Carstens 		schedule();
1488b0c632dbSHeiko Carstens 
1489d3a73acbSMartin Schwidefsky 	if (test_cpu_flag(CIF_MCCK_PENDING))
149071cde587SChristian Borntraeger 		s390_handle_mcck();
149171cde587SChristian Borntraeger 
149279395031SJens Freimann 	if (!kvm_is_ucontrol(vcpu->kvm)) {
149379395031SJens Freimann 		rc = kvm_s390_deliver_pending_interrupts(vcpu);
149479395031SJens Freimann 		if (rc)
149579395031SJens Freimann 			return rc;
149679395031SJens Freimann 	}
14970ff31867SCarsten Otte 
14982c70fe44SChristian Borntraeger 	rc = kvm_s390_handle_requests(vcpu);
14992c70fe44SChristian Borntraeger 	if (rc)
15002c70fe44SChristian Borntraeger 		return rc;
15012c70fe44SChristian Borntraeger 
150227291e21SDavid Hildenbrand 	if (guestdbg_enabled(vcpu)) {
150327291e21SDavid Hildenbrand 		kvm_s390_backup_guest_per_regs(vcpu);
150427291e21SDavid Hildenbrand 		kvm_s390_patch_guest_per_regs(vcpu);
150527291e21SDavid Hildenbrand 	}
150627291e21SDavid Hildenbrand 
1507b0c632dbSHeiko Carstens 	vcpu->arch.sie_block->icptcode = 0;
15083fb4c40fSThomas Huth 	cpuflags = atomic_read(&vcpu->arch.sie_block->cpuflags);
15093fb4c40fSThomas Huth 	VCPU_EVENT(vcpu, 6, "entering sie flags %x", cpuflags);
15103fb4c40fSThomas Huth 	trace_kvm_s390_sie_enter(vcpu, cpuflags);
15112b29a9fdSDominik Dingel 
15123fb4c40fSThomas Huth 	return 0;
15133fb4c40fSThomas Huth }
15143fb4c40fSThomas Huth 
15153fb4c40fSThomas Huth static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
15163fb4c40fSThomas Huth {
151724eb3a82SDominik Dingel 	int rc = -1;
15182b29a9fdSDominik Dingel 
15192b29a9fdSDominik Dingel 	VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
15202b29a9fdSDominik Dingel 		   vcpu->arch.sie_block->icptcode);
15212b29a9fdSDominik Dingel 	trace_kvm_s390_sie_exit(vcpu, vcpu->arch.sie_block->icptcode);
15222b29a9fdSDominik Dingel 
152327291e21SDavid Hildenbrand 	if (guestdbg_enabled(vcpu))
152427291e21SDavid Hildenbrand 		kvm_s390_restore_guest_per_regs(vcpu);
152527291e21SDavid Hildenbrand 
15263fb4c40fSThomas Huth 	if (exit_reason >= 0) {
15277c470539SMartin Schwidefsky 		rc = 0;
1528210b1607SThomas Huth 	} else if (kvm_is_ucontrol(vcpu->kvm)) {
1529210b1607SThomas Huth 		vcpu->run->exit_reason = KVM_EXIT_S390_UCONTROL;
1530210b1607SThomas Huth 		vcpu->run->s390_ucontrol.trans_exc_code =
1531210b1607SThomas Huth 						current->thread.gmap_addr;
1532210b1607SThomas Huth 		vcpu->run->s390_ucontrol.pgm_code = 0x10;
1533210b1607SThomas Huth 		rc = -EREMOTE;
153424eb3a82SDominik Dingel 
153524eb3a82SDominik Dingel 	} else if (current->thread.gmap_pfault) {
15363c038e6bSDominik Dingel 		trace_kvm_s390_major_guest_pfault(vcpu);
153724eb3a82SDominik Dingel 		current->thread.gmap_pfault = 0;
1538fa576c58SThomas Huth 		if (kvm_arch_setup_async_pf(vcpu)) {
153924eb3a82SDominik Dingel 			rc = 0;
1540fa576c58SThomas Huth 		} else {
1541fa576c58SThomas Huth 			gpa_t gpa = current->thread.gmap_addr;
1542fa576c58SThomas Huth 			rc = kvm_arch_fault_in_page(vcpu, gpa, 1);
1543fa576c58SThomas Huth 		}
154424eb3a82SDominik Dingel 	}
154524eb3a82SDominik Dingel 
154624eb3a82SDominik Dingel 	if (rc == -1) {
1547699bde3bSChristian Borntraeger 		VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction");
1548699bde3bSChristian Borntraeger 		trace_kvm_s390_sie_fault(vcpu);
1549699bde3bSChristian Borntraeger 		rc = kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
15501f0d0f09SCarsten Otte 	}
1551b0c632dbSHeiko Carstens 
15525a32c1afSChristian Borntraeger 	memcpy(&vcpu->run->s.regs.gprs[14], &vcpu->arch.sie_block->gg14, 16);
15533fb4c40fSThomas Huth 
1554a76ccff6SThomas Huth 	if (rc == 0) {
1555a76ccff6SThomas Huth 		if (kvm_is_ucontrol(vcpu->kvm))
15562955c83fSChristian Borntraeger 			/* Don't exit for host interrupts. */
15572955c83fSChristian Borntraeger 			rc = vcpu->arch.sie_block->icptcode ? -EOPNOTSUPP : 0;
1558a76ccff6SThomas Huth 		else
1559a76ccff6SThomas Huth 			rc = kvm_handle_sie_intercept(vcpu);
1560a76ccff6SThomas Huth 	}
1561a76ccff6SThomas Huth 
15623fb4c40fSThomas Huth 	return rc;
15633fb4c40fSThomas Huth }
15643fb4c40fSThomas Huth 
15653fb4c40fSThomas Huth static int __vcpu_run(struct kvm_vcpu *vcpu)
15663fb4c40fSThomas Huth {
15673fb4c40fSThomas Huth 	int rc, exit_reason;
15683fb4c40fSThomas Huth 
1569800c1065SThomas Huth 	/*
1570800c1065SThomas Huth 	 * We try to hold kvm->srcu during most of vcpu_run (except when run-
1571800c1065SThomas Huth 	 * ning the guest), so that memslots (and other stuff) are protected
1572800c1065SThomas Huth 	 */
1573800c1065SThomas Huth 	vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
1574800c1065SThomas Huth 
1575a76ccff6SThomas Huth 	do {
15763fb4c40fSThomas Huth 		rc = vcpu_pre_run(vcpu);
15773fb4c40fSThomas Huth 		if (rc)
1578a76ccff6SThomas Huth 			break;
15793fb4c40fSThomas Huth 
1580800c1065SThomas Huth 		srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
15813fb4c40fSThomas Huth 		/*
1582a76ccff6SThomas Huth 		 * As PF_VCPU will be used in fault handler, between
1583a76ccff6SThomas Huth 		 * guest_enter and guest_exit should be no uaccess.
15843fb4c40fSThomas Huth 		 */
15853fb4c40fSThomas Huth 		preempt_disable();
15863fb4c40fSThomas Huth 		kvm_guest_enter();
15873fb4c40fSThomas Huth 		preempt_enable();
1588a76ccff6SThomas Huth 		exit_reason = sie64a(vcpu->arch.sie_block,
1589a76ccff6SThomas Huth 				     vcpu->run->s.regs.gprs);
15903fb4c40fSThomas Huth 		kvm_guest_exit();
1591800c1065SThomas Huth 		vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
15923fb4c40fSThomas Huth 
15933fb4c40fSThomas Huth 		rc = vcpu_post_run(vcpu, exit_reason);
159427291e21SDavid Hildenbrand 	} while (!signal_pending(current) && !guestdbg_exit_pending(vcpu) && !rc);
15953fb4c40fSThomas Huth 
1596800c1065SThomas Huth 	srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
1597e168bf8dSCarsten Otte 	return rc;
1598b0c632dbSHeiko Carstens }
1599b0c632dbSHeiko Carstens 
1600b028ee3eSDavid Hildenbrand static void sync_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1601b028ee3eSDavid Hildenbrand {
1602b028ee3eSDavid Hildenbrand 	vcpu->arch.sie_block->gpsw.mask = kvm_run->psw_mask;
1603b028ee3eSDavid Hildenbrand 	vcpu->arch.sie_block->gpsw.addr = kvm_run->psw_addr;
1604b028ee3eSDavid Hildenbrand 	if (kvm_run->kvm_dirty_regs & KVM_SYNC_PREFIX)
1605b028ee3eSDavid Hildenbrand 		kvm_s390_set_prefix(vcpu, kvm_run->s.regs.prefix);
1606b028ee3eSDavid Hildenbrand 	if (kvm_run->kvm_dirty_regs & KVM_SYNC_CRS) {
1607b028ee3eSDavid Hildenbrand 		memcpy(&vcpu->arch.sie_block->gcr, &kvm_run->s.regs.crs, 128);
1608d3d692c8SDavid Hildenbrand 		/* some control register changes require a tlb flush */
1609d3d692c8SDavid Hildenbrand 		kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
1610b028ee3eSDavid Hildenbrand 	}
1611b028ee3eSDavid Hildenbrand 	if (kvm_run->kvm_dirty_regs & KVM_SYNC_ARCH0) {
1612b028ee3eSDavid Hildenbrand 		vcpu->arch.sie_block->cputm = kvm_run->s.regs.cputm;
1613b028ee3eSDavid Hildenbrand 		vcpu->arch.sie_block->ckc = kvm_run->s.regs.ckc;
1614b028ee3eSDavid Hildenbrand 		vcpu->arch.sie_block->todpr = kvm_run->s.regs.todpr;
1615b028ee3eSDavid Hildenbrand 		vcpu->arch.sie_block->pp = kvm_run->s.regs.pp;
1616b028ee3eSDavid Hildenbrand 		vcpu->arch.sie_block->gbea = kvm_run->s.regs.gbea;
1617b028ee3eSDavid Hildenbrand 	}
1618b028ee3eSDavid Hildenbrand 	if (kvm_run->kvm_dirty_regs & KVM_SYNC_PFAULT) {
1619b028ee3eSDavid Hildenbrand 		vcpu->arch.pfault_token = kvm_run->s.regs.pft;
1620b028ee3eSDavid Hildenbrand 		vcpu->arch.pfault_select = kvm_run->s.regs.pfs;
1621b028ee3eSDavid Hildenbrand 		vcpu->arch.pfault_compare = kvm_run->s.regs.pfc;
16229fbd8082SDavid Hildenbrand 		if (vcpu->arch.pfault_token == KVM_S390_PFAULT_TOKEN_INVALID)
16239fbd8082SDavid Hildenbrand 			kvm_clear_async_pf_completion_queue(vcpu);
1624b028ee3eSDavid Hildenbrand 	}
1625b028ee3eSDavid Hildenbrand 	kvm_run->kvm_dirty_regs = 0;
1626b028ee3eSDavid Hildenbrand }
1627b028ee3eSDavid Hildenbrand 
1628b028ee3eSDavid Hildenbrand static void store_regs(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1629b028ee3eSDavid Hildenbrand {
1630b028ee3eSDavid Hildenbrand 	kvm_run->psw_mask = vcpu->arch.sie_block->gpsw.mask;
1631b028ee3eSDavid Hildenbrand 	kvm_run->psw_addr = vcpu->arch.sie_block->gpsw.addr;
1632b028ee3eSDavid Hildenbrand 	kvm_run->s.regs.prefix = kvm_s390_get_prefix(vcpu);
1633b028ee3eSDavid Hildenbrand 	memcpy(&kvm_run->s.regs.crs, &vcpu->arch.sie_block->gcr, 128);
1634b028ee3eSDavid Hildenbrand 	kvm_run->s.regs.cputm = vcpu->arch.sie_block->cputm;
1635b028ee3eSDavid Hildenbrand 	kvm_run->s.regs.ckc = vcpu->arch.sie_block->ckc;
1636b028ee3eSDavid Hildenbrand 	kvm_run->s.regs.todpr = vcpu->arch.sie_block->todpr;
1637b028ee3eSDavid Hildenbrand 	kvm_run->s.regs.pp = vcpu->arch.sie_block->pp;
1638b028ee3eSDavid Hildenbrand 	kvm_run->s.regs.gbea = vcpu->arch.sie_block->gbea;
1639b028ee3eSDavid Hildenbrand 	kvm_run->s.regs.pft = vcpu->arch.pfault_token;
1640b028ee3eSDavid Hildenbrand 	kvm_run->s.regs.pfs = vcpu->arch.pfault_select;
1641b028ee3eSDavid Hildenbrand 	kvm_run->s.regs.pfc = vcpu->arch.pfault_compare;
1642b028ee3eSDavid Hildenbrand }
1643b028ee3eSDavid Hildenbrand 
1644b0c632dbSHeiko Carstens int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
1645b0c632dbSHeiko Carstens {
16468f2abe6aSChristian Borntraeger 	int rc;
1647b0c632dbSHeiko Carstens 	sigset_t sigsaved;
1648b0c632dbSHeiko Carstens 
164927291e21SDavid Hildenbrand 	if (guestdbg_exit_pending(vcpu)) {
165027291e21SDavid Hildenbrand 		kvm_s390_prepare_debug_exit(vcpu);
165127291e21SDavid Hildenbrand 		return 0;
165227291e21SDavid Hildenbrand 	}
165327291e21SDavid Hildenbrand 
1654b0c632dbSHeiko Carstens 	if (vcpu->sigset_active)
1655b0c632dbSHeiko Carstens 		sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
1656b0c632dbSHeiko Carstens 
16576352e4d2SDavid Hildenbrand 	if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm)) {
16586852d7b6SDavid Hildenbrand 		kvm_s390_vcpu_start(vcpu);
16596352e4d2SDavid Hildenbrand 	} else if (is_vcpu_stopped(vcpu)) {
16606352e4d2SDavid Hildenbrand 		pr_err_ratelimited("kvm-s390: can't run stopped vcpu %d\n",
16616352e4d2SDavid Hildenbrand 				   vcpu->vcpu_id);
16626352e4d2SDavid Hildenbrand 		return -EINVAL;
16636352e4d2SDavid Hildenbrand 	}
1664b0c632dbSHeiko Carstens 
1665b028ee3eSDavid Hildenbrand 	sync_regs(vcpu, kvm_run);
1666d7b0b5ebSCarsten Otte 
1667dab4079dSHeiko Carstens 	might_fault();
1668e168bf8dSCarsten Otte 	rc = __vcpu_run(vcpu);
16699ace903dSChristian Ehrhardt 
1670b1d16c49SChristian Ehrhardt 	if (signal_pending(current) && !rc) {
1671b1d16c49SChristian Ehrhardt 		kvm_run->exit_reason = KVM_EXIT_INTR;
16728f2abe6aSChristian Borntraeger 		rc = -EINTR;
1673b1d16c49SChristian Ehrhardt 	}
16748f2abe6aSChristian Borntraeger 
167527291e21SDavid Hildenbrand 	if (guestdbg_exit_pending(vcpu) && !rc)  {
167627291e21SDavid Hildenbrand 		kvm_s390_prepare_debug_exit(vcpu);
167727291e21SDavid Hildenbrand 		rc = 0;
167827291e21SDavid Hildenbrand 	}
167927291e21SDavid Hildenbrand 
1680b8e660b8SHeiko Carstens 	if (rc == -EOPNOTSUPP) {
16818f2abe6aSChristian Borntraeger 		/* intercept cannot be handled in-kernel, prepare kvm-run */
16828f2abe6aSChristian Borntraeger 		kvm_run->exit_reason         = KVM_EXIT_S390_SIEIC;
16838f2abe6aSChristian Borntraeger 		kvm_run->s390_sieic.icptcode = vcpu->arch.sie_block->icptcode;
16848f2abe6aSChristian Borntraeger 		kvm_run->s390_sieic.ipa      = vcpu->arch.sie_block->ipa;
16858f2abe6aSChristian Borntraeger 		kvm_run->s390_sieic.ipb      = vcpu->arch.sie_block->ipb;
16868f2abe6aSChristian Borntraeger 		rc = 0;
16878f2abe6aSChristian Borntraeger 	}
16888f2abe6aSChristian Borntraeger 
16898f2abe6aSChristian Borntraeger 	if (rc == -EREMOTE) {
16908f2abe6aSChristian Borntraeger 		/* intercept was handled, but userspace support is needed
16918f2abe6aSChristian Borntraeger 		 * kvm_run has been prepared by the handler */
16928f2abe6aSChristian Borntraeger 		rc = 0;
16938f2abe6aSChristian Borntraeger 	}
16948f2abe6aSChristian Borntraeger 
1695b028ee3eSDavid Hildenbrand 	store_regs(vcpu, kvm_run);
1696d7b0b5ebSCarsten Otte 
1697b0c632dbSHeiko Carstens 	if (vcpu->sigset_active)
1698b0c632dbSHeiko Carstens 		sigprocmask(SIG_SETMASK, &sigsaved, NULL);
1699b0c632dbSHeiko Carstens 
1700b0c632dbSHeiko Carstens 	vcpu->stat.exit_userspace++;
17017e8e6ab4SHeiko Carstens 	return rc;
1702b0c632dbSHeiko Carstens }
1703b0c632dbSHeiko Carstens 
1704b0c632dbSHeiko Carstens /*
1705b0c632dbSHeiko Carstens  * store status at address
1706b0c632dbSHeiko Carstens  * we use have two special cases:
1707b0c632dbSHeiko Carstens  * KVM_S390_STORE_STATUS_NOADDR: -> 0x1200 on 64 bit
1708b0c632dbSHeiko Carstens  * KVM_S390_STORE_STATUS_PREFIXED: -> prefix
1709b0c632dbSHeiko Carstens  */
1710d0bce605SHeiko Carstens int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long gpa)
1711b0c632dbSHeiko Carstens {
1712092670cdSCarsten Otte 	unsigned char archmode = 1;
1713fda902cbSMichael Mueller 	unsigned int px;
1714178bd789SThomas Huth 	u64 clkcomp;
1715d0bce605SHeiko Carstens 	int rc;
1716b0c632dbSHeiko Carstens 
1717d0bce605SHeiko Carstens 	if (gpa == KVM_S390_STORE_STATUS_NOADDR) {
1718d0bce605SHeiko Carstens 		if (write_guest_abs(vcpu, 163, &archmode, 1))
1719b0c632dbSHeiko Carstens 			return -EFAULT;
1720d0bce605SHeiko Carstens 		gpa = SAVE_AREA_BASE;
1721d0bce605SHeiko Carstens 	} else if (gpa == KVM_S390_STORE_STATUS_PREFIXED) {
1722d0bce605SHeiko Carstens 		if (write_guest_real(vcpu, 163, &archmode, 1))
1723b0c632dbSHeiko Carstens 			return -EFAULT;
1724d0bce605SHeiko Carstens 		gpa = kvm_s390_real_to_abs(vcpu, SAVE_AREA_BASE);
1725d0bce605SHeiko Carstens 	}
1726d0bce605SHeiko Carstens 	rc = write_guest_abs(vcpu, gpa + offsetof(struct save_area, fp_regs),
1727d0bce605SHeiko Carstens 			     vcpu->arch.guest_fpregs.fprs, 128);
1728d0bce605SHeiko Carstens 	rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, gp_regs),
1729d0bce605SHeiko Carstens 			      vcpu->run->s.regs.gprs, 128);
1730d0bce605SHeiko Carstens 	rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, psw),
1731d0bce605SHeiko Carstens 			      &vcpu->arch.sie_block->gpsw, 16);
1732fda902cbSMichael Mueller 	px = kvm_s390_get_prefix(vcpu);
1733d0bce605SHeiko Carstens 	rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, pref_reg),
1734fda902cbSMichael Mueller 			      &px, 4);
1735d0bce605SHeiko Carstens 	rc |= write_guest_abs(vcpu,
1736d0bce605SHeiko Carstens 			      gpa + offsetof(struct save_area, fp_ctrl_reg),
1737d0bce605SHeiko Carstens 			      &vcpu->arch.guest_fpregs.fpc, 4);
1738d0bce605SHeiko Carstens 	rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, tod_reg),
1739d0bce605SHeiko Carstens 			      &vcpu->arch.sie_block->todpr, 4);
1740d0bce605SHeiko Carstens 	rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, timer),
1741d0bce605SHeiko Carstens 			      &vcpu->arch.sie_block->cputm, 8);
1742178bd789SThomas Huth 	clkcomp = vcpu->arch.sie_block->ckc >> 8;
1743d0bce605SHeiko Carstens 	rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, clk_cmp),
1744d0bce605SHeiko Carstens 			      &clkcomp, 8);
1745d0bce605SHeiko Carstens 	rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, acc_regs),
1746d0bce605SHeiko Carstens 			      &vcpu->run->s.regs.acrs, 64);
1747d0bce605SHeiko Carstens 	rc |= write_guest_abs(vcpu, gpa + offsetof(struct save_area, ctrl_regs),
1748d0bce605SHeiko Carstens 			      &vcpu->arch.sie_block->gcr, 128);
1749d0bce605SHeiko Carstens 	return rc ? -EFAULT : 0;
1750b0c632dbSHeiko Carstens }
1751b0c632dbSHeiko Carstens 
1752e879892cSThomas Huth int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
1753e879892cSThomas Huth {
1754e879892cSThomas Huth 	/*
1755e879892cSThomas Huth 	 * The guest FPRS and ACRS are in the host FPRS/ACRS due to the lazy
1756e879892cSThomas Huth 	 * copying in vcpu load/put. Lets update our copies before we save
1757e879892cSThomas Huth 	 * it into the save area
1758e879892cSThomas Huth 	 */
1759e879892cSThomas Huth 	save_fp_ctl(&vcpu->arch.guest_fpregs.fpc);
1760e879892cSThomas Huth 	save_fp_regs(vcpu->arch.guest_fpregs.fprs);
1761e879892cSThomas Huth 	save_access_regs(vcpu->run->s.regs.acrs);
1762e879892cSThomas Huth 
1763e879892cSThomas Huth 	return kvm_s390_store_status_unloaded(vcpu, addr);
1764e879892cSThomas Huth }
1765e879892cSThomas Huth 
17668ad35755SDavid Hildenbrand static void __disable_ibs_on_vcpu(struct kvm_vcpu *vcpu)
17678ad35755SDavid Hildenbrand {
17688ad35755SDavid Hildenbrand 	kvm_check_request(KVM_REQ_ENABLE_IBS, vcpu);
17698ad35755SDavid Hildenbrand 	kvm_make_request(KVM_REQ_DISABLE_IBS, vcpu);
17708ad35755SDavid Hildenbrand 	exit_sie_sync(vcpu);
17718ad35755SDavid Hildenbrand }
17728ad35755SDavid Hildenbrand 
17738ad35755SDavid Hildenbrand static void __disable_ibs_on_all_vcpus(struct kvm *kvm)
17748ad35755SDavid Hildenbrand {
17758ad35755SDavid Hildenbrand 	unsigned int i;
17768ad35755SDavid Hildenbrand 	struct kvm_vcpu *vcpu;
17778ad35755SDavid Hildenbrand 
17788ad35755SDavid Hildenbrand 	kvm_for_each_vcpu(i, vcpu, kvm) {
17798ad35755SDavid Hildenbrand 		__disable_ibs_on_vcpu(vcpu);
17808ad35755SDavid Hildenbrand 	}
17818ad35755SDavid Hildenbrand }
17828ad35755SDavid Hildenbrand 
17838ad35755SDavid Hildenbrand static void __enable_ibs_on_vcpu(struct kvm_vcpu *vcpu)
17848ad35755SDavid Hildenbrand {
17858ad35755SDavid Hildenbrand 	kvm_check_request(KVM_REQ_DISABLE_IBS, vcpu);
17868ad35755SDavid Hildenbrand 	kvm_make_request(KVM_REQ_ENABLE_IBS, vcpu);
17878ad35755SDavid Hildenbrand 	exit_sie_sync(vcpu);
17888ad35755SDavid Hildenbrand }
17898ad35755SDavid Hildenbrand 
17906852d7b6SDavid Hildenbrand void kvm_s390_vcpu_start(struct kvm_vcpu *vcpu)
17916852d7b6SDavid Hildenbrand {
17928ad35755SDavid Hildenbrand 	int i, online_vcpus, started_vcpus = 0;
17938ad35755SDavid Hildenbrand 
17948ad35755SDavid Hildenbrand 	if (!is_vcpu_stopped(vcpu))
17958ad35755SDavid Hildenbrand 		return;
17968ad35755SDavid Hildenbrand 
17976852d7b6SDavid Hildenbrand 	trace_kvm_s390_vcpu_start_stop(vcpu->vcpu_id, 1);
17988ad35755SDavid Hildenbrand 	/* Only one cpu at a time may enter/leave the STOPPED state. */
1799433b9ee4SDavid Hildenbrand 	spin_lock(&vcpu->kvm->arch.start_stop_lock);
18008ad35755SDavid Hildenbrand 	online_vcpus = atomic_read(&vcpu->kvm->online_vcpus);
18018ad35755SDavid Hildenbrand 
18028ad35755SDavid Hildenbrand 	for (i = 0; i < online_vcpus; i++) {
18038ad35755SDavid Hildenbrand 		if (!is_vcpu_stopped(vcpu->kvm->vcpus[i]))
18048ad35755SDavid Hildenbrand 			started_vcpus++;
18058ad35755SDavid Hildenbrand 	}
18068ad35755SDavid Hildenbrand 
18078ad35755SDavid Hildenbrand 	if (started_vcpus == 0) {
18088ad35755SDavid Hildenbrand 		/* we're the only active VCPU -> speed it up */
18098ad35755SDavid Hildenbrand 		__enable_ibs_on_vcpu(vcpu);
18108ad35755SDavid Hildenbrand 	} else if (started_vcpus == 1) {
18118ad35755SDavid Hildenbrand 		/*
18128ad35755SDavid Hildenbrand 		 * As we are starting a second VCPU, we have to disable
18138ad35755SDavid Hildenbrand 		 * the IBS facility on all VCPUs to remove potentially
18148ad35755SDavid Hildenbrand 		 * oustanding ENABLE requests.
18158ad35755SDavid Hildenbrand 		 */
18168ad35755SDavid Hildenbrand 		__disable_ibs_on_all_vcpus(vcpu->kvm);
18178ad35755SDavid Hildenbrand 	}
18188ad35755SDavid Hildenbrand 
18196852d7b6SDavid Hildenbrand 	atomic_clear_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags);
18208ad35755SDavid Hildenbrand 	/*
18218ad35755SDavid Hildenbrand 	 * Another VCPU might have used IBS while we were offline.
18228ad35755SDavid Hildenbrand 	 * Let's play safe and flush the VCPU at startup.
18238ad35755SDavid Hildenbrand 	 */
1824d3d692c8SDavid Hildenbrand 	kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
1825433b9ee4SDavid Hildenbrand 	spin_unlock(&vcpu->kvm->arch.start_stop_lock);
18268ad35755SDavid Hildenbrand 	return;
18276852d7b6SDavid Hildenbrand }
18286852d7b6SDavid Hildenbrand 
18296852d7b6SDavid Hildenbrand void kvm_s390_vcpu_stop(struct kvm_vcpu *vcpu)
18306852d7b6SDavid Hildenbrand {
18318ad35755SDavid Hildenbrand 	int i, online_vcpus, started_vcpus = 0;
18328ad35755SDavid Hildenbrand 	struct kvm_vcpu *started_vcpu = NULL;
18338ad35755SDavid Hildenbrand 
18348ad35755SDavid Hildenbrand 	if (is_vcpu_stopped(vcpu))
18358ad35755SDavid Hildenbrand 		return;
18368ad35755SDavid Hildenbrand 
18376852d7b6SDavid Hildenbrand 	trace_kvm_s390_vcpu_start_stop(vcpu->vcpu_id, 0);
18388ad35755SDavid Hildenbrand 	/* Only one cpu at a time may enter/leave the STOPPED state. */
1839433b9ee4SDavid Hildenbrand 	spin_lock(&vcpu->kvm->arch.start_stop_lock);
18408ad35755SDavid Hildenbrand 	online_vcpus = atomic_read(&vcpu->kvm->online_vcpus);
18418ad35755SDavid Hildenbrand 
184232f5ff63SDavid Hildenbrand 	/* SIGP STOP and SIGP STOP AND STORE STATUS has been fully processed */
18436cddd432SDavid Hildenbrand 	kvm_s390_clear_stop_irq(vcpu);
184432f5ff63SDavid Hildenbrand 
18456cddd432SDavid Hildenbrand 	atomic_set_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags);
18468ad35755SDavid Hildenbrand 	__disable_ibs_on_vcpu(vcpu);
18478ad35755SDavid Hildenbrand 
18488ad35755SDavid Hildenbrand 	for (i = 0; i < online_vcpus; i++) {
18498ad35755SDavid Hildenbrand 		if (!is_vcpu_stopped(vcpu->kvm->vcpus[i])) {
18508ad35755SDavid Hildenbrand 			started_vcpus++;
18518ad35755SDavid Hildenbrand 			started_vcpu = vcpu->kvm->vcpus[i];
18528ad35755SDavid Hildenbrand 		}
18538ad35755SDavid Hildenbrand 	}
18548ad35755SDavid Hildenbrand 
18558ad35755SDavid Hildenbrand 	if (started_vcpus == 1) {
18568ad35755SDavid Hildenbrand 		/*
18578ad35755SDavid Hildenbrand 		 * As we only have one VCPU left, we want to enable the
18588ad35755SDavid Hildenbrand 		 * IBS facility for that VCPU to speed it up.
18598ad35755SDavid Hildenbrand 		 */
18608ad35755SDavid Hildenbrand 		__enable_ibs_on_vcpu(started_vcpu);
18618ad35755SDavid Hildenbrand 	}
18628ad35755SDavid Hildenbrand 
1863433b9ee4SDavid Hildenbrand 	spin_unlock(&vcpu->kvm->arch.start_stop_lock);
18648ad35755SDavid Hildenbrand 	return;
18656852d7b6SDavid Hildenbrand }
18666852d7b6SDavid Hildenbrand 
1867d6712df9SCornelia Huck static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
1868d6712df9SCornelia Huck 				     struct kvm_enable_cap *cap)
1869d6712df9SCornelia Huck {
1870d6712df9SCornelia Huck 	int r;
1871d6712df9SCornelia Huck 
1872d6712df9SCornelia Huck 	if (cap->flags)
1873d6712df9SCornelia Huck 		return -EINVAL;
1874d6712df9SCornelia Huck 
1875d6712df9SCornelia Huck 	switch (cap->cap) {
1876fa6b7fe9SCornelia Huck 	case KVM_CAP_S390_CSS_SUPPORT:
1877fa6b7fe9SCornelia Huck 		if (!vcpu->kvm->arch.css_support) {
1878fa6b7fe9SCornelia Huck 			vcpu->kvm->arch.css_support = 1;
1879fa6b7fe9SCornelia Huck 			trace_kvm_s390_enable_css(vcpu->kvm);
1880fa6b7fe9SCornelia Huck 		}
1881fa6b7fe9SCornelia Huck 		r = 0;
1882fa6b7fe9SCornelia Huck 		break;
1883d6712df9SCornelia Huck 	default:
1884d6712df9SCornelia Huck 		r = -EINVAL;
1885d6712df9SCornelia Huck 		break;
1886d6712df9SCornelia Huck 	}
1887d6712df9SCornelia Huck 	return r;
1888d6712df9SCornelia Huck }
1889d6712df9SCornelia Huck 
1890b0c632dbSHeiko Carstens long kvm_arch_vcpu_ioctl(struct file *filp,
1891b0c632dbSHeiko Carstens 			 unsigned int ioctl, unsigned long arg)
1892b0c632dbSHeiko Carstens {
1893b0c632dbSHeiko Carstens 	struct kvm_vcpu *vcpu = filp->private_data;
1894b0c632dbSHeiko Carstens 	void __user *argp = (void __user *)arg;
1895800c1065SThomas Huth 	int idx;
1896bc923cc9SAvi Kivity 	long r;
1897b0c632dbSHeiko Carstens 
189893736624SAvi Kivity 	switch (ioctl) {
189993736624SAvi Kivity 	case KVM_S390_INTERRUPT: {
1900ba5c1e9bSCarsten Otte 		struct kvm_s390_interrupt s390int;
1901383d0b05SJens Freimann 		struct kvm_s390_irq s390irq;
1902ba5c1e9bSCarsten Otte 
190393736624SAvi Kivity 		r = -EFAULT;
1904ba5c1e9bSCarsten Otte 		if (copy_from_user(&s390int, argp, sizeof(s390int)))
190593736624SAvi Kivity 			break;
1906383d0b05SJens Freimann 		if (s390int_to_s390irq(&s390int, &s390irq))
1907383d0b05SJens Freimann 			return -EINVAL;
1908383d0b05SJens Freimann 		r = kvm_s390_inject_vcpu(vcpu, &s390irq);
190993736624SAvi Kivity 		break;
1910ba5c1e9bSCarsten Otte 	}
1911b0c632dbSHeiko Carstens 	case KVM_S390_STORE_STATUS:
1912800c1065SThomas Huth 		idx = srcu_read_lock(&vcpu->kvm->srcu);
1913bc923cc9SAvi Kivity 		r = kvm_s390_vcpu_store_status(vcpu, arg);
1914800c1065SThomas Huth 		srcu_read_unlock(&vcpu->kvm->srcu, idx);
1915bc923cc9SAvi Kivity 		break;
1916b0c632dbSHeiko Carstens 	case KVM_S390_SET_INITIAL_PSW: {
1917b0c632dbSHeiko Carstens 		psw_t psw;
1918b0c632dbSHeiko Carstens 
1919bc923cc9SAvi Kivity 		r = -EFAULT;
1920b0c632dbSHeiko Carstens 		if (copy_from_user(&psw, argp, sizeof(psw)))
1921bc923cc9SAvi Kivity 			break;
1922bc923cc9SAvi Kivity 		r = kvm_arch_vcpu_ioctl_set_initial_psw(vcpu, psw);
1923bc923cc9SAvi Kivity 		break;
1924b0c632dbSHeiko Carstens 	}
1925b0c632dbSHeiko Carstens 	case KVM_S390_INITIAL_RESET:
1926bc923cc9SAvi Kivity 		r = kvm_arch_vcpu_ioctl_initial_reset(vcpu);
1927bc923cc9SAvi Kivity 		break;
192814eebd91SCarsten Otte 	case KVM_SET_ONE_REG:
192914eebd91SCarsten Otte 	case KVM_GET_ONE_REG: {
193014eebd91SCarsten Otte 		struct kvm_one_reg reg;
193114eebd91SCarsten Otte 		r = -EFAULT;
193214eebd91SCarsten Otte 		if (copy_from_user(&reg, argp, sizeof(reg)))
193314eebd91SCarsten Otte 			break;
193414eebd91SCarsten Otte 		if (ioctl == KVM_SET_ONE_REG)
193514eebd91SCarsten Otte 			r = kvm_arch_vcpu_ioctl_set_one_reg(vcpu, &reg);
193614eebd91SCarsten Otte 		else
193714eebd91SCarsten Otte 			r = kvm_arch_vcpu_ioctl_get_one_reg(vcpu, &reg);
193814eebd91SCarsten Otte 		break;
193914eebd91SCarsten Otte 	}
194027e0393fSCarsten Otte #ifdef CONFIG_KVM_S390_UCONTROL
194127e0393fSCarsten Otte 	case KVM_S390_UCAS_MAP: {
194227e0393fSCarsten Otte 		struct kvm_s390_ucas_mapping ucasmap;
194327e0393fSCarsten Otte 
194427e0393fSCarsten Otte 		if (copy_from_user(&ucasmap, argp, sizeof(ucasmap))) {
194527e0393fSCarsten Otte 			r = -EFAULT;
194627e0393fSCarsten Otte 			break;
194727e0393fSCarsten Otte 		}
194827e0393fSCarsten Otte 
194927e0393fSCarsten Otte 		if (!kvm_is_ucontrol(vcpu->kvm)) {
195027e0393fSCarsten Otte 			r = -EINVAL;
195127e0393fSCarsten Otte 			break;
195227e0393fSCarsten Otte 		}
195327e0393fSCarsten Otte 
195427e0393fSCarsten Otte 		r = gmap_map_segment(vcpu->arch.gmap, ucasmap.user_addr,
195527e0393fSCarsten Otte 				     ucasmap.vcpu_addr, ucasmap.length);
195627e0393fSCarsten Otte 		break;
195727e0393fSCarsten Otte 	}
195827e0393fSCarsten Otte 	case KVM_S390_UCAS_UNMAP: {
195927e0393fSCarsten Otte 		struct kvm_s390_ucas_mapping ucasmap;
196027e0393fSCarsten Otte 
196127e0393fSCarsten Otte 		if (copy_from_user(&ucasmap, argp, sizeof(ucasmap))) {
196227e0393fSCarsten Otte 			r = -EFAULT;
196327e0393fSCarsten Otte 			break;
196427e0393fSCarsten Otte 		}
196527e0393fSCarsten Otte 
196627e0393fSCarsten Otte 		if (!kvm_is_ucontrol(vcpu->kvm)) {
196727e0393fSCarsten Otte 			r = -EINVAL;
196827e0393fSCarsten Otte 			break;
196927e0393fSCarsten Otte 		}
197027e0393fSCarsten Otte 
197127e0393fSCarsten Otte 		r = gmap_unmap_segment(vcpu->arch.gmap, ucasmap.vcpu_addr,
197227e0393fSCarsten Otte 			ucasmap.length);
197327e0393fSCarsten Otte 		break;
197427e0393fSCarsten Otte 	}
197527e0393fSCarsten Otte #endif
1976ccc7910fSCarsten Otte 	case KVM_S390_VCPU_FAULT: {
1977527e30b4SMartin Schwidefsky 		r = gmap_fault(vcpu->arch.gmap, arg, 0);
1978ccc7910fSCarsten Otte 		break;
1979ccc7910fSCarsten Otte 	}
1980d6712df9SCornelia Huck 	case KVM_ENABLE_CAP:
1981d6712df9SCornelia Huck 	{
1982d6712df9SCornelia Huck 		struct kvm_enable_cap cap;
1983d6712df9SCornelia Huck 		r = -EFAULT;
1984d6712df9SCornelia Huck 		if (copy_from_user(&cap, argp, sizeof(cap)))
1985d6712df9SCornelia Huck 			break;
1986d6712df9SCornelia Huck 		r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap);
1987d6712df9SCornelia Huck 		break;
1988d6712df9SCornelia Huck 	}
1989b0c632dbSHeiko Carstens 	default:
19903e6afcf1SCarsten Otte 		r = -ENOTTY;
1991b0c632dbSHeiko Carstens 	}
1992bc923cc9SAvi Kivity 	return r;
1993b0c632dbSHeiko Carstens }
1994b0c632dbSHeiko Carstens 
19955b1c1493SCarsten Otte int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
19965b1c1493SCarsten Otte {
19975b1c1493SCarsten Otte #ifdef CONFIG_KVM_S390_UCONTROL
19985b1c1493SCarsten Otte 	if ((vmf->pgoff == KVM_S390_SIE_PAGE_OFFSET)
19995b1c1493SCarsten Otte 		 && (kvm_is_ucontrol(vcpu->kvm))) {
20005b1c1493SCarsten Otte 		vmf->page = virt_to_page(vcpu->arch.sie_block);
20015b1c1493SCarsten Otte 		get_page(vmf->page);
20025b1c1493SCarsten Otte 		return 0;
20035b1c1493SCarsten Otte 	}
20045b1c1493SCarsten Otte #endif
20055b1c1493SCarsten Otte 	return VM_FAULT_SIGBUS;
20065b1c1493SCarsten Otte }
20075b1c1493SCarsten Otte 
20085587027cSAneesh Kumar K.V int kvm_arch_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot,
20095587027cSAneesh Kumar K.V 			    unsigned long npages)
2010db3fe4ebSTakuya Yoshikawa {
2011db3fe4ebSTakuya Yoshikawa 	return 0;
2012db3fe4ebSTakuya Yoshikawa }
2013db3fe4ebSTakuya Yoshikawa 
2014b0c632dbSHeiko Carstens /* Section: memory related */
2015f7784b8eSMarcelo Tosatti int kvm_arch_prepare_memory_region(struct kvm *kvm,
2016f7784b8eSMarcelo Tosatti 				   struct kvm_memory_slot *memslot,
20177b6195a9STakuya Yoshikawa 				   struct kvm_userspace_memory_region *mem,
20187b6195a9STakuya Yoshikawa 				   enum kvm_mr_change change)
2019b0c632dbSHeiko Carstens {
2020dd2887e7SNick Wang 	/* A few sanity checks. We can have memory slots which have to be
2021dd2887e7SNick Wang 	   located/ended at a segment boundary (1MB). The memory in userland is
2022dd2887e7SNick Wang 	   ok to be fragmented into various different vmas. It is okay to mmap()
2023dd2887e7SNick Wang 	   and munmap() stuff in this slot after doing this call at any time */
2024b0c632dbSHeiko Carstens 
2025598841caSCarsten Otte 	if (mem->userspace_addr & 0xffffful)
2026b0c632dbSHeiko Carstens 		return -EINVAL;
2027b0c632dbSHeiko Carstens 
2028598841caSCarsten Otte 	if (mem->memory_size & 0xffffful)
2029b0c632dbSHeiko Carstens 		return -EINVAL;
2030b0c632dbSHeiko Carstens 
2031f7784b8eSMarcelo Tosatti 	return 0;
2032f7784b8eSMarcelo Tosatti }
2033f7784b8eSMarcelo Tosatti 
2034f7784b8eSMarcelo Tosatti void kvm_arch_commit_memory_region(struct kvm *kvm,
2035f7784b8eSMarcelo Tosatti 				struct kvm_userspace_memory_region *mem,
20368482644aSTakuya Yoshikawa 				const struct kvm_memory_slot *old,
20378482644aSTakuya Yoshikawa 				enum kvm_mr_change change)
2038f7784b8eSMarcelo Tosatti {
2039f7850c92SCarsten Otte 	int rc;
2040f7784b8eSMarcelo Tosatti 
20412cef4debSChristian Borntraeger 	/* If the basics of the memslot do not change, we do not want
20422cef4debSChristian Borntraeger 	 * to update the gmap. Every update causes several unnecessary
20432cef4debSChristian Borntraeger 	 * segment translation exceptions. This is usually handled just
20442cef4debSChristian Borntraeger 	 * fine by the normal fault handler + gmap, but it will also
20452cef4debSChristian Borntraeger 	 * cause faults on the prefix page of running guest CPUs.
20462cef4debSChristian Borntraeger 	 */
20472cef4debSChristian Borntraeger 	if (old->userspace_addr == mem->userspace_addr &&
20482cef4debSChristian Borntraeger 	    old->base_gfn * PAGE_SIZE == mem->guest_phys_addr &&
20492cef4debSChristian Borntraeger 	    old->npages * PAGE_SIZE == mem->memory_size)
20502cef4debSChristian Borntraeger 		return;
2051598841caSCarsten Otte 
2052598841caSCarsten Otte 	rc = gmap_map_segment(kvm->arch.gmap, mem->userspace_addr,
2053598841caSCarsten Otte 		mem->guest_phys_addr, mem->memory_size);
2054598841caSCarsten Otte 	if (rc)
2055f7850c92SCarsten Otte 		printk(KERN_WARNING "kvm-s390: failed to commit memory region\n");
2056598841caSCarsten Otte 	return;
2057b0c632dbSHeiko Carstens }
2058b0c632dbSHeiko Carstens 
2059b0c632dbSHeiko Carstens static int __init kvm_s390_init(void)
2060b0c632dbSHeiko Carstens {
2061ef50f7acSChristian Borntraeger 	int ret;
20620ee75beaSAvi Kivity 	ret = kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE);
2063ef50f7acSChristian Borntraeger 	if (ret)
2064ef50f7acSChristian Borntraeger 		return ret;
2065ef50f7acSChristian Borntraeger 
2066ef50f7acSChristian Borntraeger 	/*
2067ef50f7acSChristian Borntraeger 	 * guests can ask for up to 255+1 double words, we need a full page
206825985edcSLucas De Marchi 	 * to hold the maximum amount of facilities. On the other hand, we
2069ef50f7acSChristian Borntraeger 	 * only set facilities that are known to work in KVM.
2070ef50f7acSChristian Borntraeger 	 */
207178c4b59fSMichael Mueller 	vfacilities = (unsigned long *) get_zeroed_page(GFP_KERNEL|GFP_DMA);
207278c4b59fSMichael Mueller 	if (!vfacilities) {
2073ef50f7acSChristian Borntraeger 		kvm_exit();
2074ef50f7acSChristian Borntraeger 		return -ENOMEM;
2075ef50f7acSChristian Borntraeger 	}
207678c4b59fSMichael Mueller 	memcpy(vfacilities, S390_lowcore.stfle_fac_list, 16);
20777be81a46SChristian Borntraeger 	vfacilities[0] &= 0xff82fffbf47c2000UL;
20787feb6bb8SMichael Mueller 	vfacilities[1] &= 0x005c000000000000UL;
2079ef50f7acSChristian Borntraeger 	return 0;
2080b0c632dbSHeiko Carstens }
2081b0c632dbSHeiko Carstens 
2082b0c632dbSHeiko Carstens static void __exit kvm_s390_exit(void)
2083b0c632dbSHeiko Carstens {
208478c4b59fSMichael Mueller 	free_page((unsigned long) vfacilities);
2085b0c632dbSHeiko Carstens 	kvm_exit();
2086b0c632dbSHeiko Carstens }
2087b0c632dbSHeiko Carstens 
2088b0c632dbSHeiko Carstens module_init(kvm_s390_init);
2089b0c632dbSHeiko Carstens module_exit(kvm_s390_exit);
2090566af940SCornelia Huck 
2091566af940SCornelia Huck /*
2092566af940SCornelia Huck  * Enable autoloading of the kvm module.
2093566af940SCornelia Huck  * Note that we add the module alias here instead of virt/kvm/kvm_main.c
2094566af940SCornelia Huck  * since x86 takes a different approach.
2095566af940SCornelia Huck  */
2096566af940SCornelia Huck #include <linux/miscdevice.h>
2097566af940SCornelia Huck MODULE_ALIAS_MISCDEV(KVM_MINOR);
2098566af940SCornelia Huck MODULE_ALIAS("devname:kvm");
2099