s390: fix save and restore of the floating-point-control register
The FPC_VALID_MASK has been used to check the validity of the value to be loaded into the floating-point-control register. With the introduction of the floating-point extension facility and the decimal-floating-point additional bits have been defined which need to be checked in a non straight forward way. So far these bits have been ignored which can cause an incorrect results for decimal- floating-point operations, e.g. an incorrect rounding mode to be set after signal return. The static check with the FPC_VALID_MASK is replaced with a trial load of the floating-point-control value, see test_fp_ctl. In addition an information leak with the padding word between the floating-point-control word and the floating-point registers in the s390_fp_regs is fixed. Reported-by: Heiko Carstens <heiko.carstens@de.ibm.com> Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
@@ -343,10 +343,11 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
|
||||
|
||||
void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
|
||||
{
|
||||
save_fp_regs(&vcpu->arch.host_fpregs);
|
||||
save_fp_ctl(&vcpu->arch.host_fpregs.fpc);
|
||||
save_fp_regs(vcpu->arch.host_fpregs.fprs);
|
||||
save_access_regs(vcpu->arch.host_acrs);
|
||||
vcpu->arch.guest_fpregs.fpc &= FPC_VALID_MASK;
|
||||
restore_fp_regs(&vcpu->arch.guest_fpregs);
|
||||
restore_fp_ctl(&vcpu->arch.guest_fpregs.fpc);
|
||||
restore_fp_regs(vcpu->arch.guest_fpregs.fprs);
|
||||
restore_access_regs(vcpu->run->s.regs.acrs);
|
||||
gmap_enable(vcpu->arch.gmap);
|
||||
atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
|
||||
@@ -356,9 +357,11 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
|
||||
gmap_disable(vcpu->arch.gmap);
|
||||
save_fp_regs(&vcpu->arch.guest_fpregs);
|
||||
save_fp_ctl(&vcpu->arch.guest_fpregs.fpc);
|
||||
save_fp_regs(vcpu->arch.guest_fpregs.fprs);
|
||||
save_access_regs(vcpu->run->s.regs.acrs);
|
||||
restore_fp_regs(&vcpu->arch.host_fpregs);
|
||||
restore_fp_ctl(&vcpu->arch.host_fpregs.fpc);
|
||||
restore_fp_regs(vcpu->arch.host_fpregs.fprs);
|
||||
restore_access_regs(vcpu->arch.host_acrs);
|
||||
}
|
||||
|
||||
@@ -618,9 +621,12 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
|
||||
|
||||
int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
|
||||
{
|
||||
if (test_fp_ctl(fpu->fpc))
|
||||
return -EINVAL;
|
||||
memcpy(&vcpu->arch.guest_fpregs.fprs, &fpu->fprs, sizeof(fpu->fprs));
|
||||
vcpu->arch.guest_fpregs.fpc = fpu->fpc & FPC_VALID_MASK;
|
||||
restore_fp_regs(&vcpu->arch.guest_fpregs);
|
||||
vcpu->arch.guest_fpregs.fpc = fpu->fpc;
|
||||
restore_fp_ctl(&vcpu->arch.guest_fpregs.fpc);
|
||||
restore_fp_regs(vcpu->arch.guest_fpregs.fprs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -876,7 +882,8 @@ int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
|
||||
* copying in vcpu load/put. Lets update our copies before we save
|
||||
* it into the save area
|
||||
*/
|
||||
save_fp_regs(&vcpu->arch.guest_fpregs);
|
||||
save_fp_ctl(&vcpu->arch.guest_fpregs.fpc);
|
||||
save_fp_regs(vcpu->arch.guest_fpregs.fprs);
|
||||
save_access_regs(vcpu->run->s.regs.acrs);
|
||||
|
||||
if (__guestcopy(vcpu, addr + offsetof(struct save_area, fp_regs),
|
||||
|
Reference in New Issue
Block a user