diff options
Diffstat (limited to 'arch/s390/kvm/intercept.c')
-rw-r--r-- | arch/s390/kvm/intercept.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index e757230b982c..7f7347b5f34a 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c | |||
@@ -18,6 +18,86 @@ | |||
18 | #include <asm/kvm_host.h> | 18 | #include <asm/kvm_host.h> |
19 | 19 | ||
20 | #include "kvm-s390.h" | 20 | #include "kvm-s390.h" |
21 | #include "gaccess.h" | ||
22 | |||
23 | static int handle_lctg(struct kvm_vcpu *vcpu) | ||
24 | { | ||
25 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; | ||
26 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; | ||
27 | int base2 = vcpu->arch.sie_block->ipb >> 28; | ||
28 | int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16) + | ||
29 | ((vcpu->arch.sie_block->ipb & 0xff00) << 4); | ||
30 | u64 useraddr; | ||
31 | int reg, rc; | ||
32 | |||
33 | vcpu->stat.instruction_lctg++; | ||
34 | if ((vcpu->arch.sie_block->ipb & 0xff) != 0x2f) | ||
35 | return -ENOTSUPP; | ||
36 | |||
37 | useraddr = disp2; | ||
38 | if (base2) | ||
39 | useraddr += vcpu->arch.guest_gprs[base2]; | ||
40 | |||
41 | reg = reg1; | ||
42 | |||
43 | VCPU_EVENT(vcpu, 5, "lctg r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2, | ||
44 | disp2); | ||
45 | |||
46 | do { | ||
47 | rc = get_guest_u64(vcpu, useraddr, | ||
48 | &vcpu->arch.sie_block->gcr[reg]); | ||
49 | if (rc == -EFAULT) { | ||
50 | kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
51 | break; | ||
52 | } | ||
53 | useraddr += 8; | ||
54 | if (reg == reg3) | ||
55 | break; | ||
56 | reg = (reg + 1) % 16; | ||
57 | } while (1); | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static int handle_lctl(struct kvm_vcpu *vcpu) | ||
62 | { | ||
63 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; | ||
64 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; | ||
65 | int base2 = vcpu->arch.sie_block->ipb >> 28; | ||
66 | int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); | ||
67 | u64 useraddr; | ||
68 | u32 val = 0; | ||
69 | int reg, rc; | ||
70 | |||
71 | vcpu->stat.instruction_lctl++; | ||
72 | |||
73 | useraddr = disp2; | ||
74 | if (base2) | ||
75 | useraddr += vcpu->arch.guest_gprs[base2]; | ||
76 | |||
77 | VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2, | ||
78 | disp2); | ||
79 | |||
80 | reg = reg1; | ||
81 | do { | ||
82 | rc = get_guest_u32(vcpu, useraddr, &val); | ||
83 | if (rc == -EFAULT) { | ||
84 | kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
85 | break; | ||
86 | } | ||
87 | vcpu->arch.sie_block->gcr[reg] &= 0xffffffff00000000ul; | ||
88 | vcpu->arch.sie_block->gcr[reg] |= val; | ||
89 | useraddr += 4; | ||
90 | if (reg == reg3) | ||
91 | break; | ||
92 | reg = (reg + 1) % 16; | ||
93 | } while (1); | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static intercept_handler_t instruction_handlers[256] = { | ||
98 | [0xb7] = handle_lctl, | ||
99 | [0xeb] = handle_lctg, | ||
100 | }; | ||
21 | 101 | ||
22 | static int handle_noop(struct kvm_vcpu *vcpu) | 102 | static int handle_noop(struct kvm_vcpu *vcpu) |
23 | { | 103 | { |
@@ -58,10 +138,46 @@ static int handle_validity(struct kvm_vcpu *vcpu) | |||
58 | return -ENOTSUPP; | 138 | return -ENOTSUPP; |
59 | } | 139 | } |
60 | 140 | ||
141 | static int handle_instruction(struct kvm_vcpu *vcpu) | ||
142 | { | ||
143 | intercept_handler_t handler; | ||
144 | |||
145 | vcpu->stat.exit_instruction++; | ||
146 | handler = instruction_handlers[vcpu->arch.sie_block->ipa >> 8]; | ||
147 | if (handler) | ||
148 | return handler(vcpu); | ||
149 | return -ENOTSUPP; | ||
150 | } | ||
151 | |||
152 | static int handle_prog(struct kvm_vcpu *vcpu) | ||
153 | { | ||
154 | vcpu->stat.exit_program_interruption++; | ||
155 | return kvm_s390_inject_program_int(vcpu, vcpu->arch.sie_block->iprcc); | ||
156 | } | ||
157 | |||
158 | static int handle_instruction_and_prog(struct kvm_vcpu *vcpu) | ||
159 | { | ||
160 | int rc, rc2; | ||
161 | |||
162 | vcpu->stat.exit_instr_and_program++; | ||
163 | rc = handle_instruction(vcpu); | ||
164 | rc2 = handle_prog(vcpu); | ||
165 | |||
166 | if (rc == -ENOTSUPP) | ||
167 | vcpu->arch.sie_block->icptcode = 0x04; | ||
168 | if (rc) | ||
169 | return rc; | ||
170 | return rc2; | ||
171 | } | ||
172 | |||
61 | static const intercept_handler_t intercept_funcs[0x48 >> 2] = { | 173 | static const intercept_handler_t intercept_funcs[0x48 >> 2] = { |
62 | [0x00 >> 2] = handle_noop, | 174 | [0x00 >> 2] = handle_noop, |
175 | [0x04 >> 2] = handle_instruction, | ||
176 | [0x08 >> 2] = handle_prog, | ||
177 | [0x0C >> 2] = handle_instruction_and_prog, | ||
63 | [0x10 >> 2] = handle_noop, | 178 | [0x10 >> 2] = handle_noop, |
64 | [0x14 >> 2] = handle_noop, | 179 | [0x14 >> 2] = handle_noop, |
180 | [0x1C >> 2] = kvm_s390_handle_wait, | ||
65 | [0x20 >> 2] = handle_validity, | 181 | [0x20 >> 2] = handle_validity, |
66 | [0x28 >> 2] = handle_stop, | 182 | [0x28 >> 2] = handle_stop, |
67 | }; | 183 | }; |