diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2013-05-21 11:29:52 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2014-02-21 02:50:20 -0500 |
commit | deedabb2b4a68a63351a949b1abcf73fc97eb406 (patch) | |
tree | 1ecb9504a61ef30a74a9ac268e5b32719ac57f91 | |
parent | b31288fa83b2bcc8834e1e208e9526b8bd5ce361 (diff) |
s390/kvm: set guest page states to stable on re-ipl
The guest page state needs to be reset to stable for all pages
on initial program load via diagnose 0x308.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | arch/s390/include/asm/pgalloc.h | 1 | ||||
-rw-r--r-- | arch/s390/kvm/diag.c | 3 | ||||
-rw-r--r-- | arch/s390/mm/pgtable.c | 72 |
3 files changed, 76 insertions, 0 deletions
diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h index e1408ddb94f8..14d43c77d6cf 100644 --- a/arch/s390/include/asm/pgalloc.h +++ b/arch/s390/include/asm/pgalloc.h | |||
@@ -22,6 +22,7 @@ unsigned long *page_table_alloc(struct mm_struct *, unsigned long); | |||
22 | void page_table_free(struct mm_struct *, unsigned long *); | 22 | void page_table_free(struct mm_struct *, unsigned long *); |
23 | void page_table_free_rcu(struct mmu_gather *, unsigned long *); | 23 | void page_table_free_rcu(struct mmu_gather *, unsigned long *); |
24 | 24 | ||
25 | void page_table_reset_pgste(struct mm_struct *, unsigned long, unsigned long); | ||
25 | int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, | 26 | int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, |
26 | unsigned long key, bool nq); | 27 | unsigned long key, bool nq); |
27 | 28 | ||
diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c index 8216c0e0b2e2..6f9cfa500372 100644 --- a/arch/s390/kvm/diag.c +++ b/arch/s390/kvm/diag.c | |||
@@ -13,6 +13,7 @@ | |||
13 | 13 | ||
14 | #include <linux/kvm.h> | 14 | #include <linux/kvm.h> |
15 | #include <linux/kvm_host.h> | 15 | #include <linux/kvm_host.h> |
16 | #include <asm/pgalloc.h> | ||
16 | #include <asm/virtio-ccw.h> | 17 | #include <asm/virtio-ccw.h> |
17 | #include "kvm-s390.h" | 18 | #include "kvm-s390.h" |
18 | #include "trace.h" | 19 | #include "trace.h" |
@@ -86,9 +87,11 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu) | |||
86 | switch (subcode) { | 87 | switch (subcode) { |
87 | case 3: | 88 | case 3: |
88 | vcpu->run->s390_reset_flags = KVM_S390_RESET_CLEAR; | 89 | vcpu->run->s390_reset_flags = KVM_S390_RESET_CLEAR; |
90 | page_table_reset_pgste(current->mm, 0, TASK_SIZE); | ||
89 | break; | 91 | break; |
90 | case 4: | 92 | case 4: |
91 | vcpu->run->s390_reset_flags = 0; | 93 | vcpu->run->s390_reset_flags = 0; |
94 | page_table_reset_pgste(current->mm, 0, TASK_SIZE); | ||
92 | break; | 95 | break; |
93 | default: | 96 | default: |
94 | return -EOPNOTSUPP; | 97 | return -EOPNOTSUPP; |
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 9e2b4705dea2..9c26b7aa96d9 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
@@ -879,6 +879,78 @@ static inline void page_table_free_pgste(unsigned long *table) | |||
879 | __free_page(page); | 879 | __free_page(page); |
880 | } | 880 | } |
881 | 881 | ||
882 | static inline unsigned long page_table_reset_pte(struct mm_struct *mm, | ||
883 | pmd_t *pmd, unsigned long addr, unsigned long end) | ||
884 | { | ||
885 | pte_t *start_pte, *pte; | ||
886 | spinlock_t *ptl; | ||
887 | pgste_t pgste; | ||
888 | |||
889 | start_pte = pte_offset_map_lock(mm, pmd, addr, &ptl); | ||
890 | pte = start_pte; | ||
891 | do { | ||
892 | pgste = pgste_get_lock(pte); | ||
893 | pgste_val(pgste) &= ~_PGSTE_GPS_USAGE_MASK; | ||
894 | pgste_set_unlock(pte, pgste); | ||
895 | } while (pte++, addr += PAGE_SIZE, addr != end); | ||
896 | pte_unmap_unlock(start_pte, ptl); | ||
897 | |||
898 | return addr; | ||
899 | } | ||
900 | |||
901 | static inline unsigned long page_table_reset_pmd(struct mm_struct *mm, | ||
902 | pud_t *pud, unsigned long addr, unsigned long end) | ||
903 | { | ||
904 | unsigned long next; | ||
905 | pmd_t *pmd; | ||
906 | |||
907 | pmd = pmd_offset(pud, addr); | ||
908 | do { | ||
909 | next = pmd_addr_end(addr, end); | ||
910 | if (pmd_none_or_clear_bad(pmd)) | ||
911 | continue; | ||
912 | next = page_table_reset_pte(mm, pmd, addr, next); | ||
913 | } while (pmd++, addr = next, addr != end); | ||
914 | |||
915 | return addr; | ||
916 | } | ||
917 | |||
918 | static inline unsigned long page_table_reset_pud(struct mm_struct *mm, | ||
919 | pgd_t *pgd, unsigned long addr, unsigned long end) | ||
920 | { | ||
921 | unsigned long next; | ||
922 | pud_t *pud; | ||
923 | |||
924 | pud = pud_offset(pgd, addr); | ||
925 | do { | ||
926 | next = pud_addr_end(addr, end); | ||
927 | if (pud_none_or_clear_bad(pud)) | ||
928 | continue; | ||
929 | next = page_table_reset_pmd(mm, pud, addr, next); | ||
930 | } while (pud++, addr = next, addr != end); | ||
931 | |||
932 | return addr; | ||
933 | } | ||
934 | |||
935 | void page_table_reset_pgste(struct mm_struct *mm, | ||
936 | unsigned long start, unsigned long end) | ||
937 | { | ||
938 | unsigned long addr, next; | ||
939 | pgd_t *pgd; | ||
940 | |||
941 | addr = start; | ||
942 | down_read(&mm->mmap_sem); | ||
943 | pgd = pgd_offset(mm, addr); | ||
944 | do { | ||
945 | next = pgd_addr_end(addr, end); | ||
946 | if (pgd_none_or_clear_bad(pgd)) | ||
947 | continue; | ||
948 | next = page_table_reset_pud(mm, pgd, addr, next); | ||
949 | } while (pgd++, addr = next, addr != end); | ||
950 | up_read(&mm->mmap_sem); | ||
951 | } | ||
952 | EXPORT_SYMBOL(page_table_reset_pgste); | ||
953 | |||
882 | int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, | 954 | int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, |
883 | unsigned long key, bool nq) | 955 | unsigned long key, bool nq) |
884 | { | 956 | { |