diff options
Diffstat (limited to 'arch/s390/kvm/priv.c')
-rw-r--r-- | arch/s390/kvm/priv.c | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index d715842f56ca..d3cbcd3c9ada 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <asm/debug.h> | 18 | #include <asm/debug.h> |
19 | #include <asm/ebcdic.h> | 19 | #include <asm/ebcdic.h> |
20 | #include <asm/sysinfo.h> | 20 | #include <asm/sysinfo.h> |
21 | #include <asm/ptrace.h> | ||
22 | #include <asm/compat.h> | ||
21 | #include "gaccess.h" | 23 | #include "gaccess.h" |
22 | #include "kvm-s390.h" | 24 | #include "kvm-s390.h" |
23 | #include "trace.h" | 25 | #include "trace.h" |
@@ -166,6 +168,99 @@ static int handle_stfl(struct kvm_vcpu *vcpu) | |||
166 | return 0; | 168 | return 0; |
167 | } | 169 | } |
168 | 170 | ||
171 | static void handle_new_psw(struct kvm_vcpu *vcpu) | ||
172 | { | ||
173 | /* Check whether the new psw is enabled for machine checks. */ | ||
174 | if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_MCHECK) | ||
175 | kvm_s390_deliver_pending_machine_checks(vcpu); | ||
176 | } | ||
177 | |||
178 | #define PSW_MASK_ADDR_MODE (PSW_MASK_EA | PSW_MASK_BA) | ||
179 | #define PSW_MASK_UNASSIGNED 0xb80800fe7fffffffUL | ||
180 | #define PSW_ADDR_24 0x00000000000fffffUL | ||
181 | #define PSW_ADDR_31 0x000000007fffffffUL | ||
182 | |||
183 | int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu) | ||
184 | { | ||
185 | u64 addr; | ||
186 | psw_compat_t new_psw; | ||
187 | |||
188 | if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) | ||
189 | return kvm_s390_inject_program_int(vcpu, | ||
190 | PGM_PRIVILEGED_OPERATION); | ||
191 | |||
192 | addr = kvm_s390_get_base_disp_s(vcpu); | ||
193 | |||
194 | if (addr & 7) { | ||
195 | kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
196 | goto out; | ||
197 | } | ||
198 | |||
199 | if (copy_from_guest(vcpu, &new_psw, addr, sizeof(new_psw))) { | ||
200 | kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
201 | goto out; | ||
202 | } | ||
203 | |||
204 | if (!(new_psw.mask & PSW32_MASK_BASE)) { | ||
205 | kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
206 | goto out; | ||
207 | } | ||
208 | |||
209 | vcpu->arch.sie_block->gpsw.mask = | ||
210 | (new_psw.mask & ~PSW32_MASK_BASE) << 32; | ||
211 | vcpu->arch.sie_block->gpsw.addr = new_psw.addr; | ||
212 | |||
213 | if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_UNASSIGNED) || | ||
214 | (!(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_ADDR_MODE) && | ||
215 | (vcpu->arch.sie_block->gpsw.addr & ~PSW_ADDR_24)) || | ||
216 | ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_ADDR_MODE) == | ||
217 | PSW_MASK_EA)) { | ||
218 | kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
219 | goto out; | ||
220 | } | ||
221 | |||
222 | handle_new_psw(vcpu); | ||
223 | out: | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static int handle_lpswe(struct kvm_vcpu *vcpu) | ||
228 | { | ||
229 | u64 addr; | ||
230 | psw_t new_psw; | ||
231 | |||
232 | addr = kvm_s390_get_base_disp_s(vcpu); | ||
233 | |||
234 | if (addr & 7) { | ||
235 | kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
236 | goto out; | ||
237 | } | ||
238 | |||
239 | if (copy_from_guest(vcpu, &new_psw, addr, sizeof(new_psw))) { | ||
240 | kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
241 | goto out; | ||
242 | } | ||
243 | |||
244 | vcpu->arch.sie_block->gpsw.mask = new_psw.mask; | ||
245 | vcpu->arch.sie_block->gpsw.addr = new_psw.addr; | ||
246 | |||
247 | if ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_UNASSIGNED) || | ||
248 | (((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_ADDR_MODE) == | ||
249 | PSW_MASK_BA) && | ||
250 | (vcpu->arch.sie_block->gpsw.addr & ~PSW_ADDR_31)) || | ||
251 | (!(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_ADDR_MODE) && | ||
252 | (vcpu->arch.sie_block->gpsw.addr & ~PSW_ADDR_24)) || | ||
253 | ((vcpu->arch.sie_block->gpsw.mask & PSW_MASK_ADDR_MODE) == | ||
254 | PSW_MASK_EA)) { | ||
255 | kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
256 | goto out; | ||
257 | } | ||
258 | |||
259 | handle_new_psw(vcpu); | ||
260 | out: | ||
261 | return 0; | ||
262 | } | ||
263 | |||
169 | static int handle_stidp(struct kvm_vcpu *vcpu) | 264 | static int handle_stidp(struct kvm_vcpu *vcpu) |
170 | { | 265 | { |
171 | u64 operand2; | 266 | u64 operand2; |
@@ -292,6 +387,7 @@ static const intercept_handler_t priv_handlers[256] = { | |||
292 | [0x5f] = handle_chsc, | 387 | [0x5f] = handle_chsc, |
293 | [0x7d] = handle_stsi, | 388 | [0x7d] = handle_stsi, |
294 | [0xb1] = handle_stfl, | 389 | [0xb1] = handle_stfl, |
390 | [0xb2] = handle_lpswe, | ||
295 | }; | 391 | }; |
296 | 392 | ||
297 | int kvm_s390_handle_b2(struct kvm_vcpu *vcpu) | 393 | int kvm_s390_handle_b2(struct kvm_vcpu *vcpu) |
@@ -316,6 +412,45 @@ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu) | |||
316 | return -EOPNOTSUPP; | 412 | return -EOPNOTSUPP; |
317 | } | 413 | } |
318 | 414 | ||
415 | static int handle_epsw(struct kvm_vcpu *vcpu) | ||
416 | { | ||
417 | int reg1, reg2; | ||
418 | |||
419 | reg1 = (vcpu->arch.sie_block->ipb & 0x00f00000) >> 24; | ||
420 | reg2 = (vcpu->arch.sie_block->ipb & 0x000f0000) >> 16; | ||
421 | |||
422 | /* This basically extracts the mask half of the psw. */ | ||
423 | vcpu->run->s.regs.gprs[reg1] &= 0xffffffff00000000; | ||
424 | vcpu->run->s.regs.gprs[reg1] |= vcpu->arch.sie_block->gpsw.mask >> 32; | ||
425 | if (reg2) { | ||
426 | vcpu->run->s.regs.gprs[reg2] &= 0xffffffff00000000; | ||
427 | vcpu->run->s.regs.gprs[reg2] |= | ||
428 | vcpu->arch.sie_block->gpsw.mask & 0x00000000ffffffff; | ||
429 | } | ||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | static const intercept_handler_t b9_handlers[256] = { | ||
434 | [0x8d] = handle_epsw, | ||
435 | }; | ||
436 | |||
437 | int kvm_s390_handle_b9(struct kvm_vcpu *vcpu) | ||
438 | { | ||
439 | intercept_handler_t handler; | ||
440 | |||
441 | /* This is handled just as for the B2 instructions. */ | ||
442 | handler = b9_handlers[vcpu->arch.sie_block->ipa & 0x00ff]; | ||
443 | if (handler) { | ||
444 | if ((handler != handle_epsw) && | ||
445 | (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)) | ||
446 | return kvm_s390_inject_program_int(vcpu, | ||
447 | PGM_PRIVILEGED_OPERATION); | ||
448 | else | ||
449 | return handler(vcpu); | ||
450 | } | ||
451 | return -EOPNOTSUPP; | ||
452 | } | ||
453 | |||
319 | static int handle_tprot(struct kvm_vcpu *vcpu) | 454 | static int handle_tprot(struct kvm_vcpu *vcpu) |
320 | { | 455 | { |
321 | u64 address1, address2; | 456 | u64 address1, address2; |