diff options
-rw-r--r-- | arch/s390/include/asm/pgtable.h | 2 | ||||
-rw-r--r-- | arch/s390/include/asm/processor.h | 1 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.c | 23 | ||||
-rw-r--r-- | arch/s390/mm/fault.c | 26 |
4 files changed, 46 insertions, 6 deletions
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 2204400d0bd5..66101f6c6d81 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h | |||
@@ -767,6 +767,7 @@ static inline void pgste_set_pte(pte_t *ptep, pte_t entry) | |||
767 | * @table: pointer to the page directory | 767 | * @table: pointer to the page directory |
768 | * @asce: address space control element for gmap page table | 768 | * @asce: address space control element for gmap page table |
769 | * @crst_list: list of all crst tables used in the guest address space | 769 | * @crst_list: list of all crst tables used in the guest address space |
770 | * @pfault_enabled: defines if pfaults are applicable for the guest | ||
770 | */ | 771 | */ |
771 | struct gmap { | 772 | struct gmap { |
772 | struct list_head list; | 773 | struct list_head list; |
@@ -775,6 +776,7 @@ struct gmap { | |||
775 | unsigned long asce; | 776 | unsigned long asce; |
776 | void *private; | 777 | void *private; |
777 | struct list_head crst_list; | 778 | struct list_head crst_list; |
779 | bool pfault_enabled; | ||
778 | }; | 780 | }; |
779 | 781 | ||
780 | /** | 782 | /** |
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 0a876bc543d3..dc5fc4f90e52 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h | |||
@@ -79,6 +79,7 @@ struct thread_struct { | |||
79 | unsigned long ksp; /* kernel stack pointer */ | 79 | unsigned long ksp; /* kernel stack pointer */ |
80 | mm_segment_t mm_segment; | 80 | mm_segment_t mm_segment; |
81 | unsigned long gmap_addr; /* address of last gmap fault. */ | 81 | unsigned long gmap_addr; /* address of last gmap fault. */ |
82 | unsigned int gmap_pfault; /* signal of a pending guest pfault */ | ||
82 | struct per_regs per_user; /* User specified PER registers */ | 83 | struct per_regs per_user; /* User specified PER registers */ |
83 | struct per_event per_event; /* Cause of the last PER trap */ | 84 | struct per_event per_event; /* Cause of the last PER trap */ |
84 | unsigned long per_flags; /* Flags to control debug behavior */ | 85 | unsigned long per_flags; /* Flags to control debug behavior */ |
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 782420f3c4d5..9eec794caa7f 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c | |||
@@ -255,6 +255,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) | |||
255 | if (!kvm->arch.gmap) | 255 | if (!kvm->arch.gmap) |
256 | goto out_nogmap; | 256 | goto out_nogmap; |
257 | kvm->arch.gmap->private = kvm; | 257 | kvm->arch.gmap->private = kvm; |
258 | kvm->arch.gmap->pfault_enabled = 0; | ||
258 | } | 259 | } |
259 | 260 | ||
260 | kvm->arch.css_support = 0; | 261 | kvm->arch.css_support = 0; |
@@ -701,6 +702,17 @@ static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu) | |||
701 | return 0; | 702 | return 0; |
702 | } | 703 | } |
703 | 704 | ||
705 | static long kvm_arch_fault_in_sync(struct kvm_vcpu *vcpu) | ||
706 | { | ||
707 | long rc; | ||
708 | hva_t fault = gmap_fault(current->thread.gmap_addr, vcpu->arch.gmap); | ||
709 | struct mm_struct *mm = current->mm; | ||
710 | down_read(&mm->mmap_sem); | ||
711 | rc = get_user_pages(current, mm, fault, 1, 1, 0, NULL, NULL); | ||
712 | up_read(&mm->mmap_sem); | ||
713 | return rc; | ||
714 | } | ||
715 | |||
704 | static int vcpu_pre_run(struct kvm_vcpu *vcpu) | 716 | static int vcpu_pre_run(struct kvm_vcpu *vcpu) |
705 | { | 717 | { |
706 | int rc, cpuflags; | 718 | int rc, cpuflags; |
@@ -730,7 +742,7 @@ static int vcpu_pre_run(struct kvm_vcpu *vcpu) | |||
730 | 742 | ||
731 | static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason) | 743 | static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason) |
732 | { | 744 | { |
733 | int rc; | 745 | int rc = -1; |
734 | 746 | ||
735 | VCPU_EVENT(vcpu, 6, "exit sie icptcode %d", | 747 | VCPU_EVENT(vcpu, 6, "exit sie icptcode %d", |
736 | vcpu->arch.sie_block->icptcode); | 748 | vcpu->arch.sie_block->icptcode); |
@@ -744,7 +756,14 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason) | |||
744 | current->thread.gmap_addr; | 756 | current->thread.gmap_addr; |
745 | vcpu->run->s390_ucontrol.pgm_code = 0x10; | 757 | vcpu->run->s390_ucontrol.pgm_code = 0x10; |
746 | rc = -EREMOTE; | 758 | rc = -EREMOTE; |
747 | } else { | 759 | |
760 | } else if (current->thread.gmap_pfault) { | ||
761 | current->thread.gmap_pfault = 0; | ||
762 | if (kvm_arch_fault_in_sync(vcpu) >= 0) | ||
763 | rc = 0; | ||
764 | } | ||
765 | |||
766 | if (rc == -1) { | ||
748 | VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction"); | 767 | VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction"); |
749 | trace_kvm_s390_sie_fault(vcpu); | 768 | trace_kvm_s390_sie_fault(vcpu); |
750 | rc = kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | 769 | rc = kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); |
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index d95265b2719f..88cef505453b 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #define VM_FAULT_BADMAP 0x020000 | 50 | #define VM_FAULT_BADMAP 0x020000 |
51 | #define VM_FAULT_BADACCESS 0x040000 | 51 | #define VM_FAULT_BADACCESS 0x040000 |
52 | #define VM_FAULT_SIGNAL 0x080000 | 52 | #define VM_FAULT_SIGNAL 0x080000 |
53 | #define VM_FAULT_PFAULT 0x100000 | ||
53 | 54 | ||
54 | static unsigned long store_indication __read_mostly; | 55 | static unsigned long store_indication __read_mostly; |
55 | 56 | ||
@@ -227,6 +228,7 @@ static noinline void do_fault_error(struct pt_regs *regs, int fault) | |||
227 | return; | 228 | return; |
228 | } | 229 | } |
229 | case VM_FAULT_BADCONTEXT: | 230 | case VM_FAULT_BADCONTEXT: |
231 | case VM_FAULT_PFAULT: | ||
230 | do_no_context(regs); | 232 | do_no_context(regs); |
231 | break; | 233 | break; |
232 | case VM_FAULT_SIGNAL: | 234 | case VM_FAULT_SIGNAL: |
@@ -264,6 +266,9 @@ static noinline void do_fault_error(struct pt_regs *regs, int fault) | |||
264 | */ | 266 | */ |
265 | static inline int do_exception(struct pt_regs *regs, int access) | 267 | static inline int do_exception(struct pt_regs *regs, int access) |
266 | { | 268 | { |
269 | #ifdef CONFIG_PGSTE | ||
270 | struct gmap *gmap; | ||
271 | #endif | ||
267 | struct task_struct *tsk; | 272 | struct task_struct *tsk; |
268 | struct mm_struct *mm; | 273 | struct mm_struct *mm; |
269 | struct vm_area_struct *vma; | 274 | struct vm_area_struct *vma; |
@@ -304,9 +309,10 @@ static inline int do_exception(struct pt_regs *regs, int access) | |||
304 | down_read(&mm->mmap_sem); | 309 | down_read(&mm->mmap_sem); |
305 | 310 | ||
306 | #ifdef CONFIG_PGSTE | 311 | #ifdef CONFIG_PGSTE |
307 | if ((current->flags & PF_VCPU) && S390_lowcore.gmap) { | 312 | gmap = (struct gmap *) |
308 | address = __gmap_fault(address, | 313 | ((current->flags & PF_VCPU) ? S390_lowcore.gmap : 0); |
309 | (struct gmap *) S390_lowcore.gmap); | 314 | if (gmap) { |
315 | address = __gmap_fault(address, gmap); | ||
310 | if (address == -EFAULT) { | 316 | if (address == -EFAULT) { |
311 | fault = VM_FAULT_BADMAP; | 317 | fault = VM_FAULT_BADMAP; |
312 | goto out_up; | 318 | goto out_up; |
@@ -315,6 +321,8 @@ static inline int do_exception(struct pt_regs *regs, int access) | |||
315 | fault = VM_FAULT_OOM; | 321 | fault = VM_FAULT_OOM; |
316 | goto out_up; | 322 | goto out_up; |
317 | } | 323 | } |
324 | if (gmap->pfault_enabled) | ||
325 | flags |= FAULT_FLAG_RETRY_NOWAIT; | ||
318 | } | 326 | } |
319 | #endif | 327 | #endif |
320 | 328 | ||
@@ -371,9 +379,19 @@ retry: | |||
371 | regs, address); | 379 | regs, address); |
372 | } | 380 | } |
373 | if (fault & VM_FAULT_RETRY) { | 381 | if (fault & VM_FAULT_RETRY) { |
382 | #ifdef CONFIG_PGSTE | ||
383 | if (gmap && (flags & FAULT_FLAG_RETRY_NOWAIT)) { | ||
384 | /* FAULT_FLAG_RETRY_NOWAIT has been set, | ||
385 | * mmap_sem has not been released */ | ||
386 | current->thread.gmap_pfault = 1; | ||
387 | fault = VM_FAULT_PFAULT; | ||
388 | goto out_up; | ||
389 | } | ||
390 | #endif | ||
374 | /* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk | 391 | /* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk |
375 | * of starvation. */ | 392 | * of starvation. */ |
376 | flags &= ~FAULT_FLAG_ALLOW_RETRY; | 393 | flags &= ~(FAULT_FLAG_ALLOW_RETRY | |
394 | FAULT_FLAG_RETRY_NOWAIT); | ||
377 | flags |= FAULT_FLAG_TRIED; | 395 | flags |= FAULT_FLAG_TRIED; |
378 | down_read(&mm->mmap_sem); | 396 | down_read(&mm->mmap_sem); |
379 | goto retry; | 397 | goto retry; |