diff options
author | Dominik Dingel <dingel@linux.vnet.ibm.com> | 2014-01-29 19:02:32 +0400 |
---|---|---|
committer | Christian Borntraeger <borntraeger@de.ibm.com> | 2014-04-22 11:36:24 +0400 |
commit | d4cb11340be6a1613d40d2b546cb111ea2547066 (patch) | |
tree | a9f8509c2a9ca3ae530e848995a59961d3fed995 | |
parent | 65eef33550f68e9a7f7d2dc64da94fb6cb85be2c (diff) | |
download | linux-d4cb11340be6a1613d40d2b546cb111ea2547066.tar.xz |
KVM: s390: Clear storage keys
page_table_reset_pgste() already does a complete page table walk to
reset the pgste. Enhance it to initialize the storage keys to
PAGE_DEFAULT_KEY if requested by the caller. This will be used
for lazy storage key handling. Also provide an empty stub for
!CONFIG_PGSTE
Lets adopt the current code (diag 308) to not clear the keys.
Signed-off-by: Dominik Dingel <dingel@linux.vnet.ibm.com>
Acked-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
-rw-r--r-- | arch/s390/include/asm/pgalloc.h | 3 | ||||
-rw-r--r-- | arch/s390/kvm/diag.c | 6 | ||||
-rw-r--r-- | arch/s390/mm/pgtable.c | 43 |
3 files changed, 37 insertions, 15 deletions
diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h index 884017cbfa9f..9e18a61d3df3 100644 --- a/arch/s390/include/asm/pgalloc.h +++ b/arch/s390/include/asm/pgalloc.h @@ -22,7 +22,8 @@ unsigned long *page_table_alloc(struct mm_struct *, unsigned long); void page_table_free(struct mm_struct *, unsigned long *); void page_table_free_rcu(struct mmu_gather *, unsigned long *); -void page_table_reset_pgste(struct mm_struct *, unsigned long, unsigned long); +void page_table_reset_pgste(struct mm_struct *, unsigned long, unsigned long, + bool init_skey); int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, unsigned long key, bool nq); diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c index 08dfc839a6cf..44dcfa8860b5 100644 --- a/arch/s390/kvm/diag.c +++ b/arch/s390/kvm/diag.c @@ -169,15 +169,15 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu) switch (subcode) { case 0: case 1: - page_table_reset_pgste(current->mm, 0, TASK_SIZE); + page_table_reset_pgste(current->mm, 0, TASK_SIZE, false); return -EOPNOTSUPP; case 3: vcpu->run->s390_reset_flags = KVM_S390_RESET_CLEAR; - page_table_reset_pgste(current->mm, 0, TASK_SIZE); + page_table_reset_pgste(current->mm, 0, TASK_SIZE, false); break; case 4: vcpu->run->s390_reset_flags = 0; - page_table_reset_pgste(current->mm, 0, TASK_SIZE); + page_table_reset_pgste(current->mm, 0, TASK_SIZE, false); break; default: return -EOPNOTSUPP; diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index d7cfd57815fb..be80f55a1b78 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -883,8 +883,8 @@ static inline void page_table_free_pgste(unsigned long *table) __free_page(page); } -static inline unsigned long page_table_reset_pte(struct mm_struct *mm, - pmd_t *pmd, unsigned long addr, unsigned long end) +static inline unsigned long page_table_reset_pte(struct mm_struct *mm, pmd_t *pmd, + unsigned long addr, unsigned long end, bool init_skey) { pte_t *start_pte, *pte; spinlock_t *ptl; @@ -895,6 +895,22 @@ static inline unsigned long page_table_reset_pte(struct mm_struct *mm, do { pgste = pgste_get_lock(pte); pgste_val(pgste) &= ~_PGSTE_GPS_USAGE_MASK; + if (init_skey) { + unsigned long address; + + pgste_val(pgste) &= ~(PGSTE_ACC_BITS | PGSTE_FP_BIT | + PGSTE_GR_BIT | PGSTE_GC_BIT); + + /* skip invalid and not writable pages */ + if (pte_val(*pte) & _PAGE_INVALID || + !(pte_val(*pte) & _PAGE_WRITE)) { + pgste_set_unlock(pte, pgste); + continue; + } + + address = pte_val(*pte) & PAGE_MASK; + page_set_storage_key(address, PAGE_DEFAULT_KEY, 1); + } pgste_set_unlock(pte, pgste); } while (pte++, addr += PAGE_SIZE, addr != end); pte_unmap_unlock(start_pte, ptl); @@ -902,8 +918,8 @@ static inline unsigned long page_table_reset_pte(struct mm_struct *mm, return addr; } -static inline unsigned long page_table_reset_pmd(struct mm_struct *mm, - pud_t *pud, unsigned long addr, unsigned long end) +static inline unsigned long page_table_reset_pmd(struct mm_struct *mm, pud_t *pud, + unsigned long addr, unsigned long end, bool init_skey) { unsigned long next; pmd_t *pmd; @@ -913,14 +929,14 @@ static inline unsigned long page_table_reset_pmd(struct mm_struct *mm, next = pmd_addr_end(addr, end); if (pmd_none_or_clear_bad(pmd)) continue; - next = page_table_reset_pte(mm, pmd, addr, next); + next = page_table_reset_pte(mm, pmd, addr, next, init_skey); } while (pmd++, addr = next, addr != end); return addr; } -static inline unsigned long page_table_reset_pud(struct mm_struct *mm, - pgd_t *pgd, unsigned long addr, unsigned long end) +static inline unsigned long page_table_reset_pud(struct mm_struct *mm, pgd_t *pgd, + unsigned long addr, unsigned long end, bool init_skey) { unsigned long next; pud_t *pud; @@ -930,14 +946,14 @@ static inline unsigned long page_table_reset_pud(struct mm_struct *mm, next = pud_addr_end(addr, end); if (pud_none_or_clear_bad(pud)) continue; - next = page_table_reset_pmd(mm, pud, addr, next); + next = page_table_reset_pmd(mm, pud, addr, next, init_skey); } while (pud++, addr = next, addr != end); return addr; } -void page_table_reset_pgste(struct mm_struct *mm, - unsigned long start, unsigned long end) +void page_table_reset_pgste(struct mm_struct *mm, unsigned long start, + unsigned long end, bool init_skey) { unsigned long addr, next; pgd_t *pgd; @@ -949,7 +965,7 @@ void page_table_reset_pgste(struct mm_struct *mm, next = pgd_addr_end(addr, end); if (pgd_none_or_clear_bad(pgd)) continue; - next = page_table_reset_pud(mm, pgd, addr, next); + next = page_table_reset_pud(mm, pgd, addr, next, init_skey); } while (pgd++, addr = next, addr != end); up_read(&mm->mmap_sem); } @@ -1011,6 +1027,11 @@ static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm, return NULL; } +void page_table_reset_pgste(struct mm_struct *mm, unsigned long start, + unsigned long end, bool init_skey) +{ +} + static inline void page_table_free_pgste(unsigned long *table) { } |