|
27 | 27 | #include <asm/io.h> |
28 | 28 | #include <asm/ptrace.h> |
29 | 29 | #include <asm/sclp.h> |
| 30 | +#include <asm/ap.h> |
30 | 31 | #include "gaccess.h" |
31 | 32 | #include "kvm-s390.h" |
32 | 33 | #include "trace.h" |
@@ -592,6 +593,89 @@ static int handle_io_inst(struct kvm_vcpu *vcpu) |
592 | 593 | } |
593 | 594 | } |
594 | 595 |
|
| 596 | +/* |
| 597 | + * handle_pqap: Handling pqap interception |
| 598 | + * @vcpu: the vcpu having issue the pqap instruction |
| 599 | + * |
| 600 | + * We now support PQAP/AQIC instructions and we need to correctly |
| 601 | + * answer the guest even if no dedicated driver's hook is available. |
| 602 | + * |
| 603 | + * The intercepting code calls a dedicated callback for this instruction |
| 604 | + * if a driver did register one in the CRYPTO satellite of the |
| 605 | + * SIE block. |
| 606 | + * |
| 607 | + * If no callback is available, the queues are not available, return this |
| 608 | + * response code to the caller and set CC to 3. |
| 609 | + * Else return the response code returned by the callback. |
| 610 | + */ |
| 611 | +static int handle_pqap(struct kvm_vcpu *vcpu) |
| 612 | +{ |
| 613 | + struct ap_queue_status status = {}; |
| 614 | + unsigned long reg0; |
| 615 | + int ret; |
| 616 | + uint8_t fc; |
| 617 | + |
| 618 | + /* Verify that the AP instruction are available */ |
| 619 | + if (!ap_instructions_available()) |
| 620 | + return -EOPNOTSUPP; |
| 621 | + /* Verify that the guest is allowed to use AP instructions */ |
| 622 | + if (!(vcpu->arch.sie_block->eca & ECA_APIE)) |
| 623 | + return -EOPNOTSUPP; |
| 624 | + /* |
| 625 | + * The only possibly intercepted functions when AP instructions are |
| 626 | + * available for the guest are AQIC and TAPQ with the t bit set |
| 627 | + * since we do not set IC.3 (FIII) we currently will only intercept |
| 628 | + * the AQIC function code. |
| 629 | + */ |
| 630 | + reg0 = vcpu->run->s.regs.gprs[0]; |
| 631 | + fc = (reg0 >> 24) & 0xff; |
| 632 | + if (WARN_ON_ONCE(fc != 0x03)) |
| 633 | + return -EOPNOTSUPP; |
| 634 | + |
| 635 | + /* PQAP instruction is allowed for guest kernel only */ |
| 636 | + if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) |
| 637 | + return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); |
| 638 | + |
| 639 | + /* Common PQAP instruction specification exceptions */ |
| 640 | + /* bits 41-47 must all be zeros */ |
| 641 | + if (reg0 & 0x007f0000UL) |
| 642 | + return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); |
| 643 | + /* APFT not install and T bit set */ |
| 644 | + if (!test_kvm_facility(vcpu->kvm, 15) && (reg0 & 0x00800000UL)) |
| 645 | + return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); |
| 646 | + /* APXA not installed and APID greater 64 or APQI greater 16 */ |
| 647 | + if (!(vcpu->kvm->arch.crypto.crycbd & 0x02) && (reg0 & 0x0000c0f0UL)) |
| 648 | + return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); |
| 649 | + |
| 650 | + /* AQIC function code specific exception */ |
| 651 | + /* facility 65 not present for AQIC function code */ |
| 652 | + if (!test_kvm_facility(vcpu->kvm, 65)) |
| 653 | + return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); |
| 654 | + |
| 655 | + /* |
| 656 | + * Verify that the hook callback is registered, lock the owner |
| 657 | + * and call the hook. |
| 658 | + */ |
| 659 | + if (vcpu->kvm->arch.crypto.pqap_hook) { |
| 660 | + if (!try_module_get(vcpu->kvm->arch.crypto.pqap_hook->owner)) |
| 661 | + return -EOPNOTSUPP; |
| 662 | + ret = vcpu->kvm->arch.crypto.pqap_hook->hook(vcpu); |
| 663 | + module_put(vcpu->kvm->arch.crypto.pqap_hook->owner); |
| 664 | + if (!ret && vcpu->run->s.regs.gprs[1] & 0x00ff0000) |
| 665 | + kvm_s390_set_psw_cc(vcpu, 3); |
| 666 | + return ret; |
| 667 | + } |
| 668 | + /* |
| 669 | + * A vfio_driver must register a hook. |
| 670 | + * No hook means no driver to enable the SIE CRYCB and no queues. |
| 671 | + * We send this response to the guest. |
| 672 | + */ |
| 673 | + status.response_code = 0x01; |
| 674 | + memcpy(&vcpu->run->s.regs.gprs[1], &status, sizeof(status)); |
| 675 | + kvm_s390_set_psw_cc(vcpu, 3); |
| 676 | + return 0; |
| 677 | +} |
| 678 | + |
595 | 679 | static int handle_stfl(struct kvm_vcpu *vcpu) |
596 | 680 | { |
597 | 681 | int rc; |
@@ -878,6 +962,8 @@ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu) |
878 | 962 | return handle_sthyi(vcpu); |
879 | 963 | case 0x7d: |
880 | 964 | return handle_stsi(vcpu); |
| 965 | + case 0xaf: |
| 966 | + return handle_pqap(vcpu); |
881 | 967 | case 0xb1: |
882 | 968 | return handle_stfl(vcpu); |
883 | 969 | case 0xb2: |
|
0 commit comments