KVM: s390: fix sigp set prefix status stored cases
authorHeiko Carstens <heiko.carstens@de.ibm.com>
Tue, 26 Jun 2012 14:06:39 +0000 (16:06 +0200)
committerMarcelo Tosatti <mtosatti@redhat.com>
Tue, 3 Jul 2012 17:55:35 +0000 (14:55 -0300)
If an invalid parameter is passed or the addressed cpu is in an
incorrect state sigp set prefix will store a status.
This status must only have bits set as defined by the architecture.
The current kvm implementation missed to clear bits and also did
not set the intended status bit ("and" instead of "or" operation).

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
arch/s390/kvm/sigp.c

index caccc0ee9cee66c2a605ea2efc64ee0b9e6211ab..ca544d53557e60ca8605b99568e035cc7f82c015 100644 (file)
@@ -207,6 +207,7 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
        address = address & 0x7fffe000u;
        if (copy_from_guest_absolute(vcpu, &tmp, address, 1) ||
           copy_from_guest_absolute(vcpu, &tmp, address + PAGE_SIZE, 1)) {
+               *reg &= 0xffffffff00000000UL;
                *reg |= SIGP_STATUS_INVALID_PARAMETER;
                return 1; /* invalid parameter */
        }
@@ -220,8 +221,9 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
                li = fi->local_int[cpu_addr];
 
        if (li == NULL) {
+               *reg &= 0xffffffff00000000UL;
+               *reg |= SIGP_STATUS_INCORRECT_STATE;
                rc = 1; /* incorrect state */
-               *reg &= SIGP_STATUS_INCORRECT_STATE;
                kfree(inti);
                goto out_fi;
        }
@@ -229,8 +231,9 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
        spin_lock_bh(&li->lock);
        /* cpu must be in stopped state */
        if (!(atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) {
+               *reg &= 0xffffffff00000000UL;
+               *reg |= SIGP_STATUS_INCORRECT_STATE;
                rc = 1; /* incorrect state */
-               *reg &= SIGP_STATUS_INCORRECT_STATE;
                kfree(inti);
                goto out_li;
        }