Skip to content

Commit bc45a51

Browse files
pfedinMarc Zyngier
authored and
Marc Zyngier
committed
arm64: KVM: Correctly handle zero register during MMIO
On ARM64 register index of 31 corresponds to both zero register and SP. However, all memory access instructions, use ZR as transfer register. SP is used only as a base register in indirect memory addressing, or by register-register arithmetics, which cannot be trapped here. Correct emulation is achieved by introducing new register accessor functions, which can do special handling for reg_num == 31. These new accessors intentionally do not rely on old vcpu_reg() on ARM64, because it is to be removed. Since the affected code is shared by both ARM flavours, implementations of these accessors are also added to ARM32 code. This patch fixes setting MMIO register to a random value (actually SP) instead of zero by something like: *((volatile int *)reg) = 0; compilers tend to generate "str wzr, [xx]" here [Marc: Fixed 32bit splat] Signed-off-by: Pavel Fedin <p.fedin@samsung.com> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
1 parent fbb4574 commit bc45a51

File tree

3 files changed

+28
-2
lines changed

3 files changed

+28
-2
lines changed

arch/arm/include/asm/kvm_emulate.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@
2828
unsigned long *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num);
2929
unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu);
3030

31+
static inline unsigned long vcpu_get_reg(struct kvm_vcpu *vcpu,
32+
u8 reg_num)
33+
{
34+
return *vcpu_reg(vcpu, reg_num);
35+
}
36+
37+
static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
38+
unsigned long val)
39+
{
40+
*vcpu_reg(vcpu, reg_num) = val;
41+
}
42+
3143
bool kvm_condition_valid(struct kvm_vcpu *vcpu);
3244
void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr);
3345
void kvm_inject_undefined(struct kvm_vcpu *vcpu);

arch/arm/kvm/mmio.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
115115
trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr,
116116
data);
117117
data = vcpu_data_host_to_guest(vcpu, data, len);
118-
*vcpu_reg(vcpu, vcpu->arch.mmio_decode.rt) = data;
118+
vcpu_set_reg(vcpu, vcpu->arch.mmio_decode.rt, data);
119119
}
120120

121121
return 0;
@@ -186,7 +186,8 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
186186
rt = vcpu->arch.mmio_decode.rt;
187187

188188
if (is_write) {
189-
data = vcpu_data_guest_to_host(vcpu, *vcpu_reg(vcpu, rt), len);
189+
data = vcpu_data_guest_to_host(vcpu, vcpu_get_reg(vcpu, rt),
190+
len);
190191

191192
trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, data);
192193
mmio_write_buf(data_buf, len, data);

arch/arm64/include/asm/kvm_emulate.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,19 @@ static inline unsigned long *vcpu_reg(const struct kvm_vcpu *vcpu, u8 reg_num)
109109
return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.regs[reg_num];
110110
}
111111

112+
static inline unsigned long vcpu_get_reg(const struct kvm_vcpu *vcpu,
113+
u8 reg_num)
114+
{
115+
return (reg_num == 31) ? 0 : vcpu_gp_regs(vcpu)->regs.regs[reg_num];
116+
}
117+
118+
static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
119+
unsigned long val)
120+
{
121+
if (reg_num != 31)
122+
vcpu_gp_regs(vcpu)->regs.regs[reg_num] = val;
123+
}
124+
112125
/* Get vcpu SPSR for current mode */
113126
static inline unsigned long *vcpu_spsr(const struct kvm_vcpu *vcpu)
114127
{

0 commit comments

Comments
 (0)