diff options
-rw-r--r-- | arch/s390/include/asm/pgtable.h | 1 | ||||
-rw-r--r-- | arch/s390/kvm/intercept.c | 39 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.c | 49 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.h | 1 |
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 | ||
175 | static int handle_validity(struct kvm_vcpu *vcpu) | 175 | static 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 | |||
213 | out: | ||
214 | if (rc) | ||
215 | VCPU_EVENT(vcpu, 2, "unhandled validity intercept code %d", | ||
216 | viwhy); | ||
217 | return rc; | ||
218 | } | 183 | } |
219 | 184 | ||
220 | static int handle_instruction(struct kvm_vcpu *vcpu) | 185 | static 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 | ||
86 | static unsigned long long *facilities; | 86 | static unsigned long long *facilities; |
87 | static struct gmap_notifier gmap_notifier; | ||
87 | 88 | ||
88 | /* Section: not file related */ | 89 | /* Section: not file related */ |
89 | int kvm_arch_hardware_enable(void *garbage) | 90 | int kvm_arch_hardware_enable(void *garbage) |
@@ -96,13 +97,18 @@ void kvm_arch_hardware_disable(void *garbage) | |||
96 | { | 97 | { |
97 | } | 98 | } |
98 | 99 | ||
100 | static void kvm_gmap_notifier(struct gmap *gmap, unsigned long address); | ||
101 | |||
99 | int kvm_arch_hardware_setup(void) | 102 | int 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 | ||
104 | void kvm_arch_hardware_unsetup(void) | 109 | void kvm_arch_hardware_unsetup(void) |
105 | { | 110 | { |
111 | gmap_unregister_ipte_notifier(&gmap_notifier); | ||
106 | } | 112 | } |
107 | 113 | ||
108 | void kvm_arch_check_processor_compat(void *rtn) | 114 | void 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 | ||
493 | static 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 | |||
485 | int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu) | 509 | int 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 | ||
661 | static 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 | |||
637 | static int __vcpu_run(struct kvm_vcpu *vcpu) | 682 | static 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 | ||
68 | static inline u64 kvm_s390_get_base_disp_s(struct kvm_vcpu *vcpu) | 69 | static inline u64 kvm_s390_get_base_disp_s(struct kvm_vcpu *vcpu) |