aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/s390/include/asm/kvm_host.h1
-rw-r--r--arch/s390/include/asm/pgtable.h1
-rw-r--r--arch/s390/kvm/diag.c32
-rw-r--r--arch/s390/kvm/kvm-s390.c1
-rw-r--r--arch/s390/mm/pgtable.c49
5 files changed, 82 insertions, 2 deletions
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 00ff00dfb24..46c0bdaf479 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -143,6 +143,7 @@ struct kvm_vcpu_stat {
143 u32 instruction_sigp_arch; 143 u32 instruction_sigp_arch;
144 u32 instruction_sigp_prefix; 144 u32 instruction_sigp_prefix;
145 u32 instruction_sigp_restart; 145 u32 instruction_sigp_restart;
146 u32 diagnose_10;
146 u32 diagnose_44; 147 u32 diagnose_44;
147}; 148};
148 149
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index bc5f520f6f8..34ede0ea85a 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -698,6 +698,7 @@ int gmap_map_segment(struct gmap *gmap, unsigned long from,
698int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len); 698int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len);
699unsigned long __gmap_fault(unsigned long address, struct gmap *); 699unsigned long __gmap_fault(unsigned long address, struct gmap *);
700unsigned long gmap_fault(unsigned long address, struct gmap *); 700unsigned long gmap_fault(unsigned long address, struct gmap *);
701void gmap_discard(unsigned long from, unsigned long to, struct gmap *);
701 702
702/* 703/*
703 * Certain architectures need to do special things when PTEs 704 * Certain architectures need to do special things when PTEs
diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c
index 9e4c84187cf..87cedd61be0 100644
--- a/arch/s390/kvm/diag.c
+++ b/arch/s390/kvm/diag.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * diag.c - handling diagnose instructions 2 * diag.c - handling diagnose instructions
3 * 3 *
4 * Copyright IBM Corp. 2008 4 * Copyright IBM Corp. 2008,2011
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License (version 2 only) 7 * it under the terms of the GNU General Public License (version 2 only)
@@ -15,6 +15,34 @@
15#include <linux/kvm_host.h> 15#include <linux/kvm_host.h>
16#include "kvm-s390.h" 16#include "kvm-s390.h"
17 17
18static int diag_release_pages(struct kvm_vcpu *vcpu)
19{
20 unsigned long start, end;
21 unsigned long prefix = vcpu->arch.sie_block->prefix;
22
23 start = vcpu->arch.guest_gprs[(vcpu->arch.sie_block->ipa & 0xf0) >> 4];
24 end = vcpu->arch.guest_gprs[vcpu->arch.sie_block->ipa & 0xf] + 4096;
25
26 if (start & ~PAGE_MASK || end & ~PAGE_MASK || start > end
27 || start < 2 * PAGE_SIZE)
28 return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
29
30 VCPU_EVENT(vcpu, 5, "diag release pages %lX %lX", start, end);
31 vcpu->stat.diagnose_10++;
32
33 /* we checked for start > end above */
34 if (end < prefix || start >= prefix + 2 * PAGE_SIZE) {
35 gmap_discard(start, end, vcpu->arch.gmap);
36 } else {
37 if (start < prefix)
38 gmap_discard(start, prefix, vcpu->arch.gmap);
39 if (end >= prefix)
40 gmap_discard(prefix + 2 * PAGE_SIZE,
41 end, vcpu->arch.gmap);
42 }
43 return 0;
44}
45
18static int __diag_time_slice_end(struct kvm_vcpu *vcpu) 46static int __diag_time_slice_end(struct kvm_vcpu *vcpu)
19{ 47{
20 VCPU_EVENT(vcpu, 5, "%s", "diag time slice end"); 48 VCPU_EVENT(vcpu, 5, "%s", "diag time slice end");
@@ -57,6 +85,8 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu)
57 int code = (vcpu->arch.sie_block->ipb & 0xfff0000) >> 16; 85 int code = (vcpu->arch.sie_block->ipb & 0xfff0000) >> 16;
58 86
59 switch (code) { 87 switch (code) {
88 case 0x10:
89 return diag_release_pages(vcpu);
60 case 0x44: 90 case 0x44:
61 return __diag_time_slice_end(vcpu); 91 return __diag_time_slice_end(vcpu);
62 case 0x308: 92 case 0x308:
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index dc2b580e27b..189d6bdcac0 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -69,6 +69,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
69 { "instruction_sigp_set_arch", VCPU_STAT(instruction_sigp_arch) }, 69 { "instruction_sigp_set_arch", VCPU_STAT(instruction_sigp_arch) },
70 { "instruction_sigp_set_prefix", VCPU_STAT(instruction_sigp_prefix) }, 70 { "instruction_sigp_set_prefix", VCPU_STAT(instruction_sigp_prefix) },
71 { "instruction_sigp_restart", VCPU_STAT(instruction_sigp_restart) }, 71 { "instruction_sigp_restart", VCPU_STAT(instruction_sigp_restart) },
72 { "diagnose_10", VCPU_STAT(diagnose_10) },
72 { "diagnose_44", VCPU_STAT(diagnose_44) }, 73 { "diagnose_44", VCPU_STAT(diagnose_44) },
73 { NULL } 74 { NULL }
74}; 75};
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index 441d34445d0..301c84d3b54 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright IBM Corp. 2007,2009 2 * Copyright IBM Corp. 2007,2011
3 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> 3 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
4 */ 4 */
5 5
@@ -478,6 +478,53 @@ unsigned long gmap_fault(unsigned long address, struct gmap *gmap)
478} 478}
479EXPORT_SYMBOL_GPL(gmap_fault); 479EXPORT_SYMBOL_GPL(gmap_fault);
480 480
481void gmap_discard(unsigned long from, unsigned long to, struct gmap *gmap)
482{
483
484 unsigned long *table, address, size;
485 struct vm_area_struct *vma;
486 struct gmap_pgtable *mp;
487 struct page *page;
488
489 down_read(&gmap->mm->mmap_sem);
490 address = from;
491 while (address < to) {
492 /* Walk the gmap address space page table */
493 table = gmap->table + ((address >> 53) & 0x7ff);
494 if (unlikely(*table & _REGION_ENTRY_INV)) {
495 address = (address + PMD_SIZE) & PMD_MASK;
496 continue;
497 }
498 table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
499 table = table + ((address >> 42) & 0x7ff);
500 if (unlikely(*table & _REGION_ENTRY_INV)) {
501 address = (address + PMD_SIZE) & PMD_MASK;
502 continue;
503 }
504 table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
505 table = table + ((address >> 31) & 0x7ff);
506 if (unlikely(*table & _REGION_ENTRY_INV)) {
507 address = (address + PMD_SIZE) & PMD_MASK;
508 continue;
509 }
510 table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
511 table = table + ((address >> 20) & 0x7ff);
512 if (unlikely(*table & _SEGMENT_ENTRY_INV)) {
513 address = (address + PMD_SIZE) & PMD_MASK;
514 continue;
515 }
516 page = pfn_to_page(*table >> PAGE_SHIFT);
517 mp = (struct gmap_pgtable *) page->index;
518 vma = find_vma(gmap->mm, mp->vmaddr);
519 size = min(to - address, PMD_SIZE - (address & ~PMD_MASK));
520 zap_page_range(vma, mp->vmaddr | (address & ~PMD_MASK),
521 size, NULL);
522 address = (address + PMD_SIZE) & PMD_MASK;
523 }
524 up_read(&gmap->mm->mmap_sem);
525}
526EXPORT_SYMBOL_GPL(gmap_discard);
527
481void gmap_unmap_notifier(struct mm_struct *mm, unsigned long *table) 528void gmap_unmap_notifier(struct mm_struct *mm, unsigned long *table)
482{ 529{
483 struct gmap_rmap *rmap, *next; 530 struct gmap_rmap *rmap, *next;