.. | .. |
---|
9 | 9 | #include <linux/vmalloc.h> |
---|
10 | 10 | #include <linux/mm_types.h> |
---|
11 | 11 | #include <linux/err.h> |
---|
| 12 | +#include <linux/pgtable.h> |
---|
12 | 13 | |
---|
13 | | -#include <asm/pgtable.h> |
---|
14 | 14 | #include <asm/gmap.h> |
---|
15 | 15 | #include "kvm-s390.h" |
---|
16 | 16 | #include "gaccess.h" |
---|
.. | .. |
---|
505 | 505 | switch (prot) { |
---|
506 | 506 | case PROT_TYPE_IEP: |
---|
507 | 507 | tec->b61 = 1; |
---|
508 | | - /* FALL THROUGH */ |
---|
| 508 | + fallthrough; |
---|
509 | 509 | case PROT_TYPE_LA: |
---|
510 | 510 | tec->b56 = 1; |
---|
511 | 511 | break; |
---|
.. | .. |
---|
514 | 514 | break; |
---|
515 | 515 | case PROT_TYPE_ALC: |
---|
516 | 516 | tec->b60 = 1; |
---|
517 | | - /* FALL THROUGH */ |
---|
| 517 | + fallthrough; |
---|
518 | 518 | case PROT_TYPE_DAT: |
---|
519 | 519 | tec->b61 = 1; |
---|
520 | 520 | break; |
---|
521 | 521 | } |
---|
522 | | - /* FALL THROUGH */ |
---|
| 522 | + fallthrough; |
---|
523 | 523 | case PGM_ASCE_TYPE: |
---|
524 | 524 | case PGM_PAGE_TRANSLATION: |
---|
525 | 525 | case PGM_REGION_FIRST_TRANS: |
---|
.. | .. |
---|
534 | 534 | tec->addr = gva >> PAGE_SHIFT; |
---|
535 | 535 | tec->fsi = mode == GACC_STORE ? FSI_STORE : FSI_FETCH; |
---|
536 | 536 | tec->as = psw_bits(vcpu->arch.sie_block->gpsw).as; |
---|
537 | | - /* FALL THROUGH */ |
---|
| 537 | + fallthrough; |
---|
538 | 538 | case PGM_ALEN_TRANSLATION: |
---|
539 | 539 | case PGM_ALE_SEQUENCE: |
---|
540 | 540 | case PGM_ASTE_VALIDITY: |
---|
.. | .. |
---|
677 | 677 | dat_protection |= rfte.p; |
---|
678 | 678 | ptr = rfte.rto * PAGE_SIZE + vaddr.rsx * 8; |
---|
679 | 679 | } |
---|
680 | | - /* fallthrough */ |
---|
| 680 | + fallthrough; |
---|
681 | 681 | case ASCE_TYPE_REGION2: { |
---|
682 | 682 | union region2_table_entry rste; |
---|
683 | 683 | |
---|
.. | .. |
---|
695 | 695 | dat_protection |= rste.p; |
---|
696 | 696 | ptr = rste.rto * PAGE_SIZE + vaddr.rtx * 8; |
---|
697 | 697 | } |
---|
698 | | - /* fallthrough */ |
---|
| 698 | + fallthrough; |
---|
699 | 699 | case ASCE_TYPE_REGION3: { |
---|
700 | 700 | union region3_table_entry rtte; |
---|
701 | 701 | |
---|
.. | .. |
---|
723 | 723 | dat_protection |= rtte.fc0.p; |
---|
724 | 724 | ptr = rtte.fc0.sto * PAGE_SIZE + vaddr.sx * 8; |
---|
725 | 725 | } |
---|
726 | | - /* fallthrough */ |
---|
| 726 | + fallthrough; |
---|
727 | 727 | case ASCE_TYPE_SEGMENT: { |
---|
728 | 728 | union segment_table_entry ste; |
---|
729 | 729 | |
---|
.. | .. |
---|
976 | 976 | * kvm_s390_shadow_tables - walk the guest page table and create shadow tables |
---|
977 | 977 | * @sg: pointer to the shadow guest address space structure |
---|
978 | 978 | * @saddr: faulting address in the shadow gmap |
---|
979 | | - * @pgt: pointer to the page table address result |
---|
| 979 | + * @pgt: pointer to the beginning of the page table for the given address if |
---|
| 980 | + * successful (return value 0), or to the first invalid DAT entry in |
---|
| 981 | + * case of exceptions (return value > 0) |
---|
980 | 982 | * @fake: pgt references contiguous guest memory block, not a pgtable |
---|
981 | 983 | */ |
---|
982 | 984 | static int kvm_s390_shadow_tables(struct gmap *sg, unsigned long saddr, |
---|
.. | .. |
---|
1034 | 1036 | rfte.val = ptr; |
---|
1035 | 1037 | goto shadow_r2t; |
---|
1036 | 1038 | } |
---|
| 1039 | + *pgt = ptr + vaddr.rfx * 8; |
---|
1037 | 1040 | rc = gmap_read_table(parent, ptr + vaddr.rfx * 8, &rfte.val); |
---|
1038 | 1041 | if (rc) |
---|
1039 | 1042 | return rc; |
---|
.. | .. |
---|
1050 | 1053 | rc = gmap_shadow_r2t(sg, saddr, rfte.val, *fake); |
---|
1051 | 1054 | if (rc) |
---|
1052 | 1055 | return rc; |
---|
1053 | | - } /* fallthrough */ |
---|
| 1056 | + } |
---|
| 1057 | + fallthrough; |
---|
1054 | 1058 | case ASCE_TYPE_REGION2: { |
---|
1055 | 1059 | union region2_table_entry rste; |
---|
1056 | 1060 | |
---|
.. | .. |
---|
1059 | 1063 | rste.val = ptr; |
---|
1060 | 1064 | goto shadow_r3t; |
---|
1061 | 1065 | } |
---|
| 1066 | + *pgt = ptr + vaddr.rsx * 8; |
---|
1062 | 1067 | rc = gmap_read_table(parent, ptr + vaddr.rsx * 8, &rste.val); |
---|
1063 | 1068 | if (rc) |
---|
1064 | 1069 | return rc; |
---|
.. | .. |
---|
1076 | 1081 | rc = gmap_shadow_r3t(sg, saddr, rste.val, *fake); |
---|
1077 | 1082 | if (rc) |
---|
1078 | 1083 | return rc; |
---|
1079 | | - } /* fallthrough */ |
---|
| 1084 | + } |
---|
| 1085 | + fallthrough; |
---|
1080 | 1086 | case ASCE_TYPE_REGION3: { |
---|
1081 | 1087 | union region3_table_entry rtte; |
---|
1082 | 1088 | |
---|
.. | .. |
---|
1085 | 1091 | rtte.val = ptr; |
---|
1086 | 1092 | goto shadow_sgt; |
---|
1087 | 1093 | } |
---|
| 1094 | + *pgt = ptr + vaddr.rtx * 8; |
---|
1088 | 1095 | rc = gmap_read_table(parent, ptr + vaddr.rtx * 8, &rtte.val); |
---|
1089 | 1096 | if (rc) |
---|
1090 | 1097 | return rc; |
---|
.. | .. |
---|
1111 | 1118 | rc = gmap_shadow_sgt(sg, saddr, rtte.val, *fake); |
---|
1112 | 1119 | if (rc) |
---|
1113 | 1120 | return rc; |
---|
1114 | | - } /* fallthrough */ |
---|
| 1121 | + } |
---|
| 1122 | + fallthrough; |
---|
1115 | 1123 | case ASCE_TYPE_SEGMENT: { |
---|
1116 | 1124 | union segment_table_entry ste; |
---|
1117 | 1125 | |
---|
.. | .. |
---|
1120 | 1128 | ste.val = ptr; |
---|
1121 | 1129 | goto shadow_pgt; |
---|
1122 | 1130 | } |
---|
| 1131 | + *pgt = ptr + vaddr.sx * 8; |
---|
1123 | 1132 | rc = gmap_read_table(parent, ptr + vaddr.sx * 8, &ste.val); |
---|
1124 | 1133 | if (rc) |
---|
1125 | 1134 | return rc; |
---|
.. | .. |
---|
1154 | 1163 | * @vcpu: virtual cpu |
---|
1155 | 1164 | * @sg: pointer to the shadow guest address space structure |
---|
1156 | 1165 | * @saddr: faulting address in the shadow gmap |
---|
| 1166 | + * @datptr: will contain the address of the faulting DAT table entry, or of |
---|
| 1167 | + * the valid leaf, plus some flags |
---|
1157 | 1168 | * |
---|
1158 | 1169 | * Returns: - 0 if the shadow fault was successfully resolved |
---|
1159 | 1170 | * - > 0 (pgm exception code) on exceptions while faulting |
---|
.. | .. |
---|
1162 | 1173 | * - -ENOMEM if out of memory |
---|
1163 | 1174 | */ |
---|
1164 | 1175 | int kvm_s390_shadow_fault(struct kvm_vcpu *vcpu, struct gmap *sg, |
---|
1165 | | - unsigned long saddr) |
---|
| 1176 | + unsigned long saddr, unsigned long *datptr) |
---|
1166 | 1177 | { |
---|
1167 | 1178 | union vaddress vaddr; |
---|
1168 | 1179 | union page_table_entry pte; |
---|
1169 | | - unsigned long pgt; |
---|
| 1180 | + unsigned long pgt = 0; |
---|
1170 | 1181 | int dat_protection, fake; |
---|
1171 | 1182 | int rc; |
---|
1172 | 1183 | |
---|
1173 | | - down_read(&sg->mm->mmap_sem); |
---|
| 1184 | + mmap_read_lock(sg->mm); |
---|
1174 | 1185 | /* |
---|
1175 | 1186 | * We don't want any guest-2 tables to change - so the parent |
---|
1176 | 1187 | * tables/pointers we read stay valid - unshadowing is however |
---|
.. | .. |
---|
1188 | 1199 | pte.val = pgt + vaddr.px * PAGE_SIZE; |
---|
1189 | 1200 | goto shadow_page; |
---|
1190 | 1201 | } |
---|
1191 | | - if (!rc) |
---|
1192 | | - rc = gmap_read_table(sg->parent, pgt + vaddr.px * 8, &pte.val); |
---|
| 1202 | + |
---|
| 1203 | + switch (rc) { |
---|
| 1204 | + case PGM_SEGMENT_TRANSLATION: |
---|
| 1205 | + case PGM_REGION_THIRD_TRANS: |
---|
| 1206 | + case PGM_REGION_SECOND_TRANS: |
---|
| 1207 | + case PGM_REGION_FIRST_TRANS: |
---|
| 1208 | + pgt |= PEI_NOT_PTE; |
---|
| 1209 | + break; |
---|
| 1210 | + case 0: |
---|
| 1211 | + pgt += vaddr.px * 8; |
---|
| 1212 | + rc = gmap_read_table(sg->parent, pgt, &pte.val); |
---|
| 1213 | + } |
---|
| 1214 | + if (datptr) |
---|
| 1215 | + *datptr = pgt | dat_protection * PEI_DAT_PROT; |
---|
1193 | 1216 | if (!rc && pte.i) |
---|
1194 | 1217 | rc = PGM_PAGE_TRANSLATION; |
---|
1195 | 1218 | if (!rc && pte.z) |
---|
.. | .. |
---|
1199 | 1222 | if (!rc) |
---|
1200 | 1223 | rc = gmap_shadow_page(sg, saddr, __pte(pte.val)); |
---|
1201 | 1224 | ipte_unlock(vcpu); |
---|
1202 | | - up_read(&sg->mm->mmap_sem); |
---|
| 1225 | + mmap_read_unlock(sg->mm); |
---|
1203 | 1226 | return rc; |
---|
1204 | 1227 | } |
---|