KVM: s390: In-kernel handling of I/O instructions.
authorCornelia Huck <cornelia.huck@de.ibm.com>
Thu, 20 Dec 2012 14:32:10 +0000 (15:32 +0100)
committerMarcelo Tosatti <mtosatti@redhat.com>
Mon, 7 Jan 2013 21:53:41 +0000 (19:53 -0200)
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>
arch/s390/kvm/intercept.c
arch/s390/kvm/kvm-s390.h
arch/s390/kvm/priv.c

index 950c13ecaf607d412d133d7577ec4f51188b663b..71af87dbb42c045227e0d2feeecdb27af40af1a8 100644 (file)
@@ -30,8 +30,6 @@ static int handle_lctlg(struct kvm_vcpu *vcpu)
        int reg, rc;
 
        vcpu->stat.instruction_lctlg++;
-       if ((vcpu->arch.sie_block->ipb & 0xff) != 0x2f)
-               return -EOPNOTSUPP;
 
        useraddr = kvm_s390_get_base_disp_rsy(vcpu);
 
@@ -95,6 +93,21 @@ static int handle_lctl(struct kvm_vcpu *vcpu)
        return 0;
 }
 
+static const intercept_handler_t eb_handlers[256] = {
+       [0x2f] = handle_lctlg,
+       [0x8a] = kvm_s390_handle_priv_eb,
+};
+
+static int handle_eb(struct kvm_vcpu *vcpu)
+{
+       intercept_handler_t handler;
+
+       handler = eb_handlers[vcpu->arch.sie_block->ipb & 0xff];
+       if (handler)
+               return handler(vcpu);
+       return -EOPNOTSUPP;
+}
+
 static const intercept_handler_t instruction_handlers[256] = {
        [0x01] = kvm_s390_handle_01,
        [0x82] = kvm_s390_handle_lpsw,
@@ -104,7 +117,7 @@ static const intercept_handler_t instruction_handlers[256] = {
        [0xb7] = handle_lctl,
        [0xb9] = kvm_s390_handle_b9,
        [0xe5] = kvm_s390_handle_e5,
-       [0xeb] = handle_lctlg,
+       [0xeb] = handle_eb,
 };
 
 static int handle_noop(struct kvm_vcpu *vcpu)
index 1f7cc6ccf10294afcea8a908dd48392e6398e1c6..211b340385a7f5de2ab4d46b1a1a797feff97679 100644 (file)
@@ -120,6 +120,7 @@ int kvm_s390_handle_e5(struct kvm_vcpu *vcpu);
 int kvm_s390_handle_01(struct kvm_vcpu *vcpu);
 int kvm_s390_handle_b9(struct kvm_vcpu *vcpu);
 int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu);
+int kvm_s390_handle_priv_eb(struct kvm_vcpu *vcpu);
 
 /* implemented in sigp.c */
 int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
index d3cbcd3c9ada6d73a82f8a324474b9bdd2e5fea4..8ad776f8785660f9edad604feb8dba598d18de44 100644 (file)
@@ -127,20 +127,9 @@ static int handle_skey(struct kvm_vcpu *vcpu)
        return 0;
 }
 
-static int handle_stsch(struct kvm_vcpu *vcpu)
+static int handle_io_inst(struct kvm_vcpu *vcpu)
 {
-       vcpu->stat.instruction_stsch++;
-       VCPU_EVENT(vcpu, 4, "%s", "store subchannel - CC3");
-       /* condition code 3 */
-       vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
-       vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44;
-       return 0;
-}
-
-static int handle_chsc(struct kvm_vcpu *vcpu)
-{
-       vcpu->stat.instruction_chsc++;
-       VCPU_EVENT(vcpu, 4, "%s", "channel subsystem call - CC3");
+       VCPU_EVENT(vcpu, 4, "%s", "I/O instruction");
        /* condition code 3 */
        vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
        vcpu->arch.sie_block->gpsw.mask |= (3 & 3ul) << 44;
@@ -375,7 +364,7 @@ out_fail:
        return 0;
 }
 
-static const intercept_handler_t priv_handlers[256] = {
+static const intercept_handler_t b2_handlers[256] = {
        [0x02] = handle_stidp,
        [0x10] = handle_set_prefix,
        [0x11] = handle_store_prefix,
@@ -383,8 +372,22 @@ static const intercept_handler_t priv_handlers[256] = {
        [0x29] = handle_skey,
        [0x2a] = handle_skey,
        [0x2b] = handle_skey,
-       [0x34] = handle_stsch,
-       [0x5f] = handle_chsc,
+       [0x30] = handle_io_inst,
+       [0x31] = handle_io_inst,
+       [0x32] = handle_io_inst,
+       [0x33] = handle_io_inst,
+       [0x34] = handle_io_inst,
+       [0x35] = handle_io_inst,
+       [0x36] = handle_io_inst,
+       [0x37] = handle_io_inst,
+       [0x38] = handle_io_inst,
+       [0x39] = handle_io_inst,
+       [0x3a] = handle_io_inst,
+       [0x3b] = handle_io_inst,
+       [0x3c] = handle_io_inst,
+       [0x5f] = handle_io_inst,
+       [0x74] = handle_io_inst,
+       [0x76] = handle_io_inst,
        [0x7d] = handle_stsi,
        [0xb1] = handle_stfl,
        [0xb2] = handle_lpswe,
@@ -401,7 +404,7 @@ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu)
         * state bit and (a) handle the instruction or (b) send a code 2
         * program check.
         * Anything else goes to userspace.*/
-       handler = priv_handlers[vcpu->arch.sie_block->ipa & 0x00ff];
+       handler = b2_handlers[vcpu->arch.sie_block->ipa & 0x00ff];
        if (handler) {
                if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
                        return kvm_s390_inject_program_int(vcpu,
@@ -432,6 +435,7 @@ static int handle_epsw(struct kvm_vcpu *vcpu)
 
 static const intercept_handler_t b9_handlers[256] = {
        [0x8d] = handle_epsw,
+       [0x9c] = handle_io_inst,
 };
 
 int kvm_s390_handle_b9(struct kvm_vcpu *vcpu)
@@ -451,6 +455,24 @@ int kvm_s390_handle_b9(struct kvm_vcpu *vcpu)
        return -EOPNOTSUPP;
 }
 
+static const intercept_handler_t eb_handlers[256] = {
+       [0x8a] = handle_io_inst,
+};
+
+int kvm_s390_handle_priv_eb(struct kvm_vcpu *vcpu)
+{
+       intercept_handler_t handler;
+
+       /* All eb instructions that end up here are privileged. */
+       if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+               return kvm_s390_inject_program_int(vcpu,
+                                                  PGM_PRIVILEGED_OPERATION);
+       handler = eb_handlers[vcpu->arch.sie_block->ipb & 0xff];
+       if (handler)
+               return handler(vcpu);
+       return -EOPNOTSUPP;
+}
+
 static int handle_tprot(struct kvm_vcpu *vcpu)
 {
        u64 address1, address2;