diff options
author | Thomas Huth <thuth@linux.vnet.ibm.com> | 2014-01-27 06:06:19 -0500 |
---|---|---|
committer | Christian Borntraeger <borntraeger@de.ibm.com> | 2014-03-04 04:41:02 -0500 |
commit | 13b191ae4afc0c29a5cd768f521ede5c72a608cb (patch) | |
tree | 9782e29f87e54962a458644cccbada51eb2b786c /arch/s390/kvm | |
parent | ff520a6327e83ef55515d1be3d0a1b10c084f59c (diff) |
KVM: s390: Fixed CC of SIGP SET_PREFIX handler
When SIGP SET_PREFIX is called with an illegal CPU id, it must return
the condition code 3 ("not operational") instead of 1. Also fixed the
order in which the checks are done - CC3 has a higher priority than CC1.
And while we're at it, this patch also get rid of the floating interrupt
lock here by using kvm_get_vcpu() to get the local_int struct of the
destination CPU.
Signed-off-by: Thomas Huth <thuth@linux.vnet.ibm.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Diffstat (limited to 'arch/s390/kvm')
-rw-r--r-- | arch/s390/kvm/sigp.c | 24 |
1 files changed, 8 insertions, 16 deletions
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c index fe9442d39f0e..466eefa18708 100644 --- a/arch/s390/kvm/sigp.c +++ b/arch/s390/kvm/sigp.c | |||
@@ -249,12 +249,18 @@ static int __sigp_set_arch(struct kvm_vcpu *vcpu, u32 parameter) | |||
249 | static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address, | 249 | static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address, |
250 | u64 *reg) | 250 | u64 *reg) |
251 | { | 251 | { |
252 | struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; | 252 | struct kvm_s390_local_interrupt *li; |
253 | struct kvm_s390_local_interrupt *li = NULL; | 253 | struct kvm_vcpu *dst_vcpu = NULL; |
254 | struct kvm_s390_interrupt_info *inti; | 254 | struct kvm_s390_interrupt_info *inti; |
255 | int rc; | 255 | int rc; |
256 | u8 tmp; | 256 | u8 tmp; |
257 | 257 | ||
258 | if (cpu_addr < KVM_MAX_VCPUS) | ||
259 | dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr); | ||
260 | if (!dst_vcpu) | ||
261 | return SIGP_CC_NOT_OPERATIONAL; | ||
262 | li = &dst_vcpu->arch.local_int; | ||
263 | |||
258 | /* make sure that the new value is valid memory */ | 264 | /* make sure that the new value is valid memory */ |
259 | address = address & 0x7fffe000u; | 265 | address = address & 0x7fffe000u; |
260 | if (copy_from_guest_absolute(vcpu, &tmp, address, 1) || | 266 | if (copy_from_guest_absolute(vcpu, &tmp, address, 1) || |
@@ -268,18 +274,6 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address, | |||
268 | if (!inti) | 274 | if (!inti) |
269 | return SIGP_CC_BUSY; | 275 | return SIGP_CC_BUSY; |
270 | 276 | ||
271 | spin_lock(&fi->lock); | ||
272 | if (cpu_addr < KVM_MAX_VCPUS) | ||
273 | li = fi->local_int[cpu_addr]; | ||
274 | |||
275 | if (li == NULL) { | ||
276 | *reg &= 0xffffffff00000000UL; | ||
277 | *reg |= SIGP_STATUS_INCORRECT_STATE; | ||
278 | rc = SIGP_CC_STATUS_STORED; | ||
279 | kfree(inti); | ||
280 | goto out_fi; | ||
281 | } | ||
282 | |||
283 | spin_lock_bh(&li->lock); | 277 | spin_lock_bh(&li->lock); |
284 | /* cpu must be in stopped state */ | 278 | /* cpu must be in stopped state */ |
285 | if (!(atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) { | 279 | if (!(atomic_read(li->cpuflags) & CPUSTAT_STOPPED)) { |
@@ -302,8 +296,6 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address, | |||
302 | VCPU_EVENT(vcpu, 4, "set prefix of cpu %02x to %x", cpu_addr, address); | 296 | VCPU_EVENT(vcpu, 4, "set prefix of cpu %02x to %x", cpu_addr, address); |
303 | out_li: | 297 | out_li: |
304 | spin_unlock_bh(&li->lock); | 298 | spin_unlock_bh(&li->lock); |
305 | out_fi: | ||
306 | spin_unlock(&fi->lock); | ||
307 | return rc; | 299 | return rc; |
308 | } | 300 | } |
309 | 301 | ||