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.c135
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
171static 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
183int 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);
223out:
224 return 0;
225}
226
227static 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);
260out:
261 return 0;
262}
263
169static int handle_stidp(struct kvm_vcpu *vcpu) 264static 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
297int kvm_s390_handle_b2(struct kvm_vcpu *vcpu) 393int 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
415static 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
433static const intercept_handler_t b9_handlers[256] = {
434 [0x8d] = handle_epsw,
435};
436
437int 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
319static int handle_tprot(struct kvm_vcpu *vcpu) 454static int handle_tprot(struct kvm_vcpu *vcpu)
320{ 455{
321 u64 address1, address2; 456 u64 address1, address2;