diff options
author | David Hildenbrand <dahi@linux.vnet.ibm.com> | 2016-05-10 03:50:21 -0400 |
---|---|---|
committer | Christian Borntraeger <borntraeger@de.ibm.com> | 2016-06-10 06:07:31 -0400 |
commit | a7e19ab55ffdd82f1a8d12694b9a0c0beeef534c (patch) | |
tree | 77c52e6a73a3a871caaba0a0e7b7eda3789fa53a /arch/s390/mm | |
parent | 11ddcd41bce5c2394b0390584236afdd13656998 (diff) |
KVM: s390: handle missing storage-key facility
Without the storage-key facility, SIE won't interpret SSKE, ISKE and
RRBE for us. So let's add proper interception handlers that will be called
if lazy sske cannot be enabled.
Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Diffstat (limited to 'arch/s390/mm')
-rw-r--r-- | arch/s390/mm/pgtable.c | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index e791e8b27fd2..fa286d0c0f2d 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
@@ -572,6 +572,43 @@ int cond_set_guest_storage_key(struct mm_struct *mm, unsigned long addr, | |||
572 | } | 572 | } |
573 | EXPORT_SYMBOL(cond_set_guest_storage_key); | 573 | EXPORT_SYMBOL(cond_set_guest_storage_key); |
574 | 574 | ||
575 | /** | ||
576 | * Reset a guest reference bit (rrbe), returning the reference and changed bit. | ||
577 | * | ||
578 | * Returns < 0 in case of error, otherwise the cc to be reported to the guest. | ||
579 | */ | ||
580 | int reset_guest_reference_bit(struct mm_struct *mm, unsigned long addr) | ||
581 | { | ||
582 | spinlock_t *ptl; | ||
583 | pgste_t old, new; | ||
584 | pte_t *ptep; | ||
585 | int cc = 0; | ||
586 | |||
587 | ptep = get_locked_pte(mm, addr, &ptl); | ||
588 | if (unlikely(!ptep)) | ||
589 | return -EFAULT; | ||
590 | |||
591 | new = old = pgste_get_lock(ptep); | ||
592 | /* Reset guest reference bit only */ | ||
593 | pgste_val(new) &= ~PGSTE_GR_BIT; | ||
594 | |||
595 | if (!(pte_val(*ptep) & _PAGE_INVALID)) { | ||
596 | cc = page_reset_referenced(pte_val(*ptep) & PAGE_MASK); | ||
597 | /* Merge real referenced bit into host-set */ | ||
598 | pgste_val(new) |= ((unsigned long) cc << 53) & PGSTE_HR_BIT; | ||
599 | } | ||
600 | /* Reflect guest's logical view, not physical */ | ||
601 | cc |= (pgste_val(old) & (PGSTE_GR_BIT | PGSTE_GC_BIT)) >> 49; | ||
602 | /* Changing the guest storage key is considered a change of the page */ | ||
603 | if ((pgste_val(new) ^ pgste_val(old)) & PGSTE_GR_BIT) | ||
604 | pgste_val(new) |= PGSTE_UC_BIT; | ||
605 | |||
606 | pgste_set_unlock(ptep, new); | ||
607 | pte_unmap_unlock(ptep, ptl); | ||
608 | return 0; | ||
609 | } | ||
610 | EXPORT_SYMBOL(reset_guest_reference_bit); | ||
611 | |||
575 | int get_guest_storage_key(struct mm_struct *mm, unsigned long addr, | 612 | int get_guest_storage_key(struct mm_struct *mm, unsigned long addr, |
576 | unsigned char *key) | 613 | unsigned char *key) |
577 | { | 614 | { |