aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClaudio Imbrenda <imbrenda@linux.vnet.ibm.com>2017-04-20 04:03:45 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2017-04-20 07:33:08 -0400
commit2d42f9477320befd33846c4083cab898998cdee5 (patch)
tree71045127b1000beafd1760b509e6ba9e66e1d3c6
parentb13de4b7adeb7a5e37a5aa78d5a4926c3cd4e131 (diff)
s390/kvm: Add PGSTE manipulation functions
Add PGSTE manipulation functions: * set_pgste_bits sets specific bits in a PGSTE * get_pgste returns the whole PGSTE * pgste_perform_essa manipulates a PGSTE to set specific storage states * ESSA_[SG]ET_* macros used to indicate the action for manipulate_pgste Signed-off-by: Claudio Imbrenda <imbrenda@linux.vnet.ibm.com> Reviewed-by: Janosch Frank <frankja@de.ibm.com> Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/include/asm/page-states.h19
-rw-r--r--arch/s390/include/asm/pgtable.h16
-rw-r--r--arch/s390/mm/page-states.c3
-rw-r--r--arch/s390/mm/pgtable.c153
4 files changed, 185 insertions, 6 deletions
diff --git a/arch/s390/include/asm/page-states.h b/arch/s390/include/asm/page-states.h
new file mode 100644
index 000000000000..42267a2fe29e
--- /dev/null
+++ b/arch/s390/include/asm/page-states.h
@@ -0,0 +1,19 @@
1/*
2 * Copyright IBM Corp. 2017
3 * Author(s): Claudio Imbrenda <imbrenda@linux.vnet.ibm.com>
4 */
5
6#ifndef PAGE_STATES_H
7#define PAGE_STATES_H
8
9#define ESSA_GET_STATE 0
10#define ESSA_SET_STABLE 1
11#define ESSA_SET_UNUSED 2
12#define ESSA_SET_VOLATILE 3
13#define ESSA_SET_POT_VOLATILE 4
14#define ESSA_SET_STABLE_RESIDENT 5
15#define ESSA_SET_STABLE_IF_RESIDENT 6
16
17#define ESSA_MAX ESSA_SET_STABLE_IF_RESIDENT
18
19#endif
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 93e37b12e882..bdabbbb3e925 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -372,10 +372,12 @@ static inline int is_module_addr(void *addr)
372#define PGSTE_VSIE_BIT 0x0000200000000000UL /* ref'd in a shadow table */ 372#define PGSTE_VSIE_BIT 0x0000200000000000UL /* ref'd in a shadow table */
373 373
374/* Guest Page State used for virtualization */ 374/* Guest Page State used for virtualization */
375#define _PGSTE_GPS_ZERO 0x0000000080000000UL 375#define _PGSTE_GPS_ZERO 0x0000000080000000UL
376#define _PGSTE_GPS_USAGE_MASK 0x0000000003000000UL 376#define _PGSTE_GPS_USAGE_MASK 0x0000000003000000UL
377#define _PGSTE_GPS_USAGE_STABLE 0x0000000000000000UL 377#define _PGSTE_GPS_USAGE_STABLE 0x0000000000000000UL
378#define _PGSTE_GPS_USAGE_UNUSED 0x0000000001000000UL 378#define _PGSTE_GPS_USAGE_UNUSED 0x0000000001000000UL
379#define _PGSTE_GPS_USAGE_POT_VOLATILE 0x0000000002000000UL
380#define _PGSTE_GPS_USAGE_VOLATILE _PGSTE_GPS_USAGE_MASK
379 381
380/* 382/*
381 * A user page table pointer has the space-switch-event bit, the 383 * A user page table pointer has the space-switch-event bit, the
@@ -1041,6 +1043,12 @@ int reset_guest_reference_bit(struct mm_struct *mm, unsigned long addr);
1041int get_guest_storage_key(struct mm_struct *mm, unsigned long addr, 1043int get_guest_storage_key(struct mm_struct *mm, unsigned long addr,
1042 unsigned char *key); 1044 unsigned char *key);
1043 1045
1046int set_pgste_bits(struct mm_struct *mm, unsigned long addr,
1047 unsigned long bits, unsigned long value);
1048int get_pgste(struct mm_struct *mm, unsigned long hva, unsigned long *pgstep);
1049int pgste_perform_essa(struct mm_struct *mm, unsigned long hva, int orc,
1050 unsigned long *oldpte, unsigned long *oldpgste);
1051
1044/* 1052/*
1045 * Certain architectures need to do special things when PTEs 1053 * Certain architectures need to do special things when PTEs
1046 * within a page table are directly modified. Thus, the following 1054 * within a page table are directly modified. Thus, the following
diff --git a/arch/s390/mm/page-states.c b/arch/s390/mm/page-states.c
index 3330ea124eec..69a7b01ae746 100644
--- a/arch/s390/mm/page-states.c
+++ b/arch/s390/mm/page-states.c
@@ -13,8 +13,7 @@
13#include <linux/gfp.h> 13#include <linux/gfp.h>
14#include <linux/init.h> 14#include <linux/init.h>
15 15
16#define ESSA_SET_STABLE 1 16#include <asm/page-states.h>
17#define ESSA_SET_UNUSED 2
18 17
19static int cmma_flag = 1; 18static int cmma_flag = 1;
20 19
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index 463e5ef02304..947b66a5cdba 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -23,6 +23,7 @@
23#include <asm/tlb.h> 23#include <asm/tlb.h>
24#include <asm/tlbflush.h> 24#include <asm/tlbflush.h>
25#include <asm/mmu_context.h> 25#include <asm/mmu_context.h>
26#include <asm/page-states.h>
26 27
27static inline pte_t ptep_flush_direct(struct mm_struct *mm, 28static inline pte_t ptep_flush_direct(struct mm_struct *mm,
28 unsigned long addr, pte_t *ptep) 29 unsigned long addr, pte_t *ptep)
@@ -787,4 +788,156 @@ int get_guest_storage_key(struct mm_struct *mm, unsigned long addr,
787 return 0; 788 return 0;
788} 789}
789EXPORT_SYMBOL(get_guest_storage_key); 790EXPORT_SYMBOL(get_guest_storage_key);
791
792/**
793 * pgste_perform_essa - perform ESSA actions on the PGSTE.
794 * @mm: the memory context. It must have PGSTEs, no check is performed here!
795 * @hva: the host virtual address of the page whose PGSTE is to be processed
796 * @orc: the specific action to perform, see the ESSA_SET_* macros.
797 * @oldpte: the PTE will be saved there if the pointer is not NULL.
798 * @oldpgste: the old PGSTE will be saved there if the pointer is not NULL.
799 *
800 * Return: 1 if the page is to be added to the CBRL, otherwise 0,
801 * or < 0 in case of error. -EINVAL is returned for invalid values
802 * of orc, -EFAULT for invalid addresses.
803 */
804int pgste_perform_essa(struct mm_struct *mm, unsigned long hva, int orc,
805 unsigned long *oldpte, unsigned long *oldpgste)
806{
807 unsigned long pgstev;
808 spinlock_t *ptl;
809 pgste_t pgste;
810 pte_t *ptep;
811 int res = 0;
812
813 WARN_ON_ONCE(orc > ESSA_MAX);
814 if (unlikely(orc > ESSA_MAX))
815 return -EINVAL;
816 ptep = get_locked_pte(mm, hva, &ptl);
817 if (unlikely(!ptep))
818 return -EFAULT;
819 pgste = pgste_get_lock(ptep);
820 pgstev = pgste_val(pgste);
821 if (oldpte)
822 *oldpte = pte_val(*ptep);
823 if (oldpgste)
824 *oldpgste = pgstev;
825
826 switch (orc) {
827 case ESSA_GET_STATE:
828 break;
829 case ESSA_SET_STABLE:
830 pgstev &= ~_PGSTE_GPS_USAGE_MASK;
831 pgstev |= _PGSTE_GPS_USAGE_STABLE;
832 break;
833 case ESSA_SET_UNUSED:
834 pgstev &= ~_PGSTE_GPS_USAGE_MASK;
835 pgstev |= _PGSTE_GPS_USAGE_UNUSED;
836 if (pte_val(*ptep) & _PAGE_INVALID)
837 res = 1;
838 break;
839 case ESSA_SET_VOLATILE:
840 pgstev &= ~_PGSTE_GPS_USAGE_MASK;
841 pgstev |= _PGSTE_GPS_USAGE_VOLATILE;
842 if (pte_val(*ptep) & _PAGE_INVALID)
843 res = 1;
844 break;
845 case ESSA_SET_POT_VOLATILE:
846 pgstev &= ~_PGSTE_GPS_USAGE_MASK;
847 if (!(pte_val(*ptep) & _PAGE_INVALID)) {
848 pgstev |= _PGSTE_GPS_USAGE_POT_VOLATILE;
849 break;
850 }
851 if (pgstev & _PGSTE_GPS_ZERO) {
852 pgstev |= _PGSTE_GPS_USAGE_VOLATILE;
853 break;
854 }
855 if (!(pgstev & PGSTE_GC_BIT)) {
856 pgstev |= _PGSTE_GPS_USAGE_VOLATILE;
857 res = 1;
858 break;
859 }
860 break;
861 case ESSA_SET_STABLE_RESIDENT:
862 pgstev &= ~_PGSTE_GPS_USAGE_MASK;
863 pgstev |= _PGSTE_GPS_USAGE_STABLE;
864 /*
865 * Since the resident state can go away any time after this
866 * call, we will not make this page resident. We can revisit
867 * this decision if a guest will ever start using this.
868 */
869 break;
870 case ESSA_SET_STABLE_IF_RESIDENT:
871 if (!(pte_val(*ptep) & _PAGE_INVALID)) {
872 pgstev &= ~_PGSTE_GPS_USAGE_MASK;
873 pgstev |= _PGSTE_GPS_USAGE_STABLE;
874 }
875 break;
876 default:
877 /* we should never get here! */
878 break;
879 }
880 /* If we are discarding a page, set it to logical zero */
881 if (res)
882 pgstev |= _PGSTE_GPS_ZERO;
883
884 pgste_val(pgste) = pgstev;
885 pgste_set_unlock(ptep, pgste);
886 pte_unmap_unlock(ptep, ptl);
887 return res;
888}
889EXPORT_SYMBOL(pgste_perform_essa);
890
891/**
892 * set_pgste_bits - set specific PGSTE bits.
893 * @mm: the memory context. It must have PGSTEs, no check is performed here!
894 * @hva: the host virtual address of the page whose PGSTE is to be processed
895 * @bits: a bitmask representing the bits that will be touched
896 * @value: the values of the bits to be written. Only the bits in the mask
897 * will be written.
898 *
899 * Return: 0 on success, < 0 in case of error.
900 */
901int set_pgste_bits(struct mm_struct *mm, unsigned long hva,
902 unsigned long bits, unsigned long value)
903{
904 spinlock_t *ptl;
905 pgste_t new;
906 pte_t *ptep;
907
908 ptep = get_locked_pte(mm, hva, &ptl);
909 if (unlikely(!ptep))
910 return -EFAULT;
911 new = pgste_get_lock(ptep);
912
913 pgste_val(new) &= ~bits;
914 pgste_val(new) |= value & bits;
915
916 pgste_set_unlock(ptep, new);
917 pte_unmap_unlock(ptep, ptl);
918 return 0;
919}
920EXPORT_SYMBOL(set_pgste_bits);
921
922/**
923 * get_pgste - get the current PGSTE for the given address.
924 * @mm: the memory context. It must have PGSTEs, no check is performed here!
925 * @hva: the host virtual address of the page whose PGSTE is to be processed
926 * @pgstep: will be written with the current PGSTE for the given address.
927 *
928 * Return: 0 on success, < 0 in case of error.
929 */
930int get_pgste(struct mm_struct *mm, unsigned long hva, unsigned long *pgstep)
931{
932 spinlock_t *ptl;
933 pte_t *ptep;
934
935 ptep = get_locked_pte(mm, hva, &ptl);
936 if (unlikely(!ptep))
937 return -EFAULT;
938 *pgstep = pgste_val(pgste_get(ptep));
939 pte_unmap_unlock(ptep, ptl);
940 return 0;
941}
942EXPORT_SYMBOL(get_pgste);
790#endif 943#endif