aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/s390/include/asm/pgtable.h1
-rw-r--r--arch/s390/kvm/intercept.c39
-rw-r--r--arch/s390/kvm/kvm-s390.c49
-rw-r--r--arch/s390/kvm/kvm-s390.h1
4 files changed, 53 insertions, 37 deletions
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 1fc68d97be9d..1d0ad7d2d29a 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -739,6 +739,7 @@ struct gmap {
739 struct mm_struct *mm; 739 struct mm_struct *mm;
740 unsigned long *table; 740 unsigned long *table;
741 unsigned long asce; 741 unsigned long asce;
742 void *private;
742 struct list_head crst_list; 743 struct list_head crst_list;
743}; 744};
744 745
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index b7d1b2edeeb3..f0b8be0cc08d 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -174,47 +174,12 @@ static int handle_stop(struct kvm_vcpu *vcpu)
174 174
175static int handle_validity(struct kvm_vcpu *vcpu) 175static int handle_validity(struct kvm_vcpu *vcpu)
176{ 176{
177 unsigned long vmaddr;
178 int viwhy = vcpu->arch.sie_block->ipb >> 16; 177 int viwhy = vcpu->arch.sie_block->ipb >> 16;
179 int rc;
180 178
181 vcpu->stat.exit_validity++; 179 vcpu->stat.exit_validity++;
182 trace_kvm_s390_intercept_validity(vcpu, viwhy); 180 trace_kvm_s390_intercept_validity(vcpu, viwhy);
183 if (viwhy == 0x37) { 181 WARN_ONCE(true, "kvm: unhandled validity intercept 0x%x\n", viwhy);
184 vmaddr = gmap_fault(vcpu->arch.sie_block->prefix, 182 return -EOPNOTSUPP;
185 vcpu->arch.gmap);
186 if (IS_ERR_VALUE(vmaddr)) {
187 rc = -EOPNOTSUPP;
188 goto out;
189 }
190 rc = fault_in_pages_writeable((char __user *) vmaddr,
191 PAGE_SIZE);
192 if (rc) {
193 /* user will receive sigsegv, exit to user */
194 rc = -EOPNOTSUPP;
195 goto out;
196 }
197 vmaddr = gmap_fault(vcpu->arch.sie_block->prefix + PAGE_SIZE,
198 vcpu->arch.gmap);
199 if (IS_ERR_VALUE(vmaddr)) {
200 rc = -EOPNOTSUPP;
201 goto out;
202 }
203 rc = fault_in_pages_writeable((char __user *) vmaddr,
204 PAGE_SIZE);
205 if (rc) {
206 /* user will receive sigsegv, exit to user */
207 rc = -EOPNOTSUPP;
208 goto out;
209 }
210 } else
211 rc = -EOPNOTSUPP;
212
213out:
214 if (rc)
215 VCPU_EVENT(vcpu, 2, "unhandled validity intercept code %d",
216 viwhy);
217 return rc;
218} 183}
219 184
220static int handle_instruction(struct kvm_vcpu *vcpu) 185static int handle_instruction(struct kvm_vcpu *vcpu)
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index ef4ef21f2c73..08227c1e816f 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -84,6 +84,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
84}; 84};
85 85
86static unsigned long long *facilities; 86static unsigned long long *facilities;
87static struct gmap_notifier gmap_notifier;
87 88
88/* Section: not file related */ 89/* Section: not file related */
89int kvm_arch_hardware_enable(void *garbage) 90int kvm_arch_hardware_enable(void *garbage)
@@ -96,13 +97,18 @@ void kvm_arch_hardware_disable(void *garbage)
96{ 97{
97} 98}
98 99
100static void kvm_gmap_notifier(struct gmap *gmap, unsigned long address);
101
99int kvm_arch_hardware_setup(void) 102int kvm_arch_hardware_setup(void)
100{ 103{
104 gmap_notifier.notifier_call = kvm_gmap_notifier;
105 gmap_register_ipte_notifier(&gmap_notifier);
101 return 0; 106 return 0;
102} 107}
103 108
104void kvm_arch_hardware_unsetup(void) 109void kvm_arch_hardware_unsetup(void)
105{ 110{
111 gmap_unregister_ipte_notifier(&gmap_notifier);
106} 112}
107 113
108void kvm_arch_check_processor_compat(void *rtn) 114void kvm_arch_check_processor_compat(void *rtn)
@@ -239,6 +245,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
239 kvm->arch.gmap = gmap_alloc(current->mm); 245 kvm->arch.gmap = gmap_alloc(current->mm);
240 if (!kvm->arch.gmap) 246 if (!kvm->arch.gmap)
241 goto out_nogmap; 247 goto out_nogmap;
248 kvm->arch.gmap->private = kvm;
242 } 249 }
243 250
244 kvm->arch.css_support = 0; 251 kvm->arch.css_support = 0;
@@ -309,6 +316,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
309 vcpu->arch.gmap = gmap_alloc(current->mm); 316 vcpu->arch.gmap = gmap_alloc(current->mm);
310 if (!vcpu->arch.gmap) 317 if (!vcpu->arch.gmap)
311 return -ENOMEM; 318 return -ENOMEM;
319 vcpu->arch.gmap->private = vcpu->kvm;
312 return 0; 320 return 0;
313 } 321 }
314 322
@@ -482,6 +490,22 @@ void exit_sie_sync(struct kvm_vcpu *vcpu)
482 exit_sie(vcpu); 490 exit_sie(vcpu);
483} 491}
484 492
493static void kvm_gmap_notifier(struct gmap *gmap, unsigned long address)
494{
495 int i;
496 struct kvm *kvm = gmap->private;
497 struct kvm_vcpu *vcpu;
498
499 kvm_for_each_vcpu(i, vcpu, kvm) {
500 /* match against both prefix pages */
501 if (vcpu->arch.sie_block->prefix == (address & ~0x1000UL)) {
502 VCPU_EVENT(vcpu, 2, "gmap notifier for %lx", address);
503 kvm_make_request(KVM_REQ_MMU_RELOAD, vcpu);
504 exit_sie_sync(vcpu);
505 }
506 }
507}
508
485int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu) 509int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
486{ 510{
487 /* kvm common code refers to this, but never calls it */ 511 /* kvm common code refers to this, but never calls it */
@@ -634,6 +658,27 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
634 return -EINVAL; /* not implemented yet */ 658 return -EINVAL; /* not implemented yet */
635} 659}
636 660
661static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu)
662{
663 /*
664 * We use MMU_RELOAD just to re-arm the ipte notifier for the
665 * guest prefix page. gmap_ipte_notify will wait on the ptl lock.
666 * This ensures that the ipte instruction for this request has
667 * already finished. We might race against a second unmapper that
668 * wants to set the blocking bit. Lets just retry the request loop.
669 */
670 while (kvm_check_request(KVM_REQ_MMU_RELOAD, vcpu)) {
671 int rc;
672 rc = gmap_ipte_notify(vcpu->arch.gmap,
673 vcpu->arch.sie_block->prefix,
674 PAGE_SIZE * 2);
675 if (rc)
676 return rc;
677 s390_vcpu_unblock(vcpu);
678 }
679 return 0;
680}
681
637static int __vcpu_run(struct kvm_vcpu *vcpu) 682static int __vcpu_run(struct kvm_vcpu *vcpu)
638{ 683{
639 int rc; 684 int rc;
@@ -649,6 +694,10 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
649 if (!kvm_is_ucontrol(vcpu->kvm)) 694 if (!kvm_is_ucontrol(vcpu->kvm))
650 kvm_s390_deliver_pending_interrupts(vcpu); 695 kvm_s390_deliver_pending_interrupts(vcpu);
651 696
697 rc = kvm_s390_handle_requests(vcpu);
698 if (rc)
699 return rc;
700
652 vcpu->arch.sie_block->icptcode = 0; 701 vcpu->arch.sie_block->icptcode = 0;
653 preempt_disable(); 702 preempt_disable();
654 kvm_guest_enter(); 703 kvm_guest_enter();
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 7a8abfd26a0f..269b523d0f6e 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -63,6 +63,7 @@ static inline void kvm_s390_set_prefix(struct kvm_vcpu *vcpu, u32 prefix)
63{ 63{
64 vcpu->arch.sie_block->prefix = prefix & 0x7fffe000u; 64 vcpu->arch.sie_block->prefix = prefix & 0x7fffe000u;
65 vcpu->arch.sie_block->ihcpu = 0xffff; 65 vcpu->arch.sie_block->ihcpu = 0xffff;
66 kvm_make_request(KVM_REQ_MMU_RELOAD, vcpu);
66} 67}
67 68
68static inline u64 kvm_s390_get_base_disp_s(struct kvm_vcpu *vcpu) 69static inline u64 kvm_s390_get_base_disp_s(struct kvm_vcpu *vcpu)