From: Rusty Russell <rusty.russell@xxxxxxxxxx> Add a new 'struct arm_insn' to represent the decoded instruction; the decoding logic belong in a separate structure (arm_decode). Signed-off-by: Rusty Russell <rusty.russell@xxxxxxxxxx> --- arch/arm/kvm/emulate.c | 120 +++++++++++++++++++++++++++--------------------- 1 file changed, 68 insertions(+), 52 deletions(-) diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c index 30124cb..e4fc12b 100644 --- a/arch/arm/kvm/emulate.c +++ b/arch/arm/kvm/emulate.c @@ -288,34 +288,37 @@ out: /****************************************************************************** * Load-Store instruction emulation *****************************************************************************/ +enum SRType { + SRType_LSL, + SRType_LSR, + SRType_ASR, + SRType_ROR, + SRType_RRX +}; -struct arm_instr { - /* Instruction decoding */ - u32 opc; - u32 opc_mask; - +struct arm_insn { /* Decoding for the register write back */ bool register_form; u32 imm; - u8 Rm; u8 type; + u8 Rt, Rn, Rm; u8 shift_n; /* Common decoding */ u8 len; bool sign_extend; bool w; +}; + +struct arm_decode { + /* Instruction decoding */ + u32 opc; + u32 opc_mask; bool (*decode)(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, - unsigned long instr, struct arm_instr *ai); -}; + unsigned long instr, struct arm_insn *ai); -enum SRType { - SRType_LSL, - SRType_LSR, - SRType_ASR, - SRType_ROR, - SRType_RRX + struct arm_insn template; }; /* Modelled after DecodeImmShift() in the ARM ARM */ @@ -383,7 +386,7 @@ u32 shift(u32 value, u8 N, enum SRType type, u8 amount, bool carry_in) } static bool decode_arm_wb(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, - unsigned long instr, const struct arm_instr *ai) + unsigned long instr, const struct arm_insn *ai) { u8 Rt = (instr >> 12) & 0xf; u8 Rn = (instr >> 16) & 0xf; @@ -431,7 +434,7 @@ static bool decode_arm_wb(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, } static bool decode_arm_ls(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, - unsigned long instr, struct arm_instr *ai) + unsigned long instr, struct arm_insn *ai) { u8 A = (instr >> 25) & 1; @@ -449,7 +452,7 @@ static bool decode_arm_ls(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, } static bool decode_arm_extra(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, - unsigned long instr, struct arm_instr *ai) + unsigned long instr, struct arm_insn *ai) { mmio->is_write = ai->w; mmio->len = ai->len; @@ -476,56 +479,69 @@ static bool decode_arm_extra(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, * loads and stores as their encodings mandate the W bit set and the P bit * clear. */ -static const struct arm_instr arm_instr[] = { +static const struct arm_decode arm_decode[] = { /**************** Load/Store Word and Byte **********************/ /* Store word with writeback */ - { .opc = 0x04000000, .opc_mask = 0x0c500000, .len = 4, .w = true, - .sign_extend = false, .decode = decode_arm_ls }, + { .opc = 0x04000000, .opc_mask = 0x0c500000, + .decode = decode_arm_ls, + .template = { .len = 4, .w = true, .sign_extend = false, }, }, /* Store byte with writeback */ - { .opc = 0x04400000, .opc_mask = 0x0c500000, .len = 1, .w = true, - .sign_extend = false, .decode = decode_arm_ls }, + { .opc = 0x04400000, .opc_mask = 0x0c500000, + .decode = decode_arm_ls, + .template = { .len = 1, .w = true, .sign_extend = false, }, }, /* Load word with writeback */ - { .opc = 0x04100000, .opc_mask = 0x0c500000, .len = 4, .w = false, - .sign_extend = false, .decode = decode_arm_ls }, + { .opc = 0x04100000, .opc_mask = 0x0c500000, + .decode = decode_arm_ls, + .template = { .len = 4, .w = false, .sign_extend = false, }, }, /* Load byte with writeback */ - { .opc = 0x04500000, .opc_mask = 0x0c500000, .len = 1, .w = false, - .sign_extend = false, .decode = decode_arm_ls }, + { .opc = 0x04500000, .opc_mask = 0x0c500000, + .decode = decode_arm_ls, + .template = { .len = 1, .w = false, .sign_extend = false, }, }, /*************** Extra load/store instructions ******************/ /* Store halfword with writeback */ - { .opc = 0x000000b0, .opc_mask = 0x0c1000f0, .len = 2, .w = true, - .sign_extend = false, .decode = decode_arm_extra }, + { .opc = 0x000000b0, .opc_mask = 0x0c1000f0, + .decode = decode_arm_extra, + .template = { .len = 2, .w = true, .sign_extend = false, }, }, /* Load halfword with writeback */ - { .opc = 0x001000b0, .opc_mask = 0x0c1000f0, .len = 2, .w = false, - .sign_extend = false, .decode = decode_arm_extra }, - + { .opc = 0x001000b0, .opc_mask = 0x0c1000f0, + .decode = decode_arm_extra, + .template = { .len = 2, .w = false, .sign_extend = false, }, }, /* Load dual with writeback */ - { .opc = 0x000000d0, .opc_mask = 0x0c1000f0, .len = 8, .w = false, - .sign_extend = false, .decode = decode_arm_extra }, + { .opc = 0x000000d0, .opc_mask = 0x0c1000f0, + .decode = decode_arm_extra, + .template = { .len = 8, .w = false, .sign_extend = false, }, }, /* Load signed byte with writeback */ - { .opc = 0x001000d0, .opc_mask = 0x0c1000f0, .len = 1, .w = false, - .sign_extend = true, .decode = decode_arm_extra }, + { .opc = 0x001000d0, .opc_mask = 0x0c1000f0, + .decode = decode_arm_extra, + .template = { .len = 1, .w = false, .sign_extend = true, }, }, /* Store dual with writeback */ - { .opc = 0x000000f0, .opc_mask = 0x0c1000f0, .len = 8, .w = true, - .sign_extend = false, .decode = decode_arm_extra }, + { .opc = 0x000000f0, .opc_mask = 0x0c1000f0, + .decode = decode_arm_extra, + .template = { .len = 8, .w = true, .sign_extend = false, }, }, /* Load signed halfword with writeback */ - { .opc = 0x001000f0, .opc_mask = 0x0c1000f0, .len = 2, .w = false, - .sign_extend = true, .decode = decode_arm_extra }, + { .opc = 0x001000f0, .opc_mask = 0x0c1000f0, + .decode = decode_arm_extra, + .template = { .len = 2, .w = false, .sign_extend = true, }, }, /* Store halfword unprivileged */ - { .opc = 0x002000b0, .opc_mask = 0x0f3000f0, .len = 2, .w = true, - .sign_extend = false, .decode = decode_arm_extra }, + { .opc = 0x002000b0, .opc_mask = 0x0f3000f0, + .decode = decode_arm_extra, + .template = { .len = 2, .w = true, .sign_extend = false, }, }, /* Load halfword unprivileged */ - { .opc = 0x003000b0, .opc_mask = 0x0f3000f0, .len = 2, .w = false, - .sign_extend = false, .decode = decode_arm_extra }, + { .opc = 0x003000b0, .opc_mask = 0x0f3000f0, + .decode = decode_arm_extra, + .template = { .len = 2, .w = false, .sign_extend = false, }, }, /* Load signed byte unprivileged */ - { .opc = 0x003000d0, .opc_mask = 0x0f3000f0, .len = 1, .w = false, - .sign_extend = true , .decode = decode_arm_extra }, + { .opc = 0x003000d0, .opc_mask = 0x0f3000f0, + .decode = decode_arm_extra, + .template = { .len = 1, .w = false, .sign_extend = true, }, }, /* Load signed halfword unprivileged */ - { .opc = 0x003000d0, .opc_mask = 0x0f3000f0, .len = 2, .w = false, - .sign_extend = true , .decode = decode_arm_extra }, + { .opc = 0x003000d0, .opc_mask = 0x0f3000f0, + .decode = decode_arm_extra, + .template = { .len = 2, .w = false, .sign_extend = true, }, }, }; static bool kvm_decode_arm_ls(struct kvm_vcpu *vcpu, unsigned long instr, @@ -533,11 +549,11 @@ static bool kvm_decode_arm_ls(struct kvm_vcpu *vcpu, unsigned long instr, { int i; - for (i = 0; i < ARRAY_SIZE(arm_instr); i++) { - const struct arm_instr *ai = &arm_instr[i]; - if ((instr & ai->opc_mask) == ai->opc) { - struct arm_instr ai_copy = *ai; - return ai->decode(vcpu, mmio, instr, &ai_copy); + for (i = 0; i < ARRAY_SIZE(arm_decode); i++) { + 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); } } 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