aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kvm
diff options
context:
space:
mode:
authorDavid Hildenbrand <dahi@linux.vnet.ibm.com>2016-04-18 07:24:52 -0400
committerChristian Borntraeger <borntraeger@de.ibm.com>2016-06-20 03:54:51 -0400
commitfd8d4e3ab6993e194287a59c4d3a6a43da86b8dc (patch)
tree7b604322fdb22cda63e86edf7a81775df321b2e9 /arch/s390/kvm
parent5b062bd4940f81e0bd26b0d75f56d7abebf0309f (diff)
s390/mm: support EDAT1 for gmap shadows
If the guest is enabled for EDAT1, we can easily create shadows for guest2 -> guest3 provided tables that make use of EDAT1. If guest2 references a 1MB page, this memory looks consecutive for guest2, but it might not be so for us. Therefore we have to create fake page tables. We can easily add that to our existing infrastructure. The invalidation mechanism will make sure that fake page tables are removed when the parent table (sgt table entry) is changed. As EDAT1 also introduced protection on all page table levels, we have to also shadow these correctly. We don't have to care about: - ACCF-Validity Control in STE - Access-Control Bits in STE - Fetch-Protection Bit in STE - Common-Segment Bit in STE As all bits might be dropped and there is no guaranteed that they are active ("unpredictable whether the CPU uses these bits", "may be used"). Without using EDAT1 in the shadow ourselfes (STE-format control == 0), simply shadowing these bits would not be enough. They would be ignored. Please note that we are using the "fake" flag to make this look consistent with further changes (EDAT2, real-space designation support) and don't let the shadow functions handle fc=1 stes. In the future, with huge pages in the host, gmap_shadow_pgt() could simply try to map a huge host page if "fake" is set to one and indicate via return value that no lower fake tables / shadow ptes are required. Acked-by: Martin Schwidefsky <schwidefsky@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/kvm')
-rw-r--r--arch/s390/kvm/gaccess.c34
1 files changed, 27 insertions, 7 deletions
diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c
index a85bc6c6a098..af1fc6fa7b74 100644
--- a/arch/s390/kvm/gaccess.c
+++ b/arch/s390/kvm/gaccess.c
@@ -953,9 +953,11 @@ int kvm_s390_check_low_addr_prot_real(struct kvm_vcpu *vcpu, unsigned long gra)
953 * @sg: pointer to the shadow guest address space structure 953 * @sg: pointer to the shadow guest address space structure
954 * @saddr: faulting address in the shadow gmap 954 * @saddr: faulting address in the shadow gmap
955 * @pgt: pointer to the page table address result 955 * @pgt: pointer to the page table address result
956 * @fake: pgt references contiguous guest memory block, not a pgtable
956 */ 957 */
957static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr, 958static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr,
958 unsigned long *pgt, int *dat_protection) 959 unsigned long *pgt, int *dat_protection,
960 int *fake)
959{ 961{
960 struct gmap *parent; 962 struct gmap *parent;
961 union asce asce; 963 union asce asce;
@@ -963,6 +965,7 @@ static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr,
963 unsigned long ptr; 965 unsigned long ptr;
964 int rc; 966 int rc;
965 967
968 *fake = 0;
966 parent = sg->parent; 969 parent = sg->parent;
967 vaddr.addr = saddr; 970 vaddr.addr = saddr;
968 asce.val = sg->orig_asce; 971 asce.val = sg->orig_asce;
@@ -1060,10 +1063,20 @@ static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr,
1060 if (ste.cs && asce.p) 1063 if (ste.cs && asce.p)
1061 return PGM_TRANSLATION_SPEC; 1064 return PGM_TRANSLATION_SPEC;
1062 *dat_protection = ste.fc0.p; 1065 *dat_protection = ste.fc0.p;
1063 rc = gmap_shadow_pgt(sg, saddr, ste.val); 1066 if (ste.fc && sg->edat_level >= 1) {
1067 bool prot = ste.fc1.p;
1068
1069 *fake = 1;
1070 ptr = ste.fc1.sfaa << 20UL;
1071 ste.val = ptr;
1072 ste.fc0.p = prot;
1073 goto shadow_pgt;
1074 }
1075 ptr = ste.fc0.pto << 11UL;
1076shadow_pgt:
1077 rc = gmap_shadow_pgt(sg, saddr, ste.val, *fake);
1064 if (rc) 1078 if (rc)
1065 return rc; 1079 return rc;
1066 ptr = ste.fc0.pto * 2048;
1067 } 1080 }
1068 } 1081 }
1069 /* Return the parent address of the page table */ 1082 /* Return the parent address of the page table */
@@ -1089,7 +1102,7 @@ int kvm_s390_shadow_fault(struct kvm_vcpu *vcpu, struct gmap *sg,
1089 union vaddress vaddr; 1102 union vaddress vaddr;
1090 union page_table_entry pte; 1103 union page_table_entry pte;
1091 unsigned long pgt; 1104 unsigned long pgt;
1092 int dat_protection; 1105 int dat_protection, fake;
1093 int rc; 1106 int rc;
1094 1107
1095 down_read(&sg->mm->mmap_sem); 1108 down_read(&sg->mm->mmap_sem);
@@ -1100,17 +1113,24 @@ int kvm_s390_shadow_fault(struct kvm_vcpu *vcpu, struct gmap *sg,
1100 */ 1113 */
1101 ipte_lock(vcpu); 1114 ipte_lock(vcpu);
1102 1115
1103 rc = gmap_shadow_pgt_lookup(sg, saddr, &pgt, &dat_protection); 1116 rc = gmap_shadow_pgt_lookup(sg, saddr, &pgt, &dat_protection, &fake);
1104 if (rc) 1117 if (rc)
1105 rc = kvm_s390_shadow_tables(sg, saddr, &pgt, &dat_protection); 1118 rc = kvm_s390_shadow_tables(sg, saddr, &pgt, &dat_protection,
1119 &fake);
1106 1120
1107 vaddr.addr = saddr; 1121 vaddr.addr = saddr;
1122 if (fake) {
1123 /* offset in 1MB guest memory block */
1124 pte.val = pgt + ((unsigned long) vaddr.px << 12UL);
1125 goto shadow_page;
1126 }
1108 if (!rc) 1127 if (!rc)
1109 rc = gmap_read_table(sg->parent, pgt + vaddr.px * 8, &pte.val); 1128 rc = gmap_read_table(sg->parent, pgt + vaddr.px * 8, &pte.val);
1110 if (!rc && pte.i) 1129 if (!rc && pte.i)
1111 rc = PGM_PAGE_TRANSLATION; 1130 rc = PGM_PAGE_TRANSLATION;
1112 if (!rc && (pte.z || pte.co)) 1131 if (!rc && (pte.z || (pte.co && sg->edat_level < 1)))
1113 rc = PGM_TRANSLATION_SPEC; 1132 rc = PGM_TRANSLATION_SPEC;
1133shadow_page:
1114 pte.p |= dat_protection; 1134 pte.p |= dat_protection;
1115 if (!rc) 1135 if (!rc)
1116 rc = gmap_shadow_page(sg, saddr, __pte(pte.val)); 1136 rc = gmap_shadow_page(sg, saddr, __pte(pte.val));