diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/s390/kvm/intercept.c | 85 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.h | 3 | ||||
-rw-r--r-- | arch/s390/kvm/priv.c | 78 |
3 files changed, 81 insertions, 85 deletions
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index f0b8be0cc08d..5ee56e5acc23 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c | |||
@@ -22,87 +22,6 @@ | |||
22 | #include "trace.h" | 22 | #include "trace.h" |
23 | #include "trace-s390.h" | 23 | #include "trace-s390.h" |
24 | 24 | ||
25 | static int handle_lctlg(struct kvm_vcpu *vcpu) | ||
26 | { | ||
27 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; | ||
28 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; | ||
29 | u64 useraddr; | ||
30 | int reg, rc; | ||
31 | |||
32 | vcpu->stat.instruction_lctlg++; | ||
33 | |||
34 | useraddr = kvm_s390_get_base_disp_rsy(vcpu); | ||
35 | |||
36 | if (useraddr & 7) | ||
37 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
38 | |||
39 | reg = reg1; | ||
40 | |||
41 | VCPU_EVENT(vcpu, 5, "lctlg r1:%x, r3:%x, addr:%llx", reg1, reg3, | ||
42 | useraddr); | ||
43 | trace_kvm_s390_handle_lctl(vcpu, 1, reg1, reg3, useraddr); | ||
44 | |||
45 | do { | ||
46 | rc = get_guest(vcpu, vcpu->arch.sie_block->gcr[reg], | ||
47 | (u64 __user *) useraddr); | ||
48 | if (rc) | ||
49 | return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
50 | useraddr += 8; | ||
51 | if (reg == reg3) | ||
52 | break; | ||
53 | reg = (reg + 1) % 16; | ||
54 | } while (1); | ||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static int handle_lctl(struct kvm_vcpu *vcpu) | ||
59 | { | ||
60 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; | ||
61 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; | ||
62 | u64 useraddr; | ||
63 | u32 val = 0; | ||
64 | int reg, rc; | ||
65 | |||
66 | vcpu->stat.instruction_lctl++; | ||
67 | |||
68 | useraddr = kvm_s390_get_base_disp_rs(vcpu); | ||
69 | |||
70 | if (useraddr & 3) | ||
71 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
72 | |||
73 | VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x, addr:%llx", reg1, reg3, | ||
74 | useraddr); | ||
75 | trace_kvm_s390_handle_lctl(vcpu, 0, reg1, reg3, useraddr); | ||
76 | |||
77 | reg = reg1; | ||
78 | do { | ||
79 | rc = get_guest(vcpu, val, (u32 __user *) useraddr); | ||
80 | if (rc) | ||
81 | return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
82 | vcpu->arch.sie_block->gcr[reg] &= 0xffffffff00000000ul; | ||
83 | vcpu->arch.sie_block->gcr[reg] |= val; | ||
84 | useraddr += 4; | ||
85 | if (reg == reg3) | ||
86 | break; | ||
87 | reg = (reg + 1) % 16; | ||
88 | } while (1); | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static const intercept_handler_t eb_handlers[256] = { | ||
93 | [0x2f] = handle_lctlg, | ||
94 | [0x8a] = kvm_s390_handle_priv_eb, | ||
95 | }; | ||
96 | |||
97 | static int handle_eb(struct kvm_vcpu *vcpu) | ||
98 | { | ||
99 | intercept_handler_t handler; | ||
100 | |||
101 | handler = eb_handlers[vcpu->arch.sie_block->ipb & 0xff]; | ||
102 | if (handler) | ||
103 | return handler(vcpu); | ||
104 | return -EOPNOTSUPP; | ||
105 | } | ||
106 | 25 | ||
107 | static const intercept_handler_t instruction_handlers[256] = { | 26 | static const intercept_handler_t instruction_handlers[256] = { |
108 | [0x01] = kvm_s390_handle_01, | 27 | [0x01] = kvm_s390_handle_01, |
@@ -110,10 +29,10 @@ static const intercept_handler_t instruction_handlers[256] = { | |||
110 | [0x83] = kvm_s390_handle_diag, | 29 | [0x83] = kvm_s390_handle_diag, |
111 | [0xae] = kvm_s390_handle_sigp, | 30 | [0xae] = kvm_s390_handle_sigp, |
112 | [0xb2] = kvm_s390_handle_b2, | 31 | [0xb2] = kvm_s390_handle_b2, |
113 | [0xb7] = handle_lctl, | 32 | [0xb7] = kvm_s390_handle_lctl, |
114 | [0xb9] = kvm_s390_handle_b9, | 33 | [0xb9] = kvm_s390_handle_b9, |
115 | [0xe5] = kvm_s390_handle_e5, | 34 | [0xe5] = kvm_s390_handle_e5, |
116 | [0xeb] = handle_eb, | 35 | [0xeb] = kvm_s390_handle_eb, |
117 | }; | 36 | }; |
118 | 37 | ||
119 | static int handle_noop(struct kvm_vcpu *vcpu) | 38 | static int handle_noop(struct kvm_vcpu *vcpu) |
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h index 15795b8f8ff5..028ca9fd2158 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h | |||
@@ -132,7 +132,8 @@ int kvm_s390_handle_e5(struct kvm_vcpu *vcpu); | |||
132 | int kvm_s390_handle_01(struct kvm_vcpu *vcpu); | 132 | int kvm_s390_handle_01(struct kvm_vcpu *vcpu); |
133 | int kvm_s390_handle_b9(struct kvm_vcpu *vcpu); | 133 | int kvm_s390_handle_b9(struct kvm_vcpu *vcpu); |
134 | int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu); | 134 | int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu); |
135 | int kvm_s390_handle_priv_eb(struct kvm_vcpu *vcpu); | 135 | int kvm_s390_handle_lctl(struct kvm_vcpu *vcpu); |
136 | int kvm_s390_handle_eb(struct kvm_vcpu *vcpu); | ||
136 | 137 | ||
137 | /* implemented in sigp.c */ | 138 | /* implemented in sigp.c */ |
138 | int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu); | 139 | int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu); |
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 | ||