aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kvm/priv.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kvm/priv.c')
-rw-r--r--arch/s390/kvm/priv.c78
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
593int 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
631static 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
593static const intercept_handler_t eb_handlers[256] = { 668static 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
597int kvm_s390_handle_priv_eb(struct kvm_vcpu *vcpu) 673int kvm_s390_handle_eb(struct kvm_vcpu *vcpu)
598{ 674{
599 intercept_handler_t handler; 675 intercept_handler_t handler;
600 676