diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2012-12-20 09:32:10 -0500 |
---|---|---|
committer | Marcelo Tosatti <mtosatti@redhat.com> | 2013-01-07 16:53:41 -0500 |
commit | f379aae558b8daff0f7a1c5fc225af5d35c741f7 (patch) | |
tree | 26f66b7da5a2883cc4049e838f4a1fb75ef604aa | |
parent | 48a3e950f4cee6a345ffbe9baf599f1e9a54c479 (diff) |
KVM: s390: In-kernel handling of I/O instructions.
Explicitely catch all channel I/O related instructions intercepts
in the kernel and set condition code 3 for them.
This paves the way for properly handling these instructions later
on.
Note: This is not architecture compliant (the previous code wasn't
either) since setting cc 3 is not the correct thing to do for some
of these instructions. For Linux guests, however, it still has the
intended effect of stopping css probing.
Reviewed-by: Marcelo Tosatti <mtosatti@redhat.com>
Reviewed-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rw-r--r-- | arch/s390/kvm/intercept.c | 19 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.h | 1 | ||||
-rw-r--r-- | arch/s390/kvm/priv.c | 56 |
3 files changed, 56 insertions, 20 deletions
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index 950c13ecaf60..71af87dbb42c 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c | |||
@@ -30,8 +30,6 @@ static int handle_lctlg(struct kvm_vcpu *vcpu) | |||
30 | int reg, rc; | 30 | int reg, rc; |
31 | 31 | ||
32 | vcpu->stat.instruction_lctlg++; | 32 | vcpu->stat.instruction_lctlg++; |
33 | if ((vcpu->arch.sie_block->ipb & 0xff) != 0x2f) | ||
34 | return -EOPNOTSUPP; | ||
35 | 33 | ||
36 | useraddr = kvm_s390_get_base_disp_rsy(vcpu); | 34 | useraddr = kvm_s390_get_base_disp_rsy(vcpu); |
37 | 35 | ||
@@ -95,6 +93,21 @@ static int handle_lctl(struct kvm_vcpu *vcpu) | |||
95 | return 0; | 93 | return 0; |
96 | } | 94 | } |
97 | 95 | ||
96 | static const intercept_handler_t eb_handlers[256] = { | ||
97 | [0x2f] = handle_lctlg, | ||
98 | [0x8a] = kvm_s390_handle_priv_eb, | ||
99 | }; | ||
100 | |||
101 | static int handle_eb(struct kvm_vcpu *vcpu) | ||
102 | { | ||
103 | intercept_handler_t handler; | ||
104 | |||
105 | handler = eb_handlers[vcpu->arch.sie_block->ipb & 0xff]; | ||
106 | if (handler) | ||
107 | return handler(vcpu); | ||
108 | return -EOPNOTSUPP; | ||
109 | } | ||
110 | |||
98 | static const intercept_handler_t instruction_handlers[256] = { | 111 | static const intercept_handler_t instruction_handlers[256] = { |
99 | [0x01] = kvm_s390_handle_01, | 112 | [0x01] = kvm_s390_handle_01, |
100 | [0x82] = kvm_s390_handle_lpsw, | 113 | [0x82] = kvm_s390_handle_lpsw, |
@@ -104,7 +117,7 @@ static const intercept_handler_t instruction_handlers[256] = { | |||
104 | [0xb7] = handle_lctl, | 117 | [0xb7] = handle_lctl, |
105 | [0xb9] = kvm_s390_handle_b9, | 118 | [0xb9] = kvm_s390_handle_b9, |
106 | [0xe5] = kvm_s390_handle_e5, | 119 | [0xe5] = kvm_s390_handle_e5, |
107 | [0xeb] = handle_lctlg, | 120 | [0xeb] = handle_eb, |
108 | }; | 121 | }; |
109 | 122 | ||
110 | static int handle_noop(struct kvm_vcpu *vcpu) | 123 | 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 1f7cc6ccf102..211b340385a7 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h | |||
@@ -120,6 +120,7 @@ int kvm_s390_handle_e5(struct kvm_vcpu *vcpu); | |||
120 | int kvm_s390_handle_01(struct kvm_vcpu *vcpu); | 120 | int kvm_s390_handle_01(struct kvm_vcpu *vcpu); |
121 | int kvm_s390_handle_b9(struct kvm_vcpu *vcpu); | 121 | int kvm_s390_handle_b9(struct kvm_vcpu *vcpu); |
122 | int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu); | 122 | int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu); |
123 | int kvm_s390_handle_priv_eb(struct kvm_vcpu *vcpu); | ||
123 | 124 | ||
124 | /* implemented in sigp.c */ | 125 | /* implemented in sigp.c */ |
125 | int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu); | 126 | int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu); |
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index d3cbcd3c9ada..8ad776f87856 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c | |||
@@ -127,20 +127,9 @@ static int handle_skey(struct kvm_vcpu *vcpu) | |||
127 | return 0; | 127 | return 0; |
128 | } | 128 | } |
129 | 129 | ||
130 | static int handle_stsch(struct kvm_vcpu *vcpu) | 130 | static int handle_io_inst(struct kvm_vcpu *vcpu) |
131 | { | 131 | { |
132 | vcpu->stat.instruction_stsch++; | 132 | VCPU_EVENT(vcpu, 4, "%s", "I/O instruction"); |
133 | VCPU_EVENT(vcpu, 4, "%s", "store subchannel - CC3"); | ||
134 | /* condition code 3 */ | ||
135 | vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); | ||
136 | vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44; | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static int handle_chsc(struct kvm_vcpu *vcpu) | ||
141 | { | ||
142 | vcpu->stat.instruction_chsc++; | ||
143 | VCPU_EVENT(vcpu, 4, "%s", "channel subsystem call - CC3"); | ||
144 | /* condition code 3 */ | 133 | /* condition code 3 */ |
145 | vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); | 134 | vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); |
146 | vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44; | 135 | vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44; |
@@ -375,7 +364,7 @@ out_fail: | |||
375 | return 0; | 364 | return 0; |
376 | } | 365 | } |
377 | 366 | ||
378 | static const intercept_handler_t priv_handlers[256] = { | 367 | static const intercept_handler_t b2_handlers[256] = { |
379 | [0x02] = handle_stidp, | 368 | [0x02] = handle_stidp, |
380 | [0x10] = handle_set_prefix, | 369 | [0x10] = handle_set_prefix, |
381 | [0x11] = handle_store_prefix, | 370 | [0x11] = handle_store_prefix, |
@@ -383,8 +372,22 @@ static const intercept_handler_t priv_handlers[256] = { | |||
383 | [0x29] = handle_skey, | 372 | [0x29] = handle_skey, |
384 | [0x2a] = handle_skey, | 373 | [0x2a] = handle_skey, |
385 | [0x2b] = handle_skey, | 374 | [0x2b] = handle_skey, |
386 | [0x34] = handle_stsch, | 375 | [0x30] = handle_io_inst, |
387 | [0x5f] = handle_chsc, | 376 | [0x31] = handle_io_inst, |
377 | [0x32] = handle_io_inst, | ||
378 | [0x33] = handle_io_inst, | ||
379 | [0x34] = handle_io_inst, | ||
380 | [0x35] = handle_io_inst, | ||
381 | [0x36] = handle_io_inst, | ||
382 | [0x37] = handle_io_inst, | ||
383 | [0x38] = handle_io_inst, | ||
384 | [0x39] = handle_io_inst, | ||
385 | [0x3a] = handle_io_inst, | ||
386 | [0x3b] = handle_io_inst, | ||
387 | [0x3c] = handle_io_inst, | ||
388 | [0x5f] = handle_io_inst, | ||
389 | [0x74] = handle_io_inst, | ||
390 | [0x76] = handle_io_inst, | ||
388 | [0x7d] = handle_stsi, | 391 | [0x7d] = handle_stsi, |
389 | [0xb1] = handle_stfl, | 392 | [0xb1] = handle_stfl, |
390 | [0xb2] = handle_lpswe, | 393 | [0xb2] = handle_lpswe, |
@@ -401,7 +404,7 @@ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu) | |||
401 | * state bit and (a) handle the instruction or (b) send a code 2 | 404 | * state bit and (a) handle the instruction or (b) send a code 2 |
402 | * program check. | 405 | * program check. |
403 | * Anything else goes to userspace.*/ | 406 | * Anything else goes to userspace.*/ |
404 | handler = priv_handlers[vcpu->arch.sie_block->ipa & 0x00ff]; | 407 | handler = b2_handlers[vcpu->arch.sie_block->ipa & 0x00ff]; |
405 | if (handler) { | 408 | if (handler) { |
406 | if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) | 409 | if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) |
407 | return kvm_s390_inject_program_int(vcpu, | 410 | return kvm_s390_inject_program_int(vcpu, |
@@ -432,6 +435,7 @@ static int handle_epsw(struct kvm_vcpu *vcpu) | |||
432 | 435 | ||
433 | static const intercept_handler_t b9_handlers[256] = { | 436 | static const intercept_handler_t b9_handlers[256] = { |
434 | [0x8d] = handle_epsw, | 437 | [0x8d] = handle_epsw, |
438 | [0x9c] = handle_io_inst, | ||
435 | }; | 439 | }; |
436 | 440 | ||
437 | int kvm_s390_handle_b9(struct kvm_vcpu *vcpu) | 441 | int kvm_s390_handle_b9(struct kvm_vcpu *vcpu) |
@@ -451,6 +455,24 @@ int kvm_s390_handle_b9(struct kvm_vcpu *vcpu) | |||
451 | return -EOPNOTSUPP; | 455 | return -EOPNOTSUPP; |
452 | } | 456 | } |
453 | 457 | ||
458 | static const intercept_handler_t eb_handlers[256] = { | ||
459 | [0x8a] = handle_io_inst, | ||
460 | }; | ||
461 | |||
462 | int kvm_s390_handle_priv_eb(struct kvm_vcpu *vcpu) | ||
463 | { | ||
464 | intercept_handler_t handler; | ||
465 | |||
466 | /* All eb instructions that end up here are privileged. */ | ||
467 | if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) | ||
468 | return kvm_s390_inject_program_int(vcpu, | ||
469 | PGM_PRIVILEGED_OPERATION); | ||
470 | handler = eb_handlers[vcpu->arch.sie_block->ipb & 0xff]; | ||
471 | if (handler) | ||
472 | return handler(vcpu); | ||
473 | return -EOPNOTSUPP; | ||
474 | } | ||
475 | |||
454 | static int handle_tprot(struct kvm_vcpu *vcpu) | 476 | static int handle_tprot(struct kvm_vcpu *vcpu) |
455 | { | 477 | { |
456 | u64 address1, address2; | 478 | u64 address1, address2; |