aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
authorChristian Borntraeger <borntraeger@de.ibm.com>2013-01-25 09:34:17 -0500
committerGleb Natapov <gleb@redhat.com>2013-01-30 05:35:59 -0500
commit0c29b2293b25527a1759cbd22b106f19258636b6 (patch)
treefd9f0f38e9361aef6fd1d3f0f854fb0cbc47c67b /arch/s390
parentc98d3683ce675d689121147ed00e7c4af4737518 (diff)
s390/kvm: Fix instruction decoding
Instructions with long displacement have a signed displacement. Currently the sign bit is interpreted as 2^20: Lets fix it by doing the sign extension from 20bit to 32bit and then use it as a signed variable in the addition (see kvm_s390_get_base_disp_rsy). Furthermore, there are lots of "int" in that code. This is problematic, because shifting on a signed integer is undefined/implementation defined if the bit value happens to be negative. Fortunately the promotion rules will make the right hand side unsigned anyway, so there is no real problem right now. Let's convert them anyway to unsigned where appropriate to avoid problems if the code is changed or copy/pasted later on. Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Gleb Natapov <gleb@redhat.com>
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/kvm/kvm-s390.h25
1 files changed, 14 insertions, 11 deletions
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 3e05deff21b6..4d89d64a8161 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -67,8 +67,8 @@ static inline void kvm_s390_set_prefix(struct kvm_vcpu *vcpu, u32 prefix)
67 67
68static inline u64 kvm_s390_get_base_disp_s(struct kvm_vcpu *vcpu) 68static inline u64 kvm_s390_get_base_disp_s(struct kvm_vcpu *vcpu)
69{ 69{
70 int base2 = vcpu->arch.sie_block->ipb >> 28; 70 u32 base2 = vcpu->arch.sie_block->ipb >> 28;
71 int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); 71 u32 disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
72 72
73 return (base2 ? vcpu->run->s.regs.gprs[base2] : 0) + disp2; 73 return (base2 ? vcpu->run->s.regs.gprs[base2] : 0) + disp2;
74} 74}
@@ -76,10 +76,10 @@ static inline u64 kvm_s390_get_base_disp_s(struct kvm_vcpu *vcpu)
76static inline void kvm_s390_get_base_disp_sse(struct kvm_vcpu *vcpu, 76static inline void kvm_s390_get_base_disp_sse(struct kvm_vcpu *vcpu,
77 u64 *address1, u64 *address2) 77 u64 *address1, u64 *address2)
78{ 78{
79 int base1 = (vcpu->arch.sie_block->ipb & 0xf0000000) >> 28; 79 u32 base1 = (vcpu->arch.sie_block->ipb & 0xf0000000) >> 28;
80 int disp1 = (vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16; 80 u32 disp1 = (vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16;
81 int base2 = (vcpu->arch.sie_block->ipb & 0xf000) >> 12; 81 u32 base2 = (vcpu->arch.sie_block->ipb & 0xf000) >> 12;
82 int disp2 = vcpu->arch.sie_block->ipb & 0x0fff; 82 u32 disp2 = vcpu->arch.sie_block->ipb & 0x0fff;
83 83
84 *address1 = (base1 ? vcpu->run->s.regs.gprs[base1] : 0) + disp1; 84 *address1 = (base1 ? vcpu->run->s.regs.gprs[base1] : 0) + disp1;
85 *address2 = (base2 ? vcpu->run->s.regs.gprs[base2] : 0) + disp2; 85 *address2 = (base2 ? vcpu->run->s.regs.gprs[base2] : 0) + disp2;
@@ -87,17 +87,20 @@ static inline void kvm_s390_get_base_disp_sse(struct kvm_vcpu *vcpu,
87 87
88static inline u64 kvm_s390_get_base_disp_rsy(struct kvm_vcpu *vcpu) 88static inline u64 kvm_s390_get_base_disp_rsy(struct kvm_vcpu *vcpu)
89{ 89{
90 int base2 = vcpu->arch.sie_block->ipb >> 28; 90 u32 base2 = vcpu->arch.sie_block->ipb >> 28;
91 int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16) + 91 u32 disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16) +
92 ((vcpu->arch.sie_block->ipb & 0xff00) << 4); 92 ((vcpu->arch.sie_block->ipb & 0xff00) << 4);
93 /* The displacement is a 20bit _SIGNED_ value */
94 if (disp2 & 0x80000)
95 disp2+=0xfff00000;
93 96
94 return (base2 ? vcpu->run->s.regs.gprs[base2] : 0) + disp2; 97 return (base2 ? vcpu->run->s.regs.gprs[base2] : 0) + (long)(int)disp2;
95} 98}
96 99
97static inline u64 kvm_s390_get_base_disp_rs(struct kvm_vcpu *vcpu) 100static inline u64 kvm_s390_get_base_disp_rs(struct kvm_vcpu *vcpu)
98{ 101{
99 int base2 = vcpu->arch.sie_block->ipb >> 28; 102 u32 base2 = vcpu->arch.sie_block->ipb >> 28;
100 int disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16); 103 u32 disp2 = ((vcpu->arch.sie_block->ipb & 0x0fff0000) >> 16);
101 104
102 return (base2 ? vcpu->run->s.regs.gprs[base2] : 0) + disp2; 105 return (base2 ? vcpu->run->s.regs.gprs[base2] : 0) + disp2;
103} 106}