From: Rusty Russell <rusty.russell@xxxxxxxxxx> This adds more fields which we need to store in the struct arm_insn, so execute() knows what to do. Signed-off-by: Rusty Russell <rusty.russell@xxxxxxxxxx> --- arch/arm/kvm/emulate.c | 80 ++++++++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c index e4fc12b..05b534f 100644 --- a/arch/arm/kvm/emulate.c +++ b/arch/arm/kvm/emulate.c @@ -303,11 +303,12 @@ struct arm_insn { u8 type; u8 Rt, Rn, Rm; u8 shift_n; + u32 offset_addr; /* Common decoding */ u8 len; bool sign_extend; - bool w; + bool w, W, U, P; }; struct arm_decode { @@ -315,7 +316,7 @@ struct arm_decode { u32 opc; u32 opc_mask; - bool (*decode)(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, + bool (*decode)(struct kvm_vcpu *vcpu, unsigned long instr, struct arm_insn *ai); struct arm_insn template; @@ -385,31 +386,24 @@ u32 shift(u32 value, u8 N, enum SRType type, u8 amount, bool carry_in) return value & mask; } -static bool decode_arm_wb(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, - unsigned long instr, const struct arm_insn *ai) +static bool decode_arm_wb(struct kvm_vcpu *vcpu, unsigned long instr, + struct arm_insn *ai) { - u8 Rt = (instr >> 12) & 0xf; - u8 Rn = (instr >> 16) & 0xf; - u8 W = (instr >> 21) & 1; - u8 U = (instr >> 23) & 1; - u8 P = (instr >> 24) & 1; - u32 base_addr = *vcpu_reg(vcpu, Rn); - u32 offset_addr, offset; + u32 base_addr, offset; - /* - * Technically this is allowed in certain circumstances, - * but we don't support it. - */ - if (Rt == 15 || Rn == 15) - return false; + ai->Rt = (instr >> 12) & 0xf; + ai->Rn = (instr >> 16) & 0xf; + ai->W = (instr >> 21) & 1; + ai->U = (instr >> 23) & 1; + ai->P = (instr >> 24) & 1; + + base_addr = *vcpu_reg(vcpu, ai->Rn); - if (P && !W) { + if (ai->P && !ai->W) { kvm_err("Decoding operation with valid ISV?\n"); return false; } - vcpu->arch.mmio.rd = Rt; - if (ai->register_form) { /* Register operation */ enum SRType s_type; @@ -425,46 +419,56 @@ static bool decode_arm_wb(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, } /* Handle Writeback */ - if (U) - offset_addr = base_addr + offset; + if (ai->U) + ai->offset_addr = base_addr + offset; else - offset_addr = base_addr - offset; - *vcpu_reg(vcpu, Rn) = offset_addr; + ai->offset_addr = base_addr - offset; return true; } -static bool decode_arm_ls(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, +static bool decode_arm_ls(struct kvm_vcpu *vcpu, unsigned long instr, struct arm_insn *ai) { u8 A = (instr >> 25) & 1; - mmio->is_write = ai->w; - mmio->len = ai->len; - vcpu->arch.mmio.sign_extend = false; - ai->register_form = A; ai->imm = instr & 0xfff; ai->Rm = instr & 0xf; ai->type = (instr >> 5) & 0x3; ai->shift_n = (instr >> 7) & 0x1f; - return decode_arm_wb(vcpu, mmio, instr, ai); + return decode_arm_wb(vcpu, instr, ai); } -static bool decode_arm_extra(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, +static bool decode_arm_extra(struct kvm_vcpu *vcpu, unsigned long instr, struct arm_insn *ai) { - mmio->is_write = ai->w; - mmio->len = ai->len; - vcpu->arch.mmio.sign_extend = ai->sign_extend; - ai->register_form = !((instr >> 22) & 1); ai->imm = ((instr >> 4) & 0xf0) | (instr & 0xf); ai->Rm = instr & 0xf; ai->type = 0; /* SRType_LSL */ ai->shift_n = 0; - return decode_arm_wb(vcpu, mmio, instr, ai); + return decode_arm_wb(vcpu, instr, ai); +} + +static bool execute(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, + const struct arm_insn *ai) +{ + /* + * Technically this is allowed in certain circumstances, + * but we don't support it. + */ + if (ai->Rt == 15 || ai->Rn == 15) + return false; + + mmio->is_write = ai->w; + mmio->len = ai->len; + vcpu->arch.mmio.sign_extend = ai->sign_extend; + + vcpu->arch.mmio.rd = ai->Rt; + *vcpu_reg(vcpu, ai->Rn) = ai->offset_addr; + return true; } /* @@ -553,7 +557,9 @@ static bool kvm_decode_arm_ls(struct kvm_vcpu *vcpu, unsigned long instr, const struct arm_decode *d = &arm_decode[i]; if ((instr & d->opc_mask) == d->opc) { struct arm_insn ai = d->template; - return d->decode(vcpu, mmio, instr, &ai); + if (!d->decode(vcpu, instr, &ai)) + return false; + return execute(vcpu, mmio, &ai); } } return false; -- 1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html