diff options
Diffstat (limited to 'arch/s390/kvm/priv.c')
-rw-r--r-- | arch/s390/kvm/priv.c | 78 |
1 files changed, 77 insertions, 1 deletions
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index 4b8fb6cc3c45..c7603f5b4c28 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c | |||
@@ -590,11 +590,87 @@ int kvm_s390_handle_b9(struct kvm_vcpu *vcpu) | |||
590 | return -EOPNOTSUPP; | 590 | return -EOPNOTSUPP; |
591 | } | 591 | } |
592 | 592 | ||
593 | int kvm_s390_handle_lctl(struct kvm_vcpu *vcpu) | ||
594 | { | ||
595 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; | ||
596 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; | ||
597 | u64 useraddr; | ||
598 | u32 val = 0; | ||
599 | int reg, rc; | ||
600 | |||
601 | vcpu->stat.instruction_lctl++; | ||
602 | |||
603 | if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) | ||
604 | return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); | ||
605 | |||
606 | useraddr = kvm_s390_get_base_disp_rs(vcpu); | ||
607 | |||
608 | if (useraddr & 3) | ||
609 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
610 | |||
611 | VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x, addr:%llx", reg1, reg3, | ||
612 | useraddr); | ||
613 | trace_kvm_s390_handle_lctl(vcpu, 0, reg1, reg3, useraddr); | ||
614 | |||
615 | reg = reg1; | ||
616 | do { | ||
617 | rc = get_guest(vcpu, val, (u32 __user *) useraddr); | ||
618 | if (rc) | ||
619 | return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
620 | vcpu->arch.sie_block->gcr[reg] &= 0xffffffff00000000ul; | ||
621 | vcpu->arch.sie_block->gcr[reg] |= val; | ||
622 | useraddr += 4; | ||
623 | if (reg == reg3) | ||
624 | break; | ||
625 | reg = (reg + 1) % 16; | ||
626 | } while (1); | ||
627 | |||
628 | return 0; | ||
629 | } | ||
630 | |||
631 | static int handle_lctlg(struct kvm_vcpu *vcpu) | ||
632 | { | ||
633 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; | ||
634 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; | ||
635 | u64 useraddr; | ||
636 | int reg, rc; | ||
637 | |||
638 | vcpu->stat.instruction_lctlg++; | ||
639 | |||
640 | if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) | ||
641 | return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); | ||
642 | |||
643 | useraddr = kvm_s390_get_base_disp_rsy(vcpu); | ||
644 | |||
645 | if (useraddr & 7) | ||
646 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
647 | |||
648 | reg = reg1; | ||
649 | |||
650 | VCPU_EVENT(vcpu, 5, "lctlg r1:%x, r3:%x, addr:%llx", reg1, reg3, | ||
651 | useraddr); | ||
652 | trace_kvm_s390_handle_lctl(vcpu, 1, reg1, reg3, useraddr); | ||
653 | |||
654 | do { | ||
655 | rc = get_guest(vcpu, vcpu->arch.sie_block->gcr[reg], | ||
656 | (u64 __user *) useraddr); | ||
657 | if (rc) | ||
658 | return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
659 | useraddr += 8; | ||
660 | if (reg == reg3) | ||
661 | break; | ||
662 | reg = (reg + 1) % 16; | ||
663 | } while (1); | ||
664 | |||
665 | return 0; | ||
666 | } | ||
667 | |||
593 | static const intercept_handler_t eb_handlers[256] = { | 668 | static const intercept_handler_t eb_handlers[256] = { |
669 | [0x2f] = handle_lctlg, | ||
594 | [0x8a] = handle_io_inst, | 670 | [0x8a] = handle_io_inst, |
595 | }; | 671 | }; |
596 | 672 | ||
597 | int kvm_s390_handle_priv_eb(struct kvm_vcpu *vcpu) | 673 | int kvm_s390_handle_eb(struct kvm_vcpu *vcpu) |
598 | { | 674 | { |
599 | intercept_handler_t handler; | 675 | intercept_handler_t handler; |
600 | 676 | ||