.. | .. |
---|
2 | 2 | /* |
---|
3 | 3 | * handling privileged instructions |
---|
4 | 4 | * |
---|
5 | | - * Copyright IBM Corp. 2008, 2018 |
---|
| 5 | + * Copyright IBM Corp. 2008, 2020 |
---|
6 | 6 | * |
---|
7 | 7 | * Author(s): Carsten Otte <cotte@de.ibm.com> |
---|
8 | 8 | * Christian Borntraeger <borntraeger@de.ibm.com> |
---|
.. | .. |
---|
13 | 13 | #include <linux/errno.h> |
---|
14 | 14 | #include <linux/compat.h> |
---|
15 | 15 | #include <linux/mm_types.h> |
---|
| 16 | +#include <linux/pgtable.h> |
---|
16 | 17 | |
---|
17 | 18 | #include <asm/asm-offsets.h> |
---|
18 | 19 | #include <asm/facility.h> |
---|
.. | .. |
---|
20 | 21 | #include <asm/debug.h> |
---|
21 | 22 | #include <asm/ebcdic.h> |
---|
22 | 23 | #include <asm/sysinfo.h> |
---|
23 | | -#include <asm/pgtable.h> |
---|
24 | 24 | #include <asm/page-states.h> |
---|
25 | | -#include <asm/pgalloc.h> |
---|
26 | 25 | #include <asm/gmap.h> |
---|
27 | 26 | #include <asm/io.h> |
---|
28 | 27 | #include <asm/ptrace.h> |
---|
29 | 28 | #include <asm/sclp.h> |
---|
| 29 | +#include <asm/ap.h> |
---|
30 | 30 | #include "gaccess.h" |
---|
31 | 31 | #include "kvm-s390.h" |
---|
32 | 32 | #include "trace.h" |
---|
.. | .. |
---|
102 | 102 | return kvm_s390_inject_prog_cond(vcpu, rc); |
---|
103 | 103 | |
---|
104 | 104 | VCPU_EVENT(vcpu, 3, "SCK: setting guest TOD to 0x%llx", gtod.tod); |
---|
105 | | - kvm_s390_set_tod_clock(vcpu->kvm, >od); |
---|
| 105 | + /* |
---|
| 106 | + * To set the TOD clock the kvm lock must be taken, but the vcpu lock |
---|
| 107 | + * is already held in handle_set_clock. The usual lock order is the |
---|
| 108 | + * opposite. As SCK is deprecated and should not be used in several |
---|
| 109 | + * cases, for example when the multiple epoch facility or TOD clock |
---|
| 110 | + * steering facility is installed (see Principles of Operation), a |
---|
| 111 | + * slow path can be used. If the lock can not be taken via try_lock, |
---|
| 112 | + * the instruction will be retried via -EAGAIN at a later point in |
---|
| 113 | + * time. |
---|
| 114 | + */ |
---|
| 115 | + if (!kvm_s390_try_set_tod_clock(vcpu->kvm, >od)) { |
---|
| 116 | + kvm_s390_retry_instr(vcpu); |
---|
| 117 | + return -EAGAIN; |
---|
| 118 | + } |
---|
106 | 119 | |
---|
107 | 120 | kvm_s390_set_psw_cc(vcpu, 0); |
---|
108 | 121 | return 0; |
---|
.. | .. |
---|
269 | 282 | return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); |
---|
270 | 283 | retry: |
---|
271 | 284 | unlocked = false; |
---|
272 | | - down_read(¤t->mm->mmap_sem); |
---|
| 285 | + mmap_read_lock(current->mm); |
---|
273 | 286 | rc = get_guest_storage_key(current->mm, vmaddr, &key); |
---|
274 | 287 | |
---|
275 | 288 | if (rc) { |
---|
276 | | - rc = fixup_user_fault(current, current->mm, vmaddr, |
---|
| 289 | + rc = fixup_user_fault(current->mm, vmaddr, |
---|
277 | 290 | FAULT_FLAG_WRITE, &unlocked); |
---|
278 | 291 | if (!rc) { |
---|
279 | | - up_read(¤t->mm->mmap_sem); |
---|
| 292 | + mmap_read_unlock(current->mm); |
---|
280 | 293 | goto retry; |
---|
281 | 294 | } |
---|
282 | 295 | } |
---|
283 | | - up_read(¤t->mm->mmap_sem); |
---|
| 296 | + mmap_read_unlock(current->mm); |
---|
284 | 297 | if (rc == -EFAULT) |
---|
285 | 298 | return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); |
---|
286 | 299 | if (rc < 0) |
---|
.. | .. |
---|
316 | 329 | return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); |
---|
317 | 330 | retry: |
---|
318 | 331 | unlocked = false; |
---|
319 | | - down_read(¤t->mm->mmap_sem); |
---|
| 332 | + mmap_read_lock(current->mm); |
---|
320 | 333 | rc = reset_guest_reference_bit(current->mm, vmaddr); |
---|
321 | 334 | if (rc < 0) { |
---|
322 | | - rc = fixup_user_fault(current, current->mm, vmaddr, |
---|
| 335 | + rc = fixup_user_fault(current->mm, vmaddr, |
---|
323 | 336 | FAULT_FLAG_WRITE, &unlocked); |
---|
324 | 337 | if (!rc) { |
---|
325 | | - up_read(¤t->mm->mmap_sem); |
---|
| 338 | + mmap_read_unlock(current->mm); |
---|
326 | 339 | goto retry; |
---|
327 | 340 | } |
---|
328 | 341 | } |
---|
329 | | - up_read(¤t->mm->mmap_sem); |
---|
| 342 | + mmap_read_unlock(current->mm); |
---|
330 | 343 | if (rc == -EFAULT) |
---|
331 | 344 | return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); |
---|
332 | 345 | if (rc < 0) |
---|
.. | .. |
---|
384 | 397 | if (kvm_is_error_hva(vmaddr)) |
---|
385 | 398 | return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); |
---|
386 | 399 | |
---|
387 | | - down_read(¤t->mm->mmap_sem); |
---|
| 400 | + mmap_read_lock(current->mm); |
---|
388 | 401 | rc = cond_set_guest_storage_key(current->mm, vmaddr, key, &oldkey, |
---|
389 | 402 | m3 & SSKE_NQ, m3 & SSKE_MR, |
---|
390 | 403 | m3 & SSKE_MC); |
---|
391 | 404 | |
---|
392 | 405 | if (rc < 0) { |
---|
393 | | - rc = fixup_user_fault(current, current->mm, vmaddr, |
---|
| 406 | + rc = fixup_user_fault(current->mm, vmaddr, |
---|
394 | 407 | FAULT_FLAG_WRITE, &unlocked); |
---|
395 | 408 | rc = !rc ? -EAGAIN : rc; |
---|
396 | 409 | } |
---|
397 | | - up_read(¤t->mm->mmap_sem); |
---|
| 410 | + mmap_read_unlock(current->mm); |
---|
398 | 411 | if (rc == -EFAULT) |
---|
399 | 412 | return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); |
---|
400 | 413 | if (rc == -EAGAIN) |
---|
.. | .. |
---|
594 | 607 | } |
---|
595 | 608 | } |
---|
596 | 609 | |
---|
| 610 | +/* |
---|
| 611 | + * handle_pqap: Handling pqap interception |
---|
| 612 | + * @vcpu: the vcpu having issue the pqap instruction |
---|
| 613 | + * |
---|
| 614 | + * We now support PQAP/AQIC instructions and we need to correctly |
---|
| 615 | + * answer the guest even if no dedicated driver's hook is available. |
---|
| 616 | + * |
---|
| 617 | + * The intercepting code calls a dedicated callback for this instruction |
---|
| 618 | + * if a driver did register one in the CRYPTO satellite of the |
---|
| 619 | + * SIE block. |
---|
| 620 | + * |
---|
| 621 | + * If no callback is available, the queues are not available, return this |
---|
| 622 | + * response code to the caller and set CC to 3. |
---|
| 623 | + * Else return the response code returned by the callback. |
---|
| 624 | + */ |
---|
| 625 | +static int handle_pqap(struct kvm_vcpu *vcpu) |
---|
| 626 | +{ |
---|
| 627 | + struct ap_queue_status status = {}; |
---|
| 628 | + unsigned long reg0; |
---|
| 629 | + int ret; |
---|
| 630 | + uint8_t fc; |
---|
| 631 | + |
---|
| 632 | + /* Verify that the AP instruction are available */ |
---|
| 633 | + if (!ap_instructions_available()) |
---|
| 634 | + return -EOPNOTSUPP; |
---|
| 635 | + /* Verify that the guest is allowed to use AP instructions */ |
---|
| 636 | + if (!(vcpu->arch.sie_block->eca & ECA_APIE)) |
---|
| 637 | + return -EOPNOTSUPP; |
---|
| 638 | + /* |
---|
| 639 | + * The only possibly intercepted functions when AP instructions are |
---|
| 640 | + * available for the guest are AQIC and TAPQ with the t bit set |
---|
| 641 | + * since we do not set IC.3 (FIII) we currently will only intercept |
---|
| 642 | + * the AQIC function code. |
---|
| 643 | + * Note: running nested under z/VM can result in intercepts for other |
---|
| 644 | + * function codes, e.g. PQAP(QCI). We do not support this and bail out. |
---|
| 645 | + */ |
---|
| 646 | + reg0 = vcpu->run->s.regs.gprs[0]; |
---|
| 647 | + fc = (reg0 >> 24) & 0xff; |
---|
| 648 | + if (fc != 0x03) |
---|
| 649 | + return -EOPNOTSUPP; |
---|
| 650 | + |
---|
| 651 | + /* PQAP instruction is allowed for guest kernel only */ |
---|
| 652 | + if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) |
---|
| 653 | + return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); |
---|
| 654 | + |
---|
| 655 | + /* Common PQAP instruction specification exceptions */ |
---|
| 656 | + /* bits 41-47 must all be zeros */ |
---|
| 657 | + if (reg0 & 0x007f0000UL) |
---|
| 658 | + return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); |
---|
| 659 | + /* APFT not install and T bit set */ |
---|
| 660 | + if (!test_kvm_facility(vcpu->kvm, 15) && (reg0 & 0x00800000UL)) |
---|
| 661 | + return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); |
---|
| 662 | + /* APXA not installed and APID greater 64 or APQI greater 16 */ |
---|
| 663 | + if (!(vcpu->kvm->arch.crypto.crycbd & 0x02) && (reg0 & 0x0000c0f0UL)) |
---|
| 664 | + return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); |
---|
| 665 | + |
---|
| 666 | + /* AQIC function code specific exception */ |
---|
| 667 | + /* facility 65 not present for AQIC function code */ |
---|
| 668 | + if (!test_kvm_facility(vcpu->kvm, 65)) |
---|
| 669 | + return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); |
---|
| 670 | + |
---|
| 671 | + /* |
---|
| 672 | + * Verify that the hook callback is registered, lock the owner |
---|
| 673 | + * and call the hook. |
---|
| 674 | + */ |
---|
| 675 | + if (vcpu->kvm->arch.crypto.pqap_hook) { |
---|
| 676 | + if (!try_module_get(vcpu->kvm->arch.crypto.pqap_hook->owner)) |
---|
| 677 | + return -EOPNOTSUPP; |
---|
| 678 | + ret = vcpu->kvm->arch.crypto.pqap_hook->hook(vcpu); |
---|
| 679 | + module_put(vcpu->kvm->arch.crypto.pqap_hook->owner); |
---|
| 680 | + if (!ret && vcpu->run->s.regs.gprs[1] & 0x00ff0000) |
---|
| 681 | + kvm_s390_set_psw_cc(vcpu, 3); |
---|
| 682 | + return ret; |
---|
| 683 | + } |
---|
| 684 | + /* |
---|
| 685 | + * A vfio_driver must register a hook. |
---|
| 686 | + * No hook means no driver to enable the SIE CRYCB and no queues. |
---|
| 687 | + * We send this response to the guest. |
---|
| 688 | + */ |
---|
| 689 | + status.response_code = 0x01; |
---|
| 690 | + memcpy(&vcpu->run->s.regs.gprs[1], &status, sizeof(status)); |
---|
| 691 | + kvm_s390_set_psw_cc(vcpu, 3); |
---|
| 692 | + return 0; |
---|
| 693 | +} |
---|
| 694 | + |
---|
597 | 695 | static int handle_stfl(struct kvm_vcpu *vcpu) |
---|
598 | 696 | { |
---|
599 | 697 | int rc; |
---|
.. | .. |
---|
790 | 888 | |
---|
791 | 889 | operand2 = kvm_s390_get_base_disp_s(vcpu, &ar); |
---|
792 | 890 | |
---|
793 | | - if (operand2 & 0xfff) |
---|
| 891 | + if (!kvm_s390_pv_cpu_is_protected(vcpu) && (operand2 & 0xfff)) |
---|
794 | 892 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); |
---|
795 | 893 | |
---|
796 | 894 | switch (fc) { |
---|
.. | .. |
---|
811 | 909 | handle_stsi_3_2_2(vcpu, (void *) mem); |
---|
812 | 910 | break; |
---|
813 | 911 | } |
---|
814 | | - |
---|
815 | | - rc = write_guest(vcpu, operand2, ar, (void *)mem, PAGE_SIZE); |
---|
| 912 | + if (kvm_s390_pv_cpu_is_protected(vcpu)) { |
---|
| 913 | + memcpy((void *)sida_origin(vcpu->arch.sie_block), (void *)mem, |
---|
| 914 | + PAGE_SIZE); |
---|
| 915 | + rc = 0; |
---|
| 916 | + } else { |
---|
| 917 | + rc = write_guest(vcpu, operand2, ar, (void *)mem, PAGE_SIZE); |
---|
| 918 | + } |
---|
816 | 919 | if (rc) { |
---|
817 | 920 | rc = kvm_s390_inject_prog_cond(vcpu, rc); |
---|
818 | 921 | goto out; |
---|
.. | .. |
---|
880 | 983 | return handle_sthyi(vcpu); |
---|
881 | 984 | case 0x7d: |
---|
882 | 985 | return handle_stsi(vcpu); |
---|
| 986 | + case 0xaf: |
---|
| 987 | + return handle_pqap(vcpu); |
---|
883 | 988 | case 0xb1: |
---|
884 | 989 | return handle_stfl(vcpu); |
---|
885 | 990 | case 0xb2: |
---|
.. | .. |
---|
1000 | 1105 | |
---|
1001 | 1106 | if (rc) |
---|
1002 | 1107 | return rc; |
---|
1003 | | - down_read(¤t->mm->mmap_sem); |
---|
| 1108 | + mmap_read_lock(current->mm); |
---|
1004 | 1109 | rc = cond_set_guest_storage_key(current->mm, vmaddr, |
---|
1005 | 1110 | key, NULL, nq, mr, mc); |
---|
1006 | 1111 | if (rc < 0) { |
---|
1007 | | - rc = fixup_user_fault(current, current->mm, vmaddr, |
---|
| 1112 | + rc = fixup_user_fault(current->mm, vmaddr, |
---|
1008 | 1113 | FAULT_FLAG_WRITE, &unlocked); |
---|
1009 | 1114 | rc = !rc ? -EAGAIN : rc; |
---|
1010 | 1115 | } |
---|
1011 | | - up_read(¤t->mm->mmap_sem); |
---|
| 1116 | + mmap_read_unlock(current->mm); |
---|
1012 | 1117 | if (rc == -EFAULT) |
---|
1013 | 1118 | return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); |
---|
1014 | 1119 | if (rc == -EAGAIN) |
---|
.. | .. |
---|
1031 | 1136 | } |
---|
1032 | 1137 | |
---|
1033 | 1138 | /* |
---|
1034 | | - * Must be called with relevant read locks held (kvm->mm->mmap_sem, kvm->srcu) |
---|
| 1139 | + * Must be called with relevant read locks held (kvm->mm->mmap_lock, kvm->srcu) |
---|
1035 | 1140 | */ |
---|
1036 | 1141 | static inline int __do_essa(struct kvm_vcpu *vcpu, const int orc) |
---|
1037 | 1142 | { |
---|
.. | .. |
---|
1129 | 1234 | * already correct, we do nothing and avoid the lock. |
---|
1130 | 1235 | */ |
---|
1131 | 1236 | if (vcpu->kvm->mm->context.uses_cmm == 0) { |
---|
1132 | | - down_write(&vcpu->kvm->mm->mmap_sem); |
---|
| 1237 | + mmap_write_lock(vcpu->kvm->mm); |
---|
1133 | 1238 | vcpu->kvm->mm->context.uses_cmm = 1; |
---|
1134 | | - up_write(&vcpu->kvm->mm->mmap_sem); |
---|
| 1239 | + mmap_write_unlock(vcpu->kvm->mm); |
---|
1135 | 1240 | } |
---|
1136 | 1241 | /* |
---|
1137 | 1242 | * If we are here, we are supposed to have CMMA enabled in |
---|
.. | .. |
---|
1148 | 1253 | } else { |
---|
1149 | 1254 | int srcu_idx; |
---|
1150 | 1255 | |
---|
1151 | | - down_read(&vcpu->kvm->mm->mmap_sem); |
---|
| 1256 | + mmap_read_lock(vcpu->kvm->mm); |
---|
1152 | 1257 | srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); |
---|
1153 | 1258 | i = __do_essa(vcpu, orc); |
---|
1154 | 1259 | srcu_read_unlock(&vcpu->kvm->srcu, srcu_idx); |
---|
1155 | | - up_read(&vcpu->kvm->mm->mmap_sem); |
---|
| 1260 | + mmap_read_unlock(vcpu->kvm->mm); |
---|
1156 | 1261 | if (i < 0) |
---|
1157 | 1262 | return i; |
---|
1158 | 1263 | /* Account for the possible extra cbrl entry */ |
---|
.. | .. |
---|
1160 | 1265 | } |
---|
1161 | 1266 | vcpu->arch.sie_block->cbrlo &= PAGE_MASK; /* reset nceo */ |
---|
1162 | 1267 | cbrlo = phys_to_virt(vcpu->arch.sie_block->cbrlo); |
---|
1163 | | - down_read(&gmap->mm->mmap_sem); |
---|
| 1268 | + mmap_read_lock(gmap->mm); |
---|
1164 | 1269 | for (i = 0; i < entries; ++i) |
---|
1165 | 1270 | __gmap_zap(gmap, cbrlo[i]); |
---|
1166 | | - up_read(&gmap->mm->mmap_sem); |
---|
| 1271 | + mmap_read_unlock(gmap->mm); |
---|
1167 | 1272 | return 0; |
---|
1168 | 1273 | } |
---|
1169 | 1274 | |
---|